From 4880316ab932d983bda83ff7600b2071e122f24e Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 9 Jan 2019 15:20:18 +0200 Subject: [PATCH 01/14] fix hash --- client/emv/emv_pki.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c index be4dfa0a7..602dcacce 100644 --- a/client/emv/emv_pki.c +++ b/client/emv/emv_pki.c @@ -109,10 +109,12 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, } va_end(vl); - if (memcmp(data + data_len - 1 - hash_len, crypto_hash_read(ch), hash_len)) { + uint8_t hash[20] = {0}; + memcpy(hash, crypto_hash_read(ch), hash_len); + if (memcmp(data + data_len - 1 - hash_len, hash, hash_len)) { printf("ERROR: Calculated wrong hash\n"); printf("decoded: %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len)); - printf("calculated: %s\n",sprint_hex(crypto_hash_read(ch), hash_len)); + printf("calculated: %s\n",sprint_hex(hash, hash_len)); if (strictExecution) { crypto_hash_close(ch); From 010492a87e47326c32040cd5495eb4baf3f2f991 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 9 Jan 2019 17:04:21 +0200 Subject: [PATCH 02/14] input list build fixed --- client/emv/cmdemv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 206401917..a21337d03 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -892,7 +892,7 @@ int CmdEMVExec(const char *cmd) { // Build Input list for Offline Data Authentication // EMV 4.3 book3 10.3, page 96 - if (SFIoffline) { + if (SFIoffline > 0) { if (SFI < 11) { const unsigned char *abuf = buf; size_t elmlen = len; @@ -907,6 +907,8 @@ int CmdEMVExec(const char *cmd) { memcpy(&ODAiList[ODAiListLen], buf, len); ODAiListLen += len; } + + SFIoffline--; } } } From 4a38ab7be4a8c20c761ea5abbb12365ef2734b7b Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 9 Jan 2019 17:08:23 +0200 Subject: [PATCH 03/14] small fix --- client/emv/cmdemv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index a21337d03..0cc6614d9 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -870,7 +870,7 @@ int CmdEMVExec(const char *cmd) { uint8_t SFIend = AFL->value[i * 4 + 2]; uint8_t SFIoffline = AFL->value[i * 4 + 3]; - PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); + PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline count:%02x", SFI, SFIstart, SFIend, SFIoffline); if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { PrintAndLogEx(NORMAL, "SFI ERROR! Skipped..."); continue; From 88b2cf41de9f3793faf942c35de365e6c561f194 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 9 Jan 2019 18:46:55 +0200 Subject: [PATCH 04/14] add description --- client/emv/emvcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 621287031..b672004c3 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -781,7 +781,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); if (dac_db) { const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL); - PrintAndLogEx(NORMAL, "SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); + PrintAndLogEx(NORMAL, "SDA verified OK. (Data Authentication Code: %02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); tlvdb_add(tlv, dac_db); } else { PrintAndLogEx(WARNING, "Error: SSAD verify error"); From 506da60cad7bf9d952deff2bb855add1369123ff Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 9 Jan 2019 18:47:26 +0200 Subject: [PATCH 05/14] hash init --- client/emv/emv_pki.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c index 602dcacce..593c8a00c 100644 --- a/client/emv/emv_pki.c +++ b/client/emv/emv_pki.c @@ -109,7 +109,8 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, } va_end(vl); - uint8_t hash[20] = {0}; + uint8_t hash[hash_len]; + memset(hash, 0, hash_len); memcpy(hash, crypto_hash_read(ch), hash_len); if (memcmp(data + data_len - 1 - hash_len, hash, hash_len)) { printf("ERROR: Calculated wrong hash\n"); From 20d29f35e5f9e0889539479b1ac5f1f3aa077f65 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 9 Jan 2019 19:32:08 +0200 Subject: [PATCH 06/14] SDA works --- client/emv/emv_pki.c | 43 +++++++++++++++++++++++++++++++++++++++++++ client/emv/emvcore.c | 2 +- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c index 593c8a00c..40edc79e4 100644 --- a/client/emv/emv_pki.c +++ b/client/emv/emv_pki.c @@ -313,14 +313,57 @@ struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb NULL); } +unsigned char *emv_pki_sdatl_fill(const struct tlvdb *db, size_t *sdatl_len) { + uint8_t buf[2048] = {0}; + size_t len = 0; + + *sdatl_len = 0; + + const struct tlv *sda_tl = tlvdb_get(db, 0x9f4a, NULL); + if (!sda_tl || sda_tl->len <= 0) + return NULL; + + for (int i = 0; i < sda_tl->len; i++) { + uint32_t tag = sda_tl->value[i]; // here may be multibyte, but now not + const struct tlv *elm = tlvdb_get(db, tag, NULL); + if (elm) { + memcpy(&buf[len], elm->value, elm->len); + len += elm->len; + } + } + + if (len) { + *sdatl_len = len; + unsigned char *value = malloc(len); + memcpy(value, buf, len); + return value; + } + + return NULL; +} + + struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData) { size_t data_len; + + // Static Data Authentication Tag List + size_t sdatl_len; + unsigned char *sdatl = emv_pki_sdatl_fill(db, &sdatl_len); + struct tlv sda_tdata = { + .tag = 0x00, // dummy tag + .len = sdatl_len, + .value = sdatl + }; + unsigned char *data = emv_pki_decode_message(enc_pk, 3, &data_len, tlvdb_get(db, 0x93, NULL), sda_tlv, + &sda_tdata, NULL); + free(sdatl); // malloc here: emv_pki_sdatl_fill + if (!data || data_len < 5) return NULL; diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index b672004c3..743fa2f9e 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -653,7 +653,7 @@ int trSDA(struct tlvdb *tlv) { struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); if (dac_db) { const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL); - PrintAndLogEx(NORMAL, "SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); + PrintAndLogEx(NORMAL, "SDA verified OK. (Data Authentication Code: %02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); tlvdb_add(tlv, dac_db); } else { emv_pk_free(issuer_pk); From 4921308d8465051346065f94a4033f2463f63dfd Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 9 Jan 2019 21:03:56 +0200 Subject: [PATCH 07/14] some changes in DDA --- client/emv/emvcore.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 743fa2f9e..c4b815715 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -596,7 +596,7 @@ int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t * } int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv); + return EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, true, Result, MaxResultLen, ResultLen, sw, tlv); } int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { @@ -682,12 +682,12 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { } const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL); - if (!sda_tlv || sda_tlv->len < 1) { +/* if (!sda_tlv || sda_tlv->len < 1) { it may be 0!!!! emv_pk_free(pk); PrintAndLogEx(WARNING, "Error: Can't find input list for Offline Data Authentication. Exit."); return 3; } - +*/ struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv); if (!issuer_pk) { emv_pk_free(pk); @@ -710,7 +710,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { if (!icc_pk) { emv_pk_free(pk); emv_pk_free(issuer_pk); - PrintAndLogEx(WARNING, "Error: ICC setrificate not found. Exit."); + PrintAndLogEx(WARNING, "Error: ICC certificate not found. Exit."); return 2; } PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", @@ -725,21 +725,25 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { icc_pk->serial[2] ); - struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv); - if (!icc_pe_pk) { - PrintAndLogEx(WARNING, "WARNING: ICC PE PK recover error. "); + if (tlvdb_get(tlv, 0x9f2d, NULL)) { + struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv); + if (!icc_pe_pk) { + PrintAndLogEx(WARNING, "WARNING: ICC PE PK recover error. "); + } else { + PrintAndLogEx(SUCCESS, "ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + icc_pe_pk->rid[0], + icc_pe_pk->rid[1], + icc_pe_pk->rid[2], + icc_pe_pk->rid[3], + icc_pe_pk->rid[4], + icc_pe_pk->index, + icc_pe_pk->serial[0], + icc_pe_pk->serial[1], + icc_pe_pk->serial[2] + ); + } } else { - PrintAndLogEx(SUCCESS, "ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", - icc_pe_pk->rid[0], - icc_pe_pk->rid[1], - icc_pe_pk->rid[2], - icc_pe_pk->rid[3], - icc_pe_pk->rid[4], - icc_pe_pk->index, - icc_pe_pk->serial[0], - icc_pe_pk->serial[1], - icc_pe_pk->serial[2] - ); + PrintAndLogEx(INFO, "ICC PE PK (PIN Encipherment Public Key Certificate) not found.\n"); } // 9F4B: Signed Dynamic Application Data From 56c0dad966fa7d0340333819dfaa1e87fcc13487 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Wed, 9 Jan 2019 21:05:52 +0200 Subject: [PATCH 08/14] changes in cert decoding logic --- client/emv/emv_pki.c | 39 +++++++++++++++++++++++++++++++-------- client/emv/emv_pki.h | 1 + 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c index 40edc79e4..84224a957 100644 --- a/client/emv/emv_pki.c +++ b/client/emv/emv_pki.c @@ -41,7 +41,8 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, uint8_t msgtype, size_t *len, const struct tlv *cert_tlv, - ... /* A list of tlv pointers, end with NULL */ + int tlv_count, + ... /* A list of tlv pointers */ ) { struct crypto_pk *kcp; @@ -99,11 +100,11 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, size_t hash_len = crypto_hash_get_size(ch); crypto_hash_write(ch, data + 1, data_len - 2 - hash_len); - va_start(vl, cert_tlv); - while (true) { + va_start(vl, tlv_count); + for (int i = 0; i < tlv_count; i++) { const struct tlv *add_tlv = va_arg(vl, const struct tlv *); if (!add_tlv) - break; + continue; crypto_hash_write(ch, add_tlv->value, add_tlv->len); } @@ -168,6 +169,7 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk, const struct tlv *exp_tlv, const struct tlv *rem_tlv, const struct tlv *add_tlv, + const struct tlv *sdatl_tlv, bool showData ) { @@ -193,9 +195,11 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk, data = emv_pki_decode_message(enc_pk, msgtype, &data_len, cert_tlv, + 5, rem_tlv, exp_tlv, add_tlv, + sdatl_tlv, NULL); if (!data || data_len < 11 + pan_length) { printf("ERROR: Can't decode message\n"); @@ -278,9 +282,10 @@ static struct emv_pk *emv_pki_decode_key(const struct emv_pk *enc_pk, const struct tlv *cert_tlv, const struct tlv *exp_tlv, const struct tlv *rem_tlv, - const struct tlv *add_tlv + const struct tlv *add_tlv, + const struct tlv *sdatl_tlv ) { - return emv_pki_decode_key_ex(enc_pk, msgtype, pan_tlv, cert_tlv, exp_tlv, rem_tlv, add_tlv, false); + return emv_pki_decode_key_ex(enc_pk, msgtype, pan_tlv, cert_tlv, exp_tlv, rem_tlv, add_tlv, sdatl_tlv, false); } struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db) @@ -290,17 +295,30 @@ struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb tlvdb_get(db, 0x90, NULL), tlvdb_get(db, 0x9f32, NULL), tlvdb_get(db, 0x92, NULL), + NULL, NULL); } struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv) { - return emv_pki_decode_key(pk, 4, + size_t sdatl_len; + unsigned char *sdatl = emv_pki_sdatl_fill(db, &sdatl_len); + struct tlv sda_tdata = { + .tag = 0x00, // dummy tag + .len = sdatl_len, + .value = sdatl + }; + + struct emv_pk *res = emv_pki_decode_key(pk, 4, tlvdb_get(db, 0x5a, NULL), tlvdb_get(db, 0x9f46, NULL), tlvdb_get(db, 0x9f47, NULL), tlvdb_get(db, 0x9f48, NULL), - sda_tlv); + sda_tlv, + &sda_tdata); + + free(sdatl); // malloc here: emv_pki_sdatl_fill + return res; } struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db) @@ -310,6 +328,7 @@ struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb tlvdb_get(db, 0x9f2d, NULL), tlvdb_get(db, 0x9f2e, NULL), tlvdb_get(db, 0x9f2f, NULL), + NULL, NULL); } @@ -358,6 +377,7 @@ struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct t unsigned char *data = emv_pki_decode_message(enc_pk, 3, &data_len, tlvdb_get(db, 0x93, NULL), + 3, sda_tlv, &sda_tdata, NULL); @@ -391,6 +411,7 @@ struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct t size_t data_len; unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len, tlvdb_get(db, 0x9f4b, NULL), + 2, dyn_tlv, NULL); @@ -426,6 +447,7 @@ struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct t size_t data_len; unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len, tlvdb_get(db, 0x9f4b, NULL), + 5, tlvdb_get(db, 0x9f37, NULL), tlvdb_get(db, 0x9f02, NULL), tlvdb_get(db, 0x5f2a, NULL), @@ -502,6 +524,7 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t size_t data_len = 0; unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len, tlvdb_get(this_db, 0x9f4b, NULL), + 2, un_tlv, NULL); if (!data || data_len < 3) { diff --git a/client/emv/emv_pki.h b/client/emv/emv_pki.h index 6fa7b12e9..f5d80bd6d 100644 --- a/client/emv/emv_pki.h +++ b/client/emv/emv_pki.h @@ -23,6 +23,7 @@ extern void PKISetStrictExecution(bool se); +unsigned char *emv_pki_sdatl_fill(const struct tlvdb *db, size_t *sdatl_len); struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db); struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv); struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db); From 0ac728f0d47ee644120c8e44df68663595b5be99 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 10 Jan 2019 13:06:56 +0200 Subject: [PATCH 09/14] VSDC path sketch --- client/emv/cmdemv.c | 11 +++++++++-- client/emv/emvcore.c | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 0cc6614d9..708e0d562 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -731,9 +731,9 @@ int CmdEMVExec(const char *cmd) { enum TransactionType TrType = TT_MSD; if (arg_get_lit(7)) - TrType = TT_QVSDCMCHIP; + TrType = TT_QVSDCMCHIP; if (arg_get_lit(8)) - TrType = TT_CDA; + TrType = TT_CDA; if (arg_get_lit(9)) TrType = TT_VSDC; @@ -1130,6 +1130,13 @@ int CmdEMVExec(const char *cmd) { } } + // VSDC + if (GetCardPSVendor(AID, AIDlen) == CV_VISA && (TrType == TT_VSDC)){ + PrintAndLogEx(NORMAL, "\n--> VSDC transaction."); + + + } + DropField(); // Destroy TLV's diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index c4b815715..a7d625af8 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -785,7 +785,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); if (dac_db) { const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL); - PrintAndLogEx(NORMAL, "SDA verified OK. (Data Authentication Code: %02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); + PrintAndLogEx(NORMAL, "SDAD verified OK. (Data Authentication Code: %02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); tlvdb_add(tlv, dac_db); } else { PrintAndLogEx(WARNING, "Error: SSAD verify error"); From 8240639d73bf1114c414fc2a6dcb190bc6dabe61 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 10 Jan 2019 13:22:27 +0200 Subject: [PATCH 10/14] fill VSDC with only AC1 --- client/emv/cmdemv.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 708e0d562..46ed20165 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -1134,6 +1134,34 @@ int CmdEMVExec(const char *cmd) { if (GetCardPSVendor(AID, AIDlen) == CV_VISA && (TrType == TT_VSDC)){ PrintAndLogEx(NORMAL, "\n--> VSDC transaction."); + PrintAndLogEx(NORMAL, "* * Calc CDOL1"); + struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag + if (!cdol_data_tlv) { + PrintAndLogEx(WARNING, "Error: can't create CDOL1 TLV."); + dreturn(6); + } + + PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len)); + + PrintAndLogEx(NORMAL, "* * AC1"); + // EMVAC_TC + EMVAC_CDAREQ --- to get SDAD + res = EMVAC(channel, 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); + + if (res) { + PrintAndLogEx(NORMAL, "AC1 error(%d): %4x. Exit...", res, sw); + dreturn(7); + } + + if (decodeTLV) + TLVPrintFromBuffer(buf, len); + + PrintAndLogEx(NORMAL, "\n* * Processing online request\n"); + + // authorization response code from acquirer + const char HostResponse[] = "0"; + PrintAndLogEx(NORMAL, "* * Host Response: `%s`", HostResponse); + tlvdb_change_or_add_node(tlvRoot, 0x8a, sizeof(HostResponse) - 1, (const unsigned char *)HostResponse); + } From 70744d2cbbdf412d97d1624b21c86cf52890c429 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 10 Jan 2019 13:26:15 +0200 Subject: [PATCH 11/14] small fix --- client/emv/cmdemv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 46ed20165..2274f3d69 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -1131,7 +1131,7 @@ int CmdEMVExec(const char *cmd) { } // VSDC - if (GetCardPSVendor(AID, AIDlen) == CV_VISA && (TrType == TT_VSDC)){ + if (GetCardPSVendor(AID, AIDlen) == CV_VISA && (TrType == TT_VSDC || TrType == TT_CDA)){ PrintAndLogEx(NORMAL, "\n--> VSDC transaction."); PrintAndLogEx(NORMAL, "* * Calc CDOL1"); @@ -1158,7 +1158,7 @@ int CmdEMVExec(const char *cmd) { PrintAndLogEx(NORMAL, "\n* * Processing online request\n"); // authorization response code from acquirer - const char HostResponse[] = "0"; + const char HostResponse[] = "00"; // 0x3030 PrintAndLogEx(NORMAL, "* * Host Response: `%s`", HostResponse); tlvdb_change_or_add_node(tlvRoot, 0x8a, sizeof(HostResponse) - 1, (const unsigned char *)HostResponse); From 607bef7ffd2be0403b907f7c720e531c5dbe7161 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 10 Jan 2019 16:22:32 +0200 Subject: [PATCH 12/14] AC Response Format1 --- client/emv/cmdemv.c | 53 ++++++++++++++++++++++++++++++++++++++++++--- client/emv/tlv.c | 15 +++++++++++-- client/emv/tlv.h | 1 + 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 2274f3d69..a30c22aec 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -38,6 +38,9 @@ void ParamLoadDefaults(struct tlvdb *tlvRoot) { TLV_ADD(0x9F6A, "\x01\x02\x03\x04"); //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4 TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC + //95:(Terminal Verification Results) len:5 + // all OK TVR + TLV_ADD(0x95, "\x00\x00\x00\x00\x00"); } void PrintChannel(EMVCommandChannel channel) { @@ -685,6 +688,50 @@ void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, } } +void ProcessACResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, bool decodeTLV) { + if (buf[0] == 0x80) { + if (decodeTLV){ + PrintAndLog("GPO response format1:"); + TLVPrintFromBuffer(buf, len); + } + + uint8_t elmlen = len - 2; // wo 0x80XX + + if (len < 4 + 2 || (elmlen - 2) % 4 || elmlen != buf[1]) { + PrintAndLogEx(ERR, "GPO response format1 parsing error. length=%d", len); + } else { + struct tlvdb *tlvElm = NULL; + if (decodeTLV) + PrintAndLog("\n------------ Format1 decoded ------------"); + + // CID (Cryptogram Information Data) + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f27, 1, &buf[2], &tlvElm); + if (decodeTLV) + TLVPrintFromTLV(tlvElm); + + // ATC (Application Transaction Counter) + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f36, 2, &buf[3], &tlvElm); + if (decodeTLV) + TLVPrintFromTLV(tlvElm); + + // AC (Application Cryptogram) + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f26, min(8, elmlen - 3), &buf[5], &tlvElm); + if (decodeTLV) + TLVPrintFromTLV(tlvElm); + + // IAD (Issuer Application Data) - optional + if (len > 11 + 2) { + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f10, elmlen - 11, &buf[13], &tlvElm); + if (decodeTLV) + TLVPrintFromTLV(tlvElm); + } + } + } else { + if (decodeTLV) + TLVPrintFromBuffer(buf, len); + } +} + int CmdEMVExec(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; @@ -1151,9 +1198,9 @@ int CmdEMVExec(const char *cmd) { PrintAndLogEx(NORMAL, "AC1 error(%d): %4x. Exit...", res, sw); dreturn(7); } - - if (decodeTLV) - TLVPrintFromBuffer(buf, len); + + // process Format1 (0x80) anf print Format2 (0x77) + ProcessACResponseFormat1(tlvRoot, buf, len, decodeTLV); PrintAndLogEx(NORMAL, "\n* * Processing online request\n"); diff --git a/client/emv/tlv.c b/client/emv/tlv.c index 013e9735a..9722c9311 100644 --- a/client/emv/tlv.c +++ b/client/emv/tlv.c @@ -359,12 +359,15 @@ void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other) tlvdb->next = other; } -void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value) +void tlvdb_change_or_add_node_ex(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value, struct tlvdb **tlvdb_elm) { struct tlvdb *telm = tlvdb_find_full(tlvdb, tag); if (telm == NULL) { // new tlv element - tlvdb_add(tlvdb, tlvdb_fixed(tag, len, value)); + struct tlvdb *elm = tlvdb_fixed(tag, len, value); + tlvdb_add(tlvdb, elm); + if (tlvdb_elm) + *tlvdb_elm = elm; } else { // the same tlv structure if (telm->tag.tag == tag && telm->tag.len == len && !memcmp(telm->tag.value, value, len)) @@ -400,11 +403,19 @@ void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, co // free old element with childrens telm->next = NULL; tlvdb_free(telm); + + if (tlvdb_elm) + *tlvdb_elm = tnewelm; } return; } +void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value) +{ + tlvdb_change_or_add_node_ex(tlvdb, tag, len, value, NULL); +} + void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level) { struct tlvdb *next = NULL; diff --git a/client/emv/tlv.h b/client/emv/tlv.h index d2a55525f..1f52e440b 100644 --- a/client/emv/tlv.h +++ b/client/emv/tlv.h @@ -50,6 +50,7 @@ struct tlvdb *tlvdb_find_path(struct tlvdb *tlvdb, tlv_tag_t tag[]); void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other); void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value); +void tlvdb_change_or_add_node_ex(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value, struct tlvdb **tlvdb_elm); void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level); const struct tlv *tlvdb_get(const struct tlvdb *tlvdb, tlv_tag_t tag, const struct tlv *prev); From 170cf7c67a49eeb3e976e5621ca6ec778c491d98 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 10 Jan 2019 17:06:59 +0200 Subject: [PATCH 13/14] inc timeout of card's response --- common/i2c.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/common/i2c.c b/common/i2c.c index 99f8b6e12..25b17b6bc 100644 --- a/common/i2c.c +++ b/common/i2c.c @@ -161,10 +161,11 @@ bool WaitSCL_L(void) { return WaitSCL_L_delay(15000); } -// Wait max 300ms or until SCL goes LOW. +// Wait max 1800ms or until SCL goes LOW. +// It timeout reading response from card // Which ever comes first -bool WaitSCL_L_300ms(void){ - volatile uint16_t delay = 310; +bool WaitSCL_L_timeout(void){ + volatile uint16_t delay = 1800; while ( delay-- ) { // exit on SCL LOW if (!SCL_read) @@ -193,7 +194,8 @@ bool I2C_Start(void) { bool I2C_WaitForSim() { - if (!WaitSCL_L_300ms()) + // wait for data from card + if (!WaitSCL_L_timeout()) return false; // 8051 speaks with smart card. From cada4e4877a5c311216416c7425c5623ba39f0ae Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Thu, 10 Jan 2019 17:24:45 +0200 Subject: [PATCH 14/14] DDA works --- client/emv/emvcore.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index a7d625af8..5ea9026c2 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -829,9 +829,16 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { if (len < 3 ) { PrintAndLogEx(WARNING, "Error: Internal Authenticate format1 parsing error. length=%d", len); } else { + // parse response 0x80 + struct tlvdb *t80 = tlvdb_parse_multi(buf, len); + const struct tlv * t80tlv = tlvdb_get_tlv(t80); + // 9f4b Signed Dynamic Application Data - dda_db = tlvdb_fixed(0x9f4b, len - 2, buf + 2); + dda_db = tlvdb_fixed(0x9f4b, t80tlv->len, t80tlv->value); tlvdb_add(tlv, dda_db); + + tlvdb_free(t80); + if (decodeTLV){ PrintAndLogEx(NORMAL, "* * Decode response format 1:"); TLVPrintFromTLV(dda_db);