mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
make style
This commit is contained in:
parent
0d9223a547
commit
0373696662
483 changed files with 56514 additions and 52451 deletions
|
@ -257,9 +257,10 @@ const APDUCode APDUCodeTable[] = {
|
|||
{"9FXX", APDUCODE_TYPE_NONE, "Command successfully executed; 'xx' bytes of data are available and can be requested using GET RESPONSE."},
|
||||
{"9XXX", APDUCODE_TYPE_NONE, "Application related status, (ISO 7816-3)"}
|
||||
};
|
||||
const size_t APDUCodeTableLen = sizeof(APDUCodeTable)/sizeof(APDUCode);
|
||||
const size_t APDUCodeTableLen = sizeof(APDUCodeTable) / sizeof(APDUCode);
|
||||
|
||||
int CodeCmp(const char *code1, const char *code2) {
|
||||
int CodeCmp(const char *code1, const char *code2)
|
||||
{
|
||||
int xsymb = 0;
|
||||
int cmp = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -277,7 +278,8 @@ int CodeCmp(const char *code1, const char *code2) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2) {
|
||||
const APDUCode *const GetAPDUCode(uint8_t sw1, uint8_t sw2)
|
||||
{
|
||||
char buf[6] = {0};
|
||||
int res;
|
||||
int mineq = APDUCodeTableLen;
|
||||
|
@ -308,7 +310,8 @@ const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const char* GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2) {
|
||||
const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2)
|
||||
{
|
||||
const APDUCode *cd = GetAPDUCode(sw1, sw2);
|
||||
if (cd)
|
||||
return cd->Description;
|
||||
|
|
|
@ -28,7 +28,7 @@ typedef struct {
|
|||
const char *Description;
|
||||
} APDUCode;
|
||||
|
||||
extern const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2);
|
||||
extern const char* GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2);
|
||||
extern const APDUCode *const GetAPDUCode(uint8_t sw1, uint8_t sw2);
|
||||
extern const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
#define TLV_ADD(tag, value)( tlvdb_change_or_add_node(tlvRoot, tag, sizeof(value) - 1, (const unsigned char *)value) )
|
||||
void ParamLoadDefaults(struct tlvdb *tlvRoot) {
|
||||
void ParamLoadDefaults(struct tlvdb *tlvRoot)
|
||||
{
|
||||
//9F02:(Amount, authorized (Numeric)) len:6
|
||||
TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
|
||||
//9F1A:(Terminal Country Code) len:2
|
||||
|
@ -43,26 +44,28 @@ void ParamLoadDefaults(struct tlvdb *tlvRoot) {
|
|||
TLV_ADD(0x95, "\x00\x00\x00\x00\x00");
|
||||
}
|
||||
|
||||
void PrintChannel(EMVCommandChannel channel) {
|
||||
switch(channel) {
|
||||
case ECC_CONTACTLESS:
|
||||
PrintAndLogEx(INFO, "Channel: CONTACTLESS");
|
||||
break;
|
||||
case ECC_CONTACT:
|
||||
PrintAndLogEx(INFO, "Channel: CONTACT");
|
||||
break;
|
||||
void PrintChannel(EMVCommandChannel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case ECC_CONTACTLESS:
|
||||
PrintAndLogEx(INFO, "Channel: CONTACTLESS");
|
||||
break;
|
||||
case ECC_CONTACT:
|
||||
PrintAndLogEx(INFO, "Channel: CONTACT");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int CmdEMVSelect(const char *cmd) {
|
||||
int CmdEMVSelect(const char *cmd)
|
||||
{
|
||||
uint8_t data[APDU_AID_LEN] = {0};
|
||||
int datalen = 0;
|
||||
|
||||
CLIParserInit("emv select",
|
||||
"Executes select applet command",
|
||||
"Usage:\n\temv select -s a00000000101 -> select card, select applet\n\temv select -st a00000000101 -> select card, select applet, show result in TLV\n");
|
||||
"Executes select applet command",
|
||||
"Usage:\n\temv select -s a00000000101 -> select card, select applet\n\temv select -st a00000000101 -> select card, select applet, show result in TLV\n");
|
||||
|
||||
void* argtable[] = {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("sS", "select", "activate field and select card"),
|
||||
arg_lit0("kK", "keep", "keep field for next command"),
|
||||
|
@ -105,13 +108,14 @@ int CmdEMVSelect(const char *cmd) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CmdEMVSearch(const char *cmd) {
|
||||
int CmdEMVSearch(const char *cmd)
|
||||
{
|
||||
|
||||
CLIParserInit("emv search",
|
||||
"Tries to select all applets from applet list:\n",
|
||||
"Usage:\n\temv search -s -> select card and search\n\temv search -st -> select card, search and show result in TLV\n");
|
||||
"Tries to select all applets from applet list:\n",
|
||||
"Usage:\n\temv search -s -> select card and search\n\temv search -st -> select card, search and show result in TLV\n");
|
||||
|
||||
void* argtable[] = {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("sS", "select", "activate field and select card"),
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
|
@ -155,13 +159,14 @@ int CmdEMVSearch(const char *cmd) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CmdEMVPPSE(const char *cmd) {
|
||||
int CmdEMVPPSE(const char *cmd)
|
||||
{
|
||||
|
||||
CLIParserInit("emv pse",
|
||||
"Executes PSE/PPSE select command. It returns list of applet on the card:\n",
|
||||
"Usage:\n\temv pse -s1 -> select, get pse\n\temv pse -st2 -> select, get ppse, show result in TLV\n");
|
||||
"Executes PSE/PPSE select command. It returns list of applet on the card:\n",
|
||||
"Usage:\n\temv pse -s1 -> select, get pse\n\temv pse -st2 -> select, get ppse, show result in TLV\n");
|
||||
|
||||
void* argtable[] = {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("sS", "select", "activate field and select card"),
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
|
@ -210,17 +215,18 @@ int CmdEMVPPSE(const char *cmd) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CmdEMVGPO(const char *cmd) {
|
||||
int CmdEMVGPO(const char *cmd)
|
||||
{
|
||||
uint8_t data[APDU_RES_LEN] = {0};
|
||||
int datalen = 0;
|
||||
|
||||
CLIParserInit("emv gpo",
|
||||
"Executes Get Processing Options command. It returns data in TLV format (0x77 - format2) or plain format (0x80 - format1).\nNeeds a EMV applet to be selected.",
|
||||
"Usage:\n\temv gpo -k -> execute GPO\n"
|
||||
"\temv gpo -t 01020304 -> execute GPO with 4-byte PDOL data, show result in TLV\n"
|
||||
"\temv gpo -pmt 9F 37 04 -> load params from file, make PDOL data from PDOL, execute GPO with PDOL, show result in TLV\n");
|
||||
"Executes Get Processing Options command. It returns data in TLV format (0x77 - format2) or plain format (0x80 - format1).\nNeeds a EMV applet to be selected.",
|
||||
"Usage:\n\temv gpo -k -> execute GPO\n"
|
||||
"\temv gpo -t 01020304 -> execute GPO with 4-byte PDOL data, show result in TLV\n"
|
||||
"\temv gpo -pmt 9F 37 04 -> load params from file, make PDOL data from PDOL, execute GPO with PDOL, show result in TLV\n");
|
||||
|
||||
void* argtable[] = {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
arg_lit0("pP", "params", "load parameters from `emv/defparams.json` file for PDOLdata making from PDOL and parameters"),
|
||||
|
@ -269,7 +275,7 @@ int CmdEMVGPO(const char *cmd) {
|
|||
|
||||
tmp_ext = tlvdb_external(0x9f38, datalen, data);
|
||||
pdol_data_tlv = dol_process((const struct tlv *)tmp_ext, tlvRoot, 0x83);
|
||||
if (!pdol_data_tlv){
|
||||
if (!pdol_data_tlv) {
|
||||
PrintAndLogEx(ERR, "Can't create PDOL TLV.");
|
||||
tlvdb_free(tmp_ext);
|
||||
tlvdb_free(tlvRoot);
|
||||
|
@ -316,15 +322,16 @@ int CmdEMVGPO(const char *cmd) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CmdEMVReadRecord(const char *cmd) {
|
||||
int CmdEMVReadRecord(const char *cmd)
|
||||
{
|
||||
uint8_t data[APDU_RES_LEN] = {0};
|
||||
int datalen = 0;
|
||||
|
||||
CLIParserInit("emv readrec",
|
||||
"Executes Read Record command. It returns data in TLV format.\nNeeds a bank applet to be selected and sometimes needs GPO to be executed.",
|
||||
"Usage:\n\temv readrec -k 0101 -> read file SFI=01, SFIrec=01\n\temv readrec -kt 0201-> read file 0201 and show result in TLV\n");
|
||||
"Executes Read Record command. It returns data in TLV format.\nNeeds a bank applet to be selected and sometimes needs GPO to be executed.",
|
||||
"Usage:\n\temv readrec -k 0101 -> read file SFI=01, SFIrec=01\n\temv readrec -kt 0201-> read file 0201 and show result in TLV\n");
|
||||
|
||||
void* argtable[] = {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
||||
|
@ -371,18 +378,19 @@ int CmdEMVReadRecord(const char *cmd) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CmdEMVAC(const char *cmd) {
|
||||
int CmdEMVAC(const char *cmd)
|
||||
{
|
||||
uint8_t data[APDU_RES_LEN] = {0};
|
||||
int datalen = 0;
|
||||
|
||||
CLIParserInit("emv genac",
|
||||
"Generate Application Cryptogram command. It returns data in TLV format .\nNeeds a EMV applet to be selected and GPO to be executed.",
|
||||
"Usage:\n\temv genac -k 0102 -> generate AC with 2-byte CDOLdata and keep field ON after command\n"
|
||||
"\temv genac -t 01020304 -> generate AC with 4-byte CDOL data, show result in TLV\n"
|
||||
"\temv genac -Daac 01020304 -> generate AC with 4-byte CDOL data and terminal decision 'declined'\n"
|
||||
"\temv genac -pmt 9F 37 04 -> load params from file, make CDOL data from CDOL, generate AC with CDOL, show result in TLV");
|
||||
"Generate Application Cryptogram command. It returns data in TLV format .\nNeeds a EMV applet to be selected and GPO to be executed.",
|
||||
"Usage:\n\temv genac -k 0102 -> generate AC with 2-byte CDOLdata and keep field ON after command\n"
|
||||
"\temv genac -t 01020304 -> generate AC with 4-byte CDOL data, show result in TLV\n"
|
||||
"\temv genac -Daac 01020304 -> generate AC with 4-byte CDOL data and terminal decision 'declined'\n"
|
||||
"\temv genac -pmt 9F 37 04 -> load params from file, make CDOL data from CDOL, generate AC with CDOL, show result in TLV");
|
||||
|
||||
void* argtable[] = {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
arg_lit0("cC", "cda", "executes CDA transaction. Needs to get SDAD in results."),
|
||||
|
@ -453,7 +461,7 @@ int CmdEMVAC(const char *cmd) {
|
|||
|
||||
tmp_ext = tlvdb_external(0x8c, datalen, data);
|
||||
cdol_data_tlv = dol_process((const struct tlv *)tmp_ext, tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!cdol_data_tlv){
|
||||
if (!cdol_data_tlv) {
|
||||
PrintAndLogEx(ERR, "Can't create CDOL TLV.");
|
||||
tlvdb_free(tmp_ext);
|
||||
tlvdb_free(tlvRoot);
|
||||
|
@ -492,13 +500,14 @@ int CmdEMVAC(const char *cmd) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CmdEMVGenerateChallenge(const char *cmd) {
|
||||
int CmdEMVGenerateChallenge(const char *cmd)
|
||||
{
|
||||
|
||||
CLIParserInit("emv challenge",
|
||||
"Executes Generate Challenge command. It returns 4 or 8-byte random number from card.\nNeeds a EMV applet to be selected and GPO to be executed.",
|
||||
"Usage:\n\temv challenge -> get challenge\n\temv challenge -k -> get challenge, keep fileld ON\n");
|
||||
"Executes Generate Challenge command. It returns 4 or 8-byte random number from card.\nNeeds a EMV applet to be selected and GPO to be executed.",
|
||||
"Usage:\n\temv challenge -> get challenge\n\temv challenge -k -> get challenge, keep fileld ON\n");
|
||||
|
||||
void* argtable[] = {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
||||
|
@ -537,20 +546,21 @@ int CmdEMVGenerateChallenge(const char *cmd) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CmdEMVInternalAuthenticate(const char *cmd) {
|
||||
int CmdEMVInternalAuthenticate(const char *cmd)
|
||||
{
|
||||
uint8_t data[APDU_RES_LEN] = {0};
|
||||
int datalen = 0;
|
||||
|
||||
CLIParserInit("emv intauth",
|
||||
"Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\n"
|
||||
"Needs a EMV applet to be selected and GPO to be executed.",
|
||||
"Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\n"
|
||||
"Needs a EMV applet to be selected and GPO to be executed.",
|
||||
|
||||
"Usage:\n"
|
||||
"\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n"
|
||||
"\temv intauth -t 01020304 -> execute Internal Authenticate with 4-byte DDOL data, show result in TLV\n"
|
||||
"\temv intauth -pmt 9F 37 04 -> load params from file, make DDOL data from DDOL, Internal Authenticate with DDOL, show result in TLV");
|
||||
"Usage:\n"
|
||||
"\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n"
|
||||
"\temv intauth -t 01020304 -> execute Internal Authenticate with 4-byte DDOL data, show result in TLV\n"
|
||||
"\temv intauth -pmt 9F 37 04 -> load params from file, make DDOL data from DDOL, Internal Authenticate with DDOL, show result in TLV");
|
||||
|
||||
void* argtable[] = {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("kK", "keep", "keep field ON for next command"),
|
||||
arg_lit0("pP", "params", "load parameters from `emv/defparams.json` file for DDOLdata making from DDOL and parameters"),
|
||||
|
@ -600,7 +610,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
|
|||
|
||||
tmp_ext = tlvdb_external(0x9f49, datalen, data);
|
||||
ddol_data_tlv = dol_process((const struct tlv *)tmp_ext, tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!ddol_data_tlv){
|
||||
if (!ddol_data_tlv) {
|
||||
PrintAndLogEx(ERR, "Can't create DDOL TLV.");
|
||||
tlvdb_free(tmp_ext);
|
||||
tlvdb_free(tlvRoot);
|
||||
|
@ -641,7 +651,8 @@ int CmdEMVInternalAuthenticate(const char *cmd) {
|
|||
|
||||
#define dreturn(n) {free(pdol_data_tlv); tlvdb_free(tlvSelect); tlvdb_free(tlvRoot); DropFieldEx( channel ); return n;}
|
||||
|
||||
void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON, enum TransactionType TrType, bool GenACGPO) {
|
||||
void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON, enum TransactionType TrType, bool GenACGPO)
|
||||
{
|
||||
|
||||
ParamLoadDefaults(tlvRoot);
|
||||
|
||||
|
@ -655,7 +666,7 @@ void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON, enum T
|
|||
if (GenACGPO) {
|
||||
qVSDC = "\x26\x80\x00\x00";
|
||||
}
|
||||
switch(TrType) {
|
||||
switch (TrType) {
|
||||
case TT_MSD:
|
||||
TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
|
||||
break;
|
||||
|
@ -674,9 +685,10 @@ void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON, enum T
|
|||
}
|
||||
}
|
||||
|
||||
void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, bool decodeTLV) {
|
||||
void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, bool decodeTLV)
|
||||
{
|
||||
if (buf[0] == 0x80) {
|
||||
if (decodeTLV){
|
||||
if (decodeTLV) {
|
||||
PrintAndLog("GPO response format1:");
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
}
|
||||
|
@ -685,15 +697,15 @@ void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len,
|
|||
PrintAndLogEx(ERR, "GPO response format1 parsing error. length=%d", len);
|
||||
} else {
|
||||
// AIP
|
||||
struct tlvdb * f1AIP = tlvdb_fixed(0x82, 2, buf + 2);
|
||||
struct tlvdb *f1AIP = tlvdb_fixed(0x82, 2, buf + 2);
|
||||
tlvdb_add(tlvRoot, f1AIP);
|
||||
if (decodeTLV){
|
||||
if (decodeTLV) {
|
||||
PrintAndLogEx(INFO, "\n* * Decode response format 1 (0x80) AIP and AFL:");
|
||||
TLVPrintFromTLV(f1AIP);
|
||||
}
|
||||
|
||||
// AFL
|
||||
struct tlvdb * f1AFL = tlvdb_fixed(0x94, len - 4, buf + 2 + 2);
|
||||
struct tlvdb *f1AFL = tlvdb_fixed(0x94, len - 4, buf + 2 + 2);
|
||||
tlvdb_add(tlvRoot, f1AFL);
|
||||
if (decodeTLV)
|
||||
TLVPrintFromTLV(f1AFL);
|
||||
|
@ -704,9 +716,10 @@ void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len,
|
|||
}
|
||||
}
|
||||
|
||||
void ProcessACResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, bool decodeTLV) {
|
||||
void ProcessACResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, bool decodeTLV)
|
||||
{
|
||||
if (buf[0] == 0x80) {
|
||||
if (decodeTLV){
|
||||
if (decodeTLV) {
|
||||
PrintAndLog("GPO response format1:");
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
}
|
||||
|
@ -748,7 +761,8 @@ void ProcessACResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, b
|
|||
}
|
||||
}
|
||||
|
||||
int CmdEMVExec(const char *cmd) {
|
||||
int CmdEMVExec(const char *cmd)
|
||||
{
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
size_t len = 0;
|
||||
uint16_t sw = 0;
|
||||
|
@ -764,12 +778,12 @@ int CmdEMVExec(const char *cmd) {
|
|||
struct tlv *pdol_data_tlv = NULL;
|
||||
|
||||
CLIParserInit("emv exec",
|
||||
"Executes EMV contactless transaction",
|
||||
"Usage:\n"
|
||||
"\temv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n"
|
||||
"\temv exec -satc -> select card, execute CDA transaction, show APDU and TLV\n");
|
||||
"Executes EMV contactless transaction",
|
||||
"Usage:\n"
|
||||
"\temv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n"
|
||||
"\temv exec -satc -> select card, execute CDA transaction, show APDU and TLV\n");
|
||||
|
||||
void* argtable[] = {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("sS", "select", "activate field and select card."),
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses."),
|
||||
|
@ -810,7 +824,7 @@ int CmdEMVExec(const char *cmd) {
|
|||
|
||||
#ifndef WITH_SMARTCARD
|
||||
// not compiled with smartcard functionality, we need to exit
|
||||
if ( channel == ECC_CONTACT ) {
|
||||
if (channel == ECC_CONTACT) {
|
||||
PrintAndLogEx(WARNING, "PM3 Client is not compiled with support for SMARTCARD. Exiting.");
|
||||
return 0;
|
||||
}
|
||||
|
@ -880,7 +894,7 @@ int CmdEMVExec(const char *cmd) {
|
|||
|
||||
PrintAndLogEx(NORMAL, "\n* Calc PDOL.");
|
||||
pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
|
||||
if (!pdol_data_tlv){
|
||||
if (!pdol_data_tlv) {
|
||||
PrintAndLogEx(WARNING, "Error: can't create PDOL TLV.");
|
||||
dreturn(4);
|
||||
}
|
||||
|
@ -1019,7 +1033,7 @@ int CmdEMVExec(const char *cmd) {
|
|||
// transaction check
|
||||
|
||||
// qVSDC
|
||||
if (TrType == TT_QVSDCMCHIP || TrType == TT_CDA){
|
||||
if (TrType == TT_QVSDCMCHIP || TrType == TT_CDA) {
|
||||
// 9F26: Application Cryptogram
|
||||
const struct tlv *AC = tlvdb_get(tlvRoot, 0x9F26, NULL);
|
||||
if (AC) {
|
||||
|
@ -1043,7 +1057,7 @@ int CmdEMVExec(const char *cmd) {
|
|||
PrintAndLogEx(NORMAL, "\tKey index: 0x%02x", IAD->value[1]);
|
||||
PrintAndLogEx(NORMAL, "\tCrypto ver: 0x%02x(%03d)", IAD->value[2], IAD->value[2]);
|
||||
PrintAndLogEx(NORMAL, "\tCVR:", sprint_hex(&IAD->value[3], IAD->value[0] - 2));
|
||||
struct tlvdb * cvr = tlvdb_fixed(0x20, IAD->value[0] - 2, &IAD->value[3]);
|
||||
struct tlvdb *cvr = tlvdb_fixed(0x20, IAD->value[0] - 2, &IAD->value[3]);
|
||||
TLVPrintFromTLVLev(cvr, 1);
|
||||
}
|
||||
} else {
|
||||
|
@ -1057,7 +1071,7 @@ int CmdEMVExec(const char *cmd) {
|
|||
}
|
||||
|
||||
// Mastercard M/CHIP
|
||||
if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD && (TrType == TT_QVSDCMCHIP || TrType == TT_CDA)){
|
||||
if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD && (TrType == TT_QVSDCMCHIP || TrType == TT_CDA)) {
|
||||
const struct tlv *CDOL1 = tlvdb_get(tlvRoot, 0x8c, NULL);
|
||||
if (CDOL1 && GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) { // and m/chip transaction flag
|
||||
PrintAndLogEx(NORMAL, "\n--> Mastercard M/Chip transaction.");
|
||||
|
@ -1074,7 +1088,7 @@ int CmdEMVExec(const char *cmd) {
|
|||
}
|
||||
|
||||
// ICC Dynamic Number
|
||||
struct tlvdb * ICCDynN = tlvdb_fixed(0x9f4c, len, buf);
|
||||
struct tlvdb *ICCDynN = tlvdb_fixed(0x9f4c, len, buf);
|
||||
tlvdb_add(tlvRoot, ICCDynN);
|
||||
if (decodeTLV) {
|
||||
PrintAndLogEx(NORMAL, "\n* * ICC Dynamic Number:");
|
||||
|
@ -1120,7 +1134,7 @@ int CmdEMVExec(const char *cmd) {
|
|||
emv_tag_dump(CID, stdout, 0);
|
||||
PrintAndLogEx(NORMAL, "------------------------------");
|
||||
if (CID->len > 0) {
|
||||
switch(CID->value[0] & EMVAC_AC_MASK){
|
||||
switch (CID->value[0] & EMVAC_AC_MASK) {
|
||||
case EMVAC_AAC:
|
||||
PrintAndLogEx(NORMAL, "Transaction DECLINED.");
|
||||
break;
|
||||
|
@ -1202,7 +1216,7 @@ int CmdEMVExec(const char *cmd) {
|
|||
}
|
||||
|
||||
// VSDC
|
||||
if (GetCardPSVendor(AID, AIDlen) == CV_VISA && (TrType == TT_VSDC || TrType == TT_CDA)){
|
||||
if (GetCardPSVendor(AID, AIDlen) == CV_VISA && (TrType == TT_VSDC || TrType == TT_CDA)) {
|
||||
PrintAndLogEx(NORMAL, "\n--> VSDC transaction.");
|
||||
|
||||
PrintAndLogEx(NORMAL, "* * Calc CDOL1");
|
||||
|
@ -1323,18 +1337,18 @@ int CmdEMVExec(const char *cmd) {
|
|||
|
||||
// here must be AC2, but we dont make external authenticate (
|
||||
|
||||
/* // AC2
|
||||
PRINT_INDENT(level);
|
||||
if ((CID & EMVAC_AC2_MASK) == EMVAC_AAC2) fprintf(f, "\tAC2: AAC (Transaction declined)\n");
|
||||
if ((CID & EMVAC_AC2_MASK) == EMVAC_TC2) fprintf(f, "\tAC2: TC (Transaction approved)\n");
|
||||
if ((CID & EMVAC_AC2_MASK) == EMVAC_ARQC2) fprintf(f, "\tAC2: not requested (ARQC)\n");
|
||||
if ((CID & EMVAC_AC2_MASK) == EMVAC_AC2_MASK) fprintf(f, "\tAC2: RFU\n");
|
||||
*/
|
||||
/* // AC2
|
||||
PRINT_INDENT(level);
|
||||
if ((CID & EMVAC_AC2_MASK) == EMVAC_AAC2) fprintf(f, "\tAC2: AAC (Transaction declined)\n");
|
||||
if ((CID & EMVAC_AC2_MASK) == EMVAC_TC2) fprintf(f, "\tAC2: TC (Transaction approved)\n");
|
||||
if ((CID & EMVAC_AC2_MASK) == EMVAC_ARQC2) fprintf(f, "\tAC2: not requested (ARQC)\n");
|
||||
if ((CID & EMVAC_AC2_MASK) == EMVAC_AC2_MASK) fprintf(f, "\tAC2: RFU\n");
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
|
||||
// Destroy TLV's
|
||||
free(pdol_data_tlv);
|
||||
|
@ -1345,7 +1359,8 @@ int CmdEMVExec(const char *cmd) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CmdEMVScan(const char *cmd) {
|
||||
int CmdEMVScan(const char *cmd)
|
||||
{
|
||||
uint8_t AID[APDU_AID_LEN] = {0};
|
||||
size_t AIDlen = 0;
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
|
@ -1356,12 +1371,12 @@ int CmdEMVScan(const char *cmd) {
|
|||
json_error_t error;
|
||||
|
||||
CLIParserInit("emv scan",
|
||||
"Scan EMV card and save it contents to a file.",
|
||||
"It executes EMV contactless transaction and saves result to a file which can be used for emulation\n"
|
||||
"Usage:\n\temv scan -at -> scan MSD transaction mode and show APDU and TLV\n"
|
||||
"\temv scan -c -> scan CDA transaction mode\n");
|
||||
"Scan EMV card and save it contents to a file.",
|
||||
"It executes EMV contactless transaction and saves result to a file which can be used for emulation\n"
|
||||
"Usage:\n\temv scan -at -> scan MSD transaction mode and show APDU and TLV\n"
|
||||
"\temv scan -c -> scan CDA transaction mode\n");
|
||||
|
||||
void* argtable[] = {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses."),
|
||||
arg_lit0("tT", "tlv", "TLV decode results."),
|
||||
|
@ -1399,7 +1414,7 @@ int CmdEMVScan(const char *cmd) {
|
|||
channel = ECC_CONTACT;
|
||||
PrintChannel(channel);
|
||||
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
|
||||
uint8_t relfname[250] ={0};
|
||||
uint8_t relfname[250] = {0};
|
||||
char *crelfname = (char *)relfname;
|
||||
int relfnamelen = 0;
|
||||
CLIGetStrWithReturn(12, relfname, &relfnamelen);
|
||||
|
@ -1407,7 +1422,7 @@ int CmdEMVScan(const char *cmd) {
|
|||
|
||||
#ifndef WITH_SMARTCARD
|
||||
// not compiled with smartcard functionality, we need to exit
|
||||
if ( channel == ECC_CONTACT ) {
|
||||
if (channel == ECC_CONTACT) {
|
||||
PrintAndLogEx(WARNING, "PM3 Client is not compiled with support for SMARTCARD. Exiting.");
|
||||
return 0;
|
||||
}
|
||||
|
@ -1438,7 +1453,7 @@ int CmdEMVScan(const char *cmd) {
|
|||
}
|
||||
|
||||
// drop field at start
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
|
||||
JsonSaveStr(root, "$.File.Created", "proxmark3 `emv scan`");
|
||||
|
||||
|
@ -1478,7 +1493,7 @@ int CmdEMVScan(const char *cmd) {
|
|||
PrintAndLogEx(NORMAL, "--> PPSE.");
|
||||
res = EMVSelectPSE(channel, true, true, 2, buf, sizeof(buf), &len, &sw);
|
||||
|
||||
if (!res && sw == 0x9000){
|
||||
if (!res && sw == 0x9000) {
|
||||
if (decodeTLV)
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
|
||||
|
@ -1505,7 +1520,7 @@ int CmdEMVScan(const char *cmd) {
|
|||
if (EMVSearch(channel, false, true, decodeTLV, tlvSelect)) {
|
||||
PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit...");
|
||||
tlvdb_free(tlvSelect);
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
@ -1521,7 +1536,7 @@ int CmdEMVScan(const char *cmd) {
|
|||
|
||||
if (!AIDlen) {
|
||||
PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit...");
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
@ -1540,7 +1555,7 @@ int CmdEMVScan(const char *cmd) {
|
|||
if (res) {
|
||||
PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res);
|
||||
tlvdb_free(tlvRoot);
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
return 5;
|
||||
}
|
||||
|
||||
|
@ -1565,10 +1580,10 @@ int CmdEMVScan(const char *cmd) {
|
|||
|
||||
PrintAndLogEx(NORMAL, "-->Calc PDOL.");
|
||||
struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
|
||||
if (!pdol_data_tlv){
|
||||
if (!pdol_data_tlv) {
|
||||
PrintAndLogEx(ERR, "Can't create PDOL TLV.");
|
||||
tlvdb_free(tlvRoot);
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
return 6;
|
||||
}
|
||||
|
||||
|
@ -1577,7 +1592,7 @@ int CmdEMVScan(const char *cmd) {
|
|||
if (!pdol_data_tlv_data) {
|
||||
PrintAndLogEx(ERR, "Can't create PDOL data.");
|
||||
tlvdb_free(tlvRoot);
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
return 6;
|
||||
}
|
||||
PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
|
||||
|
@ -1591,7 +1606,7 @@ int CmdEMVScan(const char *cmd) {
|
|||
if (res) {
|
||||
PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw);
|
||||
tlvdb_free(tlvRoot);
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
return 7;
|
||||
}
|
||||
ProcessGPOResponseFormat1(tlvRoot, buf, len, decodeTLV);
|
||||
|
@ -1610,7 +1625,7 @@ int CmdEMVScan(const char *cmd) {
|
|||
PrintAndLogEx(INFO, "-->Read records from AFL.");
|
||||
const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL);
|
||||
|
||||
while(AFL && AFL->len) {
|
||||
while (AFL && AFL->len) {
|
||||
if (AFL->len % 4) {
|
||||
PrintAndLogEx(ERR, "Wrong AFL length: %d", AFL->len);
|
||||
break;
|
||||
|
@ -1639,7 +1654,7 @@ int CmdEMVScan(const char *cmd) {
|
|||
continue;
|
||||
}
|
||||
|
||||
for(int n = SFIstart; n <= SFIend; n++) {
|
||||
for (int n = SFIstart; n <= SFIend; n++) {
|
||||
PrintAndLogEx(INFO, "---->SFI[%02x] %d", SFI, n);
|
||||
|
||||
res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
|
@ -1683,7 +1698,7 @@ int CmdEMVScan(const char *cmd) {
|
|||
// free tlv object
|
||||
tlvdb_free(tlvRoot);
|
||||
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
|
||||
res = json_dump_file(root, fname, JSON_INDENT(2));
|
||||
if (res) {
|
||||
|
@ -1698,15 +1713,18 @@ int CmdEMVScan(const char *cmd) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CmdEMVList(const char *Cmd) {
|
||||
int CmdEMVList(const char *Cmd)
|
||||
{
|
||||
return CmdTraceList("7816");
|
||||
}
|
||||
|
||||
int CmdEMVTest(const char *cmd) {
|
||||
int CmdEMVTest(const char *cmd)
|
||||
{
|
||||
return ExecuteCryptoTests(true);
|
||||
}
|
||||
|
||||
int CmdEMVRoca(const char *cmd) {
|
||||
int CmdEMVRoca(const char *cmd)
|
||||
{
|
||||
uint8_t AID[APDU_AID_LEN] = {0};
|
||||
size_t AIDlen = 0;
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
|
@ -1715,13 +1733,13 @@ int CmdEMVRoca(const char *cmd) {
|
|||
int res;
|
||||
|
||||
CLIParserInit("emv roca",
|
||||
"Tries to extract public keys and run the ROCA test against them.\n",
|
||||
"Usage:\n"
|
||||
"\temv roca -w -> select --CONTACT-- card and run test\n"
|
||||
"\temv roca -> select --CONTACTLESS-- card and run test\n"
|
||||
);
|
||||
"Tries to extract public keys and run the ROCA test against them.\n",
|
||||
"Usage:\n"
|
||||
"\temv roca -w -> select --CONTACT-- card and run test\n"
|
||||
"\temv roca -> select --CONTACTLESS-- card and run test\n"
|
||||
);
|
||||
|
||||
void* argtable[] = {
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("tT", "selftest", "self test"),
|
||||
arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."),
|
||||
|
@ -1740,7 +1758,7 @@ int CmdEMVRoca(const char *cmd) {
|
|||
|
||||
#ifndef WITH_SMARTCARD
|
||||
// not compiled with smartcard functionality, we need to exit
|
||||
if ( channel == ECC_CONTACT ) {
|
||||
if (channel == ECC_CONTACT) {
|
||||
PrintAndLogEx(WARNING, "PM3 Client is not compiled with support for SMARTCARD. Exiting.");
|
||||
return 0;
|
||||
}
|
||||
|
@ -1768,7 +1786,7 @@ int CmdEMVRoca(const char *cmd) {
|
|||
if (EMVSearch(channel, false, true, false, tlvSelect)) {
|
||||
PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit...");
|
||||
tlvdb_free(tlvSelect);
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
@ -1784,7 +1802,7 @@ int CmdEMVRoca(const char *cmd) {
|
|||
|
||||
if (!AIDlen) {
|
||||
PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit...");
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
@ -1799,7 +1817,7 @@ int CmdEMVRoca(const char *cmd) {
|
|||
if (res) {
|
||||
PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res);
|
||||
tlvdb_free(tlvRoot);
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
return 5;
|
||||
}
|
||||
|
||||
|
@ -1808,10 +1826,10 @@ int CmdEMVRoca(const char *cmd) {
|
|||
|
||||
PrintAndLogEx(NORMAL, "-->Calc PDOL.");
|
||||
struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
|
||||
if (!pdol_data_tlv){
|
||||
if (!pdol_data_tlv) {
|
||||
PrintAndLogEx(ERR, "Can't create PDOL TLV.");
|
||||
tlvdb_free(tlvRoot);
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
return 6;
|
||||
}
|
||||
|
||||
|
@ -1820,7 +1838,7 @@ int CmdEMVRoca(const char *cmd) {
|
|||
if (!pdol_data_tlv_data) {
|
||||
PrintAndLogEx(ERR, "Can't create PDOL data.");
|
||||
tlvdb_free(tlvRoot);
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
free(pdol_data_tlv);
|
||||
return 6;
|
||||
}
|
||||
|
@ -1835,7 +1853,7 @@ int CmdEMVRoca(const char *cmd) {
|
|||
if (res) {
|
||||
PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw);
|
||||
tlvdb_free(tlvRoot);
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
return 7;
|
||||
}
|
||||
ProcessGPOResponseFormat1(tlvRoot, buf, len, false);
|
||||
|
@ -1843,7 +1861,7 @@ int CmdEMVRoca(const char *cmd) {
|
|||
PrintAndLogEx(INFO, "-->Read records from AFL.");
|
||||
const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL);
|
||||
|
||||
while(AFL && AFL->len) {
|
||||
while (AFL && AFL->len) {
|
||||
if (AFL->len % 4) {
|
||||
PrintAndLogEx(ERR, "Wrong AFL length: %d", AFL->len);
|
||||
break;
|
||||
|
@ -1861,7 +1879,7 @@ int CmdEMVRoca(const char *cmd) {
|
|||
continue;
|
||||
}
|
||||
|
||||
for(int n = SFIstart; n <= SFIend; n++) {
|
||||
for (int n = SFIstart; n <= SFIend; n++) {
|
||||
PrintAndLogEx(INFO, "---->SFI[%02x] %d", SFI, n);
|
||||
|
||||
res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
|
@ -1894,10 +1912,10 @@ int CmdEMVRoca(const char *cmd) {
|
|||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %s IDX %02hhx CSN %s",
|
||||
sprint_hex(issuer_pk->rid, 5),
|
||||
issuer_pk->index,
|
||||
sprint_hex(issuer_pk->serial, 3)
|
||||
);
|
||||
sprint_hex(issuer_pk->rid, 5),
|
||||
issuer_pk->index,
|
||||
sprint_hex(issuer_pk->serial, 3)
|
||||
);
|
||||
|
||||
|
||||
struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlvRoot, NULL);
|
||||
|
@ -1908,10 +1926,10 @@ int CmdEMVRoca(const char *cmd) {
|
|||
goto out;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %s IDX %02hhx CSN %s\n",
|
||||
sprint_hex(icc_pk->rid, 5),
|
||||
icc_pk->index,
|
||||
sprint_hex(icc_pk->serial, 3)
|
||||
);
|
||||
sprint_hex(icc_pk->rid, 5),
|
||||
icc_pk->index,
|
||||
sprint_hex(icc_pk->serial, 3)
|
||||
);
|
||||
|
||||
PrintAndLogEx(INFO, "ICC pk modulus: %s", sprint_hex_inrow(icc_pk->modulus, icc_pk->mlen));
|
||||
|
||||
|
@ -1933,7 +1951,7 @@ out:
|
|||
// free tlv object
|
||||
tlvdb_free(tlvRoot);
|
||||
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1962,13 +1980,15 @@ static command_t CommandTable[] = {
|
|||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
int CmdEMV(const char *Cmd) {
|
||||
int CmdEMV(const char *Cmd)
|
||||
{
|
||||
clearCommandBuffer();
|
||||
CmdsParse(CommandTable, Cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CmdHelp(const char *Cmd) {
|
||||
int CmdHelp(const char *Cmd)
|
||||
{
|
||||
CmdsHelp(CommandTable);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ static struct crypto_pk *crypto_pk_polarssl_open_rsa(va_list vl)
|
|||
mbedtls_mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen);
|
||||
|
||||
int res = mbedtls_rsa_check_pubkey(&cp->ctx);
|
||||
if(res != 0) {
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "PolarSSL public key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen);
|
||||
free(cp);
|
||||
return NULL;
|
||||
|
@ -138,18 +138,18 @@ static struct crypto_pk *crypto_pk_polarssl_open_priv_rsa(va_list vl)
|
|||
mbedtls_rsa_init(&cp->ctx, MBEDTLS_RSA_PKCS_V15, 0);
|
||||
|
||||
cp->ctx.len = modlen; // size(N) in bytes
|
||||
mbedtls_mpi_read_binary(&cp->ctx.N, (const unsigned char *)mod, modlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.N, (const unsigned char *)mod, modlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen);
|
||||
|
||||
mbedtls_mpi_read_binary(&cp->ctx.D, (const unsigned char *)d, dlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.P, (const unsigned char *)p, plen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.Q, (const unsigned char *)q, qlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.D, (const unsigned char *)d, dlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.P, (const unsigned char *)p, plen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.Q, (const unsigned char *)q, qlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.DP, (const unsigned char *)dp, dplen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.DQ, (const unsigned char *)dq, dqlen);
|
||||
mbedtls_mpi_inv_mod(&cp->ctx.QP, &cp->ctx.Q, &cp->ctx.P);
|
||||
|
||||
int res = mbedtls_rsa_check_privkey(&cp->ctx);
|
||||
if(res != 0) {
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "PolarSSL private key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen);
|
||||
free(cp);
|
||||
return NULL;
|
||||
|
@ -158,13 +158,14 @@ static struct crypto_pk *crypto_pk_polarssl_open_priv_rsa(va_list vl)
|
|||
return &cp->cp;
|
||||
}
|
||||
|
||||
static int myrand(void *rng_state, unsigned char *output, size_t len) {
|
||||
static int myrand(void *rng_state, unsigned char *output, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if(rng_state != NULL)
|
||||
if (rng_state != NULL)
|
||||
rng_state = NULL;
|
||||
|
||||
for( i = 0; i < len; ++i )
|
||||
for (i = 0; i < len; ++i)
|
||||
output[i] = rand();
|
||||
|
||||
return 0;
|
||||
|
@ -217,7 +218,7 @@ static unsigned char *crypto_pk_polarssl_encrypt(const struct crypto_pk *_cp, co
|
|||
}
|
||||
|
||||
res = mbedtls_rsa_public(&cp->ctx, buf, result);
|
||||
if(res) {
|
||||
if (res) {
|
||||
printf("RSA encrypt failed. Error: %x data len: %zd key len: %zd\n", res * -1, len, keylen);
|
||||
free(result);
|
||||
return NULL;
|
||||
|
@ -244,7 +245,7 @@ static unsigned char *crypto_pk_polarssl_decrypt(const struct crypto_pk *_cp, co
|
|||
}
|
||||
|
||||
res = mbedtls_rsa_private(&cp->ctx, NULL, NULL, buf, result); // CHECK???
|
||||
if(res) {
|
||||
if (res) {
|
||||
printf("RSA decrypt failed. Error: %x data len: %zd key len: %zd\n", res * -1, len, keylen);
|
||||
free(result);
|
||||
return NULL;
|
||||
|
@ -260,14 +261,14 @@ static size_t crypto_pk_polarssl_get_nbits(const struct crypto_pk *_cp)
|
|||
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||
|
||||
return cp->ctx.len * 8;
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *crypto_pk_polarssl_get_parameter(const struct crypto_pk *_cp, unsigned param, size_t *plen)
|
||||
{
|
||||
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||
unsigned char *result = NULL;
|
||||
switch(param){
|
||||
switch (param) {
|
||||
// mod
|
||||
case 0:
|
||||
*plen = mbedtls_mpi_size(&cp->ctx.N);
|
||||
|
|
|
@ -51,7 +51,7 @@ void dump_buffer(const unsigned char *ptr, size_t len, FILE *f, int level)
|
|||
}
|
||||
fprintf(f, " |");
|
||||
for (j = 0; j < 16 && i + j < len; j++) {
|
||||
fprintf(f, "%c", (ptr[i+j] >= 0x20 && ptr[i+j] < 0x7f) ? ptr[i+j] : '.' );
|
||||
fprintf(f, "%c", (ptr[i + j] >= 0x20 && ptr[i + j] < 0x7f) ? ptr[i + j] : '.');
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
|
|
@ -31,12 +31,12 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#define BCD(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
|
||||
-1)
|
||||
-1)
|
||||
|
||||
#define HEX(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
|
||||
((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : \
|
||||
((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : \
|
||||
-1)
|
||||
((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : \
|
||||
((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : \
|
||||
-1)
|
||||
|
||||
#define TOHEX(v) ((v) < 10 ? (v) + '0' : (v) - 10 + 'a')
|
||||
|
||||
|
@ -180,8 +180,8 @@ struct emv_pk *emv_pk_parse_pk(char *buf)
|
|||
goto out;
|
||||
buf += l;
|
||||
|
||||
r->modulus = malloc(2048/8);
|
||||
l = emv_pk_read_bin(buf, r->modulus, 2048/8, &r->mlen);
|
||||
r->modulus = malloc(2048 / 8);
|
||||
l = emv_pk_read_bin(buf, r->modulus, 2048 / 8, &r->mlen);
|
||||
if (l <= 0)
|
||||
goto out2;
|
||||
buf += l;
|
||||
|
@ -270,9 +270,9 @@ char *emv_pk_dump_pk(const struct emv_pk *pk)
|
|||
out[outpos++] = TOHEX((pk->expire >> 20) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 16) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 12) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 8 ) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 4 ) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 0 ) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 8) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 4) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 0) & 0xf);
|
||||
out[outpos++] = ' ';
|
||||
|
||||
if (pk->pk_algo == PK_RSA) {
|
||||
|
@ -321,7 +321,7 @@ char *emv_pk_dump_pk(const struct emv_pk *pk)
|
|||
goto err;
|
||||
outpos += rc;
|
||||
|
||||
out[outpos-1] = '\0';
|
||||
out[outpos - 1] = '\0';
|
||||
|
||||
return out;
|
||||
|
||||
|
@ -389,10 +389,10 @@ void emv_pk_free(struct emv_pk *pk)
|
|||
}
|
||||
|
||||
static struct emv_pk *emv_pk_get_ca_pk_from_file(const char *fname,
|
||||
const unsigned char *rid,
|
||||
unsigned char idx)
|
||||
const unsigned char *rid,
|
||||
unsigned char idx)
|
||||
{
|
||||
if (!fname)
|
||||
if (!fname)
|
||||
return NULL;
|
||||
|
||||
FILE *f = fopen(fname, "r");
|
||||
|
@ -431,13 +431,13 @@ char *emv_pk_get_ca_pk_file(const char *dirname, const unsigned char *rid, unsig
|
|||
|
||||
char *filename;
|
||||
int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx_%02hhx.0",
|
||||
dirname,
|
||||
rid[0],
|
||||
rid[1],
|
||||
rid[2],
|
||||
rid[3],
|
||||
rid[4],
|
||||
idx);
|
||||
dirname,
|
||||
rid[0],
|
||||
rid[1],
|
||||
rid[2],
|
||||
rid[3],
|
||||
rid[4],
|
||||
idx);
|
||||
|
||||
if (ret <= 0)
|
||||
return NULL;
|
||||
|
@ -452,12 +452,12 @@ char *emv_pk_get_ca_pk_rid_file(const char *dirname, const unsigned char *rid)
|
|||
|
||||
char *filename;
|
||||
int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx.pks",
|
||||
dirname,
|
||||
rid[0],
|
||||
rid[1],
|
||||
rid[2],
|
||||
rid[3],
|
||||
rid[4]);
|
||||
dirname,
|
||||
rid[0],
|
||||
rid[1],
|
||||
rid[2],
|
||||
rid[3],
|
||||
rid[4]);
|
||||
|
||||
if (ret <= 0)
|
||||
return NULL;
|
||||
|
@ -469,22 +469,22 @@ struct emv_pk *emv_pk_get_ca_pk(const unsigned char *rid, unsigned char idx)
|
|||
{
|
||||
struct emv_pk *pk = NULL;
|
||||
|
||||
/* if (!pk) {
|
||||
char *fname = emv_pk_get_ca_pk_file(NULL, rid, idx);
|
||||
if (fname) {
|
||||
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||
free(fname);
|
||||
/* if (!pk) {
|
||||
char *fname = emv_pk_get_ca_pk_file(NULL, rid, idx);
|
||||
if (fname) {
|
||||
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||
free(fname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pk) {
|
||||
char *fname = emv_pk_get_ca_pk_rid_file(NULL, rid);
|
||||
if (fname) {
|
||||
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||
free(fname);
|
||||
if (!pk) {
|
||||
char *fname = emv_pk_get_ca_pk_rid_file(NULL, rid);
|
||||
if (fname) {
|
||||
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||
free(fname);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
*/
|
||||
if (!pk) {
|
||||
const char *relfname = "emv/capk.txt";
|
||||
|
||||
|
@ -498,13 +498,13 @@ struct emv_pk *emv_pk_get_ca_pk(const unsigned char *rid, unsigned char idx)
|
|||
return NULL;
|
||||
|
||||
printf("Verifying CA PK for %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx %zd bits...",
|
||||
pk->rid[0],
|
||||
pk->rid[1],
|
||||
pk->rid[2],
|
||||
pk->rid[3],
|
||||
pk->rid[4],
|
||||
pk->index,
|
||||
pk->mlen * 8);
|
||||
pk->rid[0],
|
||||
pk->rid[1],
|
||||
pk->rid[2],
|
||||
pk->rid[3],
|
||||
pk->rid[4],
|
||||
pk->index,
|
||||
pk->mlen * 8);
|
||||
if (emv_pk_verify(pk)) {
|
||||
printf("OK\n");
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
#include <stdarg.h>
|
||||
|
||||
static bool strictExecution = true;
|
||||
void PKISetStrictExecution(bool se) {
|
||||
void PKISetStrictExecution(bool se)
|
||||
{
|
||||
strictExecution = se;
|
||||
}
|
||||
|
||||
|
@ -38,12 +39,12 @@ static const struct tlv empty_tlv = {.tag = 0x0, .len = 0, .value = empty_tlv_va
|
|||
static size_t emv_pki_hash_psn[256] = { 0, 0, 11, 2, 17, 2, };
|
||||
|
||||
static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
|
||||
uint8_t msgtype,
|
||||
size_t *len,
|
||||
const struct tlv *cert_tlv,
|
||||
int tlv_count,
|
||||
... /* A list of tlv pointers */
|
||||
)
|
||||
uint8_t msgtype,
|
||||
size_t *len,
|
||||
const struct tlv *cert_tlv,
|
||||
int tlv_count,
|
||||
... /* A list of tlv pointers */
|
||||
)
|
||||
{
|
||||
struct crypto_pk *kcp;
|
||||
unsigned char *data;
|
||||
|
@ -63,27 +64,27 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
|
|||
return NULL;
|
||||
}
|
||||
kcp = crypto_pk_open(enc_pk->pk_algo,
|
||||
enc_pk->modulus, enc_pk->mlen,
|
||||
enc_pk->exp, enc_pk->elen);
|
||||
enc_pk->modulus, enc_pk->mlen,
|
||||
enc_pk->exp, enc_pk->elen);
|
||||
if (!kcp)
|
||||
return NULL;
|
||||
|
||||
data = crypto_pk_encrypt(kcp, cert_tlv->value, cert_tlv->len, &data_len);
|
||||
crypto_pk_close(kcp);
|
||||
|
||||
/* if (true){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}*/
|
||||
/* if (true){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}*/
|
||||
|
||||
if (data[data_len-1] != 0xbc || data[0] != 0x6a || data[1] != msgtype) {
|
||||
if (data[data_len - 1] != 0xbc || data[0] != 0x6a || data[1] != msgtype) {
|
||||
printf("ERROR: Certificate format\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t hash_pos = emv_pki_hash_psn[msgtype];
|
||||
if (hash_pos == 0 || hash_pos > data_len){
|
||||
if (hash_pos == 0 || hash_pos > data_len) {
|
||||
printf("ERROR: Cant get hash position in the certificate\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
|
@ -115,8 +116,8 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
|
|||
memcpy(hash, crypto_hash_read(ch), hash_len);
|
||||
if (memcmp(data + data_len - 1 - hash_len, hash, hash_len)) {
|
||||
printf("ERROR: Calculated wrong hash\n");
|
||||
printf("decoded: %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len));
|
||||
printf("calculated: %s\n",sprint_hex(hash, hash_len));
|
||||
printf("decoded: %s\n", sprint_hex(data + data_len - 1 - hash_len, hash_len));
|
||||
printf("calculated: %s\n", sprint_hex(hash, hash_len));
|
||||
|
||||
if (strictExecution) {
|
||||
crypto_hash_close(ch);
|
||||
|
@ -163,15 +164,15 @@ static unsigned char emv_cn_get(const struct tlv *tlv, unsigned pos)
|
|||
}
|
||||
|
||||
static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
|
||||
unsigned char msgtype,
|
||||
const struct tlv *pan_tlv,
|
||||
const struct tlv *cert_tlv,
|
||||
const struct tlv *exp_tlv,
|
||||
const struct tlv *rem_tlv,
|
||||
const struct tlv *add_tlv,
|
||||
const struct tlv *sdatl_tlv,
|
||||
bool showData
|
||||
)
|
||||
unsigned char msgtype,
|
||||
const struct tlv *pan_tlv,
|
||||
const struct tlv *cert_tlv,
|
||||
const struct tlv *exp_tlv,
|
||||
const struct tlv *rem_tlv,
|
||||
const struct tlv *add_tlv,
|
||||
const struct tlv *sdatl_tlv,
|
||||
bool showData
|
||||
)
|
||||
{
|
||||
size_t pan_length;
|
||||
unsigned char *data;
|
||||
|
@ -194,19 +195,19 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
|
|||
}
|
||||
|
||||
data = emv_pki_decode_message(enc_pk, msgtype, &data_len,
|
||||
cert_tlv,
|
||||
5,
|
||||
rem_tlv,
|
||||
exp_tlv,
|
||||
add_tlv,
|
||||
sdatl_tlv,
|
||||
NULL);
|
||||
cert_tlv,
|
||||
5,
|
||||
rem_tlv,
|
||||
exp_tlv,
|
||||
add_tlv,
|
||||
sdatl_tlv,
|
||||
NULL);
|
||||
if (!data || data_len < 11 + pan_length) {
|
||||
printf("ERROR: Can't decode message\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (showData){
|
||||
if (showData) {
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
@ -265,9 +266,9 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
|
|||
memset(pk->pan + pan_length, 0xff, 10 - pan_length);
|
||||
|
||||
memcpy(pk->modulus, data + 11 + pan_length,
|
||||
pk_len < data_len - (11 + pan_length) ?
|
||||
pk_len :
|
||||
data_len - (11 + pan_length));
|
||||
pk_len < data_len - (11 + pan_length) ?
|
||||
pk_len :
|
||||
data_len - (11 + pan_length));
|
||||
memcpy(pk->modulus + data_len - (11 + pan_length), rem_tlv->value, rem_tlv->len);
|
||||
memcpy(pk->exp, exp_tlv->value, exp_tlv->len);
|
||||
|
||||
|
@ -277,26 +278,27 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
|
|||
}
|
||||
|
||||
static struct emv_pk *emv_pki_decode_key(const struct emv_pk *enc_pk,
|
||||
unsigned char msgtype,
|
||||
const struct tlv *pan_tlv,
|
||||
const struct tlv *cert_tlv,
|
||||
const struct tlv *exp_tlv,
|
||||
const struct tlv *rem_tlv,
|
||||
const struct tlv *add_tlv,
|
||||
const struct tlv *sdatl_tlv
|
||||
) {
|
||||
unsigned char msgtype,
|
||||
const struct tlv *pan_tlv,
|
||||
const struct tlv *cert_tlv,
|
||||
const struct tlv *exp_tlv,
|
||||
const struct tlv *rem_tlv,
|
||||
const struct tlv *add_tlv,
|
||||
const struct tlv *sdatl_tlv
|
||||
)
|
||||
{
|
||||
return emv_pki_decode_key_ex(enc_pk, msgtype, pan_tlv, cert_tlv, exp_tlv, rem_tlv, add_tlv, sdatl_tlv, false);
|
||||
}
|
||||
|
||||
struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db)
|
||||
{
|
||||
return emv_pki_decode_key(pk, 2,
|
||||
tlvdb_get(db, 0x5a, NULL),
|
||||
tlvdb_get(db, 0x90, NULL),
|
||||
tlvdb_get(db, 0x9f32, NULL),
|
||||
tlvdb_get(db, 0x92, NULL),
|
||||
NULL,
|
||||
NULL);
|
||||
tlvdb_get(db, 0x5a, NULL),
|
||||
tlvdb_get(db, 0x90, NULL),
|
||||
tlvdb_get(db, 0x9f32, NULL),
|
||||
tlvdb_get(db, 0x92, NULL),
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv)
|
||||
|
@ -310,12 +312,12 @@ struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *d
|
|||
};
|
||||
|
||||
struct emv_pk *res = emv_pki_decode_key(pk, 4,
|
||||
tlvdb_get(db, 0x5a, NULL),
|
||||
tlvdb_get(db, 0x9f46, NULL),
|
||||
tlvdb_get(db, 0x9f47, NULL),
|
||||
tlvdb_get(db, 0x9f48, NULL),
|
||||
sda_tlv,
|
||||
&sda_tdata);
|
||||
tlvdb_get(db, 0x5a, NULL),
|
||||
tlvdb_get(db, 0x9f46, NULL),
|
||||
tlvdb_get(db, 0x9f47, NULL),
|
||||
tlvdb_get(db, 0x9f48, NULL),
|
||||
sda_tlv,
|
||||
&sda_tdata);
|
||||
|
||||
free(sdatl); // malloc here: emv_pki_sdatl_fill
|
||||
return res;
|
||||
|
@ -324,15 +326,16 @@ struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *d
|
|||
struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db)
|
||||
{
|
||||
return emv_pki_decode_key(pk, 4,
|
||||
tlvdb_get(db, 0x5a, NULL),
|
||||
tlvdb_get(db, 0x9f2d, NULL),
|
||||
tlvdb_get(db, 0x9f2e, NULL),
|
||||
tlvdb_get(db, 0x9f2f, NULL),
|
||||
NULL,
|
||||
NULL);
|
||||
tlvdb_get(db, 0x5a, NULL),
|
||||
tlvdb_get(db, 0x9f2d, NULL),
|
||||
tlvdb_get(db, 0x9f2e, NULL),
|
||||
tlvdb_get(db, 0x9f2f, NULL),
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
unsigned char *emv_pki_sdatl_fill(const struct tlvdb *db, size_t *sdatl_len) {
|
||||
unsigned char *emv_pki_sdatl_fill(const struct tlvdb *db, size_t *sdatl_len)
|
||||
{
|
||||
uint8_t buf[2048] = {0};
|
||||
size_t len = 0;
|
||||
|
||||
|
@ -376,33 +379,35 @@ struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct t
|
|||
};
|
||||
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 3, &data_len,
|
||||
tlvdb_get(db, 0x93, NULL),
|
||||
3,
|
||||
sda_tlv,
|
||||
&sda_tdata,
|
||||
NULL);
|
||||
tlvdb_get(db, 0x93, NULL),
|
||||
3,
|
||||
sda_tlv,
|
||||
&sda_tdata,
|
||||
NULL);
|
||||
|
||||
free(sdatl); // malloc here: emv_pki_sdatl_fill
|
||||
|
||||
if (!data || data_len < 5)
|
||||
return NULL;
|
||||
|
||||
if (showData){
|
||||
if (showData) {
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
||||
struct tlvdb *dac_db = tlvdb_fixed(0x9f45, 2, data+3);
|
||||
struct tlvdb *dac_db = tlvdb_fixed(0x9f45, 2, data + 3);
|
||||
|
||||
free(data);
|
||||
|
||||
return dac_db;
|
||||
}
|
||||
struct tlvdb *emv_pki_recover_dac(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv) {
|
||||
struct tlvdb *emv_pki_recover_dac(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv)
|
||||
{
|
||||
return emv_pki_recover_dac_ex(enc_pk, db, sda_tlv, false);
|
||||
}
|
||||
|
||||
struct tlvdb *emv_pki_recover_idn(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv) {
|
||||
struct tlvdb *emv_pki_recover_idn(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv)
|
||||
{
|
||||
return emv_pki_recover_idn_ex(enc_pk, db, dyn_tlv, false);
|
||||
}
|
||||
|
||||
|
@ -410,10 +415,10 @@ struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct t
|
|||
{
|
||||
size_t data_len;
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||
tlvdb_get(db, 0x9f4b, NULL),
|
||||
2,
|
||||
dyn_tlv,
|
||||
NULL);
|
||||
tlvdb_get(db, 0x9f4b, NULL),
|
||||
2,
|
||||
dyn_tlv,
|
||||
NULL);
|
||||
|
||||
if (!data || data_len < 3)
|
||||
return NULL;
|
||||
|
@ -423,7 +428,7 @@ struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct t
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (showData){
|
||||
if (showData) {
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
@ -446,13 +451,13 @@ struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct t
|
|||
{
|
||||
size_t data_len;
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||
tlvdb_get(db, 0x9f4b, NULL),
|
||||
5,
|
||||
tlvdb_get(db, 0x9f37, NULL),
|
||||
tlvdb_get(db, 0x9f02, NULL),
|
||||
tlvdb_get(db, 0x5f2a, NULL),
|
||||
tlvdb_get(db, 0x9f69, NULL),
|
||||
NULL);
|
||||
tlvdb_get(db, 0x9f4b, NULL),
|
||||
5,
|
||||
tlvdb_get(db, 0x9f37, NULL),
|
||||
tlvdb_get(db, 0x9f02, NULL),
|
||||
tlvdb_get(db, 0x5f2a, NULL),
|
||||
tlvdb_get(db, 0x9f69, NULL),
|
||||
NULL);
|
||||
|
||||
if (!data || data_len < 3)
|
||||
return NULL;
|
||||
|
@ -462,7 +467,7 @@ struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct t
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (showData){
|
||||
if (showData) {
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
@ -501,19 +506,19 @@ static bool tlv_hash(void *data, const struct tlv *tlv, int level, bool is_leaf)
|
|||
}
|
||||
|
||||
struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||
const struct tlvdb *this_db,
|
||||
const struct tlv *pdol_data_tlv,
|
||||
const struct tlv *crm1_tlv,
|
||||
const struct tlv *crm2_tlv)
|
||||
const struct tlvdb *this_db,
|
||||
const struct tlv *pdol_data_tlv,
|
||||
const struct tlv *crm1_tlv,
|
||||
const struct tlv *crm2_tlv)
|
||||
{
|
||||
return emv_pki_perform_cda_ex(enc_pk, db, this_db, pdol_data_tlv, crm1_tlv, crm2_tlv, false);
|
||||
}
|
||||
struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||
const struct tlvdb *this_db, // AC TLV result
|
||||
const struct tlv *pdol_data_tlv, // PDOL
|
||||
const struct tlv *crm1_tlv, // CDOL1
|
||||
const struct tlv *crm2_tlv, // CDOL2
|
||||
bool showData)
|
||||
const struct tlvdb *this_db, // AC TLV result
|
||||
const struct tlv *pdol_data_tlv, // PDOL
|
||||
const struct tlv *crm1_tlv, // CDOL1
|
||||
const struct tlv *crm2_tlv, // CDOL2
|
||||
bool showData)
|
||||
{
|
||||
const struct tlv *un_tlv = tlvdb_get(db, 0x9f37, NULL);
|
||||
const struct tlv *cid_tlv = tlvdb_get(this_db, 0x9f27, NULL);
|
||||
|
@ -523,16 +528,16 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t
|
|||
|
||||
size_t data_len = 0;
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||
tlvdb_get(this_db, 0x9f4b, NULL),
|
||||
2,
|
||||
un_tlv,
|
||||
NULL);
|
||||
tlvdb_get(this_db, 0x9f4b, NULL),
|
||||
2,
|
||||
un_tlv,
|
||||
NULL);
|
||||
if (!data || data_len < 3) {
|
||||
printf("ERROR: can't decode message. len %zu\n", data_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (showData){
|
||||
if (showData) {
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
|
|
@ -34,15 +34,15 @@ struct tlvdb *emv_pki_recover_idn(const struct emv_pk *pk, const struct tlvdb *d
|
|||
struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData);
|
||||
struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, bool showData);
|
||||
struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||
const struct tlvdb *this_db,
|
||||
const struct tlv *pdol_data_tlv,
|
||||
const struct tlv *crm1_tlv,
|
||||
const struct tlv *crm2_tlv);
|
||||
const struct tlvdb *this_db,
|
||||
const struct tlv *pdol_data_tlv,
|
||||
const struct tlv *crm1_tlv,
|
||||
const struct tlv *crm2_tlv);
|
||||
struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||
const struct tlvdb *this_db,
|
||||
const struct tlv *pdol_data_tlv,
|
||||
const struct tlv *crm1_tlv,
|
||||
const struct tlv *crm2_tlv,
|
||||
bool showData);
|
||||
const struct tlvdb *this_db,
|
||||
const struct tlv *pdol_data_tlv,
|
||||
const struct tlv *crm1_tlv,
|
||||
const struct tlv *crm2_tlv,
|
||||
bool showData);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
#include <stdarg.h>
|
||||
|
||||
struct emv_pk *emv_pki_make_ca(const struct crypto_pk *cp,
|
||||
const unsigned char *rid, unsigned char index,
|
||||
unsigned int expire, enum crypto_algo_hash hash_algo)
|
||||
const unsigned char *rid, unsigned char index,
|
||||
unsigned int expire, enum crypto_algo_hash hash_algo)
|
||||
{
|
||||
size_t modlen, explen;
|
||||
unsigned char *mod, *exp;
|
||||
|
@ -82,10 +82,10 @@ struct emv_pk *emv_pki_make_ca(const struct crypto_pk *cp,
|
|||
}
|
||||
|
||||
static struct tlvdb *emv_pki_sign_message(const struct crypto_pk *cp,
|
||||
tlv_tag_t cert_tag, tlv_tag_t rem_tag,
|
||||
const unsigned char *msg, size_t msg_len,
|
||||
... /* A list of tlv pointers, end with NULL */
|
||||
)
|
||||
tlv_tag_t cert_tag, tlv_tag_t rem_tag,
|
||||
const unsigned char *msg, size_t msg_len,
|
||||
... /* A list of tlv pointers, end with NULL */
|
||||
)
|
||||
{
|
||||
size_t tmp_len = (crypto_pk_get_nbits(cp) + 7) / 8;
|
||||
unsigned char *tmp = malloc(tmp_len);
|
||||
|
@ -168,14 +168,14 @@ static struct tlvdb *emv_pki_sign_message(const struct crypto_pk *cp,
|
|||
}
|
||||
|
||||
static struct tlvdb *emv_pki_sign_key(const struct crypto_pk *cp,
|
||||
struct emv_pk *ipk,
|
||||
unsigned char msgtype,
|
||||
size_t pan_len,
|
||||
tlv_tag_t cert_tag,
|
||||
tlv_tag_t exp_tag,
|
||||
tlv_tag_t rem_tag,
|
||||
const struct tlv *add_tlv
|
||||
)
|
||||
struct emv_pk *ipk,
|
||||
unsigned char msgtype,
|
||||
size_t pan_len,
|
||||
tlv_tag_t cert_tag,
|
||||
tlv_tag_t exp_tag,
|
||||
tlv_tag_t rem_tag,
|
||||
const struct tlv *add_tlv
|
||||
)
|
||||
{
|
||||
unsigned pos = 0;
|
||||
unsigned char *msg = malloc(1 + pan_len + 2 + 3 + 1 + 1 + 1 + 1 + ipk->mlen);
|
||||
|
@ -184,10 +184,12 @@ static struct tlvdb *emv_pki_sign_key(const struct crypto_pk *cp,
|
|||
return NULL;
|
||||
|
||||
msg[pos++] = msgtype;
|
||||
memcpy(msg + pos, ipk->pan, pan_len); pos += pan_len;
|
||||
memcpy(msg + pos, ipk->pan, pan_len);
|
||||
pos += pan_len;
|
||||
msg[pos++] = (ipk->expire >> 8) & 0xff;
|
||||
msg[pos++] = (ipk->expire >> 16) & 0xff;
|
||||
memcpy(msg + pos, ipk->serial, 3); pos += 3;
|
||||
memcpy(msg + pos, ipk->serial, 3);
|
||||
pos += 3;
|
||||
msg[pos++] = ipk->hash_algo;
|
||||
msg[pos++] = ipk->pk_algo;
|
||||
msg[pos++] = ipk->mlen;
|
||||
|
@ -203,11 +205,11 @@ static struct tlvdb *emv_pki_sign_key(const struct crypto_pk *cp,
|
|||
}
|
||||
|
||||
struct tlvdb *db = emv_pki_sign_message(cp,
|
||||
cert_tag, rem_tag,
|
||||
msg, pos,
|
||||
tlvdb_get(exp_db, exp_tag, NULL),
|
||||
add_tlv,
|
||||
NULL);
|
||||
cert_tag, rem_tag,
|
||||
msg, pos,
|
||||
tlvdb_get(exp_db, exp_tag, NULL),
|
||||
add_tlv,
|
||||
NULL);
|
||||
free(msg);
|
||||
if (!db)
|
||||
return NULL;
|
||||
|
@ -235,21 +237,21 @@ struct tlvdb *emv_pki_sign_icc_pe_cert(const struct crypto_pk *cp, struct emv_pk
|
|||
struct tlvdb *emv_pki_sign_dac(const struct crypto_pk *cp, const struct tlv *dac_tlv, const struct tlv *sda_tlv)
|
||||
{
|
||||
unsigned pos = 0;
|
||||
unsigned char *msg = malloc(1+1+dac_tlv->len);
|
||||
unsigned char *msg = malloc(1 + 1 + dac_tlv->len);
|
||||
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
msg[pos++] = 3;
|
||||
msg[pos++] = HASH_SHA_1;
|
||||
memcpy(msg+pos, dac_tlv->value, dac_tlv->len);
|
||||
memcpy(msg + pos, dac_tlv->value, dac_tlv->len);
|
||||
pos += dac_tlv->len;
|
||||
|
||||
struct tlvdb *db = emv_pki_sign_message(cp,
|
||||
0x93, 0,
|
||||
msg, pos,
|
||||
sda_tlv,
|
||||
NULL);
|
||||
0x93, 0,
|
||||
msg, pos,
|
||||
sda_tlv,
|
||||
NULL);
|
||||
|
||||
free(msg);
|
||||
|
||||
|
@ -259,7 +261,7 @@ struct tlvdb *emv_pki_sign_dac(const struct crypto_pk *cp, const struct tlv *dac
|
|||
struct tlvdb *emv_pki_sign_idn(const struct crypto_pk *cp, const struct tlv *idn_tlv, const struct tlv *dyn_tlv)
|
||||
{
|
||||
unsigned pos = 0;
|
||||
unsigned char *msg = malloc(1+1+1+1+idn_tlv->len);
|
||||
unsigned char *msg = malloc(1 + 1 + 1 + 1 + idn_tlv->len);
|
||||
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
@ -268,14 +270,14 @@ struct tlvdb *emv_pki_sign_idn(const struct crypto_pk *cp, const struct tlv *idn
|
|||
msg[pos++] = HASH_SHA_1;
|
||||
msg[pos++] = idn_tlv->len + 1;
|
||||
msg[pos++] = idn_tlv->len;
|
||||
memcpy(msg+pos, idn_tlv->value, idn_tlv->len);
|
||||
memcpy(msg + pos, idn_tlv->value, idn_tlv->len);
|
||||
pos += idn_tlv->len;
|
||||
|
||||
struct tlvdb *db = emv_pki_sign_message(cp,
|
||||
0x9f4b, 0,
|
||||
msg, pos,
|
||||
dyn_tlv,
|
||||
NULL);
|
||||
0x9f4b, 0,
|
||||
msg, pos,
|
||||
dyn_tlv,
|
||||
NULL);
|
||||
|
||||
free(msg);
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#include <stddef.h>
|
||||
|
||||
struct emv_pk *emv_pki_make_ca(const struct crypto_pk *cp,
|
||||
const unsigned char *rid, unsigned char index,
|
||||
unsigned int expire, enum crypto_algo_hash hash_algo);
|
||||
const unsigned char *rid, unsigned char index,
|
||||
unsigned int expire, enum crypto_algo_hash hash_algo);
|
||||
struct tlvdb *emv_pki_sign_issuer_cert(const struct crypto_pk *cp, struct emv_pk *issuer_pk);
|
||||
struct tlvdb *emv_pki_sign_icc_cert(const struct crypto_pk *cp, struct emv_pk *icc_pk, const struct tlv *sda_tlv);
|
||||
struct tlvdb *emv_pki_sign_icc_pe_cert(const struct crypto_pk *cp, struct emv_pk *icc_pe_pk);
|
||||
|
|
|
@ -29,7 +29,8 @@ static uint8_t g_primes[ROCA_PRINTS_LENGTH] = {
|
|||
|
||||
mbedtls_mpi g_prints[ROCA_PRINTS_LENGTH];
|
||||
|
||||
void rocacheck_init(void) {
|
||||
void rocacheck_init(void)
|
||||
{
|
||||
|
||||
for (int i = 0; i < ROCA_PRINTS_LENGTH; i++)
|
||||
mbedtls_mpi_init(&g_prints[i]);
|
||||
|
@ -53,12 +54,14 @@ void rocacheck_init(void) {
|
|||
mbedtls_mpi_read_string(&g_prints[16], 10, "126304807362733370595828809000324029340048915994");
|
||||
}
|
||||
|
||||
void rocacheck_cleanup(void) {
|
||||
void rocacheck_cleanup(void)
|
||||
{
|
||||
for (int i = 0; i < ROCA_PRINTS_LENGTH; i++)
|
||||
mbedtls_mpi_free(&g_prints[i]);
|
||||
}
|
||||
|
||||
int bitand_is_zero( mbedtls_mpi* a, mbedtls_mpi* b ) {
|
||||
int bitand_is_zero(mbedtls_mpi *a, mbedtls_mpi *b)
|
||||
{
|
||||
|
||||
for (int i = 0; i < mbedtls_mpi_bitlen(a); i++) {
|
||||
|
||||
|
@ -69,7 +72,8 @@ int bitand_is_zero( mbedtls_mpi* a, mbedtls_mpi* b ) {
|
|||
}
|
||||
|
||||
|
||||
mbedtls_mpi_uint mpi_get_uint(const mbedtls_mpi *X) {
|
||||
mbedtls_mpi_uint mpi_get_uint(const mbedtls_mpi *X)
|
||||
{
|
||||
|
||||
if (X->n == 1 && X->s > 0) {
|
||||
return X->p[0];
|
||||
|
@ -78,7 +82,8 @@ mbedtls_mpi_uint mpi_get_uint(const mbedtls_mpi *X) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void print_mpi(const char *msg, int radix, const mbedtls_mpi *X) {
|
||||
void print_mpi(const char *msg, int radix, const mbedtls_mpi *X)
|
||||
{
|
||||
|
||||
char Xchar[400] = {0};
|
||||
size_t len = 0;
|
||||
|
@ -87,7 +92,8 @@ void print_mpi(const char *msg, int radix, const mbedtls_mpi *X) {
|
|||
printf("%s[%d] %s\n", msg, len, Xchar);
|
||||
}
|
||||
|
||||
bool emv_rocacheck(const unsigned char *buf, size_t buflen, bool verbose) {
|
||||
bool emv_rocacheck(const unsigned char *buf, size_t buflen, bool verbose)
|
||||
{
|
||||
|
||||
mbedtls_mpi t_modulus;
|
||||
mbedtls_mpi_init(&t_modulus);
|
||||
|
@ -96,7 +102,7 @@ bool emv_rocacheck(const unsigned char *buf, size_t buflen, bool verbose) {
|
|||
|
||||
rocacheck_init();
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary(&t_modulus, buf, buflen) );
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&t_modulus, buf, buflen));
|
||||
|
||||
for (int i = 0; i < ROCA_PRINTS_LENGTH; i++) {
|
||||
|
||||
|
@ -108,13 +114,13 @@ bool emv_rocacheck(const unsigned char *buf, size_t buflen, bool verbose) {
|
|||
mbedtls_mpi_init(&t_prime);
|
||||
mbedtls_mpi_init(&g_one);
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string(&g_one, 10, "1") );
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&g_one, 10, "1"));
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_add_int(&t_prime, &t_prime, g_primes[i]) );
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&t_prime, &t_prime, g_primes[i]));
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi(&t_temp, &t_modulus, &t_prime) );
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&t_temp, &t_modulus, &t_prime));
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l(&g_one, mpi_get_uint(&t_temp)) );
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&g_one, mpi_get_uint(&t_temp)));
|
||||
|
||||
if (bitand_is_zero(&g_one, &g_prints[i])) {
|
||||
if (verbose)
|
||||
|
@ -138,37 +144,37 @@ cleanup:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int roca_self_test(void) {
|
||||
int roca_self_test(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
PrintAndLogEx(INFO, "ROCA check vulnerability tests" );
|
||||
PrintAndLogEx(INFO, "ROCA check vulnerability tests");
|
||||
|
||||
// positive
|
||||
uint8_t keyp[] = "\x94\x4e\x13\x20\x8a\x28\x0c\x37\xef\xc3\x1c\x31\x14\x48\x5e\x59"\
|
||||
"\x01\x92\xad\xbb\x8e\x11\xc8\x7c\xad\x60\xcd\xef\x00\x37\xce\x99"\
|
||||
"\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\
|
||||
"\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7";
|
||||
"\x01\x92\xad\xbb\x8e\x11\xc8\x7c\xad\x60\xcd\xef\x00\x37\xce\x99"\
|
||||
"\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\
|
||||
"\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7";
|
||||
|
||||
|
||||
if (emv_rocacheck(keyp, 64, false)) {
|
||||
PrintAndLogEx(SUCCESS, "Weak modulus [ %s]", _GREEN_(PASS) );
|
||||
}
|
||||
else {
|
||||
PrintAndLogEx(SUCCESS, "Weak modulus [ %s]", _GREEN_(PASS));
|
||||
} else {
|
||||
ret++;
|
||||
PrintAndLogEx(FAILED, "Weak modulus [ %s]", _RED_(FAIL) );
|
||||
PrintAndLogEx(FAILED, "Weak modulus [ %s]", _RED_(FAIL));
|
||||
}
|
||||
|
||||
// negative
|
||||
uint8_t keyn[] = "\x84\x4e\x13\x20\x8a\x28\x0c\x37\xef\xc3\x1c\x31\x14\x48\x5e\x59"\
|
||||
"\x01\x92\xad\xbb\x8e\x11\xc8\x7c\xad\x60\xcd\xef\x00\x37\xce\x99"\
|
||||
"\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\
|
||||
"\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7";
|
||||
"\x01\x92\xad\xbb\x8e\x11\xc8\x7c\xad\x60\xcd\xef\x00\x37\xce\x99"\
|
||||
"\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\
|
||||
"\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7";
|
||||
|
||||
if (emv_rocacheck(keyn, 64, false)) {
|
||||
ret++;
|
||||
PrintAndLogEx(FAILED, "Strong modulus [ %s]", _RED_(FAIL) );
|
||||
PrintAndLogEx(FAILED, "Strong modulus [ %s]", _RED_(FAIL));
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "Strong modulus [ %s]", _GREEN_(PASS) );
|
||||
PrintAndLogEx(SUCCESS, "Strong modulus [ %s]", _GREEN_(PASS));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -31,8 +31,8 @@
|
|||
|
||||
#define ROCA_PRINTS_LENGTH 17
|
||||
|
||||
extern bool emv_rocacheck( const unsigned char *buf, size_t buflen, bool verbose );
|
||||
extern int roca_self_test( void );
|
||||
extern bool emv_rocacheck(const unsigned char *buf, size_t buflen, bool verbose);
|
||||
extern int roca_self_test(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -173,24 +173,24 @@ static const struct emv_tag_bit EMV_CVR[] = {
|
|||
// http://dexterous-programmer.blogspot.in/2012/05/emv-tags.html
|
||||
static const struct emv_tag emv_tags[] = {
|
||||
// internal
|
||||
{ 0x00 , "Unknown ???" },
|
||||
{ 0x01 , "", EMV_TAG_STRING }, // string for headers
|
||||
{ 0x02 , "Raw data" }, // data
|
||||
{ 0x06 , "Object Identifier (OID)" },
|
||||
{ 0x20 , "Cardholder Verification Results (CVR)", EMV_TAG_CVR }, // not standard!
|
||||
{ 0x21 , "Input list for Offline Data Authentication" }, // not standard! data for "Offline Data Authentication" come from "read records" command. (EMV book3 10.3)
|
||||
{ 0x00, "Unknown ???" },
|
||||
{ 0x01, "", EMV_TAG_STRING }, // string for headers
|
||||
{ 0x02, "Raw data" }, // data
|
||||
{ 0x06, "Object Identifier (OID)" },
|
||||
{ 0x20, "Cardholder Verification Results (CVR)", EMV_TAG_CVR }, // not standard!
|
||||
{ 0x21, "Input list for Offline Data Authentication" }, // not standard! data for "Offline Data Authentication" come from "read records" command. (EMV book3 10.3)
|
||||
|
||||
// EMV
|
||||
{ 0x41 , "Country code and national data" },
|
||||
{ 0x42 , "Issuer Identification Number (IIN)" },
|
||||
{ 0x4f , "Application Dedicated File (ADF) Name" },
|
||||
{ 0x50 , "Application Label", EMV_TAG_STRING },
|
||||
{ 0x51 , "File reference data element" },
|
||||
{ 0x52 , "Command APDU" },
|
||||
{ 0x53 , "Discretionary data (or template)" },
|
||||
{ 0x56 , "Track 1 Data" },
|
||||
{ 0x57 , "Track 2 Equivalent Data" },
|
||||
{ 0x5a , "Application Primary Account Number (PAN)" },
|
||||
{ 0x41, "Country code and national data" },
|
||||
{ 0x42, "Issuer Identification Number (IIN)" },
|
||||
{ 0x4f, "Application Dedicated File (ADF) Name" },
|
||||
{ 0x50, "Application Label", EMV_TAG_STRING },
|
||||
{ 0x51, "File reference data element" },
|
||||
{ 0x52, "Command APDU" },
|
||||
{ 0x53, "Discretionary data (or template)" },
|
||||
{ 0x56, "Track 1 Data" },
|
||||
{ 0x57, "Track 2 Equivalent Data" },
|
||||
{ 0x5a, "Application Primary Account Number (PAN)" },
|
||||
{ 0x5f20, "Cardholder Name", EMV_TAG_STRING },
|
||||
{ 0x5f24, "Application Expiration Date", EMV_TAG_YYMMDD },
|
||||
{ 0x5f25, "Application Effective Date", EMV_TAG_YYMMDD },
|
||||
|
@ -206,40 +206,40 @@ static const struct emv_tag emv_tags[] = {
|
|||
{ 0x5f55, "Issuer Country Code (alpha2 format)", EMV_TAG_STRING },
|
||||
{ 0x5f56, "Issuer Country Code (alpha3 format)", EMV_TAG_STRING },
|
||||
|
||||
{ 0x61 , "Application Template" },
|
||||
{ 0x6f , "File Control Information (FCI) Template" },
|
||||
{ 0x70 , "READ RECORD Response Message Template" },
|
||||
{ 0x71 , "Issues Script Template 1" },
|
||||
{ 0x72 , "Issues Script Template 2" },
|
||||
{ 0x73 , "Directory Discretionary Template" },
|
||||
{ 0x77 , "Response Message Template Format 2" },
|
||||
{ 0x80 , "Response Message Template Format 1" },
|
||||
{ 0x81 , "Amount, Authorised (Binary)" },
|
||||
{ 0x82 , "Application Interchange Profile", EMV_TAG_BITMASK, &EMV_AIP },
|
||||
{ 0x83 , "Command Template" },
|
||||
{ 0x84 , "Dedicated File (DF) Name" },
|
||||
{ 0x86 , "Issuer Script Command" },
|
||||
{ 0x87 , "Application Priority Indicator" },
|
||||
{ 0x88 , "Short File Identifier (SFI)" },
|
||||
{ 0x89 , "Authorisation Code" },
|
||||
{ 0x8a , "Authorisation Response Code" },
|
||||
{ 0x8c , "Card Risk Management Data Object List 1 (CDOL1)", EMV_TAG_DOL },
|
||||
{ 0x8d , "Card Risk Management Data Object List 2 (CDOL2)", EMV_TAG_DOL },
|
||||
{ 0x8e , "Cardholder Verification Method (CVM) List", EMV_TAG_CVM_LIST },
|
||||
{ 0x8f , "Certification Authority Public Key Index" },
|
||||
{ 0x90 , "Issuer Public Key Certificate" },
|
||||
{ 0x91 , "Issuer Authentication Data" },
|
||||
{ 0x92 , "Issuer Public Key Remainder" },
|
||||
{ 0x93 , "Signed Static Application Data" },
|
||||
{ 0x94 , "Application File Locator (AFL)", EMV_TAG_AFL },
|
||||
{ 0x95 , "Terminal Verification Results" },
|
||||
{ 0x97 , "Transaction Certificate Data Object List (TDOL)" },
|
||||
{ 0x98 , "Transaction Certificate (TC) Hash Value" },
|
||||
{ 0x99 , "Transaction Personal Identification Number (PIN) Data" },
|
||||
{ 0x9a , "Transaction Date", EMV_TAG_YYMMDD },
|
||||
{ 0x9b , "Transaction Status Information" },
|
||||
{ 0x9c , "Transaction Type", EMV_TAG_NUMERIC },
|
||||
{ 0x9d , "Directory Definition File (DDF) Name" },
|
||||
{ 0x61, "Application Template" },
|
||||
{ 0x6f, "File Control Information (FCI) Template" },
|
||||
{ 0x70, "READ RECORD Response Message Template" },
|
||||
{ 0x71, "Issues Script Template 1" },
|
||||
{ 0x72, "Issues Script Template 2" },
|
||||
{ 0x73, "Directory Discretionary Template" },
|
||||
{ 0x77, "Response Message Template Format 2" },
|
||||
{ 0x80, "Response Message Template Format 1" },
|
||||
{ 0x81, "Amount, Authorised (Binary)" },
|
||||
{ 0x82, "Application Interchange Profile", EMV_TAG_BITMASK, &EMV_AIP },
|
||||
{ 0x83, "Command Template" },
|
||||
{ 0x84, "Dedicated File (DF) Name" },
|
||||
{ 0x86, "Issuer Script Command" },
|
||||
{ 0x87, "Application Priority Indicator" },
|
||||
{ 0x88, "Short File Identifier (SFI)" },
|
||||
{ 0x89, "Authorisation Code" },
|
||||
{ 0x8a, "Authorisation Response Code" },
|
||||
{ 0x8c, "Card Risk Management Data Object List 1 (CDOL1)", EMV_TAG_DOL },
|
||||
{ 0x8d, "Card Risk Management Data Object List 2 (CDOL2)", EMV_TAG_DOL },
|
||||
{ 0x8e, "Cardholder Verification Method (CVM) List", EMV_TAG_CVM_LIST },
|
||||
{ 0x8f, "Certification Authority Public Key Index" },
|
||||
{ 0x90, "Issuer Public Key Certificate" },
|
||||
{ 0x91, "Issuer Authentication Data" },
|
||||
{ 0x92, "Issuer Public Key Remainder" },
|
||||
{ 0x93, "Signed Static Application Data" },
|
||||
{ 0x94, "Application File Locator (AFL)", EMV_TAG_AFL },
|
||||
{ 0x95, "Terminal Verification Results" },
|
||||
{ 0x97, "Transaction Certificate Data Object List (TDOL)" },
|
||||
{ 0x98, "Transaction Certificate (TC) Hash Value" },
|
||||
{ 0x99, "Transaction Personal Identification Number (PIN) Data" },
|
||||
{ 0x9a, "Transaction Date", EMV_TAG_YYMMDD },
|
||||
{ 0x9b, "Transaction Status Information" },
|
||||
{ 0x9c, "Transaction Type", EMV_TAG_NUMERIC },
|
||||
{ 0x9d, "Directory Definition File (DDF) Name" },
|
||||
|
||||
{ 0x9f01, "Acquirer Identifier", EMV_TAG_NUMERIC },
|
||||
{ 0x9f02, "Amount, Authorised (Numeric)", EMV_TAG_NUMERIC },
|
||||
|
@ -364,7 +364,7 @@ static const struct emv_tag emv_tags[] = {
|
|||
{ 0x9f7d, "DS Summary 1" },
|
||||
{ 0x9f7f, "DS Unpredictable Number" },
|
||||
|
||||
{ 0xa5 , "File Control Information (FCI) Proprietary Template" },
|
||||
{ 0xa5, "File Control Information (FCI) Proprietary Template" },
|
||||
{ 0xbf0c, "File Control Information (FCI) Issuer Discretionary Data" },
|
||||
{ 0xdf20, "Issuer Proprietary Bitmap (IPB)" },
|
||||
{ 0xdf4b, "POS Cardholder Interaction Information" },
|
||||
|
@ -424,20 +424,23 @@ static const struct emv_tag emv_tags[] = {
|
|||
{ 0xff8106, "Discretionary Data" },
|
||||
};
|
||||
|
||||
static int emv_sort_tag(tlv_tag_t tag) {
|
||||
static int emv_sort_tag(tlv_tag_t tag)
|
||||
{
|
||||
return (int)(tag >= 0x100 ? tag : tag << 8);
|
||||
}
|
||||
|
||||
static int emv_tlv_compare(const void *a, const void *b) {
|
||||
static int emv_tlv_compare(const void *a, const void *b)
|
||||
{
|
||||
const struct tlv *tlv = a;
|
||||
const struct emv_tag *tag = b;
|
||||
|
||||
return emv_sort_tag(tlv->tag) - (emv_sort_tag(tag->tag));
|
||||
}
|
||||
|
||||
static const struct emv_tag *emv_get_tag(const struct tlv *tlv) {
|
||||
struct emv_tag *tag = bsearch(tlv, emv_tags, sizeof(emv_tags)/sizeof(emv_tags[0]),
|
||||
sizeof(emv_tags[0]), emv_tlv_compare);
|
||||
static const struct emv_tag *emv_get_tag(const struct tlv *tlv)
|
||||
{
|
||||
struct emv_tag *tag = bsearch(tlv, emv_tags, sizeof(emv_tags) / sizeof(emv_tags[0]),
|
||||
sizeof(emv_tags[0]), emv_tlv_compare);
|
||||
|
||||
return tag ? tag : &emv_tags[0];
|
||||
}
|
||||
|
@ -453,7 +456,8 @@ static const char *bitstrings[] = {
|
|||
"1.......",
|
||||
};
|
||||
|
||||
static void emv_tag_dump_bitmask(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
|
||||
static void emv_tag_dump_bitmask(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level)
|
||||
{
|
||||
const struct emv_tag_bit *bits = tag->data;
|
||||
unsigned bit, byte;
|
||||
|
||||
|
@ -462,7 +466,7 @@ static void emv_tag_dump_bitmask(const struct tlv *tlv, const struct emv_tag *ta
|
|||
PRINT_INDENT(level);
|
||||
fprintf(f, "\tByte %u (%02x)\n", byte, val);
|
||||
for (bit = 8; bit > 0; bit--, val <<= 1) {
|
||||
if (val & 0x80){
|
||||
if (val & 0x80) {
|
||||
PRINT_INDENT(level);
|
||||
fprintf(f, "\t\t%s - '%s'\n", bitstrings[bit - 1],
|
||||
bits->bit == EMV_BIT(byte, bit) ? bits->name : "Unknown");
|
||||
|
@ -473,7 +477,8 @@ static void emv_tag_dump_bitmask(const struct tlv *tlv, const struct emv_tag *ta
|
|||
}
|
||||
}
|
||||
|
||||
static void emv_tag_dump_dol(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
|
||||
static void emv_tag_dump_dol(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level)
|
||||
{
|
||||
const unsigned char *buf = tlv->value;
|
||||
size_t left = tlv->len;
|
||||
|
||||
|
@ -494,13 +499,15 @@ static void emv_tag_dump_dol(const struct tlv *tlv, const struct emv_tag *tag, F
|
|||
}
|
||||
}
|
||||
|
||||
static void emv_tag_dump_string(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
|
||||
static void emv_tag_dump_string(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level)
|
||||
{
|
||||
fprintf(f, "\tString value '");
|
||||
fwrite(tlv->value, 1, tlv->len, f);
|
||||
fprintf(f, "'\n");
|
||||
}
|
||||
|
||||
static unsigned long emv_value_numeric(const struct tlv *tlv, unsigned start, unsigned end) {
|
||||
static unsigned long emv_value_numeric(const struct tlv *tlv, unsigned start, unsigned end)
|
||||
{
|
||||
unsigned long ret = 0;
|
||||
int i;
|
||||
|
||||
|
@ -510,32 +517,34 @@ static unsigned long emv_value_numeric(const struct tlv *tlv, unsigned start, un
|
|||
return ret;
|
||||
|
||||
if (start & 1) {
|
||||
ret += tlv->value[start/2] & 0xf;
|
||||
ret += tlv->value[start / 2] & 0xf;
|
||||
i = start + 1;
|
||||
} else
|
||||
i = start;
|
||||
|
||||
for (; i < end - 1; i += 2) {
|
||||
ret *= 10;
|
||||
ret += tlv->value[i/2] >> 4;
|
||||
ret += tlv->value[i / 2] >> 4;
|
||||
ret *= 10;
|
||||
ret += tlv->value[i/2] & 0xf;
|
||||
ret += tlv->value[i / 2] & 0xf;
|
||||
}
|
||||
|
||||
if (end & 1) {
|
||||
ret *= 10;
|
||||
ret += tlv->value[end/2] >> 4;
|
||||
ret += tlv->value[end / 2] >> 4;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void emv_tag_dump_numeric(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
|
||||
static void emv_tag_dump_numeric(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level)
|
||||
{
|
||||
PRINT_INDENT(level);
|
||||
fprintf(f, "\tNumeric value %lu\n", emv_value_numeric(tlv, 0, tlv->len * 2));
|
||||
}
|
||||
|
||||
static void emv_tag_dump_yymmdd(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
|
||||
static void emv_tag_dump_yymmdd(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level)
|
||||
{
|
||||
PRINT_INDENT(level);
|
||||
fprintf(f, "\tDate: 20%02ld.%ld.%ld\n",
|
||||
emv_value_numeric(tlv, 0, 2),
|
||||
|
@ -543,12 +552,14 @@ static void emv_tag_dump_yymmdd(const struct tlv *tlv, const struct emv_tag *tag
|
|||
emv_value_numeric(tlv, 4, 6));
|
||||
}
|
||||
|
||||
static uint32_t emv_get_binary(const unsigned char *S) {
|
||||
static uint32_t emv_get_binary(const unsigned char *S)
|
||||
{
|
||||
return (S[0] << 24) | (S[1] << 16) | (S[2] << 8) | (S[3] << 0);
|
||||
}
|
||||
|
||||
// https://github.com/binaryfoo/emv-bertlv/blob/master/src/main/resources/fields/visa-cvr.txt
|
||||
static void emv_tag_dump_cvr(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
|
||||
static void emv_tag_dump_cvr(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level)
|
||||
{
|
||||
if (!tlv || tlv->len < 1) {
|
||||
PRINT_INDENT(level);
|
||||
fprintf(f, "\tINVALID!\n");
|
||||
|
@ -612,7 +623,8 @@ static void emv_tag_dump_cvr(const struct tlv *tlv, const struct emv_tag *tag, F
|
|||
}
|
||||
|
||||
// EMV Book 3
|
||||
static void emv_tag_dump_cid(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
|
||||
static void emv_tag_dump_cid(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level)
|
||||
{
|
||||
if (!tlv || tlv->len < 1) {
|
||||
PRINT_INDENT(level);
|
||||
fprintf(f, "\tINVALID!\n");
|
||||
|
@ -633,7 +645,7 @@ static void emv_tag_dump_cid(const struct tlv *tlv, const struct emv_tag *tag, F
|
|||
if (tlv->value[0] & EMVCID_REASON_MASK) {
|
||||
PRINT_INDENT(level);
|
||||
fprintf(f, "\tReason/advice/referral code: ");
|
||||
switch((tlv->value[0] & EMVCID_REASON_MASK)) {
|
||||
switch ((tlv->value[0] & EMVCID_REASON_MASK)) {
|
||||
case 0:
|
||||
fprintf(f, "No information given\n");
|
||||
break;
|
||||
|
@ -653,7 +665,8 @@ static void emv_tag_dump_cid(const struct tlv *tlv, const struct emv_tag *tag, F
|
|||
}
|
||||
}
|
||||
|
||||
static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
|
||||
static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level)
|
||||
{
|
||||
uint32_t X, Y;
|
||||
int i;
|
||||
|
||||
|
@ -671,87 +684,88 @@ static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *t
|
|||
PRINT_INDENT(level);
|
||||
fprintf(f, "\tY: %d\n", Y);
|
||||
|
||||
for (i = 8; i < tlv->len; i+= 2) {
|
||||
for (i = 8; i < tlv->len; i += 2) {
|
||||
const char *method;
|
||||
const char *condition;
|
||||
|
||||
switch (tlv->value[i] & 0x3f) {
|
||||
case 0x0:
|
||||
method = "Fail CVM processing";
|
||||
break;
|
||||
case 0x1:
|
||||
method = "Plaintext PIN verification performed by ICC";
|
||||
break;
|
||||
case 0x2:
|
||||
method = "Enciphered PIN verified online";
|
||||
break;
|
||||
case 0x3:
|
||||
method = "Plaintext PIN verification performed by ICC and signature (paper)";
|
||||
break;
|
||||
case 0x4:
|
||||
method = "Enciphered PIN verification performed by ICC";
|
||||
break;
|
||||
case 0x5:
|
||||
method = "Enciphered PIN verification performed by ICC and signature (paper)";
|
||||
break;
|
||||
case 0x1e:
|
||||
method = "Signature (paper)";
|
||||
break;
|
||||
case 0x1f:
|
||||
method = "No CVM required";
|
||||
break;
|
||||
case 0x3f:
|
||||
method = "NOT AVAILABLE!";
|
||||
break;
|
||||
default:
|
||||
method = "Unknown";
|
||||
break;
|
||||
case 0x0:
|
||||
method = "Fail CVM processing";
|
||||
break;
|
||||
case 0x1:
|
||||
method = "Plaintext PIN verification performed by ICC";
|
||||
break;
|
||||
case 0x2:
|
||||
method = "Enciphered PIN verified online";
|
||||
break;
|
||||
case 0x3:
|
||||
method = "Plaintext PIN verification performed by ICC and signature (paper)";
|
||||
break;
|
||||
case 0x4:
|
||||
method = "Enciphered PIN verification performed by ICC";
|
||||
break;
|
||||
case 0x5:
|
||||
method = "Enciphered PIN verification performed by ICC and signature (paper)";
|
||||
break;
|
||||
case 0x1e:
|
||||
method = "Signature (paper)";
|
||||
break;
|
||||
case 0x1f:
|
||||
method = "No CVM required";
|
||||
break;
|
||||
case 0x3f:
|
||||
method = "NOT AVAILABLE!";
|
||||
break;
|
||||
default:
|
||||
method = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (tlv->value[i+1]) {
|
||||
case 0x00:
|
||||
condition = "Always";
|
||||
break;
|
||||
case 0x01:
|
||||
condition = "If unattended cash";
|
||||
break;
|
||||
case 0x02:
|
||||
condition = "If not unattended cash and not manual cash and not purchase with cashback";
|
||||
break;
|
||||
case 0x03:
|
||||
condition = "If terminal supports the CVM";
|
||||
break;
|
||||
case 0x04:
|
||||
condition = "If manual cash";
|
||||
break;
|
||||
case 0x05:
|
||||
condition = "If purchase with cashback";
|
||||
break;
|
||||
case 0x06:
|
||||
condition = "If transaction is in the application currency and is under X value";
|
||||
break;
|
||||
case 0x07:
|
||||
condition = "If transaction is in the application currency and is over X value";
|
||||
break;
|
||||
case 0x08:
|
||||
condition = "If transaction is in the application currency and is under Y value";
|
||||
break;
|
||||
case 0x09:
|
||||
condition = "If transaction is in the application currency and is over Y value";
|
||||
break;
|
||||
default:
|
||||
condition = "Unknown";
|
||||
break;
|
||||
switch (tlv->value[i + 1]) {
|
||||
case 0x00:
|
||||
condition = "Always";
|
||||
break;
|
||||
case 0x01:
|
||||
condition = "If unattended cash";
|
||||
break;
|
||||
case 0x02:
|
||||
condition = "If not unattended cash and not manual cash and not purchase with cashback";
|
||||
break;
|
||||
case 0x03:
|
||||
condition = "If terminal supports the CVM";
|
||||
break;
|
||||
case 0x04:
|
||||
condition = "If manual cash";
|
||||
break;
|
||||
case 0x05:
|
||||
condition = "If purchase with cashback";
|
||||
break;
|
||||
case 0x06:
|
||||
condition = "If transaction is in the application currency and is under X value";
|
||||
break;
|
||||
case 0x07:
|
||||
condition = "If transaction is in the application currency and is over X value";
|
||||
break;
|
||||
case 0x08:
|
||||
condition = "If transaction is in the application currency and is under Y value";
|
||||
break;
|
||||
case 0x09:
|
||||
condition = "If transaction is in the application currency and is over Y value";
|
||||
break;
|
||||
default:
|
||||
condition = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
PRINT_INDENT(level);
|
||||
fprintf(f, "\t%02x %02x: '%s' '%s' and '%s' if this CVM is unsuccessful\n",
|
||||
tlv->value[i], tlv->value[i+1],
|
||||
tlv->value[i], tlv->value[i + 1],
|
||||
method, condition, (tlv->value[i] & 0x40) ? "continue" : "fail");
|
||||
}
|
||||
}
|
||||
|
||||
static void emv_tag_dump_afl(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) {
|
||||
static void emv_tag_dump_afl(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level)
|
||||
{
|
||||
if (tlv->len < 4 || tlv->len % 4) {
|
||||
PRINT_INDENT(level);
|
||||
fprintf(f, "\tINVALID!\n");
|
||||
|
@ -764,7 +778,8 @@ static void emv_tag_dump_afl(const struct tlv *tlv, const struct emv_tag *tag, F
|
|||
}
|
||||
}
|
||||
|
||||
bool emv_tag_dump(const struct tlv *tlv, FILE *f, int level) {
|
||||
bool emv_tag_dump(const struct tlv *tlv, FILE *f, int level)
|
||||
{
|
||||
if (!tlv) {
|
||||
fprintf(f, "NULL\n");
|
||||
return false;
|
||||
|
@ -776,48 +791,49 @@ bool emv_tag_dump(const struct tlv *tlv, FILE *f, int level) {
|
|||
fprintf(f, "--%2hx[%02zx] '%s':", tlv->tag, tlv->len, tag->name);
|
||||
|
||||
switch (tag->type) {
|
||||
case EMV_TAG_GENERIC:
|
||||
fprintf(f, "\n");
|
||||
break;
|
||||
case EMV_TAG_BITMASK:
|
||||
fprintf(f, "\n");
|
||||
emv_tag_dump_bitmask(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_DOL:
|
||||
fprintf(f, "\n");
|
||||
emv_tag_dump_dol(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_CVM_LIST:
|
||||
fprintf(f, "\n");
|
||||
emv_tag_dump_cvm_list(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_AFL:
|
||||
fprintf(f, "\n");
|
||||
emv_tag_dump_afl(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_STRING:
|
||||
emv_tag_dump_string(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_NUMERIC:
|
||||
emv_tag_dump_numeric(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_YYMMDD:
|
||||
emv_tag_dump_yymmdd(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_CVR:
|
||||
fprintf(f, "\n");
|
||||
emv_tag_dump_cvr(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_CID:
|
||||
fprintf(f, "\n");
|
||||
emv_tag_dump_cid(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_GENERIC:
|
||||
fprintf(f, "\n");
|
||||
break;
|
||||
case EMV_TAG_BITMASK:
|
||||
fprintf(f, "\n");
|
||||
emv_tag_dump_bitmask(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_DOL:
|
||||
fprintf(f, "\n");
|
||||
emv_tag_dump_dol(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_CVM_LIST:
|
||||
fprintf(f, "\n");
|
||||
emv_tag_dump_cvm_list(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_AFL:
|
||||
fprintf(f, "\n");
|
||||
emv_tag_dump_afl(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_STRING:
|
||||
emv_tag_dump_string(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_NUMERIC:
|
||||
emv_tag_dump_numeric(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_YYMMDD:
|
||||
emv_tag_dump_yymmdd(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_CVR:
|
||||
fprintf(f, "\n");
|
||||
emv_tag_dump_cvr(tlv, tag, f, level);
|
||||
break;
|
||||
case EMV_TAG_CID:
|
||||
fprintf(f, "\n");
|
||||
emv_tag_dump_cid(tlv, tag, f, level);
|
||||
break;
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char *emv_get_tag_name(const struct tlv *tlv) {
|
||||
char *emv_get_tag_name(const struct tlv *tlv)
|
||||
{
|
||||
static char *defstr = "";
|
||||
|
||||
if (!tlv)
|
||||
|
|
|
@ -29,7 +29,7 @@ char *TransactionTypeStr[] = {
|
|||
|
||||
typedef struct {
|
||||
enum CardPSVendor vendor;
|
||||
const char* aid;
|
||||
const char *aid;
|
||||
} TAIDList;
|
||||
|
||||
static const TAIDList AIDlist [] = {
|
||||
|
@ -88,22 +88,24 @@ static const TAIDList AIDlist [] = {
|
|||
{ CV_OTHER, "A0000005241010" }, // RuPay - RuPay
|
||||
{ CV_OTHER, "D5780000021010" } // Bankaxept - Bankaxept
|
||||
};
|
||||
static const size_t AIDlistLen = sizeof(AIDlist)/sizeof(TAIDList);
|
||||
static const size_t AIDlistLen = sizeof(AIDlist) / sizeof(TAIDList);
|
||||
|
||||
static bool APDULogging = false;
|
||||
void SetAPDULogging(bool logging) {
|
||||
void SetAPDULogging(bool logging)
|
||||
{
|
||||
APDULogging = logging;
|
||||
}
|
||||
|
||||
enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen) {
|
||||
enum CardPSVendor GetCardPSVendor(uint8_t *AID, size_t AIDlen)
|
||||
{
|
||||
char buf[100] = {0};
|
||||
if (AIDlen < 1)
|
||||
return CV_NA;
|
||||
|
||||
hex_to_buffer((uint8_t *)buf, AID, AIDlen, sizeof(buf) - 1, 0, 0, true);
|
||||
|
||||
for(int i = 0; i < AIDlistLen; i ++) {
|
||||
if (strncmp(AIDlist[i].aid, buf, strlen(AIDlist[i].aid)) == 0){
|
||||
for (int i = 0; i < AIDlistLen; i ++) {
|
||||
if (strncmp(AIDlist[i].aid, buf, strlen(AIDlist[i].aid)) == 0) {
|
||||
return AIDlist[i].vendor;
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +113,8 @@ enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen) {
|
|||
return CV_NA;
|
||||
}
|
||||
|
||||
static bool print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf) {
|
||||
static bool print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf)
|
||||
{
|
||||
emv_tag_dump(tlv, stdout, level);
|
||||
if (is_leaf) {
|
||||
dump_buffer(tlv->value, tlv->len, stdout, level);
|
||||
|
@ -120,7 +123,8 @@ static bool print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool TLVPrintFromBuffer(uint8_t *data, int datalen) {
|
||||
bool TLVPrintFromBuffer(uint8_t *data, int datalen)
|
||||
{
|
||||
struct tlvdb *t = NULL;
|
||||
t = tlvdb_parse_multi(data, datalen);
|
||||
if (t) {
|
||||
|
@ -135,18 +139,21 @@ bool TLVPrintFromBuffer(uint8_t *data, int datalen) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void TLVPrintFromTLVLev(struct tlvdb *tlv, int level) {
|
||||
void TLVPrintFromTLVLev(struct tlvdb *tlv, int level)
|
||||
{
|
||||
if (!tlv)
|
||||
return;
|
||||
|
||||
tlvdb_visit(tlv, print_cb, NULL, level);
|
||||
}
|
||||
|
||||
void TLVPrintFromTLV(struct tlvdb *tlv) {
|
||||
void TLVPrintFromTLV(struct tlvdb *tlv)
|
||||
{
|
||||
TLVPrintFromTLVLev(tlv, 0);
|
||||
}
|
||||
|
||||
void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv) {
|
||||
void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv)
|
||||
{
|
||||
PrintAndLogEx(NORMAL, "|------------------|--------|-------------------------|");
|
||||
PrintAndLogEx(NORMAL, "| AID |Priority| Name |");
|
||||
PrintAndLogEx(NORMAL, "|------------------|--------|-------------------------|");
|
||||
|
@ -162,9 +169,9 @@ void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv) {
|
|||
if (!tgAID)
|
||||
break;
|
||||
PrintAndLogEx(NORMAL, "|%s| %s |%s|",
|
||||
sprint_hex_inrow_ex(tgAID->value, tgAID->len, 18),
|
||||
(tgPrio) ? sprint_hex(tgPrio->value, 1) : " ",
|
||||
(tgName) ? sprint_ascii_ex(tgName->value, tgName->len, 25) : " ");
|
||||
sprint_hex_inrow_ex(tgAID->value, tgAID->len, 18),
|
||||
(tgPrio) ? sprint_hex(tgPrio->value, 1) : " ",
|
||||
(tgName) ? sprint_ascii_ex(tgName->value, tgName->len, 25) : " ");
|
||||
|
||||
ttmp = tlvdb_find_next(ttmp, 0x6f);
|
||||
}
|
||||
|
@ -172,7 +179,8 @@ void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv) {
|
|||
PrintAndLogEx(NORMAL, "|------------------|--------|-------------------------|");
|
||||
}
|
||||
|
||||
struct tlvdb *GetPANFromTrack2(const struct tlv *track2) {
|
||||
struct tlvdb *GetPANFromTrack2(const struct tlv *track2)
|
||||
{
|
||||
char track2Hex[200] = {0};
|
||||
uint8_t PAN[100] = {0};
|
||||
int PANlen = 0;
|
||||
|
@ -196,10 +204,11 @@ struct tlvdb *GetPANFromTrack2(const struct tlv *track2) {
|
|||
|
||||
param_gethex_to_eol(track2Hex, 0, PAN, sizeof(PAN), &PANlen);
|
||||
|
||||
return tlvdb_fixed(0x5a, PANlen, PAN);
|
||||
return tlvdb_fixed(0x5a, PANlen, PAN);
|
||||
}
|
||||
|
||||
struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) {
|
||||
struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2)
|
||||
{
|
||||
char track2Hex[200] = {0};
|
||||
char dCVVHex[100] = {0};
|
||||
uint8_t dCVV[100] = {0};
|
||||
|
@ -229,10 +238,11 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) {
|
|||
|
||||
param_gethex_to_eol(dCVVHex, 0, dCVV, sizeof(dCVV), &dCVVlen);
|
||||
|
||||
return tlvdb_fixed(0x02, dCVVlen, dCVV);
|
||||
return tlvdb_fixed(0x02, dCVVlen, dCVV);
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
|
@ -241,7 +251,7 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField
|
|||
int res = 0;
|
||||
|
||||
if (ActivateField) {
|
||||
DropFieldEx( channel );
|
||||
DropFieldEx(channel);
|
||||
msleep(50);
|
||||
}
|
||||
|
||||
|
@ -251,26 +261,26 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField
|
|||
memcpy(&data[5], apdu.data, apdu.Lc);
|
||||
|
||||
if (APDULogging)
|
||||
PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, (IncludeLe?6:5) + apdu.Lc));
|
||||
PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, (IncludeLe ? 6 : 5) + apdu.Lc));
|
||||
|
||||
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);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
case ECC_CONTACT:
|
||||
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);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
case ECC_CONTACT:
|
||||
#ifdef WITH_SMARTCARD
|
||||
res = ExchangeAPDUSC(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
|
||||
res = ExchangeAPDUSC(data, (IncludeLe ? 6 : 5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
|
||||
#else
|
||||
res = 1;
|
||||
res = 1;
|
||||
#endif
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (APDULogging)
|
||||
|
@ -305,15 +315,18 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField
|
|||
return 0;
|
||||
}
|
||||
|
||||
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(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);
|
||||
}
|
||||
|
||||
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(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 EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
|
||||
int EMVSelectPSE(EMVCommandChannel 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;
|
||||
|
@ -335,7 +348,8 @@ int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO
|
|||
return res;
|
||||
}
|
||||
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
int retrycnt = 0;
|
||||
int res = 0;
|
||||
do {
|
||||
|
@ -343,7 +357,7 @@ int EMVSelectWithRetry(EMVCommandChannel channel, bool ActivateField, bool Leave
|
|||
|
||||
// retry if error and not returned sw error
|
||||
if (res && res != 5) {
|
||||
if (++retrycnt < 3){
|
||||
if (++retrycnt < 3) {
|
||||
continue;
|
||||
} else {
|
||||
// card select error, proxmark error
|
||||
|
@ -362,7 +376,8 @@ int EMVSelectWithRetry(EMVCommandChannel channel, bool ActivateField, bool Leave
|
|||
return res;
|
||||
}
|
||||
|
||||
int EMVCheckAID(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlvdbelm, struct tlvdb *tlv){
|
||||
int EMVCheckAID(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlvdbelm, struct tlvdb *tlv)
|
||||
{
|
||||
uint8_t data[APDU_RES_LEN] = {0};
|
||||
size_t datalen = 0;
|
||||
int res = 0;
|
||||
|
@ -384,7 +399,7 @@ int EMVCheckAID(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlvdbel
|
|||
break;
|
||||
|
||||
// all is ok
|
||||
if (decodeTLV){
|
||||
if (decodeTLV) {
|
||||
PrintAndLogEx(NORMAL, "%s:", sprint_hex_inrow(tgAID->value, tgAID->len));
|
||||
TLVPrintFromBuffer(data, datalen);
|
||||
}
|
||||
|
@ -394,7 +409,8 @@ int EMVCheckAID(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlvdbel
|
|||
return res;
|
||||
}
|
||||
|
||||
int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) {
|
||||
int EMVSearchPSE(EMVCommandChannel 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];
|
||||
|
@ -406,7 +422,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO
|
|||
// select PPSE
|
||||
res = EMVSelectPSE(channel, ActivateField, true, PSENum, data, sizeof(data), &datalen, &sw);
|
||||
|
||||
if (!res){
|
||||
if (!res) {
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(FAILED, "Select PSE error. APDU error: %04x.", sw);
|
||||
return 1;
|
||||
|
@ -416,7 +432,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO
|
|||
t = tlvdb_parse_multi(data, datalen);
|
||||
if (t) {
|
||||
// PSE/PPSE with SFI
|
||||
struct tlvdb *tsfi = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0x88, 0x00});
|
||||
struct tlvdb *tsfi = tlvdb_find_path(t, (tlv_tag_t[]) {0x6f, 0xa5, 0x88, 0x00});
|
||||
if (tsfi) {
|
||||
uint8_t sfin = 0;
|
||||
tlv_get_uint8(tlvdb_get_tlv(tsfi), &sfin);
|
||||
|
@ -440,7 +456,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO
|
|||
break;
|
||||
}
|
||||
|
||||
if (decodeTLV){
|
||||
if (decodeTLV) {
|
||||
TLVPrintFromBuffer(sfidata[ui], sfidatalen[ui]);
|
||||
}
|
||||
}
|
||||
|
@ -450,7 +466,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO
|
|||
struct tlvdb *tsfi = NULL;
|
||||
tsfi = tlvdb_parse_multi(sfidata[ui], sfidatalen[ui]);
|
||||
if (tsfi) {
|
||||
struct tlvdb *tsfitmp = tlvdb_find_path(tsfi, (tlv_tag_t[]){0x70, 0x61, 0x00});
|
||||
struct tlvdb *tsfitmp = tlvdb_find_path(tsfi, (tlv_tag_t[]) {0x70, 0x61, 0x00});
|
||||
if (!tsfitmp) {
|
||||
PrintAndLogEx(FAILED, "SFI 0x%02d don't have records.", sfidatalen[ui]);
|
||||
continue;
|
||||
|
@ -465,7 +481,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO
|
|||
|
||||
|
||||
// PSE/PPSE plain (wo SFI)
|
||||
struct tlvdb *ttmp = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0xbf0c, 0x61, 0x00});
|
||||
struct tlvdb *ttmp = tlvdb_find_path(t, (tlv_tag_t[]) {0x6f, 0xa5, 0xbf0c, 0x61, 0x00});
|
||||
if (ttmp) {
|
||||
res = EMVCheckAID(channel, decodeTLV, ttmp, tlv);
|
||||
fileFound = true;
|
||||
|
@ -482,13 +498,14 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO
|
|||
PrintAndLogEx(WARNING, "PPSE ERROR: Can't select PPSE AID. Error: %d", res);
|
||||
}
|
||||
|
||||
if(!LeaveFieldON)
|
||||
DropFieldEx( channel );
|
||||
if (!LeaveFieldON)
|
||||
DropFieldEx(channel);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) {
|
||||
int EMVSearch(EMVCommandChannel 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};
|
||||
|
@ -497,12 +514,12 @@ int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON,
|
|||
|
||||
int res = 0;
|
||||
int retrycnt = 0;
|
||||
for(int i = 0; i < AIDlistLen; i ++) {
|
||||
for (int i = 0; i < AIDlistLen; i ++) {
|
||||
param_gethex_to_eol(AIDlist[i].aid, 0, aidbuf, sizeof(aidbuf), &aidlen);
|
||||
res = EMVSelect(channel, (i == 0) ? ActivateField : false, (i == AIDlistLen - 1) ? LeaveFieldON : true, aidbuf, aidlen, data, sizeof(data), &datalen, &sw, tlv);
|
||||
// retry if error and not returned sw error
|
||||
if (res && res != 5) {
|
||||
if (++retrycnt < 3){
|
||||
if (++retrycnt < 3) {
|
||||
i--;
|
||||
} else {
|
||||
// (1) - card select error, proxmark error OR (200) - result length = 0
|
||||
|
@ -533,7 +550,8 @@ int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) {
|
||||
int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen)
|
||||
{
|
||||
// check priority. 0x00 - highest
|
||||
int prio = 0xffff;
|
||||
|
||||
|
@ -551,7 +569,7 @@ int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) {
|
|||
break;
|
||||
|
||||
if (tgPrio) {
|
||||
int pt = bytes_to_num((uint8_t*)tgPrio->value, (tgPrio->len < 2) ? tgPrio->len : 2);
|
||||
int pt = bytes_to_num((uint8_t *)tgPrio->value, (tgPrio->len < 2) ? tgPrio->len : 2);
|
||||
if (pt < prio) {
|
||||
prio = pt;
|
||||
|
||||
|
@ -561,8 +579,8 @@ int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) {
|
|||
} else {
|
||||
// takes the first application from list wo priority
|
||||
if (!*AIDlen) {
|
||||
memcpy(AID, tgAID->value, tgAID->len);
|
||||
*AIDlen = tgAID->len;
|
||||
memcpy(AID, tgAID->value, tgAID->len);
|
||||
*AIDlen = tgAID->len;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -572,42 +590,49 @@ 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) {
|
||||
return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||
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)
|
||||
{
|
||||
return EMVExchange(channel, LeaveFieldON, (sAPDU) {0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, 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 res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, 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 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...");
|
||||
res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||
res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||
}
|
||||
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) {
|
||||
return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0xae, RefControl, 0x00, CDOLLen, CDOL}, Result, MaxResultLen, ResultLen, sw, 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)
|
||||
{
|
||||
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 res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, 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 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...");
|
||||
res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||
res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU) {0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||
}
|
||||
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) {
|
||||
return EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, true, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, 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)
|
||||
{
|
||||
return EMVExchange(channel, LeaveFieldON, (sAPDU) {0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||
}
|
||||
|
||||
// Authentication
|
||||
struct emv_pk *get_ca_pk(struct tlvdb *db) {
|
||||
struct emv_pk *get_ca_pk(struct tlvdb *db)
|
||||
{
|
||||
const struct tlv *df_tlv = tlvdb_get(db, 0x84, NULL);
|
||||
const struct tlv *caidx_tlv = tlvdb_get(db, 0x8f, NULL);
|
||||
|
||||
|
@ -618,7 +643,8 @@ struct emv_pk *get_ca_pk(struct tlvdb *db) {
|
|||
return emv_pk_get_ca_pk(df_tlv->value, caidx_tlv->value[0]);
|
||||
}
|
||||
|
||||
int trSDA(struct tlvdb *tlv) {
|
||||
int trSDA(struct tlvdb *tlv)
|
||||
{
|
||||
|
||||
struct emv_pk *pk = get_ca_pk(tlv);
|
||||
if (!pk) {
|
||||
|
@ -634,16 +660,16 @@ int trSDA(struct tlvdb *tlv) {
|
|||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "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]
|
||||
);
|
||||
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]
|
||||
);
|
||||
|
||||
const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
|
||||
if (!sda_tlv || sda_tlv->len < 1) {
|
||||
|
@ -673,7 +699,8 @@ 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(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv)
|
||||
{
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
size_t len = 0;
|
||||
uint16_t sw = 0;
|
||||
|
@ -685,12 +712,12 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
|||
}
|
||||
|
||||
const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
|
||||
/* if (!sda_tlv || sda_tlv->len < 1) { it may be 0!!!!
|
||||
emv_pk_free(pk);
|
||||
PrintAndLogEx(WARNING, "Error: Can't find input list for Offline Data Authentication. Exit.");
|
||||
return 3;
|
||||
}
|
||||
*/
|
||||
/* if (!sda_tlv || sda_tlv->len < 1) { it may be 0!!!!
|
||||
emv_pk_free(pk);
|
||||
PrintAndLogEx(WARNING, "Error: Can't find input list for Offline Data Authentication. Exit.");
|
||||
return 3;
|
||||
}
|
||||
*/
|
||||
struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
|
||||
if (!issuer_pk) {
|
||||
emv_pk_free(pk);
|
||||
|
@ -698,16 +725,16 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
|||
return 2;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
|
||||
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]
|
||||
);
|
||||
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]
|
||||
);
|
||||
|
||||
struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv);
|
||||
if (!icc_pk) {
|
||||
|
@ -717,16 +744,16 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
|||
return 2;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "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]
|
||||
);
|
||||
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]
|
||||
);
|
||||
|
||||
if (tlvdb_get(tlv, 0x9f2d, NULL)) {
|
||||
struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv);
|
||||
|
@ -734,16 +761,16 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
|||
PrintAndLogEx(WARNING, "WARNING: ICC PE PK recover error. ");
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
|
||||
icc_pe_pk->rid[0],
|
||||
icc_pe_pk->rid[1],
|
||||
icc_pe_pk->rid[2],
|
||||
icc_pe_pk->rid[3],
|
||||
icc_pe_pk->rid[4],
|
||||
icc_pe_pk->index,
|
||||
icc_pe_pk->serial[0],
|
||||
icc_pe_pk->serial[1],
|
||||
icc_pe_pk->serial[2]
|
||||
);
|
||||
icc_pe_pk->rid[0],
|
||||
icc_pe_pk->rid[1],
|
||||
icc_pe_pk->rid[2],
|
||||
icc_pe_pk->rid[3],
|
||||
icc_pe_pk->rid[4],
|
||||
icc_pe_pk->index,
|
||||
icc_pe_pk->serial[0],
|
||||
icc_pe_pk->serial[1],
|
||||
icc_pe_pk->serial[2]
|
||||
);
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "ICC PE PK (PIN Encipherment Public Key Certificate) not found.\n");
|
||||
|
@ -767,11 +794,11 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
|||
|
||||
// 9f36 Application Transaction Counter (ATC)
|
||||
const struct tlv *atc_tlv = tlvdb_get(atc_db, 0x9f36, NULL);
|
||||
if(atc_tlv) {
|
||||
if (atc_tlv) {
|
||||
PrintAndLogEx(NORMAL, "\nATC (Application Transaction Counter) [%zu] %s", atc_tlv->len, sprint_hex_inrow(atc_tlv->value, atc_tlv->len));
|
||||
|
||||
const struct tlv *core_atc_tlv = tlvdb_get(tlv, 0x9f36, NULL);
|
||||
if(tlv_equal(core_atc_tlv, atc_tlv)) {
|
||||
if (tlv_equal(core_atc_tlv, atc_tlv)) {
|
||||
PrintAndLogEx(SUCCESS, "ATC check OK.");
|
||||
PrintAndLogEx(SUCCESS, "fDDA (fast DDA) verified OK.");
|
||||
} else {
|
||||
|
@ -829,12 +856,12 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
|||
|
||||
struct tlvdb *dda_db = NULL;
|
||||
if (buf[0] == 0x80) {
|
||||
if (len < 3 ) {
|
||||
if (len < 3) {
|
||||
PrintAndLogEx(WARNING, "Error: Internal Authenticate format1 parsing error. length=%d", len);
|
||||
} else {
|
||||
// parse response 0x80
|
||||
struct tlvdb *t80 = tlvdb_parse_multi(buf, len);
|
||||
const struct tlv * t80tlv = tlvdb_get_tlv(t80);
|
||||
const struct tlv *t80tlv = tlvdb_get_tlv(t80);
|
||||
|
||||
// 9f4b Signed Dynamic Application Data
|
||||
dda_db = tlvdb_fixed(0x9f4b, t80tlv->len, t80tlv->value);
|
||||
|
@ -842,14 +869,14 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
|||
|
||||
tlvdb_free(t80);
|
||||
|
||||
if (decodeTLV){
|
||||
if (decodeTLV) {
|
||||
PrintAndLogEx(NORMAL, "* * * Decode response format 1:");
|
||||
TLVPrintFromTLV(dda_db);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dda_db = tlvdb_parse_multi(buf, len);
|
||||
if(!dda_db) {
|
||||
if (!dda_db) {
|
||||
PrintAndLogEx(WARNING, "Error: Can't parse Internal Authenticate result as TLV");
|
||||
free(ddol_data_tlv);
|
||||
emv_pk_free(pk);
|
||||
|
@ -877,7 +904,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
|||
|
||||
// 9f4c ICC Dynamic Number
|
||||
const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
|
||||
if(idn_tlv) {
|
||||
if (idn_tlv) {
|
||||
PrintAndLogEx(INFO, "\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
|
||||
PrintAndLogEx(INFO, "DDA verified OK.");
|
||||
tlvdb_add(tlv, idn_db);
|
||||
|
@ -899,7 +926,8 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv) {
|
||||
int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv)
|
||||
{
|
||||
|
||||
struct emv_pk *pk = get_ca_pk(tlv);
|
||||
if (!pk) {
|
||||
|
@ -921,16 +949,16 @@ int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, st
|
|||
return 2;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
|
||||
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]
|
||||
);
|
||||
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]
|
||||
);
|
||||
|
||||
struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv);
|
||||
if (!icc_pk) {
|
||||
|
@ -940,16 +968,16 @@ int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, st
|
|||
return 2;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "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]
|
||||
);
|
||||
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]
|
||||
);
|
||||
|
||||
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
||||
if (dac_db) {
|
||||
|
@ -966,10 +994,10 @@ int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, st
|
|||
|
||||
PrintAndLogEx(NORMAL, "\n* * Check Signed Dynamic Application Data (SDAD)");
|
||||
struct tlvdb *idn_db = emv_pki_perform_cda_ex(icc_pk, tlv, ac_tlv,
|
||||
pdol_data_tlv, // pdol
|
||||
ac_data_tlv, // cdol1
|
||||
NULL, // cdol2
|
||||
true);
|
||||
pdol_data_tlv, // pdol
|
||||
ac_data_tlv, // cdol1
|
||||
NULL, // cdol2
|
||||
true);
|
||||
if (idn_db) {
|
||||
const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
|
||||
PrintAndLogEx(NORMAL, "\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
|
||||
|
@ -985,7 +1013,8 @@ int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, st
|
|||
return 0;
|
||||
}
|
||||
|
||||
int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) {
|
||||
int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root)
|
||||
{
|
||||
|
||||
struct emv_pk *pk = get_ca_pk(tlvRoot);
|
||||
if (!pk) {
|
||||
|
@ -1000,16 +1029,16 @@ int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) {
|
|||
return 2;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "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]
|
||||
);
|
||||
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);
|
||||
|
||||
|
@ -1026,16 +1055,16 @@ int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) {
|
|||
return 2;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "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]
|
||||
);
|
||||
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);
|
||||
|
|
|
@ -63,7 +63,7 @@ enum CardPSVendor {
|
|||
CV_CB,
|
||||
CV_OTHER,
|
||||
};
|
||||
extern enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen);
|
||||
extern enum CardPSVendor GetCardPSVendor(uint8_t *AID, size_t AIDlen);
|
||||
|
||||
extern bool TLVPrintFromBuffer(uint8_t *data, int datalen);
|
||||
extern void TLVPrintFromTLV(struct tlvdb *tlv);
|
||||
|
|
|
@ -20,47 +20,48 @@
|
|||
#include "emv_tags.h"
|
||||
|
||||
static const ApplicationDataElm ApplicationData[] = {
|
||||
{0x82, "AIP"},
|
||||
{0x94, "AFL"},
|
||||
{0x82, "AIP"},
|
||||
{0x94, "AFL"},
|
||||
|
||||
{0x5A, "PAN"},
|
||||
{0x5F34, "PANSeqNo"},
|
||||
{0x5F24, "ExpirationDate"},
|
||||
{0x5F25, "EffectiveDate"},
|
||||
{0x5F28, "IssuerCountryCode"},
|
||||
{0x5A, "PAN"},
|
||||
{0x5F34, "PANSeqNo"},
|
||||
{0x5F24, "ExpirationDate"},
|
||||
{0x5F25, "EffectiveDate"},
|
||||
{0x5F28, "IssuerCountryCode"},
|
||||
|
||||
{0x50, "ApplicationLabel"},
|
||||
{0x9F08, "VersionNumber"},
|
||||
{0x9F42, "CurrencyCode"},
|
||||
{0x5F2D, "LanguagePreference"},
|
||||
{0x87, "PriorityIndicator"},
|
||||
{0x9F36, "ATC"}, //Application Transaction Counter
|
||||
{0x50, "ApplicationLabel"},
|
||||
{0x9F08, "VersionNumber"},
|
||||
{0x9F42, "CurrencyCode"},
|
||||
{0x5F2D, "LanguagePreference"},
|
||||
{0x87, "PriorityIndicator"},
|
||||
{0x9F36, "ATC"}, //Application Transaction Counter
|
||||
|
||||
{0x5F20, "CardholderName"},
|
||||
{0x5F20, "CardholderName"},
|
||||
|
||||
{0x9F38, "PDOL"},
|
||||
{0x8C, "CDOL1"},
|
||||
{0x8D, "CDOL2"},
|
||||
{0x9F38, "PDOL"},
|
||||
{0x8C, "CDOL1"},
|
||||
{0x8D, "CDOL2"},
|
||||
|
||||
{0x9F07, "AUC"}, // Application Usage Control
|
||||
{0x9F6C, "CTQ"},
|
||||
{0x8E, "CVMList"},
|
||||
{0x9F0D, "IACDefault"},
|
||||
{0x9F0E, "IACDeny"},
|
||||
{0x9F0F, "IACOnline"},
|
||||
{0x9F07, "AUC"}, // Application Usage Control
|
||||
{0x9F6C, "CTQ"},
|
||||
{0x8E, "CVMList"},
|
||||
{0x9F0D, "IACDefault"},
|
||||
{0x9F0E, "IACDeny"},
|
||||
{0x9F0F, "IACOnline"},
|
||||
|
||||
{0x8F, "CertificationAuthorityPublicKeyIndex"},
|
||||
{0x9F32, "IssuerPublicKeyExponent"},
|
||||
{0x92, "IssuerPublicKeyRemainder"},
|
||||
{0x90, "IssuerPublicKeyCertificate"},
|
||||
{0x9F47, "ICCPublicKeyExponent"},
|
||||
{0x9F46, "ICCPublicKeyCertificate"},
|
||||
{0x8F, "CertificationAuthorityPublicKeyIndex"},
|
||||
{0x9F32, "IssuerPublicKeyExponent"},
|
||||
{0x92, "IssuerPublicKeyRemainder"},
|
||||
{0x90, "IssuerPublicKeyCertificate"},
|
||||
{0x9F47, "ICCPublicKeyExponent"},
|
||||
{0x9F46, "ICCPublicKeyCertificate"},
|
||||
|
||||
{0x00, "end..."}
|
||||
{0x00, "end..."}
|
||||
};
|
||||
int ApplicationDataLen = sizeof(ApplicationData) / sizeof(ApplicationDataElm);
|
||||
|
||||
char* GetApplicationDataName(tlv_tag_t tag) {
|
||||
char *GetApplicationDataName(tlv_tag_t tag)
|
||||
{
|
||||
for (int i = 0; i < ApplicationDataLen; i++)
|
||||
if (ApplicationData[i].Tag == tag)
|
||||
return ApplicationData[i].Name;
|
||||
|
@ -68,7 +69,8 @@ char* GetApplicationDataName(tlv_tag_t tag) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int JsonSaveJsonObject(json_t *root, char *path, json_t *value) {
|
||||
int JsonSaveJsonObject(json_t *root, char *path, json_t *value)
|
||||
{
|
||||
json_error_t error;
|
||||
|
||||
if (strlen(path) < 1)
|
||||
|
@ -86,31 +88,36 @@ int JsonSaveJsonObject(json_t *root, char *path, json_t *value) {
|
|||
}
|
||||
}
|
||||
|
||||
int JsonSaveInt(json_t *root, char *path, int value) {
|
||||
int JsonSaveInt(json_t *root, char *path, int value)
|
||||
{
|
||||
return JsonSaveJsonObject(root, path, json_integer(value));
|
||||
}
|
||||
|
||||
int JsonSaveStr(json_t *root, char *path, char *value) {
|
||||
int JsonSaveStr(json_t *root, char *path, char *value)
|
||||
{
|
||||
return JsonSaveJsonObject(root, path, json_string(value));
|
||||
};
|
||||
|
||||
int JsonSaveBufAsHexCompact(json_t *elm, char *path, uint8_t *data, size_t datalen) {
|
||||
char * msg = sprint_hex_inrow(data, datalen);
|
||||
int JsonSaveBufAsHexCompact(json_t *elm, char *path, uint8_t *data, size_t datalen)
|
||||
{
|
||||
char *msg = sprint_hex_inrow(data, datalen);
|
||||
if (msg && strlen(msg) && msg[strlen(msg) - 1] == ' ')
|
||||
msg[strlen(msg) - 1] = '\0';
|
||||
|
||||
return JsonSaveStr(elm, path, msg);
|
||||
}
|
||||
|
||||
int JsonSaveBufAsHex(json_t *elm, char *path, uint8_t *data, size_t datalen) {
|
||||
char * msg = sprint_hex(data, datalen);
|
||||
int JsonSaveBufAsHex(json_t *elm, char *path, uint8_t *data, size_t datalen)
|
||||
{
|
||||
char *msg = sprint_hex(data, datalen);
|
||||
if (msg && strlen(msg) && msg[strlen(msg) - 1] == ' ')
|
||||
msg[strlen(msg) - 1] = '\0';
|
||||
|
||||
return JsonSaveStr(elm, path, msg);
|
||||
}
|
||||
|
||||
int JsonSaveHex(json_t *elm, char *path, uint64_t data, int datalen) {
|
||||
int JsonSaveHex(json_t *elm, char *path, uint64_t data, int datalen)
|
||||
{
|
||||
uint8_t bdata[8] = {0};
|
||||
int len = 0;
|
||||
if (!datalen) {
|
||||
|
@ -130,7 +137,8 @@ int JsonSaveHex(json_t *elm, char *path, uint64_t data, int datalen) {
|
|||
return JsonSaveBufAsHex(elm, path, bdata, len);
|
||||
}
|
||||
|
||||
int JsonSaveTLVValue(json_t *root, char *path, struct tlvdb *tlvdbelm) {
|
||||
int JsonSaveTLVValue(json_t *root, char *path, struct tlvdb *tlvdbelm)
|
||||
{
|
||||
const struct tlv *tlvelm = tlvdb_get_tlv(tlvdbelm);
|
||||
if (tlvelm)
|
||||
return JsonSaveBufAsHex(root, path, (uint8_t *)tlvelm->value, tlvelm->len);
|
||||
|
@ -138,7 +146,8 @@ int JsonSaveTLVValue(json_t *root, char *path, struct tlvdb *tlvdbelm) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int JsonSaveTLVElm(json_t *elm, char *path, struct tlv *tlvelm, bool saveName, bool saveValue, bool saveAppDataLink) {
|
||||
int JsonSaveTLVElm(json_t *elm, char *path, struct tlv *tlvelm, bool saveName, bool saveValue, bool saveAppDataLink)
|
||||
{
|
||||
json_error_t error;
|
||||
|
||||
if (strlen(path) < 1 || !tlvelm)
|
||||
|
@ -164,11 +173,11 @@ int JsonSaveTLVElm(json_t *elm, char *path, struct tlv *tlvelm, bool saveName, b
|
|||
}
|
||||
|
||||
if (saveAppDataLink) {
|
||||
char * AppDataName = GetApplicationDataName(tlvelm->tag);
|
||||
char *AppDataName = GetApplicationDataName(tlvelm->tag);
|
||||
if (AppDataName)
|
||||
JsonSaveStr(obj, "appdata", AppDataName);
|
||||
} else {
|
||||
char * name = emv_get_tag_name(tlvelm);
|
||||
char *name = emv_get_tag_name(tlvelm);
|
||||
if (saveName && name && strlen(name) > 0 && strncmp(name, "Unknown", 7))
|
||||
JsonSaveStr(obj, "name", emv_get_tag_name(tlvelm));
|
||||
JsonSaveHex(obj, "tag", tlvelm->tag, 0);
|
||||
|
@ -182,15 +191,17 @@ int JsonSaveTLVElm(json_t *elm, char *path, struct tlv *tlvelm, bool saveName, b
|
|||
return 0;
|
||||
}
|
||||
|
||||
int JsonSaveTLVTreeElm(json_t *elm, char *path, struct tlvdb *tlvdbelm, bool saveName, bool saveValue, bool saveAppDataLink) {
|
||||
int JsonSaveTLVTreeElm(json_t *elm, char *path, struct tlvdb *tlvdbelm, bool saveName, bool saveValue, bool saveAppDataLink)
|
||||
{
|
||||
return JsonSaveTLVElm(elm, path, (struct tlv *)tlvdb_get_tlv(tlvdbelm), saveName, saveValue, saveAppDataLink);
|
||||
}
|
||||
|
||||
int JsonSaveTLVTree(json_t *root, json_t *elm, char *path, struct tlvdb *tlvdbelm) {
|
||||
int JsonSaveTLVTree(json_t *root, json_t *elm, char *path, struct tlvdb *tlvdbelm)
|
||||
{
|
||||
struct tlvdb *tlvp = tlvdbelm;
|
||||
while (tlvp) {
|
||||
const struct tlv * tlvpelm = tlvdb_get_tlv(tlvp);
|
||||
char * AppDataName = NULL;
|
||||
const struct tlv *tlvpelm = tlvdb_get_tlv(tlvp);
|
||||
char *AppDataName = NULL;
|
||||
if (tlvpelm)
|
||||
AppDataName = GetApplicationDataName(tlvpelm->tag);
|
||||
|
||||
|
@ -213,7 +224,7 @@ int JsonSaveTLVTree(json_t *root, json_t *elm, char *path, struct tlvdb *tlvdbel
|
|||
|
||||
if (tlvdb_elm_get_children(tlvp)) {
|
||||
// get path element
|
||||
if(!pelm)
|
||||
if (!pelm)
|
||||
return 1;
|
||||
|
||||
// check childs element and add it if not found
|
||||
|
@ -239,7 +250,8 @@ int JsonSaveTLVTree(json_t *root, json_t *elm, char *path, struct tlvdb *tlvdbel
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t * buffer, size_t maxbufferlen, size_t *bufferlen) {
|
||||
bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t *buffer, size_t maxbufferlen, size_t *bufferlen)
|
||||
{
|
||||
int buflen = 0;
|
||||
|
||||
switch (param_gethex_to_eol(hexvalue, 0, buffer, maxbufferlen, &buflen)) {
|
||||
|
@ -259,13 +271,14 @@ bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t * buffer, s
|
|||
return false;
|
||||
}
|
||||
|
||||
if ( bufferlen )
|
||||
if (bufferlen)
|
||||
*bufferlen = buflen;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int JsonLoadStr(json_t *root, char *path, char *value) {
|
||||
int JsonLoadStr(json_t *root, char *path, char *value)
|
||||
{
|
||||
if (!value)
|
||||
return 1;
|
||||
|
||||
|
@ -273,7 +286,7 @@ int JsonLoadStr(json_t *root, char *path, char *value) {
|
|||
if (!jelm || !json_is_string(jelm))
|
||||
return 2;
|
||||
|
||||
const char * strval = json_string_value(jelm);
|
||||
const char *strval = json_string_value(jelm);
|
||||
if (!strval)
|
||||
return 1;
|
||||
|
||||
|
@ -282,7 +295,8 @@ int JsonLoadStr(json_t *root, char *path, char *value) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int JsonLoadBufAsHex(json_t *elm, char *path, uint8_t *data, size_t maxbufferlen, size_t *datalen) {
|
||||
int JsonLoadBufAsHex(json_t *elm, char *path, uint8_t *data, size_t maxbufferlen, size_t *datalen)
|
||||
{
|
||||
if (datalen)
|
||||
*datalen = 0;
|
||||
|
||||
|
@ -296,7 +310,8 @@ int JsonLoadBufAsHex(json_t *elm, char *path, uint8_t *data, size_t maxbufferlen
|
|||
return 0;
|
||||
};
|
||||
|
||||
bool ParamLoadFromJson(struct tlvdb *tlv) {
|
||||
bool ParamLoadFromJson(struct tlvdb *tlv)
|
||||
{
|
||||
json_t *root;
|
||||
json_error_t error;
|
||||
|
||||
|
@ -324,20 +339,18 @@ bool ParamLoadFromJson(struct tlvdb *tlv) {
|
|||
|
||||
PrintAndLog("Load params: json(%d) OK", json_array_size(root));
|
||||
|
||||
for(int i = 0; i < json_array_size(root); i++) {
|
||||
for (int i = 0; i < json_array_size(root); i++) {
|
||||
json_t *data, *jtag, *jlength, *jvalue;
|
||||
|
||||
data = json_array_get(root, i);
|
||||
if(!json_is_object(data))
|
||||
{
|
||||
if (!json_is_object(data)) {
|
||||
PrintAndLog("Load params: data [%d] is not an object", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
|
||||
jtag = json_object_get(data, "tag");
|
||||
if(!json_is_string(jtag))
|
||||
{
|
||||
if (!json_is_string(jtag)) {
|
||||
PrintAndLog("Load params: data [%d] tag is not a string", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
|
@ -345,8 +358,7 @@ bool ParamLoadFromJson(struct tlvdb *tlv) {
|
|||
const char *tlvTag = json_string_value(jtag);
|
||||
|
||||
jvalue = json_object_get(data, "value");
|
||||
if(!json_is_string(jvalue))
|
||||
{
|
||||
if (!json_is_string(jvalue)) {
|
||||
PrintAndLog("Load params: data [%d] value is not a string", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
|
@ -354,8 +366,7 @@ bool ParamLoadFromJson(struct tlvdb *tlv) {
|
|||
const char *tlvValue = json_string_value(jvalue);
|
||||
|
||||
jlength = json_object_get(data, "length");
|
||||
if(!json_is_number(jlength))
|
||||
{
|
||||
if (!json_is_number(jlength)) {
|
||||
PrintAndLog("Load params: data [%d] length is not a number", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
|
|
|
@ -18,7 +18,7 @@ typedef struct {
|
|||
char *Name;
|
||||
} ApplicationDataElm;
|
||||
|
||||
extern char* GetApplicationDataName(tlv_tag_t tag);
|
||||
extern char *GetApplicationDataName(tlv_tag_t tag);
|
||||
|
||||
extern int JsonSaveJsonObject(json_t *root, char *path, json_t *value);
|
||||
extern int JsonSaveStr(json_t *root, char *path, char *value);
|
||||
|
|
|
@ -37,11 +37,13 @@ struct emv_pk c_mchip_05 = {
|
|||
0x06, 0xd8, 0xce, 0x70,
|
||||
0x2d, 0xa3, 0xea, 0xe8,
|
||||
0x90, 0x70, 0x1d, 0x45,
|
||||
0xe2, 0x74, 0xc8, 0x45, },
|
||||
0xe2, 0x74, 0xc8, 0x45,
|
||||
},
|
||||
.exp = { 0x03, },
|
||||
.elen = 1,
|
||||
.mlen = 1408 / 8,
|
||||
.modulus = (unsigned char[]){
|
||||
.modulus = (unsigned char[])
|
||||
{
|
||||
0xb8, 0x04, 0x8a, 0xbc, 0x30, 0xc9, 0x0d, 0x97, 0x63, 0x36, 0x54, 0x3e, 0x3f, 0xd7, 0x09, 0x1c,
|
||||
0x8f, 0xe4, 0x80, 0x0d, 0xf8, 0x20, 0xed, 0x55, 0xe7, 0xe9, 0x48, 0x13, 0xed, 0x00, 0x55, 0x5b,
|
||||
0x57, 0x3f, 0xec, 0xa3, 0xd8, 0x4a, 0xf6, 0x13, 0x1a, 0x65, 0x1d, 0x66, 0xcf, 0xf4, 0x28, 0x4f,
|
||||
|
@ -57,45 +59,45 @@ struct emv_pk c_mchip_05 = {
|
|||
};
|
||||
|
||||
const unsigned char c_issuer_cert[] = {
|
||||
0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
|
||||
0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
|
||||
0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
|
||||
0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
|
||||
0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
|
||||
0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
|
||||
0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
|
||||
0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
|
||||
0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
|
||||
0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
|
||||
0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
|
||||
0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
|
||||
0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
|
||||
0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
|
||||
0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
|
||||
0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
|
||||
0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
|
||||
0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
|
||||
0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
|
||||
0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
|
||||
0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
|
||||
0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
|
||||
};
|
||||
|
||||
const unsigned char c_issuer_rem[] = {
|
||||
0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
|
||||
0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
|
||||
0x6d, 0xbd, 0x64, 0x15,
|
||||
0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
|
||||
0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
|
||||
0x6d, 0xbd, 0x64, 0x15,
|
||||
};
|
||||
|
||||
const unsigned char c_issuer_exp[] = {
|
||||
0x03,
|
||||
0x03,
|
||||
};
|
||||
|
||||
const unsigned char c_icc_cert[] = {
|
||||
0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
|
||||
0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
|
||||
0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
|
||||
0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
|
||||
0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
|
||||
0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
|
||||
0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
|
||||
0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
|
||||
0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
|
||||
0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
|
||||
0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
|
||||
0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
|
||||
0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
|
||||
0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
|
||||
0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
|
||||
0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
|
||||
0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
|
||||
0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
|
||||
0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
|
||||
0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
|
||||
0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
|
||||
0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
|
||||
};
|
||||
|
||||
const unsigned char c_icc_exp[] = {
|
||||
0x03,
|
||||
0x03,
|
||||
};
|
||||
|
||||
const unsigned char c_sdad_cr[] = {
|
||||
|
@ -153,8 +155,8 @@ static int cda_test_raw(bool verbose)
|
|||
const struct emv_pk *pk = &c_mchip_05;
|
||||
|
||||
struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
|
||||
pk->modulus, pk->mlen,
|
||||
pk->exp, pk->elen);
|
||||
pk->modulus, pk->mlen,
|
||||
pk->exp, pk->elen);
|
||||
if (!kcp)
|
||||
return 1;
|
||||
|
||||
|
@ -212,7 +214,7 @@ static int cda_test_raw(bool verbose)
|
|||
free(ipk_data);
|
||||
|
||||
struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
|
||||
c_issuer_exp, (int) sizeof(c_issuer_exp));
|
||||
c_issuer_exp, (int) sizeof(c_issuer_exp));
|
||||
free(ipk_pk);
|
||||
if (!ikcp)
|
||||
return 1;
|
||||
|
@ -270,7 +272,7 @@ static int cda_test_raw(bool verbose)
|
|||
free(iccpk_data);
|
||||
|
||||
struct crypto_pk *icckcp = crypto_pk_open(PK_RSA, iccpk_pk, (int) iccpk_pk_len,
|
||||
c_issuer_exp, (int) sizeof(c_issuer_exp));
|
||||
c_issuer_exp, (int) sizeof(c_issuer_exp));
|
||||
free(iccpk_pk);
|
||||
if (!icckcp)
|
||||
return 1;
|
||||
|
@ -375,16 +377,16 @@ static int cda_test_pk(bool verbose)
|
|||
tlvdb_add(db, tlvdb_fixed(0x9f37, sizeof(c_dd1), c_dd1));
|
||||
|
||||
struct tlvdb *cda_db;
|
||||
cda_db = tlvdb_fixed(0x9f27, 1, (unsigned char[]){ 0x40 });
|
||||
cda_db = tlvdb_fixed(0x9f27, 1, (unsigned char[]) { 0x40 });
|
||||
tlvdb_add(cda_db, tlvdb_fixed(0x9f36, 2, (unsigned char[]) { 0x00, 0x10 }));
|
||||
tlvdb_add(cda_db, tlvdb_external(0x9f4b, sizeof(c_sdad_cr), c_sdad_cr));
|
||||
tlvdb_add(cda_db, tlvdb_fixed(0x9f10, 0x12,
|
||||
(unsigned char[]) { 0x00, 0x10, 0x90, 0x40, 0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}));
|
||||
(unsigned char[]) { 0x00, 0x10, 0x90, 0x40, 0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}));
|
||||
|
||||
struct tlvdb *idndb = emv_pki_perform_cda(iccpk, db, cda_db,
|
||||
NULL,
|
||||
&crm1_tlv,
|
||||
NULL);
|
||||
NULL,
|
||||
&crm1_tlv,
|
||||
NULL);
|
||||
if (!idndb) {
|
||||
fprintf(stderr, "Could not recover IDN!\n");
|
||||
tlvdb_free(cda_db);
|
||||
|
|
|
@ -204,8 +204,8 @@ static int test_pk(bool verbose)
|
|||
printf("Testing public keys interfaces\n");
|
||||
|
||||
pubk = crypto_pk_open(PK_RSA,
|
||||
pk_N, sizeof(pk_N),
|
||||
pk_E, sizeof(pk_E));
|
||||
pk_N, sizeof(pk_N),
|
||||
pk_E, sizeof(pk_E));
|
||||
if (!pubk) {
|
||||
fprintf(stderr, "ERROR: open public key.\n");
|
||||
return 1;
|
||||
|
@ -234,14 +234,14 @@ static int test_pk(bool verbose)
|
|||
free(tmp);
|
||||
|
||||
privk = crypto_pk_open_priv(PK_RSA,
|
||||
pk_N, sizeof(pk_N),
|
||||
pk_E, sizeof(pk_E),
|
||||
pk_D, sizeof(pk_D),
|
||||
pk_P, sizeof(pk_P),
|
||||
pk_Q, sizeof(pk_Q),
|
||||
pk_dP, sizeof(pk_dP),
|
||||
pk_dQ, sizeof(pk_dQ),
|
||||
pk_I, sizeof(pk_I));
|
||||
pk_N, sizeof(pk_N),
|
||||
pk_E, sizeof(pk_E),
|
||||
pk_D, sizeof(pk_D),
|
||||
pk_P, sizeof(pk_P),
|
||||
pk_Q, sizeof(pk_Q),
|
||||
pk_dP, sizeof(pk_dP),
|
||||
pk_dQ, sizeof(pk_dQ),
|
||||
pk_I, sizeof(pk_I));
|
||||
if (!privk) {
|
||||
fprintf(stderr, "ERROR: open private key.\n");
|
||||
goto close_pub;
|
||||
|
|
|
@ -13,6 +13,6 @@
|
|||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern int exec_crypto_test(bool verbose);
|
||||
|
|
|
@ -33,7 +33,8 @@
|
|||
#include "crypto/libpcrypto.h"
|
||||
#include "emv/emv_roca.h"
|
||||
|
||||
int ExecuteCryptoTests(bool verbose) {
|
||||
int ExecuteCryptoTests(bool verbose)
|
||||
{
|
||||
int res;
|
||||
bool TestFail = false;
|
||||
|
||||
|
@ -97,9 +98,9 @@ int ExecuteCryptoTests(bool verbose) {
|
|||
PrintAndLog("\n--------------------------");
|
||||
|
||||
if (TestFail)
|
||||
PrintAndLogEx(FAILED, "\tTest(s) [ %s ]", _RED_(FAIL) );
|
||||
PrintAndLogEx(FAILED, "\tTest(s) [ %s ]", _RED_(FAIL));
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, "\tTest(s) [ %s ]", _GREEN_(OK) );
|
||||
PrintAndLogEx(SUCCESS, "\tTest(s) [ %s ]", _GREEN_(OK));
|
||||
|
||||
return TestFail;
|
||||
}
|
||||
|
|
|
@ -39,11 +39,13 @@ struct emv_pk mchip_05 = {
|
|||
0x06, 0xd8, 0xce, 0x70,
|
||||
0x2d, 0xa3, 0xea, 0xe8,
|
||||
0x90, 0x70, 0x1d, 0x45,
|
||||
0xe2, 0x74, 0xc8, 0x45, },
|
||||
0xe2, 0x74, 0xc8, 0x45,
|
||||
},
|
||||
.exp = { 0x03, },
|
||||
.elen = 1,
|
||||
.mlen = 1408 / 8,
|
||||
.modulus = (unsigned char[]){
|
||||
.modulus = (unsigned char[])
|
||||
{
|
||||
0xb8, 0x04, 0x8a, 0xbc, 0x30, 0xc9, 0x0d, 0x97, 0x63, 0x36, 0x54, 0x3e, 0x3f, 0xd7, 0x09, 0x1c,
|
||||
0x8f, 0xe4, 0x80, 0x0d, 0xf8, 0x20, 0xed, 0x55, 0xe7, 0xe9, 0x48, 0x13, 0xed, 0x00, 0x55, 0x5b,
|
||||
0x57, 0x3f, 0xec, 0xa3, 0xd8, 0x4a, 0xf6, 0x13, 0x1a, 0x65, 0x1d, 0x66, 0xcf, 0xf4, 0x28, 0x4f,
|
||||
|
@ -59,45 +61,45 @@ struct emv_pk mchip_05 = {
|
|||
};
|
||||
|
||||
const unsigned char d_issuer_cert[] = {
|
||||
0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
|
||||
0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
|
||||
0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
|
||||
0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
|
||||
0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
|
||||
0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
|
||||
0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
|
||||
0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
|
||||
0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
|
||||
0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
|
||||
0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
|
||||
0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
|
||||
0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
|
||||
0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
|
||||
0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
|
||||
0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
|
||||
0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
|
||||
0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
|
||||
0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
|
||||
0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
|
||||
0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
|
||||
0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
|
||||
};
|
||||
|
||||
const unsigned char d_issuer_rem[] = {
|
||||
0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
|
||||
0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
|
||||
0x6d, 0xbd, 0x64, 0x15,
|
||||
0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
|
||||
0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
|
||||
0x6d, 0xbd, 0x64, 0x15,
|
||||
};
|
||||
|
||||
const unsigned char d_issuer_exp[] = {
|
||||
0x03,
|
||||
0x03,
|
||||
};
|
||||
|
||||
const unsigned char d_icc_cert[] = {
|
||||
0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
|
||||
0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
|
||||
0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
|
||||
0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
|
||||
0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
|
||||
0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
|
||||
0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
|
||||
0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
|
||||
0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
|
||||
0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
|
||||
0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
|
||||
0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
|
||||
0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
|
||||
0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
|
||||
0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
|
||||
0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
|
||||
0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
|
||||
0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
|
||||
0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
|
||||
0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
|
||||
0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
|
||||
0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
|
||||
};
|
||||
|
||||
const unsigned char d_icc_exp[] = {
|
||||
0x03,
|
||||
0x03,
|
||||
};
|
||||
|
||||
const unsigned char d_sdad_cr[] = {
|
||||
|
@ -143,8 +145,8 @@ static int dda_test_raw(bool verbose)
|
|||
const struct emv_pk *pk = &mchip_05;
|
||||
|
||||
struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
|
||||
pk->modulus, pk->mlen,
|
||||
pk->exp, pk->elen);
|
||||
pk->modulus, pk->mlen,
|
||||
pk->exp, pk->elen);
|
||||
if (!kcp)
|
||||
return 1;
|
||||
|
||||
|
@ -202,7 +204,7 @@ static int dda_test_raw(bool verbose)
|
|||
free(ipk_data);
|
||||
|
||||
struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
|
||||
d_issuer_exp, (int) sizeof(d_issuer_exp));
|
||||
d_issuer_exp, (int) sizeof(d_issuer_exp));
|
||||
free(ipk_pk);
|
||||
if (!ikcp)
|
||||
return 1;
|
||||
|
@ -260,7 +262,7 @@ static int dda_test_raw(bool verbose)
|
|||
free(iccpk_data);
|
||||
|
||||
struct crypto_pk *icckcp = crypto_pk_open(PK_RSA, iccpk_pk, (int) iccpk_pk_len,
|
||||
d_issuer_exp, (int) sizeof(d_issuer_exp));
|
||||
d_issuer_exp, (int) sizeof(d_issuer_exp));
|
||||
free(iccpk_pk);
|
||||
if (!icckcp)
|
||||
return 1;
|
||||
|
|
|
@ -37,11 +37,13 @@ struct emv_pk vsdc_01 = {
|
|||
0x60, 0x11, 0xc7, 0xe7,
|
||||
0xce, 0x3a, 0xec, 0x5f,
|
||||
0x03, 0xad, 0x2f, 0x8c,
|
||||
0xfc, 0x55, 0x03, 0xcc, },
|
||||
0xfc, 0x55, 0x03, 0xcc,
|
||||
},
|
||||
.exp = { 0x03, },
|
||||
.elen = 1,
|
||||
.mlen = 1024 / 8,
|
||||
.modulus = (unsigned char[]){
|
||||
.modulus = (unsigned char[])
|
||||
{
|
||||
0xc6, 0x96, 0x03, 0x42, 0x13, 0xd7, 0xd8, 0x54, 0x69, 0x84, 0x57, 0x9d, 0x1d, 0x0f, 0x0e, 0xa5,
|
||||
0x19, 0xcf, 0xf8, 0xde, 0xff, 0xc4, 0x29, 0x35, 0x4c, 0xf3, 0xa8, 0x71, 0xa6, 0xf7, 0x18, 0x3f,
|
||||
0x12, 0x28, 0xda, 0x5c, 0x74, 0x70, 0xc0, 0x55, 0x38, 0x71, 0x00, 0xcb, 0x93, 0x5a, 0x71, 0x2c,
|
||||
|
@ -54,35 +56,35 @@ struct emv_pk vsdc_01 = {
|
|||
};
|
||||
|
||||
const unsigned char issuer_cert[] = {
|
||||
0x3c, 0x5f, 0xea, 0xd4, 0xdd, 0x7b, 0xca, 0x44, 0xf9, 0x3e, 0x90, 0xc4, 0x4f, 0x76, 0xed, 0xe5,
|
||||
0x4a, 0x32, 0x88, 0xec, 0xdc, 0x78, 0x46, 0x9f, 0xcb, 0x12, 0x25, 0xc0, 0x3b, 0x2c, 0x04, 0xf2,
|
||||
0xc2, 0xf4, 0x12, 0x28, 0x1a, 0x08, 0x22, 0xdf, 0x14, 0x64, 0x92, 0x30, 0x98, 0x9f, 0xb1, 0x49,
|
||||
0x40, 0x70, 0xda, 0xf8, 0xc9, 0x53, 0x4a, 0x78, 0x81, 0x96, 0x01, 0x48, 0x61, 0x6a, 0xce, 0x58,
|
||||
0x17, 0x88, 0x12, 0x0d, 0x35, 0x06, 0xac, 0xe4, 0xce, 0xe5, 0x64, 0xfb, 0x27, 0xee, 0x53, 0x34,
|
||||
0x1c, 0x22, 0xf0, 0xb4, 0x5b, 0x31, 0x87, 0x3d, 0x05, 0xde, 0x54, 0x5e, 0xfe, 0x33, 0xbc, 0xd2,
|
||||
0x9b, 0x21, 0x85, 0xd0, 0x35, 0xa8, 0x06, 0xad, 0x08, 0xc6, 0x97, 0x6f, 0x35, 0x05, 0xa1, 0x99,
|
||||
0x99, 0x93, 0x0c, 0xa8, 0xa0, 0x3e, 0xfa, 0x32, 0x1c, 0x48, 0x60, 0x61, 0xf7, 0xdc, 0xec, 0x9f,
|
||||
0x3c, 0x5f, 0xea, 0xd4, 0xdd, 0x7b, 0xca, 0x44, 0xf9, 0x3e, 0x90, 0xc4, 0x4f, 0x76, 0xed, 0xe5,
|
||||
0x4a, 0x32, 0x88, 0xec, 0xdc, 0x78, 0x46, 0x9f, 0xcb, 0x12, 0x25, 0xc0, 0x3b, 0x2c, 0x04, 0xf2,
|
||||
0xc2, 0xf4, 0x12, 0x28, 0x1a, 0x08, 0x22, 0xdf, 0x14, 0x64, 0x92, 0x30, 0x98, 0x9f, 0xb1, 0x49,
|
||||
0x40, 0x70, 0xda, 0xf8, 0xc9, 0x53, 0x4a, 0x78, 0x81, 0x96, 0x01, 0x48, 0x61, 0x6a, 0xce, 0x58,
|
||||
0x17, 0x88, 0x12, 0x0d, 0x35, 0x06, 0xac, 0xe4, 0xce, 0xe5, 0x64, 0xfb, 0x27, 0xee, 0x53, 0x34,
|
||||
0x1c, 0x22, 0xf0, 0xb4, 0x5b, 0x31, 0x87, 0x3d, 0x05, 0xde, 0x54, 0x5e, 0xfe, 0x33, 0xbc, 0xd2,
|
||||
0x9b, 0x21, 0x85, 0xd0, 0x35, 0xa8, 0x06, 0xad, 0x08, 0xc6, 0x97, 0x6f, 0x35, 0x05, 0xa1, 0x99,
|
||||
0x99, 0x93, 0x0c, 0xa8, 0xa0, 0x3e, 0xfa, 0x32, 0x1c, 0x48, 0x60, 0x61, 0xf7, 0xdc, 0xec, 0x9f,
|
||||
};
|
||||
|
||||
const unsigned char issuer_rem[] = {
|
||||
0x1e, 0xbc, 0xa3, 0x0f, 0x00, 0xce, 0x59, 0x62, 0xa8, 0xc6, 0xe1, 0x30, 0x54, 0x4b, 0x82, 0x89,
|
||||
0x1b, 0x23, 0x6c, 0x65, 0xde, 0x29, 0x31, 0x7f, 0x36, 0x47, 0x35, 0xde, 0xe6, 0x3f, 0x65, 0x98,
|
||||
0x97, 0x58, 0x35, 0xd5
|
||||
0x1e, 0xbc, 0xa3, 0x0f, 0x00, 0xce, 0x59, 0x62, 0xa8, 0xc6, 0xe1, 0x30, 0x54, 0x4b, 0x82, 0x89,
|
||||
0x1b, 0x23, 0x6c, 0x65, 0xde, 0x29, 0x31, 0x7f, 0x36, 0x47, 0x35, 0xde, 0xe6, 0x3f, 0x65, 0x98,
|
||||
0x97, 0x58, 0x35, 0xd5
|
||||
};
|
||||
|
||||
const unsigned char issuer_exp[] = {
|
||||
0x03,
|
||||
0x03,
|
||||
};
|
||||
|
||||
const unsigned char ssad_cr[] = {
|
||||
0x99, 0xa5, 0x58, 0xb6, 0x2b, 0x67, 0x4a, 0xa5, 0xe7, 0xd2, 0xa5, 0x7e, 0x5e, 0xf6, 0xa6, 0xf2,
|
||||
0x25, 0x8e, 0x5d, 0xa0, 0x52, 0xd0, 0x5b, 0x54, 0xe5, 0xc1, 0x15, 0xff, 0x1c, 0xec, 0xf9, 0x4a,
|
||||
0xa2, 0xdf, 0x8f, 0x39, 0xa0, 0x1d, 0x71, 0xc6, 0x19, 0xeb, 0x81, 0x9d, 0xa5, 0x2e, 0xf3, 0x81,
|
||||
0xe8, 0x49, 0x79, 0x58, 0x6a, 0xea, 0x78, 0x55, 0xff, 0xbe, 0xf4, 0x0a, 0xa3, 0xa7, 0x1c, 0xd3,
|
||||
0xb0, 0x4c, 0xfd, 0xf2, 0x70, 0xae, 0xc8, 0x15, 0x8a, 0x27, 0x97, 0xf2, 0x4f, 0xd6, 0x13, 0xb7,
|
||||
0x48, 0x13, 0x46, 0x61, 0x13, 0x5c, 0xd2, 0x90, 0xe4, 0x5b, 0x04, 0xa8, 0xe0, 0xcc, 0xc7, 0x11,
|
||||
0xae, 0x04, 0x2f, 0x15, 0x9e, 0x73, 0xc8, 0x9c, 0x2a, 0x7e, 0x65, 0xa4, 0xc2, 0xfd, 0x1d, 0x61,
|
||||
0x06, 0x02, 0x4a, 0xa2, 0x71, 0x30, 0xb0, 0xec, 0xec, 0x02, 0x38, 0xf9, 0x16, 0x59, 0xde, 0x96,
|
||||
0x99, 0xa5, 0x58, 0xb6, 0x2b, 0x67, 0x4a, 0xa5, 0xe7, 0xd2, 0xa5, 0x7e, 0x5e, 0xf6, 0xa6, 0xf2,
|
||||
0x25, 0x8e, 0x5d, 0xa0, 0x52, 0xd0, 0x5b, 0x54, 0xe5, 0xc1, 0x15, 0xff, 0x1c, 0xec, 0xf9, 0x4a,
|
||||
0xa2, 0xdf, 0x8f, 0x39, 0xa0, 0x1d, 0x71, 0xc6, 0x19, 0xeb, 0x81, 0x9d, 0xa5, 0x2e, 0xf3, 0x81,
|
||||
0xe8, 0x49, 0x79, 0x58, 0x6a, 0xea, 0x78, 0x55, 0xff, 0xbe, 0xf4, 0x0a, 0xa3, 0xa7, 0x1c, 0xd3,
|
||||
0xb0, 0x4c, 0xfd, 0xf2, 0x70, 0xae, 0xc8, 0x15, 0x8a, 0x27, 0x97, 0xf2, 0x4f, 0xd6, 0x13, 0xb7,
|
||||
0x48, 0x13, 0x46, 0x61, 0x13, 0x5c, 0xd2, 0x90, 0xe4, 0x5b, 0x04, 0xa8, 0xe0, 0xcc, 0xc7, 0x11,
|
||||
0xae, 0x04, 0x2f, 0x15, 0x9e, 0x73, 0xc8, 0x9c, 0x2a, 0x7e, 0x65, 0xa4, 0xc2, 0xfd, 0x1d, 0x61,
|
||||
0x06, 0x02, 0x4a, 0xa2, 0x71, 0x30, 0xb0, 0xec, 0xec, 0x02, 0x38, 0xf9, 0x16, 0x59, 0xde, 0x96,
|
||||
};
|
||||
|
||||
const unsigned char ssd1[] = {
|
||||
|
@ -103,8 +105,8 @@ static int sda_test_raw(bool verbose)
|
|||
const struct emv_pk *pk = &vsdc_01;
|
||||
|
||||
struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
|
||||
pk->modulus, pk->mlen,
|
||||
pk->exp, pk->elen);
|
||||
pk->modulus, pk->mlen,
|
||||
pk->exp, pk->elen);
|
||||
if (!kcp)
|
||||
return 1;
|
||||
|
||||
|
@ -162,7 +164,7 @@ static int sda_test_raw(bool verbose)
|
|||
free(ipk_data);
|
||||
|
||||
struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
|
||||
issuer_exp, (int) sizeof(issuer_exp));
|
||||
issuer_exp, (int) sizeof(issuer_exp));
|
||||
free(ipk_pk);
|
||||
if (!ikcp)
|
||||
return 1;
|
||||
|
|
|
@ -91,7 +91,7 @@ static size_t tlv_parse_len(const unsigned char **buf, size_t *len)
|
|||
if (!(l & TLV_LEN_LONG))
|
||||
return l;
|
||||
|
||||
size_t ll = l &~ TLV_LEN_LONG;
|
||||
size_t ll = l & ~ TLV_LEN_LONG;
|
||||
if (ll > 5)
|
||||
return TLV_LEN_INVALID;
|
||||
|
||||
|
@ -123,9 +123,9 @@ bool tlv_parse_tl(const unsigned char **buf, size_t *len, struct tlv *tlv)
|
|||
static struct tlvdb *tlvdb_parse_children(struct tlvdb *parent);
|
||||
|
||||
static bool tlvdb_parse_one(struct tlvdb *tlvdb,
|
||||
struct tlvdb *parent,
|
||||
const unsigned char **tmp,
|
||||
size_t *left)
|
||||
struct tlvdb *parent,
|
||||
const unsigned char **tmp,
|
||||
size_t *left)
|
||||
{
|
||||
tlvdb->next = tlvdb->children = NULL;
|
||||
tlvdb->parent = parent;
|
||||
|
@ -240,7 +240,7 @@ struct tlvdb *tlvdb_parse_multi(const unsigned char *buf, size_t len)
|
|||
while (left != 0) {
|
||||
struct tlvdb *db = malloc(sizeof(*db));
|
||||
if (!tlvdb_parse_one(db, NULL, &tmp, &left)) {
|
||||
free (db);
|
||||
free(db);
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -298,14 +298,16 @@ void tlvdb_free(struct tlvdb *tlvdb)
|
|||
}
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_find_next(struct tlvdb *tlvdb, tlv_tag_t tag) {
|
||||
struct tlvdb *tlvdb_find_next(struct tlvdb *tlvdb, tlv_tag_t tag)
|
||||
{
|
||||
if (!tlvdb)
|
||||
return NULL;
|
||||
|
||||
return tlvdb_find(tlvdb->next, tag);
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_find(struct tlvdb *tlvdb, tlv_tag_t tag) {
|
||||
struct tlvdb *tlvdb_find(struct tlvdb *tlvdb, tlv_tag_t tag)
|
||||
{
|
||||
if (!tlvdb)
|
||||
return NULL;
|
||||
|
||||
|
@ -317,7 +319,8 @@ struct tlvdb *tlvdb_find(struct tlvdb *tlvdb, tlv_tag_t tag) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_find_full(struct tlvdb *tlvdb, tlv_tag_t tag) {
|
||||
struct tlvdb *tlvdb_find_full(struct tlvdb *tlvdb, tlv_tag_t tag)
|
||||
{
|
||||
if (!tlvdb)
|
||||
return NULL;
|
||||
|
||||
|
@ -326,7 +329,7 @@ struct tlvdb *tlvdb_find_full(struct tlvdb *tlvdb, tlv_tag_t tag) {
|
|||
return tlvdb;
|
||||
|
||||
if (tlvdb->children) {
|
||||
struct tlvdb * ch = tlvdb_find_full(tlvdb->children, tag);
|
||||
struct tlvdb *ch = tlvdb_find_full(tlvdb->children, tag);
|
||||
if (ch)
|
||||
return ch;
|
||||
}
|
||||
|
@ -335,7 +338,8 @@ struct tlvdb *tlvdb_find_full(struct tlvdb *tlvdb, tlv_tag_t tag) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_find_path(struct tlvdb *tlvdb, tlv_tag_t tag[]) {
|
||||
struct tlvdb *tlvdb_find_path(struct tlvdb *tlvdb, tlv_tag_t tag[])
|
||||
{
|
||||
int i = 0;
|
||||
struct tlvdb *tnext = tlvdb;
|
||||
|
||||
|
@ -469,12 +473,14 @@ const struct tlv *tlvdb_get(const struct tlvdb *tlvdb, tlv_tag_t tag, const stru
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const struct tlv *tlvdb_get_inchild(const struct tlvdb *tlvdb, tlv_tag_t tag, const struct tlv *prev) {
|
||||
const struct tlv *tlvdb_get_inchild(const struct tlvdb *tlvdb, tlv_tag_t tag, const struct tlv *prev)
|
||||
{
|
||||
tlvdb = tlvdb->children;
|
||||
return tlvdb_get(tlvdb, tag, prev);
|
||||
}
|
||||
|
||||
const struct tlv *tlvdb_get_tlv(const struct tlvdb *tlvdb) {
|
||||
const struct tlv *tlvdb_get_tlv(const struct tlvdb *tlvdb)
|
||||
{
|
||||
if (tlvdb)
|
||||
return &tlvdb->tag;
|
||||
else
|
||||
|
@ -564,13 +570,11 @@ bool tlvdb_get_uint8(struct tlvdb *tlvRoot, tlv_tag_t tag, uint8_t *value)
|
|||
bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value)
|
||||
{
|
||||
*value = 0;
|
||||
if (etlv)
|
||||
{
|
||||
if (etlv) {
|
||||
if (etlv->len == 0)
|
||||
return true;
|
||||
|
||||
if (etlv->len == 1)
|
||||
{
|
||||
if (etlv->len == 1) {
|
||||
*value = etlv->value[0];
|
||||
return true;
|
||||
}
|
||||
|
@ -581,15 +585,12 @@ bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value)
|
|||
bool tlv_get_int(const struct tlv *etlv, int *value)
|
||||
{
|
||||
*value = 0;
|
||||
if (etlv)
|
||||
{
|
||||
if (etlv) {
|
||||
if (etlv->len == 0)
|
||||
return true;
|
||||
|
||||
if (etlv->len <= 4)
|
||||
{
|
||||
for (int i = 0; i < etlv->len; i++)
|
||||
{
|
||||
if (etlv->len <= 4) {
|
||||
for (int i = 0; i < etlv->len; i++) {
|
||||
*value += etlv->value[i] * (1 << (i * 8));
|
||||
}
|
||||
return true;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue