mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-22 22:23:38 -07:00
SDA,DDA,fDDA,CDA works
This commit is contained in:
parent
2fd87dd426
commit
66a2d6baf1
4 changed files with 94 additions and 48 deletions
|
@ -287,6 +287,7 @@ int UsageCmdHFEMVExec(void) {
|
||||||
PrintAndLog(" -v : transaction type - qVSDC or M/Chip.\n");
|
PrintAndLog(" -v : transaction type - qVSDC or M/Chip.\n");
|
||||||
PrintAndLog(" -c : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n");
|
PrintAndLog(" -c : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n");
|
||||||
PrintAndLog(" -x : transaction type - VSDC. For test only. Not a standart behavior.\n");
|
PrintAndLog(" -x : transaction type - VSDC. For test only. Not a standart behavior.\n");
|
||||||
|
PrintAndLog(" -g : VISA. generate AC from GPO\n");
|
||||||
PrintAndLog("By default : transaction type - MSD.\n");
|
PrintAndLog("By default : transaction type - MSD.\n");
|
||||||
PrintAndLog("Samples:");
|
PrintAndLog("Samples:");
|
||||||
PrintAndLog(" hf emv pse -s -> select card");
|
PrintAndLog(" hf emv pse -s -> select card");
|
||||||
|
@ -302,6 +303,7 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
bool decodeTLV = false;
|
bool decodeTLV = false;
|
||||||
bool forceSearch = false;
|
bool forceSearch = false;
|
||||||
enum TransactionType TrType = TT_MSD;
|
enum TransactionType TrType = TT_MSD;
|
||||||
|
bool GenACGPO = false;
|
||||||
|
|
||||||
uint8_t buf[APDU_RES_LEN] = {0};
|
uint8_t buf[APDU_RES_LEN] = {0};
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
@ -355,6 +357,10 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
case 'C':
|
case 'C':
|
||||||
TrType = TT_CDA;
|
TrType = TT_CDA;
|
||||||
break;
|
break;
|
||||||
|
case 'g':
|
||||||
|
case 'G':
|
||||||
|
GenACGPO = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
|
PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -425,6 +431,10 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
PrintAndLog("\n* Init transaction parameters.");
|
PrintAndLog("\n* Init transaction parameters.");
|
||||||
|
|
||||||
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
|
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
|
||||||
|
char *qVSDC = "\x26\x00\x00\x00";
|
||||||
|
if (GenACGPO) {
|
||||||
|
qVSDC = "\x26\x80\x00\x00";
|
||||||
|
}
|
||||||
switch(TrType) {
|
switch(TrType) {
|
||||||
case TT_MSD:
|
case TT_MSD:
|
||||||
TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
|
TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
|
||||||
|
@ -434,15 +444,16 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC
|
TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC
|
||||||
break;
|
break;
|
||||||
case TT_QVSDCMCHIP:
|
case TT_QVSDCMCHIP:
|
||||||
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
TLV_ADD(0x9F66, qVSDC); // qVSDC
|
||||||
break;
|
break;
|
||||||
case TT_CDA:
|
case TT_CDA:
|
||||||
TLV_ADD(0x9F66, "\x26\x80\x00\x00"); // CDA
|
TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//9F02:(Amount, Authorised (Numeric)) len:6
|
//9F02:(Amount, Authorised (Numeric)) len:6
|
||||||
TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
|
TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
|
||||||
//9F1A:(Terminal Country Code) len:2
|
//9F1A:(Terminal Country Code) len:2
|
||||||
|
@ -480,7 +491,7 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||||
|
|
||||||
free(pdol_data_tlv_data);
|
free(pdol_data_tlv_data);
|
||||||
//free(pdol_data_tlv);
|
//free(pdol_data_tlv); --- free on exit.
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLog("GPO error(%d): %4x. Exit...", res, sw);
|
PrintAndLog("GPO error(%d): %4x. Exit...", res, sw);
|
||||||
|
@ -695,8 +706,6 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
// EMVAC_TC + EMVAC_CDAREQ --- to get SDAD
|
// EMVAC_TC + EMVAC_CDAREQ --- to get SDAD
|
||||||
res = EMVAC(true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
res = EMVAC(true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||||
|
|
||||||
//free(cdol_data_tlv);
|
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
PrintAndLog("AC1 error(%d): %4x. Exit...", res, sw);
|
PrintAndLog("AC1 error(%d): %4x. Exit...", res, sw);
|
||||||
return 5;
|
return 5;
|
||||||
|
@ -713,6 +722,7 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
PrintAndLog("CDA error (%d)", res);
|
PrintAndLog("CDA error (%d)", res);
|
||||||
}
|
}
|
||||||
free(ac_tlv);
|
free(ac_tlv);
|
||||||
|
free(cdol_data_tlv);
|
||||||
|
|
||||||
PrintAndLog("\n* M/Chip transaction result:");
|
PrintAndLog("\n* M/Chip transaction result:");
|
||||||
// 9F27: Cryptogram Information Data (CID)
|
// 9F27: Cryptogram Information Data (CID)
|
||||||
|
@ -804,6 +814,7 @@ int CmdHFEMVExec(const char *cmd) {
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
// Destroy TLV's
|
// Destroy TLV's
|
||||||
|
free(pdol_data_tlv);
|
||||||
tlvdb_free(tlvSelect);
|
tlvdb_free(tlvSelect);
|
||||||
tlvdb_free(tlvRoot);
|
tlvdb_free(tlvRoot);
|
||||||
|
|
||||||
|
|
|
@ -367,6 +367,44 @@ struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct t
|
||||||
return idn_db;
|
return idn_db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, bool showData)
|
||||||
|
{
|
||||||
|
size_t data_len;
|
||||||
|
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||||
|
tlvdb_get(db, 0x9f4b, NULL),
|
||||||
|
tlvdb_get(db, 0x9f37, NULL),
|
||||||
|
tlvdb_get(db, 0x9f02, NULL),
|
||||||
|
tlvdb_get(db, 0x5f2a, NULL),
|
||||||
|
tlvdb_get(db, 0x9f69, NULL),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!data || data_len < 3)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (data[3] < 2 || data[3] > data_len - 3) {
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showData){
|
||||||
|
printf("Recovered data:\n");
|
||||||
|
dump_buffer(data, data_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t idn_len = data[4];
|
||||||
|
if (idn_len > data[3] - 1) {
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9f36 Application Transaction Counter (ATC)
|
||||||
|
struct tlvdb *atc_db = tlvdb_fixed(0x9f36, idn_len, data + 5);
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return atc_db;
|
||||||
|
}
|
||||||
|
|
||||||
static bool tlv_hash(void *data, const struct tlv *tlv, int level, bool is_leaf)
|
static bool tlv_hash(void *data, const struct tlv *tlv, int level, bool is_leaf)
|
||||||
{
|
{
|
||||||
struct crypto_hash *ch = data;
|
struct crypto_hash *ch = data;
|
||||||
|
|
|
@ -29,6 +29,7 @@ struct tlvdb *emv_pki_recover_dac(const struct emv_pk *pk, const struct tlvdb *d
|
||||||
struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData);
|
struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData);
|
||||||
struct tlvdb *emv_pki_recover_idn(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv);
|
struct tlvdb *emv_pki_recover_idn(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv);
|
||||||
struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData);
|
struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData);
|
||||||
|
struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, bool showData);
|
||||||
struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||||
const struct tlvdb *this_db,
|
const struct tlvdb *this_db,
|
||||||
const struct tlv *pdol_data_tlv,
|
const struct tlv *pdol_data_tlv,
|
||||||
|
|
|
@ -532,14 +532,6 @@ int trSDA(struct tlvdb *tlv) {
|
||||||
static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04};
|
static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04};
|
||||||
static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value };
|
static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value };
|
||||||
|
|
||||||
static const unsigned char default_fdda_ddol_value[] =
|
|
||||||
{0x9f, 0x37, 0x04,
|
|
||||||
0x9f, 0x02, 0x06,
|
|
||||||
0x5f, 0x2A, 0x02,
|
|
||||||
0x9f, 0x69, 0x07, // 9f69[07] Card Authentication Related Data
|
|
||||||
};
|
|
||||||
static struct tlv default_fdda_ddol_tlv = {.tag = 0x9f49, .len = 12, .value = default_fdda_ddol_value };
|
|
||||||
|
|
||||||
int trDDA(bool decodeTLV, struct tlvdb *tlv) {
|
int trDDA(bool decodeTLV, struct tlvdb *tlv) {
|
||||||
uint8_t buf[APDU_RES_LEN] = {0};
|
uint8_t buf[APDU_RES_LEN] = {0};
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
@ -608,7 +600,6 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tlvdb *dda_db = NULL;
|
|
||||||
struct tlv *ddol_data_tlv = NULL;
|
struct tlv *ddol_data_tlv = NULL;
|
||||||
// 9F4B: Signed Dynamic Application Data
|
// 9F4B: Signed Dynamic Application Data
|
||||||
const struct tlv *sdad_tlv = tlvdb_get(tlv, 0x9f4b, NULL);
|
const struct tlv *sdad_tlv = tlvdb_get(tlv, 0x9f4b, NULL);
|
||||||
|
@ -616,17 +607,30 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) {
|
||||||
// EMV kernel3 v2.4, contactless book C-3, C.1., page 147
|
// EMV kernel3 v2.4, contactless book C-3, C.1., page 147
|
||||||
if (sdad_tlv) {
|
if (sdad_tlv) {
|
||||||
PrintAndLog("\n* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA...");
|
PrintAndLog("\n* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA...");
|
||||||
dda_db = tlv;
|
|
||||||
|
|
||||||
PrintAndLog("\n* Calc fDDA hash");
|
const struct tlvdb *atc_db = emv_pki_recover_atc_ex(icc_pk, tlv, true);
|
||||||
ddol_data_tlv = dol_process(&default_fdda_ddol_tlv, tlv, 0);
|
free(ddol_data_tlv);
|
||||||
if (!ddol_data_tlv) {
|
if (!atc_db) {
|
||||||
PrintAndLog("ERROR: Can't create fDDA hash TLV");
|
PrintAndLog("ERROR: Can't recover IDN (ICC Dynamic Number)");
|
||||||
return 5;
|
return 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintAndLog("fDDA hash data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len));
|
// 9f36 Application Transaction Counter (ATC)
|
||||||
|
const struct tlv *atc_tlv = tlvdb_get(atc_db, 0x9f36, NULL);
|
||||||
|
if(atc_tlv) {
|
||||||
|
PrintAndLog("\nATC (Application Transaction Counter) [%zu] %s", atc_tlv->len, sprint_hex_inrow(atc_tlv->value, atc_tlv->len));
|
||||||
|
|
||||||
|
const struct tlv *core_atc_tlv = tlvdb_get(tlv, 0x9f36, NULL);
|
||||||
|
if(tlv_equal(core_atc_tlv, atc_tlv)) {
|
||||||
|
PrintAndLog("ATC check OK.");
|
||||||
|
PrintAndLog("fDDA (fast DDA) verified OK.");
|
||||||
|
} else {
|
||||||
|
PrintAndLog("ERROR: fDDA verified, but ATC in the certificate and ATC in the record not the same.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PrintAndLog("\nERROR: fDDA (fast DDA) verify error");
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
||||||
if (dac_db) {
|
if (dac_db) {
|
||||||
|
@ -660,6 +664,7 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) {
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tlvdb *dda_db = NULL;
|
||||||
if (buf[0] == 0x80) {
|
if (buf[0] == 0x80) {
|
||||||
if (len < 3 ) {
|
if (len < 3 ) {
|
||||||
PrintAndLog("ERROR: Internal Authenticate format1 parsing error. length=%d", len);
|
PrintAndLog("ERROR: Internal Authenticate format1 parsing error. length=%d", len);
|
||||||
|
@ -683,7 +688,6 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) {
|
||||||
if (decodeTLV)
|
if (decodeTLV)
|
||||||
TLVPrintFromTLV(dda_db);
|
TLVPrintFromTLV(dda_db);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
struct tlvdb *idn_db = emv_pki_recover_idn_ex(icc_pk, dda_db, ddol_data_tlv, true);
|
struct tlvdb *idn_db = emv_pki_recover_idn_ex(icc_pk, dda_db, ddol_data_tlv, true);
|
||||||
free(ddol_data_tlv);
|
free(ddol_data_tlv);
|
||||||
|
@ -697,24 +701,16 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) {
|
||||||
// 9f4c ICC Dynamic Number
|
// 9f4c ICC Dynamic Number
|
||||||
const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
|
const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
|
||||||
if(idn_tlv) {
|
if(idn_tlv) {
|
||||||
if(sdad_tlv) { // fDDA
|
|
||||||
PrintAndLog("\nATC (Application Transaction Counter) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
|
|
||||||
PrintAndLog("fDDA (fast DDA) verified OK.");
|
|
||||||
} else { // DDA
|
|
||||||
PrintAndLog("\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
|
PrintAndLog("\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
|
||||||
PrintAndLog("DDA verified OK.");
|
PrintAndLog("DDA verified OK.");
|
||||||
}
|
|
||||||
tlvdb_add(tlv, idn_db);
|
tlvdb_add(tlv, idn_db);
|
||||||
tlvdb_free(idn_db);
|
tlvdb_free(idn_db);
|
||||||
} else {
|
} else {
|
||||||
if(sdad_tlv) { // fDDA
|
|
||||||
PrintAndLog("\nERROR: fDDA (fast DDA) verify error");
|
|
||||||
} else { // DDA
|
|
||||||
PrintAndLog("\nERROR: DDA verify error");
|
PrintAndLog("\nERROR: DDA verify error");
|
||||||
}
|
|
||||||
tlvdb_free(idn_db);
|
tlvdb_free(idn_db);
|
||||||
return 9;
|
return 9;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue