mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-20 21:33:19 -07:00
Emv4 - more additions to hf emv exec
* added rsa polarssl and changed sha1 location to polarssl dir * deleted old sha1 * added emv-tools pk files * added polarrssl wrapper sketch to emv_tols * added test command * added crypto polarssl with sda test * added crypto tests and crypto_polarssl sha logic * added SDA,DDA,fDDA,CDA
This commit is contained in:
parent
69f98ec91e
commit
d03fb293bc
40 changed files with 9983 additions and 191 deletions
|
@ -9,6 +9,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdemv.h"
|
||||
#include "test/cryptotest.h"
|
||||
|
||||
int UsageCmdHFEMVSelect(void) {
|
||||
PrintAndLog("HELP : Executes select applet command:\n");
|
||||
|
@ -277,7 +278,7 @@ int CmdHFEMVPPSE(const char *cmd) {
|
|||
|
||||
int UsageCmdHFEMVExec(void) {
|
||||
PrintAndLog("HELP : Executes EMV contactless transaction:\n");
|
||||
PrintAndLog("Usage: hf emv exec [-s][-a][-t]\n");
|
||||
PrintAndLog("Usage: hf emv exec [-s][-a][-t][-f][-v][-c][-x][-g]\n");
|
||||
PrintAndLog(" Options:");
|
||||
PrintAndLog(" -s : select card");
|
||||
PrintAndLog(" -a : show APDU reqests and responses\n");
|
||||
|
@ -286,14 +287,16 @@ int UsageCmdHFEMVExec(void) {
|
|||
PrintAndLog(" -v : transaction type - qVSDC or M/Chip.\n");
|
||||
PrintAndLog(" -c : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n");
|
||||
PrintAndLog(" -x : transaction type - VSDC. For test only. Not a standart behavior.\n");
|
||||
PrintAndLog(" -g : VISA. generate AC from GPO\n");
|
||||
PrintAndLog("By default : transaction type - MSD.\n");
|
||||
PrintAndLog("Samples:");
|
||||
PrintAndLog(" hf emv pse -s -> select card");
|
||||
PrintAndLog(" hf emv pse -s -t -a -> select card, show responses in TLV, show APDU");
|
||||
PrintAndLog(" hf emv exec -s -a -t -> execute MSD transaction");
|
||||
PrintAndLog(" hf emv exec -s -a -t -c -> execute CDA transaction");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TLV_ADD(tag, value)( tlvdb_add(tlvRoot, tlvdb_fixed(tag, sizeof(value) - 1, (const unsigned char *)value)) )
|
||||
#define dreturn(n) {free(pdol_data_tlv);tlvdb_free(tlvSelect);tlvdb_free(tlvRoot);DropField();return n;}
|
||||
|
||||
int CmdHFEMVExec(const char *cmd) {
|
||||
bool activateField = false;
|
||||
|
@ -301,15 +304,22 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
bool decodeTLV = false;
|
||||
bool forceSearch = false;
|
||||
enum TransactionType TrType = TT_MSD;
|
||||
bool GenACGPO = false;
|
||||
|
||||
uint8_t buf[APDU_RES_LEN] = {0};
|
||||
size_t len = 0;
|
||||
uint16_t sw = 0;
|
||||
uint8_t AID[APDU_AID_LEN] = {0};
|
||||
size_t AIDlen = 0;
|
||||
uint8_t ODAiList[4096];
|
||||
size_t ODAiListLen = 0;
|
||||
|
||||
int res;
|
||||
|
||||
struct tlvdb *tlvSelect = NULL;
|
||||
struct tlvdb *tlvRoot = NULL;
|
||||
struct tlv *pdol_data_tlv = NULL;
|
||||
|
||||
if (strlen(cmd) < 1) {
|
||||
UsageCmdHFEMVExec();
|
||||
return 0;
|
||||
|
@ -352,6 +362,10 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
case 'C':
|
||||
TrType = TT_CDA;
|
||||
break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
GenACGPO = true;
|
||||
break;
|
||||
default:
|
||||
PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
|
||||
return 1;
|
||||
|
@ -361,7 +375,6 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
|
||||
|
||||
// init applets list tree
|
||||
struct tlvdb *tlvSelect = NULL;
|
||||
const char *al = "Applets list";
|
||||
tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al);
|
||||
|
||||
|
@ -385,8 +398,7 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
PrintAndLog("\n* Search AID in list.");
|
||||
SetAPDULogging(false);
|
||||
if (EMVSearch(activateField, true, decodeTLV, tlvSelect)) {
|
||||
tlvdb_free(tlvSelect);
|
||||
return 2;
|
||||
dreturn(2);
|
||||
}
|
||||
|
||||
// check search and select application id
|
||||
|
@ -395,14 +407,13 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
}
|
||||
|
||||
// Init TLV tree
|
||||
struct tlvdb *tlvRoot = NULL;
|
||||
const char *alr = "Root terminal TLV tree";
|
||||
tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr);
|
||||
|
||||
// check if we found EMV application on card
|
||||
if (!AIDlen) {
|
||||
PrintAndLog("Can't select AID. EMV AID not found");
|
||||
return 2;
|
||||
dreturn(2);
|
||||
}
|
||||
|
||||
// Select
|
||||
|
@ -412,7 +423,7 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
|
||||
if (res) {
|
||||
PrintAndLog("Can't select AID (%d). Exit...", res);
|
||||
return 3;
|
||||
dreturn(3);
|
||||
}
|
||||
|
||||
if (decodeTLV)
|
||||
|
@ -422,25 +433,30 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
PrintAndLog("\n* Init transaction parameters.");
|
||||
|
||||
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
|
||||
char *qVSDC = "\x26\x00\x00\x00";
|
||||
if (GenACGPO) {
|
||||
qVSDC = "\x26\x80\x00\x00";
|
||||
}
|
||||
switch(TrType) {
|
||||
case TT_MSD:
|
||||
TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
|
||||
break;
|
||||
// not standart for contactless. just for test.
|
||||
// not standard for contactless. just for test.
|
||||
case TT_VSDC:
|
||||
TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC
|
||||
break;
|
||||
case TT_QVSDCMCHIP:
|
||||
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
||||
TLV_ADD(0x9F66, qVSDC); // qVSDC
|
||||
break;
|
||||
case TT_CDA:
|
||||
TLV_ADD(0x9F66, "\x86\x80\x00\x00"); // CDA
|
||||
TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled)
|
||||
break;
|
||||
default:
|
||||
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
||||
break;
|
||||
}
|
||||
//9F02:(Amount, Authorised (Numeric)) len:6
|
||||
|
||||
//9F02:(Amount, authorized (Numeric)) len:6
|
||||
TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
|
||||
//9F1A:(Terminal Country Code) len:2
|
||||
TLV_ADD(0x9F1A, "ru");
|
||||
|
@ -459,17 +475,17 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
TLVPrintFromTLV(tlvRoot); // TODO delete!!!
|
||||
|
||||
PrintAndLog("\n* Calc PDOL.");
|
||||
struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
|
||||
pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83);
|
||||
if (!pdol_data_tlv){
|
||||
PrintAndLog("ERROR: can't create PDOL TLV.");
|
||||
return 4;
|
||||
dreturn(4);
|
||||
}
|
||||
|
||||
size_t pdol_data_tlv_data_len;
|
||||
unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len);
|
||||
if (!pdol_data_tlv_data) {
|
||||
PrintAndLog("ERROR: can't create PDOL data.");
|
||||
return 4;
|
||||
dreturn(4);
|
||||
}
|
||||
PrintAndLog("PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len));
|
||||
|
||||
|
@ -477,11 +493,11 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
|
||||
free(pdol_data_tlv_data);
|
||||
free(pdol_data_tlv);
|
||||
//free(pdol_data_tlv); --- free on exit.
|
||||
|
||||
if (res) {
|
||||
PrintAndLog("GPO error(%d): %4x. Exit...", res, sw);
|
||||
return 5;
|
||||
dreturn(5);
|
||||
}
|
||||
|
||||
// process response template format 1 [id:80 2b AIP + x4b AFL] and format 2 [id:77 TLV]
|
||||
|
@ -567,9 +583,23 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
PrintAndLog("");
|
||||
}
|
||||
|
||||
// Build Input list for Offline Data Authentication
|
||||
// EMV 4.3 book3 10.3, page 96
|
||||
if (SFIoffline) {
|
||||
// here will be offline records storing...
|
||||
// dont foget: if (sfi < 11)
|
||||
if (SFI < 11) {
|
||||
const unsigned char *abuf = buf;
|
||||
size_t elmlen = len;
|
||||
struct tlv e;
|
||||
if (tlv_parse_tl(&abuf, &elmlen, &e)) {
|
||||
memcpy(&ODAiList[ODAiListLen], &buf[len - elmlen], elmlen);
|
||||
ODAiListLen += elmlen;
|
||||
} else {
|
||||
PrintAndLog("ERROR SFI[%02x]. Creating input list for Offline Data Authentication error.", SFI);
|
||||
}
|
||||
} else {
|
||||
memcpy(&ODAiList[ODAiListLen], buf, len);
|
||||
ODAiListLen += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -577,6 +607,13 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
break;
|
||||
}
|
||||
|
||||
// copy Input list for Offline Data Authentication
|
||||
if (ODAiListLen) {
|
||||
struct tlvdb *oda = tlvdb_fixed(0x21, ODAiListLen, ODAiList); // not a standard tag
|
||||
tlvdb_add(tlvRoot, oda);
|
||||
PrintAndLog("* Input list for Offline Data Authentication added to TLV. len=%d \n", ODAiListLen);
|
||||
}
|
||||
|
||||
// get AIP
|
||||
const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL);
|
||||
uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100;
|
||||
|
@ -585,13 +622,13 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
// SDA
|
||||
if (AIP & 0x0040) {
|
||||
PrintAndLog("\n* SDA");
|
||||
trSDA(AID, AIDlen, tlvRoot);
|
||||
trSDA(tlvRoot);
|
||||
}
|
||||
|
||||
// DDA
|
||||
if (AIP & 0x0020) {
|
||||
PrintAndLog("\n* DDA");
|
||||
|
||||
trDDA(decodeTLV, tlvRoot);
|
||||
}
|
||||
|
||||
// transaction check
|
||||
|
@ -644,11 +681,11 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
res = EMVGenerateChallenge(true, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
if (res) {
|
||||
PrintAndLog("ERROR GetChallenge. APDU error %4x", sw);
|
||||
return 5;
|
||||
dreturn(6);
|
||||
}
|
||||
if (len < 4) {
|
||||
PrintAndLog("ERROR GetChallenge. Wrong challenge length %d", len);
|
||||
return 5;
|
||||
dreturn(6);
|
||||
}
|
||||
|
||||
// ICC Dynamic Number
|
||||
|
@ -663,7 +700,7 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!cdol_data_tlv){
|
||||
PrintAndLog("ERROR: can't create CDOL1 TLV.");
|
||||
return 4;
|
||||
dreturn(6);
|
||||
}
|
||||
PrintAndLog("CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
|
||||
|
||||
|
@ -671,17 +708,25 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
// EMVAC_TC + EMVAC_CDAREQ --- to get SDAD
|
||||
res = EMVAC(true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
|
||||
free(cdol_data_tlv);
|
||||
|
||||
if (res) {
|
||||
PrintAndLog("AC1 error(%d): %4x. Exit...", res, sw);
|
||||
return 5;
|
||||
dreturn(7);
|
||||
}
|
||||
|
||||
if (decodeTLV)
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
|
||||
PrintAndLog("* M/Chip transaction result:");
|
||||
// CDA
|
||||
PrintAndLog("\n* CDA:");
|
||||
struct tlvdb *ac_tlv = tlvdb_parse_multi(buf, len);
|
||||
res = trCDA(tlvRoot, ac_tlv, pdol_data_tlv, cdol_data_tlv);
|
||||
if (res) {
|
||||
PrintAndLog("CDA error (%d)", res);
|
||||
}
|
||||
free(ac_tlv);
|
||||
free(cdol_data_tlv);
|
||||
|
||||
PrintAndLog("\n* M/Chip transaction result:");
|
||||
// 9F27: Cryptogram Information Data (CID)
|
||||
const struct tlv *CID = tlvdb_get(tlvRoot, 0x9F27, NULL);
|
||||
if (CID) {
|
||||
|
@ -743,7 +788,7 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag
|
||||
if (!udol_data_tlv){
|
||||
PrintAndLog("ERROR: can't create UDOL TLV.");
|
||||
return 4;
|
||||
dreturn(8);
|
||||
}
|
||||
|
||||
PrintAndLog("UDOL data[%d]: %s", udol_data_tlv->len, sprint_hex(udol_data_tlv->value, udol_data_tlv->len));
|
||||
|
@ -753,24 +798,27 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
res = MSCComputeCryptoChecksum(true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot);
|
||||
if (res) {
|
||||
PrintAndLog("ERROR Compute Crypto Checksum. APDU error %4x", sw);
|
||||
return 5;
|
||||
free(udol_data_tlv);
|
||||
dreturn(9);
|
||||
}
|
||||
|
||||
if (decodeTLV) {
|
||||
TLVPrintFromBuffer(buf, len);
|
||||
PrintAndLog("");
|
||||
}
|
||||
free(udol_data_tlv);
|
||||
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("ERROR MSD: Track2 data not found.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// DropField
|
||||
DropField();
|
||||
|
||||
// Destroy TLV's
|
||||
free(pdol_data_tlv);
|
||||
tlvdb_free(tlvSelect);
|
||||
tlvdb_free(tlvRoot);
|
||||
|
||||
|
@ -779,6 +827,10 @@ int CmdHFEMVExec(const char *cmd) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CmdHFEMVTest(const char *cmd) {
|
||||
return ExecuteCryptoTests(true);
|
||||
}
|
||||
|
||||
int CmdHelp(const char *Cmd);
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
|
@ -786,6 +838,7 @@ static command_t CommandTable[] = {
|
|||
{"pse", CmdHFEMVPPSE, 0, "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."},
|
||||
{"search", CmdHFEMVSearch, 0, "Try to select all applets from applets list and print installed applets."},
|
||||
{"select", CmdHFEMVSelect, 0, "Select applet."},
|
||||
{"test", CmdHFEMVTest, 0, "Crypto logic test."},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue