mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
commit
7eb3e79d83
7 changed files with 220 additions and 41 deletions
|
@ -38,6 +38,9 @@ void ParamLoadDefaults(struct tlvdb *tlvRoot) {
|
||||||
TLV_ADD(0x9F6A, "\x01\x02\x03\x04");
|
TLV_ADD(0x9F6A, "\x01\x02\x03\x04");
|
||||||
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
|
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
|
||||||
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
|
||||||
|
//95:(Terminal Verification Results) len:5
|
||||||
|
// all OK TVR
|
||||||
|
TLV_ADD(0x95, "\x00\x00\x00\x00\x00");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintChannel(EMVCommandChannel channel) {
|
void PrintChannel(EMVCommandChannel channel) {
|
||||||
|
@ -685,6 +688,50 @@ void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProcessACResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, bool decodeTLV) {
|
||||||
|
if (buf[0] == 0x80) {
|
||||||
|
if (decodeTLV){
|
||||||
|
PrintAndLog("GPO response format1:");
|
||||||
|
TLVPrintFromBuffer(buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t elmlen = len - 2; // wo 0x80XX
|
||||||
|
|
||||||
|
if (len < 4 + 2 || (elmlen - 2) % 4 || elmlen != buf[1]) {
|
||||||
|
PrintAndLogEx(ERR, "GPO response format1 parsing error. length=%d", len);
|
||||||
|
} else {
|
||||||
|
struct tlvdb *tlvElm = NULL;
|
||||||
|
if (decodeTLV)
|
||||||
|
PrintAndLog("\n------------ Format1 decoded ------------");
|
||||||
|
|
||||||
|
// CID (Cryptogram Information Data)
|
||||||
|
tlvdb_change_or_add_node_ex(tlvRoot, 0x9f27, 1, &buf[2], &tlvElm);
|
||||||
|
if (decodeTLV)
|
||||||
|
TLVPrintFromTLV(tlvElm);
|
||||||
|
|
||||||
|
// ATC (Application Transaction Counter)
|
||||||
|
tlvdb_change_or_add_node_ex(tlvRoot, 0x9f36, 2, &buf[3], &tlvElm);
|
||||||
|
if (decodeTLV)
|
||||||
|
TLVPrintFromTLV(tlvElm);
|
||||||
|
|
||||||
|
// AC (Application Cryptogram)
|
||||||
|
tlvdb_change_or_add_node_ex(tlvRoot, 0x9f26, min(8, elmlen - 3), &buf[5], &tlvElm);
|
||||||
|
if (decodeTLV)
|
||||||
|
TLVPrintFromTLV(tlvElm);
|
||||||
|
|
||||||
|
// IAD (Issuer Application Data) - optional
|
||||||
|
if (len > 11 + 2) {
|
||||||
|
tlvdb_change_or_add_node_ex(tlvRoot, 0x9f10, elmlen - 11, &buf[13], &tlvElm);
|
||||||
|
if (decodeTLV)
|
||||||
|
TLVPrintFromTLV(tlvElm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (decodeTLV)
|
||||||
|
TLVPrintFromBuffer(buf, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int CmdEMVExec(const char *cmd) {
|
int CmdEMVExec(const char *cmd) {
|
||||||
uint8_t buf[APDU_RES_LEN] = {0};
|
uint8_t buf[APDU_RES_LEN] = {0};
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
@ -731,9 +778,9 @@ int CmdEMVExec(const char *cmd) {
|
||||||
|
|
||||||
enum TransactionType TrType = TT_MSD;
|
enum TransactionType TrType = TT_MSD;
|
||||||
if (arg_get_lit(7))
|
if (arg_get_lit(7))
|
||||||
TrType = TT_QVSDCMCHIP;
|
TrType = TT_QVSDCMCHIP;
|
||||||
if (arg_get_lit(8))
|
if (arg_get_lit(8))
|
||||||
TrType = TT_CDA;
|
TrType = TT_CDA;
|
||||||
if (arg_get_lit(9))
|
if (arg_get_lit(9))
|
||||||
TrType = TT_VSDC;
|
TrType = TT_VSDC;
|
||||||
|
|
||||||
|
@ -870,7 +917,7 @@ int CmdEMVExec(const char *cmd) {
|
||||||
uint8_t SFIend = AFL->value[i * 4 + 2];
|
uint8_t SFIend = AFL->value[i * 4 + 2];
|
||||||
uint8_t SFIoffline = AFL->value[i * 4 + 3];
|
uint8_t SFIoffline = AFL->value[i * 4 + 3];
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline);
|
PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline count:%02x", SFI, SFIstart, SFIend, SFIoffline);
|
||||||
if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) {
|
if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) {
|
||||||
PrintAndLogEx(NORMAL, "SFI ERROR! Skipped...");
|
PrintAndLogEx(NORMAL, "SFI ERROR! Skipped...");
|
||||||
continue;
|
continue;
|
||||||
|
@ -892,7 +939,7 @@ int CmdEMVExec(const char *cmd) {
|
||||||
|
|
||||||
// Build Input list for Offline Data Authentication
|
// Build Input list for Offline Data Authentication
|
||||||
// EMV 4.3 book3 10.3, page 96
|
// EMV 4.3 book3 10.3, page 96
|
||||||
if (SFIoffline) {
|
if (SFIoffline > 0) {
|
||||||
if (SFI < 11) {
|
if (SFI < 11) {
|
||||||
const unsigned char *abuf = buf;
|
const unsigned char *abuf = buf;
|
||||||
size_t elmlen = len;
|
size_t elmlen = len;
|
||||||
|
@ -907,6 +954,8 @@ int CmdEMVExec(const char *cmd) {
|
||||||
memcpy(&ODAiList[ODAiListLen], buf, len);
|
memcpy(&ODAiList[ODAiListLen], buf, len);
|
||||||
ODAiListLen += len;
|
ODAiListLen += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SFIoffline--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1128,6 +1177,41 @@ int CmdEMVExec(const char *cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VSDC
|
||||||
|
if (GetCardPSVendor(AID, AIDlen) == CV_VISA && (TrType == TT_VSDC || TrType == TT_CDA)){
|
||||||
|
PrintAndLogEx(NORMAL, "\n--> VSDC transaction.");
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "* * Calc CDOL1");
|
||||||
|
struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag
|
||||||
|
if (!cdol_data_tlv) {
|
||||||
|
PrintAndLogEx(WARNING, "Error: can't create CDOL1 TLV.");
|
||||||
|
dreturn(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len));
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "* * AC1");
|
||||||
|
// EMVAC_TC + EMVAC_CDAREQ --- to get SDAD
|
||||||
|
res = EMVAC(channel, 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);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
PrintAndLogEx(NORMAL, "AC1 error(%d): %4x. Exit...", res, sw);
|
||||||
|
dreturn(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// process Format1 (0x80) anf print Format2 (0x77)
|
||||||
|
ProcessACResponseFormat1(tlvRoot, buf, len, decodeTLV);
|
||||||
|
|
||||||
|
PrintAndLogEx(NORMAL, "\n* * Processing online request\n");
|
||||||
|
|
||||||
|
// authorization response code from acquirer
|
||||||
|
const char HostResponse[] = "00"; // 0x3030
|
||||||
|
PrintAndLogEx(NORMAL, "* * Host Response: `%s`", HostResponse);
|
||||||
|
tlvdb_change_or_add_node(tlvRoot, 0x8a, sizeof(HostResponse) - 1, (const unsigned char *)HostResponse);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
|
|
||||||
// Destroy TLV's
|
// Destroy TLV's
|
||||||
|
|
|
@ -41,7 +41,8 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
|
||||||
uint8_t msgtype,
|
uint8_t msgtype,
|
||||||
size_t *len,
|
size_t *len,
|
||||||
const struct tlv *cert_tlv,
|
const struct tlv *cert_tlv,
|
||||||
... /* A list of tlv pointers, end with NULL */
|
int tlv_count,
|
||||||
|
... /* A list of tlv pointers */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
struct crypto_pk *kcp;
|
struct crypto_pk *kcp;
|
||||||
|
@ -99,20 +100,23 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
|
||||||
size_t hash_len = crypto_hash_get_size(ch);
|
size_t hash_len = crypto_hash_get_size(ch);
|
||||||
crypto_hash_write(ch, data + 1, data_len - 2 - hash_len);
|
crypto_hash_write(ch, data + 1, data_len - 2 - hash_len);
|
||||||
|
|
||||||
va_start(vl, cert_tlv);
|
va_start(vl, tlv_count);
|
||||||
while (true) {
|
for (int i = 0; i < tlv_count; i++) {
|
||||||
const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
|
const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
|
||||||
if (!add_tlv)
|
if (!add_tlv)
|
||||||
break;
|
continue;
|
||||||
|
|
||||||
crypto_hash_write(ch, add_tlv->value, add_tlv->len);
|
crypto_hash_write(ch, add_tlv->value, add_tlv->len);
|
||||||
}
|
}
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
|
|
||||||
if (memcmp(data + data_len - 1 - hash_len, crypto_hash_read(ch), hash_len)) {
|
uint8_t hash[hash_len];
|
||||||
|
memset(hash, 0, hash_len);
|
||||||
|
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("ERROR: Calculated wrong hash\n");
|
||||||
printf("decoded: %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len));
|
printf("decoded: %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len));
|
||||||
printf("calculated: %s\n",sprint_hex(crypto_hash_read(ch), hash_len));
|
printf("calculated: %s\n",sprint_hex(hash, hash_len));
|
||||||
|
|
||||||
if (strictExecution) {
|
if (strictExecution) {
|
||||||
crypto_hash_close(ch);
|
crypto_hash_close(ch);
|
||||||
|
@ -165,6 +169,7 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
|
||||||
const struct tlv *exp_tlv,
|
const struct tlv *exp_tlv,
|
||||||
const struct tlv *rem_tlv,
|
const struct tlv *rem_tlv,
|
||||||
const struct tlv *add_tlv,
|
const struct tlv *add_tlv,
|
||||||
|
const struct tlv *sdatl_tlv,
|
||||||
bool showData
|
bool showData
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -190,9 +195,11 @@ 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,
|
data = emv_pki_decode_message(enc_pk, msgtype, &data_len,
|
||||||
cert_tlv,
|
cert_tlv,
|
||||||
|
5,
|
||||||
rem_tlv,
|
rem_tlv,
|
||||||
exp_tlv,
|
exp_tlv,
|
||||||
add_tlv,
|
add_tlv,
|
||||||
|
sdatl_tlv,
|
||||||
NULL);
|
NULL);
|
||||||
if (!data || data_len < 11 + pan_length) {
|
if (!data || data_len < 11 + pan_length) {
|
||||||
printf("ERROR: Can't decode message\n");
|
printf("ERROR: Can't decode message\n");
|
||||||
|
@ -275,9 +282,10 @@ static struct emv_pk *emv_pki_decode_key(const struct emv_pk *enc_pk,
|
||||||
const struct tlv *cert_tlv,
|
const struct tlv *cert_tlv,
|
||||||
const struct tlv *exp_tlv,
|
const struct tlv *exp_tlv,
|
||||||
const struct tlv *rem_tlv,
|
const struct tlv *rem_tlv,
|
||||||
const struct tlv *add_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, false);
|
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)
|
struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db)
|
||||||
|
@ -287,17 +295,30 @@ struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb
|
||||||
tlvdb_get(db, 0x90, NULL),
|
tlvdb_get(db, 0x90, NULL),
|
||||||
tlvdb_get(db, 0x9f32, NULL),
|
tlvdb_get(db, 0x9f32, NULL),
|
||||||
tlvdb_get(db, 0x92, NULL),
|
tlvdb_get(db, 0x92, NULL),
|
||||||
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv)
|
struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv)
|
||||||
{
|
{
|
||||||
return emv_pki_decode_key(pk, 4,
|
size_t sdatl_len;
|
||||||
|
unsigned char *sdatl = emv_pki_sdatl_fill(db, &sdatl_len);
|
||||||
|
struct tlv sda_tdata = {
|
||||||
|
.tag = 0x00, // dummy tag
|
||||||
|
.len = sdatl_len,
|
||||||
|
.value = sdatl
|
||||||
|
};
|
||||||
|
|
||||||
|
struct emv_pk *res = emv_pki_decode_key(pk, 4,
|
||||||
tlvdb_get(db, 0x5a, NULL),
|
tlvdb_get(db, 0x5a, NULL),
|
||||||
tlvdb_get(db, 0x9f46, NULL),
|
tlvdb_get(db, 0x9f46, NULL),
|
||||||
tlvdb_get(db, 0x9f47, NULL),
|
tlvdb_get(db, 0x9f47, NULL),
|
||||||
tlvdb_get(db, 0x9f48, NULL),
|
tlvdb_get(db, 0x9f48, NULL),
|
||||||
sda_tlv);
|
sda_tlv,
|
||||||
|
&sda_tdata);
|
||||||
|
|
||||||
|
free(sdatl); // malloc here: emv_pki_sdatl_fill
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db)
|
struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db)
|
||||||
|
@ -307,17 +328,62 @@ struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb
|
||||||
tlvdb_get(db, 0x9f2d, NULL),
|
tlvdb_get(db, 0x9f2d, NULL),
|
||||||
tlvdb_get(db, 0x9f2e, NULL),
|
tlvdb_get(db, 0x9f2e, NULL),
|
||||||
tlvdb_get(db, 0x9f2f, NULL),
|
tlvdb_get(db, 0x9f2f, NULL),
|
||||||
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned char *emv_pki_sdatl_fill(const struct tlvdb *db, size_t *sdatl_len) {
|
||||||
|
uint8_t buf[2048] = {0};
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
*sdatl_len = 0;
|
||||||
|
|
||||||
|
const struct tlv *sda_tl = tlvdb_get(db, 0x9f4a, NULL);
|
||||||
|
if (!sda_tl || sda_tl->len <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (int i = 0; i < sda_tl->len; i++) {
|
||||||
|
uint32_t tag = sda_tl->value[i]; // here may be multibyte, but now not
|
||||||
|
const struct tlv *elm = tlvdb_get(db, tag, NULL);
|
||||||
|
if (elm) {
|
||||||
|
memcpy(&buf[len], elm->value, elm->len);
|
||||||
|
len += elm->len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len) {
|
||||||
|
*sdatl_len = len;
|
||||||
|
unsigned char *value = malloc(len);
|
||||||
|
memcpy(value, buf, len);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData)
|
struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData)
|
||||||
{
|
{
|
||||||
size_t data_len;
|
size_t data_len;
|
||||||
|
|
||||||
|
// Static Data Authentication Tag List
|
||||||
|
size_t sdatl_len;
|
||||||
|
unsigned char *sdatl = emv_pki_sdatl_fill(db, &sdatl_len);
|
||||||
|
struct tlv sda_tdata = {
|
||||||
|
.tag = 0x00, // dummy tag
|
||||||
|
.len = sdatl_len,
|
||||||
|
.value = sdatl
|
||||||
|
};
|
||||||
|
|
||||||
unsigned char *data = emv_pki_decode_message(enc_pk, 3, &data_len,
|
unsigned char *data = emv_pki_decode_message(enc_pk, 3, &data_len,
|
||||||
tlvdb_get(db, 0x93, NULL),
|
tlvdb_get(db, 0x93, NULL),
|
||||||
|
3,
|
||||||
sda_tlv,
|
sda_tlv,
|
||||||
|
&sda_tdata,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
free(sdatl); // malloc here: emv_pki_sdatl_fill
|
||||||
|
|
||||||
if (!data || data_len < 5)
|
if (!data || data_len < 5)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -345,6 +411,7 @@ struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct t
|
||||||
size_t data_len;
|
size_t data_len;
|
||||||
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||||
tlvdb_get(db, 0x9f4b, NULL),
|
tlvdb_get(db, 0x9f4b, NULL),
|
||||||
|
2,
|
||||||
dyn_tlv,
|
dyn_tlv,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
@ -380,6 +447,7 @@ struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct t
|
||||||
size_t data_len;
|
size_t data_len;
|
||||||
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||||
tlvdb_get(db, 0x9f4b, NULL),
|
tlvdb_get(db, 0x9f4b, NULL),
|
||||||
|
5,
|
||||||
tlvdb_get(db, 0x9f37, NULL),
|
tlvdb_get(db, 0x9f37, NULL),
|
||||||
tlvdb_get(db, 0x9f02, NULL),
|
tlvdb_get(db, 0x9f02, NULL),
|
||||||
tlvdb_get(db, 0x5f2a, NULL),
|
tlvdb_get(db, 0x5f2a, NULL),
|
||||||
|
@ -456,6 +524,7 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t
|
||||||
size_t data_len = 0;
|
size_t data_len = 0;
|
||||||
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||||
tlvdb_get(this_db, 0x9f4b, NULL),
|
tlvdb_get(this_db, 0x9f4b, NULL),
|
||||||
|
2,
|
||||||
un_tlv,
|
un_tlv,
|
||||||
NULL);
|
NULL);
|
||||||
if (!data || data_len < 3) {
|
if (!data || data_len < 3) {
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
extern void PKISetStrictExecution(bool se);
|
extern void PKISetStrictExecution(bool se);
|
||||||
|
|
||||||
|
unsigned char *emv_pki_sdatl_fill(const struct tlvdb *db, size_t *sdatl_len);
|
||||||
struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db);
|
struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db);
|
||||||
struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv);
|
struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv);
|
||||||
struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db);
|
struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db);
|
||||||
|
|
|
@ -596,7 +596,7 @@ int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *
|
||||||
}
|
}
|
||||||
|
|
||||||
int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
int EMVInternalAuthenticate(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 EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
|
return EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, true, Result, MaxResultLen, ResultLen, sw, tlv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
|
int MSCComputeCryptoChecksum(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) {
|
||||||
|
@ -653,7 +653,7 @@ int trSDA(struct tlvdb *tlv) {
|
||||||
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
||||||
if (dac_db) {
|
if (dac_db) {
|
||||||
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
|
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
|
||||||
PrintAndLogEx(NORMAL, "SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
|
PrintAndLogEx(NORMAL, "SDA verified OK. (Data Authentication Code: %02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
|
||||||
tlvdb_add(tlv, dac_db);
|
tlvdb_add(tlv, dac_db);
|
||||||
} else {
|
} else {
|
||||||
emv_pk_free(issuer_pk);
|
emv_pk_free(issuer_pk);
|
||||||
|
@ -682,12 +682,12 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
|
const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
|
||||||
if (!sda_tlv || sda_tlv->len < 1) {
|
/* if (!sda_tlv || sda_tlv->len < 1) { it may be 0!!!!
|
||||||
emv_pk_free(pk);
|
emv_pk_free(pk);
|
||||||
PrintAndLogEx(WARNING, "Error: Can't find input list for Offline Data Authentication. Exit.");
|
PrintAndLogEx(WARNING, "Error: Can't find input list for Offline Data Authentication. Exit.");
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
|
struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
|
||||||
if (!issuer_pk) {
|
if (!issuer_pk) {
|
||||||
emv_pk_free(pk);
|
emv_pk_free(pk);
|
||||||
|
@ -710,7 +710,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
||||||
if (!icc_pk) {
|
if (!icc_pk) {
|
||||||
emv_pk_free(pk);
|
emv_pk_free(pk);
|
||||||
emv_pk_free(issuer_pk);
|
emv_pk_free(issuer_pk);
|
||||||
PrintAndLogEx(WARNING, "Error: ICC setrificate not found. Exit.");
|
PrintAndLogEx(WARNING, "Error: ICC certificate not found. Exit.");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
|
PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
|
||||||
|
@ -725,21 +725,25 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
||||||
icc_pk->serial[2]
|
icc_pk->serial[2]
|
||||||
);
|
);
|
||||||
|
|
||||||
struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv);
|
if (tlvdb_get(tlv, 0x9f2d, NULL)) {
|
||||||
if (!icc_pe_pk) {
|
struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv);
|
||||||
PrintAndLogEx(WARNING, "WARNING: ICC PE PK recover error. ");
|
if (!icc_pe_pk) {
|
||||||
|
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]
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(SUCCESS, "ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
|
PrintAndLogEx(INFO, "ICC PE PK (PIN Encipherment Public Key Certificate) not found.\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]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 9F4B: Signed Dynamic Application Data
|
// 9F4B: Signed Dynamic Application Data
|
||||||
|
@ -781,7 +785,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
||||||
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
||||||
if (dac_db) {
|
if (dac_db) {
|
||||||
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
|
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
|
||||||
PrintAndLogEx(NORMAL, "SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
|
PrintAndLogEx(NORMAL, "SDAD verified OK. (Data Authentication Code: %02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
|
||||||
tlvdb_add(tlv, dac_db);
|
tlvdb_add(tlv, dac_db);
|
||||||
} else {
|
} else {
|
||||||
PrintAndLogEx(WARNING, "Error: SSAD verify error");
|
PrintAndLogEx(WARNING, "Error: SSAD verify error");
|
||||||
|
@ -825,9 +829,16 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
|
||||||
if (len < 3 ) {
|
if (len < 3 ) {
|
||||||
PrintAndLogEx(WARNING, "Error: Internal Authenticate format1 parsing error. length=%d", len);
|
PrintAndLogEx(WARNING, "Error: Internal Authenticate format1 parsing error. length=%d", len);
|
||||||
} else {
|
} else {
|
||||||
|
// parse response 0x80
|
||||||
|
struct tlvdb *t80 = tlvdb_parse_multi(buf, len);
|
||||||
|
const struct tlv * t80tlv = tlvdb_get_tlv(t80);
|
||||||
|
|
||||||
// 9f4b Signed Dynamic Application Data
|
// 9f4b Signed Dynamic Application Data
|
||||||
dda_db = tlvdb_fixed(0x9f4b, len - 2, buf + 2);
|
dda_db = tlvdb_fixed(0x9f4b, t80tlv->len, t80tlv->value);
|
||||||
tlvdb_add(tlv, dda_db);
|
tlvdb_add(tlv, dda_db);
|
||||||
|
|
||||||
|
tlvdb_free(t80);
|
||||||
|
|
||||||
if (decodeTLV){
|
if (decodeTLV){
|
||||||
PrintAndLogEx(NORMAL, "* * Decode response format 1:");
|
PrintAndLogEx(NORMAL, "* * Decode response format 1:");
|
||||||
TLVPrintFromTLV(dda_db);
|
TLVPrintFromTLV(dda_db);
|
||||||
|
|
|
@ -359,12 +359,15 @@ void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other)
|
||||||
tlvdb->next = other;
|
tlvdb->next = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value)
|
void tlvdb_change_or_add_node_ex(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value, struct tlvdb **tlvdb_elm)
|
||||||
{
|
{
|
||||||
struct tlvdb *telm = tlvdb_find_full(tlvdb, tag);
|
struct tlvdb *telm = tlvdb_find_full(tlvdb, tag);
|
||||||
if (telm == NULL) {
|
if (telm == NULL) {
|
||||||
// new tlv element
|
// new tlv element
|
||||||
tlvdb_add(tlvdb, tlvdb_fixed(tag, len, value));
|
struct tlvdb *elm = tlvdb_fixed(tag, len, value);
|
||||||
|
tlvdb_add(tlvdb, elm);
|
||||||
|
if (tlvdb_elm)
|
||||||
|
*tlvdb_elm = elm;
|
||||||
} else {
|
} else {
|
||||||
// the same tlv structure
|
// the same tlv structure
|
||||||
if (telm->tag.tag == tag && telm->tag.len == len && !memcmp(telm->tag.value, value, len))
|
if (telm->tag.tag == tag && telm->tag.len == len && !memcmp(telm->tag.value, value, len))
|
||||||
|
@ -400,11 +403,19 @@ void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, co
|
||||||
// free old element with childrens
|
// free old element with childrens
|
||||||
telm->next = NULL;
|
telm->next = NULL;
|
||||||
tlvdb_free(telm);
|
tlvdb_free(telm);
|
||||||
|
|
||||||
|
if (tlvdb_elm)
|
||||||
|
*tlvdb_elm = tnewelm;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value)
|
||||||
|
{
|
||||||
|
tlvdb_change_or_add_node_ex(tlvdb, tag, len, value, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level)
|
void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level)
|
||||||
{
|
{
|
||||||
struct tlvdb *next = NULL;
|
struct tlvdb *next = NULL;
|
||||||
|
|
|
@ -50,6 +50,7 @@ struct tlvdb *tlvdb_find_path(struct tlvdb *tlvdb, tlv_tag_t tag[]);
|
||||||
|
|
||||||
void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other);
|
void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other);
|
||||||
void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value);
|
void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value);
|
||||||
|
void tlvdb_change_or_add_node_ex(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value, struct tlvdb **tlvdb_elm);
|
||||||
|
|
||||||
void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level);
|
void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level);
|
||||||
const struct tlv *tlvdb_get(const struct tlvdb *tlvdb, tlv_tag_t tag, const struct tlv *prev);
|
const struct tlv *tlvdb_get(const struct tlvdb *tlvdb, tlv_tag_t tag, const struct tlv *prev);
|
||||||
|
|
10
common/i2c.c
10
common/i2c.c
|
@ -161,10 +161,11 @@ bool WaitSCL_L(void) {
|
||||||
return WaitSCL_L_delay(15000);
|
return WaitSCL_L_delay(15000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait max 300ms or until SCL goes LOW.
|
// Wait max 1800ms or until SCL goes LOW.
|
||||||
|
// It timeout reading response from card
|
||||||
// Which ever comes first
|
// Which ever comes first
|
||||||
bool WaitSCL_L_300ms(void){
|
bool WaitSCL_L_timeout(void){
|
||||||
volatile uint16_t delay = 310;
|
volatile uint16_t delay = 1800;
|
||||||
while ( delay-- ) {
|
while ( delay-- ) {
|
||||||
// exit on SCL LOW
|
// exit on SCL LOW
|
||||||
if (!SCL_read)
|
if (!SCL_read)
|
||||||
|
@ -193,7 +194,8 @@ bool I2C_Start(void) {
|
||||||
|
|
||||||
bool I2C_WaitForSim() {
|
bool I2C_WaitForSim() {
|
||||||
|
|
||||||
if (!WaitSCL_L_300ms())
|
// wait for data from card
|
||||||
|
if (!WaitSCL_L_timeout())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// 8051 speaks with smart card.
|
// 8051 speaks with smart card.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue