From 7726ec60006f29a58ee287ed0e1cc33615ab38b8 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 16 Jul 2019 16:05:47 +0300 Subject: [PATCH 1/5] move sAPDU --- client/emv/apduinfo.h | 9 +++++++++ client/emv/emvcore.h | 9 --------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/client/emv/apduinfo.h b/client/emv/apduinfo.h index b81877366b..b2d323e5b9 100644 --- a/client/emv/apduinfo.h +++ b/client/emv/apduinfo.h @@ -34,6 +34,15 @@ typedef struct { const APDUCode *GetAPDUCode(uint8_t sw1, uint8_t sw2); const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2); +typedef struct { + uint8_t CLA; + uint8_t INS; + uint8_t P1; + uint8_t P2; + uint8_t Lc; + uint8_t *data; +} PACKED sAPDU; + typedef struct { uint8_t cla; uint8_t ins; diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h index 219c3f9b5b..3faae283d2 100644 --- a/client/emv/emvcore.h +++ b/client/emv/emvcore.h @@ -45,15 +45,6 @@ enum TransactionType { }; extern const char *TransactionTypeStr[]; -typedef struct { - uint8_t CLA; - uint8_t INS; - uint8_t P1; - uint8_t P2; - uint8_t Lc; - uint8_t *data; -} sAPDU; - enum CardPSVendor { CV_NA, CV_VISA, From a30c62137b53be28370112cb35ab3ed916bc57c5 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 16 Jul 2019 17:04:54 +0300 Subject: [PATCH 2/5] use apduencode for emv commands --- client/emv/apduinfo.c | 24 ++++++++++++++++++++++++ client/emv/apduinfo.h | 1 + client/emv/emvcore.c | 26 ++++++++++++-------------- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/client/emv/apduinfo.c b/client/emv/apduinfo.c index 469078456d..2449391b72 100644 --- a/client/emv/apduinfo.c +++ b/client/emv/apduinfo.c @@ -467,6 +467,30 @@ int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len) { return 0; } +int APDUEncodeS(sAPDU *sapdu, bool extended, uint16_t le, uint8_t *data, int *len) { + if (extended && le > 0x100) + return 10; + + APDUStruct apdu; + + apdu.cla = sapdu->CLA; + apdu.ins = sapdu->INS; + apdu.p1 = sapdu->P1; + apdu.p2 = sapdu->P2; + + apdu.lc = sapdu->Lc; + if (sapdu->Lc) + apdu.data = sapdu->data; + else + apdu.data = NULL; + apdu.le = le; + + apdu.extended_apdu = extended; + apdu.case_type = 0x00; + + return APDUEncode(&apdu, data, len); +} + void APDUPrint(APDUStruct apdu) { APDUPrintEx(apdu, 0); } diff --git a/client/emv/apduinfo.h b/client/emv/apduinfo.h index b2d323e5b9..25d062dcf1 100644 --- a/client/emv/apduinfo.h +++ b/client/emv/apduinfo.h @@ -65,6 +65,7 @@ typedef struct { extern int APDUDecode(uint8_t *data, int len, APDUStruct *apdu); extern int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len); +extern int APDUEncodeS(sAPDU *apdu, bool extended, uint16_t le, uint8_t *data, int *len); extern void APDUPrint(APDUStruct apdu); extern void APDUPrintEx(APDUStruct apdu, size_t maxdatalen); diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 2d96b567aa..e7c2690b73 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -277,24 +277,22 @@ static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool Lea } // COMPUTE APDU - memcpy(data, &apdu, 5); - if (apdu.data) - memcpy(&data[5], apdu.data, apdu.Lc); + int datalen = 0; + APDUEncodeS(&apdu, false, IncludeLe ? 0x100 : 0x00, data, &datalen); if (APDULogging) - PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, (IncludeLe ? 6 : 5) + apdu.Lc)); + PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen)); switch (channel) { case ECC_CONTACTLESS: - // 6 byes + data = INS + CLA + P1 + P2 + Lc + + Le(?IncludeLe) - res = ExchangeAPDU14a(data, (IncludeLe ? 6 : 5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + res = ExchangeAPDU14a(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); if (res) { return res; } break; case ECC_CONTACT: if (IfPm3Smartcard()) - res = ExchangeAPDUSC(data, (IncludeLe ? 6 : 5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + res = ExchangeAPDUSC(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); else res = 1; if (res) { @@ -336,7 +334,7 @@ static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool Lea } int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchangeEx(channel, false, LeaveFieldON, apdu, (channel == ECC_CONTACTLESS), Result, MaxResultLen, ResultLen, sw, tlv); + return EMVExchangeEx(channel, false, LeaveFieldON, apdu, false, Result, MaxResultLen, ResultLen, sw, tlv); } int EMVSelect(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) { @@ -609,9 +607,9 @@ int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t P } int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - int res = EMVExchange(channel, LeaveFieldON, (sAPDU) {0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); - if (*sw == 0x6700) { - PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le..."); + int res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, true, Result, MaxResultLen, ResultLen, sw, tlv); + if (*sw == 0x6700 || *sw == 0x6f00) { + PrintAndLogEx(INFO, ">>> trying to reissue command without Le..."); res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); } return res; @@ -622,9 +620,9 @@ int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint } int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - int res = EMVExchange(channel, LeaveFieldON, (sAPDU) {0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); - if (*sw == 0x6700) { - PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le..."); + int res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x00, 0x84, 0x00, 0x00, 0x00, NULL}, true, Result, MaxResultLen, ResultLen, sw, tlv); + if (*sw == 0x6700 || *sw == 0x6f00) { + PrintAndLogEx(INFO, ">>> trying to reissue command without Le..."); res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); } return res; From e61a65fbe87c4f232ca4cc48472539d5c3dbfd6c Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 16 Jul 2019 17:15:32 +0300 Subject: [PATCH 3/5] check PPSE instead of PSE and vice versa. I have one card with this strange behavior... --- client/emv/cmdemv.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 0b50ecfe1f..5ac9adb00c 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -829,6 +829,12 @@ static int CmdEMVExec(const char *Cmd) { PrintAndLogEx(NORMAL, "\n* PPSE."); SetAPDULogging(showAPDU); res = EMVSearchPSE(channel, activateField, true, psenum, decodeTLV, tlvSelect); + + // check PPSE instead of PSE and vice versa + if (res) { + PrintAndLogEx(NORMAL, "Check PPSE instead of PSE and vice versa..."); + res = EMVSearchPSE(channel, false, true, psenum == 1 ? 2 : 1, decodeTLV, tlvSelect); + } // check PPSE and select application id if (!res) { From 5fd2a7613fa476b32e96d6daa276801de4203578 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 16 Jul 2019 18:05:23 +0300 Subject: [PATCH 4/5] add check --- client/emv/emvcore.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index e7c2690b73..fd70ca871e 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -278,7 +278,10 @@ static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool Lea // COMPUTE APDU int datalen = 0; - APDUEncodeS(&apdu, false, IncludeLe ? 0x100 : 0x00, data, &datalen); + if (APDUEncodeS(&apdu, false, IncludeLe ? 0x100 : 0x00, data, &datalen)) { + PrintAndLogEx(ERR, "APDU encoding error."); + return 201; + } if (APDULogging) PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen)); From 638d6984456a7c9c9dbafd0a3dc53df5f4b0a188 Mon Sep 17 00:00:00 2001 From: merlokk <807634+merlokk@users.noreply.github.com> Date: Tue, 16 Jul 2019 18:05:36 +0300 Subject: [PATCH 5/5] make style --- client/emv/apduinfo.c | 6 +++--- client/emv/cmdemv.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/emv/apduinfo.c b/client/emv/apduinfo.c index 2449391b72..48e97622ba 100644 --- a/client/emv/apduinfo.c +++ b/client/emv/apduinfo.c @@ -472,7 +472,7 @@ int APDUEncodeS(sAPDU *sapdu, bool extended, uint16_t le, uint8_t *data, int *le return 10; APDUStruct apdu; - + apdu.cla = sapdu->CLA; apdu.ins = sapdu->INS; apdu.p1 = sapdu->P1; @@ -484,10 +484,10 @@ int APDUEncodeS(sAPDU *sapdu, bool extended, uint16_t le, uint8_t *data, int *le else apdu.data = NULL; apdu.le = le; - + apdu.extended_apdu = extended; apdu.case_type = 0x00; - + return APDUEncode(&apdu, data, len); } diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 5ac9adb00c..0cf1776206 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -829,7 +829,7 @@ static int CmdEMVExec(const char *Cmd) { PrintAndLogEx(NORMAL, "\n* PPSE."); SetAPDULogging(showAPDU); res = EMVSearchPSE(channel, activateField, true, psenum, decodeTLV, tlvSelect); - + // check PPSE instead of PSE and vice versa if (res) { PrintAndLogEx(NORMAL, "Check PPSE instead of PSE and vice versa...");