From ffb20e5916550f0dd00592efa113ea23a364ebef Mon Sep 17 00:00:00 2001 From: Andreas Schwier Date: Sun, 14 Oct 2012 14:35:46 +0200 Subject: [PATCH] sc-hsm: Added sc-hsm-tool with DKEK support and key wrap / unwrap --- doc/tools/sc-hsm-tool.1.xml | 217 ++++++++ src/libopensc/asn1.h | 2 + src/libopensc/card-sc-hsm.c | 201 +++++++ src/libopensc/card-sc-hsm.h | 2 + src/libopensc/cardctl.h | 28 +- src/libopensc/errors.c | 3 +- src/libopensc/errors.h | 1 + src/libopensc/internal.h | 3 - src/libopensc/iso7816.c | 2 +- src/libopensc/libopensc.exports | 1 + src/pkcs15init/pkcs15-sc-hsm.c | 6 +- src/tools/Makefile.am | 4 +- src/tools/Makefile.mak | 2 +- src/tools/sc-hsm-tool.c | 913 ++++++++++++++++++++++++++++++++ win32/OpenSC.wxs.in | 4 + 15 files changed, 1378 insertions(+), 11 deletions(-) create mode 100644 doc/tools/sc-hsm-tool.1.xml create mode 100644 src/tools/sc-hsm-tool.c diff --git a/doc/tools/sc-hsm-tool.1.xml b/doc/tools/sc-hsm-tool.1.xml new file mode 100644 index 00000000..4c42439a --- /dev/null +++ b/doc/tools/sc-hsm-tool.1.xml @@ -0,0 +1,217 @@ + + + + sc-hsm-tool + 1 + OpenSC + OpenSC Tools + opensc + + + + sc-hsm-tool + smart card utility for SmartCard-HSM + + + + + sc-hsm-tool + OPTIONS + + + + + + The sc-hsm-tool utility can be used from the command line to perform + extended maintenance tasks not available via PKCS#11 or other tools in the OpenSC package. + It can be used to query the status of a SmartCard-HSM, initialize a device, generate and import + Device Key Encryption Key (DKEK) shares and to wrap and unwrap keys. + + + + + Options + + + + + , + + + + Initialize token, removing all existing keys, certificates and files. + Use to define SO-PIN for first initialization or to verify in subsequent + initializations. + 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. + + + + + + filename, + filename + + + Create a DKEK share encrypted under a user supplied password and saved to the file + given as parameter. + Use to provide a password for encryption rather than prompting for one. + + + + + + filename, + filename + + + Prompt for user password, read and decrypt DKEK share and import into SmartCard-HSM. + Use to provide a password for decryption rather than prompting for one. + + + + + + filename, + filename + + + Wrap the key referenced in and save with it together with the key description + and certificate to the given file. + Use to provide the user PIN on the command line. + + + + + + filename, + filename + + + Read wrapped key, description and certificate from file and import into SmartCard-HSM + under the key reference given in . + Determine the key reference using the output of pkcs15-tool -D. + Use to provide a user PIN on the command line. + Use to remove any key, key description or certificate in the way. + + + + + + number-of-shares, + number-of-shares + + + Define the number of DKEK shares to use for recreating the DKEK. + This is an optional parameter. Using without + will disable the DKEK completely. + Using with 0 shares requests the SmartCard-HSM to + generate a random DKEK. Keys wrapped with this DKEK can only be unwrapped in the + same SmartCard-HSM. + After using with one or more DKEK shares, the + SmartCard-HSM will remain in the initialized state until all DKEK shares have + been imported. During this phase no new keys can be generated or imported. + + + + + + value + + + Define SO-PIN for initialization. + + + + + + value + + + Define user PIN for initialization, wrap or unwrap operation. + + + + + + value + + + Define number of PIN retries for user PIN during initialization. Default is 3. + + + + + + value + + + Define password for DKEK share encryption. + + + + + + + + + Force removal of existing key, description and certificate. + + + + + + num, + num + + Use the given reader number. The default is + 0, the first reader in the system. + + + + + , + + + Wait for a card to be inserted + + + + + , + + + Causes sc-hsm-tool to be more verbose. + Specify this flag several times to enable debug output in the opensc + library. + + + + + + + Examples + Create a DKEK share: + sc-hsm-tool --create-dkek-share dkek-share-1.pbe + Initialize SmartCard-HSM to use a single DKEK share + sc-hsm-tool --initialize --so-pin 3537363231383830 --pin 648219 --dkek-shares 1 + Import DKEK share + sc-hsm-tool --import-dkek-share dkek-share-1.pbe + Wrap referenced key, description and certificate + sc-hsm-tool --wrap-key wrap-key.bin --key-reference 1 --pin 648219 + Unwrap key into same or in different SmartCard-HSM with the same DKEK + sc-hsm-tool --unwrap-key wrap-key.bin --key-reference 10 --pin 648219 --force + + + + See also + + + opensc-tool + 1 + + + + + diff --git a/src/libopensc/asn1.h b/src/libopensc/asn1.h index a6bbb62a..1189275f 100644 --- a/src/libopensc/asn1.h +++ b/src/libopensc/asn1.h @@ -72,6 +72,8 @@ int _sc_asn1_decode(struct sc_context *, struct sc_asn1_entry *, int _sc_asn1_encode(struct sc_context *, const struct sc_asn1_entry *, u8 **, size_t *, int); +int sc_asn1_read_tag(const u8 ** buf, size_t buflen, unsigned int *cla_out, + unsigned int *tag_out, size_t *taglen); const u8 *sc_asn1_find_tag(struct sc_context *ctx, const u8 * buf, size_t buflen, unsigned int tag, size_t *taglen); const u8 *sc_asn1_verify_tag(struct sc_context *ctx, const u8 * buf, diff --git a/src/libopensc/card-sc-hsm.c b/src/libopensc/card-sc-hsm.c index 516964ad..0a696d4e 100644 --- a/src/libopensc/card-sc-hsm.c +++ b/src/libopensc/card-sc-hsm.c @@ -134,11 +134,46 @@ static int sc_hsm_match_card(struct sc_card *card) +static int sc_hsm_pin_info(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; + sc_apdu_t apdu; + int r; + + sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x20, 0x00, data->pin_reference); + + r = sc_transmit_apdu(card, &apdu); + LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); + + r = sc_check_sw(card, apdu.sw1, apdu.sw2); + + if (r == SC_ERROR_PIN_CODE_INCORRECT) { + data->pin1.tries_left = apdu.sw2 & 0xF; + r = SC_SUCCESS; + } else if (r == SC_ERROR_AUTH_METHOD_BLOCKED) { + data->pin1.tries_left = 0; + r = SC_SUCCESS; + } + LOG_TEST_RET(card->ctx, r, "Check SW error"); + + if (tries_left != NULL) { + *tries_left = data->pin1.tries_left; + } + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + + + 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->cmd == SC_PIN_CMD_GET_INFO) { + return sc_hsm_pin_info(card, data, tries_left); + } if (data->pin_reference == 0x88) { // Save SO PIN for later use in init pin memcpy(priv->initpw, data->pin1.data, sizeof(priv->initpw)); @@ -581,6 +616,164 @@ 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; + int r, i; + sc_apdu_t apdu; + u8 ibuff[50], *p; + + LOG_FUNC_CALLED(card->ctx); + + p = ibuff; + *p++ = 0x80; // Options + *p++ = 0x02; + memcpy(p, params->options, 2); + p += 2; + + *p++ = 0x81; // User PIN + *p++ = params->user_pin_len; + memcpy(p, params->user_pin, params->user_pin_len); + p += params->user_pin_len; + + *p++ = 0x82; // Initialization code + *p++ = 0x08; + memcpy(p, params->init_code, 8); + p += 8; + + *p++ = 0x91; // User PIN retry counter + *p++ = 0x01; + *p++ = params->user_pin_retry_counter; + + if (params->dkek_shares >= 0) { + *p++ = 0x92; // Number of DKEK shares + *p++ = 0x01; + *p++ = (u8)params->dkek_shares; + } + + 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_import_dkek_share(sc_card_t *card, sc_cardctl_sc_hsm_dkek_t *params) +{ + sc_context_t *ctx = card->ctx; + sc_apdu_t apdu; + u8 status[SC_MAX_APDU_BUFFER_SIZE]; + int r; + + LOG_FUNC_CALLED(card->ctx); + + if (params->importShare) { + sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x52, 0x00, 0x00); + apdu.cla = 0x80; + apdu.data = params->dkek_share; + apdu.datalen = sizeof(params->dkek_share); + apdu.lc = apdu.datalen; + } else { + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x52, 0x00, 0x00); + } + apdu.cla = 0x80; + apdu.le = 0; + apdu.resp = status; + apdu.resplen = sizeof(status); + + 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"); + + assert(apdu.resplen >= (sizeof(params->key_check_value) + 2)); + + params->dkek_shares = status[0]; + params->outstanding_shares = status[1]; + memcpy(params->key_check_value, status + 2, sizeof(params->key_check_value)); + + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + + + +static int sc_hsm_wrap_key(sc_card_t *card, sc_cardctl_sc_hsm_wrapped_key_t *params) +{ + sc_context_t *ctx = card->ctx; + sc_apdu_t apdu; + u8 data[SC_MAX_EXT_APDU_BUFFER_SIZE]; + int r; + + LOG_FUNC_CALLED(card->ctx); + + sc_format_apdu(card, &apdu, SC_APDU_CASE_2_EXT, 0x72, params->key_id, 0x92); + apdu.cla = 0x80; + apdu.le = 0; + apdu.resp = data; + apdu.resplen = sizeof(data); + + 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"); + + params->wrapped_key_length = apdu.resplen; + params->wrapped_key = malloc(apdu.resplen); + if (params->wrapped_key == NULL) { + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + } + memcpy(params->wrapped_key, data, apdu.resplen); + LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); +} + + + +static int sc_hsm_unwrap_key(sc_card_t *card, sc_cardctl_sc_hsm_wrapped_key_t *params) +{ + sc_context_t *ctx = card->ctx; + sc_apdu_t apdu; + u8 status[MAX_EXT_APDU_LENGTH]; + int r; + + LOG_FUNC_CALLED(card->ctx); + + sc_format_apdu(card, &apdu, SC_APDU_CASE_3_EXT, 0x74, params->key_id, 0x93); + apdu.cla = 0x80; + apdu.lc = params->wrapped_key_length; + apdu.data = params->wrapped_key; + apdu.datalen = params->wrapped_key_length; + + 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(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; @@ -734,6 +927,14 @@ static int sc_hsm_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr) 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); + case SC_CARDCTL_SC_HSM_INITIALIZE: + return sc_hsm_initialize(card, (sc_cardctl_sc_hsm_init_param_t *)ptr); + case SC_CARDCTL_SC_HSM_IMPORT_DKEK_SHARE: + return sc_hsm_import_dkek_share(card, (sc_cardctl_sc_hsm_dkek_t *)ptr); + case SC_CARDCTL_SC_HSM_WRAP_KEY: + return sc_hsm_wrap_key(card, (sc_cardctl_sc_hsm_wrapped_key_t *)ptr); + case SC_CARDCTL_SC_HSM_UNWRAP_KEY: + return sc_hsm_unwrap_key(card, (sc_cardctl_sc_hsm_wrapped_key_t *)ptr); } return SC_ERROR_NOT_SUPPORTED; } diff --git a/src/libopensc/card-sc-hsm.h b/src/libopensc/card-sc-hsm.h index 370641bf..0d01b54b 100644 --- a/src/libopensc/card-sc-hsm.h +++ b/src/libopensc/card-sc-hsm.h @@ -47,6 +47,8 @@ #define ALGO_EC_SHA256 0x73 /* ECDSA signature with SHA-256 hash */ #define ALGO_EC_DH 0x80 /* ECDH key derivation */ +#define ID_USER_PIN 0x81 /* User PIN identifier */ +#define ID_SO_PIN 0x88 /* Security officer PIN identifier */ /* Information the driver maintains between calls */ typedef struct sc_hsm_private_data { diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h index caa23989..e32ad8c1 100644 --- a/src/libopensc/cardctl.h +++ b/src/libopensc/cardctl.h @@ -244,7 +244,11 @@ enum { * SmartCard-HSM */ SC_CARDCTL_SC_HSMP_BASE = _CTL_PREFIX('S', 'C', 'H'), - SC_CARDCTL_SC_HSM_GENERATE_KEY + SC_CARDCTL_SC_HSM_GENERATE_KEY, + SC_CARDCTL_SC_HSM_INITIALIZE, + SC_CARDCTL_SC_HSM_IMPORT_DKEK_SHARE, + SC_CARDCTL_SC_HSM_WRAP_KEY, + SC_CARDCTL_SC_HSM_UNWRAP_KEY }; enum { @@ -908,6 +912,28 @@ typedef struct sc_cardctl_sc_hsm_keygen_info { size_t gakpresponse_len; /* Size of response */ } sc_cardctl_sc_hsm_keygen_info_t; +typedef struct sc_cardctl_sc_hsm_init_param { + u8 init_code[8]; /* Initialization code */ + 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 */ + char dkek_shares; /* Number of DKEK shares, 0 for card generated, -1 for none */ +} sc_cardctl_sc_hsm_init_param_t; + +typedef struct sc_cardctl_sc_hsm_dkek { + int importShare; /* True to import share, false to just query status */ + u8 dkek_share[32]; /* AES-256 DKEK share */ + u8 dkek_shares; /* Total number of shares */ + u8 outstanding_shares; /* Number of shares to be presented */ + u8 key_check_value[8]; /* Key check value for DKEK */ +} sc_cardctl_sc_hsm_dkek_t; + +typedef struct sc_cardctl_sc_hsm_wrapped_key { + u8 key_id; /* Key identifier */ + u8 *wrapped_key; /* Binary wrapped key */ + size_t wrapped_key_length; /* Length of key blob */ +} sc_cardctl_sc_hsm_wrapped_key_t; #ifdef __cplusplus } diff --git a/src/libopensc/errors.c b/src/libopensc/errors.c index be5a27f5..aee5fa8b 100644 --- a/src/libopensc/errors.c +++ b/src/libopensc/errors.c @@ -69,7 +69,8 @@ const char *sc_strerror(int error) "Data object not found", "Not enough memory on card", "Part of returned data may be corrupted", - "End of file/record reached before reading Le bytes" + "End of file/record reached before reading Le bytes", + "Reference data not usable" }; const int card_base = -SC_ERROR_CARD_CMD_FAILED; diff --git a/src/libopensc/errors.h b/src/libopensc/errors.h index 8e5e62a0..579de685 100644 --- a/src/libopensc/errors.h +++ b/src/libopensc/errors.h @@ -67,6 +67,7 @@ extern "C" { #define SC_ERROR_NOT_ENOUGH_MEMORY -1217 #define SC_ERROR_CORRUPTED_DATA -1218 #define SC_ERROR_FILE_END_REACHED -1219 +#define SC_ERROR_REF_DATA_NOT_USABLE -1220 /* Returned by OpenSC library when called with invalid arguments */ #define SC_ERROR_INVALID_ARGUMENTS -1300 diff --git a/src/libopensc/internal.h b/src/libopensc/internal.h index 85402ad9..f0270bea 100644 --- a/src/libopensc/internal.h +++ b/src/libopensc/internal.h @@ -123,9 +123,6 @@ int _sc_card_add_rsa_alg(struct sc_card *card, unsigned int key_length, int _sc_card_add_ec_alg(struct sc_card *card, unsigned int key_length, unsigned long flags, unsigned long ext_flags); -int sc_asn1_read_tag(const u8 ** buf, size_t buflen, unsigned int *cla_out, - unsigned int *tag_out, size_t *taglen); - /********************************************************************/ /* pkcs1 padding/encoding functions */ /********************************************************************/ diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c index 89c644f4..a15addf6 100644 --- a/src/libopensc/iso7816.c +++ b/src/libopensc/iso7816.c @@ -51,7 +51,7 @@ static const struct sc_card_error iso7816_errors[] = { { 0x6981, SC_ERROR_CARD_CMD_FAILED, "Command incompatible with file structure" }, { 0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Security status not satisfied" }, { 0x6983, SC_ERROR_AUTH_METHOD_BLOCKED, "Authentication method blocked" }, - { 0x6984, SC_ERROR_CARD_CMD_FAILED, "Referenced data invalidated" }, + { 0x6984, SC_ERROR_REF_DATA_NOT_USABLE, "Referenced data not usable" }, { 0x6985, SC_ERROR_NOT_ALLOWED, "Conditions of use not satisfied" }, { 0x6986, SC_ERROR_NOT_ALLOWED, "Command not allowed (no current EF)" }, { 0x6987, SC_ERROR_INCORRECT_PARAMETERS,"Expected SM data objects missing" }, diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index 0f161745..fe118014 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -44,6 +44,7 @@ sc_asn1_decode_object_id sc_asn1_encode sc_asn1_encode_object_id sc_asn1_encode_algorithm_id +sc_asn1_read_tag sc_asn1_find_tag sc_asn1_print_tags sc_asn1_put_tag diff --git a/src/pkcs15init/pkcs15-sc-hsm.c b/src/pkcs15init/pkcs15-sc-hsm.c index 18cfb40c..389a5d3d 100644 --- a/src/pkcs15init/pkcs15-sc-hsm.c +++ b/src/pkcs15init/pkcs15-sc-hsm.c @@ -180,7 +180,7 @@ static int sc_hsm_update_ef(sc_pkcs15_card_t *p15card, u8 prefix, u8 id, int era file->status = SC_FILE_STATUS_ACTIVATED; r = sc_create_file(card, file); sc_file_free(file); - LOG_TEST_RET(card->ctx, r, "Could not creat file"); + LOG_TEST_RET(card->ctx, r, "Could not create file"); } r = sc_update_binary(card, 0, buf, buflen, 0); @@ -462,8 +462,8 @@ static int sc_hsm_generate_key(struct sc_profile *profile, struct sc_pkcs15_card cvcpo = cvcbin; - sc_asn1_read_tag(&cvcpo, cvclen, &cla, &tag, &taglen); - sc_asn1_read_tag(&cvcpo, cvclen, &cla, &tag, &taglen); + sc_asn1_read_tag((const u8 **)&cvcpo, cvclen, &cla, &tag, &taglen); + sc_asn1_read_tag((const u8 **)&cvcpo, cvclen, &cla, &tag, &taglen); sc_hsm_keyinfo.key_id = key_info->key_reference; sc_hsm_keyinfo.auth_key_id = 0; diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am index b42f8a4d..a1e37344 100644 --- a/src/tools/Makefile.am +++ b/src/tools/Makefile.am @@ -7,7 +7,7 @@ noinst_HEADERS = util.h bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-tool pkcs15-crypt \ pkcs11-tool cardos-tool eidenv openpgp-tool iasecc-tool if ENABLE_OPENSSL -bin_PROGRAMS += cryptoflex-tool pkcs15-init netkey-tool piv-tool westcos-tool +bin_PROGRAMS += cryptoflex-tool pkcs15-init netkey-tool piv-tool westcos-tool sc-hsm-tool endif # compile with $(PTHREAD_CFLAGS) to allow debugging with gdb @@ -46,6 +46,7 @@ openpgp_tool_SOURCES = openpgp-tool.c util.c openpgp_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS) iasecc_tool_SOURCES = iasecc-tool.c util.c iasecc_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS) +sc_hsm_tool_SOURCES = sc-hsm-tool.c util.c if WIN32 opensc_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc @@ -62,4 +63,5 @@ netkey_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc westcos_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc openpgp_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc iasecc_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc +sc_hsm_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc endif diff --git a/src/tools/Makefile.mak b/src/tools/Makefile.mak index 153bff76..3706b6af 100644 --- a/src/tools/Makefile.mak +++ b/src/tools/Makefile.mak @@ -3,7 +3,7 @@ TOPDIR = ..\.. !INCLUDE $(TOPDIR)\win32\Make.rules.mak TARGETS = opensc-tool.exe opensc-explorer.exe pkcs15-tool.exe pkcs15-crypt.exe \ - pkcs11-tool.exe cardos-tool.exe eidenv.exe \ + pkcs11-tool.exe cardos-tool.exe eidenv.exe sc-hsm-tool.exe \ $(PROGRAMS_OPENSSL) $(TARGETS): $(TOPDIR)\win32\versioninfo.res util.obj diff --git a/src/tools/sc-hsm-tool.c b/src/tools/sc-hsm-tool.c new file mode 100644 index 00000000..72613846 --- /dev/null +++ b/src/tools/sc-hsm-tool.c @@ -0,0 +1,913 @@ +/* + * sc-hsm-tool.c: SmartCard-HSM Management Tool + * + * Copyright (C) 2001 Juha Yrjölä + * Copyright (C) 2012 www.CardContact.de, Andreas Schwier, Minden, Germany + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include + +/* Requires openssl for dkek import */ +#include +#include +#include + + +#include "libopensc/opensc.h" +#include "libopensc/cardctl.h" +#include "libopensc/asn1.h" +#include "libopensc/card-sc-hsm.h" +#include "util.h" + +static const char *app_name = "sc-hsm-tool"; + +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 int verbose = 0; + +// Some reasonable maximums +#define MAX_CERT 4096 +#define MAX_PRKD 256 +#define MAX_KEY 512 +#define MAX_WRAPPED_KEY (MAX_CERT + MAX_PRKD + MAX_KEY) + +enum { + OPT_SO_PIN = 0x100, + OPT_PIN, + OPT_RETRY, + OPT_PASSWORD +}; + +static const struct option options[] = { + { "initialize", 0, NULL, 'X' }, + { "create-dkek-share", 1, NULL, 'C' }, + { "import-dkek-share", 1, NULL, 'I' }, + { "wrap-key", 1, NULL, 'W' }, + { "unwrap-key", 1, NULL, 'U' }, + { "dkek-shares", 1, NULL, 's' }, + { "so-pin", 1, NULL, OPT_SO_PIN }, + { "pin", 1, NULL, OPT_PIN }, + { "pin-retry", 1, NULL, OPT_RETRY }, + { "password", 1, NULL, OPT_PASSWORD }, + { "key-reference", 1, NULL, 'i' }, + { "force", 0, NULL, 'f' }, + { "reader", 1, NULL, 'r' }, + { "wait", 0, NULL, 'w' }, + { "verbose", 0, NULL, 'v' }, + { NULL, 0, NULL, 0 } +}; + +static const char *option_help[] = { + "Initialize token", + "Create DKEK key share and save to ", + "Import DKEK key share ", + "Wrap key and save to ", + "Unwrap key read from ", + "Number of DKEK shares [No DKEK]", + "Define security officer PIN (SO-PIN)", + "Define user PIN", + "Define user PIN retry counter", + "Define password for DKEK share", + "Key reference for key wrap/unwrap", + "Force replacement of key and certificate", + "Uses reader number [0]", + "Wait for a card to be inserted", + "Verbose operation. Use several times to enable debug output.", +}; + + +static sc_context_t *ctx = NULL; +static sc_card_t *card = NULL; + + + + +static void print_dkek_info(sc_cardctl_sc_hsm_dkek_t *dkekinfo) { + printf("DKEK shares : %d\n", dkekinfo->dkek_shares); + if (dkekinfo->outstanding_shares > 0) { + printf("DKEK import pending, %d share(s) still missing\n",dkekinfo->outstanding_shares); + } else { + printf("DKEK key check value : "); + util_hex_dump(stdout, dkekinfo->key_check_value, 8, NULL); + printf("\n"); + } +} + + + +static void print_info(sc_card_t *card, sc_file_t *file) +{ + int r, tries_left; + struct sc_pin_cmd_data data; + sc_cardctl_sc_hsm_dkek_t dkekinfo; + + u8 major, minor; + + major = file->prop_attr[file->prop_attr_len - 2]; + minor = file->prop_attr[file->prop_attr_len - 1]; + printf("Version : %d.%d\n", (int)major, (int)minor); + + /* Try to update PIN info from card */ + memset(&data, 0, sizeof(data)); + data.cmd = SC_PIN_CMD_GET_INFO; + data.pin_type = SC_AC_CHV; + data.pin_reference = ID_USER_PIN; + + r = sc_pin_cmd(card, &data, &tries_left); + + if (r == SC_ERROR_REF_DATA_NOT_USABLE) { + printf("SmartCard-HSM has never been initialized\n"); + } else { + if (tries_left == 0) { + printf("User PIN locked\n"); + } else { + printf("User PIN tries left : %d\n", tries_left); + } + } + + memset(&dkekinfo, 0, sizeof(dkekinfo)); + + r = sc_card_ctl(card, SC_CARDCTL_SC_HSM_IMPORT_DKEK_SHARE, (void *)&dkekinfo); + + if (r == SC_ERROR_INS_NOT_SUPPORTED) { // Not supported or not initialized for key shares + return; + } + + if (r < 0) { + fprintf(stderr, "sc_card_ctl(*, SC_CARDCTL_SC_HSM_IMPORT_DKEK_SHARE, *) failed with %s\n", sc_strerror(r)); + } + print_dkek_info(&dkekinfo); +} + + + +static void initialize(sc_card_t *card, const char *so_pin, const char *user_pin, int retry_counter, int dkek_shares) +{ + sc_cardctl_sc_hsm_init_param_t param; + size_t len; + char *_so_pin = NULL, *_user_pin = NULL; + int r; + + if (so_pin == NULL) { + printf("Enter SO-PIN : "); + util_getpass(&_so_pin, NULL, stdin); + printf("\n"); + } else { + _so_pin = (char *)so_pin; + } + + if (user_pin == NULL) { + printf("Enter initial User-PIN : "); + util_getpass(&_user_pin, NULL, stdin); + printf("\n"); + } else { + _user_pin = (char *)user_pin; + } + + len = sizeof(param.init_code); + r = sc_hex_to_bin(_so_pin, param.init_code, &len); + if (r < 0) { + fprintf(stderr, "Error decoding initialization code (%s)\n", sc_strerror(r)); + return; + } + + if (len != 8) { + fprintf(stderr, "Initialization code must contain 8 bytes\n"); + return; + } + + param.user_pin_len = strlen(_user_pin); + param.user_pin = (u8 *)_user_pin; + + param.user_pin_retry_counter = (u8)retry_counter; + + param.options[0] = 0x00; + param.options[1] = 0x01; + + param.dkek_shares = (char)dkek_shares; + + r = sc_card_ctl(card, SC_CARDCTL_SC_HSM_INITIALIZE, (void *)¶m); + if (r < 0) { + fprintf(stderr, "sc_card_ctl(*, SC_CARDCTL_SC_HSM_INITIALIZE, *) failed with %s\n", sc_strerror(r)); + } +} + + + +static void import_dkek_share(sc_card_t *card, const char *inf, int iter, char *password) +{ + sc_cardctl_sc_hsm_dkek_t dkekinfo; + EVP_CIPHER_CTX ctx; + FILE *in = NULL; + u8 filebuff[64],key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH],outbuff[64]; + char *pwd = NULL; + int r, outlen; + + in = fopen(inf, "rb"); + + if (in == NULL) { + perror(inf); + return; + } + + if (fread(filebuff, 1, sizeof(filebuff), in) != sizeof(filebuff)) { + perror(inf); + return; + } + + fclose(in); + + if (memcmp(filebuff, magic, sizeof(magic) - 1)) { + printf("File %s is not a DKEK share\n", inf); + return; + } + + if (password == NULL) { + printf("Enter password to decrypt DKEK share : "); + util_getpass(&pwd, NULL, stdin); + printf("\n"); + } else { + pwd = password; + } + + printf("Deciphering DKEK share, please wait...\n"); + EVP_BytesToKey(EVP_aes_256_cbc(), EVP_md5(), filebuff + 8, (u8 *)pwd, strlen(pwd), iter, key, iv); + OPENSSL_cleanse(pwd, strlen(pwd)); + + if (password == NULL) { + free(pwd); + } + + EVP_CIPHER_CTX_init(&ctx); + EVP_DecryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, iv); + if (!EVP_DecryptUpdate(&ctx, outbuff, &outlen, filebuff + 16, sizeof(filebuff) - 16)) { + printf("Error decrypting DKEK share. Password correct ?\n"); + return; + } + + if (!EVP_DecryptFinal_ex(&ctx, outbuff + outlen, &r)) { + printf("Error decrypting DKEK share. Password correct ?\n"); + return; + } + + memset(&dkekinfo, 0, sizeof(dkekinfo)); + memcpy(dkekinfo.dkek_share, outbuff, sizeof(dkekinfo.dkek_share)); + dkekinfo.importShare = 1; + + OPENSSL_cleanse(outbuff, sizeof(outbuff)); + + r = sc_card_ctl(card, SC_CARDCTL_SC_HSM_IMPORT_DKEK_SHARE, (void *)&dkekinfo); + + OPENSSL_cleanse(&dkekinfo.dkek_share, sizeof(dkekinfo.dkek_share)); + EVP_CIPHER_CTX_cleanup(&ctx); + + if (r == SC_ERROR_INS_NOT_SUPPORTED) { // Not supported or not initialized for key shares + return; + } + + if (r < 0) { + fprintf(stderr, "sc_card_ctl(*, SC_CARDCTL_SC_HSM_IMPORT_DKEK_SHARE, *) failed with %s\n", sc_strerror(r)); + return; + } + printf("DKEK share imported\n"); + print_dkek_info(&dkekinfo); +} + + + +static void create_dkek_share(sc_card_t *card, const char *outf, int iter, char *password) +{ + EVP_CIPHER_CTX ctx; + FILE *out = NULL; + u8 filebuff[64],key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH],outbuff[64]; + u8 dkek_share[32]; + char *pwd = NULL; + int r, outlen; + + if (password == NULL) { + char *refpwd = NULL; + + printf("\nThe DKEK share will be enciphered using a key derived from a user supplied password.\n"); + printf("The security of the DKEK share relies on a well chosen and sufficiently long password.\n"); + printf("The recommended length is more than 10 characters, which are mixed letters, numbers and\n"); + printf("symbols.\n\n"); + printf("Please keep the generated DKEK share file in a save location. We also recommend to keep a\n"); + printf("paper printout, in case the electronic version becomes unavailable. A printable version\n"); + printf("of the file can be generated using \"openssl base64 -in \".\n"); + while(1) { + printf("Enter password to encrypt DKEK share : "); + util_getpass(&pwd, NULL, stdin); + printf("\n"); + if (strlen(pwd) < 6) { + printf("Password way to short. Please retry.\n"); + continue; + } + printf("Please retype password to confirm : "); + util_getpass(&refpwd, NULL, stdin); + printf("\n"); + if (strcmp(pwd, refpwd)) { + printf("Passwords do not match. Please retry.\n"); + continue; + } + break; + } + OPENSSL_cleanse(refpwd, strlen(refpwd)); + free(refpwd); + } else { + pwd = password; + } + + memcpy(filebuff, magic, sizeof(magic) - 1); + + r = sc_get_challenge(card, filebuff + 8, 8); + if (r < 0) { + printf("Error generating random number failed with ", sc_strerror(r)); + return; + } + + printf("Enciphering DKEK share, please wait...\n"); + EVP_BytesToKey(EVP_aes_256_cbc(), EVP_md5(), filebuff + 8, (u8 *)pwd, strlen(pwd), iter, key, iv); + + if (password == NULL) { + OPENSSL_cleanse(pwd, strlen(pwd)); + free(pwd); + } + + r = sc_get_challenge(card, dkek_share, sizeof(dkek_share)); + if (r < 0) { + printf("Error generating random number failed with ", sc_strerror(r)); + return; + } + + EVP_CIPHER_CTX_init(&ctx); + EVP_EncryptInit_ex(&ctx, EVP_aes_256_cbc(), NULL, key, iv); + if (!EVP_EncryptUpdate(&ctx, filebuff + 16, &outlen, dkek_share, sizeof(dkek_share))) { + printf("Error encrypting DKEK share\n"); + return; + } + + if (!EVP_EncryptFinal_ex(&ctx, filebuff + 16 + outlen, &r)) { + printf("Error encrypting DKEK share\n"); + return; + } + + out = fopen(outf, "wb"); + + if (out == NULL) { + perror(outf); + return; + } + + if (fwrite(filebuff, 1, sizeof(filebuff), out) != sizeof(filebuff)) { + perror(outf); + return; + } + + fclose(out); + + OPENSSL_cleanse(filebuff, sizeof(filebuff)); + EVP_CIPHER_CTX_cleanup(&ctx); + + printf("DKEK share created and saved to %s\n", outf); +} + + + +static size_t determineLength(const u8 *tlv, size_t buflen) +{ + const u8 *ptr = tlv; + unsigned int cla,tag; + size_t len; + + if (sc_asn1_read_tag(&ptr, buflen, &cla, &tag, &len) != SC_SUCCESS) { + return 0; + } + + return len + (ptr - tlv); +} + + + +static void wrap_key(sc_card_t *card, u8 keyid, const char *outf, const char *pin) +{ + sc_cardctl_sc_hsm_wrapped_key_t wrapped_key; + struct sc_pin_cmd_data data; + sc_file_t *file = NULL; + sc_path_t path; + FILE *out = NULL; + u8 fid[2]; + u8 ef_prkd[MAX_PRKD]; + u8 ef_cert[MAX_CERT]; + u8 keyblob[MAX_WRAPPED_KEY]; + u8 *key; + u8 *ptr; + char *lpin = NULL; + size_t key_len; + int r, ef_prkd_len, ef_cert_len; + + if (pin == NULL) { + printf("Enter User PIN : "); + util_getpass(&lpin, NULL, stdin); + printf("\n"); + } else { + lpin = (u8 *)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.len = strlen(lpin); + + r = sc_pin_cmd(card, &data, NULL); + + if (r < 0) { + fprintf(stderr, "PIN verification failed with %s\n", sc_strerror(r)); + return; + } + + if (pin == NULL) { + free(lpin); + } + + wrapped_key.key_id = keyid; + + r = sc_card_ctl(card, SC_CARDCTL_SC_HSM_WRAP_KEY, (void *)&wrapped_key); + + if (r == SC_ERROR_INS_NOT_SUPPORTED) { // Not supported or not initialized for key shares + return; + } + + if (r < 0) { + fprintf(stderr, "sc_card_ctl(*, SC_CARDCTL_SC_HSM_WRAP_KEY, *) failed with %s\n", sc_strerror(r)); + return; + } + + + fid[0] = PRKD_PREFIX; + fid[1] = keyid; + ef_prkd_len = 0; + + /* Try to select a related EF containing the PKCS#15 description of the key */ + sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0); + r = sc_select_file(card, &path, NULL); + + if (r == SC_SUCCESS) { + ef_prkd_len = sc_read_binary(card, 0, ef_prkd, sizeof(ef_prkd), 0); + + if (ef_prkd_len < 0) { + fprintf(stderr, "Error reading PRKD file %s. Skipping.\n", sc_strerror(ef_prkd_len)); + ef_prkd_len = 0; + } else { + ef_prkd_len = determineLength(ef_prkd, ef_prkd_len); + } + } + + fid[0] = EE_CERTIFICATE_PREFIX; + fid[1] = keyid; + ef_cert_len = 0; + + /* Try to select a related EF containing the certificate for the key */ + sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0); + r = sc_select_file(card, &path, NULL); + + if (r == SC_SUCCESS) { + ef_cert_len = sc_read_binary(card, 0, ef_cert, sizeof(ef_cert), 0); + + if (ef_cert_len < 0) { + fprintf(stderr, "Error reading certificate %s. Skipping\n", sc_strerror(ef_cert_len)); + ef_cert_len = 0; + } else { + ef_cert_len = determineLength(ef_cert, ef_cert_len); + } + } + + + ptr = keyblob; + + // Encode key in octet string object + sc_asn1_write_element(card->ctx, SC_ASN1_OCTET_STRING, + wrapped_key.wrapped_key, wrapped_key.wrapped_key_length, + &key, &key_len); + + memcpy(ptr, key, key_len); + ptr += key_len; + free(key); + + // Add private key description + if (ef_prkd_len > 0) { + memcpy(ptr, ef_prkd, ef_prkd_len); + ptr += ef_prkd_len; + } + + // Add certificate + if (ef_cert_len > 0) { + memcpy(ptr, ef_cert, ef_cert_len); + ptr += ef_cert_len; + } + + // Encode key in octet string object + sc_asn1_write_element(card->ctx, SC_ASN1_SEQUENCE|SC_ASN1_CONS, + keyblob, ptr - keyblob, + &key, &key_len); + + out = fopen(outf, "wb"); + + if (out == NULL) { + perror(outf); + free(key); + return; + } + + if (fwrite(key, 1, key_len, out) != key_len) { + perror(outf); + free(key); + return; + } + + free(key); + fclose(out); +} + + + +static int update_ef(sc_card_t *card, u8 prefix, u8 id, int erase, const u8 *buf, size_t buflen) +{ + sc_file_t *file = NULL; + sc_file_t newfile; + sc_path_t path; + u8 fid[2]; + int r; + + fid[0] = prefix; + fid[1] = id; + + sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, -1); + + r = sc_select_file(card, &path, NULL); + + if ((r == SC_SUCCESS) && erase) { + r = sc_delete_file(card, &path); + r = SC_ERROR_FILE_NOT_FOUND; + } + + if (r == SC_ERROR_FILE_NOT_FOUND) { + file = sc_file_new(); + file->id = (path.value[0] << 8) | path.value[1]; + file->type = SC_FILE_TYPE_WORKING_EF; + file->ef_structure = SC_FILE_EF_TRANSPARENT; + file->size = (size_t) 0; + file->status = SC_FILE_STATUS_ACTIVATED; + r = sc_create_file(card, file); + sc_file_free(file); + if (r < 0) { + return r; + } + } + + r = sc_update_binary(card, 0, buf, buflen, 0); + return r; +} + + + +static void unwrap_key(sc_card_t *card, u8 keyid, const char *inf, const char *pin, int force) +{ + sc_cardctl_sc_hsm_wrapped_key_t wrapped_key; + struct sc_pin_cmd_data data; + u8 keyblob[MAX_WRAPPED_KEY]; + const u8 *ptr,*prkd,*cert; + FILE *in = NULL; + sc_path_t path; + u8 fid[2]; + char *lpin = NULL; + unsigned int cla, tag; + int r, keybloblen; + size_t len, olen, prkd_len, cert_len; + + in = fopen(inf, "rb"); + + if (in == NULL) { + perror(inf); + return; + } + + if ((keybloblen = fread(keyblob, 1, sizeof(keyblob), in)) < 0) { + perror(inf); + return; + } + + fclose(in); + + ptr = keyblob; + if ((sc_asn1_read_tag(&ptr, keybloblen, &cla, &tag, &len) != SC_SUCCESS) || + ((cla & SC_ASN1_TAG_CONSTRUCTED) != SC_ASN1_TAG_CONSTRUCTED) || + ((tag != SC_ASN1_TAG_SEQUENCE)) ){ + fprintf(stderr, "Invalid wrapped key format (Outer sequence).\n"); + return; + } + + if ((sc_asn1_read_tag(&ptr, len, &cla, &tag, &olen) != SC_SUCCESS) || + (cla & SC_ASN1_TAG_CONSTRUCTED) || + ((tag != SC_ASN1_TAG_OCTET_STRING)) ){ + fprintf(stderr, "Invalid wrapped key format (Key binary).\n"); + return; + } + + wrapped_key.wrapped_key = (u8 *)ptr; + wrapped_key.wrapped_key_length = olen; + + ptr += olen; + prkd = ptr; + prkd_len = determineLength(ptr, keybloblen - (ptr - keyblob)); + + ptr += prkd_len; + cert = ptr; + cert_len = determineLength(ptr, keybloblen - (ptr - keyblob)); + + printf("Wrapped key contains:\n"); + printf(" Key blob\n"); + if (prkd_len > 0) { + printf(" Private Key Description (PRKD)\n"); + } + if (cert_len > 0) { + printf(" Certificate\n"); + } + + if ((prkd_len > 0) && !force) { + fid[0] = PRKD_PREFIX; + fid[1] = keyid; + + /* Try to select a related EF containing the PKCS#15 description of the key */ + sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0); + r = sc_select_file(card, &path, NULL); + + if (r == SC_SUCCESS) { + fprintf(stderr, "Found existing private key description in EF with fid %02x%02x. Please remove key first, select unused key reference or use --force.\n", fid[0], fid[1]); + return; + } + } + + if ((cert_len > 0) && !force) { + fid[0] = EE_CERTIFICATE_PREFIX; + fid[1] = keyid; + + /* Try to select a related EF containing the certificate */ + sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0); + r = sc_select_file(card, &path, NULL); + + if (r == SC_SUCCESS) { + fprintf(stderr, "Found existing certificate in EF with fid %02x%02x. Please remove certificate first, select unused key reference or use --force.\n", fid[0], fid[1]); + return; + } + } + + if (pin == NULL) { + printf("Enter User PIN : "); + util_getpass(&lpin, NULL, stdin); + printf("\n"); + } else { + lpin = (u8 *)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.len = strlen(lpin); + + r = sc_pin_cmd(card, &data, NULL); + + if (r < 0) { + fprintf(stderr, "PIN verification failed with %s\n", sc_strerror(r)); + return; + } + + if (pin == NULL) { + free(lpin); + } + + if (force) { + fid[0] = KEY_PREFIX; + fid[1] = keyid; + + sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, -1); + sc_delete_file(card, &path); + } + + wrapped_key.key_id = keyid; + + r = sc_card_ctl(card, SC_CARDCTL_SC_HSM_UNWRAP_KEY, (void *)&wrapped_key); + + if (r == SC_ERROR_INS_NOT_SUPPORTED) { // Not supported or not initialized for key shares + return; + } + + if (r < 0) { + fprintf(stderr, "sc_card_ctl(*, SC_CARDCTL_SC_HSM_UNWRAP_KEY, *) failed with %s\n", sc_strerror(r)); + return; + } + + if (prkd_len > 0) { + r = update_ef(card, PRKD_PREFIX, keyid, force, prkd, prkd_len); + + if (r < 0) { + fprintf(stderr, "Updating private key description failed with %s\n", sc_strerror(r)); + return; + } + } + + if (cert_len > 0) { + r = update_ef(card, EE_CERTIFICATE_PREFIX, keyid, force, cert, cert_len); + + if (r < 0) { + fprintf(stderr, "Updating certificate failed with %s\n", sc_strerror(r)); + return; + } + } + + printf("Key successfully imported\n"); +} + + + +int main(int argc, char * const argv[]) +{ + int err = 0, r, c, long_optind = 0; + int action_count = 0; + int do_initialize = 0; + int do_import_dkek_share = 0; + int do_create_dkek_share = 0; + int do_wrap_key = 0; + int do_unwrap_key = 0; + sc_path_t path; + sc_file_t *file = NULL; + const char *opt_so_pin = NULL; + const char *opt_pin = NULL; + const char *opt_filename = NULL; + char *opt_password = NULL; + int opt_retry_counter = 3; + int opt_dkek_shares = -1; + int opt_key_reference = -1; + int opt_force = 0; + int opt_iter = 10000000; + sc_context_param_t ctx_param; + + setbuf(stderr, NULL); + setbuf(stdout, NULL); + + while (1) { + c = getopt_long(argc, argv, "XC:I:W:U:s:i:fr:wv", options, &long_optind); + if (c == -1) + break; + if (c == '?') + util_print_usage_and_die(app_name, options, option_help, NULL); + switch (c) { + case 'X': + do_initialize = 1; + action_count++; + break; + case 'C': + do_create_dkek_share = 1; + opt_filename = optarg; + action_count++; + break; + case 'I': + do_import_dkek_share = 1; + opt_filename = optarg; + action_count++; + break; + case 'W': + do_wrap_key = 1; + opt_filename = optarg; + action_count++; + break; + case 'U': + do_unwrap_key = 1; + opt_filename = optarg; + action_count++; + break; + case OPT_PASSWORD: + opt_password = optarg; + break; + case OPT_SO_PIN: + opt_so_pin = optarg; + break; + case OPT_PIN: + opt_pin = optarg; + break; + case OPT_RETRY: + opt_retry_counter = atol(optarg); + break; + case 's': + opt_dkek_shares = atol(optarg); + break; + case 'f': + opt_force = 1; + break; + case 'i': + opt_key_reference = atol(optarg); + break; + case 'r': + opt_reader = optarg; + break; + case 'v': + verbose++; + break; + case 'w': + opt_wait = 1; + break; + } + } + + CRYPTO_malloc_init(); + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + + memset(&ctx_param, 0, sizeof(sc_context_param_t)); + ctx_param.app_name = app_name; + + r = sc_context_create(&ctx, &ctx_param); + if (r != SC_SUCCESS) { + fprintf(stderr, "Failed to establish context: %s\n", sc_strerror(r)); + return 1; + } + + /* Only change if not in opensc.conf */ + if (verbose > 1 && ctx->debug == 0) { + ctx->debug = verbose; + sc_ctx_log_to_file(ctx, "stderr"); + } + + err = util_connect_card(ctx, &card, opt_reader, opt_wait, verbose); + if (err) + goto end; + + sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0); + r = sc_select_file(card, &path, &file); + + if (do_initialize) { + initialize(card, opt_so_pin, opt_pin, opt_retry_counter, opt_dkek_shares); + } + + if (do_create_dkek_share) { + create_dkek_share(card, opt_filename, opt_iter, opt_password); + } + + if (do_import_dkek_share) { + import_dkek_share(card, opt_filename, opt_iter, opt_password); + } + + if (do_wrap_key) { + wrap_key(card, opt_key_reference, opt_filename, opt_pin); + } + + if (do_unwrap_key) { + unwrap_key(card, opt_key_reference, opt_filename, opt_pin, opt_force); + } + + if (action_count == 0) { + print_info(card, file); + } + +end: + if (card) { + sc_unlock(card); + sc_disconnect_card(card); + } + if (ctx) + sc_release_context(ctx); + + ERR_print_errors_fp(stderr); + return err; +} diff --git a/win32/OpenSC.wxs.in b/win32/OpenSC.wxs.in index d4cbcde0..d24fa710 100755 --- a/win32/OpenSC.wxs.in +++ b/win32/OpenSC.wxs.in @@ -103,6 +103,9 @@ + + + @@ -211,6 +214,7 @@ +