]> git.zerfleddert.de Git - proxmark3-svn/commitdiff
EVM fixes and additions (RRG repository PRs 78-82 by @merlokk) (#776)
authorpwpiwi <pwpiwi@users.noreply.github.com>
Wed, 6 Feb 2019 06:50:57 +0000 (07:50 +0100)
committerGitHub <noreply@github.com>
Wed, 6 Feb 2019 06:50:57 +0000 (07:50 +0100)
armsrc/i2c.c
client/cmdsmartcard.c
client/emv/cmdemv.c
client/emv/emv_pki.c
client/emv/emv_pki.h
client/emv/emv_roca.c
client/emv/emv_roca.h
client/emv/emvcore.c
client/emv/test/cryptotest.c
client/emv/tlv.c
client/emv/tlv.h

index 7ef0c9c035ce767bfe8cd39b7f4e6a2cec021d5e..51513114d3e81494e626714a24ca0388b37e32d0 100644 (file)
@@ -257,10 +257,11 @@ static void I2C_Reset_EnterBootloader(void) {
        WaitMS(10);
 }
 
-// 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
-static 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)
@@ -272,8 +273,8 @@ static bool WaitSCL_L_300ms(void) {
 }
 
 static bool I2C_WaitForSim() {
-       // variable delay here.
-       if (!WaitSCL_L_300ms())
+       // wait for data from card
+       if (!WaitSCL_L_timeout())
                return false;
 
        // 8051 speaks with smart card.
index 90a219ab6974572eacf2d5b1e10841f60b7dd4a5..53ee9119fc2080b645d765cb50fd6a1fe7fdcc3f 100644 (file)
@@ -570,7 +570,7 @@ int ExchangeAPDUSC(uint8_t *APDU, int APDUlen, bool activateCard, bool leaveSign
        }
 
        if (*responselen < 0 ) {
-               return 2;
+               return 1;
        } else {
                return 0;
        }
index 16835ba87a441c15ca8ed2f597513326416f9c5a..832df82e24aacca613e914b094874008c0843ad1 100644 (file)
@@ -42,6 +42,20 @@ 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) {
+       switch(channel) {
+       case ECC_CONTACTLESS:
+               PrintAndLogEx(INFO, "Channel: CONTACTLESS");
+               break;
+       case ECC_CONTACT:
+               PrintAndLogEx(INFO, "Channel: CONTACT");
+               break;
+       }
 }
 
 int CmdEMVSelect(const char *cmd) {
@@ -74,6 +88,7 @@ int CmdEMVSelect(const char *cmd) {
 #ifdef WITH_SMARTCARD
        if (arg_get_lit(5))
                channel = ECC_CONTACT;
+       PrintChannel(channel);
        CLIGetHexWithReturn(6, data, &datalen);
 #else
        CLIGetHexWithReturn(5, data, &datalen);
@@ -128,6 +143,7 @@ int CmdEMVSearch(const char *cmd) {
        if (arg_get_lit(5))
                channel = ECC_CONTACT;
 #endif
+       PrintChannel(channel);
        CLIParserFree();
        
        SetAPDULogging(APDULogging);
@@ -188,6 +204,7 @@ int CmdEMVPPSE(const char *cmd) {
        if (arg_get_lit(7))
                channel = ECC_CONTACT;
 #endif
+       PrintChannel(channel);
        CLIParserFree();    
        
        SetAPDULogging(APDULogging);
@@ -249,6 +266,7 @@ int CmdEMVGPO(const char *cmd) {
 #else
        CLIGetHexWithReturn(6, data, &datalen);
 #endif
+       PrintChannel(channel);
        CLIParserFree();    
        
        SetAPDULogging(APDULogging);
@@ -346,6 +364,7 @@ int CmdEMVReadRecord(const char *cmd) {
 #else
        CLIGetHexWithReturn(4, data, &datalen);
 #endif
+       PrintChannel(channel);
        CLIParserFree();
        
        if (datalen != 2) {
@@ -434,6 +453,7 @@ int CmdEMVAC(const char *cmd) {
 #else
        CLIGetHexWithReturn(8, data, &datalen);
 #endif
+       PrintChannel(channel);
        CLIParserFree();    
        
        SetAPDULogging(APDULogging);
@@ -519,6 +539,7 @@ int CmdEMVGenerateChallenge(const char *cmd) {
        if (arg_get_lit(3))
                channel = ECC_CONTACT;
 #endif
+       PrintChannel(channel);
        CLIParserFree();    
        
        SetAPDULogging(APDULogging);
@@ -584,6 +605,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
 #else
        CLIGetHexWithReturn(6, data, &datalen);
 #endif
+       PrintChannel(channel);
        CLIParserFree();    
        
        SetAPDULogging(APDULogging);
@@ -710,6 +732,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_RESPONSE_LEN] = {0};
        size_t len = 0;
@@ -768,6 +834,7 @@ int CmdEMVExec(const char *cmd) {
        if (arg_get_lit(11))
                channel = ECC_CONTACT;
 #endif
+       PrintChannel(channel);
        uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
        char *PSE_or_PPSE = psenum == 1 ? "PSE" : "PPSE";
        
@@ -898,7 +965,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;
@@ -920,7 +987,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;
@@ -935,6 +1002,8 @@ int CmdEMVExec(const char *cmd) {
                                                memcpy(&ODAiList[ODAiListLen], buf, len);
                                                ODAiListLen += len;
                                        }
+                                       
+                                       SFIoffline--;
                                }
                        }
                }
@@ -1154,6 +1223,40 @@ int CmdEMVExec(const char *cmd) {
                }
        }
 
+       // VSDC
+       if (GetCardPSVendor(AID, AIDlen) == CV_VISA && (TrType == TT_VSDC || TrType == TT_CDA)){
+               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);
+               }
+
+               // process Format1 (0x80) and print Format2 (0x77)
+               ProcessACResponseFormat1(tlvRoot, buf, len, decodeTLV);
+               
+               PrintAndLogEx(NORMAL, "\n* * Processing online request\n");
+
+               // authorization response code from acquirer
+               const char HostResponse[] = "00"; //0 x3030
+               PrintAndLogEx(NORMAL, "* * Host Response: `%s`", HostResponse);
+               tlvdb_change_or_add_node(tlvRoot, 0x8a, sizeof(HostResponse) - 1, (const unsigned char *)HostResponse);         
+               
+       }
+
        if (channel == ECC_CONTACTLESS) {
                DropField();
        }
@@ -1230,6 +1333,7 @@ int CmdEMVScan(const char *cmd) {
 #else
        CLIGetStrWithReturn(11, relfname, &relfnamelen);
 #endif
+       PrintChannel(channel);
        uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
        CLIParserFree();
        
@@ -1535,10 +1639,13 @@ int CmdEMVRoca(const char *cmd) {
        CLIParserInit("emv roca", 
                "Tries to extract public keys and run the ROCA test against them.\n", 
                "Usage:\n"
-                       "\temv roca -w -> select CONTACT card and run test\n\temv roca -> select CONTACTLESS card and run test\n");
+                       "\temv roca -w -> select --CONTACT-- card and run test\n"
+                       "\temv roca -> select --CONTACTLESS-- card and run test\n"
+       );
 
        void* argtable[] = {
                arg_param_begin,
+               arg_lit0("tT",  "selftest",   "self test"),
                arg_lit0("wW",  "wired",   "Send data via contact (iso7816) interface. Contactless interface set by default."),
                arg_param_end
        };
@@ -1546,10 +1653,16 @@ int CmdEMVRoca(const char *cmd) {
        
        EMVCommandChannel channel = ECC_CONTACTLESS;
        if (arg_get_lit(1))
+        return roca_self_test();
+#ifdef WITH_SMARTCARD
+    if (arg_get_lit(2))
                channel = ECC_CONTACT;
+#endif
+       PrintChannel(channel);
 
        // select card
        uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
+       char *PSE_or_PPSE = psenum == 1 ? "PSE" : "PPSE";
        
        SetAPDULogging(false);
        
@@ -1557,18 +1670,18 @@ int CmdEMVRoca(const char *cmd) {
        const char *al = "Applets list";
        struct tlvdb *tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al);
 
-       // EMV PPSE
-       PrintAndLogEx(NORMAL, "--> PPSE.");
-       res = EMVSearchPSE(channel, false, true, psenum, false, tlvSelect);
+       // EMV PSE/PPSE
+       PrintAndLogEx(NORMAL, "--> %s.", PSE_or_PPSE);
+       res = EMVSearchPSE(channel, true, true, psenum, false, tlvSelect);
 
-       // check PPSE and select application id
+       // check PSE/PPSE and select application id
        if (!res) {     
                TLVPrintAIDlistFromSelectTLV(tlvSelect);                
        } else {
                // EMV SEARCH with AID list
                PrintAndLogEx(NORMAL, "--> AID search.");
                if (EMVSearch(channel, false, true, false, tlvSelect)) {
-                       PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit...");
+                       PrintAndLogEx(ERR, "Couldn't find any known EMV AID. Exit...");
                        tlvdb_free(tlvSelect);
                        DropField();
                        return 3;
@@ -1579,7 +1692,7 @@ int CmdEMVRoca(const char *cmd) {
        }
 
        // EMV SELECT application
-       SetAPDULogging(false);
+       SetAPDULogging(true);
        EMVSelectApplication(tlvSelect, AID, &AIDlen);
 
        tlvdb_free(tlvSelect);
index da102291876fd69a29dcd4a78585dd6074ecb2e5..1ff1e4c6b36ee40135d388ad0b9b43bc607b0300 100644 (file)
@@ -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,20 +100,23 @@ 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);
        }
        va_end(vl);
 
-       if (memcmp(data + data_len - 1 - hash_len, crypto_hash_read(ch), hash_len)) {
+       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");
                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);
@@ -165,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
                )
 {
@@ -190,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");
@@ -275,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)
@@ -287,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)
@@ -307,17 +328,62 @@ 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);
 }
 
+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),
+                       3,
                        sda_tlv,
+                       &sda_tdata,
                        NULL);
 
+       free(sdatl); // malloc here: emv_pki_sdatl_fill
+       
        if (!data || data_len < 5)
                return NULL;
 
@@ -345,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);
 
@@ -380,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),
@@ -456,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) {
index 6fa7b12e95efbcf9d9f4af719fe3a846607d809d..f5d80bd6dc92834bf907dbb3dc1bfcb5f54779a7 100644 (file)
@@ -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);
index 3701ddf8ba58781a1582f3cd7376e0bd162c7b28..bc317db8dd5931bd8b82b6afd4a9946f630363c8 100644 (file)
@@ -28,6 +28,7 @@
 #include <stdbool.h>
 
 #include "ui.h"
+#include "util.h"
 #include "mbedtls/bignum.h"
 
 
@@ -146,11 +147,10 @@ cleanup:
        return ret;
 }
 
-int roca_self_test( int verbose ) {
+int roca_self_test( void ) {
        int ret = 0;
 
-       if( verbose != 0 )
-               printf( "\nROCA check vulnerability tests\n" );
+       PrintAndLogEx(INFO, "ROCA check vulnerability tests" );
 
        // positive
        uint8_t keyp[] = "\x94\x4e\x13\x20\x8a\x28\x0c\x37\xef\xc3\x1c\x31\x14\x48\x5e\x59"\
@@ -158,16 +158,13 @@ int roca_self_test( int verbose ) {
                                        "\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\
                                        "\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7";
 
-       if( verbose != 0 )
-               printf( "  ROCA positive test: " );
        
        if (emv_rocacheck(keyp, 64, false)) {
-               if( verbose != 0 )
-                       printf( "passed\n" );
-       } else {
-               ret = 1;
-               if( verbose != 0 )
-                       printf( "failed\n" );
+               PrintAndLogEx(SUCCESS, "Weak modulus [ %s]", _GREEN_(PASS) );   
+       }
+       else {
+               ret++;
+               PrintAndLogEx(FAILED, "Weak modulus [ %s]", _RED_(FAIL) );
        }
 
        // negative
@@ -176,18 +173,12 @@ int roca_self_test( int verbose ) {
                                        "\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\
                                        "\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7";
 
-       if( verbose != 0 )
-               printf( "  ROCA negative test: " );
-
        if (emv_rocacheck(keyn, 64, false)) {
-               ret = 1;
-               if( verbose != 0 )
-                       printf( "failed\n" );
+               ret++;
+               PrintAndLogEx(FAILED, "Strong modulus [ %s]", _RED_(FAIL) );
        } else {
-               if( verbose != 0 )
-                       printf( "passed\n" );
+               PrintAndLogEx(SUCCESS, "Strong modulus [ %s]", _GREEN_(PASS) ); 
        }
 
-       
        return ret;
 }
index b0b9a0eae09a9137ac6d803b4ae7dd3e1049a383..2bb391f3b29477952446aa2362f77122368ad027 100644 (file)
@@ -30,7 +30,7 @@
 #define ROCA_PRINTS_LENGTH     17
 
 extern bool emv_rocacheck( const unsigned char *buf, size_t buflen, bool verbose );
-extern int roca_self_test( int verbose );
+extern int roca_self_test( void );
 
 #endif
 
index 78a30206662ed873fa797bf7f06bd8c42aadf605..8deb4aa69eaabf5e8ed8114c8ba79b54491650f5 100644 (file)
@@ -387,11 +387,76 @@ int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO
        return res;
 }
 
+
+int EMVSelectWithRetry(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
+       int retrycnt = 0;
+       int res = 0;
+       do {
+               res = EMVSelect(channel, false, true, AID, AIDLen, Result, MaxResultLen, ResultLen, sw, tlv);
+
+               // retry if error and not returned sw error
+               if (res && res != 5) {
+                       if (++retrycnt < 3){
+                               continue;
+                       } else {
+                               // card select error, proxmark error
+                               if (res == 1) {
+                                       PrintAndLogEx(WARNING, "Exit...");
+                                       return 1;
+                               }
+                               
+                               retrycnt = 0;
+                               PrintAndLogEx(NORMAL, "Retry failed [%s]. Skiped...", sprint_hex_inrow(AID, AIDLen));
+                               return res;
+                       }       
+               }
+       } while (res && res != 5);
+
+       return res;
+}
+
+
+int EMVCheckAID(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlvdbelm, struct tlvdb *tlv){
+       uint8_t data[APDU_RESPONSE_LEN] = {0};
+       size_t datalen = 0;
+       int res = 0;
+       uint16_t sw = 0;
+
+       while (tlvdbelm) {
+               const struct tlv *tgAID = tlvdb_get_inchild(tlvdbelm, 0x4f, NULL);
+               if (tgAID) {
+                       res = EMVSelectWithRetry(channel, false, true, (uint8_t *)tgAID->value, tgAID->len, data, sizeof(data), &datalen, &sw, tlv);
+
+                       // if returned sw error
+                       if (res == 5) {
+                               // next element
+                               tlvdbelm = tlvdb_find_next(tlvdbelm, 0x61);
+                               continue;
+                       }
+                       
+                       if (res)
+                               break;
+
+                       // all is ok
+                       if (decodeTLV){
+                               PrintAndLogEx(NORMAL, "%s:", sprint_hex_inrow(tgAID->value, tgAID->len));
+                               TLVPrintFromBuffer(data, datalen);
+                       }
+               }
+               tlvdbelm = tlvdb_find_next(tlvdbelm, 0x61);
+       }
+       return res;
+}
+
+
 int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) {
        uint8_t data[APDU_RESPONSE_LEN] = {0};
        size_t datalen = 0;
+       uint8_t sfidata[0x11][APDU_RESPONSE_LEN] = {0};
+       size_t sfidatalen[0x11] = {0};
        uint16_t sw = 0;
        int res;
+       bool fileFound = false;
 
        char *PSE_or_PPSE = PSENum == 1 ? "PSE" : "PPSE";
        
@@ -399,50 +464,73 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO
        res = EMVSelectPSE(channel, ActivateField, true, PSENum, data, sizeof(data), &datalen, &sw);
 
        if (!res){
+               if (sw != 0x9000) {
+                       PrintAndLogEx(FAILED, "Select PSE error. APDU error: %04x.", sw);
+                       return 1;
+               }
+               
                struct tlvdb *t = NULL;
                t = tlvdb_parse_multi(data, datalen);
                if (t) {
-                       int retrycnt = 0;
-                       struct tlvdb *ttmp = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0xbf0c, 0x61, 0x00});
-                       if (!ttmp)
-                               PrintAndLogEx(FAILED, "%s doesn't have any records.", PSE_or_PPSE);
-
-                       while (ttmp) {
-                               const struct tlv *tgAID = tlvdb_get_inchild(ttmp, 0x4f, NULL);
-                               if (tgAID) {
-                                       res = EMVSelect(channel, false, true, (uint8_t *)tgAID->value, tgAID->len, data, sizeof(data), &datalen, &sw, tlv);
-
-                                       // retry if error and not returned sw error
-                                       if (res && res != 5) {
-                                               if (++retrycnt < 3){
-                                                       continue;
-                                               } else {
-                                                       // card select error, proxmark error
-                                                       if (res == 1) {
-                                                               PrintAndLogEx(WARNING, "Exit...");
-                                                               return 1;
-                                                       }
-
-                                                       retrycnt = 0;
-                                                       PrintAndLogEx(NORMAL, "Retry failed [%s]. Skiped...", sprint_hex_inrow(tgAID->value, tgAID->len));
-                                               }
-
-                                               // next element
-                                               ttmp = tlvdb_find_next(ttmp, 0x61);
-                                               continue;
+                       // PSE/PPSE with SFI
+                       struct tlvdb *tsfi = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0x88, 0x00});
+                       if (tsfi) {
+                               uint8_t sfin = 0;
+                               tlv_get_uint8(tlvdb_get_tlv(tsfi), &sfin);
+                               PrintAndLogEx(INFO, "* PPSE get SFI: 0x%02x.", sfin);
+                               
+                               for (uint8_t ui = 0x01; ui <= 0x10; ui++) {
+                                       PrintAndLogEx(INFO, "* * Get SFI: 0x%02x. num: 0x%02x", sfin, ui);
+                                       res = EMVReadRecord(channel, true, sfin, ui, sfidata[ui], APDU_RESPONSE_LEN, &sfidatalen[ui], &sw, NULL);
+                                       
+                                       // end of records
+                                       if (sw == 0x6a83) {
+                                               sfidatalen[ui] = 0;
+                                               PrintAndLogEx(INFO, "* * PPSE get SFI. End of records.");
+                                               break;
+                                       }
+                                       
+                                       // error catch!
+                                       if (sw != 0x9000) {
+                                               sfidatalen[ui] = 0;
+                                               PrintAndLogEx(FAILED, "PPSE get Error. APDU error: %04x.", sw);
+                                               break;
                                        }
-                                       retrycnt = 0;
 
-                                       // all is ok
                                        if (decodeTLV){
-                                               PrintAndLogEx(NORMAL, "%s:", sprint_hex_inrow(tgAID->value, tgAID->len));
-                                               TLVPrintFromBuffer(data, datalen);
+                                               TLVPrintFromBuffer(sfidata[ui], sfidatalen[ui]);
                                        }
                                }
 
-                               ttmp = tlvdb_find_next(ttmp, 0x61);
+                               for (uint8_t ui = 0x01; ui <= 0x10; ui++) {
+                                       if (sfidatalen[ui]) {
+                                               struct tlvdb *tsfi = NULL;
+                                               tsfi = tlvdb_parse_multi(sfidata[ui], sfidatalen[ui]);
+                                               if (tsfi) {
+                                                       struct tlvdb *tsfitmp = tlvdb_find_path(tsfi, (tlv_tag_t[]){0x70, 0x61, 0x00});
+                                                       if (!tsfitmp) {
+                                                               PrintAndLogEx(FAILED, "SFI 0x%02d doesn't have any records.", sfidatalen[ui]);
+                                                               continue;
+                                                       }
+                                                       res = EMVCheckAID(channel, decodeTLV, tsfitmp, tlv);                                                    
+                                                       fileFound = true;
+                                               }
+                                               tlvdb_free(tsfi);
+                                       }
+                               }
                        }
 
+
+                       // PSE/PPSE plain (wo SFI)
+                       struct tlvdb *ttmp = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0xbf0c, 0x61, 0x00});
+                       if (ttmp) {
+                               res = EMVCheckAID(channel, decodeTLV, ttmp, tlv);
+                               fileFound = true;
+                       }
+                       
+                       if (!fileFound)
+                               PrintAndLogEx(FAILED, "PPSE doesn't have any records.");
+
                        tlvdb_free(t);
                } else {
                        PrintAndLogEx(WARNING, "%s ERROR: Can't get TLV from response.", PSE_or_PPSE);
@@ -650,7 +738,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);
@@ -679,12 +767,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);
@@ -707,7 +795,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",
@@ -722,21 +810,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
@@ -778,7 +870,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, "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");
@@ -822,9 +914,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);
index b0212a70b453fe7d5a478c24eb834ae1c218684d..58cbdd4b9692055d5b0ddd18d2b1038e2b001282 100644 (file)
@@ -91,14 +91,14 @@ int ExecuteCryptoTests(bool verbose) {
        res = exec_crypto_test(verbose);
        if (res) TestFail = true;
 
-       res = roca_self_test(verbose);
+       res = roca_self_test();
        if (res) TestFail = true;
 
        PrintAndLog("\n--------------------------");
        if (TestFail)
-               PrintAndLog("Test(s) [ERROR].");
+               PrintAndLogEx(FAILED, "\tTest(s) [ %s ]", _RED_(FAIL) );
        else
-               PrintAndLog("Tests [OK].");
+               PrintAndLogEx(SUCCESS, "\tTest(s) [ %s ]", _GREEN_(OK) );
        
        return TestFail;
 }
index 35bdb5d4cca05d161fca1c54cef0b6c7afe862c0..9722c9311ec9cd485daab3527c7e9b245781b12b 100644 (file)
@@ -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;
@@ -534,3 +545,40 @@ struct tlvdb *tlvdb_elm_get_parent(struct tlvdb *tlvdb)
 {
        return tlvdb->parent;
 }
+
+bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value) 
+{
+       *value = 0;
+       if (etlv)
+       {
+               if (etlv->len == 0)
+                       return true;
+               
+               if (etlv->len == 1)
+               {
+                       *value = etlv->value[0];
+                       return true;
+               }
+       }
+       return false;
+}
+
+bool tlv_get_int(const struct tlv *etlv, int *value)
+{
+       *value = 0;
+       if (etlv)
+       {
+               if (etlv->len == 0)
+                       return true;
+               
+               if (etlv->len <= 4)
+               {
+                       for (int i = 0; i < etlv->len; i++)
+                       {
+                               *value += etlv->value[i] * (1 << (i * 8));
+                       }
+                       return true;
+               }
+       }
+       return false;
+}
index b25b51de262bc9da873f32dd672ac96d030d1197..80f6b74faee6134520a51fac5fd788ecb96a89f2 100644 (file)
@@ -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);
@@ -61,4 +62,10 @@ unsigned char *tlv_encode(const struct tlv *tlv, size_t *len);
 bool tlv_is_constructed(const struct tlv *tlv);
 bool tlv_equal(const struct tlv *a, const struct tlv *b);
 
+bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value);
+bool tlv_get_int(const struct tlv *etlv, int *value);
+
+bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value);
+bool tlv_get_int(const struct tlv *etlv, int *value);
+
 #endif
Impressum, Datenschutz