mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-05-12 11:18:11 -07:00
Merge pull request #3287 from kormax/duox-verifycert
Implement `hf mfd verifycert` command
This commit is contained in:
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Added `hf mfd verifycert` command (@kormax)
|
||||
- Added `hf calypso dump` command (@kormax)
|
||||
- Added `pm3trace_edit.py` script for editing of pm3 trace files (@iceman1001)
|
||||
- Added `hf calypso info` command (@kormax)
|
||||
|
||||
@@ -313,6 +313,7 @@ set (TARGET_SOURCES
|
||||
${PM3_ROOT}/common/hitag2/hitag2_crypto.c
|
||||
${PM3_ROOT}/client/src/crypto/asn1dump.c
|
||||
${PM3_ROOT}/client/src/crypto/asn1utils.c
|
||||
${PM3_ROOT}/client/src/crypto/duoxcrypto.c
|
||||
${PM3_ROOT}/client/src/crypto/libpcrypto.c
|
||||
${PM3_ROOT}/client/src/crypto/originality.c
|
||||
${PM3_ROOT}/client/src/emv/test/cda_test.c
|
||||
|
||||
@@ -770,6 +770,7 @@ SRCS = mifare/aiddesfire.c \
|
||||
comms.c \
|
||||
crypto/asn1dump.c \
|
||||
crypto/asn1utils.c\
|
||||
crypto/duoxcrypto.c\
|
||||
crypto/libpcrypto.c\
|
||||
crypto/originality.c\
|
||||
emv/cmdemv.c \
|
||||
|
||||
@@ -233,6 +233,7 @@ set (TARGET_SOURCES
|
||||
${PM3_ROOT}/common/hitag2/hitag2_crypto.c
|
||||
${PM3_ROOT}/client/src/crypto/asn1dump.c
|
||||
${PM3_ROOT}/client/src/crypto/asn1utils.c
|
||||
${PM3_ROOT}/client/src/crypto/duoxcrypto.c
|
||||
${PM3_ROOT}/client/src/crypto/libpcrypto.c
|
||||
${PM3_ROOT}/client/src/crypto/originality.c
|
||||
${PM3_ROOT}/client/src/emv/test/cda_test.c
|
||||
|
||||
+1086
-13
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// MIFARE DUOX certificate crypto helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef DUOXCRYPTO_H
|
||||
#define DUOXCRYPTO_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <mbedtls/ecp.h>
|
||||
|
||||
#define DUOX_DEFAULT_CA_DIR "duox_trust"
|
||||
#define DUOX_EC_PUBKEY_MAX_LEN 133
|
||||
#define DUOX_MAX_CERTIFICATE_ANCHORS 16
|
||||
#define DUOX_CERTIFICATE_ANCHOR_NAME_LEN 96
|
||||
#define DUOX_CERTIFICATE_ANCHOR_MAX_PATHS 128
|
||||
#define DUOX_CERTIFICATE_ANCHOR_PATH_LEN 1024
|
||||
#define DUOX_CERT_TEXT_LEN 256
|
||||
#define DUOX_VDE_CHALLENGE_LEN 32
|
||||
#define DUOX_VDE_SIG_LEN 64
|
||||
|
||||
typedef enum {
|
||||
DUOX_CERTIFICATE_FORMAT_UNKNOWN = 0,
|
||||
DUOX_CERTIFICATE_FORMAT_X509,
|
||||
DUOX_CERTIFICATE_FORMAT_GP_VDE,
|
||||
} duox_certificate_format_t;
|
||||
|
||||
typedef struct {
|
||||
duox_certificate_format_t format;
|
||||
mbedtls_ecp_group_id curveid;
|
||||
uint8_t pubkey[DUOX_EC_PUBKEY_MAX_LEN];
|
||||
size_t pubkey_len;
|
||||
char issuer[DUOX_CERT_TEXT_LEN];
|
||||
char subject[DUOX_CERT_TEXT_LEN];
|
||||
char serial[DUOX_CERT_TEXT_LEN];
|
||||
char valid_from[DUOX_CERT_TEXT_LEN];
|
||||
char valid_to[DUOX_CERT_TEXT_LEN];
|
||||
char certificate_profile_note[DUOX_CERT_TEXT_LEN];
|
||||
} duox_cert_info_t;
|
||||
|
||||
typedef struct {
|
||||
mbedtls_ecp_group_id curveid;
|
||||
uint8_t pubkey[DUOX_EC_PUBKEY_MAX_LEN];
|
||||
size_t pubkey_len;
|
||||
} duox_ec_public_key_t;
|
||||
|
||||
typedef enum {
|
||||
DUOX_CERTIFICATE_ANCHOR_MATERIAL_NONE = 0,
|
||||
DUOX_CERTIFICATE_ANCHOR_MATERIAL_PUBLIC_KEY,
|
||||
DUOX_CERTIFICATE_ANCHOR_MATERIAL_CERT,
|
||||
} duox_certificate_anchor_material_type_t;
|
||||
|
||||
typedef struct {
|
||||
char name[DUOX_CERTIFICATE_ANCHOR_NAME_LEN];
|
||||
char source[DUOX_CERTIFICATE_ANCHOR_PATH_LEN];
|
||||
duox_certificate_anchor_material_type_t type;
|
||||
union {
|
||||
duox_ec_public_key_t key;
|
||||
duox_cert_info_t cert;
|
||||
} material;
|
||||
} duox_certificate_anchor_t;
|
||||
|
||||
const char *duox_certificate_format_name(duox_certificate_format_t format);
|
||||
const char *duox_cert_info_format_name(const duox_cert_info_t *cert);
|
||||
int duox_certificate_anchor_public_key(const duox_certificate_anchor_t *anchor,
|
||||
mbedtls_ecp_group_id *curveid,
|
||||
const uint8_t **pubkey, size_t *pubkey_len);
|
||||
const char *duox_certificate_anchor_subject(const duox_certificate_anchor_t *anchor);
|
||||
const char *duox_certificate_anchor_display_name(const duox_certificate_anchor_t *anchor);
|
||||
int duox_load_certificate_anchor_from_input(const char *input, const char *anchor_store_dir,
|
||||
duox_certificate_anchor_t *anchor);
|
||||
int duox_load_certificate_anchors_from_store(const char *anchor_store_dir,
|
||||
duox_certificate_anchor_t *anchors,
|
||||
size_t max_anchors, size_t *out_count);
|
||||
int duox_parse_x509_certificate(const uint8_t *data, size_t data_len,
|
||||
bool verbose, duox_cert_info_t *out);
|
||||
int duox_verify_x509_certificate_with_anchors(const uint8_t *data, size_t data_len,
|
||||
const duox_certificate_anchor_t *anchors, size_t anchor_count,
|
||||
bool verbose, duox_cert_info_t *out,
|
||||
size_t *matched_index);
|
||||
int duox_parse_gp_vde_certificate(const uint8_t *data, size_t data_len,
|
||||
const duox_certificate_anchor_t *ca_anchors, size_t ca_anchor_count,
|
||||
bool verify_signature,
|
||||
bool verbose, duox_cert_info_t *out, size_t *matched_index);
|
||||
int duox_parse_or_verify_certificate_variants(const uint8_t *data, size_t data_len,
|
||||
const duox_certificate_anchor_t *ca_anchors, size_t ca_anchor_count,
|
||||
bool verify_signature,
|
||||
bool verbose, duox_cert_info_t *out, size_t *matched_index);
|
||||
|
||||
#endif /* DUOXCRYPTO_H */
|
||||
@@ -526,6 +526,7 @@ const static vocabulary_t vocabulary[] = {
|
||||
{ 0, "hf mfdes write" },
|
||||
{ 0, "hf mfdes value" },
|
||||
{ 0, "hf mfdes clearrecfile" },
|
||||
{ 0, "hf mfdes verifycert" },
|
||||
{ 0, "hf mfdes intauth" },
|
||||
{ 0, "hf mfdes vdesign" },
|
||||
{ 1, "hf mfdes test" },
|
||||
|
||||
@@ -1391,6 +1391,71 @@ void strn_upper(char *s, size_t n) {
|
||||
s[i] = toupper(s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int char_compare_case_insensitive(char a, char b) {
|
||||
return tolower((unsigned char)a) - tolower((unsigned char)b);
|
||||
}
|
||||
|
||||
bool str_equal_case_insensitive(const char *a, const char *b) {
|
||||
if (a == NULL || b == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (*a != '\0' && *b != '\0') {
|
||||
if (char_compare_case_insensitive(*a, *b) != 0) {
|
||||
return false;
|
||||
}
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
|
||||
return *a == '\0' && *b == '\0';
|
||||
}
|
||||
|
||||
bool str_startswith_case_insensitive(const char *s, const char *pre) {
|
||||
if (s == NULL || pre == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (*pre != '\0') {
|
||||
if (*s == '\0' || char_compare_case_insensitive(*s, *pre) != 0) {
|
||||
return false;
|
||||
}
|
||||
s++;
|
||||
pre++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool str_contains_case_insensitive(const char *s, const char *needle) {
|
||||
if (s == NULL || needle == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t needle_len = strlen(needle);
|
||||
if (needle_len == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t s_len = strlen(s);
|
||||
if (needle_len > s_len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i <= (s_len - needle_len); i++) {
|
||||
size_t j = 0;
|
||||
while (j < needle_len && char_compare_case_insensitive(s[i + j], needle[j]) == 0) {
|
||||
j++;
|
||||
}
|
||||
if (j == needle_len) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// check for prefix in string
|
||||
bool str_startswith(const char *s, const char *pre) {
|
||||
return strncmp(pre, s, strlen(pre)) == 0;
|
||||
@@ -1499,6 +1564,28 @@ size_t str_nlen(const char *src, size_t maxlen) {
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t str_copy(char *dst, size_t dst_size, const char *src) {
|
||||
if (src == NULL) {
|
||||
if (dst != NULL && dst_size > 0) {
|
||||
dst[0] = '\0';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t src_len = strlen(src);
|
||||
if (dst == NULL || dst_size == 0) {
|
||||
return src_len;
|
||||
}
|
||||
|
||||
size_t copy_len = src_len;
|
||||
if (copy_len >= dst_size) {
|
||||
copy_len = dst_size - 1;
|
||||
}
|
||||
memcpy(dst, src, copy_len);
|
||||
dst[copy_len] = '\0';
|
||||
return src_len;
|
||||
}
|
||||
|
||||
static bool str_regex_atom_matches(char atom, bool escaped, char c) {
|
||||
if (!escaped && atom == '.') {
|
||||
return true;
|
||||
|
||||
@@ -166,6 +166,9 @@ void str_lower(char *s); // converts string to lower case
|
||||
void str_upper(char *s); // converts string to UPPER case
|
||||
void strn_upper(char *s, size_t n);
|
||||
|
||||
bool str_equal_case_insensitive(const char *a, const char *b);
|
||||
bool str_startswith_case_insensitive(const char *s, const char *pre);
|
||||
bool str_contains_case_insensitive(const char *s, const char *needle);
|
||||
bool str_startswith(const char *s, const char *pre); // check for prefix in string
|
||||
bool str_endswith(const char *s, const char *suffix); // check for suffix in string
|
||||
void clean_ascii(unsigned char *buf, size_t len);
|
||||
@@ -181,6 +184,7 @@ void str_trim(char *s);
|
||||
char *str_dup(const char *src);
|
||||
char *str_ndup(const char *src, size_t len);
|
||||
size_t str_nlen(const char *src, size_t maxlen);
|
||||
size_t str_copy(char *dst, size_t dst_size, const char *src);
|
||||
// Lightweight regex subset:
|
||||
// - supported metacharacters: '^' (start), '$' (end), '.' (any char), '*' (zero or more)
|
||||
// - escaping: '\\' to match the following char literally
|
||||
|
||||
Reference in New Issue
Block a user