Esempio n. 1
0
static void build_cap(struct tlvdb *db)
{
	const struct tlv *ipb = tlvdb_get(db, 0x9f56, NULL);

	ipb_dol_value[sizeof(ipb_dol_value) - 1] = ipb->len - (1 + 1 + 2 + 8);

	struct tlv *ipb_data_tlv = dol_process(&ipb_dol, db, 0);
	if (!ipb_data_tlv)
		return;

	dump_buffer(ipb_data_tlv->value, ipb_data_tlv->len, stdout);
	dump_buffer(ipb->value, ipb->len, stdout);
	if (ipb_data_tlv->len < ipb->len) {
		free(ipb_data_tlv);
		return;
	}

	unsigned char buf[ipb->len];
	int i, j, k = 0;
	unsigned char c = 0;
	for (i = ipb->len; i > 0; i--) {
		for (j = 0; j < 8; j++) {
			if ((ipb->value[i-1] & (1 << j)) == 0)
				continue;

			c |= ((ipb_data_tlv->value[i-1] >> j) & 1) << (k % 8);
			k++;

			if (k % 8 != 0)
				continue;

			buf[k / 8 - 1] = c;
			c = 0;
		}
	}
	free(ipb_data_tlv);

	if (k % 8 != 0) {
		k += 8 - (k % 8);
		buf[k / 8 - 1] = c;
	}

	k /= 8;

	unsigned long data = 0;
	for (i = 0; i < k; i++)
		data |= ((unsigned long) buf[i]) << (8 * i);
	dump_buffer(buf, k, stdout);

	fprintf(stdout, "CAP data: %lu\n", data);
}
Esempio n. 2
0
struct tlv *dol_process(const struct tlv *tlv, const struct tlvdb *tlvdb, tlv_tag_t tag)
{
	size_t res_len;
	if (!tlv || !(res_len = dol_calculate_len(tlv, 0))) {
		struct tlv *res_tlv = malloc(sizeof(*res_tlv));

		res_tlv->tag = tag;
		res_tlv->len = 0;
		res_tlv->value = NULL;

		return res_tlv;
	}

	struct tlv *res_tlv = malloc(sizeof(*res_tlv) + res_len);
	if (!res_tlv)
		return NULL;

	const unsigned char *buf = tlv->value;
	size_t left = tlv->len;
	unsigned char *res = (unsigned char *)(res_tlv + 1);
	size_t pos = 0;

	while (left) {
		struct tlv cur_tlv;
		if (!tlv_parse_tl(&buf, &left, &cur_tlv) || pos + cur_tlv.len > res_len) {
			free(res_tlv);

			return NULL;
		}

		const struct tlv *tag_tlv = tlvdb_get(tlvdb, cur_tlv.tag, NULL);
		if (!tag_tlv) {
			memset(res + pos, 0, cur_tlv.len);
		} else if (tag_tlv->len > cur_tlv.len) {
			memcpy(res + pos, tag_tlv->value, cur_tlv.len);
		} else {
			// FIXME: cn data should be padded with 0xFF !!!
			memcpy(res + pos, tag_tlv->value, tag_tlv->len);
			memset(res + pos + tag_tlv->len, 0, cur_tlv.len - tag_tlv->len);
		}
		pos += cur_tlv.len;
	}

	res_tlv->tag = tag;
	res_tlv->len = res_len;
	res_tlv->value = res;

	return res_tlv;
}
Esempio n. 3
0
unsigned char *dol_process(const struct tlv *tlv, const struct tlvdb *tlvdb, size_t *len)
{
	if (!tlv) {
		*len = 0;
		return NULL;
	}

	const unsigned char *buf = tlv->value;
	size_t left = tlv->len;
	size_t res_len = dol_calculate_len(tlv, 0);
	unsigned char *res;
	size_t pos = 0;

	if (!res_len) {
		*len = 0;
		return NULL;
	}

	res = malloc(res_len);

	while (left) {
		struct tlv cur_tlv;
		if (!tlv_parse_tl(&buf, &left, &cur_tlv) || pos + cur_tlv.len > res_len) {
			free(res);
			return NULL;
		}

		const struct tlv *tag_tlv = tlvdb_get(tlvdb, cur_tlv.tag, NULL);
		if (!tag_tlv) {
			memset(res + pos, 0, cur_tlv.len);
		} else if (tag_tlv->len > cur_tlv.len) {
			memcpy(res + pos, tag_tlv->value, cur_tlv.len);
		} else {
			// FIXME: cn data should be padded with 0xFF !!!
			memcpy(res + pos, tag_tlv->value, tag_tlv->len);
			memset(res + pos + tag_tlv->len, 0, cur_tlv.len - tag_tlv->len);
		}
		pos += cur_tlv.len;
	}

	*len = pos;

	return res;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
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;
}
Esempio n. 7
0
static struct emu_df *read_df(FILE *f, struct sc *sc, const unsigned char *name, size_t name_len)
{
	struct emu_df *df;
	int i, j;
	struct tlvdb *s;
	unsigned short sw;
	size_t outlen;
	unsigned char *outbuf;
	struct tlv pdol_data_tlv;
	size_t pdol_data_len;
	unsigned char *pdol_data;

	outbuf = sc_command(sc, 0x00, 0xa4, 0x04, 0x00, name_len, name, &sw, &outlen);
	if (sw != 0x9000)
		return NULL;

	s = tlvdb_parse(outbuf, outlen);
	if (!s)
		return NULL;

	df = emu_df_new();

	pdol_data_tlv.tag = 0x83;
	pdol_data_tlv.value = dol_process(tlvdb_get(s, 0x9f38, NULL), s, &pdol_data_tlv.len);
	pdol_data = tlv_encode(&pdol_data_tlv, &pdol_data_len);
	if (!pdol_data)
		return NULL;
	free((unsigned char *)pdol_data_tlv.value);

	tlvdb_free(s);

	emu_df_append(df, emu_property_new("name", emu_value_new_buf(name, name_len)));

	emu_df_append(df, emu_property_new("fci", emu_value_new_buf(outbuf, outlen)));
	free(outbuf);

	outbuf = sc_command(sc, 0x80, 0xa8, 0x00, 0x00, pdol_data_len, pdol_data, &sw, &outlen);
	free(pdol_data);
	if (sw == 0x9000) {
		emu_df_append(df, emu_property_new("gpo", emu_value_new_buf(outbuf, outlen)));
		free(outbuf);
	}

	for (i = 1; i < 31; i++) {
		int last = 0;
		struct emu_value *value = NULL;
		char buf[7];

		snprintf(buf, sizeof(buf), "sfi%d", i);

		for (j = 1; j < 256; j++) {
			outbuf = sc_command(sc, 0x00, 0xb2, j, (i << 3) | 4, 0, NULL, &sw, &outlen);
			if (sw == 0x6985)
				continue;
			else if (sw != 0x9000)
				break;

			for (; last < j - 1; last++)
				value = emu_value_append(value, "");

			value = emu_value_append_buf(value, outbuf, outlen);
			last ++;
			free(outbuf);
		}
		if (value)
			emu_df_append(df, emu_property_new(buf, value));
	}

	for (i = 0; card_data[i]; i++) {
		char buf[10];
		tlv_tag_t tag = card_data[i];
		outbuf = sc_command(sc, 0x80, 0xca, tag >> 8, tag & 0xff, 0, NULL, &sw, &outlen);
		if (sw != 0x9000)
			continue;

		snprintf(buf, sizeof(buf), "data%x", tag);
		emu_df_append(df, emu_property_new(buf, emu_value_new_buf(outbuf, outlen)));
		free(outbuf);
	}

	return df;
}
Esempio n. 8
0
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;
}