static int sda_test_pk(void) { const struct emv_pk *pk = &vsdc_01; struct tlvdb *db; db = tlvdb_external(0x90, sizeof(issuer_cert), issuer_cert); tlvdb_add(db, tlvdb_external(0x9f32, sizeof(issuer_exp), issuer_exp)); tlvdb_add(db, tlvdb_external(0x92, sizeof(issuer_rem), issuer_rem)); struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db); if (!ipk) { fprintf(stderr, "Could not recover Issuer certificate!\n"); tlvdb_free(db); return 2; } tlvdb_add(db, tlvdb_external(0x93, sizeof(ssad_cr), ssad_cr)); struct tlvdb *dacdb = emv_pki_recover_dac(ipk, db, ssd1, sizeof(ssd1)); if (!dacdb) { fprintf(stderr, "Could not recover DAC!\n"); emv_pk_free(ipk); tlvdb_free(db); return 2; } const struct tlv *dac = tlvdb_get(dacdb, 0x9f45, NULL); if (!dac) { fprintf(stderr, "DAC not found!\n"); tlvdb_free(dacdb); emv_pk_free(ipk); tlvdb_free(db); return 2; } dump_buffer(dac->value, dac->len, stdout); tlvdb_free(dacdb); emv_pk_free(ipk); tlvdb_free(db); return 0; }
static int cda_test_pk(void) { const struct emv_pk *pk = &mchip_05; struct tlvdb *db; db = tlvdb_external(0x90, sizeof(issuer_cert), issuer_cert); tlvdb_add(db, tlvdb_external(0x9f32, sizeof(issuer_exp), issuer_exp)); tlvdb_add(db, tlvdb_external(0x92, sizeof(issuer_rem), issuer_rem)); tlvdb_add(db, tlvdb_external(0x5a, sizeof(pan), pan)); struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db); if (!ipk) { fprintf(stderr, "Could not recover Issuer certificate!\n"); tlvdb_free(db); return 2; } tlvdb_add(db, tlvdb_external(0x9f46, sizeof(icc_cert), icc_cert)); tlvdb_add(db, tlvdb_external(0x9f47, sizeof(icc_exp), icc_exp)); /*tlvdb_add(db, tlvdb_external(0x9f48, sizeof(issuer_rem), issuer_rem));*/ struct emv_pk *iccpk = emv_pki_recover_icc_cert(ipk, db, &ssd1_tlv); if (!iccpk) { fprintf(stderr, "Could not recover ICC certificate!\n"); emv_pk_free(ipk); tlvdb_free(db); return 2; } tlvdb_add(db, tlvdb_fixed(0x9f37, sizeof(dd1), dd1)); struct tlvdb *cda_db; cda_db = tlvdb_fixed(0x9f27, 1, (unsigned char[]){ 0x40 });
struct tlvdb *dol_parse(const struct tlv *tlv, const unsigned char *data, size_t data_len) { if (!tlv) return NULL; const unsigned char *buf = tlv->value; size_t left = tlv->len; size_t res_len = dol_calculate_len(tlv, data_len); size_t pos = 0; struct tlvdb *db = NULL; if (res_len != data_len) return NULL; while (left) { struct tlv cur_tlv; if (!tlv_parse_tl(&buf, &left, &cur_tlv) || pos + cur_tlv.len > res_len) { tlvdb_free(db); return NULL; } /* Last tag can be of variable length */ if (cur_tlv.len == 0 && left == 0) cur_tlv.len = res_len - pos; struct tlvdb *tag_db = tlvdb_fixed(cur_tlv.tag, cur_tlv.len, data + pos); if (!db) db = tag_db; else tlvdb_add(db, tag_db); pos += cur_tlv.len; } return db; }
int main(void) { int i; struct sc *sc; sc = scard_init(NULL); if (!sc) { printf("Cannot init scard\n"); return 1; } scard_connect(sc, openemv_config_get_int("scard.reader", 0)); if (scard_is_error(sc)) { printf("%s\n", scard_error(sc)); return 1; } struct tlvdb *s; struct tlvdb *t; for (i = 0, s = NULL; apps[i].name_len != 0; i++) { const struct tlv aid_tlv = { .len = apps[i].name_len, .value = apps[i].name, }; s = emv_select(sc, &aid_tlv); if (s) break; } if (!s) return 1; struct tlv *pdol_data_tlv = dol_process(tlvdb_get(s, 0x9f38, NULL), s, 0x83); if (!pdol_data_tlv) return 1; t = emv_gpo(sc, pdol_data_tlv); free(pdol_data_tlv); if (!t) return 1; tlvdb_add(s, t); struct tlv *sda_tlv = emv_read_records(sc, s); if (!sda_tlv) return 1; /* Only PTC read should happen before VERIFY */ tlvdb_add(s, emv_get_data(sc, 0x9f17)); verify_offline_clear(s, sc); #define TAG(tag, len, value...) tlvdb_add(s, tlvdb_fixed(tag, len, (unsigned char[]){value})) // TAG(0x9f02, 6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); // TAG(0x9f1a, 2, 0x06, 0x43); TAG(0x95, 5, 0x80, 0x00, 0x00, 0x00, 0x00); // TAG(0x5f2a, 2, 0x06, 0x43); // TAG(0x9a, 3, 0x14, 0x09, 0x25); // TAG(0x9c, 1, 0x50); // TAG(0x9f37, 4, 0x12, 0x34, 0x57, 0x79); TAG(0x9f35, 1, 0x34); TAG(0x9f34, 3, 0x01, 0x00, 0x02); #undef TAG /* Generate ARQC */ struct tlv *crm_tlv = dol_process(tlvdb_get(s, 0x8c, NULL), s, 0); if (!crm_tlv) return 1; t = emv_generate_ac(sc, 0x80, crm_tlv); free(crm_tlv); tlvdb_add(s, t); build_cap(s); #define TAG(tag, len, value...) tlvdb_add(s, tlvdb_fixed(tag, len, (unsigned char[]){value})) TAG(0x8a, 2, 'Z', '3'); #undef TAG /* Generate AC asking for AAC */ crm_tlv = dol_process(tlvdb_get(s, 0x8d, NULL), s, 0); if (!crm_tlv) return 1; t = emv_generate_ac(sc, 0x00, crm_tlv); free(crm_tlv); tlvdb_add(s, t); tlvdb_visit(s, print_cb, NULL); tlvdb_free(s); scard_disconnect(sc); if (scard_is_error(sc)) { printf("%s\n", scard_error(sc)); return 1; } scard_shutdown(sc); return 0; }
bool emv_read_records(struct sc *sc, struct tlvdb *db, unsigned char **pdata, size_t *plen) { *pdata = NULL; *plen = 0; const struct tlv *afl = tlvdb_get(db, 0x94, NULL); if (!afl) return 1; unsigned char *sda_data = NULL; size_t sda_len = 0; int i; for (i = 0; i < afl->len; i += 4) { unsigned char p2 = afl->value[i + 0]; unsigned char first = afl->value[i + 1]; unsigned char last = afl->value[i + 2]; unsigned char sdarec = afl->value[i + 3]; unsigned char sfi = p2 >> 3; if (sfi == 0 || sfi == 31 || first == 0 || first > last) return false; for (; first <= last; first ++) { unsigned short sw; size_t outlen; unsigned char *outbuf; struct tlvdb *t; outbuf = emv_read_record(sc, sfi, first, &sw, &outlen); if (!outbuf) return false; if (sw == 0x9000) { t = tlvdb_parse(outbuf, outlen); if (!t) return false; } else return false; if (sdarec) { const unsigned char *data; size_t data_len; if (sfi < 11) { const struct tlv *e = tlvdb_get(t, 0x70, NULL); if (!e) return false; data = e->value; data_len = e->len; } else { data = outbuf; data_len = outlen; } sda_data = realloc(sda_data, sda_len + data_len); memcpy(sda_data + sda_len, data, data_len); sda_len += data_len; sdarec --; } free(outbuf); tlvdb_add(db, t); } } const struct tlv *sdatl_tlv = tlvdb_get(db, 0x9f4a, NULL); if (sdatl_tlv) { const struct tlv *aip_tlv = tlvdb_get(db, 0x82, NULL); if (sdatl_tlv->len == 1 && sdatl_tlv->value[0] == 0x82 && aip_tlv) { sda_data = realloc(sda_data, sda_len + aip_tlv->len); memcpy(sda_data + sda_len, aip_tlv->value, aip_tlv->len); sda_len += aip_tlv->len; } else { /* Error!! */ free(sda_data); sda_data = NULL; sda_len = 0; } } *pdata = sda_data; *plen = sda_len; return true; }
int main(void) { int i; struct sc *sc; sc = scard_init(NULL); if (!sc) { printf("Cannot init scard\n"); return 1; } scard_connect(sc, 0); if (scard_is_error(sc)) { printf("%s\n", scard_error(sc)); return 1; } struct tlvdb *s; struct tlvdb *t; for (i = 0, s = NULL; apps[i].name_len != 0; i++) { s = emv_select(sc, apps[i].name, apps[i].name_len); if (s) break; } if (!s) return 1; size_t pdol_data_len; unsigned char *pdol_data = dol_process(tlvdb_get(s, 0x9f38, NULL), s, &pdol_data_len); struct tlv pdol_data_tlv = { .tag = 0x83, .len = pdol_data_len, .value = pdol_data }; size_t pdol_data_tlv_data_len; unsigned char *pdol_data_tlv_data = tlv_encode(&pdol_data_tlv, &pdol_data_tlv_data_len); free(pdol_data); if (!pdol_data_tlv_data) return 1; t = emv_gpo(sc, pdol_data_tlv_data, pdol_data_tlv_data_len); free(pdol_data_tlv_data); if (!t) return 1; tlvdb_add(s, t); unsigned char *sda_data = NULL; size_t sda_len = 0; bool ok = emv_read_records(sc, s, &sda_data, &sda_len); if (!ok) return 1; free(sda_data); /* Generate AC asking for AAC */ size_t crm_data_len; unsigned char *crm_data = dol_process(tlvdb_get(s, 0x8c, NULL), s, &crm_data_len); t = emv_generate_ac(sc, 0x00, crm_data, crm_data_len); free(crm_data); tlvdb_add(s, t); tlvdb_add(s, emv_get_data(sc, 0x9f36)); tlvdb_add(s, emv_get_data(sc, 0x9f13)); tlvdb_add(s, emv_get_data(sc, 0x9f17)); tlvdb_add(s, emv_get_data(sc, 0x9f4f)); tlvdb_visit(s, print_cb, NULL); const struct tlv *logent_tlv = tlvdb_get(s, 0x9f4d, NULL); const struct tlv *logent_dol = tlvdb_get(s, 0x9f4f, NULL); if (logent_tlv && logent_tlv->len == 2 && logent_dol) { for (i = 1; i <= logent_tlv->value[1]; i++) { unsigned short sw; size_t log_len; unsigned char *log = emv_read_record(sc, logent_tlv->value[0], i, &sw, &log_len); if (!log) continue; if (sw == 0x9000) { printf("Log #%d\n", i); struct tlvdb *log_db = dol_parse(logent_dol, log, log_len); tlvdb_visit(log_db, print_cb, NULL); tlvdb_free(log_db); } free(log); } } tlvdb_free(s); scard_disconnect(sc); if (scard_is_error(sc)) { printf("%s\n", scard_error(sc)); return 1; } scard_shutdown(sc); return 0; }