Example #1
0
static int list_readers(sc_context_t *ctx)
{
    char card_atr[0x3e];
    sc_card_t *card;
    sc_reader_t *reader;
	size_t i, rcount = sc_ctx_get_reader_count(ctx);
	
	if (rcount == 0) {
		printf("No smart card readers found.\n");
		return 0;
	}
    printf("%-4s %-7s %s\n", "Nr.", "Driver", "Smart Card Reader");
	for (i = 0; i < rcount; i++) {
		reader = sc_ctx_get_reader(ctx, i);
        memset(card_atr, '\0', sizeof card_atr);
        if (sc_detect_card_presence(reader) & SC_READER_CARD_PRESENT) {
            if (sc_connect_card(reader, &card) == SC_SUCCESS) {
                sc_bin_to_hex(card->atr.value, card->atr.len,
                        card_atr, sizeof card_atr, ':');
            }
            sc_disconnect_card(card);
        } else {
            strncpy(card_atr, "[no card present]", sizeof card_atr);
        }
        printf("%-4d %-7s %s\n", i, reader->driver->short_name, reader->name);
        printf("             ATR: %s\n", card_atr);
	}

	return 0;
}
const char *sc_pkcs15_print_id(const struct sc_pkcs15_id *id)
{
	static char buffer[256];

	sc_bin_to_hex(id->value, id->len, buffer, sizeof(buffer), '\0');
	return buffer;
}
Example #3
0
int sc_pkcs15emu_tcos_init_ex(
	sc_pkcs15_card_t   *p15card,
	sc_pkcs15emu_opt_t *opts
){
	sc_card_t         *card = p15card->card;
	sc_context_t      *ctx = p15card->card->ctx;
	sc_serial_number_t serialnr;
	char               serial[30];
	int i, r;

	/* check if we have the correct card OS unless SC_PKCS15EMU_FLAGS_NO_CHECK */
	i=(opts && (opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK));
	if (!i && card->type!=SC_CARD_TYPE_TCOS_V2 && card->type!=SC_CARD_TYPE_TCOS_V3) return SC_ERROR_WRONG_CARD;

	/* get the card serial number */
	r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serialnr);
	if (r < 0) {
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "unable to get ICCSN\n");
		return SC_ERROR_WRONG_CARD;
	}
        sc_bin_to_hex(serialnr.value, serialnr.len , serial, sizeof(serial), 0);
	serial[19] = '\0';
        p15card->tokeninfo->serial_number = strdup(serial);

	if(!detect_netkey(p15card)) return SC_SUCCESS;
	if(!detect_idkey(p15card)) return SC_SUCCESS;
	if(!detect_unicard(p15card)) return SC_SUCCESS;
	if(!detect_signtrust(p15card)) return SC_SUCCESS;
	if(!detect_datev(p15card)) return SC_SUCCESS;

	return SC_ERROR_INTERNAL;
}
Example #4
0
/*
 * Card initialization.
 * For the cryptoflex, read the card's serial number from 3F00 0002
 */
static int
cryptoflex_init_card(sc_profile_t *profile, sc_pkcs15_card_t *p15card)
{
	sc_path_t	path;
	sc_file_t	*file;
	u8		buf[32];
	char		serial[128];
	size_t		len;
	int		r;

	sc_format_path("3F000002", &path);
	if ((r = sc_select_file(p15card->card, &path, &file)) < 0) {
		if (r == SC_ERROR_FILE_NOT_FOUND)
			return 0;
		return r;
	}

	if ((len = file->size) > sizeof(buf))
		len = sizeof(buf);
	sc_file_free(file);
	if ((r = sc_read_binary(p15card->card, 0, buf, len, 0)) < 0)
		return r;
	len = r;
	if (len == 0)
		return 0;

	if ((r = sc_bin_to_hex(buf, len, serial, sizeof(serial), '\0')) < 0)
		return r;
	sc_pkcs15init_set_serial(profile, serial);
	return 0;
}
Example #5
0
static int sc_pkcs15emu_entersafe_init( sc_pkcs15_card_t *p15card)
{
	int    r;
	char   buf[256];
	sc_card_t *card = p15card->card;
	sc_serial_number_t serial;

	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);

	/* get serial number */
	r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
	if (r != SC_SUCCESS)
		return SC_ERROR_INTERNAL;
	r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
	if (r != SC_SUCCESS)
		return SC_ERROR_INTERNAL;
	if (p15card->tokeninfo->serial_number)
		free(p15card->tokeninfo->serial_number);
	p15card->tokeninfo->serial_number = malloc(strlen(buf) + 1);
	if (!p15card->tokeninfo->serial_number)
		return SC_ERROR_INTERNAL;
	strcpy(p15card->tokeninfo->serial_number, buf);

	/* the manufacturer ID, in this case Giesecke & Devrient GmbH */
	if (p15card->tokeninfo->manufacturer_id)
		free(p15card->tokeninfo->manufacturer_id);
	p15card->tokeninfo->manufacturer_id = malloc(strlen(MANU_ID) + 1);
	if (!p15card->tokeninfo->manufacturer_id)
		return SC_ERROR_INTERNAL;
	strcpy(p15card->tokeninfo->manufacturer_id, MANU_ID);

	return SC_SUCCESS;
}
Example #6
0
/* prettify hex */
static char *prettify_hex(u8 *data, size_t length, char *buffer, size_t buflen)
{
	if (data != NULL) {
		int r = sc_bin_to_hex(data, length, buffer, buflen, ':');

		if (r == SC_SUCCESS)
			return buffer;
	}
	return NULL;
}
Example #7
0
static const char *get_inserted_text(struct sc_pkcs15_card *p15card, struct sc_atr *atr)
{
	static char text[3*SC_MAX_ATR_SIZE] = {0};
	const char prefix[] = "ATR: ";

	if (p15card && p15card->card && p15card->card->name) {
		return p15card->card->name;
	}

	if (!atr)
		return NULL;

	strcpy(text, prefix);
	sc_bin_to_hex(atr->value, atr->len, text + (sizeof prefix) - 1,
			sizeof(text) - (sizeof prefix) - 1, ':');

	return text;
}
/* Do the PIN command */
static int
part10_pin_cmd(sc_reader_t *reader, sc_slot_info_t *slot,
	     struct sc_pin_cmd_data *data)
{
	struct pcsc_private_data *priv = GET_PRIV_DATA(reader);
	u8 rbuf[SC_MAX_APDU_BUFFER_SIZE], sbuf[SC_MAX_APDU_BUFFER_SIZE];
	char dbuf[SC_MAX_APDU_BUFFER_SIZE * 3];
	size_t rcount = sizeof(rbuf), scount = 0;
	int r;
	DWORD ioctl = 0;
	sc_apdu_t *apdu;
	struct pcsc_slot_data *pslot = (struct pcsc_slot_data *) slot->drv_data;

	SC_FUNC_CALLED(reader->ctx, 3);
	assert(pslot != NULL);

	if (priv->gpriv->SCardControl == NULL)
		return SC_ERROR_NOT_SUPPORTED;

	/* The APDU must be provided by the card driver */
	if (!data->apdu) {
		sc_error(reader->ctx, "No APDU provided for PC/SC v2 pinpad verification!");
		return SC_ERROR_NOT_SUPPORTED;
	}

	apdu = data->apdu;
	switch (data->cmd) {
	case SC_PIN_CMD_VERIFY:
		if (!(pslot->verify_ioctl || (pslot->verify_ioctl_start && pslot->verify_ioctl_finish))) {
			sc_error(reader->ctx, "Pinpad reader does not support verification!");
			return SC_ERROR_NOT_SUPPORTED;
		}
		r = part10_build_verify_pin_block(sbuf, &scount, slot, data);
		ioctl = pslot->verify_ioctl ? pslot->verify_ioctl : pslot->verify_ioctl_start;
		break;
	case SC_PIN_CMD_CHANGE:
	case SC_PIN_CMD_UNBLOCK:
		if (!(pslot->modify_ioctl || (pslot->modify_ioctl_start && pslot->modify_ioctl_finish))) {
			sc_error(reader->ctx, "Pinpad reader does not support modification!");
			return SC_ERROR_NOT_SUPPORTED;
		}
		r = part10_build_modify_pin_block(sbuf, &scount, slot, data);
		ioctl = pslot->modify_ioctl ? pslot->modify_ioctl : pslot->modify_ioctl_start;
		break;
	default:
		sc_error(reader->ctx, "Unknown PIN command %d", data->cmd);
		return SC_ERROR_NOT_SUPPORTED;
	}

	/* If PIN block building failed, we fail too */
	SC_TEST_RET(reader->ctx, r, "PC/SC v2 pinpad block building failed!");
	/* If not, debug it, just for fun */
	sc_bin_to_hex(sbuf, scount, dbuf, sizeof(dbuf), ':');
	sc_debug(reader->ctx, "PC/SC v2 pinpad block: %s", dbuf);

	r = pcsc_internal_transmit(reader, slot, sbuf, scount, rbuf, &rcount, ioctl);

	SC_TEST_RET(reader->ctx, r, "PC/SC v2 pinpad: block transmit failed!");
	/* finish the call if it was a two-phase operation */
	if ((ioctl == pslot->verify_ioctl_start)
	    || (ioctl == pslot->modify_ioctl_start)) {
		if (rcount != 0) {
			SC_FUNC_RETURN(reader->ctx, 2, SC_ERROR_UNKNOWN_DATA_RECEIVED);
		}
		ioctl = (ioctl == pslot->verify_ioctl_start) ? pslot->verify_ioctl_finish : pslot->modify_ioctl_finish;

		rcount = sizeof(rbuf);
		r = pcsc_internal_transmit(reader, slot, sbuf, 0, rbuf, &rcount, ioctl);
		SC_TEST_RET(reader->ctx, r, "PC/SC v2 pinpad: finish operation failed!");
	}

	/* We expect only two bytes of result data (SW1 and SW2) */
	if (rcount != 2) {
		SC_FUNC_RETURN(reader->ctx, 2, SC_ERROR_UNKNOWN_DATA_RECEIVED);
	}

	/* Extract the SWs for the result APDU */
	apdu->sw1 = (unsigned int) rbuf[rcount - 2];
	apdu->sw2 = (unsigned int) rbuf[rcount - 1];

	r = SC_SUCCESS;
	switch (((unsigned int) apdu->sw1 << 8) | apdu->sw2) {
	case 0x6400: /* Input timed out */
		r = SC_ERROR_KEYPAD_TIMEOUT;
		break;
	case 0x6401: /* Input cancelled */
		r = SC_ERROR_KEYPAD_CANCELLED;
		break;
	case 0x6402: /* PINs don't match */
		r = SC_ERROR_KEYPAD_PIN_MISMATCH;
		break;
	case 0x6B80: /* Wrong data in the buffer, rejected by firmware */
		r = SC_ERROR_READER;
		break;
	}

	SC_TEST_RET(reader->ctx, r, "PIN command failed");

	/* PIN command completed, all is good */
	return SC_SUCCESS;
}
Example #9
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 
sc_pkcs15emu_oberthur_init(struct sc_pkcs15_card * p15card)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_pkcs15_auth_info auth_info;
	struct sc_pkcs15_object   obj;
	struct sc_card *card = p15card->card;
	struct sc_path path;
	int rv, ii, tries_left;
	char serial[0x10];
	unsigned char sopin_reference = 0x04;
	
	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
	sc_bin_to_hex(card->serialnr.value, card->serialnr.len, serial, sizeof(serial), 0);
	p15card->tokeninfo->serial_number = strdup(serial);

	p15card->ops.parse_df = sc_awp_parse_df;
	p15card->ops.clear = sc_awp_clear;
	
	sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Oberthur init: serial %s", p15card->tokeninfo->serial_number);

	sc_format_path(AWP_PIN_DF, &path);
	rv = sc_select_file(card, &path, NULL);
	SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Oberthur init failed: cannot select PIN dir");
	
	tries_left = -1;
	rv = sc_verify(card, SC_AC_CHV, sopin_reference, (unsigned char *)"", 0, &tries_left);
	if (rv && rv != SC_ERROR_PIN_CODE_INCORRECT)   {
		sopin_reference = 0x84;
		rv = sc_verify(card, SC_AC_CHV, sopin_reference, (unsigned char *)"", 0, &tries_left);
	}
	if (rv && rv != SC_ERROR_PIN_CODE_INCORRECT)
		SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Invalid state of SO-PIN");

	/* add PIN */
	memset(&auth_info, 0, sizeof(auth_info));
	memset(&obj,  0, sizeof(obj));

	auth_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;	
	auth_info.auth_method	= SC_AC_CHV;
	auth_info.auth_id.len = 1;
	auth_info.auth_id.value[0] = 0xFF;
	auth_info.attrs.pin.min_length		= 4;
	auth_info.attrs.pin.max_length		= 64;
	auth_info.attrs.pin.stored_length	= 64;
	auth_info.attrs.pin.type		= SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
	auth_info.attrs.pin.reference		= sopin_reference;
	auth_info.attrs.pin.pad_char		= 0xFF;
	auth_info.attrs.pin.flags		= SC_PKCS15_PIN_FLAG_CASE_SENSITIVE 
				| SC_PKCS15_PIN_FLAG_INITIALIZED 
				| SC_PKCS15_PIN_FLAG_NEEDS_PADDING
				| SC_PKCS15_PIN_FLAG_SO_PIN;
	auth_info.tries_left		= tries_left;
	
	strncpy(obj.label, "SO PIN", SC_PKCS15_MAX_LABEL_SIZE-1);
	obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE;
	
	sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Add PIN(%s,auth_id:%s,reference:%i)", obj.label, 
			sc_pkcs15_print_id(&auth_info.auth_id), auth_info.attrs.pin.reference);
	rv = sc_pkcs15emu_add_pin_obj(p15card, &obj, &auth_info);
	SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Oberthur init failed: cannot add PIN object");

	tries_left = -1;
	rv = sc_verify(card, SC_AC_CHV, 0x81, (unsigned char *)"", 0, &tries_left);
	if (rv == SC_ERROR_PIN_CODE_INCORRECT)   {
		/* add PIN */
		memset(&auth_info, 0, sizeof(auth_info));
		memset(&obj,  0, sizeof(obj));
	
		auth_info.auth_id.len = sizeof(PinDomainID) > sizeof(auth_info.auth_id.value) 
				? sizeof(auth_info.auth_id.value) : sizeof(PinDomainID);
		memcpy(auth_info.auth_id.value, PinDomainID, auth_info.auth_id.len);
		auth_info.auth_method	= SC_AC_CHV;

		auth_info.attrs.pin.min_length		= 4;
		auth_info.attrs.pin.max_length		= 64;
		auth_info.attrs.pin.stored_length	= 64;
		auth_info.attrs.pin.type		= SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
		auth_info.attrs.pin.reference		= 0x81;
		auth_info.attrs.pin.pad_char		= 0xFF;
		auth_info.attrs.pin.flags		= SC_PKCS15_PIN_FLAG_CASE_SENSITIVE 
					| SC_PKCS15_PIN_FLAG_INITIALIZED 
					| SC_PKCS15_PIN_FLAG_NEEDS_PADDING
					| SC_PKCS15_PIN_FLAG_LOCAL;
		auth_info.tries_left		= tries_left;
	
		strncpy(obj.label, PIN_DOMAIN_LABEL, SC_PKCS15_MAX_LABEL_SIZE-1);
		obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE;
	
		sc_format_path(AWP_PIN_DF, &auth_info.path); 
		auth_info.path.type = SC_PATH_TYPE_PATH;
	
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Add PIN(%s,auth_id:%s,reference:%i)", obj.label, 
				sc_pkcs15_print_id(&auth_info.auth_id), auth_info.attrs.pin.reference);
		rv = sc_pkcs15emu_add_pin_obj(p15card, &obj, &auth_info);
		SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Oberthur init failed: cannot add PIN object");
	}
	else if (rv != SC_ERROR_DATA_OBJECT_NOT_FOUND)    {
		SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Oberthur init failed: cannot verify PIN");
	}

	for (ii=0; oberthur_infos[ii].name; ii++)   {
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Oberthur init: read %s file", oberthur_infos[ii].name);
		rv = sc_oberthur_read_file(p15card, oberthur_infos[ii].path,
				&oberthur_infos[ii].content, &oberthur_infos[ii].len, 1);
		SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Oberthur init failed: read oberthur file error");
		
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Oberthur init: parse %s file, content length %i", 
				oberthur_infos[ii].name, oberthur_infos[ii].len);
		rv = oberthur_infos[ii].parser(p15card, oberthur_infos[ii].content, oberthur_infos[ii].len, 
				oberthur_infos[ii].postpone_allowed);
		SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, rv, "Oberthur init failed: parse error");
	}

	SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS);
}
Example #11
0
static int sc_pkcs15emu_cac_init(sc_pkcs15_card_t *p15card)
{
	static const pindata pins[] = {
		{ "1", "PIN", "", 0x00,
		  SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
		  8, 4, 8,
		  SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
		  SC_PKCS15_PIN_FLAG_INITIALIZED ,
		  -1, 0xFF,
		  SC_PKCS15_CO_FLAG_PRIVATE },
		{ NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	};
	/* oid for key usage */
	static const struct sc_object_id usage_type = {{ 2, 5, 29, 15, -1 }};
	unsigned int usage;


	/*
	 * The size of the key or the algid is not really known
	 * but can be derived from the certificates.
	 * the cert, pubkey and privkey are a set.
	 * Key usages bits taken from certificate key usage extension.
	 */

	int    r, i;
	sc_card_t *card = p15card->card;
	sc_serial_number_t serial;
	char buf[SC_MAX_SERIALNR * 2 + 1];
	int count;
	char *token_name = NULL;


	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);

	memset(&serial, 0, sizeof(serial));

	/* could read this off card if needed */

	p15card->tokeninfo->label = strdup(cac_get_name(card->type));
	p15card->tokeninfo->manufacturer_id = strdup(MANU_ID);

	/*
	 * get serial number
	 */
	r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
	if (r < 0) {
		sc_log(card->ctx, "sc_card_ctl rc=%d",r);
		p15card->tokeninfo->serial_number = strdup("00000000");
	} else {
		sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
		p15card->tokeninfo->serial_number = strdup(buf);
	}

	/* set pins */
	/* TODO we should not create PIN objects if it is not initialized
	 * (opensc-tool -s 0020000000 returns 0x6A 0x88)
	 */
	sc_log(card->ctx,  "CAC adding pins...");
	for (i = 0; pins[i].id; i++) {
		struct sc_pkcs15_auth_info pin_info;
		struct sc_pkcs15_object   pin_obj;
		const char * label;

		memset(&pin_info, 0, sizeof(pin_info));
		memset(&pin_obj,  0, sizeof(pin_obj));

		pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
		sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id);
		pin_info.attrs.pin.reference     = pins[i].ref;
		pin_info.attrs.pin.flags         = pins[i].flags;
		pin_info.attrs.pin.type          = pins[i].type;
		pin_info.attrs.pin.min_length    = pins[i].minlen;
		pin_info.attrs.pin.stored_length = pins[i].storedlen;
		pin_info.attrs.pin.max_length    = pins[i].maxlen;
		pin_info.attrs.pin.pad_char      = pins[i].pad_char;
		sc_format_path(pins[i].path, &pin_info.path);
		pin_info.tries_left    = -1;

		label = pins[i].label;
		sc_log(card->ctx,  "CAC Adding pin %d label=%s",i, label);
		strncpy(pin_obj.label, label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		pin_obj.flags = pins[i].obj_flags;

		/* get the ACA path in case it needs to be selected before PIN verify */
		r = sc_card_ctl(card, SC_CARDCTL_CAC_GET_ACA_PATH, &pin_info.path);
		if (r < 0) {
			LOG_FUNC_RETURN(card->ctx, r);
		}

		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
		if (r < 0)
			LOG_FUNC_RETURN(card->ctx, r);
	}

	/* set other objects */
	r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_INIT_GET_GENERIC_OBJECTS, &count);
	LOG_TEST_RET(card->ctx, r, "Can not initiate generic objects.");

	for (i = 0; i < count; i++) {
		struct sc_pkcs15_data_info obj_info;
		struct sc_pkcs15_object    obj_obj;

		r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_GET_NEXT_GENERIC_OBJECT, &obj_info);
		if (r < 0)
			LOG_FUNC_RETURN(card->ctx, r);
		memset(&obj_obj, 0, sizeof(obj_obj));
		memcpy(obj_obj.label, obj_info.app_label, sizeof(obj_obj.label));

		r = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT,
			&obj_obj, &obj_info);
		if (r < 0)
			LOG_FUNC_RETURN(card->ctx, r);
	}
	r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_FINAL_GET_GENERIC_OBJECTS, &count);
	LOG_TEST_RET(card->ctx, r, "Can not finalize generic objects.");

	/*
	 * certs, pubkeys and priv keys are related and we assume
	 * they are in order
	 * We need to read the cert, get modulus and keylen
	 * We use those for the pubkey, and priv key objects.
	 */
	sc_log(card->ctx,  "CAC adding certs, pub and priv keys...");
	r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_INIT_GET_CERT_OBJECTS, &count);
	LOG_TEST_RET(card->ctx, r, "Can not initiate cert objects.");

	for (i = 0; i < count; i++) {
		struct sc_pkcs15_data_info obj_info;
		struct sc_pkcs15_cert_info cert_info;
		struct sc_pkcs15_pubkey_info pubkey_info;
		struct sc_pkcs15_prkey_info prkey_info;
		struct sc_pkcs15_object cert_obj;
		struct sc_pkcs15_object pubkey_obj;
		struct sc_pkcs15_object prkey_obj;
		sc_pkcs15_der_t   cert_der;
		sc_pkcs15_cert_t *cert_out = NULL;

		r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_GET_NEXT_CERT_OBJECT, &obj_info);
		LOG_TEST_RET(card->ctx, r, "Can not get next object");

		memset(&cert_info, 0, sizeof(cert_info));
		memset(&pubkey_info, 0, sizeof(pubkey_info));
		memset(&prkey_info, 0, sizeof(prkey_info));
		memset(&cert_obj,  0, sizeof(cert_obj));
		memset(&pubkey_obj,  0, sizeof(pubkey_obj));
		memset(&prkey_obj,  0, sizeof(prkey_obj));

		cert_info.id = obj_info.id;
		pubkey_info.id = obj_info.id;
		prkey_info.id = obj_info.id;
		cert_info.path = obj_info.path;
		prkey_info.path = obj_info.path;
		/* Add 0x3f00 to the front of prkey_info.path to make sc_key_file happy */
		/* only do this if our path.len is 1 or 2 */
		if (prkey_info.path.len && prkey_info.path.len <= 2) {
			prkey_info.path.value[2] = prkey_info.path.value[0];
			prkey_info.path.value[3] = prkey_info.path.value[1];
			prkey_info.path.value[0] = 0x3f;
			prkey_info.path.value[1] = 0x00;
			prkey_info.path.len += 2;
		}
		pubkey_info.native        = 1;
		pubkey_info.key_reference = ((int)obj_info.id.value[0]) << 8 | obj_info.id.value[1];
		prkey_info.key_reference = ((int)obj_info.id.value[0]) << 8 | obj_info.id.value[1];
		prkey_info.native        = 1;

		memcpy(cert_obj.label, obj_info.app_label, sizeof(obj_info.app_label));
		memcpy(pubkey_obj.label, obj_info.app_label, sizeof(obj_info.app_label));
		memcpy(prkey_obj.label, obj_info.app_label, sizeof(obj_info.app_label));
		prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
		sc_pkcs15_format_id(pins[0].id, &prkey_obj.auth_id);

		r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len);

		if (r) {
			sc_log(card->ctx,  "No cert found,i=%d", i);
			continue;
		}
		cert_info.path.count = cert_der.len;

		sc_log(card->ctx, 
			 "cert len=%"SC_FORMAT_LEN_SIZE_T"u, cert_info.path.count=%d r=%d\n",
			 cert_der.len, cert_info.path.count, r);
		sc_log_hex(card->ctx, "cert", cert_der.value, cert_der.len);

		/* cache it using the PKCS15 emulation objects */
		/* as it does not change */
		if (cert_der.value) {
			cert_info.value.value = cert_der.value;
			cert_info.value.len = cert_der.len;
			cert_info.path.len = 0; /* use in mem cert from now on */
		}

		/* following will find the cached cert in cert_info */
		r =  sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
		if (r < 0 || cert_out->key == NULL) {
			sc_log(card->ctx,  "Failed to read/parse the certificate r=%d",r);
			if (cert_out != NULL)
				sc_pkcs15_free_certificate(cert_out);
			continue;
		}

		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
		if (r < 0) {
			sc_log(card->ctx,  " Failed to add cert obj r=%d",r);
			sc_pkcs15_free_certificate(cert_out);
			continue;
		}
		/* set the token name to the name of the CN of the first certificate */
		if (!token_name) {
			u8 * cn_name = NULL;
			size_t cn_len = 0;
			static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }};
			r = sc_pkcs15_get_name_from_dn(card->ctx, cert_out->subject,
				cert_out->subject_len, &cn_oid, &cn_name, &cn_len);
			if (r == SC_SUCCESS) {
				token_name = malloc (cn_len+1);
				if (!token_name) {
					free(cn_name);
					r = SC_ERROR_OUT_OF_MEMORY;
					goto fail;
				}
				memcpy(token_name, cn_name, cn_len);
				free(cn_name);
				token_name[cn_len] = 0;
				free(p15card->tokeninfo->label);
				p15card->tokeninfo->label = token_name;
			}
		}


		r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, cert_out->key, &pubkey_info.direct.spki.value, &pubkey_info.direct.spki.len);
		if (r < 0)
			goto fail;
		pubkey_obj.emulated = cert_out->key;

		r = sc_pkcs15_get_bitstring_extension(card->ctx, cert_out, &usage_type, &usage, NULL);
		if (r < 0) {
			usage = 0xd9ULL; /* basic default usage */
		}
		cac_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1);
		sc_log(card->ctx,   "cert %s: cert_usage=0x%x, pub_usage=0x%x priv_usage=0x%x\n",
				sc_dump_hex(cert_info.id.value, cert_info.id.len),
				 usage, pubkey_info.usage, prkey_info.usage);
		if (cert_out->key->algorithm != SC_ALGORITHM_RSA) {
			sc_log(card->ctx, "unsupported key.algorithm %d", cert_out->key->algorithm);
			sc_pkcs15_free_certificate(cert_out);
			continue;
		} else {
			pubkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8;
			prkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8;
			r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
			sc_log(card->ctx,  "adding rsa public key r=%d usage=%x",r, pubkey_info.usage);
			if (r < 0)
				goto fail;
			r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
			sc_log(card->ctx,  "adding rsa private key r=%d usage=%x",r, prkey_info.usage);
		}

		cert_out->key = NULL;
fail:
		sc_pkcs15_free_certificate(cert_out);
		if (r < 0)
			LOG_FUNC_RETURN(card->ctx, r); /* should not fail */

	}
	r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_FINAL_GET_CERT_OBJECTS, &count);
	LOG_TEST_RET(card->ctx, r, "Can not finalize cert objects.");

	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
Example #12
0
static int sc_pkcs15emu_westcos_init(sc_pkcs15_card_t * p15card)
{
	int i, r;
	int modulus_length = 0, usage = 0;
	char buf[256];
	sc_card_t *card = p15card->card;
	sc_context_t *ctx = card->ctx;
	sc_serial_number_t serial;
	sc_path_t path;
	sc_file_t *file = NULL;
	sc_format_path("3F00", &path);
	r = sc_select_file(card, &path, &file);
	if (r)
		goto out;
	if (file)
		sc_file_free(file);
	file = NULL;
	if (p15card->label != NULL)
		free(p15card->label);
	p15card->label = strdup("westcos");
	if (p15card->manufacturer_id != NULL)
		free(p15card->manufacturer_id);
	p15card->manufacturer_id = strdup("CEV");

	/* get serial number */
	r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
	r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
	if (r)
		goto out;
	if (p15card->serial_number != NULL)
		free(p15card->serial_number);
	p15card->serial_number = strdup(buf);
	p15card->version = buf[6];
	p15card->flags = SC_PKCS15_CARD_FLAG_LOGIN_REQUIRED;
	sc_format_path("AAAA", &path);
	r = sc_select_file(card, &path, &file);
	if (!r) {
		for (i = 0; i < 1; i++) {
			unsigned int flags;
			struct sc_pkcs15_pin_info pin_info;
			struct sc_pkcs15_object pin_obj;
			memset(&pin_info, 0, sizeof(pin_info));
			memset(&pin_obj, 0, sizeof(pin_obj));
			flags = SC_PKCS15_PIN_FLAG_INITIALIZED;
			if (i == 1) {
				flags |=
				    SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED |
				    SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN;
			}
			pin_info.auth_id.len = 1;
			pin_info.auth_id.value[0] = i + 1;
			pin_info.reference = i;
			pin_info.flags = flags;
			pin_info.type = SC_PKCS15_PIN_TYPE_BCD;
			pin_info.min_length = 4;
			pin_info.stored_length = 8;
			pin_info.max_length = 8;
			pin_info.pad_char = 0xff;
			pin_info.path = path;
			pin_info.tries_left = -1;
			if (i == 1)
				strlcpy(pin_obj.label, "Unblock",
					sizeof(pin_obj.label));

			else
				strlcpy(pin_obj.label, "User",
					sizeof(pin_obj.label));
			pin_obj.flags =
			    SC_PKCS15_CO_FLAG_MODIFIABLE |
			    SC_PKCS15_CO_FLAG_PRIVATE;
			r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj,
						     &pin_info);
			if (r)
				goto out;
		}
	}
	if (file)
		sc_file_free(file);
	file = NULL;
	sc_format_path("0002", &path);
	r = sc_select_file(card, &path, &file);
	if (!r) {
		struct sc_pkcs15_cert_info cert_info;
		struct sc_pkcs15_object cert_obj;
		struct sc_pkcs15_pubkey_info pubkey_info;
		struct sc_pkcs15_object pubkey_obj;
		struct sc_pkcs15_pubkey *pkey = NULL;
		memset(&cert_info, 0, sizeof(cert_info));
		memset(&cert_obj, 0, sizeof(cert_obj));
		cert_info.id.len = 1;
		cert_info.id.value[0] = 0x45;
		cert_info.authority = 0;
		cert_info.path = path;
		r = sc_pkcs15_read_certificate(p15card, &cert_info,
					       (sc_pkcs15_cert_t
						**) (&cert_obj.data));
		if (!r) {
			sc_pkcs15_cert_t *cert =
			    (sc_pkcs15_cert_t *) (cert_obj.data);
			strlcpy(cert_obj.label, "User certificat",
				sizeof(cert_obj.label));
			cert_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;
			r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj,
						       &cert_info);
			if (r)
				goto out;
			pkey = &cert->key;
		}
		memset(&pubkey_info, 0, sizeof(pubkey_info));
		memset(&pubkey_obj, 0, sizeof(pubkey_obj));
		pubkey_info.id.len = 1;
		pubkey_info.id.value[0] = 0x45;
		pubkey_info.modulus_length = modulus_length;
		pubkey_info.key_reference = 1;
		pubkey_info.native = 1;
		pubkey_info.usage =
		    SC_PKCS15_PRKEY_USAGE_VERIFY |
		    SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
		    SC_PKCS15_PRKEY_USAGE_ENCRYPT |
		    SC_PKCS15_PRKEY_USAGE_WRAP;
		pubkey_info.path = path;
		strlcpy(pubkey_obj.label, "Public Key",
			sizeof(pubkey_obj.label));
		pubkey_obj.auth_id.len = 1;
		pubkey_obj.auth_id.value[0] = 1;
		pubkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
		pubkey_obj.type = SC_PKCS15_TYPE_PUBKEY_RSA;
		if (pkey == NULL) {
			pubkey_obj.data = &pubkey_info;
			r = sc_pkcs15_read_pubkey(p15card, &pubkey_obj, &pkey);
			if (r)
				goto out;

			//force rechargement clef et maj infos lors de sc_pkcs15emu_add_rsa_pubkey (sinon modulus = 0)
			pubkey_obj.flags = 0;
		}
		if (pkey->algorithm == SC_ALGORITHM_RSA) {
			modulus_length = (int)(pkey->u.rsa.modulus.len * 8);
		}
		pubkey_info.modulus_length = modulus_length;
		pubkey_obj.data = pkey;
		r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj,
						&pubkey_info);
		if (r < 0)
			goto out;
	}
	if (!usage) {
		usage =
		    SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_DECRYPT |
		    SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
	}
	if (file)
		sc_file_free(file);
	file = NULL;
	sc_format_path("0001", &path);
	r = sc_select_file(card, &path, &file);
	if (!r) {
		struct sc_pkcs15_prkey_info prkey_info;
		struct sc_pkcs15_object prkey_obj;
		memset(&prkey_info, 0, sizeof(prkey_info));
		memset(&prkey_obj, 0, sizeof(prkey_obj));
		prkey_info.id.len = 1;
		prkey_info.id.value[0] = 0x45;
		prkey_info.usage =
		    SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_DECRYPT
		    | SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
		prkey_info.native = 1;
		prkey_info.key_reference = 1;
		prkey_info.modulus_length = modulus_length;
		prkey_info.path = path;
		strlcpy(prkey_obj.label, "Private Key",
			sizeof(prkey_obj.label));
		prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
		prkey_obj.auth_id.len = 1;
		prkey_obj.auth_id.value[0] = 1;
		r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj,
					       &prkey_info);
		if (r < 0)
			goto out;
	}
	r = 0;
      out:if (file)
		sc_file_free(file);
	return r;
}
Example #13
0
static int
sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
{
	sc_card_t	*card = p15card->card;
	sc_context_t	*ctx = card->ctx;
	char		string[256];
	u8		c4data[10];
	u8		c5data[70];
	int		r, i;
	const pgp_pin_cfg_t *pin_cfg = (card->type == SC_CARD_TYPE_OPENPGP_V1)
	                               ? pin_cfg_v1 : pin_cfg_v2;
	sc_path_t path;
	sc_file_t *file = NULL;

	set_string(&p15card->tokeninfo->label, "OpenPGP card");
	set_string(&p15card->tokeninfo->manufacturer_id, "OpenPGP project");

	/* card->serialnr = 2 byte manufacturer_id + 4 byte serial_number */
	if (card->serialnr.len > 0) {
		unsigned short manuf_id = bebytes2ushort(card->serialnr.value);
		int j;

		sc_bin_to_hex(card->serialnr.value, card->serialnr.len, string, sizeof(string)-1, 0);
		set_string(&p15card->tokeninfo->serial_number, string);

		for (j = 0; manuf_map[j].name != NULL; j++) {
			if (manuf_id == manuf_map[j].id) {
				set_string(&p15card->tokeninfo->manufacturer_id, manuf_map[j].name);
				break;
			}
		}
	}

	p15card->tokeninfo->flags = SC_PKCS15_TOKEN_PRN_GENERATION | SC_PKCS15_TOKEN_EID_COMPLIANT;

	/* Extract preferred language */
	r = read_file(card, "0065:5f2d", string, sizeof(string)-1);
	if (r < 0)
		goto failed;
	string[r] = '\0';
	set_string(&p15card->tokeninfo->preferred_language, string);

	/* Get CHV status bytes from DO 006E/0073/00C4:
	 *  00:		1 == user consent for signature PIN
	 *		(i.e. PIN still valid for next PSO:CDS command)
	 *  01-03:	max length of pins 1-3
	 *  04-07:	tries left for pins 1-3
	 */
	if ((r = read_file(card, "006E:0073:00C4", c4data, sizeof(c4data))) < 0)
		goto failed;
	if (r != 7) {
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
			"CHV status bytes have unexpected length (expected 7, got %d)\n", r);
		return SC_ERROR_OBJECT_NOT_VALID;
	}

	/* Add PIN codes */
	for (i = 0; i < 3; i++) {
		sc_pkcs15_auth_info_t pin_info;
		sc_pkcs15_object_t   pin_obj;

		memset(&pin_info, 0, sizeof(pin_info));
		memset(&pin_obj,  0, sizeof(pin_obj));

		pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
		pin_info.auth_id.len      = 1;
		pin_info.auth_id.value[0] = pin_cfg[i].reference;
		pin_info.attrs.pin.reference     = pin_cfg[i].reference;
		pin_info.attrs.pin.flags         = pin_cfg[i].flags;
		pin_info.attrs.pin.type          = SC_PKCS15_PIN_TYPE_UTF8;
		pin_info.attrs.pin.min_length    = pin_cfg[i].min_length;
		pin_info.attrs.pin.stored_length = c4data[1 + pin_cfg[i].do_index];
		pin_info.attrs.pin.max_length    = c4data[1 + pin_cfg[i].do_index];
		pin_info.attrs.pin.pad_char      = '\0';
		pin_info.tries_left = c4data[4 + pin_cfg[i].do_index];
		pin_info.logged_in = SC_PIN_STATE_UNKNOWN;

		sc_format_path("3F00", &pin_info.path);

		strlcpy(pin_obj.label, pin_cfg[i].label, sizeof(pin_obj.label));
		pin_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE;
		if (i < 2) {
			pin_obj.auth_id.len = 1;
			pin_obj.auth_id.value[0] = 3;
		}

		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}

	/* Get private key finger prints from DO 006E/0073/00C5:
	 *  00-19:	finger print for SIG key
	 *  20-39:	finger print for ENC key
	 *  40-59:	finger print for AUT key
	 */
	if ((r = read_file(card, "006E:0073:00C5", c5data, sizeof(c5data))) < 0)
		goto failed;
	if (r != 60) {
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
			"finger print bytes have unexpected length (expected 60, got %d)\n", r);
		return SC_ERROR_OBJECT_NOT_VALID;
	}

	/* XXX: check if "halfkeys" can be stored with gpg2. If not, add keypairs in one loop */
	for (i = 0; i < 3; i++) {
		sc_pkcs15_prkey_info_t prkey_info;
		sc_pkcs15_object_t     prkey_obj;
		u8 cxdata[10];
		char path_template[] = "006E:0073:00Cx";
		int j;

		memset(&prkey_info, 0, sizeof(prkey_info));
		memset(&prkey_obj,  0, sizeof(prkey_obj));

		path_template[13] = '1' + i; /* The needed tags are C1 C2 and C3 */
		if ((r = read_file(card, path_template, cxdata, sizeof(cxdata))) < 0)
			goto failed;
		if (r != 6) {
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Key info bytes have unexpected length (expected 6, got %d)\n", r);
			return SC_ERROR_INTERNAL;
		}

		/* check validity using finger prints */
		for (j = 19; j >= 0; j--) {
			if (c5data[20 * i + j] != '\0')
				break;
		}

		/* only add valid keys, i.e. those with a legal algorithm identifier & finger print */
		if (j >= 0 && cxdata[0] != 0) {
			prkey_info.id.len         = 1;
			prkey_info.id.value[0]    = i + 1;
			prkey_info.usage          = key_cfg[i].prkey_usage;
			prkey_info.native         = 1;
			prkey_info.key_reference  = i;
			prkey_info.modulus_length = bebytes2ushort(cxdata + 1);

			strlcpy(prkey_obj.label, key_cfg[i].label, sizeof(prkey_obj.label));
			prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE | SC_PKCS15_CO_FLAG_MODIFIABLE;
			prkey_obj.auth_id.len      = 1;
			prkey_obj.auth_id.value[0] = key_cfg[i].prkey_pin;

			r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
			if (r < 0)
				return SC_ERROR_INTERNAL;
		}
	}
	/* Add public keys */
	for (i = 0; i < 3; i++) {
		sc_pkcs15_pubkey_info_t pubkey_info;
		sc_pkcs15_object_t      pubkey_obj;
		u8 cxdata[10];
		char path_template[] = "006E:0073:00Cx";
		int j;

		memset(&pubkey_info, 0, sizeof(pubkey_info));
		memset(&pubkey_obj,  0, sizeof(pubkey_obj));

		path_template[13] = '1' + i; /* The needed tags are C1 C2 and C3 */
		if ((r = read_file(card, path_template, cxdata, sizeof(cxdata))) < 0)
			goto failed;
		if (r != 6) {
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Key info bytes have unexpected length (expected 6, got %d)\n", r);
			return SC_ERROR_INTERNAL;
		}

		/* check validity using finger prints */
		for (j = 19; j >= 0; j--) {
			if (c5data[20 * i + j] != '\0')
				break;
		}

		/* only add valid keys, i.e. those with a legal algorithm identifier & finger print */
		if (j >= 0 && cxdata[0] != 0) {
			pubkey_info.id.len         = 1;
			pubkey_info.id.value[0]    = i + 1;
			pubkey_info.modulus_length = bebytes2ushort(cxdata + 1);
			pubkey_info.usage          = key_cfg[i].pubkey_usage;
			sc_format_path(key_cfg[i].pubkey_path, &pubkey_info.path);

			strlcpy(pubkey_obj.label, key_cfg[i].label, sizeof(pubkey_obj.label));
			pubkey_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;

			r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
			if (r < 0)
				return SC_ERROR_INTERNAL;
		}
	}

	/* Check if certificate DO 7F21 holds data */
	sc_format_path("7F21", &path);
	r = sc_select_file(card, &path, &file);
	if (r < 0)
		goto failed;

	/* If DO 7F21 holds data, we declare a cert object for pkcs15 */
	if (file->size > 0) {
		struct sc_pkcs15_cert_info cert_info;
		struct sc_pkcs15_object    cert_obj;

		memset(&cert_info, 0, sizeof(cert_info));
		memset(&cert_obj,  0, sizeof(cert_obj));

		/* Certificate ID. We use the same ID as the authentication key */
		cert_info.id.value[0] = 3;
		cert_info.id.len = 1;
		/* Authority, flag is zero */
		/* The path following which PKCS15 will find the content of the object */
		sc_format_path("3F007F21", &cert_info.path);
		/* Object label */
		strlcpy(cert_obj.label, "Cardholder certificate", sizeof(cert_obj.label));

		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
		if (r < 0)
			goto failed;
	}

	/* Add PKCS#15 DATA objects from other OpenPGP card DOs. The return
	 * value is ignored, so this will not cause initialization to fail.
	 */
	sc_pkcs15emu_openpgp_add_data(p15card);

failed:
	if (r < 0) {
		sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
				"Failed to initialize OpenPGP emulation: %s\n",
				sc_strerror(r));
	}
	sc_file_free(file);

	return r;
}
int sc_pkcs15emu_tcos_init_ex(sc_pkcs15_card_t *p15card,
                              sc_pkcs15emu_opt_t *opts)
{
    static const struct {
        const char *card, *manufacturer;
    } cardlist[]= {
        {"Netkey E4 Card", "TeleSec GmbH"},
        {"SignTrust Card", "Deutsche Post"},
        {"DATEV classic", "DATEV"},
        {"Smartkey Card TypA", "Kobil GmbH"},
        {"Smartkey Card TypB", "Kobil GmbH"},
        {"Chipkarte JLU Giessen", "Kobil GmbH"}
    };
    static struct {
        int         flags;
        const int   type, id, writable;
        const char *path;
        const char *label;
    } certlist[]= {
        {0, 1, 0x45, 0, "DF01C000",     "Telesec Signatur Zertifikat"},
        {3, 1, 0x45, 1, "DF014331",     "Signatur Zertifikat 1"},
        {3, 1, 0x45, 1, "DF014332",     "Signatur Zertifikat 2"},
        {1, 1, 0x46, 0, "DF01C100",     "Telesec Authentifizierungs Zertifikat"},
        {3, 1, 0x46, 1, "DF014371",     "Authentifizierungs Zertifikat 1"},
        {3, 1, 0x46, 1, "DF014372",     "Authentifizierungs Zertifikat 2"},
        {1, 1, 0x47, 0, "DF01C200",     "Telesec Verschluesselungs Zertifikat"},
        {3, 1, 0x47, 1, "DF0143B1",     "Verschluesselungs Zertifikat 1"},
        {3, 1, 0x47, 1, "DF0143B2",     "Verschluesselungs Zertifikat 2"},
        {1, 1, 0x48, 1, "DF06C000",     "SigG Zertifikat 1"},
        {1, 1, 0x48, 1, "DF064331",     "SigG Zertifikat 2"},
        {1, 1, 0x48, 1, "DF064332",     "SigG Zertifikat 3"},
        {1, 1, 0x49, 1, "41014352",     "W2K Logon Zertifikat"},
        {0, 2, 0x45, 1, "8000DF01C000", "SignTrust Signatur Zertifikat"},
        {1, 2, 0x46, 1, "800082008220", "SignTrust Verschluesselungs Zertifikat"},
        {1, 2, 0x47, 1, "800083008320", "SignTrust Authentifizierungs Zertifikat"},
        {0, 3, 0x45, 0, "3000C500",     "DATEV Signatur Zertifikat"},
        {1, 3, 0x46, 0, "DF02C200",     "DATEV Verschluesselungs Zertifikat"},
        {1, 3, 0x47, 0, "DF02C500",     "DATEV Authentifizierungs Zertifikat"},
        {0, 4, 0x45, 1, "41004352",     "Smartkey Zertifikat 1"},
        {0, 4, 0x46, 1, "41004353",     "Smartkey Zertifikat 2"},
        {0, 5, 0x45, 1, "41014352",     "Smartkey Zertifikat 1"},
        {0, 5, 0x46, 1, "41014353",     "Smartkey Zertifikat 2"},
        {0, 6, 0x45, 1, "41004352",     "UniCard Giessen Zertifikat"},
        {0, 0, 0, 0, NULL, NULL}
    };
    static const struct {
        int           type, id, auth_id;
        const char   *path;
        unsigned char key_reference;
        const char   *label;
    } keylist[]= {
        {1, 0x45, 4, "DF015331",     0x80, "Signatur Schluessel"},
        {1, 0x46, 3, "DF015371",     0x82, "Authentifizierungs Schluessel"},
        {1, 0x47, 3, "DF0153B1",     0x81, "Verschluesselungs Schluessel"},
        {1, 0x48, 5, "DF065331",     0x80, "SigG Schluessel"},
        {1, 0x49, 1, "41015103",     0x83, "W2K Logon Schluessel"},
        {2, 0x45, 1, "8000DF015331", 0x80, "Signatur Schluessel"},
        {2, 0x46, 2, "800082008210", 0x80, "Verschluesselungs Schluessel"},
        {2, 0x47, 3, "800083008310", 0x80, "Authentifizierungs Schluessel"},
        {3, 0x45, 1, "30005371",     0x82, "Signatur Schluessel"},
        {3, 0x46, 1, "DF0253B1",     0x81, "Verschluesselungs Schluessel"},
        {3, 0x47, 1, "DF025371",     0x82, "Authentifizierung Schluessel"},
        {4, 0x45, 1, "41005103",     0x83, "Smartkey Schluessel 1"},
        {4, 0x46, 1, "41005104",     0x84, "Smartkey Schluessel 2"},
        {5, 0x45, 1, "41015103",     0x83, "Smartkey Schluessel 1"},
        {5, 0x46, 1, "41015104",     0x84, "Smartkey Schluessel 2"},
        {6, 0x45, 1, "3F004100",     0x83, "UniCard Giessen Schluessel"},
        {0, 0, 0, NULL, 0, NULL}
    };
    static const struct {
        int           type, id, auth_id, min_length;
        unsigned char reference;
        const char   *path;
        const char   *label;
        int           flags;
    } pinlist[]= {
        {   1, 1, 2, 6, 0x00, "5000", "globale PIN",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
            SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN
        },
        {   1, 2, 0, 8, 0x01, "5001", "globale PUK",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
            SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN | SC_PKCS15_PIN_FLAG_SO_PIN
        },
        {   1, 3, 1, 6, 0x80, "DF015080", "Netkey PIN0",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
            SC_PKCS15_PIN_FLAG_INITIALIZED
        },
        {   1, 4, 1, 6, 0x81, "DF015081", "Netkey PIN1",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
            SC_PKCS15_PIN_FLAG_INITIALIZED
        },
        {   1, 5, 0, 6, 0x81, "DF065081", "SigG PIN",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
            SC_PKCS15_PIN_FLAG_INITIALIZED
        },
        {   2, 1, 0, 6, 0x81, "8000DF010000", "Signatur PIN",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
            SC_PKCS15_PIN_FLAG_INITIALIZED
        },
        {   2, 2, 0, 6, 0x81, "800082000040", "Verschluesselungs PIN",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
            SC_PKCS15_PIN_FLAG_INITIALIZED
        },
        {   2, 3, 0, 6, 0x81, "800083000040", "Authentifizierungs PIN",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_LOCAL |
            SC_PKCS15_PIN_FLAG_INITIALIZED
        },
        {   3, 1, 0, 6, 0x01, "5001", "globale PIN",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
            SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN
        },
        {   4, 1, 2, 6, 0x00, "5000", "globale PIN",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
            SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN
        },
        {   4, 2, 0, 8, 0x01, "5008", "globale PUK",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
            SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN | SC_PKCS15_PIN_FLAG_SO_PIN
        },
        {   5, 1, 2, 6, 0x00, "5000", "globale PIN",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
            SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN
        },
        {   5, 2, 0, 8, 0x01, "5008", "globale PUK",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED |
            SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN | SC_PKCS15_PIN_FLAG_SO_PIN
        },
        {   6, 1, 0, 6, 0x00, "4100", "globale PIN",
            SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | SC_PKCS15_PIN_FLAG_INITIALIZED
        },
        {0, 0, 0, 0, 0, NULL, NULL, 0}
    };
    sc_card_t         *card = p15card->card;
    sc_context_t      *ctx = p15card->card->ctx;
    sc_path_t          path;
    sc_file_t         *file;
    sc_serial_number_t serialnr;
    char               serial[30];
    int                i, j, found, r, usage, cardtype;

    /* check if we have the correct card OS unless SC_PKCS15EMU_FLAGS_NO_CHECK */
    i=(opts && opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK);
    if (!i && strcmp(card->name, "TCOS")) return SC_ERROR_WRONG_CARD;

    /* get the card serial number */
    r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serialnr);
    if (r < 0) {
        sc_debug(ctx, "unable to get ICCSN\n");
        r = SC_ERROR_WRONG_CARD;
        goto failed;
    }
    sc_bin_to_hex(serialnr.value, serialnr.len , serial, sizeof(serial), 0);
    serial[19] = '\0';
    set_string(&p15card->serial_number, serial);

    /* detect cardtype and certificates */
    cardtype=0;
    for(i=0; certlist[i].id; ++i) {
        if(cardtype && certlist[i].type!=cardtype) continue;
        if(!cardtype && (certlist[i].flags&1)) continue;
        if(!cardtype && ctx->debug>=2) sc_debug(ctx, "Testing %s\n",cardlist[certlist[i].type-1].card);
        if(ctx->debug>=2) sc_debug(ctx, "Testing Cert %s, %s\n", certlist[i].path, certlist[i].label);

        sc_format_path(certlist[i].path, &path);
        sc_ctx_suppress_errors_on(ctx);
        r = sc_select_file(card, &path, NULL);
        sc_ctx_suppress_errors_off(ctx);
        if(r<0) continue;
        cardtype=certlist[i].type;
        certlist[i].flags |= 4;
    }
    if(ctx->debug >= 1) sc_debug(ctx, "Cardtype=%d, %s\n", cardtype, cardlist[cardtype-1].card);
    if(cardtype<1 || cardtype>(int)(sizeof(cardlist)/sizeof(cardlist[0]))) {
        r = SC_ERROR_WRONG_CARD;
        goto failed;
    }
    set_string(&p15card->label, cardlist[cardtype-1].card);
    set_string(&p15card->manufacturer_id, cardlist[cardtype-1].manufacturer);

    /* insert certificates */
    for(found=1; found;) {
        for(i=found=0; certlist[i].id && !found; ++i) if(certlist[i].flags&4) found=certlist[i].id;
        for(j=0; j<2; ++j) for(i=0; certlist[i].id; ++i) {
                struct sc_pkcs15_cert_info cert_info;
                struct sc_pkcs15_object    cert_obj;
                unsigned char cert[20];

                if(certlist[i].id!=found) continue;
                if((certlist[i].flags&2) == 2*j) continue;
                if(!(certlist[i].flags&4)) continue;
                certlist[i].flags-=4;

                sc_format_path(certlist[i].path, &path);
                if(sc_select_file(card, &path, NULL)<0) continue;

                /* read first 20 bytes of certificate, first two bytes
                * must be 0x30 0x82, otherwise this is an empty cert-file
                */
                r = sc_read_binary(card, 0, cert, sizeof(cert), 0);
                if(r<0 || cert[0]!=0x30 || cert[1]!=0x82) continue;

                if(ctx->debug>=1) {
                    sc_debug(ctx,"Cert %02X %s, %s\n",certlist[i].id,certlist[i].path,certlist[i].label);
                }

                /* Telesec-Certificates are prefixed by an OID,
                * for example 06:03:55:04:24. so use appropriate offset
                */
                if(cert[4]==0x06 && cert[5]<10 && cert[6+cert[5]]==0x30 && cert[7+cert[5]]==0x82) {
                    path.index=6+cert[5];
                    path.count=(cert[8+cert[5]]<<8) + cert[9+cert[5]] + 4;
                } else {
                    path.index=0;
                    path.count=(cert[2]<<8) + cert[3] + 4;
                }

                memset(&cert_info, 0, sizeof(cert_info));
                cert_info.id.len      = 1;
                cert_info.id.value[0] = certlist[i].id;
                cert_info.authority   = 0;
                cert_info.path        = path;

                memset(&cert_obj, 0, sizeof(cert_obj));
                strlcpy(cert_obj.label, certlist[i].label, sizeof(cert_obj.label));
                cert_obj.flags = certlist[i].writable ? SC_PKCS15_CO_FLAG_MODIFIABLE : 0;

                r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
                if (r < 0) {
                    sc_debug(ctx, "sc_pkcs15emu_add_x509_cert(%s) failed\n", certlist[i].path);
                    r = SC_ERROR_INTERNAL;
                    goto failed;
                }
            }
    }

    for(i=0; keylist[i].id; ++i) {
        struct sc_pkcs15_prkey_info prkey_info;
        struct sc_pkcs15_object     prkey_obj;

        if(keylist[i].type!=cardtype) continue;

        sc_format_path(keylist[i].path, &path);
        sc_ctx_suppress_errors_on(ctx);
        r = sc_select_file(card, &path, &file);
        sc_ctx_suppress_errors_off(ctx);
        if (r < 0) continue;
        if(ctx->debug >= 1) sc_debug(ctx,"Key %02X %s, %s\n",keylist[i].id,keylist[i].path,keylist[i].label);

        usage = SC_PKCS15_PRKEY_USAGE_SIGN;
        if (file->prop_attr[1] & 0x04) usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT;
        if (file->prop_attr[1] & 0x08) usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;

        memset(&prkey_info, 0, sizeof(prkey_info));
        prkey_info.id.len         = 1;
        prkey_info.id.value[0]    = keylist[i].id;
        prkey_info.usage          = usage;
        prkey_info.native         = 1;
        prkey_info.key_reference  = keylist[i].key_reference;
        prkey_info.modulus_length = 1024;
        sc_format_path(keylist[i].path, &prkey_info.path);

        memset(&prkey_obj, 0, sizeof(prkey_obj));
        strlcpy(prkey_obj.label, keylist[i].label, sizeof(prkey_obj.label));
        prkey_obj.flags            = SC_PKCS15_CO_FLAG_PRIVATE;
        prkey_obj.auth_id.len      = 1;
        prkey_obj.auth_id.value[0] = keylist[i].auth_id;

        r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
        sc_file_free(file);
        if (r < 0) {
            sc_debug(ctx, "sc_pkcs15emu_add_rsa_prkey(%s) failed\n", keylist[i].path);
            r = SC_ERROR_INTERNAL;
            goto failed;
        }
    }

    for(i=0; pinlist[i].id; ++i) {
        struct sc_pkcs15_pin_info pin_info;
        struct sc_pkcs15_object   pin_obj;

        if(pinlist[i].type && pinlist[i].type!=cardtype) continue;

        sc_format_path(pinlist[i].path, &path);
        sc_ctx_suppress_errors_on(ctx);
        r = sc_select_file(card, &path, &file);
        sc_ctx_suppress_errors_off(ctx);
        if (r < 0) continue;
        if(ctx->debug >= 1) sc_debug(ctx, "PIN %02X %s, %s\n", pinlist[i].id,pinlist[i].path,pinlist[i].label);

        memset(&pin_info, 0, sizeof(pin_info));
        pin_info.auth_id.len      = 1;
        pin_info.auth_id.value[0] = pinlist[i].id;
        pin_info.reference        = pinlist[i].reference;
        pin_info.flags            = pinlist[i].flags;
        pin_info.type             = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
        pin_info.min_length       = pinlist[i].min_length;
        pin_info.stored_length    = 16;
        pin_info.max_length       = 16;
        pin_info.pad_char         = '\0';
        pin_info.tries_left       = file->prop_attr[3];
        sc_format_path(pinlist[i].path, &pin_info.path);

        memset(&pin_obj, 0, sizeof(pin_obj));
        strlcpy(pin_obj.label, pinlist[i].label, sizeof(pin_obj.label));
        pin_obj.flags            = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE;
        pin_obj.auth_id.len      = pinlist[i].auth_id ? 0 : 1;
        pin_obj.auth_id.value[0] = pinlist[i].auth_id;

        r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
        sc_file_free(file);
        if (r < 0) {
            sc_debug(ctx, "sc_pkcs15emu_add_pin_obj(%s) failed\n", pinlist[i].path);
            r = SC_ERROR_INTERNAL;
            goto failed;
        }
    }

    /* return to MF */
    sc_format_path("3F00", &path);
    r = sc_select_file(card, &path, NULL);

failed:
    if (r < 0)
        sc_debug(ctx, "PKCS15-emulation for TCOS based preformatted failed: %s\n", sc_strerror(r));
    return r;
}
static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
{

	/* The cert objects will return all the data */
const objdata objects[] = {
	{"1", "Card Capability Container", 
			"2.16.840.1.101.3.7.1.219.0", NULL, "DB00", 0},
	{"2", "Card Holder Unique Identifier",
			"2.16.840.1.101.3.7.2.48.0", NULL, "3000", 0},
	{"3", "Unsigned Card Holder Unique Identifier",
			"2.16.840.1.101.3.7.2.48.2", NULL, "3010", 0},
	{"4", "X.509 Certificate for PIV Authentication",
			"2.16.840.1.101.3.7.2.1.1", NULL, "0101", 0},
	{"5", "Card Holder Fingerprints",
			"2.16.840.1.101.3.7.2.96.16", "1", "6010", SC_PKCS15_CO_FLAG_PRIVATE},
	{"6", "Printed Information",
			"2.16.840.1.101.3.7.2.48.1", "1", "3001", SC_PKCS15_CO_FLAG_PRIVATE},
	{"7", "Card Holder Facial Image", 
			"2.16.840.1.101.3.7.2.96.48", "1", "6030", SC_PKCS15_CO_FLAG_PRIVATE},
	{"8", "X.509 Certificate for Digital Signature",
			"2.16.840.1.101.3.7.2.1.0",  NULL, "0100", 0},
	{"9", "X.509 Certificate for Key Management", 
			"2.16.840.1.101.3.7.2.1.2", NULL, "0102", 0},
	{"10","X.509 Certificate for Card Authentication",
			"2.16.840.1.101.3.7.2.5.0", NULL, "0500", 0},
	{"11", "Security Object",
			"2.16.840.1.101.3.7.2.144.0", NULL, "9000", 0},
	{NULL, NULL, NULL, NULL, NULL, 0}
};
	/* 
	 * NIST 800-73-1 is proposing to lift the restriction on 
	 * requering pin protected certs. Thus the default will be to 
	 * not require this. But there are a number of test cards 
	 * that do enforce it. Code later on will allow SC_PKCS15_CO_FLAG_PRIVATE
	 * to be set. 
	 */
	/* certs will be pulled out from the cert objects */
	cdata certs[] = {
		{"1", "Certificate for PIV Authentication", 0, "0101cece", 0, 0},

		{"2", "Certificate for Digital Signature", 0, "0100cece", 0, 0},
		{"3", "Certificate for Key Management", 0, "0102cece", 0, 0},
		{"4", "Certificate for Card Authentication", 0, "0500cece", 0, 0},
		{NULL, NULL, 0, NULL, 0, 0}
	};

	const pindata pins[] = {
		{ "1", "PIV Card Holder pin", "", 0x80,
		  SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
		  8, 4, 8, 
		  SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
		  SC_PKCS15_PIN_FLAG_LOCAL, 
		  -1, 0xFF,
		  SC_PKCS15_CO_FLAG_PRIVATE },
		{ "2", "PIV PUK", "", 0x81, 
		  SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
		  8, 4, 8, 
		  SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
		  SC_PKCS15_PIN_FLAG_LOCAL | SC_PKCS15_PIN_FLAG_SO_PIN |
		  SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN, 
		  -1, 0xFF, 
		  SC_PKCS15_CO_FLAG_PRIVATE },
		/* there are some more key, but dont need for now */
		/* The admin 9b might fall in here */
		{ NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	};


	/*
	 * The size of the key or the algid is not really known
	 * but can be derived from the certificates. 
	 * the cert, pubkey and privkey are a set. 
	 * Key usages bits taken from pkcs15v1_1 Table 2
	 */
	pubdata pubkeys[] = {

		{ "1", "PIV AUTH pubkey", 0000, 
			 	SC_PKCS15_PRKEY_USAGE_ENCRYPT |
			 	SC_PKCS15_PRKEY_USAGE_WRAP |
				SC_PKCS15_PRKEY_USAGE_VERIFY |
				SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER,
			"9A06", 0x9A, "1", 0, 0},
		{ "2", "SIGN pubkey", 0000, 
				SC_PKCS15_PRKEY_USAGE_ENCRYPT |
				SC_PKCS15_PRKEY_USAGE_VERIFY |
				SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
				SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
			"9C06", 0x9C, "1", 0, 0},
		{ "3", "KEY MAN pubkey", 0000, 
				SC_PKCS15_PRKEY_USAGE_WRAP,
			"9D06", 0x9D, "1", 0, 0},
		{ "4", "CARD AUTH pubkey", 0000, 
				SC_PKCS15_PRKEY_USAGE_VERIFY |
				SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER, 
			"9E06", 0x9E, "0", 0, 0},  /* no pin, and avail in contactless */
		{ NULL, NULL, 0, 0, NULL, 0, NULL, 0, 0}
		
	};

	prdata prkeys[] = {
		{ "1", "PIV AUTH key", 0000, 
				SC_PKCS15_PRKEY_USAGE_DECRYPT |
				SC_PKCS15_PRKEY_USAGE_UNWRAP |
				SC_PKCS15_PRKEY_USAGE_SIGN |
				SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
			"", 0x9A, "1", 0},
		{ "2", "SIGN key", 0000, 
				SC_PKCS15_PRKEY_USAGE_DECRYPT |
				SC_PKCS15_PRKEY_USAGE_SIGN |
				SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
				SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
			"", 0x9C, "1", 0},
		{ "3", "KEY MAN key", 0000, 
				SC_PKCS15_PRKEY_USAGE_UNWRAP,
			"", 0x9D, "1", 0},
		{ "4", "CARD AUTH key", 0000, 
				SC_PKCS15_PRKEY_USAGE_SIGN |
				SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
			"", 0x9E, NULL, 0}, /* no PIN needed, works with wireless */
		{ NULL, NULL, 0, 0, NULL, 0, NULL, 0}
	};

	int    r, i;
	sc_card_t *card = p15card->card;
	sc_file_t *file_out = NULL;
	int exposed_cert[4] = {1, 0, 0, 0};
	sc_serial_number_t serial;
	char buf[SC_MAX_SERIALNR * 2 + 1];

	SC_FUNC_CALLED(card->ctx, 1);

	/* could read this off card if needed */

	/* CSP does not like a - in the name */
	p15card->label = strdup("PIV_II");
	p15card->manufacturer_id = strdup(MANU_ID);

	/*
	 * get serial number 
	 * We will use the FASC-N from the CHUID
	 * Note we are not verifying CHUID, belongs to this card
	 * but need serial number for Mac tokend 
	 */

	sc_ctx_suppress_errors_on(card->ctx);
	r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
	sc_ctx_suppress_errors_off(card->ctx);
	if (r < 0) {
		sc_debug(card->ctx,"sc_card_ctl rc=%d",r);
		p15card->serial_number = strdup("00000000");
	} else {
		sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
		p15card->serial_number = strdup(buf);
	}

	sc_debug(card->ctx, "PIV-II adding objects...");

	/* set other objects */
	for (i = 0; objects[i].label; i++) {
		struct sc_pkcs15_data_info obj_info;
		struct sc_pkcs15_object    obj_obj;

		memset(&obj_info, 0, sizeof(obj_info));
		memset(&obj_obj, 0, sizeof(obj_obj));
		sc_pkcs15_format_id(objects[i].id, &obj_info.id);
		sc_format_path(objects[i].path, &obj_info.path);

		/* We could make sure the object is on the card */
		/* But really don't need to do this now */
//		sc_ctx_suppress_errors_on(card->ctx);
//		r = sc_select_file(card, &obj_info.path, NULL);
//		sc_ctx_suppress_errors_off(card->ctx);
//		if (r == SC_ERROR_FILE_NOT_FOUND)
//			continue; 
			
		strncpy(obj_info.app_label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		r = sc_format_oid(&obj_info.app_oid, objects[i].aoid);
		if (r != SC_SUCCESS)
			return r;

		if (objects[i].auth_id)
			sc_pkcs15_format_id(objects[i].auth_id, &obj_obj.auth_id);

		strncpy(obj_obj.label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		obj_obj.flags = objects[i].obj_flags;
		
		r = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT, 
			&obj_obj, &obj_info); 
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, 1, r);
	}

	/*
	 * certs, pubkeys and priv keys are related and we assume
	 * they are in order 
	 * We need to read the cert, get modulus and keylen 
	 * We use those for the pubkey, and priv key objects. 
	 * If no cert, then see if pubkey (i.e. we are initilizing,
	 * and the pubkey is in a file,) then add pubkey and privkey
	 * If no cert and no pubkey, skip adding them. 
 
	 */
	/* set certs */
	sc_debug(card->ctx, "PIV-II adding certs...");
	for (i = 0; certs[i].label; i++) {
		struct sc_pkcs15_cert_info cert_info;
		struct sc_pkcs15_object    cert_obj;
		sc_pkcs15_der_t   cert_der;
		sc_pkcs15_cert_t *cert_out;
		
		if ((card->flags & 0x20) &&  (exposed_cert[i] == 0))
			continue;

		memset(&cert_info, 0, sizeof(cert_info));
		memset(&cert_obj,  0, sizeof(cert_obj));
	
		sc_pkcs15_format_id(certs[i].id, &cert_info.id);
		cert_info.authority = certs[i].authority;
		sc_format_path(certs[i].path, &cert_info.path);

		strncpy(cert_obj.label, certs[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		cert_obj.flags = certs[i].obj_flags;

		/* see if we have a cert */

		/* use a &file_out so card-piv will read cert if present */
		sc_ctx_suppress_errors_on(card->ctx);
		r = sc_pkcs15_read_file(p15card, &cert_info.path, 
				&cert_der.value, &cert_der.len, &file_out);
		sc_ctx_suppress_errors_off(card->ctx);
		if (file_out) {
			sc_file_free(file_out);
			file_out = NULL;
		}

		if (r) { 
			sc_debug(card->ctx, "No cert found,i=%d", i);
			continue;
		}

		certs[i].found = 1;
		/* cache it using the PKCS15 emulation objects */
		/* as it does not change */
               	if (cert_der.value) {
               	 	cert_info.value.value = cert_der.value;
                       	cert_info.value.len = cert_der.len;
                       	cert_info.path.len = 0; /* use in mem cert from now on */
               	}
		/* following will find the cached cert in cert_info */
		r =  sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
		if (r < 0) {
			sc_debug(card->ctx, "Failed to read/parse the certificate r=%d",r);
			continue;
		}
		/* TODO support DSA keys */
		if (cert_out->key.algorithm == SC_ALGORITHM_RSA) {
			/* save modulus_len in pub and priv */
			pubkeys[i].modulus_len = cert_out->key.u.rsa.modulus.len * 8;
			prkeys[i].modulus_len = cert_out->key.u.rsa.modulus.len * 8;
		}
		sc_pkcs15_free_certificate(cert_out);

		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
		if (r < 0) {
			sc_error(card->ctx, " Failed to add cert obj r=%d",r);
			continue;
		}
	}

	/* set pins */
	sc_debug(card->ctx, "PIV-II adding pins...");
	for (i = 0; pins[i].label; i++) {
		struct sc_pkcs15_pin_info pin_info;
		struct sc_pkcs15_object   pin_obj;

		memset(&pin_info, 0, sizeof(pin_info));
		memset(&pin_obj,  0, sizeof(pin_obj));

		sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id);
		pin_info.reference     = pins[i].ref;
		pin_info.flags         = pins[i].flags;
		pin_info.type          = pins[i].type;
		pin_info.min_length    = pins[i].minlen;
		pin_info.stored_length = pins[i].storedlen;
		pin_info.max_length    = pins[i].maxlen;
		pin_info.pad_char      = pins[i].pad_char;
		sc_format_path(pins[i].path, &pin_info.path);
		pin_info.tries_left    = -1;

		strncpy(pin_obj.label, pins[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		pin_obj.flags = pins[i].obj_flags;

		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, 1, r);
	}



	/* set public keys */
	/* We may only need this during initialzation when genkey
	 * gets the pubkey, but it can not be read from the card 
	 * at a later time. The piv-tool can stach in file 
	 */ 
	sc_debug(card->ctx, "PIV-II adding pub keys...");
	for (i = 0; pubkeys[i].label; i++) {
		struct sc_pkcs15_pubkey_info pubkey_info;
		struct sc_pkcs15_object     pubkey_obj;
		struct sc_pkcs15_pubkey *p15_key;

		if ((card->flags & 0x20) &&  (exposed_cert[i] == 0))
			continue;

		memset(&pubkey_info, 0, sizeof(pubkey_info));
		memset(&pubkey_obj,  0, sizeof(pubkey_obj));


		sc_pkcs15_format_id(pubkeys[i].id, &pubkey_info.id);
		pubkey_info.usage         = pubkeys[i].usage;
		pubkey_info.native        = 1;
		pubkey_info.key_reference = pubkeys[i].ref;

		sc_format_path(pubkeys[i].path, &pubkey_info.path);

		strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);

		pubkey_obj.flags = pubkeys[i].obj_flags;
		

		if (pubkeys[i].auth_id)
			sc_pkcs15_format_id(pubkeys[i].auth_id, &pubkey_obj.auth_id);

		if (certs[i].found == 0) { /*  no cert found */
			sc_debug(card->ctx,"No cert for this pub key i=%d",i);
			/* TODO DSA */
			pubkey_obj.type = SC_PKCS15_TYPE_PUBKEY_RSA;
			pubkey_obj.data = &pubkey_info;
			sc_ctx_suppress_errors_on(card->ctx);
			r = sc_pkcs15_read_pubkey(p15card, &pubkey_obj, &p15_key);
			sc_ctx_suppress_errors_off(card->ctx);
				pubkey_obj.data = NULL;
				sc_debug(card->ctx," READING PUB KEY r=%d",r);
			if (r < 0 ) {
				continue;
			}
			/* Only get here if no cert, and the card-piv.c found 
			 * there is a pub key file. This only happens when trying
			 * initializing a card and have set env to point at file  
			 */
			if (p15_key->algorithm == SC_ALGORITHM_RSA) {
			/* save modulus_len in pub and priv */
			pubkeys[i].modulus_len = p15_key->u.rsa.modulus.len * 8;
			prkeys[i].modulus_len = p15_key->u.rsa.modulus.len * 8;
			pubkeys[i].found = 1;
			}

		}
		pubkey_info.modulus_length = pubkeys[i].modulus_len;
		strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);

		/* TODO DSA keys */
		r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, 1, r); /* should not fail */

		pubkeys[i].found = 1;
	}


	/* set private keys */
	sc_debug(card->ctx, "PIV-II adding private keys...");
	for (i = 0; prkeys[i].label; i++) {
		struct sc_pkcs15_prkey_info prkey_info;
		struct sc_pkcs15_object     prkey_obj;

		if ((card->flags & 0x20) &&  (exposed_cert[i] == 0))
			continue;

		memset(&prkey_info, 0, sizeof(prkey_info));
		memset(&prkey_obj,  0, sizeof(prkey_obj));

		if (certs[i].found == 0 && pubkeys[i].found == 0)
			continue; /* i.e. no cert or pubkey */
		
		sc_pkcs15_format_id(prkeys[i].id, &prkey_info.id);
		prkey_info.usage         = prkeys[i].usage;
		prkey_info.native        = 1;
		prkey_info.key_reference = prkeys[i].ref;
		prkey_info.modulus_length= prkeys[i].modulus_len;
		/* The cert or pubkey should have filled modulus_len */
		/* TODO DSA keys */
		sc_format_path(prkeys[i].path, &prkey_info.path);

		strncpy(prkey_obj.label, prkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);

		prkey_obj.flags = prkeys[i].obj_flags;

		if (prkeys[i].auth_id)
			sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id);

		r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, 1, r);
	}

	SC_FUNC_RETURN(card->ctx, 1, SC_SUCCESS);
}
Example #16
0
int sc_test_init(int *argc, char *argv[])
{
	char	*opt_driver = NULL, *app_name;
	int	opt_debug = 0, opt_reader = -1;
	int	i, c, rc;
	sc_context_param_t ctx_param;

	if  ((app_name = strrchr(argv[0], '/')) != NULL)
		app_name++;
	else
		app_name = argv[0];

	while ((c = getopt_long(*argc, argv, "r:c:d", options, NULL)) != -1) {
		switch (c) {
		case 'r':
			opt_reader = atoi(optarg);
			break;
		case 'c':
			opt_driver = optarg;
			break;
		case 'd':
			opt_debug++;
			break;
		default:
			fprintf(stderr,
				"usage: %s [-r reader] [-c driver] [-d]\n",
				app_name);
			exit(1);
		}
	}
	*argc = optind;

	printf("Using libopensc version %s.\n", sc_get_version());

	memset(&ctx_param, 0, sizeof(ctx_param));
	ctx_param.ver      = 0;
	ctx_param.app_name = app_name;

	i = sc_context_create(&ctx, &ctx_param);
	if (i != SC_SUCCESS) {
		printf("Failed to establish context: %s\n", sc_strerror(i));
		return i;
	}
	ctx->debug = opt_debug;

	if (opt_reader >= sc_ctx_get_reader_count(ctx)) {
		fprintf(stderr, "Illegal reader number.\n"
				"Only %d reader(s) configured.\n",
				sc_ctx_get_reader_count(ctx));
		exit(1);
	}

	while (1) {
		if (opt_reader >= 0) {
			rc = sc_detect_card_presence(sc_ctx_get_reader(ctx, opt_reader));
			printf("Card %s.\n", rc == 1 ? "present" : "absent");
			if (rc < 0)
				return rc;
		} else {
			for (i = rc = 0; rc != 1 && i < sc_ctx_get_reader_count(ctx); i++)
				rc = sc_detect_card_presence(sc_ctx_get_reader(ctx, opt_reader));
			if (rc == 1)
				opt_reader = i - 1;
		}

		if (rc > 0) {
			printf("Card detected in reader '%s'\n",sc_ctx_get_reader(ctx, opt_reader)->name);
			break;
		}
		if (rc < 0)
			return rc;

		printf("Please insert a smart card. Press return to continue");
		fflush(stdout);
		while (getc(stdin) != '\n')
			;
	}

	printf("Connecting... ");
	fflush(stdout);
	i = sc_connect_card(sc_ctx_get_reader(ctx, opt_reader), &card);
	if (i != SC_SUCCESS) {
		printf("Connecting to card failed: %s\n", sc_strerror(i));
		return i;
	}
	printf("connected.\n");
	{
		char tmp[SC_MAX_ATR_SIZE*3];
		sc_bin_to_hex(card->atr, card->atr_len, tmp, sizeof(tmp) - 1, ':');
		printf("ATR = %s\n",tmp);
	}

	if (opt_driver != NULL) {
		rc = sc_set_card_driver(ctx, opt_driver);
		if (rc != 0) {
			fprintf(stderr,
				"Driver '%s' not found!\n", opt_driver);
			return rc;
		}
	}

	return 0;
}
Example #17
0
static int generate_pwd_shares(sc_card_t *card, char **pwd, int *pwdlen, int password_shares_threshold, int password_shares_total)
{
	int r, i;
	BIGNUM prime;
	BIGNUM secret;
	char buf[64];
	char hex[64];
	int l;

	secret_share_t *shares = NULL;
	secret_share_t *sp;

	u8 rngseed[16];

	printf(	"\nThe DKEK will be enciphered using a randomly generated 64 bit password.\n");
	printf(	"This password is split using a (%i-of-%i) threshold scheme.\n\n", password_shares_threshold, password_shares_total);

	printf(	"Please keep the generated and encrypted DKEK file in a safe location. We also recommend \n");
	printf(	"to keep a paper printout, in case the electronic version becomes unavailable. A printable version\n");
	printf(	"of the file can be generated using \"openssl base64 -in <filename>\".\n");

	printf("\n\nPress <enter> to continue");

	waitForEnterKeyPressed();

	*pwd = calloc(1, 8);
	*pwdlen = 8;

	r = sc_get_challenge(card, *pwd, 8);
	if (r < 0) {
		printf("Error generating random key failed with ", sc_strerror(r));
		OPENSSL_cleanse(pwd, *pwdlen);
		free(pwd);
		return r;
	}
	**pwd |= 0x80;

	/*
	 * Initialize prime and secret
	 */
	BN_init(&prime);
	BN_init(&secret);

	/*
	 * Encode the secret value
	 */
	BN_bin2bn(*pwd, *pwdlen, &secret);

	/*
	 * Generate seed and calculate a prime depending on the size of the secret
	 */
	r = sc_get_challenge(card, rngseed, 16);
	if (r < 0) {
		printf("Error generating random seed failed with ", sc_strerror(r));
		OPENSSL_cleanse(pwd, *pwdlen);
		free(pwd);
		return r;
	}

	generatePrime(&prime, &secret, password_shares_total, rngseed);

	// Allocate data buffer for the generated shares
	shares = malloc(password_shares_total * sizeof(secret_share_t));

	createShares(&secret, password_shares_threshold, password_shares_total, prime, shares);

	sp = shares;
	for (i = 0; i < password_shares_total; i++) {
		clearScreen();

		printf("Press <enter> to display key share %i of %i\n\n", i + 1, password_shares_total);
		waitForEnterKeyPressed();

		clearScreen();

		printf("Share %i of %i\n\n", i + 1, password_shares_total);

		l = BN_bn2bin(&prime, buf);
		sc_bin_to_hex(buf, l, hex, 64, ':');
		printf("\nPrime       : %s\n", hex);

		printf("Share ID    : %s\n", BN_bn2dec(&(sp->x)));
		l = BN_bn2bin(&(sp->y), buf);
		sc_bin_to_hex(buf, l, hex, 64, ':');
		printf("Share value : %s\n", hex);

		printf("\n\nPlease note ALL values above and press <enter> when finished");
		waitForEnterKeyPressed();

		sp++;
	}

	clearScreen();

	cleanUpShares(shares, password_shares_total);

	BN_clear_free(&prime);
	BN_clear_free(&secret);

	return 0;
}
Example #18
0
static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
{

	/* The cert objects will return all the data */
	/* Note: pkcs11 objects do not have CK_ID values */

	static const objdata objects[] = {
	{"1", "Card Capability Container", 
			"2.16.840.1.101.3.7.1.219.0", NULL, "DB00", 0},
	{"2", "Card Holder Unique Identifier",
			"2.16.840.1.101.3.7.2.48.0", NULL, "3000", 0},
	{"3", "Unsigned Card Holder Unique Identifier",
			"2.16.840.1.101.3.7.2.48.2", NULL, "3010", 0},
	{"4", "X.509 Certificate for PIV Authentication",
			"2.16.840.1.101.3.7.2.1.1", NULL, "0101", 0},
	{"5", "Cardholder Fingerprints",
			"2.16.840.1.101.3.7.2.96.16", "1", "6010", SC_PKCS15_CO_FLAG_PRIVATE},
	{"6", "Printed Information",
			"2.16.840.1.101.3.7.2.48.1", "1", "3001", SC_PKCS15_CO_FLAG_PRIVATE},
	{"7", "Cardholder Facial Image", 
			"2.16.840.1.101.3.7.2.96.48", "1", "6030", SC_PKCS15_CO_FLAG_PRIVATE},
	{"8", "X.509 Certificate for Digital Signature",
			"2.16.840.1.101.3.7.2.1.0",  NULL, "0100", 0},
	{"9", "X.509 Certificate for Key Management", 
			"2.16.840.1.101.3.7.2.1.2", NULL, "0102", 0},
	{"10","X.509 Certificate for Card Authentication",
			"2.16.840.1.101.3.7.2.5.0", NULL, "0500", 0},
	{"11", "Security Object",
			"2.16.840.1.101.3.7.2.144.0", NULL, "9000", 0},
	{"12", "Discovery Object",
			"2.16.840.1.101.3.7.2.96.80", NULL, "6050", 0},
	{"13", "Key History Object",
			"2.16.840.1.101.3.7.2.96.96", NULL, "6060", 0},
	{"14", "Cardholder Iris Image",
			"2.16.840.1.101.3.7.2.16.21", NULL, "1015", SC_PKCS15_CO_FLAG_PRIVATE},

	{"15", "Retired X.509 Certificate for Key Management 1", 
			"2.16.840.1.101.3.7.2.16.1", NULL, "1001", 0},
	{"16", "Retired X.509 Certificate for Key Management 2", 
			"2.16.840.1.101.3.7.2.16.2", NULL, "1002", 0},
	{"17", "Retired X.509 Certificate for Key Management 3", 
			"2.16.840.1.101.3.7.2.16.3", NULL, "1003", 0},
	{"18", "Retired X.509 Certificate for Key Management 4", 
			"2.16.840.1.101.3.7.2.16.4", NULL, "1004", 0},
	{"19", "Retired X.509 Certificate for Key Management 5", 
			"2.16.840.1.101.3.7.2.16.5", NULL, "1005", 0},
	{"20", "Retired X.509 Certificate for Key Management 6", 
			"2.16.840.1.101.3.7.2.16.6", NULL, "1006", 0},
	{"21", "Retired X.509 Certificate for Key Management 7", 
			"2.16.840.1.101.3.7.2.16.7", NULL, "1007", 0},
	{"22", "Retired X.509 Certificate for Key Management 8", 
			"2.16.840.1.101.3.7.2.16.8", NULL, "1008", 0},
	{"23", "Retired X.509 Certificate for Key Management 9", 
			"2.16.840.1.101.3.7.2.16.9", NULL, "1009", 0},
	{"24", "Retired X.509 Certificate for Key Management 10", 
			"2.16.840.1.101.3.7.2.16.10", NULL, "100A", 0},
	{"25", "Retired X.509 Certificate for Key Management 11", 
			"2.16.840.1.101.3.7.2.16.11", NULL, "100B", 0},
	{"26", "Retired X.509 Certificate for Key Management 12", 
			"2.16.840.1.101.3.7.2.16.12", NULL, "100C", 0},
	{"27", "Retired X.509 Certificate for Key Management 13", 
			"2.16.840.1.101.3.7.2.16.13", NULL, "100D", 0},
	{"28", "Retired X.509 Certificate for Key Management 14", 
			"2.16.840.1.101.3.7.2.16.14", NULL, "100E", 0},
	{"29", "Retired X.509 Certificate for Key Management 15", 
			"2.16.840.1.101.3.7.2.16.15", NULL, "100F", 0},
	{"30", "Retired X.509 Certificate for Key Management 16", 
			"2.16.840.1.101.3.7.2.16.16", NULL, "1010", 0},
	{"31", "Retired X.509 Certificate for Key Management 17", 
			"2.16.840.1.101.3.7.2.16.17", NULL, "1011", 0},
	{"32", "Retired X.509 Certificate for Key Management 18", 
			"2.16.840.1.101.3.7.2.16.18", NULL, "1012", 0},
	{"33", "Retired X.509 Certificate for Key Management 19", 
			"2.16.840.1.101.3.7.2.16.19", NULL, "1013", 0},
	{"34", "Retired X.509 Certificate for Key Management 20", 
			"2.16.840.1.101.3.7.2.16.20", NULL, "1014", 0},
	{NULL, NULL, NULL, NULL, NULL, 0}
};
	/* 
	 * NIST 800-73-1 lifted the restriction on 
	 * requering pin protected certs. Thus the default is to   
	 * not require this.
	 */
	/* certs will be pulled out from the cert objects */
	/* the number of cert, pubkey and prkey triplets */

#define PIV_NUM_CERTS_AND_KEYS 24

	static const cdata certs[PIV_NUM_CERTS_AND_KEYS] = {
		{"1", "Certificate for PIV Authentication", 0, "0101cece", 0},
		{"2", "Certificate for Digital Signature", 0, "0100cece", 0},
		{"3", "Certificate for Key Management", 0, "0102cece", 0},
		{"4", "Certificate for Card Authentication", 0, "0500cece", 0},
		{"5", "Retired Certificate for Key Management 1", 0, "1001cece", 0},
		{"6", "Retired Certificate for Key Management 2", 0, "1002cece", 0},
		{"7", "Retired Certificate for Key Management 3", 0, "1003cece", 0},
		{"8", "Retired Certificate for Key Management 4", 0, "1004cece", 0},
		{"9", "Retired Certificate for Key Management 5", 0, "1005cece", 0},
		{"10", "Retired Certificate for Key Management 6", 0, "1006cece", 0},
		{"11", "Retired Certificate for Key Management 7", 0, "1007cece", 0},
		{"12", "Retired Certificate for Key Management 8", 0, "1008cece", 0},
		{"13", "Retired Certificate for Key Management 9", 0, "1009cece", 0},
		{"14", "Retired Certificate for Key Management 10", 0, "100Acece", 0},
		{"15", "Retired Certificate for Key Management 11", 0, "100Bcece", 0},
		{"16", "Retired Certificate for Key Management 12", 0, "100Ccece", 0},
		{"17", "Retired Certificate for Key Management 13", 0, "100Dcece", 0},
		{"18", "Retired Certificate for Key Management 14", 0, "100Ecece", 0},
		{"19", "Retired Certificate for Key Management 15", 0, "100Fcece", 0},
		{"20", "Retired Certificate for Key Management 16", 0, "1010cece", 0},
		{"21", "Retired Certificate for Key Management 17", 0, "1011cece", 0},
		{"22", "Retired Certificate for Key Management 18", 0, "1012cece", 0},
		{"23", "Retired Certificate for Key Management 19", 0, "1013cece", 0},
		{"24", "Retired Certificate for Key Management 20", 0, "1014cece", 0}
	};

	static const pindata pins[] = {
		{ "1", "PIV Card Holder pin", "", 0x80,
		  /* label and ref will change if using global pin */
		  SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
		  8, 4, 8, 
		  SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
		  SC_PKCS15_PIN_FLAG_LOCAL, 
		  -1, 0xFF,
		  SC_PKCS15_CO_FLAG_PRIVATE },
		{ "2", "PIV PUK", "", 0x81, 
		  SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
		  8, 4, 8, 
		  SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
		  SC_PKCS15_PIN_FLAG_LOCAL | SC_PKCS15_PIN_FLAG_SO_PIN |
		  SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN, 
		  -1, 0xFF, 
		  SC_PKCS15_CO_FLAG_PRIVATE },
		{ NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	};


	/*
	 * The size of the key or the algid is not really known
	 * but can be derived from the certificates. 
	 * the cert, pubkey and privkey are a set. 
	 * Key usages bits taken from pkcs15v1_1 Table 2
	 * RSA and EC hav differents set of usage 
	 */
	static const pubdata pubkeys[PIV_NUM_CERTS_AND_KEYS] = {

		{ "1", "PIV AUTH pubkey", 
			 	/*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT |
			 		SC_PKCS15_PRKEY_USAGE_WRAP |
					SC_PKCS15_PRKEY_USAGE_VERIFY |
					SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER,
				/*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY,
			"9A06", 0x9A, "1", 0, "PIV_9A_KEY"},
		{ "2", "SIGN pubkey", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT |
					SC_PKCS15_PRKEY_USAGE_VERIFY |
					SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
					SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
				/*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY |
					SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
			"9C06", 0x9C, "1", 0, "PIV_9C_KEY"},
		{ "3", "KEY MAN pubkey", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"9D06", 0x9D, "1", 0, "PIV_9D_KEY"},
		{ "4", "CARD AUTH pubkey", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_VERIFY |
					SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER, 
				/*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY,
			"9E06", 0x9E, "0", 0, "PIV_9E_KEY"},  /* no pin, and avail in contactless */

		{ "5", "Retired KEY MAN 1",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8206", 0x82, "1", 0, NULL},
		{ "6", "Retired KEY MAN 2",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8306", 0x83, "1", 0, NULL},
		{ "7", "Retired KEY MAN 3",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8406", 0x84, "1", 0, NULL},
		{ "8", "Retired KEY MAN 4",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8506", 0x85, "1", 0, NULL},
		{ "9", "Retired KEY MAN 5",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8606", 0x86, "1", 0, NULL},
		{ "10", "Retired KEY MAN 6",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8706", 0x87, "1", 0, NULL},
		{ "11", "Retired KEY MAN 7",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8806", 0x88, "1", 0, NULL},
		{ "12", "Retired KEY MAN 8",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8906", 0x89, "1", 0, NULL},
		{ "13", "Retired KEY MAN 9",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8A06", 0x8A, "1", 0, NULL},
		{ "14", "Retired KEY MAN 10",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8B06", 0x8B, "1", 0, NULL},
		{ "15", "Retired KEY MAN 11",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8C06", 0x8C, "1", 0, NULL},
		{ "16", "Retired KEY MAN 12",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8D06", 0x8D, "1", 0, NULL},
		{ "17", "Retired KEY MAN 13",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8E06", 0x8E, "1", 0, NULL},
		{ "18", "Retired KEY MAN 14",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8F06", 0x8F, "1", 0, NULL},
		{ "19", "Retired KEY MAN 15",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "9006", 0x90, "1", 0, NULL},
		{ "20", "Retired KEY MAN 16",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "9106", 0x91, "1", 0, NULL},
		{ "21", "Retired KEY MAN 17",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "9206", 0x92, "1", 0, NULL},
		{ "22", "Retired KEY MAN 18",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "9306", 0x93, "1", 0, NULL},
		{ "23", "Retired KEY MAN 19",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "9406", 0x94, "1", 0, NULL},
		{ "24", "Retired KEY MAN 20",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "9506", 0x95, "1", 0, NULL} };

/*
 * note some of the SC_PKCS15_PRKEY values are dependent
 * on the key algorithm, and will be reset. 
 */
	static const prdata prkeys[PIV_NUM_CERTS_AND_KEYS] = {
		{ "1", "PIV AUTH key", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT |
					SC_PKCS15_PRKEY_USAGE_UNWRAP |
					SC_PKCS15_PRKEY_USAGE_SIGN |
					SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
				/*EC*/SC_PKCS15_PRKEY_USAGE_SIGN,
			"", 0x9A, "1", SC_PKCS15_CO_FLAG_PRIVATE, 0},
		{ "2", "SIGN key", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT |
					SC_PKCS15_PRKEY_USAGE_SIGN |
					SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
					SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
				/*EC*/SC_PKCS15_PRKEY_USAGE_SIGN | 
					SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
			"", 0x9C, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "3", "KEY MAN key", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x9D, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "4", "CARD AUTH key", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_SIGN |
				SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
				/*EC*/SC_PKCS15_PRKEY_USAGE_SIGN,
			"", 0x9E, NULL, 0, 0}, /* no PIN needed, works with wireless */
		{ "5", "Retired KEY MAN 1",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x82, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "6", "Retired KEY MAN 2",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x83, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "7", "Retired KEY MAN 3",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x84, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "8", "Retired KEY MAN 4",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x85, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "9", "Retired KEY MAN 5",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x86, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "10", "Retired KEY MAN 6",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x87, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "11", "Retired KEY MAN 7",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x88, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "12", "Retired KEY MAN 8",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x89, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "13", "Retired KEY MAN 9",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x8A, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "14", "Retired KEY MAN 10",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x8B, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "15", "Retired KEY MAN 11",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x8C, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "16", "Retired KEY MAN 12",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x8D, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "17", "Retired KEY MAN 13",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x8E, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "18", "Retired KEY MAN 14",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x8F, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "19", "Retired KEY MAN 15",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x90, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "20", "Retired KEY MAN 16",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x91, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "21", "Retired KEY MAN 17",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x92, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "22", "Retired KEY MAN 18",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x93, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "23", "Retired KEY MAN 19",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x94, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "24", "Retired KEY MAN 20",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x95, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1}
	};

	int    r, i;
	sc_card_t *card = p15card->card;
	sc_file_t *file_out = NULL;
	int exposed_cert[PIV_NUM_CERTS_AND_KEYS] = {1, 0, 0, 0};
	sc_serial_number_t serial;
	char buf[SC_MAX_SERIALNR * 2 + 1];
	common_key_info ckis[PIV_NUM_CERTS_AND_KEYS];


	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);

	/* could read this off card if needed */

	/* CSP does not like a - in the name */
	p15card->tokeninfo->label = strdup("PIV_II");
	p15card->tokeninfo->manufacturer_id = strdup(MANU_ID);

	/*
	 * get serial number 
	 * We will use the FASC-N from the CHUID
	 * Note we are not verifying CHUID, belongs to this card
	 * but need serial number for Mac tokend 
	 */

	r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
	if (r < 0) {
		sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"sc_card_ctl rc=%d",r);
		p15card->tokeninfo->serial_number = strdup("00000000");
	} else {
		sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
		p15card->tokeninfo->serial_number = strdup(buf);
	}

	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "PIV-II adding objects...");

	/* set other objects */
	for (i = 0; objects[i].label; i++) {
		struct sc_pkcs15_data_info obj_info;
		struct sc_pkcs15_object    obj_obj;

		memset(&obj_info, 0, sizeof(obj_info));
		memset(&obj_obj, 0, sizeof(obj_obj));
		sc_pkcs15_format_id(objects[i].id, &obj_info.id);
		sc_format_path(objects[i].path, &obj_info.path);

		/* See if the object can not be present on the card */
		r = (card->ops->card_ctl)(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &obj_info.path);
		if (r == 1)
			continue; /* Not on card, do not define the object */
			
		strncpy(obj_info.app_label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		r = sc_format_oid(&obj_info.app_oid, objects[i].aoid);
		if (r != SC_SUCCESS)
			return r;

		if (objects[i].auth_id)
			sc_pkcs15_format_id(objects[i].auth_id, &obj_obj.auth_id);

		strncpy(obj_obj.label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		obj_obj.flags = objects[i].obj_flags;
		
		r = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT, 
			&obj_obj, &obj_info); 
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
/* TODO
 * PIV keys 9C and 9D require the pin verify be done just befor any
 * crypto operation using these keys. 
 * 
 * Nss 3.12.7 does not check the CKA_ALWAYS_AUTHENTICATE attribute of a key
 * and will do a C_FindObjects with only CKA_VALUE looking for a certificate
 * it had found earlier after c_Login. The template does not add CKA_TYPE=cert.
 * This will cause the card-piv to read all the objects and will reset
 * the security status for the 9C and 9D keys.
 * Mozilla Bug 457025 
 * 
 * We can not read all the objects, as some need the PIN!
 */  
	}

	/*
	 * certs, pubkeys and priv keys are related and we assume
	 * they are in order 
	 * We need to read the cert, get modulus and keylen 
	 * We use those for the pubkey, and priv key objects. 
	 * If no cert, then see if pubkey (i.e. we are initilizing,
	 * and the pubkey is in a file,) then add pubkey and privkey
	 * If no cert and no pubkey, skip adding them. 
 
	 */
	/* set certs */
	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "PIV-II adding certs...");
	for (i = 0; i < PIV_NUM_CERTS_AND_KEYS; i++) {
		struct sc_pkcs15_cert_info cert_info;
		struct sc_pkcs15_object    cert_obj;
		sc_pkcs15_der_t   cert_der;
		sc_pkcs15_cert_t *cert_out;
		
		ckis[i].cert_found = 0;
		ckis[i].key_alg = -1;
		ckis[i].pubkey_found = 0;
		ckis[i].pubkey_len = 0;

		if ((card->flags & 0x20) &&  (exposed_cert[i] == 0))
			continue;

		memset(&cert_info, 0, sizeof(cert_info));
		memset(&cert_obj,  0, sizeof(cert_obj));
	
		sc_pkcs15_format_id(certs[i].id, &cert_info.id);
		cert_info.authority = certs[i].authority;
		sc_format_path(certs[i].path, &cert_info.path);

		strncpy(cert_obj.label, certs[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		cert_obj.flags = certs[i].obj_flags;

		/* See if the cert might be present or not. */
		r = (card->ops->card_ctl)(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &cert_info.path);
		if (r == 1) {
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Cert can not be present,i=%d", i);
			continue;
		}

		/* use a &file_out so card-piv.c will read cert if present */
		r = sc_pkcs15_read_file(p15card, &cert_info.path, 
				&cert_der.value, &cert_der.len, &file_out);
		if (file_out) {
			sc_file_free(file_out);
			file_out = NULL;
		}

		if (r) { 
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "No cert found,i=%d", i);
			continue;
		}

		ckis[i].cert_found = 1;
		/* cache it using the PKCS15 emulation objects */
		/* as it does not change */
               	if (cert_der.value) {
               	 	cert_info.value.value = cert_der.value;
                       	cert_info.value.len = cert_der.len;
                       	cert_info.path.len = 0; /* use in mem cert from now on */
               	}
		/* following will find the cached cert in cert_info */
		r =  sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
		if (r < 0 || cert_out->key == NULL) {
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Failed to read/parse the certificate r=%d",r);
			continue;
		}
		ckis[i].key_alg = cert_out->key->algorithm;
		switch (cert_out->key->algorithm) {
			case SC_ALGORITHM_RSA:
				/* save pubkey_len for pub and priv */
				ckis[i].pubkey_len = cert_out->key->u.rsa.modulus.len * 8;
				break;
			case SC_ALGORITHM_EC:
				ckis[i].pubkey_len = cert_out->key->u.ec.field_length;
				break;
			default:
				sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsuported key.algorithm %d", cert_out->key->algorithm);
				ckis[i].pubkey_len = 0; /* set some value for now */
		}
		sc_pkcs15_free_certificate(cert_out);

		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
		if (r < 0) {
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, " Failed to add cert obj r=%d",r);
			continue;
		}
	}

	/* set pins */
	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "PIV-II adding pins...");
	for (i = 0; pins[i].label; i++) {
		struct sc_pkcs15_pin_info pin_info;
		struct sc_pkcs15_object   pin_obj;
		const char * label;
		int pin_ref;

		memset(&pin_info, 0, sizeof(pin_info));
		memset(&pin_obj,  0, sizeof(pin_obj));

		sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id);
		pin_info.reference     = pins[i].ref;
		pin_info.flags         = pins[i].flags;
		pin_info.type          = pins[i].type;
		pin_info.min_length    = pins[i].minlen;
		pin_info.stored_length = pins[i].storedlen;
		pin_info.max_length    = pins[i].maxlen;
		pin_info.pad_char      = pins[i].pad_char;
		sc_format_path(pins[i].path, &pin_info.path);
		pin_info.tries_left    = -1;

		label = pins[i].label;
		if (i == 0 &&
			(card->ops->card_ctl)(card, SC_CARDCTL_PIV_PIN_PREFERENCE,
					&pin_ref) == 0 &&
				pin_ref == 0x00) { /* must be 80 for PIV pin, or 00 for Global PIN */
			pin_info.reference = pin_ref;
			label = "Global PIN";
		} 
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DEE Adding pin %d label=%s",i, label);
		strncpy(pin_obj.label, label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		pin_obj.flags = pins[i].obj_flags;

		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
	}



	/* set public keys */
	/* We may only need this during initialzation when genkey
	 * gets the pubkey, but it can not be read from the card 
	 * at a later time. The piv-tool can stach  pubkey in file 
	 */ 
	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "PIV-II adding pub keys...");
	for (i = 0; i < PIV_NUM_CERTS_AND_KEYS; i++) {
		struct sc_pkcs15_pubkey_info pubkey_info;
		struct sc_pkcs15_object     pubkey_obj;
		struct sc_pkcs15_pubkey *p15_key;

		if ((card->flags & 0x20) &&  (exposed_cert[i] == 0))
			continue;

		memset(&pubkey_info, 0, sizeof(pubkey_info));
		memset(&pubkey_obj,  0, sizeof(pubkey_obj));


		sc_pkcs15_format_id(pubkeys[i].id, &pubkey_info.id);
		pubkey_info.native        = 1;
		pubkey_info.key_reference = pubkeys[i].ref;

//		sc_format_path(pubkeys[i].path, &pubkey_info.path);

		strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);

		pubkey_obj.flags = pubkeys[i].obj_flags;
		

		if (pubkeys[i].auth_id)
			sc_pkcs15_format_id(pubkeys[i].auth_id, &pubkey_obj.auth_id);

		/* If no cert found, piv-tool may have stached the pubkey 
		 * so we can use it when generating a certificate request
		 * The file is a OpenSSL DER EVP_KEY, which looks like 
		 * a certificate subjectPublicKeyInfo.
		 *
		 */
		if (ckis[i].cert_found == 0 ) { /*  no cert found */
			char * filename = NULL;
			
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"No cert for this pub key i=%d",i);
			
			/* 
			 * If we used the piv-tool to generate a key,
			 * we would have saved the public key as a file.
			 * This code is only used while signing a request
			 * After the certificate is loaded on the card,
			 * the public key is extracted from the certificate.
			 */
	
			
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"DEE look for env %s", 
					pubkeys[i].getenvname?pubkeys[i].getenvname:"NULL");

			if (pubkeys[i].getenvname == NULL) 
				continue;

			filename = getenv(pubkeys[i].getenvname); 
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"DEE look for file %s", filename?filename:"NULL");
			if (filename == NULL)  
				continue;
			
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Adding pubkey from file %s",filename);

			r = sc_pkcs15_pubkey_from_spki_filename(card->ctx, 
						filename,
						&p15_key);
			if (r < 0) 
				continue;
			
			/* Only get here if no cert, and the the above found the
			 * pub key file (actually the SPKI version). This only 
			 * happens when trying initializing a card and have set 
			 * env PIV_9A_KEY or 9C, 9D, 9E to point at the file. 
			 *
			 * We will cache it using the PKCS15 emulation objects
			 */

			pubkey_info.path.len = 0;
			
			ckis[i].key_alg = p15_key->algorithm; 
			switch (p15_key->algorithm) {
				case SC_ALGORITHM_RSA:
					/* save pubkey_len in pub and priv */
					ckis[i].pubkey_len = p15_key->u.rsa.modulus.len * 8;
					ckis[i].pubkey_found = 1;
					break;
				case SC_ALGORITHM_EC:
					ckis[i].key_alg = SC_ALGORITHM_EC;
					ckis[i].pubkey_len = p15_key->u.ec.field_length;
					ckis[i].pubkey_found = 1;
					break;
				default:
					sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Unsupported key_alg %d",p15_key->algorithm);
					continue;
			}
			pubkey_obj.emulated = p15_key;
			p15_key = NULL;
		}

		sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"adding pubkey for %d keyalg=%d",i, ckis[i].key_alg);
		switch (ckis[i].key_alg) {
			case SC_ALGORITHM_RSA:
				pubkey_info.usage = pubkeys[i].usage_rsa;
				pubkey_info.modulus_length = ckis[i].pubkey_len;
				strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);

				r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
				if (r < 0)
					SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); /* should not fail */

				ckis[i].pubkey_found = 1;
				break;
			case SC_ALGORITHM_EC:
				pubkey_info.usage = pubkeys[i].usage_ec;
				pubkey_info.field_length = ckis[i].pubkey_len; 
				strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);

				r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info);
				if (r < 0) 
					SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); /* should not fail */
				ckis[i].pubkey_found = 1;
				break;
			default:
				sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"key_alg %d not supported", ckis[i].key_alg);
				continue;
		}
	}


	/* set private keys */
	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "PIV-II adding private keys...");
	for (i = 0; i < PIV_NUM_CERTS_AND_KEYS; i++) {
		struct sc_pkcs15_prkey_info prkey_info;
		struct sc_pkcs15_object     prkey_obj;

		if ((card->flags & 0x20) &&  (exposed_cert[i] == 0))
			continue;

		memset(&prkey_info, 0, sizeof(prkey_info));
		memset(&prkey_obj,  0, sizeof(prkey_obj));

		if (ckis[i].cert_found == 0 && ckis[i].pubkey_found == 0)
			continue; /* i.e. no cert or pubkey */
		
		sc_pkcs15_format_id(prkeys[i].id, &prkey_info.id);
		prkey_info.native        = 1;
		prkey_info.key_reference = prkeys[i].ref;
		sc_format_path(prkeys[i].path, &prkey_info.path);

		strncpy(prkey_obj.label, prkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		prkey_obj.flags = prkeys[i].obj_flags;
		prkey_obj.user_consent = prkeys[i].user_consent;

		if (prkeys[i].auth_id)
			sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id);

		switch (ckis[i].key_alg) {
			case SC_ALGORITHM_RSA: 
				prkey_info.usage         = prkeys[i].usage_rsa;
				prkey_info.modulus_length= ckis[i].pubkey_len;
				r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
				break;
		 	case SC_ALGORITHM_EC: 
				prkey_info.usage         = prkeys[i].usage_ec;
				prkey_info.field_length = ckis[i].pubkey_len;
				sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DEE added key_alg %2.2x prkey_obj.flags %8.8x",
					 ckis[i].key_alg, prkey_obj.flags);
				r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info);
				break;
			default:
				sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsupported key_alg %d", ckis[i].key_alg);
				r = 0; /* we just skip this one */
		}
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
	}

	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS);
}
static int
sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
{
	sc_card_t	*card = p15card->card;
	sc_context_t	*ctx = card->ctx;
	char		string[256];
	u8		buffer[256];
	size_t		length;
	int		r, i;

	set_string(&p15card->label, "OpenPGP Card");
	set_string(&p15card->manufacturer_id, "OpenPGP project");

	if ((r = read_file(card, "004f", buffer, sizeof(buffer))) < 0)
		goto failed;
	sc_bin_to_hex(buffer, (size_t)r, string, sizeof(string), 0);
	set_string(&p15card->serial_number, string);
	p15card->version = (buffer[6] << 8) | buffer[7];

	p15card->flags = SC_PKCS15_CARD_FLAG_LOGIN_REQUIRED |
			 SC_PKCS15_CARD_FLAG_PRN_GENERATION |
			 SC_PKCS15_CARD_FLAG_EID_COMPLIANT;

	/* Extract preferred language */
	r = read_file(card, "00655f2d", string, sizeof(string)-1);
	if (r < 0)
		goto failed;
	string[r] = '\0';
	set_string(&p15card->preferred_language, string);

	/* Get Application Related Data (006E) */
	if ((r = sc_get_data(card, 0x006E, buffer, sizeof(buffer))) < 0)
		goto failed;
	length = r;

	/* TBD: extract algorithm info */

	/* Get CHV status bytes:
	 *  00:		??
	 *  01-03:	max length of pins 1-3
	 *  04-07:	tries left for pins 1-3
	 */
	if ((r = read_file(card, "006E007300C4", buffer, sizeof(buffer))) < 0)
		goto failed;
	if (r != 7) {
		sc_error(ctx,
			"CHV status bytes have unexpected length "
			"(expected 7, got %d)\n", r);
		return SC_ERROR_OBJECT_NOT_VALID;
	}

	for (i = 0; i < 3; i++) {
		unsigned int	flags;

		struct sc_pkcs15_pin_info pin_info;
		struct sc_pkcs15_object   pin_obj;

		memset(&pin_info, 0, sizeof(pin_info));
		memset(&pin_obj,  0, sizeof(pin_obj));

		flags =	SC_PKCS15_PIN_FLAG_CASE_SENSITIVE |
			SC_PKCS15_PIN_FLAG_INITIALIZED |
			SC_PKCS15_PIN_FLAG_LOCAL;
		if (i == 2) {
			flags |= SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED |
				 SC_PKCS15_PIN_FLAG_SO_PIN;
		}

		pin_info.auth_id.len   = 1;
		pin_info.auth_id.value[0] = i + 1;
		pin_info.reference     = i + 1;
		pin_info.flags         = flags;
		pin_info.type          = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
		pin_info.min_length    = 0;
		pin_info.stored_length = buffer[1+i];
		pin_info.max_length    = buffer[1+i];
		pin_info.pad_char      = '\0';
		sc_format_path("3F00", &pin_info.path);
		pin_info.tries_left    = buffer[4+i];

		strlcpy(pin_obj.label, pgp_pin_name[i], sizeof(pin_obj.label));
		pin_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE;

		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}

	for (i = 0; i < 3; i++) {
		static int	prkey_pin[3] = { 1, 2, 2 };
		static int	prkey_usage[3] = {
					SC_PKCS15_PRKEY_USAGE_SIGN
					| SC_PKCS15_PRKEY_USAGE_SIGNRECOVER
					| SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
					SC_PKCS15_PRKEY_USAGE_DECRYPT
					| SC_PKCS15_PRKEY_USAGE_UNWRAP,
					SC_PKCS15_PRKEY_USAGE_NONREPUDIATION
				};

		struct sc_pkcs15_prkey_info prkey_info;
		struct sc_pkcs15_object     prkey_obj;

		memset(&prkey_info, 0, sizeof(prkey_info));
		memset(&prkey_obj,  0, sizeof(prkey_obj));

		prkey_info.id.len        = 1;
		prkey_info.id.value[0]   = i + 1;
		prkey_info.usage         = prkey_usage[i];
		prkey_info.native        = 1;
		prkey_info.key_reference = i;
		prkey_info.modulus_length= 1024;

		strlcpy(prkey_obj.label, pgp_key_name[i], sizeof(prkey_obj.label));
		prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE | SC_PKCS15_CO_FLAG_MODIFIABLE;
		prkey_obj.auth_id.len      = 1;
		prkey_obj.auth_id.value[0] = prkey_pin[i];

		r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}

	for (i = 0; i < 3; i++) {
		static int	pubkey_usage[3] = {
					SC_PKCS15_PRKEY_USAGE_VERIFY
					| SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER,
					SC_PKCS15_PRKEY_USAGE_ENCRYPT
					| SC_PKCS15_PRKEY_USAGE_WRAP,
					SC_PKCS15_PRKEY_USAGE_VERIFY
				};

		struct sc_pkcs15_pubkey_info pubkey_info;
		struct sc_pkcs15_object      pubkey_obj;

		memset(&pubkey_info, 0, sizeof(pubkey_info));
		memset(&pubkey_obj,  0, sizeof(pubkey_obj));

		pubkey_info.id.len = 1;
		pubkey_info.id.value[0] = i +1;
		pubkey_info.modulus_length = 1024;
		pubkey_info.usage    = pubkey_usage[i];
		sc_format_path(pgp_pubkey_path[i], &pubkey_info.path);

		strlcpy(pubkey_obj.label, pgp_key_name[i], sizeof(pubkey_obj.label));
		pubkey_obj.auth_id.len      = 1;
		pubkey_obj.auth_id.value[0] = 3;
		pubkey_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;

		r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}

	return 0;

failed:	sc_error(card->ctx, "Failed to initialize OpenPGP emulation: %s\n",
			sc_strerror(r));
	return r;
}
int main(int argc, char * const argv[])
{
	int err = 0, r, c, long_optind = 0;
	int do_list_readers = 0;
	int do_list_drivers = 0;
	int do_list_rdrivers = 0;
	int do_list_files = 0;
	int do_send_apdu = 0;
	int do_print_atr = 0;
	int do_print_serial = 0;
	int do_print_name = 0;
	int action_count = 0;
	const char *opt_driver = NULL;
	sc_context_param_t ctx_param;
		
	setbuf(stderr, NULL);
	setbuf(stdout, NULL);

	while (1) {
		c = getopt_long(argc, argv, "nlfr:vs:DRc:aw", options, &long_optind);
		if (c == -1)
			break;
		if (c == '?')
			print_usage_and_die(app_name, options, option_help);
		switch (c) {
		case 'l':
			do_list_readers = 1;
			action_count++;
			break;
		case 'D':
			do_list_drivers = 1;
			action_count++;
			break;
		case 'R':
			do_list_rdrivers = 1;
			action_count++;
			break;
		case 'f':
			do_list_files = 1;
			action_count++;
			break;
		case 's':
			opt_apdus = (char **) realloc(opt_apdus,
					(opt_apdu_count + 1) * sizeof(char *));
			opt_apdus[opt_apdu_count] = optarg;
			do_send_apdu++;
			if (opt_apdu_count == 0)
				action_count++;
			opt_apdu_count++;
			break;
		case 'a':
			do_print_atr = 1;
			action_count++;
			break;
		case 'n':
			do_print_name = 1;
			action_count++;
			break;
		case 'r':
			opt_reader = atoi(optarg);
			break;
		case 'v':
			verbose++;
			break;
		case 'c':
			opt_driver = optarg;
			break;
		case 'w':
			opt_wait = 1;
			break;
		case OPT_SERIAL:
			do_print_serial = 1;
			action_count++;
			break;
		}
	}
	if (action_count == 0)
		print_usage_and_die(app_name, options, option_help);

	memset(&ctx_param, 0, sizeof(ctx_param));
	ctx_param.ver      = 0;
	ctx_param.app_name = app_name;

	r = sc_context_create(&ctx, &ctx_param);
	if (r) {
		fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r));
		return 1;
	}
	if (verbose > 1)
		ctx->debug = verbose-1;
	if (do_list_rdrivers) {
		if ((err = list_reader_drivers()))
			goto end;
		action_count--;
	}
	if (do_list_readers) {
		if ((err = list_readers()))
			goto end;
		action_count--;
	}
	if (do_list_drivers) {
		if ((err = list_drivers()))
			goto end;
		action_count--;
	}
	if (action_count <= 0)
		goto end;

	if (opt_driver != NULL) {
		err = sc_set_card_driver(ctx, opt_driver);
		if (err) {
			fprintf(stderr, "Driver '%s' not found!\n", opt_driver);
			err = 1;
			goto end;
		}
	}

	err = connect_card(ctx, &card, opt_reader, 0, opt_wait, verbose);
	if (err)
		goto end;

	if (do_print_atr) {
		if (verbose) {
			printf("Card ATR:\n");
			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);
		}
		action_count--;
	}
	if (do_print_serial) {
		if (verbose)
			printf("Card serial number:");
		print_serial(card);
		action_count--;
	}
	if (do_print_name) {
		if (verbose)
			printf("Card name: ");
		printf("%s\n", card->name);
		action_count--;
	}
	if (do_send_apdu) {
		if ((err = send_apdu()))
			goto end;
		action_count--;
	}
	
	if (do_list_files) {
		if ((err = list_files()))
			goto end;
		action_count--;
	}
end:
	if (card) {
		sc_unlock(card);
		sc_disconnect_card(card, 0);
	}
	if (ctx)
		sc_release_context(ctx);
	return err;
}
Example #21
0
File: dir.c Project: AktivCo/OpenSC
static int
parse_dir_record(sc_card_t *card, u8 ** buf, size_t *buflen, int rec_nr)
{
	struct sc_context *ctx = card->ctx;
	struct sc_asn1_entry asn1_dirrecord[5], asn1_dir[2];
	scconf_block *conf_block = NULL;
	sc_app_info_t *app = NULL;
	struct sc_aid aid;
	u8 label[128], path[128], ddo[128];
	size_t label_len = sizeof(label) - 1, path_len = sizeof(path), ddo_len = sizeof(ddo);
	int r;

	LOG_FUNC_CALLED(ctx);
	aid.len = sizeof(aid.value);

	memset(label, 0, sizeof(label));
	sc_copy_asn1_entry(c_asn1_dirrecord, asn1_dirrecord);
	sc_copy_asn1_entry(c_asn1_dir, asn1_dir);
	sc_format_asn1_entry(asn1_dir + 0, asn1_dirrecord, NULL, 0);
	sc_format_asn1_entry(asn1_dirrecord + 0, aid.value, &aid.len, 0);
	sc_format_asn1_entry(asn1_dirrecord + 1, label, &label_len, 0);
	sc_format_asn1_entry(asn1_dirrecord + 2, path, &path_len, 0);
	sc_format_asn1_entry(asn1_dirrecord + 3, ddo, &ddo_len, 0);

	r = sc_asn1_decode(ctx, asn1_dir, *buf, *buflen, (const u8 **) buf, buflen);
	if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
		LOG_FUNC_RETURN(ctx, r);
	LOG_TEST_RET(ctx, r, "EF(DIR) parsing failed");

	conf_block = sc_get_conf_block(ctx, "framework", "pkcs15", 1);
	if (conf_block)   {
		scconf_block **blocks = NULL;
		char aid_str[SC_MAX_AID_STRING_SIZE];
		int ignore_app = 0;

		sc_bin_to_hex(aid.value, aid.len, aid_str, sizeof(aid_str), 0);
		blocks = scconf_find_blocks(card->ctx->conf, conf_block, "application", aid_str);
		if (blocks)   {
			ignore_app = (blocks[0] && scconf_get_str(blocks[0], "disable", 0));
                        free(blocks);
		 }

		if (ignore_app)   {
			sc_log(ctx, "Application '%s' ignored", aid_str);
			LOG_FUNC_RETURN(ctx, SC_SUCCESS);
		}
	}

	app = calloc(1, sizeof(struct sc_app_info));
	if (app == NULL)
		LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);

	memcpy(&app->aid, &aid, sizeof(struct sc_aid));

	if (asn1_dirrecord[1].flags & SC_ASN1_PRESENT)
		app->label = strdup((char *) label);
	else
		app->label = NULL;

	if (asn1_dirrecord[2].flags & SC_ASN1_PRESENT && path_len > 0) {
		/* application path present: ignore AID */
		if (path_len > SC_MAX_PATH_SIZE) {
			free(app);
			LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "Application path is too long.");
		}
		memcpy(app->path.value, path, path_len);
		app->path.len = path_len;
		app->path.type = SC_PATH_TYPE_PATH;
	}
	else {
		/* application path not present: use AID as application path */
		memcpy(app->path.value, aid.value, aid.len);
		app->path.len = aid.len;
		app->path.type = SC_PATH_TYPE_DF_NAME;
	}

	if (asn1_dirrecord[3].flags & SC_ASN1_PRESENT) {
		app->ddo.value = malloc(ddo_len);
		if (app->ddo.value == NULL) {
			free(app);
			LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate DDO value");
		}
		memcpy(app->ddo.value, ddo, ddo_len);
		app->ddo.len = ddo_len;
	} else {
		app->ddo.value = NULL;
		app->ddo.len = 0;
	}

	app->rec_nr = rec_nr;
	card->app[card->app_count] = app;
	card->app_count++;

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
Example #22
0
static int sc_pkcs15emu_atrust_acos_init(sc_pkcs15_card_t *p15card)
{
	const cdata certs[] = {
		{"C.CH.EKEY", 0, "DF71C001","1", 0},/* Decryption Certificate */
		{NULL, 0, NULL, NULL, 0}
	};

	const pindata pins[] = {
		{ "01", "PIN.DEC", "3F00DF71", 0x81, /* Decryption PIN */
		  SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
		  4, 4, 8, SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
		  SC_PKCS15_PIN_FLAG_LOCAL, -1, 0x00,
		  SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE },
		{ NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0} 
	};

	const prdata prkeys[] = {
		{ "01", "SK.CH.EKEY", 1536,
			SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP,
		  "", /* do not specify file here to prevent reset of security state */
		  0x88, "01", SC_PKCS15_CO_FLAG_PRIVATE},
		{ NULL, NULL, 0, 0, NULL, 0, NULL, 0}
	};

	int    r, i;
	u8     buf[256];
	char   buf2[256];
	sc_path_t path;
	sc_file_t *file = NULL;
	sc_card_t *card = p15card->card;

	/* get serial number */

	/* read EF_CIN_CSN file */
	sc_format_path("DF71D001", &path);
	r = sc_select_file(card, &path, NULL);
	if (r != SC_SUCCESS)
		return SC_ERROR_INTERNAL;
	r = sc_read_binary(card, 0, buf, 8, 0);
	if (r != 8)
		return SC_ERROR_INTERNAL;
	r = sc_bin_to_hex(buf, 8, buf2, sizeof(buf2), 0);
	if (r != SC_SUCCESS)
		return SC_ERROR_INTERNAL;
	if (p15card->tokeninfo->serial_number)
		free(p15card->tokeninfo->serial_number);
	p15card->tokeninfo->serial_number = malloc(strlen(buf2) + 1);
	if (!p15card->tokeninfo->serial_number)
		return SC_ERROR_INTERNAL;
	strcpy(p15card->tokeninfo->serial_number, buf2);

	/* manufacturer ID */
	if (p15card->tokeninfo->manufacturer_id)
		free(p15card->tokeninfo->manufacturer_id);
	p15card->tokeninfo->manufacturer_id = malloc(strlen(MANU_ID) + 1);
	if (!p15card->tokeninfo->manufacturer_id)
		return SC_ERROR_INTERNAL;
	strcpy(p15card->tokeninfo->manufacturer_id, MANU_ID);

	/* card label */
	if (p15card->tokeninfo->label)
		free(p15card->tokeninfo->label);
	p15card->tokeninfo->label = malloc(strlen(CARD_LABEL) + 1);
	if (!p15card->tokeninfo->label)
		return SC_ERROR_INTERNAL;
	strcpy(p15card->tokeninfo->label, CARD_LABEL);

	/* set certs */
	for (i = 0; certs[i].label; i++) {
		struct sc_pkcs15_cert_info cert_info;
		struct sc_pkcs15_object    cert_obj;

		memset(&cert_info, 0, sizeof(cert_info));
		memset(&cert_obj,  0, sizeof(cert_obj));

		sc_pkcs15_format_id(certs[i].id, &cert_info.id);
		cert_info.authority = certs[i].authority;
		sc_format_path(certs[i].path, &cert_info.path);
		if (!get_cert_len(card, &cert_info.path))
			/* skip errors */
			continue;

		strlcpy(cert_obj.label, certs[i].label, sizeof(cert_obj.label));
		cert_obj.flags = certs[i].obj_flags;

		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}
	/* set pins */
	for (i = 0; pins[i].label; i++) {
		struct sc_pkcs15_auth_info pin_info;
		struct sc_pkcs15_object   pin_obj;

		memset(&pin_info, 0, sizeof(pin_info));
		memset(&pin_obj,  0, sizeof(pin_obj));

		sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id);
		pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
		pin_info.attrs.pin.reference     = pins[i].ref;
		pin_info.attrs.pin.flags         = pins[i].flags;
		pin_info.attrs.pin.type          = pins[i].type;
		pin_info.attrs.pin.min_length    = pins[i].minlen;
		pin_info.attrs.pin.stored_length = pins[i].storedlen;
		pin_info.attrs.pin.max_length    = pins[i].maxlen;
		pin_info.attrs.pin.pad_char      = pins[i].pad_char;
		sc_format_path(pins[i].path, &pin_info.path);
		pin_info.tries_left    = -1;

		strlcpy(pin_obj.label, pins[i].label, sizeof(pin_obj.label));
		pin_obj.flags = pins[i].obj_flags;

		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}
	/* set private keys */
	for (i = 0; prkeys[i].label; i++) {
		struct sc_pkcs15_prkey_info prkey_info;
		struct sc_pkcs15_object     prkey_obj;

		memset(&prkey_info, 0, sizeof(prkey_info));
		memset(&prkey_obj,  0, sizeof(prkey_obj));

		sc_pkcs15_format_id(prkeys[i].id, &prkey_info.id);
		prkey_info.usage         = prkeys[i].usage;
		prkey_info.native        = 1;
		prkey_info.key_reference = prkeys[i].ref;
		prkey_info.modulus_length= prkeys[i].modulus_len;
		sc_format_path(prkeys[i].path, &prkey_info.path);

		strlcpy(prkey_obj.label, prkeys[i].label, sizeof(prkey_obj.label));
		prkey_obj.flags = prkeys[i].obj_flags;
		if (prkeys[i].auth_id)
			sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id);

		r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}
		
	/* select the application DF */
	sc_format_path("DF71", &path);
	r = sc_select_file(card, &path, &file);
	if (r != SC_SUCCESS || !file)
		return SC_ERROR_INTERNAL;
	/* set the application DF */
	if (p15card->file_app)
		free(p15card->file_app);
	p15card->file_app = file;

	return SC_SUCCESS;
}
Example #23
0
static int generate_pwd_shares(sc_card_t *card, char **pwd, int *pwdlen, int password_shares_threshold, int password_shares_total)
{
	int r, i;
	BIGNUM *prime;
	BIGNUM *secret;
	unsigned char buf[64];
	char hex[64];
	int l;

	secret_share_t *shares = NULL;
	secret_share_t *sp;

	u8 rngseed[16];

	if ((password_shares_threshold == -1) || (password_shares_total == -1)) {
		fprintf(stderr, "Must specify both, --pwd-shares-total and --pwd-shares-threshold\n");
		return -1;
	}

	if (password_shares_total < 3) {
		fprintf(stderr, "--pwd-shares-total must be 3 or larger\n");
		return -1;
	}

	if (password_shares_threshold < 2) {
		fprintf(stderr, "--pwd-shares-threshold must 2 or larger\n");
		return -1;
	}

	if (password_shares_threshold > password_shares_total) {
		fprintf(stderr, "--pwd-shares-threshold must be smaller or equal to --pwd-shares-total\n");
		return -1;
	}

	printf(	"\nThe DKEK will be enciphered using a randomly generated 64 bit password.\n");
	printf(	"This password is split using a (%i-of-%i) threshold scheme.\n\n", password_shares_threshold, password_shares_total);

	printf(	"Please keep the generated and encrypted DKEK file in a safe location. We also recommend \n");
	printf(	"to keep a paper printout, in case the electronic version becomes unavailable. A printable version\n");
	printf(	"of the file can be generated using \"openssl base64 -in <filename>\".\n");

	printf("\n\nPress <enter> to continue");

	waitForEnterKeyPressed();

	*pwd = calloc(1, 8);
	*pwdlen = 8;

	r = sc_get_challenge(card, (unsigned char *)*pwd, 8);
	if (r < 0) {
		printf("Error generating random key failed with %s", sc_strerror(r));
		OPENSSL_cleanse(*pwd, *pwdlen);
		free(*pwd);
		return r;
	}
	**pwd &= 0x7F; // Make sure the bit size of the secret is not bigger than 63 bits

	/*
	 * Initialize prime and secret
	 */
	prime = BN_new();
	secret = BN_new();

	/*
	 * Encode the secret value
	 */
	BN_bin2bn((unsigned char *)*pwd, *pwdlen, secret);

	/*
	 * Generate seed and calculate a prime depending on the size of the secret
	 */
	r = sc_get_challenge(card, rngseed, SEED_LENGTH);
	if (r < 0) {
		printf("Error generating random seed failed with %s", sc_strerror(r));
		OPENSSL_cleanse(*pwd, *pwdlen);
		free(*pwd);
		return r;
	}

	r = generatePrime(prime, secret, 64, rngseed, SEED_LENGTH);
	if (r < 0) {
		printf("Error generating valid prime number. Please try again.");
		OPENSSL_cleanse(*pwd, *pwdlen);
		free(*pwd);
		return r;
	}

	// Allocate data buffer for the generated shares
	shares = malloc(password_shares_total * sizeof(secret_share_t));

	createShares(secret, password_shares_threshold, password_shares_total, prime, shares);

	sp = shares;
	for (i = 0; i < password_shares_total; i++) {
		clearScreen();

		printf("Press <enter> to display key share %i of %i\n\n", i + 1, password_shares_total);
		waitForEnterKeyPressed();

		clearScreen();

		printf("Share %i of %i\n\n", i + 1, password_shares_total);

		l = BN_bn2bin(prime, buf);
		sc_bin_to_hex(buf, l, hex, 64, ':');
		printf("\nPrime       : %s\n", hex);

		printf("Share ID    : %s\n", BN_bn2dec((sp->x)));
		l = BN_bn2bin((sp->y), buf);
		sc_bin_to_hex(buf, l, hex, 64, ':');
		printf("Share value : %s\n", hex);

		printf("\n\nPlease note ALL values above and press <enter> when finished");
		waitForEnterKeyPressed();

		sp++;
	}

	clearScreen();

	cleanUpShares(shares, password_shares_total);

	BN_clear_free(prime);
	BN_clear_free(secret);

	return 0;
}
Example #24
0
static int match_atr_table(sc_context_t *ctx, const struct sc_atr_table *table, struct sc_atr *atr)
{
	u8 *card_atr_bin;
	size_t card_atr_bin_len;
	char card_atr_hex[3 * SC_MAX_ATR_SIZE];
	size_t card_atr_hex_len;
	unsigned int i = 0;

	if (ctx == NULL || table == NULL || atr == NULL)
		return -1;
	card_atr_bin = atr->value;
	card_atr_bin_len = atr->len;
	sc_bin_to_hex(card_atr_bin, card_atr_bin_len, card_atr_hex, sizeof(card_atr_hex), ':');
	card_atr_hex_len = strlen(card_atr_hex);

	sc_debug(ctx, SC_LOG_DEBUG_MATCH, "ATR     : %s", card_atr_hex);

	for (i = 0; table[i].atr != NULL; i++) {
		const char *tatr = table[i].atr;
		const char *matr = table[i].atrmask;
		size_t tatr_len = strlen(tatr);
		u8 mbin[SC_MAX_ATR_SIZE], tbin[SC_MAX_ATR_SIZE];
		size_t mbin_len, tbin_len, s, matr_len;
		size_t fix_hex_len = card_atr_hex_len;
		size_t fix_bin_len = card_atr_bin_len;

		sc_debug(ctx, SC_LOG_DEBUG_MATCH, "ATR try : %s", tatr);

		if (tatr_len != fix_hex_len) {
			sc_debug(ctx, SC_LOG_DEBUG_MATCH, "ignored - wrong length");
			continue;
		}
		if (matr != NULL) {
			sc_debug(ctx, SC_LOG_DEBUG_MATCH, "ATR mask: %s", matr);

			matr_len = strlen(matr);
			if (tatr_len != matr_len)
				continue;
			tbin_len = sizeof(tbin);
			sc_hex_to_bin(tatr, tbin, &tbin_len);
			mbin_len = sizeof(mbin);
			sc_hex_to_bin(matr, mbin, &mbin_len);
			if (mbin_len != fix_bin_len) {
				sc_debug(ctx, SC_LOG_DEBUG_MATCH, "length of atr and atr mask do not match - ignored: %s - %s", tatr, matr);
				continue;
			}
			for (s = 0; s < tbin_len; s++) {
				/* reduce tatr with mask */
				tbin[s] = (tbin[s] & mbin[s]);
				/* create copy of card_atr_bin masked) */
				mbin[s] = (card_atr_bin[s] & mbin[s]);
			}
			if (memcmp(tbin, mbin, tbin_len) != 0)
				continue;
		} else {
			if (strncasecmp(tatr, card_atr_hex, tatr_len) != 0)
				continue;
		}
		return i;
	}
	return -1;
}
static int sc_pkcs15emu_starcert_init(sc_pkcs15_card_t *p15card)
{
	const cdata certs[] = {
		{"DS certificate", 0, "3F00DF01C000","1",
			SC_PKCS15_CO_FLAG_MODIFIABLE},
		{"CA certificate", 1, "3F00DF01C008","2",
			SC_PKCS15_CO_FLAG_MODIFIABLE},
		{"KE certificate", 0, "3F00DF01C200","3",
			SC_PKCS15_CO_FLAG_MODIFIABLE},
		{"AUT certificate",0, "3F00DF01C500","4",
			SC_PKCS15_CO_FLAG_MODIFIABLE},
		{NULL, 0, NULL, NULL, 0}
	};

	const pindata pins[] = {
		{ "99", "DS pin", "3F00DF01", 0x99,
		  SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
		  8, 8, 8, SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
		  SC_PKCS15_PIN_FLAG_LOCAL, -1, 0x00,
		  SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE },
		{ NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	};

	const prdata prkeys[] = {
		{ "1", "DS key", 1024, USAGE_NONREP, "3F00DF01",
		  0x84, "99", SC_PKCS15_CO_FLAG_PRIVATE},
		{ "3", "KE key", 1024, USAGE_KE, "3F00DF01",
		  0x85, NULL, SC_PKCS15_CO_FLAG_PRIVATE},
		{ "4", "AUT key", 1024, USAGE_AUT, "3F00DF01",
		  0x82, NULL, SC_PKCS15_CO_FLAG_PRIVATE},
		{ NULL, NULL, 0, 0, NULL, 0, NULL, 0}
	};

	int    r, i;
	char   buf[256];
	sc_path_t path;
	sc_file_t *file = NULL;
	sc_card_t *card = p15card->card;
	sc_serial_number_t serial;

	/* get serial number */
	r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
	r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
	if (r != SC_SUCCESS)
		return SC_ERROR_INTERNAL;
	if (p15card->serial_number)
		free(p15card->serial_number);
	p15card->serial_number = (char *) malloc(strlen(buf) + 1);
	if (!p15card->serial_number)
		return SC_ERROR_INTERNAL;
	strcpy(p15card->serial_number, buf);
	/* the TokenInfo version number */
	p15card->version = 0;
	/* the manufacturer ID, in this case Giesecke & Devrient GmbH */
	if (p15card->manufacturer_id)
		free(p15card->manufacturer_id);
	p15card->manufacturer_id = (char *) malloc(strlen(MANU_ID) + 1);
	if (!p15card->manufacturer_id)
		return SC_ERROR_INTERNAL;
	strcpy(p15card->manufacturer_id, MANU_ID);

	/* set certs */
	for (i = 0; certs[i].label; i++) {
		struct sc_pkcs15_cert_info cert_info;
		struct sc_pkcs15_object    cert_obj;

		memset(&cert_info, 0, sizeof(cert_info));
		memset(&cert_obj,  0, sizeof(cert_obj));

		sc_pkcs15_format_id(certs[i].id, &cert_info.id);
		cert_info.authority = certs[i].authority;
		sc_format_path(certs[i].path, &cert_info.path);
		if (!get_cert_len(card, &cert_info.path))
			/* skip errors */
			continue;

		strlcpy(cert_obj.label, certs[i].label, sizeof(cert_obj.label));
		cert_obj.flags = certs[i].obj_flags;

		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}
	/* set pins */
	for (i = 0; pins[i].label; i++) {
		struct sc_pkcs15_pin_info pin_info;
		struct sc_pkcs15_object   pin_obj;

		memset(&pin_info, 0, sizeof(pin_info));
		memset(&pin_obj,  0, sizeof(pin_obj));

		sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id);
		pin_info.reference     = pins[i].ref;
		pin_info.flags         = pins[i].flags;
		pin_info.type          = pins[i].type;
		pin_info.min_length    = pins[i].minlen;
		pin_info.stored_length = pins[i].storedlen;
		pin_info.max_length    = pins[i].maxlen;
		pin_info.pad_char      = pins[i].pad_char;
		sc_format_path(pins[i].path, &pin_info.path);
		pin_info.tries_left    = -1;

		strlcpy(pin_obj.label, pins[i].label, sizeof(pin_obj.label));
		pin_obj.flags = pins[i].obj_flags;

		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}
	/* set private keys */
	for (i = 0; prkeys[i].label; i++) {
		struct sc_pkcs15_prkey_info prkey_info;
		struct sc_pkcs15_object     prkey_obj;

		memset(&prkey_info, 0, sizeof(prkey_info));
		memset(&prkey_obj,  0, sizeof(prkey_obj));

		sc_pkcs15_format_id(prkeys[i].id, &prkey_info.id);
		prkey_info.usage         = prkeys[i].usage;
		prkey_info.native        = 1;
		prkey_info.key_reference = prkeys[i].ref;
		prkey_info.modulus_length= prkeys[i].modulus_len;
		sc_format_path(prkeys[i].path, &prkey_info.path);

		strlcpy(prkey_obj.label, prkeys[i].label, sizeof(prkey_obj.label));
		prkey_obj.flags = prkeys[i].obj_flags;
		if (prkeys[i].auth_id)
			sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id);

		r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}
		
	/* select the application DF */
	sc_format_path("3F00DF01", &path);
	r = sc_select_file(card, &path, &file);
	if (r != SC_SUCCESS || !file)
		return SC_ERROR_INTERNAL;
	/* set the application DF */
	if (p15card->file_app)
		free(p15card->file_app);
	p15card->file_app = file;

	return SC_SUCCESS;
}
static int infocamere_1200_init(sc_pkcs15_card_t * p15card)
{
	const int prkey_usage = SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
	const int authprkey_usage = SC_PKCS15_PRKEY_USAGE_SIGN
	    | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER
	    | SC_PKCS15_PRKEY_USAGE_ENCRYPT
	    | SC_PKCS15_PRKEY_USAGE_DECRYPT;

	sc_card_t *card = p15card->card;
	sc_path_t path;
	sc_file_t *file;
	sc_pkcs15_id_t id, auth_id;
	unsigned char buffer[256];
	unsigned char ef_gdo[256];
	char serial[256];
	unsigned char certlen[2];
	int authority, change_sign = 0;
	struct sc_pkcs15_cert_info cert_info;
        struct sc_pkcs15_object    cert_obj;

	const char *label = "User Non-repudiation Certificate";
	const char *calabel = "CA Certificate";
	const char *authlabel = "User Authentication Certificate";

	const char *infocamere_cert_path[2] = {
		"DF01C000",
		"3F00000011111A02"
	};

	const char *infocamere_auth_certpath[2] = {
		"11111A02",
		"000011111B02"
	};

	const char *infocamere_cacert_path[2] = {
		"DF01C008",
		"000011114101"
	};

	const char *infocamere_auth_path[2] = {
		"3F001111",
		"3F0000001111"
	};

	const char *infocamere_nrepud_path[2] = {
		"3F00DF01",
		"3F0000001111"
	};

	const int infocamere_idpin_auth_obj[2] = {
		0x95,
		0x81
	};

	const int infocamere_idpin_nrepud_obj[2] = {
		0x99,
		0x81
	};

	const int infocamere_idprkey_auth_obj[2] = {
		0x9B,
		0x01
	};

	const int infocamere_idprkey_nrepud_obj[2] = {
		0x84,
		0x01
	};

	const char *authPIN = "Authentication PIN";
	const char *nonrepPIN = "Non-repudiation PIN";

	const char *authPRKEY = "Authentication Key";
	const char *nonrepPRKEY = "Non repudiation Key";

	const int flags = SC_PKCS15_PIN_FLAG_CASE_SENSITIVE |
	    SC_PKCS15_PIN_FLAG_INITIALIZED |
	    SC_PKCS15_PIN_FLAG_NEEDS_PADDING;

	int r, len_iccsn, len_chn;

	sc_format_path("3F002F02", &path);

	sc_ctx_suppress_errors_on(card->ctx);
	r = sc_select_file(card, &path, &file);
	sc_ctx_suppress_errors_off(card->ctx);
	
	if (r != SC_SUCCESS || file->size > 255) {
		/* Not EF.GDO */
		return SC_ERROR_WRONG_CARD;
	}

	sc_read_binary(card, 0, ef_gdo, file->size, 0);

	if (ef_gdo[0] != 0x5A || file->size < 3) {
		/* Not EF.GDO */
		return SC_ERROR_WRONG_CARD;
	}

	len_iccsn = ef_gdo[1];

	memcpy(buffer, ef_gdo + 2, len_iccsn);

	sc_bin_to_hex(buffer, len_iccsn, serial, sizeof(serial), 0);

	if (file->size < (size_t) (len_iccsn + 5)) {
		/* Not CHN */
		return SC_ERROR_WRONG_CARD;
	}

	if (!
	    (ef_gdo[len_iccsn + 2] == 0x5F
	     && ef_gdo[len_iccsn + 3] == 0x20)) {
		/* Not CHN */
		return SC_ERROR_WRONG_CARD;
	}

	len_chn = ef_gdo[len_iccsn + 4];

	if (len_chn < 2 || len_chn > 8) {
		/* Length CHN incorrect */
		return SC_ERROR_WRONG_CARD;
	}

	if (!
	    (ef_gdo[len_iccsn + 5] == 0x12
	     && (ef_gdo[len_iccsn + 6] == 0x02
		 || ef_gdo[len_iccsn + 6] == 0x03))) {
		/* Not Infocamere Card */
		return SC_ERROR_WRONG_CARD;
	}

	set_string(&p15card->serial_number, serial);

	if (ef_gdo[len_iccsn + 6] == 0x02)
		set_string(&p15card->label, "Infocamere 1202 Card");
	else {
		set_string(&p15card->label, "Infocamere 1203 Card");
		change_sign = 1;
	}

	set_string(&p15card->manufacturer_id, "Infocamere");

	authority = 0;

	/* Get the authentication certificate length */

	sc_format_path(infocamere_auth_certpath[ef_gdo[len_iccsn+6]-2], &path);

	sc_ctx_suppress_errors_on(card->ctx);
	r = sc_select_file(card, &path, NULL);
	sc_ctx_suppress_errors_off(card->ctx);

	if (r >= 0) {

		sc_read_binary(card, 0, certlen, 2, 0);

		/* Now set the certificate offset/len */

		path.index = 2;
		path.count = (certlen[1] << 8) + certlen[0];

		memset(&cert_info, 0, sizeof(cert_info));
                memset(&cert_obj,  0, sizeof(cert_obj));

		sc_pkcs15_format_id("1", &cert_info.id);
        	cert_info.authority = authority;
        	cert_info.path = path;
		strlcpy(cert_obj.label, authlabel, sizeof(cert_obj.label));
	        cert_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;

		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
        	if (r < 0)
        		return SC_ERROR_INTERNAL;

		/* XXX: the IDs for the key/pin in case of the 1203 type 
		 * are wrong, therefore I disable them for now -- Nils */
		if (!change_sign) {    
		/* add authentication PIN */

                sc_format_path(infocamere_auth_path[ef_gdo[len_iccsn+6]-2], &path);
                
		sc_pkcs15_format_id("1", &id);
		sc_pkcs15emu_add_pin(p15card, &id,
                                authPIN, &path, infocamere_idpin_auth_obj[ef_gdo[len_iccsn+6]-2],
                                SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
                                5, 8, flags, 3, 0, 
				SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE);

		/* add authentication private key */

		auth_id.value[0] = 1;
		auth_id.len = 1;

		sc_pkcs15emu_add_prkey(p15card, &id,
				authPRKEY,
				SC_PKCS15_TYPE_PRKEY_RSA, 
				1024, authprkey_usage,
				&path, infocamere_idprkey_auth_obj[ef_gdo[len_iccsn+6]-2],
				&auth_id, SC_PKCS15_CO_FLAG_PRIVATE);
		}

	}

	/* Get the non-repudiation certificate length */

	sc_format_path(infocamere_cert_path[ef_gdo[len_iccsn+6]-2], &path);

	if (sc_select_file(card, &path, NULL) < 0)
		{
		return SC_ERROR_INTERNAL;
		}

	sc_read_binary(card, 0, certlen, 2, 0);

	/* Now set the certificate offset/len */
	path.index = 2;
	path.count = (certlen[1] << 8) + certlen[0];
	
        memset(&cert_info, 0, sizeof(cert_info));
        memset(&cert_obj,  0, sizeof(cert_obj));

	sc_pkcs15_format_id("2", &cert_info.id);

        cert_info.authority = authority;
        cert_info.path = path;
        strlcpy(cert_obj.label, label, sizeof(cert_obj.label));
        cert_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;

	r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
        if (r < 0)
        	return SC_ERROR_INTERNAL;

	/* Get the CA certificate length */

	authority = 1;

	sc_format_path(infocamere_cacert_path[ef_gdo[len_iccsn+6]-2], &path);

	sc_ctx_suppress_errors_on(card->ctx);
	r = sc_select_file(card, &path, NULL);
	sc_ctx_suppress_errors_off(card->ctx);

	if (r >= 0) {
		size_t len;

		sc_read_binary(card, 0, certlen, 2, 0);

		len = (certlen[1] << 8) + certlen[0];

		if (len != 0) {
			/* Now set the certificate offset/len */
			path.index = 2;
			path.count = len;

			memset(&cert_info, 0, sizeof(cert_info));
	                memset(&cert_obj,  0, sizeof(cert_obj));

			sc_pkcs15_format_id("3", &cert_info.id);
	        	cert_info.authority = authority;
	        	cert_info.path = path;
	        	strlcpy(cert_obj.label, calabel, sizeof(cert_obj.label));
		        cert_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;

			r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
        		if (r < 0)
        		return SC_ERROR_INTERNAL;
		}
	}

        /* add non repudiation PIN */

	sc_format_path(infocamere_nrepud_path[ef_gdo[len_iccsn+6]-2], &path);

	sc_pkcs15_format_id("2", &id);
	sc_pkcs15emu_add_pin(p15card, &id,
		nonrepPIN, &path, infocamere_idpin_nrepud_obj[ef_gdo[len_iccsn+6]-2],
		SC_PKCS15_PIN_TYPE_ASCII_NUMERIC, 5, 8, flags, 3, 0,
		SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE);


	/* add non repudiation private key */

	auth_id.value[0] = 2;
	auth_id.len = 1;

	sc_pkcs15emu_add_prkey(p15card, &id, nonrepPRKEY,
			       SC_PKCS15_TYPE_PRKEY_RSA, 
                               1024, prkey_usage,
                               &path, infocamere_idprkey_nrepud_obj[ef_gdo[len_iccsn+6]-2],
                               &auth_id, SC_PKCS15_CO_FLAG_PRIVATE);


	/* return to MF */
	sc_format_path("3F00", &path);
	r = sc_select_file(card, &path, NULL);
	if (r != SC_SUCCESS)
		return r;

	if (change_sign) {
		/* save old signature funcs */
		set_security_env = card->ops->set_security_env;
		/* set new one */
		card->ops->set_security_env = set_sec_env;
		card->ops->compute_signature = do_sign;
	}

	return SC_SUCCESS;
}
Example #27
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;
}