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; }
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; }
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; }
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; }
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; }
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; }
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; }
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); } }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }