Exemplo n.º 1
0
static int do_get_data(int argc, char **argv)
{
	unsigned char buffer[256];
	unsigned int tag;
	FILE *fp;
	int r;

	if (argc != 1 && argc != 2)
		return usage(do_get_data);

	tag = strtoul(argv[0], NULL, 16);
	r = sc_get_data(card, tag, buffer, sizeof(buffer));
	if (r < 0) {
		printf("Failed to get data object: %s\n", sc_strerror(r));
		return -1;
	}

	if (argc == 2) {
		const char	*filename = argv[1];

		if (!(fp = fopen(filename, "w"))) {
			perror(filename);
			return -1;
		}
		fwrite(buffer, r, 1, fp);
		fclose(fp);
	} else {
		printf("Object %04x:\n", tag & 0xFFFF);
		util_hex_dump_asc(stdout, buffer, r, 0);
	}

	return 0;
}
Exemplo n.º 2
0
static int read_and_util_print_binary_file(sc_file_t *file)
{
	unsigned int idx = 0;
	u8 buf[128];
	size_t count;
	int r;

	count = file->size;
	while (count) {
		int c = count > sizeof(buf) ? sizeof(buf) : count;

		r = sc_read_binary(card, idx, buf, c, 0);
		if (r < 0) {
			check_ret(r, SC_AC_OP_READ, "read failed", file);
			return -1;
		}
		if ((r != c) && (card->type != SC_CARD_TYPE_BELPIC_EID)) {
			printf("expecting %d, got only %d bytes.\n", c, r);
			return -1;
		}
		if ((r == 0) && (card->type == SC_CARD_TYPE_BELPIC_EID))
			break;
		util_hex_dump_asc(stdout, buf, r, idx);
		idx += r;
		count -= r;
	}
	return 0;
}
Exemplo n.º 3
0
static int read_and_util_print_binary_file(sc_file_t *file)
{
	unsigned char *buf = NULL;
	int r;
	size_t size;

	if (file->size) {
		size = file->size;
	} else {
		size = 1024;
	}
	buf = malloc(size);
	if (!buf)
		return -1;

	r = sc_read_binary(card, 0, buf, size, 0);
	if (r < 0)   {
		check_ret(r, SC_AC_OP_READ, "read failed", file);
		return -1;
	}
	if ((r == 0) && (card->type == SC_CARD_TYPE_BELPIC_EID))
		return -1;

	util_hex_dump_asc(stdout, buf, r, 0);

	free(buf);
	return 0;
}
Exemplo n.º 4
0
static int
do_random(int argc, char **argv)
{
	unsigned char buffer[128];
	int r, count;

	if (argc != 1)
		goto usage;

	count = atoi(argv[0]);
	if (count < 0 || count > 128) {
		printf("Number must be in range 0..128\n");
		return -1;
	}

	r = sc_get_challenge(card, buffer, count);
	if (r < 0) {
		printf("Failed to get random bytes: %s\n", sc_strerror(r));
		return -1;
	}

	util_hex_dump_asc(stdout, buffer, count, 0);
	return 0;

usage:
	printf("Usage: random count\n");
	return -1;
}
Exemplo n.º 5
0
static int do_dump_do(sc_card_t *card, unsigned int tag)
{
	int r;
	size_t length;
	unsigned char buffer[254];	// Private DO are specified up to 254 bytes

	memset(buffer, '\0', sizeof(buffer));

	if (tag < 0x101 || tag > 0x104) {
		util_error("illegal DO identifier %04X", tag);
		return SC_ERROR_INVALID_ARGUMENTS;
	}

	r = sc_get_data(card, tag, buffer, sizeof(buffer));
	if (r < 0) {
		util_error("failed to get data object DO %04X: %s", tag, sc_strerror(r));
		if (SC_ERROR_SECURITY_STATUS_NOT_SATISFIED == r) {
			util_error("make sure the 'verify' and 'pin' parameters are correct");
		}
		return r;
	}
	length = (size_t) r;	/* r is guaranteed to be non-negative */

	if (opt_raw) {
		int tmp;
		FILE *fp;

#ifndef _WIN32
		tmp = dup(fileno(stdout));
#else
		tmp = _dup(_fileno(stdout));
#endif
		if (tmp < 0)
			return EXIT_FAILURE;
		fp = freopen(NULL, "wb", stdout);
		if (fp) {
			r = (int) fwrite(buffer, sizeof(char), length, fp);
		}
#ifndef _WIN32
		dup2(tmp, fileno(stdout));
#else
		_dup2(tmp, _fileno(stdout));
#endif
		clearerr(stdout);
		close(tmp);

		if (length != (size_t) r)	/* fail on write errors */
			return EXIT_FAILURE;
	} else {
		util_hex_dump_asc(stdout, buffer, length, -1);
	}

	return EXIT_SUCCESS;
}
Exemplo n.º 6
0
static int do_apdu(int argc, char **argv)
{
	sc_apdu_t apdu;
	u8 buf[SC_MAX_APDU_BUFFER_SIZE * 2];
	u8 rbuf[SC_MAX_APDU_BUFFER_SIZE * 2];
	size_t len, i;
	int r;

	if (argc < 1)
		return usage(do_apdu);

	for (i = 0, len = 0; i < (unsigned) argc; i++)   {
		size_t len0 = strlen(argv[i]);

		if ((r = parse_string_or_hexdata(argv[i], buf + len, &len0)) < 0) {
			fprintf(stderr, "error parsing %s: %s\n", argv[i], sc_strerror(r));
			return r;
		};
		len += len0;
	}

	r = sc_bytes2apdu(card->ctx, buf, len, &apdu);
	if (r) {
		fprintf(stderr, "Invalid APDU: %s\n", sc_strerror(r));
		return 2;
	}

	apdu.resp = rbuf;
	apdu.resplen = sizeof(rbuf);

	printf("Sending: ");
	util_hex_dump(stdout, buf, len, " ");
	printf("\n");
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n", sc_strerror(r));
		return 1;
	}
	printf("Received (SW1=0x%02X, SW2=0x%02X)%s\n", apdu.sw1, apdu.sw2,
	       apdu.resplen ? ":" : "");
	if (apdu.resplen)
		util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);

	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
	if (r)
		printf("Failure: %s\n", sc_strerror(r));
	else
		printf("Success!\n");

	return 0;
}
Exemplo n.º 7
0
static int do_dump_do(sc_card_t *card, unsigned int tag)
{
	int r, tmp;
	FILE *fp;

	// Private DO are specified up to 254 bytes
	unsigned char buffer[254];
	memset(buffer, '\0', sizeof(buffer));

	r = sc_get_data(card, tag, buffer, sizeof(buffer));
	if (r < 0) {
		printf("Failed to get data object: %s\n", sc_strerror(r));
		if(SC_ERROR_SECURITY_STATUS_NOT_SATISFIED == r) {
			printf("Make sure the 'verify' and 'pin' parameters are correct.\n");
		}
		return r;
	}

	if(opt_raw) {
		r = 0;
		#ifndef _WIN32
		tmp = dup(fileno(stdout));
		#else
		tmp = _dup(_fileno(stdout));
		#endif
		if (tmp < 0)
			return EXIT_FAILURE;
		fp = freopen(NULL, "wb", stdout);
		if (fp) {
			r = (int)fwrite(buffer, sizeof(char), sizeof(buffer), fp);
		}
		#ifndef _WIN32
		dup2(tmp, fileno(stdout));
		#else
		_dup2(tmp, _fileno(stdout));
		#endif
		clearerr(stdout);
		close(tmp);
		if (sizeof(buffer) != r)
			return EXIT_FAILURE;
	} else {
		util_hex_dump_asc(stdout, buffer, sizeof(buffer), -1);
	}

	return EXIT_SUCCESS;
}
Exemplo n.º 8
0
static int read_and_print_record_file(sc_file_t *file, unsigned char sfi)
{
	u8 buf[256];
	int rec, r;

	for (rec = 1; ; rec++) {
		r = sc_read_record(card, rec, buf, sizeof(buf),
			SC_RECORD_BY_REC_NR | sfi);
		if (r == SC_ERROR_RECORD_NOT_FOUND)
			return 0;
		if (r < 0) {
			check_ret(r, SC_AC_OP_READ, "read failed", file);
			return -1;
		}
		printf("Record %d:\n", rec);
		util_hex_dump_asc(stdout, buf, r, 0);
	}
}
Exemplo n.º 9
0
static int do_apdu(int argc, char **argv)
{
	sc_apdu_t apdu;
	u8 buf[SC_MAX_APDU_BUFFER_SIZE];
	u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
	size_t len, len0, r, ii;

	if (argc < 1) {
		puts("Usage: apdu [apdu:hex:codes:...]");
		return -1;
	}

	for (ii = 0, len = 0; ii < (unsigned) argc; ii++)   {
		len0 = strlen(argv[ii]);
		sc_hex_to_bin(argv[ii], buf + len, &len0);
		len += len0;
	}

	r = sc_bytes2apdu(card->ctx, buf, len, &apdu);
	if (r) {
		fprintf(stderr, "Invalid APDU: %s\n", sc_strerror(r));
		return 2;
	}

	apdu.resp = rbuf;
	apdu.resplen = sizeof(rbuf);

	printf("Sending: ");
	for (r = 0; r < len0; r++)
		printf("%02X ", buf[r]);
	printf("\n");
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n", sc_strerror(r));
		return 1;
	}
	printf("Received (SW1=0x%02X, SW2=0x%02X)%s\n", apdu.sw1, apdu.sw2,
	       apdu.resplen ? ":" : "");
	if (apdu.resplen)
		util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);

	return 0;
}
Exemplo n.º 10
0
static int cardos_change_startkey(const char *change_startkey_apdu)
{
	#define MAX_APDU 60
	unsigned char cardos_version[2];
	unsigned char apdu_bin[MAX_APDU];
	size_t apdu_len=MAX_APDU;
	unsigned char checksum[SHA_DIGEST_LENGTH];

	static const unsigned char cardos_43b_checksum[SHA_DIGEST_LENGTH] =
		{  0x5C, 0xD6, 0x8C, 0x2C, 0x24, 0x77, 0x3C, 0xDC,
		   0x93, 0x73, 0xD8, 0x4B, 0x47, 0x29, 0x19, 0x70,
		   0x9F, 0xA2, 0x42, 0xB4  };
	sc_apdu_t apdu;
	u8 rbuf[256];
	int r;
	
	if (verbose)	{
		printf ("Change StartKey APDU:\n");
		util_hex_dump_asc(stdout, (unsigned char *)change_startkey_apdu,
			strlen(change_startkey_apdu), -1);
		}
	
	/* use GET DATA for version - 00 ca 01 82
	 * returns e.g. c8 09 for 4.2B
	 */

	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = 0x00;
	apdu.ins = 0xca;
	apdu.p1 = 0x01;
	apdu.p2 = 0x82;
	apdu.resp = rbuf;
	apdu.resplen = sizeof(rbuf);
	apdu.lc = 0;
	apdu.le = 256;
	apdu.cse = SC_APDU_CASE_2_SHORT;
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}
	if (apdu.resplen != 0x02) {
		printf("did not receive version info, aborting\n");
		return 1;
	}

	/* check all supported versions here. need a checksum check
	   for each of them below */
	if ( (rbuf[0] != 0xc8 || rbuf[1] != 0x08) ) { /* M4.3B */
		printf("currently only CardOS M4.01, M4.2B, M4.2C and M4.3B are supported, aborting\n");
		return 1;
	}
	cardos_version[0] = rbuf[0];
	cardos_version[1] = rbuf[1];

	/* GET DATA for startkey index - 00 ca 01 96
	 * returns 6 bytes PackageLoadKey.Version, PackageLoadKey.Retry
	 * Startkey.Version, Startkey.Retry, 2 internal data byes */

	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = 0x00;
	apdu.ins = 0xca;
	apdu.p1 = 0x01;
	apdu.p2 = 0x96;
	apdu.resp = rbuf;
	apdu.resplen = sizeof(rbuf);
	apdu.lc = 0;
	apdu.le = 256;
	apdu.cse = SC_APDU_CASE_2_SHORT;
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}
	if (apdu.resplen < 0x04) {
		printf("expected 4-6 bytes form GET DATA for startkey data, but got only %ld\n", apdu.resplen);
		printf("aborting\n");
		return 1;
	}

	if (apdu.resp[2] != 0x00) {
		printf("startkey version is 0x%02x, currently we support only 0x00\n", (int) apdu.resp[3]);
		printf("aborting\n");
		return 1;
	}

	if (apdu.resp[3] < 5) {
		printf("startkey has only %d tries left. to be safe: aborting\n", apdu.resp[3]);
		return 1;
	}	

	/* now check if the correct APDU was passed */
	if (sc_hex_to_bin(change_startkey_apdu, apdu_bin, &apdu_len) != 0) {
		printf("can't convert startkey apdu to binary format: aborting\n");
		return 1;
	}
	SHA1(apdu_bin, apdu_len, checksum);

	if (cardos_version[0] == 0xc8 && cardos_version[1] == 0x08) {
		if (memcmp(checksum, cardos_43b_checksum, SHA_DIGEST_LENGTH) != 0) {
			printf("change startkey apdu is wrong, checksum doesn't match\n");
			util_hex_dump_asc(stdout, checksum, SHA_DIGEST_LENGTH, -1);  
			util_hex_dump_asc(stdout, cardos_43b_checksum, SHA_DIGEST_LENGTH, -1);  
			printf("aborting\n");
			return 1;
		}
		goto change_startkey;
	}
	
	printf("checksum for your card not yet implemented, aborting\n");
	return 1;
	
change_startkey:
	/* run change startkey apdu */

	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = apdu_bin[0];
	apdu.ins = apdu_bin[1];
	apdu.p1 = apdu_bin[2];
	apdu.p2 = apdu_bin[3];
	apdu.lc = apdu_bin[4];
	apdu.data = &apdu_bin[5];
	apdu.datalen = apdu.lc;
	apdu.resp = 00;
	apdu.le = 00;
	apdu.cse = SC_APDU_CASE_3_SHORT;
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}

	printf("change startkey command issued with success\n");

	/* GET DATA for startkey index - 00 ca 01 96
	 * returns 6 bytes PackageLoadKey.Version, PackageLoadKey.Retry
	 * Startkey.Version, Startkey.Retry, 2 internal data byes */

	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = 0x00;
	apdu.ins = 0xca;
	apdu.p1 = 0x01;
	apdu.p2 = 0x96;
	apdu.resp = rbuf;
	apdu.resplen = sizeof(rbuf);
	apdu.lc = 0;
	apdu.le = 256;
	apdu.cse = SC_APDU_CASE_2_SHORT;
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}
	if (apdu.resplen < 0x04) {
		printf("expected 4-6 bytes form GET DATA for startkey data, but got only %ld\n", apdu.resplen);
		printf("aborting\n");
		return 1;
	}

	if (apdu.resp[2] != 0xff) {
		printf("startkey version is 0x%02x, should have been changed to 0xff.\n", apdu.resp[2]);
		printf("aborting\n");
		return 1;
	}

	printf("startkey is now 0xff, success!\n");
	return 0;
}
Exemplo n.º 11
0
static int cardos_info(void)
{
	sc_apdu_t apdu;
	u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
	int r;

	if (verbose) {
		printf("Card ATR:\n");
		util_hex_dump_asc(stdout, card->atr, card->atr_len, -1);      
	} else {
		char tmp[SC_MAX_ATR_SIZE*3];
		sc_bin_to_hex(card->atr, card->atr_len, tmp, sizeof(tmp) - 1, ':');
		fprintf(stdout,"%s\n",tmp);
	}

	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = 0x00;
	apdu.ins = 0xca;
	apdu.p1 = 0x01;
	apdu.p2 = 0x80;
	apdu.resp = rbuf;
	apdu.resplen = sizeof(rbuf);
	apdu.lc = 0;
	apdu.le = 256;
	apdu.cse = SC_APDU_CASE_2_SHORT;
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}
	printf("Info : %s\n", apdu.resp);

	apdu.p2 = 0x81;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}

	printf("Chip type: %d\n", apdu.resp[8]);
	printf("Serial number: %02x %02x %02x %02x %02x %02x\n",
	       apdu.resp[10], apdu.resp[11], apdu.resp[12],
	       apdu.resp[13], apdu.resp[14], apdu.resp[15]);
	printf("Full prom dump:\n");
	if (apdu.resplen)
		util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);

	apdu.p2 = 0x82;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}
	printf("OS Version: %d.%d", apdu.resp[0], apdu.resp[1]);
	if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x02) {
		printf(" (that's CardOS M4.0)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x03) {
		printf(" (that's CardOS M4.01)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x04) {
		printf(" (that's CardOS M4.01a)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x06) {
		printf(" (that's CardOS M4.2)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x07) {
		printf(" (that's CardOS M4.3)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x08) {
		printf(" (that's CardOS M4.3B)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x09) {
		printf(" (that's CardOS M4.2B)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x0B) {
		printf(" (that's CardOS M4.2C)\n");	
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x0D) {
		printf(" (that's CardOS M4.4)\n");	
	} else {
		printf(" (unknown Version)\n");
	}

	apdu.p2 = 0x83;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}


	printf("Current life cycle: ");
	if (rbuf[0] == 0x34) {
		printf("%d (manufacturing)\n", rbuf[0]);
	} else if (rbuf[0] == 0x26) {
		printf("%d (initialization)\n", rbuf[0]);
	} else if (rbuf[0] == 0x24) {
		printf("%d (personalization)\n", rbuf[0]);
	} else if (rbuf[0] == 0x20) {
		printf("%d (administration)\n", rbuf[0]);
	} else if (rbuf[0] == 0x10) {
		printf("%d (operational)\n", rbuf[0]);
	} else if (rbuf[0] == 0x29) {
		printf("%d (erase in progress)\n", rbuf[0]);
	} else {
		printf("%d (unknown)\n", rbuf[0]);
	}

	apdu.p2 = 0x84;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}

	printf("Security Status of current DF:\n");
	util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);

	apdu.p2 = 0x85;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}

	printf("Free memory : %d\n", rbuf[0]<<8|rbuf[1]);

	apdu.p2 = 0x86;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}

	if (rbuf[0] == 0x00) {
		printf("ATR Status: 0x%d ROM-ATR\n",rbuf[0]);
	} else if (rbuf[0] == 0x90) {
		printf("ATR Status: 0x%d EEPROM-ATR\n",rbuf[0]);
	} else {
		printf("ATR Status: 0x%d unknown\n",rbuf[0]);
	}
	
	apdu.p2 = 0x88;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}

	printf("Packages installed:\n");
	util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);

	apdu.p2 = 0x89;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}

	printf("Ram size: %d, Eeprom size: %d, cpu type: %x, chip config: %d\n",
			rbuf[0]<<8|rbuf[1], rbuf[2]<<8|rbuf[3], rbuf[4], rbuf[5]);

	apdu.p2 = 0x8a;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}

	printf("Free eeprom memory: %d\n", rbuf[0]<<8|rbuf[1]);

	apdu.p2 = 0x96;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}

	printf("System keys: PackageLoadKey (version 0x%02x, retries %d)\n",
			rbuf[0], rbuf[1]);
	printf("System keys: StartKey (version 0x%02x, retries %d)\n",
			rbuf[2], rbuf[3]);

	apdu.p2 = 0x87;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Unable to determine current DF:\n");
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}

	printf("Path to current DF:\n");
	util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);

	return 0;
}
Exemplo n.º 12
0
static int cardos_format(const char *opt_startkey)
{
	unsigned const char startkey[] = {
		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 
	sc_apdu_t apdu;
	u8 rbuf[256];
	int r;

	if (opt_startkey) {
		fprintf(stderr, "startkey option not implemented yet, aborting!\n");
		return 1;
		/* TODO: instead validate/parse opt_startkey into startkey */
		/* format would be ii:vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
		/* with "ii" the startkey index as hex number and */
		/* "vv" the 16 byte value in hex (32 chars) */
	}
	
	if (verbose)	{
		printf ("StartKey:\n");
		util_hex_dump_asc(stdout, startkey, 16, -1);
		}
	
	/* use GET DATA for version - 00 ca 01 82
	 * returns e.g. c8 09 for 4.2B
	 */

	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = 0x00;
	apdu.ins = 0xca;
	apdu.p1 = 0x01;
	apdu.p2 = 0x82;
	apdu.resp = rbuf;
	apdu.resplen = sizeof(rbuf);
	apdu.lc = 0;
	apdu.le = 256;
	apdu.cse = SC_APDU_CASE_2_SHORT;
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}
	if (apdu.resplen != 0x02) {
		printf("did not receive version info, aborting\n");
		return 1;
	}
	if ((rbuf[0] != 0xc8 || rbuf[1] != 0x09) &&	/* M4.2B */
		(rbuf[0] != 0xc8 || rbuf[1] != 0x08) && /* M4.3B */
		(rbuf[0] != 0xc8 || rbuf[1] != 0x0B) && /* M4.2C */
		(rbuf[0] != 0xc8 || rbuf[1] != 0x0D)) { /* M4.4 */
		printf("currently only CardOS M4.2B, M4.2C, M4.3B and M4.4 are supported, aborting\n");
		return 1;
	}

	/* GET DATA for startkey index - 00 ca 01 96
	 * returns 6 bytes PackageLoadKey.Version, PackageLoadKey.Retry
	 * Startkey.Version, Startkey.Retry, 2 internal data byes */

	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = 0x00;
	apdu.ins = 0xca;
	apdu.p1 = 0x01;
	apdu.p2 = 0x96;
	apdu.resp = rbuf;
	apdu.resplen = sizeof(rbuf);
	apdu.lc = 0;
	apdu.le = 256;
	apdu.cse = SC_APDU_CASE_2_SHORT;
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}
	if (apdu.resplen < 0x04) {
		printf("expected 4-6 bytes form GET DATA for startkey data, but got only %ld\n", apdu.resplen);
		printf("aborting\n");
		return 1;
	}

	if (apdu.resp[2] != 0xff) {
		printf("startkey version is 0x%02x, currently we support only 0xff\n", (int) apdu.resp[2]);
		printf("aborting\n");
		return 1;
	}

	if (apdu.resp[3] < 5) {
		printf("startkey has only %d tries left. to be safe: aborting\n", apdu.resp[3]);
		return 1;
	}	

	/* first run GET DATA for lifecycle	 00 CA 01 83
	 * returns 34 MANUFACTURING 20 ADMINISTRATION 10 OPERATIONAL
	 * 26 INITIALITATION, 23 PERSINALIZATION 3f DEATH
	 * 29 ERASE IN PROGRESS
 	 * */

	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = 0x00;
	apdu.ins = 0xca;
	apdu.p1 = 0x01;
	apdu.p2 = 0x83;
	apdu.resp = rbuf;
	apdu.resplen = sizeof(rbuf);
	apdu.lc = 0;
	apdu.le = 256;
	apdu.cse = SC_APDU_CASE_2_SHORT;
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}

	if (apdu.resp[0] == 0x34) {
		printf("card in manufacturing state\n");
		goto erase_state;

		/* we can leave manufacturing mode with FORMAT,
 		 * but before we do that, we need to change the secret
 		 * siemens start key to the default 0xff start key.
 		 * we know the APDU for that, but it is secreat and
 		 * siemens so far didn't allow us to publish it.
 		 */
	}

	if (apdu.resp[0] != 0x10 && apdu.resp[0] != 0x20) {
		printf("card is in unknown state 0x%02x, aborting\n",
			(int) apdu.resp[0]);
		return 1;

		/* we should handle ERASE IN PROGRESS (29) too */
	}
		
	if (apdu.resp[0] == 0x20) {
		printf("card in administrative state, ok\n");
		goto admin_state;
	}
	printf("card in operational state, need to switch to admin state\n");

	/* PHASE CONTORL 80 10 00 00 */

	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = 0x80;
	apdu.ins = 0x10;
	apdu.p1 = 0x00;
	apdu.p2 = 0x00;
	apdu.resp = 00;
	apdu.lc = 0;
	apdu.le = 00;
	apdu.cse = SC_APDU_CASE_1;
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}

	/* use GET DATA for lifecacle one more */

	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = 0x00;
	apdu.ins = 0xca;
	apdu.p1 = 0x01;
	apdu.p2 = 0x83;
	apdu.resp = rbuf;
	apdu.resplen = sizeof(rbuf);
	apdu.lc = 0;
	apdu.le = 256;
	apdu.cse = SC_APDU_CASE_2_SHORT;
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}
	if (apdu.resp[0] != 0x20) {
		printf("card not in administrative state, failed\n");
		printf("aborting\n");
		return 1;
	}

admin_state:
	/* use GET DATA for packages - 00 ca 01 88
	 * returns e1 LEN MM 04 ID ID ID ID 8f 01 SS 
	 * MM = Manufacturing ID (01 .. 3f = Siemens
	 * ID ID ID ID = Id of the package
	 * SS = License state (01 enabled, 00 disabled
	 */

	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = 0x00;
	apdu.ins = 0xca;
	apdu.p1 = 0x01;
	apdu.p2 = 0x88;
	apdu.resp = rbuf;
	apdu.resplen = sizeof(rbuf);
	apdu.lc = 0;
	apdu.le = 256;
	apdu.cse = SC_APDU_CASE_2_SHORT;
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
		fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
			apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
		return 1;
	}
	if (apdu.resplen != 0x00) {
		printf("card has packages installed.\n");
		printf("you would loose those, and we can't re-install them.\n");
		printf("to protect you card: aborting\n");
		return 1;
	}



	/* now we need to erase the card. Our command is:
	 * 	ERASE FILES 84 06 00 00
	 * but it needs to be send using SM 4h mode (signed and enc.)
	 */
	{
		unsigned const char erase_apdu[] = { 0x84, 0x06, 0x00, 0x00 };
		if (! cardos_sm4h(erase_apdu, sizeof(erase_apdu),
			rbuf, sizeof(rbuf), startkey, sizeof(startkey)))
			return 1;
		if (verbose)	{
			printf ("Erasing EEPROM!\n");
			}
		memset(&apdu, 0, sizeof(apdu));
		apdu.cse = SC_APDU_CASE_3_SHORT;
		apdu.cla = rbuf[0];
		apdu.ins = rbuf[1];
		apdu.p1 = rbuf[2];
		apdu.p2 = rbuf[3];
		apdu.lc = rbuf[4];
		apdu.data = &rbuf[5];
		apdu.datalen = rbuf[4];
		
		r = sc_transmit_apdu(card, &apdu);
		if (r) {
			fprintf(stderr, "APDU transmit failed: %s\n",
				sc_strerror(r));
			return 1;
		}
		if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
			fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
				apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
			if (apdu.resplen)
				util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
			return 1;
		}
	}
	
erase_state:

	/* next we need to format the card. Our command is:
	 * 	FORMAT 84 40 00 01
	 * 	with P2 = 01 (go to admin mode after format)
	 * and with data: T L V with tag 62 and value: more TLV
	 * 		81 02 00 80	Main Folder size 0x0080
	 * 		85 01 01 	no death bit, no deactivation bit,
	 * 					but checksums bit
	 * 		86 0a 00 ... 	10 bytes AC with all set to allow (00)
	 * 	not included: CB tag with secure mode definition
	 * 			(defaults are fine for us)
	 *
	 * this APDU needs to be send using SM 4h mode (signed and enc.)
	 */
	{
		unsigned const char format_apdu[] = {
			0x84, 0x40, 0x00, 0x01, 0x15,
				0x62, 0x13,
					0x81, 0x02, 0x00, 0x80,
					0x85, 0x01, 0x01,
	0x86, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
		if (verbose)	{
			printf ("Formatting!\n");
			}
		if (! cardos_sm4h(format_apdu, sizeof(format_apdu),
			rbuf, sizeof(rbuf), startkey, sizeof(startkey)))
			return 1;

		memset(&apdu, 0, sizeof(apdu));
		apdu.cse = SC_APDU_CASE_3_SHORT;
		apdu.cla = rbuf[0];
		apdu.ins = rbuf[1];
		apdu.p1 = rbuf[2];
		apdu.p2 = rbuf[3];
		apdu.lc = rbuf[4];
		apdu.data = &rbuf[5];
		apdu.datalen = rbuf[4];
		
		r = sc_transmit_apdu(card, &apdu);
		if (r) {
			fprintf(stderr, "APDU transmit failed: %s\n",
				sc_strerror(r));
			return 1;
		}
		if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
			fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
				apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
			if (apdu.resplen)
				util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
			return 1;
		}
	}
	return 0;
}
Exemplo n.º 13
0
static int cardos_sm4h(const unsigned char *in, size_t inlen, unsigned char
	*out, size_t outlen, const unsigned char *key, size_t keylen) {
	/* using a buffer with an APDU, build an SM 4h APDU for cardos */

	int plain_lc;	/* data size in orig APDU */
	unsigned int mac_input_len, enc_input_len;
	unsigned char *mac_input, *enc_input;
	DES_key_schedule ks_a, ks_b;
	DES_cblock des_in,des_out;
	unsigned int i,j;

	if (keylen != 16) {
		printf("key has wrong size, need 16 bytes, got %zd. aborting.\n",
			keylen);
		return 0;
	}

	if (inlen < 4)
		return 0;	/* failed, apdu too short */
	if (inlen <= 5)
		plain_lc = 0;
	if (inlen > 5)
		plain_lc = in[4];
	
	/* 4 + plain_lc plus 0..7 bytes of padding */
	mac_input_len = 4 + plain_lc;
	while (mac_input_len % 8) mac_input_len++;

	mac_input = calloc(1,mac_input_len);
	if (!mac_input) {
		printf("out of memory, aborting\n");
		return 0;
	}
	mac_input[0] = in[1]; 	/* ins */
	mac_input[1] = in[2]; 	/* p1 */
	mac_input[2] = in[3]; 	/* p2 */
	mac_input[3] = plain_lc + 8;
	if (plain_lc)	/* copy data from in APDU */
		memcpy(&mac_input[4],&in[5],plain_lc);
	/* calloc already did the ansi padding: rest is 00 */
	
	/* prepare des key using first 8 bytes of key */
	DES_set_key((const_DES_cblock*) &key[0], &ks_a);
	/* prepare des key using second 8 bytes of key */
	DES_set_key((const_DES_cblock*) &key[8], &ks_b);

	/* first block: XOR with IV and encrypt with key A IV is 8 bytes 00 */
	for (i=0; i < 8; i++) des_in[i] = mac_input[i]^00;
	DES_ecb_encrypt(&des_in, &des_out, &ks_a, 1);

	/* all other blocks: XOR with prev. result and encrypt with key A */
	for (j=1; j < (mac_input_len / 8); j++) {
		for (i=0; i < 8; i++) des_in[i] = mac_input[i+j*8]^des_out[i];
		DES_ecb_encrypt(&des_in, &des_out, &ks_a, 1);
	}

	/* now decrypt with key B and encrypt with key A again */
	/* (a noop if key A and B are the same, e.g. 8 bytes ff */
	for (i=0; i < 8; i++) des_in[i] = des_out[i];
	DES_ecb_encrypt(&des_in, &des_out, &ks_b, 0);
	for (i=0; i < 8; i++) des_in[i] = des_out[i];
	DES_ecb_encrypt(&des_in, &des_out, &ks_a, 1);

	/* now we want to enc:
 	 * orig APDU data plus mac (8 bytes) plus iso padding (1-8 bytes) */
	enc_input_len = plain_lc + 8 + 1;
	while (enc_input_len % 8) enc_input_len++;

	enc_input = calloc(1,enc_input_len);
	if (!enc_input) {
		free(mac_input);
		printf("out of memory, aborting\n");
		return 0;
	}
	if (plain_lc) 
		memcpy(&enc_input[0],&in[5],plain_lc);
	for (i=0; i < 8; i++) enc_input[i+plain_lc] = des_out[i];
	enc_input[plain_lc+8] = 0x80; /* iso padding */
	/* calloc already cleard the remaining bytes to 00 */

	if (outlen < 5 + enc_input_len) {
		free(mac_input);
		free(enc_input);
		printf("output buffer too small, aborting.\n");
		return 0;
	}

	out[0] = in[0];	/* cla */
	out[1] = in[1];	/* ins */
	out[2] = in[2];	/* p1 */
	out[3] = in[3];	/* p2 */
	out[4] = enc_input_len;	/* lc */

	/* encrypt first block */

	/* xor data and IV (8 bytes 00) to get input data */
	for (i=0; i < 8; i++) des_in[i] = enc_input[i] ^ 00;
	
	/* encrypt with des2 (tripple des, but using keys A-B-A) */
	DES_ecb2_encrypt(&des_in, &des_out, &ks_a, &ks_b, 1);

	/* copy encrypted bytes into output */
	for (i=0; i < 8; i++) out[5+i] = des_out[i];

	/* encrypt other blocks (usualy one) */
	for (j=1; j < (enc_input_len / 8); j++) {
		/* xor data and prev. result to get input data */
		for (i=0; i < 8; i++) des_in[i] = enc_input[i+j*8] ^ des_out[i];
	
		/* encrypt with des2 (tripple des, but using keys A-B-A) */
		DES_ecb2_encrypt(&des_in, &des_out, &ks_a, &ks_b, 1);

		/* copy encrypted bytes into output */
		for (i=0; i < 8; i++) out[5+8*j+i] = des_out[i];
	}
	if (verbose)	{
		printf ("Unencrypted APDU:\n");
		util_hex_dump_asc(stdout, in, inlen, -1);
		printf ("Encrypted APDU:\n");
		util_hex_dump_asc(stdout, out, out[4] + 5, -1);
		printf ("\n");
	}
	free(mac_input);
	free(enc_input);
	return 1;
}
Exemplo n.º 14
0
static int do_find_tags(int argc, char **argv)
{
	u8 start[2], end[2], rbuf[256];
	int r;
	unsigned int tag, tag_end;

	start[0] = 0x00;
	start[1] = 0x00;
	end[0] = 0xFF;
	end[1] = 0xFF;
	switch (argc) {
	case 2:
		if (arg_to_fid(argv[1], end) != 0)
			return usage(do_find_tags);
		/* fall through */
	case 1:
		if (arg_to_fid(argv[0], start) != 0)
			return usage(do_find_tags);
		/* fall through */
	case 0:
		break;
	default:
		return usage(do_find_tags);
	}
	tag = (start[0] << 8) | start[1];
	tag_end = (end[0] << 8) | end[1];

	printf("Tag\tType\n");
	while (1) {
		printf("(%04X)\r", tag);
		fflush(stdout);

		r = sc_get_data(card, tag, rbuf, sizeof rbuf);
		if (r >= 0) {
			printf(" %04X ", tag);
			if (tag == 0)
				printf("\tdump file");
			if ((0x0001 <= tag && tag <= 0x00FE)
					|| (0x1F1F <= tag && tag <= 0xFFFF))
				printf("\tBER-TLV");
			if (tag == 0x00FF || tag == 0x02FF)
				printf("\tspecial function");
			if (0x0100 <= tag && tag <= 0x01FF)
				printf("\tproprietary");
			if (tag == 0x0200)
				printf("\tRFU");
			if (0x0201 <= tag && tag <= 0x02FE)
				printf("\tSIMPLE-TLV");
			printf("\n");
			if (r > 0)
				util_hex_dump_asc(stdout, rbuf, r, -1);
		} else {
			switch (r) {
				case SC_ERROR_NOT_ALLOWED:
				case SC_ERROR_SECURITY_STATUS_NOT_SATISFIED:
					printf("(%04X)\t%s\n", tag, sc_strerror(r));
					break;
			}
		}

		if (tag >= tag_end)
			break;
		tag++;
	}
	return 0;
}
Exemplo n.º 15
0
static int cardos_change_lifecycle(void)
{
    sc_apdu_t apdu;
    u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
    int is_cardos5 = 0;
    int r;

    memset(&apdu, 0, sizeof(apdu));
    apdu.cla = 0x00;
    apdu.ins = 0xca;
    apdu.p1 = 0x01;
    apdu.p2 = 0x83;
    apdu.resp = rbuf;
    apdu.resplen = sizeof(rbuf);
    apdu.lc = 0;
    apdu.le = 256;
    apdu.cse = SC_APDU_CASE_2_SHORT;

    // Get current lifecycle:

    r = sc_transmit_apdu(card, &apdu);
    if (r) {
        fprintf(stderr, "APDU transmit failed: %s\n",
                sc_strerror(r));
        return 1;
    }
    if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00 || verbose) {
        fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
                apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
        if (apdu.resplen)
            util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
        return 1;
    }

    printf("Current life cycle: ");
    if (rbuf[0] == 0x34) {
        printf("%d (manufacturing)\n", rbuf[0]);
    } else if (rbuf[0] == 0x26) {
        if (is_cardos5)
            printf("%d (physinit)\n", rbuf[0]);
        else
            printf("%d (initialization)\n", rbuf[0]);
    } else if (rbuf[0] == 0x23) {
        printf("%d (physpers)\n", rbuf[0]);
    } else if (rbuf[0] == 0x24) {
        printf("%d (personalization)\n", rbuf[0]);
    } else if (rbuf[0] == 0x20) {
        printf("%d (administration)\n", rbuf[0]);
    } else if (rbuf[0] == 0x10) {
        printf("%d (operational)\n", rbuf[0]);
    } else if (rbuf[0] == 0x29) {
        printf("%d (erase in progress)\n", rbuf[0]);
    } else if (rbuf[0] == 0x3F) {
        printf("%d (death)\n", rbuf[0]);
    } else {
        printf("%d (unknown)\n", rbuf[0]);
    }

    // Change lifecycle to administration
    if( rbuf[0] == 0x20 ) {
        printf("card already in administration state.\n");
        printf("aborting\n");
        return 1;
    }

    printf("try to switch to administration state\n");

    /* PHASE CONTORL 80 10 00 00 */

    memset(&apdu, 0, sizeof(apdu));
    apdu.cla = 0x80;
    apdu.ins = 0x10;
    apdu.p1 = 0x00;
    apdu.p2 = 0x00;
    apdu.resp = 00;
    apdu.lc = 0;
    apdu.le = 00;
    apdu.cse = SC_APDU_CASE_1;
    r = sc_transmit_apdu(card, &apdu);
    if (r) {
        fprintf(stderr, "APDU transmit failed: %s\n",
                sc_strerror(r));
        return 1;
    }
    if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
        fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
                apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
        if (apdu.resplen)
            util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
        return 1;
    }

    /* use GET DATA for lifecycle one more */

    memset(&apdu, 0, sizeof(apdu));
    apdu.cla = 0x00;
    apdu.ins = 0xca;
    apdu.p1 = 0x01;
    apdu.p2 = 0x83;
    apdu.resp = rbuf;
    apdu.resplen = sizeof(rbuf);
    apdu.lc = 0;
    apdu.le = 256;
    apdu.cse = SC_APDU_CASE_2_SHORT;
    r = sc_transmit_apdu(card, &apdu);
    if (r) {
        fprintf(stderr, "APDU transmit failed: %s\n",
                sc_strerror(r));
        return 1;
    }
    if (apdu.sw1 != 0x90 || apdu.sw2 != 00 || verbose) {
        fprintf(stderr, "Received (SW1=0x%02X, SW2=0x%02X)%s\n",
                apdu.sw1, apdu.sw2, apdu.resplen ? ":" : "");
        if (apdu.resplen)
            util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
        return 1;
    }
    if (apdu.resp[0] != 0x20) {
        printf("card not in administrative state, failed\n");
        printf("aborting\n");
        return 1;
    }

    printf("successfully changed state to administration state.\n");
    return 0;
}
Exemplo n.º 16
0
static int cardos_info(void)
{
	sc_apdu_t apdu;
	u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
	int is_cardos5 = 0;
	int r;

	if (verbose) {
		printf("Card ATR:\n");
		util_hex_dump_asc(stdout, card->atr.value, card->atr.len, -1);
	} else {
		char tmp[SC_MAX_ATR_SIZE*3];
		sc_bin_to_hex(card->atr.value, card->atr.len, tmp, sizeof(tmp) - 1, ':');
		fprintf(stdout,"%s\n",tmp);
	}

	memset(&apdu, 0, sizeof(apdu));
	apdu.cla = 0x00;
	apdu.ins = 0xca;
	apdu.p1 = 0x01;
	apdu.p2 = 0x80;
	apdu.resp = rbuf;
	apdu.resplen = sizeof(rbuf);
	apdu.lc = 0;
	apdu.le = 256;
	apdu.cse = SC_APDU_CASE_2_SHORT;
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;
	printf("Info : %s\n", apdu.resp);

	apdu.p2 = 0x82;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;
	if (apdu.resp[0] == 0xc9)
		is_cardos5 = 1;

	apdu.p2 = 0x81;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;
	if (is_cardos5)	{
		printf("Serial number: %02x %02x %02x %02x %02x %02x %02x %02x\n",
			apdu.resp[0], apdu.resp[1], apdu.resp[2], apdu.resp[3],
			apdu.resp[4], apdu.resp[5], apdu.resp[6], apdu.resp[7]);
	} else	{
		printf("Chip type: %d\n", apdu.resp[8]);
		printf("Serial number: %02x %02x %02x %02x %02x %02x\n",
			   apdu.resp[10], apdu.resp[11], apdu.resp[12],
			   apdu.resp[13], apdu.resp[14], apdu.resp[15]);
		printf("Full prom dump:\n");
		if (apdu.resplen)
			util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
	}

	apdu.p2 = 0x82;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;
	printf("OS Version: %d.%d", apdu.resp[0], apdu.resp[1]);
	if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x02) {
		printf(" (that's CardOS M4.0)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x03) {
		printf(" (that's CardOS M4.01)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x04) {
		printf(" (that's CardOS M4.01a)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x06) {
		printf(" (that's CardOS M4.2)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x07) {
		printf(" (that's CardOS M4.3)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x08) {
		printf(" (that's CardOS M4.3B)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x09) {
		printf(" (that's CardOS M4.2B)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x0B) {
		printf(" (that's CardOS M4.2C)\n");
	} else if (apdu.resp[0] == 0xc8 && apdu.resp[1] == 0x0D) {
		printf(" (that's CardOS M4.4)\n");
	} else if (apdu.resp[0] == 0xc9 && apdu.resp[1] == 0x01) {
		printf(" (that's CardOS V5.0)\n");
	} else {
		printf(" (unknown Version)\n");
	}

	apdu.p2 = 0x83;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;

	printf("Current life cycle: ");
	if (rbuf[0] == 0x34) {
		printf("%d (manufacturing)\n", rbuf[0]);
	} else if (rbuf[0] == 0x26) {
		if (is_cardos5)
			printf("%d (physinit)\n", rbuf[0]);
		else
			printf("%d (initialization)\n", rbuf[0]);
	} else if (rbuf[0] == 0x23) {
		printf("%d (physpers)\n", rbuf[0]);
	} else if (rbuf[0] == 0x24) {
		printf("%d (personalization)\n", rbuf[0]);
	} else if (rbuf[0] == 0x20) {
		printf("%d (administration)\n", rbuf[0]);
	} else if (rbuf[0] == 0x10) {
		printf("%d (operational)\n", rbuf[0]);
	} else if (rbuf[0] == 0x29) {
		printf("%d (erase in progress)\n", rbuf[0]);
	} else if (rbuf[0] == 0x3F) {
		printf("%d (death)\n", rbuf[0]);
	} else {
		printf("%d (unknown)\n", rbuf[0]);
	}

	apdu.p2 = 0x84;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;

	printf("Security Status of current DF:\n");
	util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);

	apdu.p2 = 0x85;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;

	printf("Free memory : %d\n", rbuf[0]<<8|rbuf[1]);

	apdu.p2 = 0x86;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;

	if (rbuf[0] == 0x00) {
		printf("ATR Status: 0x%d ROM-ATR\n",rbuf[0]);
	} else if (rbuf[0] == 0x80)	{
		printf("ATR Status: 0x%d EEPROM-ATR\n",rbuf[0]);
	} else {
		printf("ATR Status: 0x%d unknown\n",rbuf[0]);
	}

	apdu.p2 = 0x88;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;

	printf("Packages installed:\n");
	util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);

	apdu.p2 = 0x89;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;

	if (is_cardos5)
		printf("Ram size: %d, Eeprom size: %d, cpu type: %x, chip config: %d, chip manufacturer: %d\n",
			rbuf[0]<<8|rbuf[1], rbuf[2]<<8|rbuf[3], rbuf[4], rbuf[6], rbuf[7]);
	else
		printf("Ram size: %d, Eeprom size: %d, cpu type: %x, chip config: %d\n",
			rbuf[0]<<8|rbuf[1], rbuf[2]<<8|rbuf[3], rbuf[4], rbuf[5]);

	apdu.p2 = 0x8a;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;

	if (is_cardos5)
		printf("Free eeprom memory: %d\n", rbuf[0]<<24|rbuf[1]<<16|rbuf[2]<<8|rbuf[3]);
	else
		printf("Free eeprom memory: %d\n", rbuf[0]<<8|rbuf[1]);

	apdu.p2 = 0x8d;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;

	printf("Current Maximum Data Field Length: %d\n", rbuf[0]<<8|rbuf[1]);

	if (is_cardos5)	{
		apdu.p2 = 0x8B;
		apdu.resplen = sizeof(rbuf);
		r = sc_transmit_apdu(card, &apdu);
		if (r) {
			fprintf(stderr, "APDU transmit failed: %s\n",
				sc_strerror(r));
			return 1;
		}
		if (check_apdu(&apdu))
			return 1;

		printf("Complete chip production data:\n");
		util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);
	}

	apdu.p2 = 0x96;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;

	printf("System keys: PackageLoadKey (version 0x%02x, retries %d)\n",
			rbuf[0], rbuf[1]);
	printf("System keys: StartKey (version 0x%02x, retries %d)\n",
			rbuf[2], rbuf[3]);

	apdu.p2 = 0x87;
	apdu.resplen = sizeof(rbuf);
	r = sc_transmit_apdu(card, &apdu);
	if (r) {
		fprintf(stderr, "APDU transmit failed: %s\n",
			sc_strerror(r));
		return 1;
	}
	if (check_apdu(&apdu))
		return 1;

	printf("Path to current DF:\n");
	util_hex_dump_asc(stdout, apdu.resp, apdu.resplen, -1);

	return 0;
}