diff --git a/src/libopensc/card-sc-hsm.c b/src/libopensc/card-sc-hsm.c index 1326ff18..516964ad 100644 --- a/src/libopensc/card-sc-hsm.c +++ b/src/libopensc/card-sc-hsm.c @@ -134,6 +134,21 @@ static int sc_hsm_match_card(struct sc_card *card) +static int sc_hsm_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, + int *tries_left) +{ + sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data; + + if (data->pin_reference == 0x88) { + // Save SO PIN for later use in init pin + memcpy(priv->initpw, data->pin1.data, sizeof(priv->initpw)); + return SC_SUCCESS; + } + return (*iso_ops->pin_cmd)(card, data, tries_left); +} + + + static int sc_hsm_read_binary(sc_card_t *card, unsigned int idx, u8 *buf, size_t count, unsigned long flags) @@ -560,7 +575,111 @@ static int sc_hsm_get_serialnr(sc_card_t *card, sc_serial_number_t *serial) serial->len = strlen(priv->serialno); strncpy(serial->value, priv->serialno, sizeof(serial->value)); - return 0; + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + + + +static int sc_hsm_init_token(sc_card_t *card, sc_cardctl_pkcs11_init_token_t *params) +{ + sc_context_t *ctx = card->ctx; + int r, i; + sc_apdu_t apdu; + u8 ibuff[50], *p; + + LOG_FUNC_CALLED(card->ctx); + + if (params->so_pin_len != 16) { + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "SO PIN wrong length (!=16)"); + } + + p = ibuff; + *p++ = 0x80; // Options + *p++ = 0x02; + *p++ = 0x00; + *p++ = 0x01; + + *p++ = 0x81; // User PIN + *p++ = 0x06; // Default value, later changed with C_InitPIN + // We use only 6 of the 16 bytes init password for the initial user PIN + memcpy(p, params->so_pin, 6); + p += 6; + + *p++ = 0x82; // Initialization code + *p++ = 0x08; + + memset(p, 0, 8); + for (i = 0; i < 16; i++) { + *p <<= 4; + *p |= params->so_pin[i] & 0xf; + if (i & 1) + p++; + } + + *p++ = 0x91; // User PIN retry counter + *p++ = 0x01; + *p++ = 0x03; + + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x50, 0x00, 0x00); + apdu.cla = 0x80; + apdu.data = ibuff; + apdu.datalen = p - ibuff; + apdu.lc = apdu.datalen; + + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(ctx, r, "APDU transmit failed"); + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + + if (r == SC_ERROR_NOT_ALLOWED) { + r = SC_ERROR_PIN_CODE_INCORRECT; + } + + LOG_TEST_RET(ctx, r, "Check SW error"); + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + + + +static int sc_hsm_init_pin(sc_card_t *card, sc_cardctl_pkcs11_init_pin_t *params) +{ + sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data; + sc_context_t *ctx = card->ctx; + int r; + sc_apdu_t apdu; + u8 ibuff[50], *p; + + LOG_FUNC_CALLED(card->ctx); + + if (params->pin_len > 16) { + LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "User PIN too long"); + } + + p = ibuff; + + // We use only 6 of the 8 bytes init password for the initial user PIN + memcpy(p, priv->initpw, 6); + p += 6; + + memcpy(p, params->pin, params->pin_len); + p += params->pin_len; + + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x24, 0x00, 0x81); + apdu.data = ibuff; + apdu.datalen = p - ibuff; + apdu.lc = apdu.datalen; + + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(ctx, r, "APDU transmit failed"); + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + LOG_TEST_RET(ctx, r, "Check SW error"); + + memset(priv->initpw, 0, sizeof(priv->initpw)); + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } @@ -609,6 +728,10 @@ static int sc_hsm_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) switch (cmd) { case SC_CARDCTL_GET_SERIALNR: return sc_hsm_get_serialnr(card, (sc_serial_number_t *)ptr); + case SC_CARDCTL_PKCS11_INIT_TOKEN: + return sc_hsm_init_token(card, (sc_cardctl_pkcs11_init_token_t *)ptr); + case SC_CARDCTL_PKCS11_INIT_PIN: + return sc_hsm_init_pin(card, (sc_cardctl_pkcs11_init_pin_t *)ptr); case SC_CARDCTL_SC_HSM_GENERATE_KEY: return sc_hsm_generate_keypair(card, (sc_cardctl_sc_hsm_keygen_info_t *)ptr); } @@ -693,6 +816,7 @@ static struct sc_card_driver * sc_get_driver(void) sc_hsm_ops.init = sc_hsm_init; sc_hsm_ops.finish = sc_hsm_finish; sc_hsm_ops.card_ctl = sc_hsm_card_ctl; + sc_hsm_ops.pin_cmd = sc_hsm_pin_cmd; /* no record oriented file services */ sc_hsm_ops.read_record = NULL; diff --git a/src/libopensc/card-sc-hsm.h b/src/libopensc/card-sc-hsm.h index 26f0f11d..370641bf 100644 --- a/src/libopensc/card-sc-hsm.h +++ b/src/libopensc/card-sc-hsm.h @@ -54,6 +54,7 @@ typedef struct sc_hsm_private_data { u8 algorithm; int noExtLength; char *serialno; + char initpw[6]; // Initial user PIN set at initialization (first 6 digits of token pin) } sc_hsm_private_data_t; diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h index 3abc7546..caa23989 100644 --- a/src/libopensc/cardctl.h +++ b/src/libopensc/cardctl.h @@ -42,6 +42,8 @@ enum { SC_CARDCTL_GET_SERIALNR, SC_CARDCTL_GET_SE_INFO, SC_CARDCTL_GET_CHV_REFERENCE_IN_SE, + SC_CARDCTL_PKCS11_INIT_TOKEN, + SC_CARDCTL_PKCS11_INIT_PIN, /* * GPK specific calls @@ -263,6 +265,23 @@ struct sc_cardctl_default_key { u8 * key_data; /* out: key data */ }; +/* + * Generic cardctl - initialize token using PKCS#11 style + */ +typedef struct sc_cardctl_pkcs11_init_token { + const char * so_pin; + size_t so_pin_len; + const char * label; +} sc_cardctl_pkcs11_init_token_t; + +/* + * Generic cardctl - set pin using PKCS#11 style + */ +typedef struct sc_cardctl_pkcs11_init_pin { + const char * pin; + size_t pin_len; +} sc_cardctl_pkcs11_init_pin_t; + /* * GPK lock file. * Parent DF of file must be selected. diff --git a/src/libopensc/pkcs15-sc-hsm.c b/src/libopensc/pkcs15-sc-hsm.c index a28f3254..3db07198 100644 --- a/src/libopensc/pkcs15-sc-hsm.c +++ b/src/libopensc/pkcs15-sc-hsm.c @@ -473,7 +473,7 @@ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card) LOG_FUNC_CALLED(card->ctx); p15card->tokeninfo->label = strdup("SmartCard-HSM"); - p15card->tokeninfo->manufacturer_id = strdup("CardContact"); + p15card->tokeninfo->manufacturer_id = strdup("www.CardContact.de"); appinfo = calloc(1, sizeof(struct sc_app_info)); @@ -552,6 +552,31 @@ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card) if (r < 0) LOG_FUNC_RETURN(card->ctx, r); + + memset(&pin_info, 0, sizeof(pin_info)); + memset(&pin_obj, 0, sizeof(pin_obj)); + + pin_info.auth_id.len = 1; + pin_info.auth_id.value[0] = 2; + pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN; + pin_info.attrs.pin.reference = 0x88; + pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_LOCAL|SC_PKCS15_PIN_FLAG_CHANGE_DISABLED|SC_PKCS15_PIN_FLAG_INITIALIZED|SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED|SC_PKCS15_PIN_FLAG_SO_PIN; + pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_BCD; + pin_info.attrs.pin.min_length = 16; + pin_info.attrs.pin.stored_length = 0; + pin_info.attrs.pin.max_length = 16; + pin_info.attrs.pin.pad_char = '\0'; + pin_info.tries_left = 3; + pin_info.max_tries = 3; + + strlcpy(pin_obj.label, "SOPIN", sizeof(pin_obj.label)); + pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE; + + r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info); + if (r < 0) + LOG_FUNC_RETURN(card->ctx, r); + + filelistlength = sc_list_files(card, filelist, sizeof(filelist)); LOG_TEST_RET(card->ctx, filelistlength, "Could not enumerate file and key identifier"); diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index 8fffabee..69f4fb86 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -22,6 +22,8 @@ #include "libopensc/log.h" #include "libopensc/asn1.h" +#include "libopensc/cardctl.h" + #include #include @@ -1637,7 +1639,43 @@ pkcs15_change_pin(struct sc_pkcs11_slot *slot, return sc_to_cryptoki_error(rc, "C_SetPIN"); } + + #ifdef USE_PKCS15_INIT +static CK_RV +pkcs15_initialize(struct sc_pkcs11_card *p11card, void *ptr, + CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen, + CK_UTF8CHAR_PTR pLabel) +{ + struct sc_cardctl_pkcs11_init_token args; + int rv; + + memset(&args, 0, sizeof(args)); + args.so_pin = pPin; + args.so_pin_len = ulPinLen; + args.label = (const char *) pLabel; + + rv = sc_card_ctl(p11card->card, SC_CARDCTL_PKCS11_INIT_TOKEN, &args); + + if (rv == SC_ERROR_NOT_SUPPORTED) + return CKR_FUNCTION_NOT_SUPPORTED; + + if (rv < 0) + return sc_to_cryptoki_error(rv, "C_InitToken"); + + rv = card_removed(p11card->reader); + if (rv != SC_SUCCESS) + return rv; + + rv = card_detect_all(); + if (rv != SC_SUCCESS) + return rv; + + return CKR_OK; +} + + + static CK_RV pkcs15_init_pin(struct sc_pkcs11_slot *slot, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) { @@ -1647,8 +1685,21 @@ pkcs15_init_pin(struct sc_pkcs11_slot *slot, CK_CHAR_PTR pPin, CK_ULONG ulPinLen struct sc_profile *profile = NULL; struct sc_pkcs15_object *auth_obj = NULL; struct sc_pkcs15_auth_info *auth_info = NULL; + struct sc_cardctl_pkcs11_init_pin p11args; int rc; + memset(&p11args, 0, sizeof(p11args)); + p11args.pin = pPin; + p11args.pin_len = ulPinLen; + + rc = sc_card_ctl(p11card->card, SC_CARDCTL_PKCS11_INIT_PIN, &p11args); + + if (rc != SC_ERROR_NOT_SUPPORTED) { + if (rc == SC_SUCCESS) + return CKR_OK; + return sc_to_cryptoki_error(rc, "C_InitPin"); + } + sc_log(context, "Init PIN: pin %p:%d; unblock style %i", pPin, ulPinLen, sc_pkcs11_conf.pin_unblock_style); fw_data = (struct pkcs15_fw_data *) p11card->fws_data[slot->fw_data_idx]; @@ -2802,7 +2853,7 @@ struct sc_pkcs11_framework_ops framework_pkcs15 = { pkcs15_login, pkcs15_logout, pkcs15_change_pin, - NULL, /* init_token */ + pkcs15_initialize, #ifdef USE_PKCS15_INIT pkcs15_init_pin, pkcs15_create_object,