Skip to content

Commit

Permalink
Merge pull request #253 from merlokk/emv_apdu
Browse files Browse the repository at this point in the history
Emv apdu
  • Loading branch information
merlokk authored Jul 16, 2019
2 parents cd307cc + 638d698 commit d3b6a8e
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 23 deletions.
24 changes: 24 additions & 0 deletions client/emv/apduinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
10 changes: 10 additions & 0 deletions client/emv/apduinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -56,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);

Expand Down
6 changes: 6 additions & 0 deletions client/emv/cmdemv.c
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,12 @@ static int CmdEMVExec(const char *Cmd) {
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) {
TLVPrintAIDlistFromSelectTLV(tlvSelect);
Expand Down
29 changes: 15 additions & 14 deletions client/emv/emvcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,24 +277,25 @@ 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;
if (APDUEncodeS(&apdu, false, IncludeLe ? 0x100 : 0x00, data, &datalen)) {
PrintAndLogEx(ERR, "APDU encoding error.");
return 201;
}

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 + <data = Nc> + 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) {
Expand Down Expand Up @@ -336,7 +337,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) {
Expand Down Expand Up @@ -609,9 +610,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;
Expand All @@ -622,9 +623,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;
Expand Down
9 changes: 0 additions & 9 deletions client/emv/emvcore.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit d3b6a8e

Please sign in to comment.