From 667a1beafb326f8a2340444b84df53b9d1c7c67b Mon Sep 17 00:00:00 2001 From: merlokk Date: Tue, 5 Dec 2017 18:13:32 +0200 Subject: [PATCH] SDA works --- client/emv/cmdemv.c | 27 +++++++++++++++++++++++++-- client/emv/emv_tags.c | 2 +- client/emv/emvcore.c | 41 ++++++++++++++++++++++------------------- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 9659720a..3c427e3f 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -308,6 +308,8 @@ int CmdHFEMVExec(const char *cmd) { uint16_t sw = 0; uint8_t AID[APDU_AID_LEN] = {0}; size_t AIDlen = 0; + uint8_t ODAiList[4096]; + size_t ODAiListLen = 0; int res; @@ -568,9 +570,23 @@ int CmdHFEMVExec(const char *cmd) { PrintAndLog(""); } + // Build Input list for Offline Data Authentication + // EMV 4.3 book3 10.3, page 96 if (SFIoffline) { - // here will be offline records storing... - // dont foget: if (sfi < 11) + if (SFI < 11) { + const unsigned char *abuf = buf; + size_t elmlen = len; + struct tlv e; + if (tlv_parse_tl(&abuf, &elmlen, &e)) { + memcpy(&ODAiList[ODAiListLen], &buf[len - elmlen], elmlen); + ODAiListLen += elmlen; + } else { + PrintAndLog("ERROR SFI[%02x]. Creating input list for Offline Data Authentication error.", SFI); + } + } else { + memcpy(&ODAiList[ODAiListLen], buf, len); + ODAiListLen += len; + } } } } @@ -578,6 +594,13 @@ int CmdHFEMVExec(const char *cmd) { break; } + // copy Input list for Offline Data Authentication + if (ODAiListLen) { + struct tlvdb *oda = tlvdb_fixed(0x21, ODAiListLen, ODAiList); // not a standard tag + tlvdb_add(tlvRoot, oda); + PrintAndLog("* Input list for Offline Data Authentication added to TLV. len=%d \n", ODAiListLen); + } + // get AIP const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL); uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100; diff --git a/client/emv/emv_tags.c b/client/emv/emv_tags.c index 30b4068e..63d01993 100644 --- a/client/emv/emv_tags.c +++ b/client/emv/emv_tags.c @@ -177,7 +177,7 @@ static const struct emv_tag emv_tags[] = { { 0x01 , "", EMV_TAG_STRING }, // string for headers { 0x02 , "Raw data", }, // data { 0x20 , "Cardholder Verification Results (CVR)", EMV_TAG_CVR }, // not standard! - { 0x21 , "SDA data" }, // not standard! data for offline authentication from read records command + { 0x21 , "Input list for Offline Data Authentication" }, // not standard! data for "Offline Data Authentication" come from "read records" command. (EMV book3 10.3) // EMV { 0x41 , "Country code and national data" }, diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 5f268e8d..db334973 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -492,7 +492,7 @@ int trSDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv) { struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv); if (!issuer_pk) { - PrintAndLog("ERROR: Issuer certificate found. Exit."); + PrintAndLog("ERROR: Issuer certificate not found. Exit."); return 2; } @@ -510,14 +510,14 @@ int trSDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv) { const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL); if (!sda_tlv || sda_tlv->len < 1) { - PrintAndLog("ERROR: Can't find dynamic authentication data. Exit."); + PrintAndLog("ERROR: Can't find input list for Offline Data Authentication. Exit."); return 3; } 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); - PrintAndLog("SDA verified OK (%02hhx:%02hhx)!\n", dac_tlv->value[0], dac_tlv->value[1]); + PrintAndLog("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); tlvdb_add(tlv, dac_db); } else { PrintAndLog("ERROR: SSAD verify error"); @@ -538,27 +538,30 @@ int trDDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv) { const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL); if (!sda_tlv || sda_tlv->len < 1) { - PrintAndLog("ERROR: Can't find dynamic authentication data. Exit."); + PrintAndLog("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) - printf("Issuer PK recovered! RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", - issuer_pk->rid[0], - issuer_pk->rid[1], - issuer_pk->rid[2], - issuer_pk->rid[3], - issuer_pk->rid[4], - issuer_pk->index, - issuer_pk->serial[0], - issuer_pk->serial[1], - issuer_pk->serial[2] - ); + if (!issuer_pk) { + PrintAndLog("ERROR: Issuer certificate not found. Exit."); + return 2; + } + printf("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + issuer_pk->rid[0], + issuer_pk->rid[1], + issuer_pk->rid[2], + issuer_pk->rid[3], + issuer_pk->rid[4], + issuer_pk->index, + issuer_pk->serial[0], + issuer_pk->serial[1], + issuer_pk->serial[2] + ); struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv); if (icc_pk) - printf("ICC PK recovered! RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", icc_pk->rid[0], icc_pk->rid[1], icc_pk->rid[2], @@ -571,7 +574,7 @@ int trDDA(uint8_t *AID, size_t AIDlen, struct tlvdb *tlv) { ); struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv); if (icc_pe_pk) - printf("ICC PE PK recovered! RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + printf("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], @@ -585,7 +588,7 @@ int trDDA(uint8_t *AID, size_t AIDlen, 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); - printf("SDA verified OK (%02hhx:%02hhx)!\n", dac_tlv->value[0], dac_tlv->value[1]); + printf("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); tlvdb_add(tlv, dac_db); }