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 *,
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,

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,
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;
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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;

View File

@ -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

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,
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 */
/********************************************************************/

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" },
{ 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" },

View File

@ -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

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;
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;

View File

@ -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

View File

@ -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

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