diff --git a/doc/tools/sc-hsm-tool.1.xml b/doc/tools/sc-hsm-tool.1.xml index 3e76aacb..f65fe7e1 100644 --- a/doc/tools/sc-hsm-tool.1.xml +++ b/doc/tools/sc-hsm-tool.1.xml @@ -45,6 +45,7 @@ Use to define the initial user pin value. Use to define the maximum number of wrong user PIN presentations. Use with to enable key wrap / unwrap. + Use with to define a token label @@ -180,6 +181,14 @@ + + + label, + label + + Define the token label to be used in --initialize. + + num, @@ -217,7 +226,7 @@ Create a DKEK share with random password split up using a (3, 5) threshold scheme: sc-hsm-tool --create-dkek-share dkek-share-1.pbe --pwd-shares-threshold 3 --pwd-shares-total 5 Initialize SmartCard-HSM to use a single DKEK share: - sc-hsm-tool --initialize --so-pin 3537363231383830 --pin 648219 --dkek-shares 1 + sc-hsm-tool --initialize --so-pin 3537363231383830 --pin 648219 --dkek-shares 1 --label mytoken Import DKEK share: sc-hsm-tool --import-dkek-share dkek-share-1.pbe Import DKEK share using a password split up using a (3, 5) threshold scheme for encryption: diff --git a/src/libopensc/card-sc-hsm.c b/src/libopensc/card-sc-hsm.c index ea9bf324..d0b9108b 100644 --- a/src/libopensc/card-sc-hsm.c +++ b/src/libopensc/card-sc-hsm.c @@ -227,9 +227,9 @@ static int sc_hsm_read_binary(sc_card_t *card, -static int sc_hsm_update_binary(sc_card_t *card, - unsigned int idx, const u8 *buf, size_t count, - unsigned long flags) +static int sc_hsm_write_ef(sc_card_t *card, + int fid, + unsigned int idx, const u8 *buf, size_t count) { sc_context_t *ctx = card->ctx; sc_apdu_t apdu; @@ -267,10 +267,11 @@ static int sc_hsm_update_binary(sc_card_t *card, len = 8; } - memcpy(p, buf, count); + if (buf != NULL) + memcpy(p, buf, count); len += count; - sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xD7, 0x00, 0x00); + sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xD7, fid >> 8, fid & 0xFF); apdu.data = cmdbuff; apdu.datalen = len; apdu.lc = len; @@ -287,6 +288,15 @@ static int sc_hsm_update_binary(sc_card_t *card, +static int sc_hsm_update_binary(sc_card_t *card, + unsigned int idx, const u8 *buf, size_t count, + unsigned long flags) +{ + return sc_hsm_write_ef(card, 0, idx, buf, count); +} + + + static int sc_hsm_list_files(sc_card_t *card, u8 * buf, size_t buflen) { sc_apdu_t apdu; @@ -322,23 +332,12 @@ static int sc_hsm_list_files(sc_card_t *card, u8 * buf, size_t buflen) static int sc_hsm_create_file(sc_card_t *card, sc_file_t *file) { - sc_context_t *ctx = card->ctx; - sc_apdu_t apdu; - u8 cmdbuff[] = { 0x54, 0x02, 0x00, 0x00, 0x53, 0x00 }; int r; - sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD7, file->id >> 8, file->id & 0xFF); - apdu.data = cmdbuff; - apdu.datalen = sizeof(cmdbuff); - apdu.lc = sizeof(cmdbuff); + r = sc_hsm_write_ef(card, file->id, 0, NULL, 0); + LOG_TEST_RET(card->ctx, r, "Create file failed"); - 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"); - - LOG_FUNC_RETURN(ctx, SC_SUCCESS); + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } @@ -432,7 +431,8 @@ static int sc_hsm_decode_ecdsa_signature(sc_card_t *card, const u8 * data, size_t datalen, u8 * out, size_t outlen) { - int fieldsizebytes, i, r; + int i, r; + size_t fieldsizebytes; const u8 *body, *tag; size_t bodylen, taglen; @@ -620,7 +620,10 @@ static int sc_hsm_get_serialnr(sc_card_t *card, sc_serial_number_t *serial) static int sc_hsm_initialize(sc_card_t *card, sc_cardctl_sc_hsm_init_param_t *params) { sc_context_t *ctx = card->ctx; + sc_pkcs15_tokeninfo_t ti; + struct sc_pin_cmd_data pincmd; int r; + size_t tilen; sc_apdu_t apdu; u8 ibuff[50], *p; @@ -669,6 +672,29 @@ static int sc_hsm_initialize(sc_card_t *card, sc_cardctl_sc_hsm_init_param_t *pa LOG_TEST_RET(ctx, r, "Check SW error"); + if (params->label) { + memset(&ti, 0, sizeof(ti)); + + ti.label = params->label; + ti.flags = SC_PKCS15_TOKEN_PRN_GENERATION; + + r = sc_pkcs15_encode_tokeninfo(ctx, &ti, &p, &tilen); + LOG_TEST_RET(ctx, r, "Error encoding tokeninfo"); + + memset(&pincmd, 0, sizeof(pincmd)); + pincmd.cmd = SC_PIN_CMD_VERIFY; + pincmd.pin_type = SC_AC_CHV; + pincmd.pin_reference = 0x81; + pincmd.pin1.data = params->user_pin; + pincmd.pin1.len = params->user_pin_len; + + r = (*iso_ops->pin_cmd)(card, &pincmd, NULL); + LOG_TEST_RET(ctx, r, "Could not verify PIN"); + + r = sc_hsm_write_ef(card, 0x2F03, 0, p, tilen); + LOG_TEST_RET(ctx, r, "Could not write EF.TokenInfo"); + } + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); } @@ -784,32 +810,27 @@ static int sc_hsm_unwrap_key(sc_card_t *card, sc_cardctl_sc_hsm_wrapped_key_t *p static int sc_hsm_init_token(sc_card_t *card, sc_cardctl_pkcs11_init_token_t *params) { sc_context_t *ctx = card->ctx; + sc_cardctl_sc_hsm_init_param_t ip; int r, i; - sc_apdu_t apdu; - u8 ibuff[50], *p; + u8 *p; + char label[33],*cpo; - LOG_FUNC_CALLED(card->ctx); + LOG_FUNC_CALLED(ctx); if (params->so_pin_len != 16) { - LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "SO PIN wrong length (!=16)"); + LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "SO PIN wrong length (!=16)"); } - p = ibuff; - *p++ = 0x80; // Options - *p++ = 0x02; - *p++ = 0x00; - *p++ = 0x01; + memset(&ip, 0, sizeof(ip)); + ip.dkek_shares = -1; + ip.options[0] = 0x00; + ip.options[0] = 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; + ip.user_pin = (unsigned char *)params->so_pin; // Use the first 6 digits of the SO-PIN as initial User-PIN value + ip.user_pin_len = 6; + ip.user_pin_retry_counter = 3; - *p++ = 0x82; // Initialization code - *p++ = 0x08; - - memset(p, 0, 8); + p = ip.init_code; for (i = 0; i < 16; i++) { *p <<= 4; *p |= params->so_pin[i] & 0xf; @@ -817,28 +838,22 @@ static int sc_hsm_init_token(sc_card_t *card, sc_cardctl_pkcs11_init_token_t *pa 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; + if (params->label) { + // Strip trailing spaces + memcpy(label, params->label, 32); + label[32] = 0; + cpo = label + 31; + while ((cpo >= label) && (*cpo == ' ')) { + *cpo = 0; + cpo--; + } + ip.label = label; } + r = sc_hsm_initialize(card, &ip); LOG_TEST_RET(ctx, r, "Check SW error"); - LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); + LOG_FUNC_RETURN(ctx, SC_SUCCESS); } diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h index 3c426ed6..b46185ab 100644 --- a/src/libopensc/cardctl.h +++ b/src/libopensc/cardctl.h @@ -938,8 +938,9 @@ typedef struct sc_cardctl_sc_hsm_init_param { u8 *user_pin; /* Initial user PIN */ size_t user_pin_len; /* Length of user PIN */ u8 user_pin_retry_counter; /* Retry counter default value */ - u8 options[2]; /* Initilization options */ + u8 options[2]; /* Initialization options */ char dkek_shares; /* Number of DKEK shares, 0 for card generated, -1 for none */ + char *label; /* Token label to be set in EF.TokenInfo (2F03) */ } sc_cardctl_sc_hsm_init_param_t; typedef struct sc_cardctl_sc_hsm_dkek { diff --git a/src/libopensc/pkcs15-sc-hsm.c b/src/libopensc/pkcs15-sc-hsm.c index df7cda4c..fa9157cd 100644 --- a/src/libopensc/pkcs15-sc-hsm.c +++ b/src/libopensc/pkcs15-sc-hsm.c @@ -514,6 +514,33 @@ static int sc_pkcs15emu_sc_hsm_add_cd(sc_pkcs15_card_t * p15card, u8 id) { +static int sc_pkcs15emu_sc_hsm_read_tokeninfo (sc_pkcs15_card_t * p15card) +{ + sc_card_t *card = p15card->card; + sc_file_t *file = NULL; + sc_path_t path; + int r; + u8 efbin[512]; + + LOG_FUNC_CALLED(card->ctx); + + /* Read token info */ + sc_path_set(&path, SC_PATH_TYPE_FILE_ID, (u8 *) "\x2F\x03", 2, 0, 0); + r = sc_select_file(card, &path, &file); + LOG_TEST_RET(card->ctx, r, "Could not select EF.TokenInfo"); + sc_file_free(file); + + r = sc_read_binary(p15card->card, 0, efbin, sizeof(efbin), 0); + LOG_TEST_RET(card->ctx, r, "Could not read EF.TokenInfo"); + + r = sc_pkcs15_parse_tokeninfo(card->ctx, p15card->tokeninfo, efbin, r); + LOG_TEST_RET(card->ctx, r, "Could not decode EF.TokenInfo"); + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + + + /* * Initialize PKCS#15 emulation with user PIN, private keys, certificate and data objects * @@ -536,16 +563,12 @@ 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("www.CardContact.de"); - appinfo = calloc(1, sizeof(struct sc_app_info)); if (appinfo == NULL) { LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } - appinfo->label = strdup(p15card->tokeninfo->label); appinfo->aid = sc_hsm_aid; appinfo->ddo.aid = sc_hsm_aid; @@ -578,14 +601,36 @@ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card) r = sc_pkcs15emu_sc_hsm_decode_cvc(p15card, (const u8 **)&ptr, &len, &devcert); LOG_TEST_RET(card->ctx, r, "Could not decode EF.C_DevAut"); + sc_pkcs15emu_sc_hsm_read_tokeninfo(p15card); + + if (p15card->tokeninfo->label == NULL) { + p15card->tokeninfo->label = strdup("SmartCard-HSM"); + if (p15card->tokeninfo->label == NULL) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + } + + if ((p15card->tokeninfo->manufacturer_id != NULL) && !strcmp("(unknown)", p15card->tokeninfo->manufacturer_id)) { + free(p15card->tokeninfo->manufacturer_id); + p15card->tokeninfo->manufacturer_id = NULL; + } + + if (p15card->tokeninfo->manufacturer_id == NULL) { + p15card->tokeninfo->manufacturer_id = strdup("www.CardContact.de"); + if (p15card->tokeninfo->manufacturer_id == NULL) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + } + + appinfo->label = strdup(p15card->tokeninfo->label); + if (appinfo->label == NULL) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + len = strlen(devcert.chr); /* Strip last 5 digit sequence number from CHR */ assert(len >= 8); len -= 5; p15card->tokeninfo->serial_number = calloc(len + 1, 1); - if (p15card->tokeninfo->serial_number == NULL) { + if (p15card->tokeninfo->serial_number == NULL) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); - } memcpy(p15card->tokeninfo->serial_number, devcert.chr, len); *(p15card->tokeninfo->serial_number + len) = 0; @@ -594,7 +639,6 @@ static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card) sc_pkcs15emu_sc_hsm_free_cvc(&devcert); - memset(&pin_info, 0, sizeof(pin_info)); memset(&pin_obj, 0, sizeof(pin_obj)); diff --git a/src/tools/sc-hsm-tool.c b/src/tools/sc-hsm-tool.c index d6eb5ed3..2f0d106e 100644 --- a/src/tools/sc-hsm-tool.c +++ b/src/tools/sc-hsm-tool.c @@ -52,7 +52,8 @@ static const char magic[] = "Salted__"; static struct sc_aid sc_hsm_aid = { { 0xE8,0x2B,0x06,0x01,0x04,0x01,0x81,0xC3,0x1F,0x02,0x01 }, 11 }; static int opt_wait = 0; -static char *opt_reader; +static char *opt_reader = NULL; +static char *opt_label = NULL; static int verbose = 0; // Some reasonable maximums @@ -84,6 +85,7 @@ static const struct option options[] = { { "pwd-shares-threshold", 1, NULL, OPT_PASSWORD_SHARES_THRESHOLD }, { "pwd-shares-total", 1, NULL, OPT_PASSWORD_SHARES_TOTAL }, { "key-reference", 1, NULL, 'i' }, + { "label", 1, NULL, 'l' }, { "force", 0, NULL, 'f' }, { "reader", 1, NULL, 'r' }, { "wait", 0, NULL, 'w' }, @@ -105,6 +107,7 @@ static const char *option_help[] = { "Define threshold for number of password shares required for reconstruction", "Define number of password shares", "Key reference for key wrap/unwrap", + "Token label for --initialize", "Force replacement of key and certificate", "Uses reader number [0]", "Wait for a card to be inserted", @@ -138,7 +141,7 @@ static sc_card_t *card = NULL; * @param rngSeed Seed value for CPRNG * */ -static void generatePrime(BIGNUM *prime, const BIGNUM *s, const unsigned int n, char *rngSeed) +static void generatePrime(BIGNUM *prime, const BIGNUM *s, const unsigned int n, unsigned char *rngSeed) { int bits = 0; @@ -490,7 +493,7 @@ static void print_info(sc_card_t *card, sc_file_t *file) -static void initialize(sc_card_t *card, const char *so_pin, const char *user_pin, int retry_counter, int dkek_shares) +static void initialize(sc_card_t *card, const char *so_pin, const char *user_pin, int retry_counter, int dkek_shares, const char *label) { sc_cardctl_sc_hsm_init_param_t param; size_t len; @@ -560,6 +563,7 @@ static void initialize(sc_card_t *card, const char *so_pin, const char *user_pin param.options[1] = 0x01; param.dkek_shares = (char)dkek_shares; + param.label = (char *)label; r = sc_card_ctl(card, SC_CARDCTL_SC_HSM_INITIALIZE, (void *)¶m); if (r < 0) { @@ -816,7 +820,7 @@ static int generate_pwd_shares(sc_card_t *card, char **pwd, int *pwdlen, int pas *pwd = calloc(1, 8); *pwdlen = 8; - r = sc_get_challenge(card, *pwd, 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); @@ -834,7 +838,7 @@ static int generate_pwd_shares(sc_card_t *card, char **pwd, int *pwdlen, int pas /* * Encode the secret value */ - BN_bin2bn(*pwd, *pwdlen, &secret); + BN_bin2bn((unsigned char *)*pwd, *pwdlen, &secret); /* * Generate seed and calculate a prime depending on the size of the secret @@ -1007,7 +1011,7 @@ static int wrap_with_tag(u8 tag, u8 *indata, size_t inlen, u8 **outdata, size_t if (inlen > 127) { do { nlc++; - } while (inlen >= (1 << (nlc << 3))); + } while (inlen >= (unsigned)(1 << (nlc << 3))); } *outlen = 2 + nlc + inlen; @@ -1056,14 +1060,14 @@ static void wrap_key(sc_card_t *card, u8 keyid, const char *outf, const char *pi util_getpass(&lpin, NULL, stdin); printf("\n"); } else { - lpin = pin; + lpin = (char *)pin; } memset(&data, 0, sizeof(data)); data.cmd = SC_PIN_CMD_VERIFY; data.pin_type = SC_AC_CHV; data.pin_reference = ID_USER_PIN; - data.pin1.data = lpin; + data.pin1.data = (unsigned char *)lpin; data.pin1.len = strlen(lpin); r = sc_pin_cmd(card, &data, NULL); @@ -1313,14 +1317,14 @@ static void unwrap_key(sc_card_t *card, u8 keyid, const char *inf, const char *p util_getpass(&lpin, NULL, stdin); printf("\n"); } else { - lpin = (u8 *)pin; + lpin = (char *)pin; } memset(&data, 0, sizeof(data)); data.cmd = SC_PIN_CMD_VERIFY; data.pin_type = SC_AC_CHV; data.pin_reference = ID_USER_PIN; - data.pin1.data = lpin; + data.pin1.data = (u8 *)lpin; data.pin1.len = strlen(lpin); r = sc_pin_cmd(card, &data, NULL); @@ -1466,6 +1470,9 @@ int main(int argc, char * const argv[]) case 'r': opt_reader = optarg; break; + case 'l': + opt_label = optarg; + break; case 'v': verbose++; break; @@ -1509,7 +1516,7 @@ int main(int argc, char * const argv[]) } if (do_initialize) { - initialize(card, opt_so_pin, opt_pin, opt_retry_counter, opt_dkek_shares); + initialize(card, opt_so_pin, opt_pin, opt_retry_counter, opt_dkek_shares, opt_label); } if (do_create_dkek_share) {