make style

This commit is contained in:
Philippe Teuwen 2019-03-10 00:00:59 +01:00
commit 0373696662
483 changed files with 56514 additions and 52451 deletions

View file

@ -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;

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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");
}

View file

@ -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");

View file

@ -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);
}

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -13,6 +13,6 @@
* Lesser General Public License for more details.
*/
#include <stdbool.h>
#include <stdbool.h>
extern int exec_crypto_test(bool verbose);

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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;