diff --git a/client/src/cipurse/cipursecore.c b/client/src/cipurse/cipursecore.c index 8f61d843d..f4dea46b4 100644 --- a/client/src/cipurse/cipursecore.c +++ b/client/src/cipurse/cipursecore.c @@ -11,15 +11,83 @@ #include "cipursecore.h" #include "commonutil.h" // ARRAYLEN +#include "comms.h" // DropField +#include "util_posix.h" // msleep +#include "cmdhf14a.h" #include "emv/emvcore.h" #include "emv/emvjson.h" #include "ui.h" #include "util.h" +static int CIPURSEExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint16_t Le, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + uint8_t data[APDU_RES_LEN] = {0}; + + *ResultLen = 0; + if (sw) *sw = 0; + uint16_t isw = 0; + int res = 0; + + if (ActivateField) { + DropField(); + msleep(50); + } + + // COMPUTE APDU + int datalen = 0; + uint16_t xle = IncludeLe ? 0x100 : 0x00; + if (xle == 0x100 && Le != 0) + xle = Le; + if (APDUEncodeS(&apdu, false, xle, data, &datalen)) { + PrintAndLogEx(ERR, "APDU encoding error."); + return 201; + } + + if (GetAPDULogging()) + PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen)); + + res = ExchangeAPDU14a(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + if (res) { + return res; + } + + if (GetAPDULogging()) + PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(Result, *ResultLen)); + + if (*ResultLen < 2) { + return 200; + } + + *ResultLen -= 2; + isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1]; + if (sw) + *sw = isw; + + if (isw != 0x9000) { + if (GetAPDULogging()) { + if (*sw >> 8 == 0x61) { + PrintAndLogEx(ERR, "APDU chaining len:%02x -->", *sw & 0xff); + } else { + PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff)); + return 5; + } + } + } + + return PM3_SUCCESS; +} + +/*static int CIPURSEExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return CIPURSEExchangeEx(false, true, apdu, true, 0, Result, MaxResultLen, ResultLen, sw); +}*/ + int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t data[] = {0x41, 0x44, 0x20, 0x46, 0x31}; return EMVSelect(ECC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); } +int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return CIPURSEExchangeEx(false, true, (sAPDU) {0x00, 0x84, 0x00, 0x00, 0x00, NULL}, true, 0x16, Result, MaxResultLen, ResultLen, sw); +} + diff --git a/client/src/cipurse/cipursecore.h b/client/src/cipurse/cipursecore.h index 7598b8343..8a18011f2 100644 --- a/client/src/cipurse/cipursecore.h +++ b/client/src/cipurse/cipursecore.h @@ -12,10 +12,14 @@ #define __CIPURSECORE_H__ #include "common.h" +#include "emv/apduinfo.h" + #include #include "emv/apduinfo.h" // sAPDU int CIPURSESelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +int CIPURSEChallenge(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); + #endif /* __CIPURSECORE_H__ */ diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 1a1cd7770..a1e9176b1 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -80,6 +80,36 @@ static int CmdHFCipurseInfo(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHFCipurseAuth(const char *Cmd) { + uint8_t buf[APDU_RES_LEN] = {0}; + size_t len = 0; + uint16_t sw = 0; + + SetAPDULogging(true); + + int res = CIPURSESelect(true, true, buf, sizeof(buf), &len, &sw); + if (res != 0 || sw != 0x9000) { + PrintAndLogEx(ERR, "Cipurse select error. Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + res = CIPURSEChallenge(buf, sizeof(buf), &len, &sw); + if (res != 0 || len != 0x16) { + PrintAndLogEx(ERR, "Cipurse get challenge error. Card returns 0x%04x.", sw); + DropField(); + return PM3_ESOFT; + } + + + DropField(); + return PM3_SUCCESS; +} + + + + + @@ -96,6 +126,7 @@ bool CheckCardCipurse(void) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help."}, {"info", CmdHFCipurseInfo, IfPm3Iso14443a, "Info about Cipurse tag."}, + {"auth", CmdHFCipurseAuth, IfPm3Iso14443a, "Authentication."}, {NULL, NULL, 0, NULL} };