mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
Isolate ISO7816 select & exchange from EMVcore
This commit is contained in:
parent
2f031ef5c3
commit
11334f9440
21 changed files with 247 additions and 174 deletions
|
@ -193,7 +193,6 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/emv/test/cryptotest.c
|
||||
${PM3_ROOT}/client/src/emv/test/dda_test.c
|
||||
${PM3_ROOT}/client/src/emv/test/sda_test.c
|
||||
${PM3_ROOT}/client/src/emv/apduinfo.c
|
||||
${PM3_ROOT}/client/src/emv/cmdemv.c
|
||||
${PM3_ROOT}/client/src/emv/crypto.c
|
||||
${PM3_ROOT}/client/src/emv/crypto_polarssl.c
|
||||
|
@ -210,6 +209,8 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/fido/cbortools.c
|
||||
${PM3_ROOT}/client/src/fido/cose.c
|
||||
${PM3_ROOT}/client/src/fido/fidocore.c
|
||||
${PM3_ROOT}/client/src/iso7816/apduinfo.c
|
||||
${PM3_ROOT}/client/src/iso7816/iso7816core.c
|
||||
${PM3_ROOT}/client/src/loclass/cipher.c
|
||||
${PM3_ROOT}/client/src/loclass/cipherutils.c
|
||||
${PM3_ROOT}/client/src/loclass/elite_crack.c
|
||||
|
|
|
@ -535,7 +535,6 @@ SRCS = aiddesfire.c \
|
|||
crypto/asn1dump.c \
|
||||
crypto/asn1utils.c\
|
||||
crypto/libpcrypto.c\
|
||||
emv/apduinfo.c \
|
||||
emv/cmdemv.c \
|
||||
emv/crypto.c\
|
||||
emv/crypto_polarssl.c\
|
||||
|
@ -562,6 +561,8 @@ SRCS = aiddesfire.c \
|
|||
generator.c \
|
||||
graph.c \
|
||||
jansson_path.c \
|
||||
iso7816/apduinfo.c \
|
||||
iso7816/iso7816core.c \
|
||||
loclass/cipher.c \
|
||||
loclass/cipherutils.c \
|
||||
loclass/elite_crack.c \
|
||||
|
|
|
@ -61,7 +61,6 @@ add_library(pm3rrg_rdv4 SHARED
|
|||
${PM3_ROOT}/client/src/emv/test/cryptotest.c
|
||||
${PM3_ROOT}/client/src/emv/test/dda_test.c
|
||||
${PM3_ROOT}/client/src/emv/test/sda_test.c
|
||||
${PM3_ROOT}/client/src/emv/apduinfo.c
|
||||
${PM3_ROOT}/client/src/emv/cmdemv.c
|
||||
${PM3_ROOT}/client/src/emv/crypto.c
|
||||
${PM3_ROOT}/client/src/emv/crypto_polarssl.c
|
||||
|
@ -78,6 +77,8 @@ add_library(pm3rrg_rdv4 SHARED
|
|||
${PM3_ROOT}/client/src/fido/cbortools.c
|
||||
${PM3_ROOT}/client/src/fido/cose.c
|
||||
${PM3_ROOT}/client/src/fido/fidocore.c
|
||||
${PM3_ROOT}/client/src/iso7816/apduinfo.c
|
||||
${PM3_ROOT}/client/src/iso7816/iso7816core.c
|
||||
${PM3_ROOT}/client/src/loclass/cipher.c
|
||||
${PM3_ROOT}/client/src/loclass/cipherutils.c
|
||||
${PM3_ROOT}/client/src/loclass/elite_crack.c
|
||||
|
|
|
@ -193,7 +193,6 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/emv/test/cryptotest.c
|
||||
${PM3_ROOT}/client/src/emv/test/dda_test.c
|
||||
${PM3_ROOT}/client/src/emv/test/sda_test.c
|
||||
${PM3_ROOT}/client/src/emv/apduinfo.c
|
||||
${PM3_ROOT}/client/src/emv/cmdemv.c
|
||||
${PM3_ROOT}/client/src/emv/crypto.c
|
||||
${PM3_ROOT}/client/src/emv/crypto_polarssl.c
|
||||
|
@ -210,6 +209,8 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/fido/cbortools.c
|
||||
${PM3_ROOT}/client/src/fido/cose.c
|
||||
${PM3_ROOT}/client/src/fido/fidocore.c
|
||||
${PM3_ROOT}/client/src/iso7816/apduinfo.c
|
||||
${PM3_ROOT}/client/src/iso7816/iso7816core.c
|
||||
${PM3_ROOT}/client/src/loclass/cipher.c
|
||||
${PM3_ROOT}/client/src/loclass/cipherutils.c
|
||||
${PM3_ROOT}/client/src/loclass/elite_crack.c
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "cliparser.h"
|
||||
#include "cmdhfmf.h"
|
||||
#include "cmdhfmfu.h"
|
||||
#include "iso7816/iso7816core.h"
|
||||
#include "emv/emvcore.h"
|
||||
#include "ui.h"
|
||||
#include "crc16.h"
|
||||
|
@ -28,7 +29,7 @@
|
|||
#include "cmdhf.h" // handle HF plot
|
||||
#include "cliparser.h"
|
||||
#include "protocols.h" // definitions of ISO14A/7816 protocol, MAGIC_GEN_1A
|
||||
#include "emv/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "iso7816/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
|
||||
#include "cmdnfc.h" // print_type4_cc_info
|
||||
|
||||
|
@ -2008,7 +2009,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
uint16_t sw = 0;
|
||||
uint8_t result[1024] = {0};
|
||||
size_t resultlen = 0;
|
||||
int res = EMVSelect(ECC_CONTACTLESS, ActivateField, true, vaid, vaidlen, result, sizeof(result), &resultlen, &sw, NULL);
|
||||
int res = Iso7816Select(CC_CONTACTLESS, ActivateField, true, vaid, vaidlen, result, sizeof(result), &resultlen, &sw);
|
||||
ActivateField = false;
|
||||
if (res)
|
||||
continue;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "crc16.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "protocols.h" // definitions of ISO14B/7816 protocol
|
||||
#include "emv/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "iso7816/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
|
||||
#include "aidsearch.h"
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "cliparser.h" // CLIParserContext etc
|
||||
#include "cmdhf14a.h" // ExchangeAPDU14a
|
||||
#include "protocols.h" // definitions of ISO14A/7816 protocol
|
||||
#include "emv/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "iso7816/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "crypto/libpcrypto.h" // Hash calculation (sha1, sha256, sha512)
|
||||
#include "mifare/desfire_crypto.h" // des_encrypt/des_decrypt
|
||||
#include "des.h" // mbedtls_des_key_set_parity
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "commonutil.h"
|
||||
#include "comms.h"
|
||||
#include "proxmark3.h"
|
||||
#include "emv/emvcore.h"
|
||||
#include "iso7816/iso7816core.h"
|
||||
#include "emv/emvjson.h"
|
||||
#include "cliparser.h"
|
||||
#include "crypto/asn1utils.h"
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
#include "protocols.h"
|
||||
#include "cmdtrace.h"
|
||||
#include "cliparser.h"
|
||||
#include "emv/apduinfo.h" // APDU manipulation / errorcodes
|
||||
#include "emv/emvcore.h" // APDU logging
|
||||
#include "iso7816/apduinfo.h" // APDU manipulation / errorcodes
|
||||
#include "iso7816/iso7816core.h" // APDU logging
|
||||
#include "util_posix.h" // msleep
|
||||
#include "mifare/desfire_crypto.h"
|
||||
#include "crapto1/crapto1.h"
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "ui.h"
|
||||
#include "cmdhf14a.h" // manufacture
|
||||
#include "protocols.h" // definitions of ISO14A/7816 protocol
|
||||
#include "emv/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "iso7816/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "crypto/asn1utils.h" // ASN1 decode / print
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "crc16.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "protocols.h" // definitions of ISO14A/7816 protocol
|
||||
#include "emv/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "iso7816/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "nfc/ndef.h" // NDEFRecordsDecodeAndPrint
|
||||
#include "cmdnfc.h" // print_type4_cc_info
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ extern "C" {
|
|||
|
||||
#ifndef DropFieldEx
|
||||
#define DropFieldEx(x) { \
|
||||
if ( (x) == ECC_CONTACTLESS) { \
|
||||
if ( (x) == CC_CONTACTLESS) { \
|
||||
DropField(); \
|
||||
} \
|
||||
}
|
||||
|
|
|
@ -56,12 +56,12 @@ static void ParamLoadDefaults(struct tlvdb *tlvRoot) {
|
|||
TLV_ADD(0x9F4E, "proxmrk3rdv\x00");
|
||||
}
|
||||
|
||||
static void PrintChannel(EMVCommandChannel channel) {
|
||||
static void PrintChannel(Iso7816CommandChannel channel) {
|
||||
switch (channel) {
|
||||
case ECC_CONTACTLESS:
|
||||
case CC_CONTACTLESS:
|
||||
PrintAndLogEx(INFO, "Selected channel... " _GREEN_("CONTACTLESS (T=CL)"));
|
||||
break;
|
||||
case ECC_CONTACT:
|
||||
case CC_CONTACT:
|
||||
PrintAndLogEx(INFO, "Selected channel... " _GREEN_("CONTACT"));
|
||||
break;
|
||||
}
|
||||
|
@ -93,9 +93,9 @@ static int CmdEMVSelect(const char *Cmd) {
|
|||
bool leaveSignalON = arg_get_lit(ctx, 2);
|
||||
bool APDULogging = arg_get_lit(ctx, 3);
|
||||
bool decodeTLV = arg_get_lit(ctx, 4);
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 5))
|
||||
channel = ECC_CONTACT;
|
||||
channel = CC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIGetHexWithReturn(ctx, 6, data, &datalen);
|
||||
CLIParserFree(ctx);
|
||||
|
@ -143,9 +143,9 @@ static int CmdEMVSearch(const char *Cmd) {
|
|||
bool leaveSignalON = arg_get_lit(ctx, 2);
|
||||
bool APDULogging = arg_get_lit(ctx, 3);
|
||||
bool decodeTLV = arg_get_lit(ctx, 4);
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 5))
|
||||
channel = ECC_CONTACT;
|
||||
channel = CC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
|
@ -201,9 +201,9 @@ static int CmdEMVPPSE(const char *Cmd) {
|
|||
PSENum = 2;
|
||||
bool APDULogging = arg_get_lit(ctx, 5);
|
||||
bool decodeTLV = arg_get_lit(ctx, 6);
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 7))
|
||||
channel = ECC_CONTACT;
|
||||
channel = CC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
|
@ -257,9 +257,9 @@ static int CmdEMVGPO(const char *Cmd) {
|
|||
bool dataMakeFromPDOL = arg_get_lit(ctx, 3);
|
||||
bool APDULogging = arg_get_lit(ctx, 4);
|
||||
bool decodeTLV = arg_get_lit(ctx, 5);
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 6))
|
||||
channel = ECC_CONTACT;
|
||||
channel = CC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIGetHexWithReturn(ctx, 7, data, &datalen);
|
||||
CLIParserFree(ctx);
|
||||
|
@ -362,9 +362,9 @@ static int CmdEMVReadRecord(const char *Cmd) {
|
|||
bool leaveSignalON = arg_get_lit(ctx, 1);
|
||||
bool APDULogging = arg_get_lit(ctx, 2);
|
||||
bool decodeTLV = arg_get_lit(ctx, 3);
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 4))
|
||||
channel = ECC_CONTACT;
|
||||
channel = CC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIGetHexWithReturn(ctx, 5, data, &datalen);
|
||||
CLIParserFree(ctx);
|
||||
|
@ -449,9 +449,9 @@ static int CmdEMVAC(const char *Cmd) {
|
|||
bool APDULogging = arg_get_lit(ctx, 6);
|
||||
bool decodeTLV = arg_get_lit(ctx, 7);
|
||||
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 8))
|
||||
channel = ECC_CONTACT;
|
||||
channel = CC_CONTACT;
|
||||
|
||||
PrintChannel(channel);
|
||||
CLIGetHexWithReturn(ctx, 9, data, &datalen);
|
||||
|
@ -541,9 +541,9 @@ static int CmdEMVGenerateChallenge(const char *Cmd) {
|
|||
|
||||
bool leaveSignalON = arg_get_lit(ctx, 1);
|
||||
bool APDULogging = arg_get_lit(ctx, 2);
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 3))
|
||||
channel = ECC_CONTACT;
|
||||
channel = CC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
|
@ -600,9 +600,9 @@ static int CmdEMVInternalAuthenticate(const char *Cmd) {
|
|||
bool dataMakeFromDDOL = arg_get_lit(ctx, 3);
|
||||
bool APDULogging = arg_get_lit(ctx, 4);
|
||||
bool decodeTLV = arg_get_lit(ctx, 5);
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 6))
|
||||
channel = ECC_CONTACT;
|
||||
channel = CC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
CLIGetHexWithReturn(ctx, 7, data, &datalen);
|
||||
CLIParserFree(ctx);
|
||||
|
@ -841,15 +841,15 @@ static int CmdEMVExec(const char *Cmd) {
|
|||
TrType = TT_VSDC;
|
||||
|
||||
bool GenACGPO = arg_get_lit(ctx, 10);
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 11))
|
||||
channel = ECC_CONTACT;
|
||||
channel = CC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
|
||||
uint8_t psenum = (channel == CC_CONTACT) ? 1 : 2;
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (!IfPm3Smartcard()) {
|
||||
if (channel == ECC_CONTACT) {
|
||||
if (channel == CC_CONTACT) {
|
||||
PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support. Exiting.");
|
||||
return PM3_EDEVNOTSUPP;
|
||||
}
|
||||
|
@ -1463,13 +1463,13 @@ static int CmdEMVScan(const char *Cmd) {
|
|||
bool GenACGPO = arg_get_lit(ctx, 9);
|
||||
bool MergeJSON = arg_get_lit(ctx, 10);
|
||||
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 11))
|
||||
channel = ECC_CONTACT;
|
||||
channel = CC_CONTACT;
|
||||
|
||||
PrintChannel(channel);
|
||||
|
||||
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
|
||||
uint8_t psenum = (channel == CC_CONTACT) ? 1 : 2;
|
||||
|
||||
uint8_t filename[FILE_PATH_SIZE] = {0};
|
||||
int filenamelen = sizeof(filename);
|
||||
|
@ -1478,7 +1478,7 @@ static int CmdEMVScan(const char *Cmd) {
|
|||
CLIParserFree(ctx);
|
||||
|
||||
if (!IfPm3Smartcard()) {
|
||||
if (channel == ECC_CONTACT) {
|
||||
if (channel == CC_CONTACT) {
|
||||
PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support, exiting");
|
||||
return PM3_EDEVNOTSUPP;
|
||||
}
|
||||
|
@ -1511,7 +1511,7 @@ static int CmdEMVScan(const char *Cmd) {
|
|||
|
||||
JsonSaveStr(root, "$.File.Created", "proxmark3 `emv scan`");
|
||||
|
||||
if (channel == ECC_CONTACTLESS) {
|
||||
if (channel == CC_CONTACTLESS) {
|
||||
// iso 14443 select
|
||||
PrintAndLogEx(INFO, "GET UID, ATS");
|
||||
|
||||
|
@ -1868,22 +1868,22 @@ static int CmdEMVRoca(const char *Cmd) {
|
|||
|
||||
bool show_apdu = arg_get_lit(ctx, 2);
|
||||
|
||||
EMVCommandChannel channel = ECC_CONTACTLESS;
|
||||
Iso7816CommandChannel channel = CC_CONTACTLESS;
|
||||
if (arg_get_lit(ctx, 3))
|
||||
channel = ECC_CONTACT;
|
||||
channel = CC_CONTACT;
|
||||
|
||||
CLIParserFree(ctx);
|
||||
PrintChannel(channel);
|
||||
|
||||
if (!IfPm3Smartcard()) {
|
||||
if (channel == ECC_CONTACT) {
|
||||
if (channel == CC_CONTACT) {
|
||||
PrintAndLogEx(WARNING, "PM3 does not have SMARTCARD support, exiting");
|
||||
return PM3_EDEVNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
// select card
|
||||
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
|
||||
uint8_t psenum = (channel == CC_CONTACT) ? 1 : 2;
|
||||
|
||||
SetAPDULogging(show_apdu);
|
||||
|
||||
|
|
|
@ -131,16 +131,6 @@ static const TAIDList AIDlist [] = {
|
|||
{ CV_OTHER, "F0000000030001" }, // BRADESCO - Brazilian Bank Banco Bradesco
|
||||
};
|
||||
|
||||
//iceman: this logging setting, should be unified with client debug etc.
|
||||
static bool APDULogging = false;
|
||||
void SetAPDULogging(bool logging) {
|
||||
APDULogging = logging;
|
||||
}
|
||||
|
||||
bool GetAPDULogging(void) {
|
||||
return APDULogging;
|
||||
}
|
||||
|
||||
enum CardPSVendor GetCardPSVendor(uint8_t *AID, size_t AIDlen) {
|
||||
char buf[100] = {0};
|
||||
if (AIDlen < 1)
|
||||
|
@ -275,90 +265,37 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) {
|
|||
return tlvdb_fixed(0x02, dCVVlen, dCVV);
|
||||
}
|
||||
|
||||
static int EMVExchangeEx(EMVCommandChannel channel, 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;
|
||||
int res = 0;
|
||||
|
||||
if (ActivateField) {
|
||||
DropFieldEx(channel);
|
||||
msleep(50);
|
||||
}
|
||||
|
||||
// COMPUTE APDU
|
||||
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, datalen));
|
||||
|
||||
switch (channel) {
|
||||
case ECC_CONTACTLESS:
|
||||
res = ExchangeAPDU14a(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
|
||||
if (res != PM3_SUCCESS) {
|
||||
res = exchange_14b_apdu(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen, 4000);
|
||||
if (res != PM3_SUCCESS)
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
case ECC_CONTACT:
|
||||
res = 1;
|
||||
if (IfPm3Smartcard())
|
||||
res = ExchangeAPDUSC(false, data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
|
||||
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (APDULogging)
|
||||
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 (APDULogging) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int EMVExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
||||
int res = Iso7816ExchangeEx(channel, ActivateField, LeaveFieldON, apdu, IncludeLe, Result, MaxResultLen, ResultLen, sw);
|
||||
// add to tlv tree
|
||||
if (tlv) {
|
||||
if ((res == PM3_SUCCESS) && tlv) {
|
||||
struct tlvdb *t = tlvdb_parse_multi(Result, *ResultLen);
|
||||
tlvdb_add(tlv, t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
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, false, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||
int EMVExchange(Iso7816CommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
||||
int res = Iso7816Exchange(channel, LeaveFieldON, apdu, Result, MaxResultLen, ResultLen, sw);
|
||||
// add to tlv tree
|
||||
if ((res == PM3_SUCCESS) && tlv) {
|
||||
struct tlvdb *t = tlvdb_parse_multi(Result, *ResultLen);
|
||||
tlvdb_add(tlv, t);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
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) {
|
||||
return EMVExchangeEx(channel, ActivateField, LeaveFieldON, (sAPDU) {0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, (channel == ECC_CONTACTLESS), Result, MaxResultLen, ResultLen, sw, tlv);
|
||||
int EMVSelect(Iso7816CommandChannel 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 res = Iso7816Select(channel, ActivateField, LeaveFieldON, AID, AIDLen, Result, MaxResultLen, ResultLen, sw);
|
||||
// add to tlv tree
|
||||
if ((res == PM3_SUCCESS) && tlv) {
|
||||
struct tlvdb *t = tlvdb_parse_multi(Result, *ResultLen);
|
||||
tlvdb_add(tlv, t);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
int EMVSelectPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
uint8_t buf[APDU_AID_LEN] = {0};
|
||||
*ResultLen = 0;
|
||||
int len = 0;
|
||||
|
@ -375,7 +312,7 @@ int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO
|
|||
return EMVSelect(channel, ActivateField, LeaveFieldON, buf, len, Result, MaxResultLen, ResultLen, sw, NULL);
|
||||
}
|
||||
|
||||
static 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) {
|
||||
static int EMVSelectWithRetry(Iso7816CommandChannel 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 {
|
||||
|
@ -402,7 +339,7 @@ static int EMVSelectWithRetry(EMVCommandChannel channel, bool ActivateField, boo
|
|||
return res;
|
||||
}
|
||||
|
||||
static int EMVCheckAID(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlvdbelm, struct tlvdb *tlv) {
|
||||
static int EMVCheckAID(Iso7816CommandChannel channel, bool decodeTLV, struct tlvdb *tlvdbelm, struct tlvdb *tlv) {
|
||||
uint8_t data[APDU_RES_LEN] = {0};
|
||||
size_t datalen = 0;
|
||||
int res = 0;
|
||||
|
@ -434,7 +371,7 @@ static int EMVCheckAID(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *
|
|||
return res;
|
||||
}
|
||||
|
||||
int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) {
|
||||
int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) {
|
||||
uint8_t data[APDU_RES_LEN] = {0};
|
||||
size_t datalen = 0;
|
||||
uint8_t sfidata[0x11][APDU_RES_LEN];
|
||||
|
@ -529,7 +466,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO
|
|||
return res;
|
||||
}
|
||||
|
||||
int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) {
|
||||
int EMVSearch(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) {
|
||||
uint8_t aidbuf[APDU_AID_LEN] = {0};
|
||||
int aidlen = 0;
|
||||
uint8_t data[APDU_RES_LEN] = {0};
|
||||
|
@ -625,11 +562,11 @@ int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
||||
int EMVGPO(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
||||
return EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, true, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||
}
|
||||
|
||||
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 EMVReadRecord(Iso7816CommandChannel 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 = 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...");
|
||||
|
@ -638,11 +575,11 @@ int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uin
|
|||
return res;
|
||||
}
|
||||
|
||||
int EMVAC(EMVCommandChannel channel, 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) {
|
||||
int EMVAC(Iso7816CommandChannel channel, 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) {
|
||||
return EMVExchange(channel, LeaveFieldON, (sAPDU) {0x80, 0xae, RefControl, 0x00, CDOLLen, CDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||
}
|
||||
|
||||
int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
||||
int EMVGenerateChallenge(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
||||
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...");
|
||||
|
@ -651,11 +588,11 @@ int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *
|
|||
return res;
|
||||
}
|
||||
|
||||
int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
||||
int EMVInternalAuthenticate(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
||||
return EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, true, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||
}
|
||||
|
||||
int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
||||
int MSCComputeCryptoChecksum(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
||||
int res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, true, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||
if (*sw == 0x6700 || *sw == 0x6f00) {
|
||||
PrintAndLogEx(INFO, ">>> trying to reissue command without Le...");
|
||||
|
@ -725,7 +662,7 @@ int trSDA(struct tlvdb *tlv) {
|
|||
static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04};
|
||||
static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value };
|
||||
|
||||
int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
||||
int trDDA(Iso7816CommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
size_t len = 0;
|
||||
uint16_t sw = 0;
|
||||
|
|
|
@ -16,17 +16,10 @@
|
|||
#include <inttypes.h>
|
||||
#include <jansson.h>
|
||||
|
||||
#include "apduinfo.h"
|
||||
#include "iso7816/apduinfo.h"
|
||||
#include "iso7816/iso7816core.h"
|
||||
#include "emv_pki.h"
|
||||
|
||||
#define APDU_RES_LEN 260
|
||||
#define APDU_AID_LEN 50
|
||||
|
||||
typedef enum {
|
||||
ECC_CONTACTLESS,
|
||||
ECC_CONTACT
|
||||
} EMVCommandChannel;
|
||||
|
||||
enum TransactionType {
|
||||
TT_MSD,
|
||||
TT_VSDC, // contact only. not standard for contactless
|
||||
|
@ -56,39 +49,32 @@ void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv);
|
|||
struct tlvdb *GetPANFromTrack2(const struct tlv *track2);
|
||||
struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2);
|
||||
|
||||
void SetAPDULogging(bool logging);
|
||||
bool GetAPDULogging(void);
|
||||
|
||||
// exchange
|
||||
int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||
int EMVExchange(Iso7816CommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||
|
||||
// search application
|
||||
int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv);
|
||||
int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv);
|
||||
int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
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);
|
||||
int EMVSearchPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv);
|
||||
int EMVSearch(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv);
|
||||
int EMVSelectPSE(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
int EMVSelect(Iso7816CommandChannel 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);
|
||||
// select application
|
||||
int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen);
|
||||
// Get Processing Options
|
||||
int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||
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 EMVGPO(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||
int EMVReadRecord(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||
// AC
|
||||
int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||
int EMVAC(EMVCommandChannel channel, 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);
|
||||
int EMVGenerateChallenge(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||
int EMVAC(Iso7816CommandChannel channel, 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);
|
||||
// DDA
|
||||
int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||
int EMVInternalAuthenticate(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||
// Mastercard
|
||||
int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||
int MSCComputeCryptoChecksum(Iso7816CommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
|
||||
// Auth
|
||||
int trSDA(struct tlvdb *tlv);
|
||||
int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv);
|
||||
int trDDA(Iso7816CommandChannel channel, bool decodeTLV, struct tlvdb *tlv);
|
||||
int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv);
|
||||
|
||||
int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root);
|
||||
|
||||
struct emv_pk *get_ca_pk(struct tlvdb *db);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
|
||||
#include "emv/emvcore.h"
|
||||
#include "iso7816/iso7816core.h"
|
||||
#include "emv/emvjson.h"
|
||||
#include "cbortools.h"
|
||||
#include "x509_crt.h"
|
||||
|
@ -172,17 +172,17 @@ const char *fido2GetCmdMemberDescription(uint8_t cmdCode, bool isResponse, int m
|
|||
int FIDOSelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
uint8_t data[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01};
|
||||
|
||||
return EMVSelect(ECC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL);
|
||||
return Iso7816Select(CC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw);
|
||||
}
|
||||
|
||||
int FIDOExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
int res = EMVExchange(ECC_CONTACTLESS, true, apdu, Result, MaxResultLen, ResultLen, sw, NULL);
|
||||
int res = Iso7816Exchange(CC_CONTACTLESS, true, apdu, Result, MaxResultLen, ResultLen, sw);
|
||||
if (res == 5) // apdu result (sw) not a 0x9000
|
||||
res = 0;
|
||||
// software chaining
|
||||
while (!res && (*sw >> 8) == 0x61) {
|
||||
size_t oldlen = *ResultLen;
|
||||
res = EMVExchange(ECC_CONTACTLESS, true, (sAPDU) {0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL);
|
||||
res = Iso7816Exchange(CC_CONTACTLESS, true, (sAPDU) {0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw);
|
||||
if (res == 5) // apdu result (sw) not a 0x9000
|
||||
res = 0;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "common.h"
|
||||
|
||||
#include <jansson.h>
|
||||
#include "emv/apduinfo.h" // sAPDU
|
||||
#include "iso7816/apduinfo.h" // sAPDU
|
||||
|
||||
typedef enum {
|
||||
fido2CmdMakeCredential = 0x01,
|
||||
|
|
108
client/src/iso7816/iso7816core.c
Normal file
108
client/src/iso7816/iso7816core.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2017 Merlok
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// ISO7816 core functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "iso7816core.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "comms.h" // DropField
|
||||
#include "cmdparser.h"
|
||||
#include "cmdsmartcard.h" // ExchangeAPDUSC
|
||||
#include "ui.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "cmdhf14b.h"
|
||||
#include "util_posix.h"
|
||||
|
||||
//iceman: this logging setting, should be unified with client debug etc.
|
||||
static bool APDULogging = false;
|
||||
void SetAPDULogging(bool logging) {
|
||||
APDULogging = logging;
|
||||
}
|
||||
|
||||
bool GetAPDULogging(void) {
|
||||
return APDULogging;
|
||||
}
|
||||
|
||||
int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, 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) {
|
||||
DropFieldEx(channel);
|
||||
msleep(50);
|
||||
}
|
||||
|
||||
// COMPUTE APDU
|
||||
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, datalen));
|
||||
|
||||
switch (channel) {
|
||||
case CC_CONTACTLESS:
|
||||
res = ExchangeAPDU14a(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
|
||||
if (res != PM3_SUCCESS) {
|
||||
res = exchange_14b_apdu(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen, 4000);
|
||||
if (res != PM3_SUCCESS)
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
case CC_CONTACT:
|
||||
res = 1;
|
||||
if (IfPm3Smartcard())
|
||||
res = ExchangeAPDUSC(false, data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
|
||||
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (APDULogging)
|
||||
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 (APDULogging) {
|
||||
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;
|
||||
}
|
||||
|
||||
int Iso7816Exchange(Iso7816CommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
return Iso7816ExchangeEx(channel, false, LeaveFieldON, apdu, false, Result, MaxResultLen, ResultLen, sw);
|
||||
}
|
||||
|
||||
int Iso7816Select(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
return Iso7816ExchangeEx(channel, ActivateField, LeaveFieldON, (sAPDU) {0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, (channel == CC_CONTACTLESS), Result, MaxResultLen, ResultLen, sw);
|
||||
}
|
37
client/src/iso7816/iso7816core.h
Normal file
37
client/src/iso7816/iso7816core.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2017 Merlok
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// ISO7816 core functionality
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef ISO7816CORE_H__
|
||||
#define ISO7816CORE_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "apduinfo.h"
|
||||
|
||||
#define APDU_RES_LEN 260
|
||||
#define APDU_AID_LEN 50
|
||||
|
||||
typedef enum {
|
||||
CC_CONTACTLESS,
|
||||
CC_CONTACT
|
||||
} Iso7816CommandChannel;
|
||||
|
||||
void SetAPDULogging(bool logging);
|
||||
bool GetAPDULogging(void);
|
||||
|
||||
// exchange
|
||||
int Iso7816Exchange(Iso7816CommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
|
||||
// search application
|
||||
int Iso7816Select(Iso7816CommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw);
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue