mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-22 14:13:42 -07:00
SDA, DDA, fDDA works
This commit is contained in:
parent
cd52522a35
commit
5419c606c1
3 changed files with 66 additions and 30 deletions
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "emv_pki.h"
|
#include "emv_pki.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
|
#include "dump.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -49,7 +50,7 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (cert_tlv->len != enc_pk->mlen) {
|
if (cert_tlv->len != enc_pk->mlen) {
|
||||||
printf("Certificate length (%d) not equal key length (%d)", cert_tlv->len, enc_pk->mlen);
|
printf("ERROR: Certificate length (%d) not equal key length (%d)\n", cert_tlv->len, enc_pk->mlen);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
kcp = crypto_pk_open(enc_pk->pk_algo,
|
kcp = crypto_pk_open(enc_pk->pk_algo,
|
||||||
|
@ -62,12 +63,14 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
|
||||||
crypto_pk_close(kcp);
|
crypto_pk_close(kcp);
|
||||||
|
|
||||||
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);
|
free(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t hash_pos = emv_pki_hash_psn[msgtype];
|
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);
|
free(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -75,6 +78,7 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
|
||||||
struct crypto_hash *ch;
|
struct crypto_hash *ch;
|
||||||
ch = crypto_hash_open(data[hash_pos]);
|
ch = crypto_hash_open(data[hash_pos]);
|
||||||
if (!ch) {
|
if (!ch) {
|
||||||
|
printf("ERROR: Cant do hash\n");
|
||||||
free(data);
|
free(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -93,6 +97,7 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
|
|
||||||
if (memcmp(data + data_len - 1 - hash_len, crypto_hash_read(ch), hash_len)) {
|
if (memcmp(data + data_len - 1 - hash_len, crypto_hash_read(ch), hash_len)) {
|
||||||
|
printf("ERROR: Calculated wrong hash\n");
|
||||||
crypto_hash_close(ch);
|
crypto_hash_close(ch);
|
||||||
free(data);
|
free(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -279,7 +284,11 @@ struct tlvdb *emv_pki_recover_dac(const struct emv_pk *enc_pk, const struct tlvd
|
||||||
return dac_db;
|
return dac_db;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData)
|
||||||
{
|
{
|
||||||
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,
|
||||||
|
@ -303,6 +312,12 @@ struct tlvdb *emv_pki_recover_idn(const struct emv_pk *enc_pk, const struct tlvd
|
||||||
|
|
||||||
// 9f4c ICC Dynamic Number
|
// 9f4c ICC Dynamic Number
|
||||||
struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
|
struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
|
||||||
|
|
||||||
|
if (showData){
|
||||||
|
printf("Recovered data:\n");
|
||||||
|
dump_buffer(data, data_len, stdout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
return idn_db;
|
return idn_db;
|
||||||
|
|
|
@ -27,6 +27,7 @@ struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb
|
||||||
|
|
||||||
struct tlvdb *emv_pki_recover_dac(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *sda_tlv);
|
struct tlvdb *emv_pki_recover_dac(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *sda_tlv);
|
||||||
struct tlvdb *emv_pki_recover_idn(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv);
|
struct tlvdb *emv_pki_recover_idn(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv);
|
||||||
|
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_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||||
const struct tlvdb *this_db,
|
const struct tlvdb *this_db,
|
||||||
const struct tlv *pdol_data_tlv,
|
const struct tlv *pdol_data_tlv,
|
||||||
|
|
|
@ -532,6 +532,14 @@ int trSDA(struct tlvdb *tlv) {
|
||||||
static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04};
|
static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04};
|
||||||
static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value };
|
static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value };
|
||||||
|
|
||||||
|
static const unsigned char default_fdda_ddol_value[] =
|
||||||
|
{0x9f, 0x37, 0x04,
|
||||||
|
0x9f, 0x02, 0x06,
|
||||||
|
0x5f, 0x2A, 0x02,
|
||||||
|
0x9f, 0x69, 0x07, // 9f69[07] Card Authentication Related Data
|
||||||
|
};
|
||||||
|
static struct tlv default_fdda_ddol_tlv = {.tag = 0x9f49, .len = 12, .value = default_fdda_ddol_value };
|
||||||
|
|
||||||
int trDDA(bool decodeTLV, struct tlvdb *tlv) {
|
int trDDA(bool decodeTLV, struct tlvdb *tlv) {
|
||||||
uint8_t buf[APDU_RES_LEN] = {0};
|
uint8_t buf[APDU_RES_LEN] = {0};
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
@ -600,40 +608,51 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
|
||||||
if (dac_db) {
|
|
||||||
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
|
|
||||||
printf("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
|
|
||||||
tlvdb_add(tlv, dac_db);
|
|
||||||
} else {
|
|
||||||
PrintAndLog("ERROR: SSAD verify error");
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLog("\n* Calc DDOL");
|
|
||||||
const struct tlv *ddol_tlv = tlvdb_get(tlv, 0x9f49, NULL);
|
|
||||||
if (!ddol_tlv) {
|
|
||||||
ddol_tlv = &default_ddol_tlv;
|
|
||||||
PrintAndLog("DDOL [9f49] not found. Using default DDOL");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct tlv *ddol_data_tlv = dol_process(ddol_tlv, tlv, 0);
|
|
||||||
if (!ddol_data_tlv) {
|
|
||||||
PrintAndLog("ERROR: Can't create DDOL TLV");
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLog("DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len));
|
|
||||||
|
|
||||||
struct tlvdb *dda_db = NULL;
|
struct tlvdb *dda_db = NULL;
|
||||||
|
struct tlv *ddol_data_tlv = NULL;
|
||||||
// 9F4B: Signed Dynamic Application Data
|
// 9F4B: Signed Dynamic Application Data
|
||||||
const struct tlv *sdad_tlv = tlvdb_get(tlv, 0x9f4b, NULL);
|
const struct tlv *sdad_tlv = tlvdb_get(tlv, 0x9f4b, NULL);
|
||||||
// DDA with internal authenticate OR fDDA with filled 0x9F4B tag (GPO result)
|
// DDA with internal authenticate OR fDDA with filled 0x9F4B tag (GPO result)
|
||||||
// EMV kernel3 v2.4, contactless book C-3, C.1., page 147
|
// EMV kernel3 v2.4, contactless book C-3, C.1., page 147
|
||||||
if (sdad_tlv) {
|
if (sdad_tlv) {
|
||||||
PrintAndLog("\n* * * * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA...");
|
PrintAndLog("\n* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA...");
|
||||||
dda_db = tlv;
|
dda_db = tlv;
|
||||||
|
|
||||||
|
PrintAndLog("\n* Calc fDDA hash");
|
||||||
|
ddol_data_tlv = dol_process(&default_fdda_ddol_tlv, tlv, 0);
|
||||||
|
if (!ddol_data_tlv) {
|
||||||
|
PrintAndLog("ERROR: Can't create fDDA hash TLV");
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLog("fDDA hash data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
|
||||||
|
if (dac_db) {
|
||||||
|
const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
|
||||||
|
printf("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
|
||||||
|
tlvdb_add(tlv, dac_db);
|
||||||
|
} else {
|
||||||
|
PrintAndLog("ERROR: SSAD verify error");
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLog("\n* Calc DDOL");
|
||||||
|
const struct tlv *ddol_tlv = tlvdb_get(tlv, 0x9f49, NULL);
|
||||||
|
if (!ddol_tlv) {
|
||||||
|
ddol_tlv = &default_ddol_tlv;
|
||||||
|
PrintAndLog("DDOL [9f49] not found. Using default DDOL");
|
||||||
|
}
|
||||||
|
|
||||||
|
ddol_data_tlv = dol_process(ddol_tlv, tlv, 0);
|
||||||
|
if (!ddol_data_tlv) {
|
||||||
|
PrintAndLog("ERROR: Can't create DDOL TLV");
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLog("DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len));
|
||||||
|
|
||||||
PrintAndLog("\n* Internal Authenticate");
|
PrintAndLog("\n* Internal Authenticate");
|
||||||
int res = EMVInternalAuthenticate(true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL);
|
int res = EMVInternalAuthenticate(true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL);
|
||||||
if (res) {
|
if (res) {
|
||||||
|
@ -666,7 +685,7 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tlvdb *idn_db = emv_pki_recover_idn(icc_pk, dda_db, ddol_data_tlv);
|
struct tlvdb *idn_db = emv_pki_recover_idn_ex(icc_pk, dda_db, ddol_data_tlv, true);
|
||||||
free(ddol_data_tlv);
|
free(ddol_data_tlv);
|
||||||
if (!idn_db) {
|
if (!idn_db) {
|
||||||
PrintAndLog("ERROR: Can't recover IDN (ICC Dynamic Number)");
|
PrintAndLog("ERROR: Can't recover IDN (ICC Dynamic Number)");
|
||||||
|
@ -678,7 +697,8 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) {
|
||||||
// 9f4c ICC Dynamic Number
|
// 9f4c ICC Dynamic Number
|
||||||
const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
|
const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
|
||||||
if(idn_tlv) {
|
if(idn_tlv) {
|
||||||
PrintAndLog("\nDDA verified OK. IDN (ICC Dynamic Number) %zu bytes long\n", idn_tlv->len);
|
PrintAndLog("\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
|
||||||
|
PrintAndLog("DDA verified OK.");
|
||||||
tlvdb_add(tlv, idn_db);
|
tlvdb_add(tlv, idn_db);
|
||||||
tlvdb_free(idn_db);
|
tlvdb_free(idn_db);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue