]> cvs.zerfleddert.de Git - proxmark3-svn/blobdiff - client/emv/emvcore.c
Fix format-truncation warning, missing string.h inclusion and strnlen warning (#723)
[proxmark3-svn] / client / emv / emvcore.c
index 08c6e3dbb53f5d57421897a35475ea9e0bb2a60f..c12591148766bd4c3ffd48ac66e185339b6879ae 100644 (file)
@@ -9,6 +9,8 @@
 //-----------------------------------------------------------------------------
 
 #include "emvcore.h"
+#include "emvjson.h"
+#include "util_posix.h"
 
 // Got from here. Thanks)
 // https://eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix
@@ -18,6 +20,13 @@ static const char *PSElist [] = {
 };
 //static const size_t PSElistLen = sizeof(PSElist)/sizeof(char*);
 
+char *TransactionTypeStr[] = {
+       "MSD",
+       "VSDC",
+       "qVCDCMCHIP",
+       "CDA"
+};
+
 typedef struct {
        enum CardPSVendor vendor;
        const char* aid;
@@ -221,15 +230,17 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) {
   return tlvdb_fixed(0x02, dCVVlen, dCVV);
 }
 
-int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
+int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
        uint8_t data[APDU_RES_LEN] = {0};
 
        *ResultLen = 0;
        if (sw) *sw = 0;
        uint16_t isw = 0;
        
-       if (ActivateField)
+       if (ActivateField){
                DropField();
+               msleep(50);
+       }
        
        // COMPUTE APDU
        memcpy(data, &apdu, 5);
@@ -237,10 +248,10 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, uint8_t *Re
                memcpy(&data[5], apdu.data, apdu.Lc);
        
        if (APDULogging)
-               PrintAndLog(">>>> %s", sprint_hex(data, 6 + apdu.Lc));
+               PrintAndLog(">>>> %s", sprint_hex(data, (IncludeLe?6:5) + apdu.Lc));
 
-       // 6 byes + data = INS + CLA + P1 + P2 + Lc + <data = Nc> + Le
-       int res = ExchangeAPDU14a(data, 6 + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
+       // 6 byes + data = INS + CLA + P1 + P2 + Lc + <data = Nc> + Le(?IncludeLe)
+       int res = ExchangeAPDU14a(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
        
        if (res) {
                return res;
@@ -255,9 +266,14 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, uint8_t *Re
                *sw = isw;
 
        if (isw != 0x9000) {
-               if (APDULogging)
-                       PrintAndLog("APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff));
-               return 5;
+               if (APDULogging) {
+                       if (*sw >> 8 == 0x61) {
+                               PrintAndLog("APDU chaining len:%02x -->", *sw & 0xff);
+                       } else {
+                               PrintAndLog("APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff));
+                               return 5;
+                       }
+               }
        }
 
        // add to tlv tree
@@ -270,11 +286,11 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, uint8_t *Re
 }
 
 int EMVExchange(bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
-       return EMVExchangeEx(false, LeaveFieldON, apdu, Result, MaxResultLen, ResultLen, sw, tlv);
+       return EMVExchangeEx(false, LeaveFieldON, apdu, true, Result, MaxResultLen, ResultLen, sw, tlv);
 }
 
 int EMVSelect(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) {
-       return EMVExchangeEx(ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, Result, MaxResultLen, ResultLen, sw, tlv);
+       return EMVExchangeEx(ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, true, Result, MaxResultLen, ResultLen, sw, tlv);
 }
 
 int EMVSelectPSE(bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
@@ -453,7 +469,12 @@ int EMVGPO(bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, si
 }
 
 int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
-       return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
+       int res = EMVExchange(LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
+       if (*sw == 0x6700) {
+               PrintAndLog(">>> trying to reissue command withouth Le...");
+               res = EMVExchangeEx(false, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv);
+       }
+       return res;
 }
 
 int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
@@ -461,7 +482,12 @@ int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen,
 }
 
 int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
-       return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
+       int res = EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
+       if (*sw == 0x6700) {
+               PrintAndLog(">>> trying to reissue command withouth Le...");
+               res = EMVExchangeEx(false, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv);
+       }
+       return res;
 }
 
 int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
@@ -839,3 +865,63 @@ int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, st
        emv_pk_free(icc_pk);
        return 0;
 }
+
+int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) {
+       
+       struct emv_pk *pk = get_ca_pk(tlvRoot);
+       if (!pk) {
+               PrintAndLog("ERROR: Key not found. Exit.");
+               return 1;
+       }
+
+       struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlvRoot);
+       if (!issuer_pk) {
+               emv_pk_free(pk);
+               PrintAndLog("WARNING: Issuer certificate not found. Exit.");
+               return 2;
+       }
+       PrintAndLog("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx",
+                       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]
+                       );
+
+       JsonSaveBufAsHex(root, "$.ApplicationData.RID", issuer_pk->rid, 5);
+
+       char *issuer_pk_c = emv_pk_dump_pk(issuer_pk);
+       JsonSaveStr(root, "$.ApplicationData.IssuerPublicKeyDec", issuer_pk_c);
+       JsonSaveBufAsHex(root, "$.ApplicationData.IssuerPublicKeyModulus", issuer_pk->modulus, issuer_pk->mlen);
+       free(issuer_pk_c);
+
+       struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlvRoot, NULL);
+       if (!icc_pk) {
+               emv_pk_free(pk);
+               emv_pk_free(issuer_pk);
+               PrintAndLog("WARNING: ICC certificate not found. Exit.");
+               return 2;
+       }
+       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],
+                       icc_pk->rid[3],
+                       icc_pk->rid[4],
+                       icc_pk->index,
+                       icc_pk->serial[0],
+                       icc_pk->serial[1],
+                       icc_pk->serial[2]
+                       );
+       
+       char *icc_pk_c = emv_pk_dump_pk(icc_pk);
+       JsonSaveStr(root, "$.ApplicationData.ICCPublicKeyDec", icc_pk_c);
+       JsonSaveBufAsHex(root, "$.ApplicationData.ICCPublicKeyModulus", icc_pk->modulus, icc_pk->mlen);
+       free(issuer_pk_c);
+       
+       return 0;
+}
Impressum, Datenschutz