mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-14 18:48:13 -07:00
client: fix mix of spaces & tabs
This commit is contained in:
parent
112411042f
commit
0d9223a547
197 changed files with 49383 additions and 49383 deletions
|
@ -29,7 +29,7 @@
|
|||
|
||||
static bool strictExecution = true;
|
||||
void PKISetStrictExecution(bool se) {
|
||||
strictExecution = se;
|
||||
strictExecution = se;
|
||||
}
|
||||
|
||||
static const unsigned char empty_tlv_value[] = {};
|
||||
|
@ -38,551 +38,551 @@ 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;
|
||||
size_t data_len;
|
||||
va_list vl;
|
||||
struct crypto_pk *kcp;
|
||||
unsigned char *data;
|
||||
size_t data_len;
|
||||
va_list vl;
|
||||
|
||||
if (!enc_pk)
|
||||
return NULL;
|
||||
if (!enc_pk)
|
||||
return NULL;
|
||||
|
||||
if (!cert_tlv) {
|
||||
printf("ERROR: Can't find certificate\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!cert_tlv) {
|
||||
printf("ERROR: Can't find certificate\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cert_tlv->len != enc_pk->mlen) {
|
||||
printf("ERROR: Certificate length (%zu) not equal key length (%zu)\n", cert_tlv->len, enc_pk->mlen);
|
||||
return NULL;
|
||||
}
|
||||
kcp = crypto_pk_open(enc_pk->pk_algo,
|
||||
enc_pk->modulus, enc_pk->mlen,
|
||||
enc_pk->exp, enc_pk->elen);
|
||||
if (!kcp)
|
||||
return NULL;
|
||||
if (cert_tlv->len != enc_pk->mlen) {
|
||||
printf("ERROR: Certificate length (%zu) not equal key length (%zu)\n", cert_tlv->len, enc_pk->mlen);
|
||||
return NULL;
|
||||
}
|
||||
kcp = crypto_pk_open(enc_pk->pk_algo,
|
||||
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);
|
||||
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) {
|
||||
printf("ERROR: Certificate format\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
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){
|
||||
printf("ERROR: Cant get hash position in the certificate\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
size_t hash_pos = emv_pki_hash_psn[msgtype];
|
||||
if (hash_pos == 0 || hash_pos > data_len){
|
||||
printf("ERROR: Cant get hash position in the certificate\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(data[hash_pos]);
|
||||
if (!ch) {
|
||||
printf("ERROR: Cant do hash\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(data[hash_pos]);
|
||||
if (!ch) {
|
||||
printf("ERROR: Cant do hash\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t hash_len = crypto_hash_get_size(ch);
|
||||
crypto_hash_write(ch, data + 1, data_len - 2 - hash_len);
|
||||
size_t hash_len = crypto_hash_get_size(ch);
|
||||
crypto_hash_write(ch, data + 1, data_len - 2 - hash_len);
|
||||
|
||||
va_start(vl, tlv_count);
|
||||
for (int i = 0; i < tlv_count; i++) {
|
||||
const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
|
||||
if (!add_tlv)
|
||||
continue;
|
||||
va_start(vl, tlv_count);
|
||||
for (int i = 0; i < tlv_count; i++) {
|
||||
const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
|
||||
if (!add_tlv)
|
||||
continue;
|
||||
|
||||
crypto_hash_write(ch, add_tlv->value, add_tlv->len);
|
||||
}
|
||||
va_end(vl);
|
||||
crypto_hash_write(ch, add_tlv->value, add_tlv->len);
|
||||
}
|
||||
va_end(vl);
|
||||
|
||||
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("decoded: %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len));
|
||||
printf("calculated: %s\n",sprint_hex(hash, 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("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);
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (strictExecution) {
|
||||
crypto_hash_close(ch);
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
crypto_hash_close(ch);
|
||||
crypto_hash_close(ch);
|
||||
|
||||
*len = data_len - hash_len - 1;
|
||||
*len = data_len - hash_len - 1;
|
||||
|
||||
return data;
|
||||
return data;
|
||||
}
|
||||
|
||||
static unsigned emv_cn_length(const struct tlv *tlv)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < tlv->len; i++) {
|
||||
unsigned char c = tlv->value[i];
|
||||
for (i = 0; i < tlv->len; i++) {
|
||||
unsigned char c = tlv->value[i];
|
||||
|
||||
if (c >> 4 == 0xf)
|
||||
return 2 * i;
|
||||
if (c >> 4 == 0xf)
|
||||
return 2 * i;
|
||||
|
||||
if ((c & 0xf) == 0xf)
|
||||
return 2 * i + 1;
|
||||
}
|
||||
if ((c & 0xf) == 0xf)
|
||||
return 2 * i + 1;
|
||||
}
|
||||
|
||||
return 2 * tlv->len;
|
||||
return 2 * tlv->len;
|
||||
}
|
||||
|
||||
static unsigned char emv_cn_get(const struct tlv *tlv, unsigned pos)
|
||||
{
|
||||
if (pos > tlv->len * 2)
|
||||
return 0xf;
|
||||
if (pos > tlv->len * 2)
|
||||
return 0xf;
|
||||
|
||||
unsigned char c = tlv->value[pos / 2];
|
||||
unsigned char c = tlv->value[pos / 2];
|
||||
|
||||
if (pos % 2)
|
||||
return c & 0xf;
|
||||
else
|
||||
return c >> 4;
|
||||
if (pos % 2)
|
||||
return c & 0xf;
|
||||
else
|
||||
return c >> 4;
|
||||
}
|
||||
|
||||
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;
|
||||
size_t data_len;
|
||||
size_t pk_len;
|
||||
size_t pan_length;
|
||||
unsigned char *data;
|
||||
size_t data_len;
|
||||
size_t pk_len;
|
||||
|
||||
if (!cert_tlv || !exp_tlv || !pan_tlv)
|
||||
return NULL;
|
||||
if (!cert_tlv || !exp_tlv || !pan_tlv)
|
||||
return NULL;
|
||||
|
||||
if (!rem_tlv)
|
||||
rem_tlv = &empty_tlv;
|
||||
if (!rem_tlv)
|
||||
rem_tlv = &empty_tlv;
|
||||
|
||||
if (msgtype == 2)
|
||||
pan_length = 4;
|
||||
else if (msgtype == 4)
|
||||
pan_length = 10;
|
||||
else {
|
||||
printf("ERROR: Message type must be 2 or 4\n");
|
||||
return NULL;
|
||||
}
|
||||
if (msgtype == 2)
|
||||
pan_length = 4;
|
||||
else if (msgtype == 4)
|
||||
pan_length = 10;
|
||||
else {
|
||||
printf("ERROR: Message type must be 2 or 4\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = emv_pki_decode_message(enc_pk, msgtype, &data_len,
|
||||
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;
|
||||
}
|
||||
data = emv_pki_decode_message(enc_pk, msgtype, &data_len,
|
||||
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){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
||||
/* Perform the rest of checks here */
|
||||
/* Perform the rest of checks here */
|
||||
|
||||
struct tlv pan2_tlv = {
|
||||
.tag = 0x5a,
|
||||
.len = pan_length,
|
||||
.value = &data[2],
|
||||
};
|
||||
unsigned pan_len = emv_cn_length(pan_tlv);
|
||||
unsigned pan2_len = emv_cn_length(&pan2_tlv);
|
||||
struct tlv pan2_tlv = {
|
||||
.tag = 0x5a,
|
||||
.len = pan_length,
|
||||
.value = &data[2],
|
||||
};
|
||||
unsigned pan_len = emv_cn_length(pan_tlv);
|
||||
unsigned pan2_len = emv_cn_length(&pan2_tlv);
|
||||
|
||||
if (((msgtype == 2) && (pan2_len < 4 || pan2_len > pan_len)) ||
|
||||
((msgtype == 4) && (pan2_len != pan_len))) {
|
||||
printf("ERROR: Invalid PAN lengths\n");
|
||||
free(data);
|
||||
if (((msgtype == 2) && (pan2_len < 4 || pan2_len > pan_len)) ||
|
||||
((msgtype == 4) && (pan2_len != pan_len))) {
|
||||
printf("ERROR: Invalid PAN lengths\n");
|
||||
free(data);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < pan2_len; i++)
|
||||
if (emv_cn_get(pan_tlv, i) != emv_cn_get(&pan2_tlv, i)) {
|
||||
printf("ERROR: PAN data mismatch\n");
|
||||
printf("tlv pan=%s\n", sprint_hex(pan_tlv->value, pan_tlv->len));
|
||||
printf("cert pan=%s\n", sprint_hex(pan2_tlv.value, pan2_tlv.len));
|
||||
free(data);
|
||||
unsigned i;
|
||||
for (i = 0; i < pan2_len; i++)
|
||||
if (emv_cn_get(pan_tlv, i) != emv_cn_get(&pan2_tlv, i)) {
|
||||
printf("ERROR: PAN data mismatch\n");
|
||||
printf("tlv pan=%s\n", sprint_hex(pan_tlv->value, pan_tlv->len));
|
||||
printf("cert pan=%s\n", sprint_hex(pan2_tlv.value, pan2_tlv.len));
|
||||
free(data);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pk_len = data[9 + pan_length];
|
||||
if (pk_len > data_len - 11 - pan_length + rem_tlv->len) {
|
||||
printf("ERROR: Invalid pk length\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
pk_len = data[9 + pan_length];
|
||||
if (pk_len > data_len - 11 - pan_length + rem_tlv->len) {
|
||||
printf("ERROR: Invalid pk length\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (exp_tlv->len != data[10 + pan_length]) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
if (exp_tlv->len != data[10 + pan_length]) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct emv_pk *pk = emv_pk_new(pk_len, exp_tlv->len);
|
||||
struct emv_pk *pk = emv_pk_new(pk_len, exp_tlv->len);
|
||||
|
||||
memcpy(pk->rid, enc_pk->rid, 5);
|
||||
pk->index = enc_pk->index;
|
||||
memcpy(pk->rid, enc_pk->rid, 5);
|
||||
pk->index = enc_pk->index;
|
||||
|
||||
pk->hash_algo = data[7 + pan_length];
|
||||
pk->pk_algo = data[8 + pan_length];
|
||||
pk->expire = (data[3 + pan_length] << 16) | (data[2 + pan_length] << 8) | 0x31;
|
||||
memcpy(pk->serial, data + 4 + pan_length, 3);
|
||||
memcpy(pk->pan, data + 2, pan_length);
|
||||
memset(pk->pan + pan_length, 0xff, 10 - pan_length);
|
||||
pk->hash_algo = data[7 + pan_length];
|
||||
pk->pk_algo = data[8 + pan_length];
|
||||
pk->expire = (data[3 + pan_length] << 16) | (data[2 + pan_length] << 8) | 0x31;
|
||||
memcpy(pk->serial, data + 4 + pan_length, 3);
|
||||
memcpy(pk->pan, data + 2, pan_length);
|
||||
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));
|
||||
memcpy(pk->modulus + data_len - (11 + pan_length), rem_tlv->value, rem_tlv->len);
|
||||
memcpy(pk->exp, exp_tlv->value, exp_tlv->len);
|
||||
memcpy(pk->modulus, data + 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);
|
||||
|
||||
free(data);
|
||||
free(data);
|
||||
|
||||
return pk;
|
||||
return 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
|
||||
) {
|
||||
return emv_pki_decode_key_ex(enc_pk, msgtype, pan_tlv, cert_tlv, exp_tlv, rem_tlv, add_tlv, sdatl_tlv, false);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv)
|
||||
{
|
||||
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
|
||||
};
|
||||
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, 0x9f46, NULL),
|
||||
tlvdb_get(db, 0x9f47, NULL),
|
||||
tlvdb_get(db, 0x9f48, NULL),
|
||||
sda_tlv,
|
||||
&sda_tdata);
|
||||
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);
|
||||
|
||||
free(sdatl); // malloc here: emv_pki_sdatl_fill
|
||||
return res;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
unsigned char *emv_pki_sdatl_fill(const struct tlvdb *db, size_t *sdatl_len) {
|
||||
uint8_t buf[2048] = {0};
|
||||
size_t len = 0;
|
||||
uint8_t buf[2048] = {0};
|
||||
size_t len = 0;
|
||||
|
||||
*sdatl_len = 0;
|
||||
*sdatl_len = 0;
|
||||
|
||||
const struct tlv *sda_tl = tlvdb_get(db, 0x9f4a, NULL);
|
||||
if (!sda_tl || sda_tl->len <= 0)
|
||||
return NULL;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (len) {
|
||||
*sdatl_len = len;
|
||||
unsigned char *value = malloc(len);
|
||||
memcpy(value, buf, len);
|
||||
return value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
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)
|
||||
{
|
||||
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
|
||||
};
|
||||
// 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,
|
||||
tlvdb_get(db, 0x93, NULL),
|
||||
3,
|
||||
sda_tlv,
|
||||
&sda_tdata,
|
||||
NULL);
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 3, &data_len,
|
||||
tlvdb_get(db, 0x93, NULL),
|
||||
3,
|
||||
sda_tlv,
|
||||
&sda_tdata,
|
||||
NULL);
|
||||
|
||||
free(sdatl); // malloc here: emv_pki_sdatl_fill
|
||||
free(sdatl); // malloc here: emv_pki_sdatl_fill
|
||||
|
||||
if (!data || data_len < 5)
|
||||
return NULL;
|
||||
if (!data || data_len < 5)
|
||||
return NULL;
|
||||
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
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);
|
||||
free(data);
|
||||
|
||||
return dac_db;
|
||||
return dac_db;
|
||||
}
|
||||
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);
|
||||
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) {
|
||||
return emv_pki_recover_idn_ex(enc_pk, db, dyn_tlv, false);
|
||||
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;
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||
tlvdb_get(db, 0x9f4b, NULL),
|
||||
2,
|
||||
dyn_tlv,
|
||||
NULL);
|
||||
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);
|
||||
|
||||
if (!data || data_len < 3)
|
||||
return NULL;
|
||||
if (!data || data_len < 3)
|
||||
return NULL;
|
||||
|
||||
if (data[3] < 2 || data[3] > data_len - 3) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
if (data[3] < 2 || data[3] > data_len - 3) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
||||
size_t idn_len = data[4];
|
||||
if (idn_len > data[3] - 1) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
size_t idn_len = data[4];
|
||||
if (idn_len > data[3] - 1) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 9f4c ICC Dynamic Number
|
||||
struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
|
||||
// 9f4c ICC Dynamic Number
|
||||
struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
|
||||
|
||||
free(data);
|
||||
free(data);
|
||||
|
||||
return idn_db;
|
||||
return idn_db;
|
||||
}
|
||||
|
||||
struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, bool showData)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
|
||||
if (!data || data_len < 3)
|
||||
return NULL;
|
||||
if (!data || data_len < 3)
|
||||
return NULL;
|
||||
|
||||
if (data[3] < 2 || data[3] > data_len - 3) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
if (data[3] < 2 || data[3] > data_len - 3) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
||||
size_t idn_len = data[4];
|
||||
if (idn_len > data[3] - 1) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
size_t idn_len = data[4];
|
||||
if (idn_len > data[3] - 1) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 9f36 Application Transaction Counter (ATC)
|
||||
struct tlvdb *atc_db = tlvdb_fixed(0x9f36, idn_len, data + 5);
|
||||
// 9f36 Application Transaction Counter (ATC)
|
||||
struct tlvdb *atc_db = tlvdb_fixed(0x9f36, idn_len, data + 5);
|
||||
|
||||
free(data);
|
||||
free(data);
|
||||
|
||||
return atc_db;
|
||||
return atc_db;
|
||||
}
|
||||
|
||||
static bool tlv_hash(void *data, const struct tlv *tlv, int level, bool is_leaf)
|
||||
{
|
||||
struct crypto_hash *ch = data;
|
||||
size_t tag_len;
|
||||
unsigned char *tag;
|
||||
struct crypto_hash *ch = data;
|
||||
size_t tag_len;
|
||||
unsigned char *tag;
|
||||
|
||||
if (tlv_is_constructed(tlv))
|
||||
return true;
|
||||
if (tlv_is_constructed(tlv))
|
||||
return true;
|
||||
|
||||
if (tlv->tag == 0x9f4b)
|
||||
return true;
|
||||
if (tlv->tag == 0x9f4b)
|
||||
return true;
|
||||
|
||||
tag = tlv_encode(tlv, &tag_len);
|
||||
crypto_hash_write(ch, tag, tag_len);
|
||||
free(tag);
|
||||
tag = tlv_encode(tlv, &tag_len);
|
||||
crypto_hash_write(ch, tag, tag_len);
|
||||
free(tag);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
const struct tlv *un_tlv = tlvdb_get(db, 0x9f37, NULL);
|
||||
const struct tlv *cid_tlv = tlvdb_get(this_db, 0x9f27, NULL);
|
||||
|
||||
if (!un_tlv || !cid_tlv)
|
||||
return NULL;
|
||||
if (!un_tlv || !cid_tlv)
|
||||
return NULL;
|
||||
|
||||
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);
|
||||
if (!data || data_len < 3) {
|
||||
printf("ERROR: can't decode message. len %zu\n", data_len);
|
||||
return NULL;
|
||||
}
|
||||
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);
|
||||
if (!data || data_len < 3) {
|
||||
printf("ERROR: can't decode message. len %zu\n", data_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
||||
if (data[3] < 30 || data[3] > data_len - 4) {
|
||||
printf("ERROR: Invalid data length\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
if (data[3] < 30 || data[3] > data_len - 4) {
|
||||
printf("ERROR: Invalid data length\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!cid_tlv || cid_tlv->len != 1 || cid_tlv->value[0] != data[5 + data[4]]) {
|
||||
printf("ERROR: CID mismatch\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
if (!cid_tlv || cid_tlv->len != 1 || cid_tlv->value[0] != data[5 + data[4]]) {
|
||||
printf("ERROR: CID mismatch\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(enc_pk->hash_algo);
|
||||
if (!ch) {
|
||||
printf("ERROR: can't create hash\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(enc_pk->hash_algo);
|
||||
if (!ch) {
|
||||
printf("ERROR: can't create hash\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pdol_data_tlv)
|
||||
crypto_hash_write(ch, pdol_data_tlv->value, pdol_data_tlv->len);
|
||||
if (crm1_tlv)
|
||||
crypto_hash_write(ch, crm1_tlv->value, crm1_tlv->len);
|
||||
if (crm2_tlv)
|
||||
crypto_hash_write(ch, crm2_tlv->value, crm2_tlv->len);
|
||||
if (pdol_data_tlv)
|
||||
crypto_hash_write(ch, pdol_data_tlv->value, pdol_data_tlv->len);
|
||||
if (crm1_tlv)
|
||||
crypto_hash_write(ch, crm1_tlv->value, crm1_tlv->len);
|
||||
if (crm2_tlv)
|
||||
crypto_hash_write(ch, crm2_tlv->value, crm2_tlv->len);
|
||||
|
||||
tlvdb_visit(this_db, tlv_hash, ch, 0);
|
||||
tlvdb_visit(this_db, tlv_hash, ch, 0);
|
||||
|
||||
if (memcmp(data + 5 + data[4] + 1 + 8, crypto_hash_read(ch), 20)) {
|
||||
printf("ERROR: calculated hash error\n");
|
||||
crypto_hash_close(ch);
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
crypto_hash_close(ch);
|
||||
if (memcmp(data + 5 + data[4] + 1 + 8, crypto_hash_read(ch), 20)) {
|
||||
printf("ERROR: calculated hash error\n");
|
||||
crypto_hash_close(ch);
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
crypto_hash_close(ch);
|
||||
|
||||
size_t idn_len = data[4];
|
||||
if (idn_len > data[3] - 1) {
|
||||
printf("ERROR: Invalid IDN length\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
size_t idn_len = data[4];
|
||||
if (idn_len > data[3] - 1) {
|
||||
printf("ERROR: Invalid IDN length\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
|
||||
free(data);
|
||||
struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
|
||||
free(data);
|
||||
|
||||
return idn_db;
|
||||
return idn_db;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue