sc-hsm: Added sc-hsm-tool with DKEK support and key wrap / unwrap

This commit is contained in:
Andreas Schwier 2012-10-14 14:35:46 +02:00 committed by Viktor Tarasov
parent 8d35b2cf58
commit ffb20e5916
15 changed files with 1378 additions and 11 deletions

217
doc/tools/sc-hsm-tool.1.xml Normal file
View File

@ -0,0 +1,217 @@
<?xml version="1.0" encoding="UTF-8"?>
<refentry id="sc-hsm-tool">
<refmeta>
<refentrytitle>sc-hsm-tool</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="productname">OpenSC</refmiscinfo>
<refmiscinfo class="manual">OpenSC Tools</refmiscinfo>
<refmiscinfo class="source">opensc</refmiscinfo>
</refmeta>
<refnamediv>
<refname>sc-hsm-tool</refname>
<refpurpose>smart card utility for SmartCard-HSM</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>sc-hsm-tool</command>
<arg choice="opt"><replaceable class="option">OPTIONS</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<para>
The <command>sc-hsm-tool</command> 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.
</para>
</refsect1>
<refsect1>
<title>Options</title>
<para>
<variablelist>
<varlistentry>
<term>
<option>--initialize</option>,
<option>-X</option>
</term>
<listitem>
<para>Initialize token, removing all existing keys, certificates and files.</para>
<para>Use <option>--so-pin</option> to define SO-PIN for first initialization or to verify in subsequent
initializations.</para>
<para>Use <option>--pin</option> to define the initial user pin value.</para>
<para>Use <option>--pin-retry</option> to define the maximum number of wrong user PIN presentations.</para>
<para>Use with <option>--dkek-shares</option> to enable key wrap / unwrap.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--create-dkek-share</option> <replaceable>filename</replaceable>,
<option>-C</option> <replaceable>filename</replaceable>
</term>
<listitem>
<para>Create a DKEK share encrypted under a user supplied password and saved to the file
given as parameter.</para>
<para>Use <option>--password</option> to provide a password for encryption rather than prompting for one.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--import-dkek-share</option> <replaceable>filename</replaceable>,
<option>-I</option> <replaceable>filename</replaceable>
</term>
<listitem>
<para>Prompt for user password, read and decrypt DKEK share and import into SmartCard-HSM.</para>
<para>Use <option>--password</option> to provide a password for decryption rather than prompting for one.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--wrap-key</option> <replaceable>filename</replaceable>,
<option>-W</option> <replaceable>filename</replaceable>
</term>
<listitem>
<para>Wrap the key referenced in <option>--key-reference</option> and save with it together with the key description
and certificate to the given file.</para>
<para>Use <option>--pin</option> to provide the user PIN on the command line.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--unwrap-key</option> <replaceable>filename</replaceable>,
<option>-U</option> <replaceable>filename</replaceable>
</term>
<listitem>
<para>Read wrapped key, description and certificate from file and import into SmartCard-HSM
under the key reference given in <option>--key-reference</option>.</para>
<para>Determine the key reference using the output of <command>pkcs15-tool -D</command>.</para>
<para>Use <option>--pin</option> to provide a user PIN on the command line.</para>
<para>Use <option>--force</option> to remove any key, key description or certificate in the way.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--dkek-shares</option> <replaceable>number-of-shares</replaceable>,
<option>-s</option> <replaceable>number-of-shares</replaceable>
</term>
<listitem>
<para>Define the number of DKEK shares to use for recreating the DKEK.</para>
<para>This is an optional parameter. Using <option>--initialize</option> without
<option>--dkek-shares</option> will disable the DKEK completely.</para>
<para>Using <option>--dkek-shares</option> 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.</para>
<para>After using <option>--initialize</option> 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.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--so-pin</option> <replaceable>value</replaceable>
</term>
<listitem>
<para>Define SO-PIN for initialization.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--pin</option> <replaceable>value</replaceable>
</term>
<listitem>
<para>Define user PIN for initialization, wrap or unwrap operation.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--pin-retry</option> <replaceable>value</replaceable>
</term>
<listitem>
<para>Define number of PIN retries for user PIN during initialization. Default is 3.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--password</option> <replaceable>value</replaceable>
</term>
<listitem>
<para>Define password for DKEK share encryption.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--force</option>
</term>
<listitem>
<para>Force removal of existing key, description and certificate.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--reader</option> <replaceable>num</replaceable>,
<option>-r</option> <replaceable>num</replaceable>
</term>
<listitem><para>Use the given reader number. The default is
<literal>0</literal>, the first reader in the system.</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--wait</option>,
<option>-w</option>
</term>
<listitem><para>Wait for a card to be inserted</para></listitem>
</varlistentry>
<varlistentry>
<term>
<option>--verbose</option>,
<option>-v</option>
</term>
<listitem><para>Causes <command>sc-hsm-tool</command> to be more verbose.
Specify this flag several times to enable debug output in the opensc
library.</para></listitem>
</varlistentry>
</variablelist>
</para>
</refsect1>
<refsect1>
<title>Examples</title>
<para>Create a DKEK share:</para>
<para><command>sc-hsm-tool --create-dkek-share dkek-share-1.pbe</command></para>
<para>Initialize SmartCard-HSM to use a single DKEK share</para>
<para><command>sc-hsm-tool --initialize --so-pin 3537363231383830 --pin 648219 --dkek-shares 1</command></para>
<para>Import DKEK share</para>
<para><command>sc-hsm-tool --import-dkek-share dkek-share-1.pbe</command></para>
<para>Wrap referenced key, description and certificate</para>
<para><command>sc-hsm-tool --wrap-key wrap-key.bin --key-reference 1 --pin 648219</command></para>
<para>Unwrap key into same or in different SmartCard-HSM with the same DKEK</para>
<para><command>sc-hsm-tool --unwrap-key wrap-key.bin --key-reference 10 --pin 648219 --force</command></para>
</refsect1>
<refsect1>
<title>See also</title>
<para>
<citerefentry>
<refentrytitle>opensc-tool</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -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 *, int _sc_asn1_encode(struct sc_context *, const struct sc_asn1_entry *,
u8 **, size_t *, int); 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, const u8 *sc_asn1_find_tag(struct sc_context *ctx, const u8 * buf,
size_t buflen, unsigned int tag, size_t *taglen); size_t buflen, unsigned int tag, size_t *taglen);
const u8 *sc_asn1_verify_tag(struct sc_context *ctx, const u8 * buf, const u8 *sc_asn1_verify_tag(struct sc_context *ctx, const u8 * buf,

View File

@ -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, static int sc_hsm_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data,
int *tries_left) int *tries_left)
{ {
sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data; 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) { if (data->pin_reference == 0x88) {
// Save SO PIN for later use in init pin // Save SO PIN for later use in init pin
memcpy(priv->initpw, data->pin1.data, sizeof(priv->initpw)); 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) static int sc_hsm_init_token(sc_card_t *card, sc_cardctl_pkcs11_init_token_t *params)
{ {
sc_context_t *ctx = card->ctx; 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); return sc_hsm_init_pin(card, (sc_cardctl_pkcs11_init_pin_t *)ptr);
case SC_CARDCTL_SC_HSM_GENERATE_KEY: case SC_CARDCTL_SC_HSM_GENERATE_KEY:
return sc_hsm_generate_keypair(card, (sc_cardctl_sc_hsm_keygen_info_t *)ptr); 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; return SC_ERROR_NOT_SUPPORTED;
} }

View File

@ -47,6 +47,8 @@
#define ALGO_EC_SHA256 0x73 /* ECDSA signature with SHA-256 hash */ #define ALGO_EC_SHA256 0x73 /* ECDSA signature with SHA-256 hash */
#define ALGO_EC_DH 0x80 /* ECDH key derivation */ #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 */ /* Information the driver maintains between calls */
typedef struct sc_hsm_private_data { typedef struct sc_hsm_private_data {

View File

@ -244,7 +244,11 @@ enum {
* SmartCard-HSM * SmartCard-HSM
*/ */
SC_CARDCTL_SC_HSMP_BASE = _CTL_PREFIX('S', 'C', 'H'), 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 { enum {
@ -908,6 +912,28 @@ typedef struct sc_cardctl_sc_hsm_keygen_info {
size_t gakpresponse_len; /* Size of response */ size_t gakpresponse_len; /* Size of response */
} sc_cardctl_sc_hsm_keygen_info_t; } 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 #ifdef __cplusplus
} }

View File

@ -69,7 +69,8 @@ const char *sc_strerror(int error)
"Data object not found", "Data object not found",
"Not enough memory on card", "Not enough memory on card",
"Part of returned data may be corrupted", "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; const int card_base = -SC_ERROR_CARD_CMD_FAILED;

View File

@ -67,6 +67,7 @@ extern "C" {
#define SC_ERROR_NOT_ENOUGH_MEMORY -1217 #define SC_ERROR_NOT_ENOUGH_MEMORY -1217
#define SC_ERROR_CORRUPTED_DATA -1218 #define SC_ERROR_CORRUPTED_DATA -1218
#define SC_ERROR_FILE_END_REACHED -1219 #define SC_ERROR_FILE_END_REACHED -1219
#define SC_ERROR_REF_DATA_NOT_USABLE -1220
/* Returned by OpenSC library when called with invalid arguments */ /* Returned by OpenSC library when called with invalid arguments */
#define SC_ERROR_INVALID_ARGUMENTS -1300 #define SC_ERROR_INVALID_ARGUMENTS -1300

View File

@ -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, int _sc_card_add_ec_alg(struct sc_card *card, unsigned int key_length,
unsigned long flags, unsigned long ext_flags); 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 */ /* pkcs1 padding/encoding functions */
/********************************************************************/ /********************************************************************/

View File

@ -51,7 +51,7 @@ static const struct sc_card_error iso7816_errors[] = {
{ 0x6981, SC_ERROR_CARD_CMD_FAILED, "Command incompatible with file structure" }, { 0x6981, SC_ERROR_CARD_CMD_FAILED, "Command incompatible with file structure" },
{ 0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Security status not satisfied" }, { 0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Security status not satisfied" },
{ 0x6983, SC_ERROR_AUTH_METHOD_BLOCKED, "Authentication method blocked" }, { 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" }, { 0x6985, SC_ERROR_NOT_ALLOWED, "Conditions of use not satisfied" },
{ 0x6986, SC_ERROR_NOT_ALLOWED, "Command not allowed (no current EF)" }, { 0x6986, SC_ERROR_NOT_ALLOWED, "Command not allowed (no current EF)" },
{ 0x6987, SC_ERROR_INCORRECT_PARAMETERS,"Expected SM data objects missing" }, { 0x6987, SC_ERROR_INCORRECT_PARAMETERS,"Expected SM data objects missing" },

View File

@ -44,6 +44,7 @@ sc_asn1_decode_object_id
sc_asn1_encode sc_asn1_encode
sc_asn1_encode_object_id sc_asn1_encode_object_id
sc_asn1_encode_algorithm_id sc_asn1_encode_algorithm_id
sc_asn1_read_tag
sc_asn1_find_tag sc_asn1_find_tag
sc_asn1_print_tags sc_asn1_print_tags
sc_asn1_put_tag sc_asn1_put_tag

View File

@ -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; file->status = SC_FILE_STATUS_ACTIVATED;
r = sc_create_file(card, file); r = sc_create_file(card, file);
sc_file_free(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); 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; cvcpo = cvcbin;
sc_asn1_read_tag(&cvcpo, cvclen, &cla, &tag, &taglen); sc_asn1_read_tag((const u8 **)&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_hsm_keyinfo.key_id = key_info->key_reference; sc_hsm_keyinfo.key_id = key_info->key_reference;
sc_hsm_keyinfo.auth_key_id = 0; sc_hsm_keyinfo.auth_key_id = 0;

View File

@ -7,7 +7,7 @@ noinst_HEADERS = util.h
bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-tool pkcs15-crypt \ bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-tool pkcs15-crypt \
pkcs11-tool cardos-tool eidenv openpgp-tool iasecc-tool pkcs11-tool cardos-tool eidenv openpgp-tool iasecc-tool
if ENABLE_OPENSSL 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 endif
# compile with $(PTHREAD_CFLAGS) to allow debugging with gdb # 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) openpgp_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
iasecc_tool_SOURCES = iasecc-tool.c util.c iasecc_tool_SOURCES = iasecc-tool.c util.c
iasecc_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS) iasecc_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
sc_hsm_tool_SOURCES = sc-hsm-tool.c util.c
if WIN32 if WIN32
opensc_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc 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 westcos_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc
openpgp_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc openpgp_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc
iasecc_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 endif

View File

@ -3,7 +3,7 @@ TOPDIR = ..\..
!INCLUDE $(TOPDIR)\win32\Make.rules.mak !INCLUDE $(TOPDIR)\win32\Make.rules.mak
TARGETS = opensc-tool.exe opensc-explorer.exe pkcs15-tool.exe pkcs15-crypt.exe \ 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) $(PROGRAMS_OPENSSL)
$(TARGETS): $(TOPDIR)\win32\versioninfo.res util.obj $(TARGETS): $(TOPDIR)\win32\versioninfo.res util.obj

913
src/tools/sc-hsm-tool.c Normal file
View File

@ -0,0 +1,913 @@
/*
* sc-hsm-tool.c: SmartCard-HSM Management Tool
*
* Copyright (C) 2001 Juha Yrjölä <juha.yrjola@iki.fi>
* 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 <stdio.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <sys/stat.h>
/* Requires openssl for dkek import */
#include <openssl/opensslconf.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#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 <filename>",
"Import DKEK key share <filename>",
"Wrap key and save to <filename>",
"Unwrap key read from <filename>",
"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 <arg> [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 *)&param);
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 <filename>\".\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;
}

View File

@ -103,6 +103,9 @@
<Component Id="pkcs15_crypt.exe" Guid="*" Win64="$(var.Win64YesNo)"> <Component Id="pkcs15_crypt.exe" Guid="*" Win64="$(var.Win64YesNo)">
<File Source="$(var.SOURCE_DIR)\src\tools\pkcs15-crypt.exe" Vital="yes"/> <File Source="$(var.SOURCE_DIR)\src\tools\pkcs15-crypt.exe" Vital="yes"/>
</Component> </Component>
<Component Id="sc_hsm_tool.exe" Guid="*" Win64="$(var.Win64YesNo)">
<File Source="$(var.SOURCE_DIR)\src\tools\sc-hsm-tool.exe" Vital="yes"/>
</Component>
</Directory> </Directory>
<Directory Id="INSTALLDIR_PROFILES" Name="profiles"> <Directory Id="INSTALLDIR_PROFILES" Name="profiles">
<Component Id="pkcs15.profile" Guid="*" Win64="$(var.Win64YesNo)"> <Component Id="pkcs15.profile" Guid="*" Win64="$(var.Win64YesNo)">
@ -211,6 +214,7 @@
<ComponentRef Id="pkcs15_init.exe"/> <ComponentRef Id="pkcs15_init.exe"/>
<ComponentRef Id="pkcs15_tool.exe"/> <ComponentRef Id="pkcs15_tool.exe"/>
<ComponentRef Id="pkcs15_crypt.exe"/> <ComponentRef Id="pkcs15_crypt.exe"/>
<ComponentRef Id="sc_hsm_tool.exe"/>
<!-- TODO: Not all profiles are listed! --> <!-- TODO: Not all profiles are listed! -->
<ComponentRef Id="pkcs15.profile"/> <ComponentRef Id="pkcs15.profile"/>
<ComponentRef Id="asepcos.profile"/> <ComponentRef Id="asepcos.profile"/>