Added support for SmartCard-HSM and ECC keys

modified:   src/libopensc/Makefile.am
new file:   src/libopensc/card-sc-hsm.c
new file:   src/libopensc/card-sc-hsm.h
modified:   src/libopensc/cards.h
modified:   src/libopensc/ctx.c
modified:   src/libopensc/pkcs15-prkey.c
new file:   src/libopensc/pkcs15-sc-hsm.c
modified:   src/libopensc/pkcs15-syn.c
This commit is contained in:
Frank Thater 2012-07-31 14:57:00 +02:00 committed by Viktor Tarasov
parent feb2b96127
commit 1a7ca32865
8 changed files with 662 additions and 6 deletions

View File

@ -10,7 +10,7 @@ noinst_HEADERS = cards.h ctbcs.h internal.h esteid.h muscle.h muscle-filesystem.
opensc.h pkcs15.h \
cardctl.h asn1.h log.h \
errors.h types.h compression.h itacns.h iso7816.h \
authentic.h iasecc.h iasecc-sdo.h sm.h
authentic.h iasecc.h iasecc-sdo.h sm.h card-sc-hsm.h
AM_CPPFLAGS = -DOPENSC_CONF_PATH=\"$(sysconfdir)/opensc.conf\"
AM_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(OPTIONAL_OPENCT_CFLAGS) \
@ -38,13 +38,13 @@ libopensc_la_SOURCES = \
card-asepcos.c card-akis.c card-gemsafeV1.c card-rutoken.c \
card-rtecp.c card-westcos.c card-myeid.c card-ias.c \
card-javacard.c card-itacns.c card-authentic.c \
card-iasecc.c iasecc-sdo.c iasecc-sm.c \
card-iasecc.c iasecc-sdo.c iasecc-sm.c card-sc-hsm.c \
\
pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \
pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafeGPK.c \
pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c \
pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c pkcs15-oberthur.c \
pkcs15-itacns.c pkcs15-gemsafeV1.c \
pkcs15-itacns.c pkcs15-gemsafeV1.c pkcs15-sc-hsm.c \
compression.c p15card-helper.c \
libopensc.exports
if WIN32

367
src/libopensc/card-sc-hsm.c Normal file
View File

@ -0,0 +1,367 @@
/*
* card-sc-hsm.c
*
* Read-only driver for the SmartCard-HSM light-weight hardware security module
*
* Copyright (C) 2012 Andreas Schwier, CardContact, Minden, Germany, and others
*
* 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 <string.h>
#include <stdlib.h>
#include "internal.h"
#include "asn1.h"
#include "cardctl.h"
#include "types.h"
#include "card-sc-hsm.h"
/* Static reference to ISO driver */
static const struct sc_card_operations *iso_ops = NULL;
/* Our operations */
static struct sc_card_operations sc_hsm_ops;
/* Our driver description */
static struct sc_card_driver sc_hsm_drv = {
"SmartCard-HSM",
"sc-hsm",
&sc_hsm_ops,
NULL,
0,
NULL
};
/* Known ATRs for SmartCard-HSMs */
static struct sc_atr_table sc_hsm_atrs[] = {
/* standard version */
{"3B:FE:18:00:00:81:31:FE:45:80:31:81:54:48:53:4D:31:73:80:21:40:81:07:FA", NULL, NULL, SC_CARD_TYPE_SC_HSM, 0, NULL},
{"3B:8E:80:01:80:31:81:54:48:53:4D:31:73:80:21:40:81:07:18", NULL, NULL, SC_CARD_TYPE_SC_HSM, 0, NULL},
{NULL, NULL, NULL, 0, 0, NULL}
};
/* Information the driver maintains between calls */
typedef struct sc_hsm_private_data {
sc_security_env_t *env;
u8 algorithm;
} sc_hsm_private_data_t;
static int sc_hsm_match_card(struct sc_card *card)
{
int i;
i = _sc_match_atr(card, sc_hsm_atrs, &card->type);
if (i < 0)
return 0;
return 1;
}
static int sc_hsm_read_binary(sc_card_t *card,
unsigned int idx, u8 *buf, size_t count,
unsigned long flags)
{
sc_context_t *ctx = card->ctx;
sc_apdu_t apdu;
u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 cmdbuff[4];
int r;
if (idx > 0xffff) {
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "invalid EF offset: 0x%X > 0xFFFF", idx);
return SC_ERROR_OFFSET_TOO_LARGE;
}
cmdbuff[0] = 0x54;
cmdbuff[1] = 0x02;
cmdbuff[2] = (idx >> 8) & 0xFF;
cmdbuff[3] = idx & 0xFF;
assert(count <= (card->max_recv_size > 0 ? card->max_recv_size : 256));
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xB1, 0x00, 0x00);
apdu.data = cmdbuff;
apdu.datalen = 4;
apdu.lc = 4;
apdu.le = count;
apdu.resplen = count;
apdu.resp = recvbuf;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
if (apdu.resplen == 0)
SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
memcpy(buf, recvbuf, apdu.resplen);
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (r == SC_ERROR_FILE_END_REACHED)
SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, apdu.resplen);
SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Check SW error");
if (apdu.resplen < count) {
r = sc_hsm_read_binary(card, idx + apdu.resplen, buf + apdu.resplen, count - apdu.resplen, flags);
/* Ignore all but 'corrupted data' errors */
if (r == SC_ERROR_CORRUPTED_DATA)
SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_CORRUPTED_DATA);
else if (r > 0)
apdu.resplen += r;
}
SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, apdu.resplen);
}
static int sc_hsm_list_files(sc_card_t *card, u8 * buf, size_t buflen)
{
sc_apdu_t apdu;
u8 recvbuf[MAX_EXT_APDU_LENGTH];
int r;
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_EXT, 0x58, 0, 0);
apdu.cla = 0x80;
apdu.resp = recvbuf;
apdu.resplen = sizeof(recvbuf);
apdu.le = 0;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "ENUMERATE OBJECTS APDU transmit failed");
memcpy(buf, recvbuf, buflen);
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, apdu.resplen);
}
static int sc_hsm_set_security_env(sc_card_t *card,
const sc_security_env_t *env,
int se_num)
{
sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data;
priv->env = env;
switch(env->algorithm) {
case SC_ALGORITHM_RSA:
// if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) {
// if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1) {
// priv->algorithm = ALGO_RSA_PKCS1_SHA1;
// } else if (env->algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA256) {
// priv->algorithm = ALGO_RSA_PKCS1_SHA256;
// } else {
// SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
// }
// } else {
priv->algorithm = ALGO_RSA_RAW;
// }
break;
case SC_ALGORITHM_EC:
if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_NONE) {
priv->algorithm = ALGO_EC_RAW;
} else if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA1) {
priv->algorithm = ALGO_EC_SHA1;
} else if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA224) {
priv->algorithm = ALGO_EC_SHA224;
} else if (env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA256) {
priv->algorithm = ALGO_EC_SHA256;
} else if (env->algorithm_flags & SC_ALGORITHM_ECDSA_RAW) {
priv->algorithm = ALGO_EC_RAW;
} else {
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
}
break;
default:
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
}
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
}
static int sc_hsm_compute_signature(sc_card_t *card,
const u8 * data, size_t datalen,
u8 * out, size_t outlen)
{
int r;
sc_apdu_t apdu;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data;
assert(card != NULL && data != NULL && out != NULL);
if (priv->env == NULL) {
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_OBJECT_NOT_FOUND);
}
sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x68, priv->env->key_ref[0], priv->algorithm);
apdu.cla = 0x80;
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf); /* FIXME */
apdu.le = 256;
memcpy(sbuf, data, datalen);
apdu.data = sbuf;
apdu.lc = datalen;
apdu.datalen = datalen;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
size_t len = apdu.resplen > outlen ? outlen : apdu.resplen;
memcpy(out, apdu.resp, len);
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, len);
}
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
static int sc_hsm_decipher(sc_card_t *card, const u8 * crgram, size_t crgram_len, u8 * out, size_t outlen)
{
int r;
sc_apdu_t apdu;
sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data;
assert(card != NULL && crgram != NULL && out != NULL);
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x62, priv->env->key_ref[0], 0x21);
apdu.cla = 0x80;
apdu.resp = out;
apdu.resplen = outlen;
/* if less than 256 bytes are expected than set Le to 0x00
* to tell the card the we want everything available (note: we
* always have Le <= crgram_len) */
apdu.le = (outlen >= 256 && crgram_len < 256) ? 256 : outlen;
apdu.data = crgram;
apdu.lc = crgram_len;
apdu.datalen = crgram_len;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, apdu.resplen);
else
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
static int sc_hsm_init(struct sc_card *card)
{
sc_hsm_private_data_t *priv;
int flags,ext_flags;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
priv = calloc(1, sizeof(sc_hsm_private_data_t));
if (!priv)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
card->drv_data = priv;
flags = SC_ALGORITHM_RSA_RAW;
// SC_ALGORITHM_RSA_PAD_PKCS1|
// SC_ALGORITHM_RSA_HASH_SHA1|
// SC_ALGORITHM_RSA_HASH_SHA256;
_sc_card_add_rsa_alg(card, 1024, flags, 0);
_sc_card_add_rsa_alg(card, 1536, flags, 0);
_sc_card_add_rsa_alg(card, 2048, flags, 0);
#if 0
flags = SC_ALGORITHM_ECDSA_RAW|
SC_ALGORITHM_ECDSA_HASH_NONE|
SC_ALGORITHM_ECDSA_HASH_SHA1|
SC_ALGORITHM_ECDSA_HASH_SHA224|
SC_ALGORITHM_ECDSA_HASH_SHA256;
#endif
flags = SC_ALGORITHM_ECDSA_HASH_NONE|
SC_ALGORITHM_ECDSA_HASH_SHA1|
SC_ALGORITHM_ECDSA_HASH_SHA224|
SC_ALGORITHM_ECDSA_HASH_SHA256;
ext_flags = SC_ALGORITHM_EXT_EC_F_P|
SC_ALGORITHM_EXT_EC_ECPARAMETERS|
SC_ALGORITHM_EXT_EC_UNCOMPRESES;
_sc_card_add_ec_alg(card, 192, flags, ext_flags);
_sc_card_add_ec_alg(card, 224, flags, ext_flags);
_sc_card_add_ec_alg(card, 256, flags, ext_flags);
_sc_card_add_ec_alg(card, 320, flags, ext_flags);
card->caps |= SC_CARD_CAP_RNG|SC_CARD_CAP_APDU_EXT;
return 0;
}
static int sc_hsm_finish(sc_card_t * card)
{
sc_hsm_private_data_t *priv = (sc_hsm_private_data_t *) card->drv_data;
free(priv);
return SC_SUCCESS;
}
static struct sc_card_driver * sc_get_driver(void)
{
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
if (iso_ops == NULL)
iso_ops = iso_drv->ops;
sc_hsm_ops = *iso_drv->ops;
sc_hsm_ops.match_card = sc_hsm_match_card;
sc_hsm_ops.read_binary = sc_hsm_read_binary;
sc_hsm_ops.list_files = sc_hsm_list_files;
sc_hsm_ops.set_security_env = sc_hsm_set_security_env;
sc_hsm_ops.compute_signature = sc_hsm_compute_signature;
sc_hsm_ops.decipher = sc_hsm_decipher;
sc_hsm_ops.init = sc_hsm_init;
sc_hsm_ops.finish = sc_hsm_finish;
/* no record oriented file services */
sc_hsm_ops.read_record = NULL;
sc_hsm_ops.write_record = NULL;
sc_hsm_ops.append_record = NULL;
sc_hsm_ops.update_record = NULL;
sc_hsm_ops.update_binary = NULL;
sc_hsm_ops.create_file = NULL;
sc_hsm_ops.delete_file = NULL;
return &sc_hsm_drv;
}
struct sc_card_driver * sc_get_sc_hsm_driver(void)
{
return sc_get_driver();
}

View File

@ -0,0 +1,42 @@
/*
* sc-hsm.h
*
* Copyright (C) 2012 Andreas Schwier, CardContact, 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
*/
#ifndef SC_HSM_H_
#define SC_HSM_H_
#define MAX_EXT_APDU_LENGTH 1014
#define KEY_PREFIX 0xCC /* Hi byte in file identifier for key objects */
#define PRKD_PREFIX 0xC4 /* Hi byte in file identifier for PRKD objects */
#define EE_CERTIFICATE_PREFIX 0xCE /* Hi byte in file identifier for EE certificates */
#define ALGO_RSA_RAW 0x20 /* RSA signature with external padding */
#define ALGO_RSA_PKCS1_SHA1 0x31 /* RSA signature with SHA-1 hash and PKCS#1 V1.5 padding */
#define ALGO_RSA_PKCS1_SHA256 0x33 /* RSA signature with SHA-256 hash and PKCS#1 V1.5 padding */
#define ALGO_RSA_PSS_SHA1 0x41 /* RSA signature with SHA-1 hash and PKCS#1 PSS padding */
#define ALGO_RSA_PSS_SHA256 0x43 /* RSA signature with SHA-256 hash and PKCS#1 PSS padding */
#define ALGO_EC_RAW 0x70 /* ECDSA signature with hash input */
#define ALGO_EC_SHA1 0x71 /* ECDSA signature with SHA-1 hash */
#define ALGO_EC_SHA224 0x72 /* ECDSA signature with SHA-224 hash */
#define ALGO_EC_SHA256 0x73 /* ECDSA signature with SHA-256 hash */
#endif /* SC_HSM_H_ */

View File

@ -187,7 +187,10 @@ enum {
SC_CARD_TYPE_IASECC_GEMALTO,
SC_CARD_TYPE_IASECC_OBERTHUR,
SC_CARD_TYPE_IASECC_SAGEM,
SC_CARD_TYPE_IASECC_AMOS
SC_CARD_TYPE_IASECC_AMOS,
/* SmartCard-HSM */
SC_CARD_TYPE_SC_HSM = 26000,
};
extern sc_card_driver_t *sc_get_default_driver(void);
@ -218,6 +221,7 @@ extern sc_card_driver_t *sc_get_rtecp_driver(void);
extern sc_card_driver_t *sc_get_westcos_driver(void);
extern sc_card_driver_t *sc_get_myeid_driver(void);
extern sc_card_driver_t *sc_get_ias_driver(void);
extern sc_card_driver_t *sc_get_sc_hsm_driver(void);
extern sc_card_driver_t *sc_get_javacard_driver(void);
extern sc_card_driver_t *sc_get_itacns_driver(void);
extern sc_card_driver_t *sc_get_authentic_driver(void);

View File

@ -96,6 +96,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
{ "rutoken_ecp",(void *(*)(void)) sc_get_rtecp_driver },
{ "westcos", (void *(*)(void)) sc_get_westcos_driver },
{ "myeid", (void *(*)(void)) sc_get_myeid_driver },
{ "sc-hsm", (void *(*)(void)) sc_get_sc_hsm_driver },
/* Here should be placed drivers that need some APDU transactions to
* recognise its cards. */

View File

@ -130,14 +130,35 @@ static const struct sc_asn1_entry c_asn1_prk_dsa_attr[C_ASN1_PRK_DSA_ATTR_SIZE]
{ NULL, 0, 0, 0, NULL, NULL }
};
#define C_ASN1_PRKEY_SIZE 4
/*
* The element fieldSize is a proprietary extension to ISO 7816-15, providing to the middleware
* the size of the underlying ECC field. This value is required for determine a proper size for
* buffer allocations. The field follows the definition for modulusLength in RSA keys
*/
#define C_ASN1_ECCKEY_ATTR 4
static const struct sc_asn1_entry c_asn1_ecckey_attr[C_ASN1_ECCKEY_ATTR] = {
{ "value", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_EMPTY_ALLOWED, NULL, NULL },
{ "fieldSize", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL },
{ "keyInfo", SC_ASN1_INTEGER, SC_ASN1_TAG_INTEGER, SC_ASN1_OPTIONAL, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
#define C_ASN1_PRK_ECC_ATTR 2
static const struct sc_asn1_entry c_asn1_prk_ecc_attr[C_ASN1_PRK_ECC_ATTR] = {
{ "privateECCKeyAttributes", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
#define C_ASN1_PRKEY_SIZE 5
static const struct sc_asn1_entry c_asn1_prkey[C_ASN1_PRKEY_SIZE] = {
{ "privateRSAKey", SC_ASN1_PKCS15_OBJECT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
{ "privateECCKey", SC_ASN1_PKCS15_OBJECT, 0 | SC_ASN1_CTX | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
{ "privateDSAKey", SC_ASN1_PKCS15_OBJECT, 2 | SC_ASN1_CTX | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
{ "privateGOSTR3410Key", SC_ASN1_PKCS15_OBJECT, 4 | SC_ASN1_CTX | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card,
struct sc_pkcs15_object *obj,
const u8 ** buf, size_t *buflen)
@ -158,11 +179,13 @@ int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card,
struct sc_asn1_entry asn1_dsakey_value_attr[C_ASN1_DSAKEY_VALUE_ATTR_SIZE];
struct sc_asn1_entry asn1_gostr3410key_attr[C_ASN1_GOSTR3410KEY_ATTR_SIZE];
struct sc_asn1_entry asn1_prk_gostr3410_attr[C_ASN1_PRK_GOSTR3410_ATTR_SIZE];
struct sc_asn1_entry asn1_ecckey_attr[C_ASN1_ECCKEY_ATTR], asn1_prk_ecc_attr[C_ASN1_PRK_ECC_ATTR];
struct sc_asn1_entry asn1_prkey[C_ASN1_PRKEY_SIZE];
struct sc_asn1_entry asn1_supported_algorithms[C_ASN1_SUPPORTED_ALGORITHMS_SIZE];
struct sc_asn1_pkcs15_object rsa_prkey_obj = {obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_rsa_attr};
struct sc_asn1_pkcs15_object dsa_prkey_obj = {obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_dsa_attr};
struct sc_asn1_pkcs15_object gostr3410_prkey_obj = {obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_gostr3410_attr};
struct sc_asn1_pkcs15_object ecc_prkey_obj = { obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_ecc_attr };
sc_copy_asn1_entry(c_asn1_prkey, asn1_prkey);
sc_copy_asn1_entry(c_asn1_supported_algorithms, asn1_supported_algorithms);
@ -175,6 +198,8 @@ int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card,
sc_copy_asn1_entry(c_asn1_dsakey_i_p_attr, asn1_dsakey_i_p_attr);
sc_copy_asn1_entry(c_asn1_prk_gostr3410_attr, asn1_prk_gostr3410_attr);
sc_copy_asn1_entry(c_asn1_gostr3410key_attr, asn1_gostr3410key_attr);
sc_copy_asn1_entry(c_asn1_prk_ecc_attr, asn1_prk_ecc_attr);
sc_copy_asn1_entry(c_asn1_ecckey_attr, asn1_ecckey_attr);
sc_copy_asn1_entry(c_asn1_com_prkey_attr, asn1_com_prkey_attr);
sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr);
@ -182,10 +207,12 @@ int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card,
sc_format_asn1_entry(asn1_prkey + 0, &rsa_prkey_obj, NULL, 0);
sc_format_asn1_entry(asn1_prkey + 1, &dsa_prkey_obj, NULL, 0);
sc_format_asn1_entry(asn1_prkey + 2, &gostr3410_prkey_obj, NULL, 0);
sc_format_asn1_entry(asn1_prkey + 3, &ecc_prkey_obj, NULL, 0);
sc_format_asn1_entry(asn1_prk_rsa_attr + 0, asn1_rsakey_attr, NULL, 0);
sc_format_asn1_entry(asn1_prk_dsa_attr + 0, asn1_dsakey_attr, NULL, 0);
sc_format_asn1_entry(asn1_prk_gostr3410_attr + 0, asn1_gostr3410key_attr, NULL, 0);
sc_format_asn1_entry(asn1_prk_ecc_attr + 0, asn1_ecckey_attr, NULL, 0);
sc_format_asn1_entry(asn1_rsakey_attr + 0, &info.path, NULL, 0);
sc_format_asn1_entry(asn1_rsakey_attr + 1, &info.modulus_length, NULL, 0);
@ -200,6 +227,9 @@ int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card,
sc_format_asn1_entry(asn1_gostr3410key_attr + 2, &gostr3410_params[1], NULL, 0);
sc_format_asn1_entry(asn1_gostr3410key_attr + 3, &gostr3410_params[2], NULL, 0);
sc_format_asn1_entry(asn1_ecckey_attr + 0, &info.path, NULL, 0);
sc_format_asn1_entry(asn1_ecckey_attr + 1, &info.field_length, NULL, 0);
sc_format_asn1_entry(asn1_com_key_attr + 0, &info.id, NULL, 0);
sc_format_asn1_entry(asn1_com_key_attr + 1, &info.usage, &usage_len, 0);
sc_format_asn1_entry(asn1_com_key_attr + 2, &info.native, NULL, 0);
@ -246,8 +276,11 @@ int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card,
keyinfo_gostparams->gostr3411 = gostr3410_params[1];
keyinfo_gostparams->gost28147 = gostr3410_params[2];
}
else if (asn1_prkey[3].flags & SC_ASN1_PRESENT) {
obj->type = SC_PKCS15_TYPE_PRKEY_EC;
}
else {
sc_log(ctx, "Neither RSA or DSA or GOSTR3410 key in PrKDF entry.");
sc_log(ctx, "Neither RSA or DSA or GOSTR3410 or ECC key in PrKDF entry.");
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT);
}

View File

@ -0,0 +1,205 @@
/*
* pkcs15-sc-hsm.c : Initialize PKCS#15 emulation
*
* Copyright (C) 2012 Andreas Schwier, CardContact, 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 <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "internal.h"
#include "pkcs15.h"
#include "asn1.h"
#include "card-sc-hsm.h"
/* Our AID */
static struct sc_aid sc_hsm_aid = { { 0xE8,0x2B,0x06,0x01,0x04,0x01,0x81,0xC3,0x1F,0x02,0x01 }, 11 };
/*
* Initialize PKCS#15 emulation with user PIN, private keys and certificate objects
*
*/
static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card)
{
sc_card_t *card = p15card->card;
sc_file_t *file = NULL;
sc_path_t path;
u8 filelist[MAX_EXT_APDU_LENGTH];
int filelistlength;
int r, i;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
p15card->tokeninfo->label = strdup("SmartCard-HSM");
p15card->tokeninfo->manufacturer_id = strdup("CardContact");
struct sc_app_info *appinfo = calloc(1, sizeof(struct sc_app_info));
if (appinfo == NULL) {
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
}
appinfo->label = strdup(p15card->tokeninfo->label);
appinfo->aid = sc_hsm_aid;
appinfo->ddo.aid = sc_hsm_aid;
p15card->app = appinfo;
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);
// ToDo: Extract version number
sc_file_free(file);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Could not select SmartCard-HSM application");
// Define UserPIN
struct sc_pkcs15_auth_info pin_info;
struct sc_pkcs15_object pin_obj;
memset(&pin_info, 0, sizeof(pin_info));
memset(&pin_obj, 0, sizeof(pin_obj));
pin_info.auth_id.len = 1;
pin_info.auth_id.value[0] = 1;
pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
pin_info.attrs.pin.reference = 0x81;
pin_info.attrs.pin.flags = 0;
pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
pin_info.attrs.pin.min_length = 4;
pin_info.attrs.pin.stored_length = 0;
pin_info.attrs.pin.max_length = 16;
pin_info.attrs.pin.pad_char = '\0';
pin_info.tries_left = 3;
pin_info.max_tries = 3;
strlcpy(pin_obj.label, "UserPIN", sizeof(pin_obj.label));
pin_obj.flags = pin_info.attrs.pin.flags;
r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
if (r < 0)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
filelistlength = sc_list_files(card, filelist, sizeof(filelist));
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Could not enumerate file and key identifier");
for (i = 0; i < filelistlength; i += 2) {
/* Look for private key files */
if (filelist[i] != KEY_PREFIX) {
continue;
}
u8 fid[2];
u8 prkdbin[512];
sc_pkcs15_object_t prkd;
u8 keyid = filelist[i + 1];
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, &file);
if (r != SC_SUCCESS) {
continue;
}
sc_file_free(file);
r = sc_read_binary(p15card->card, 0, prkdbin, sizeof(prkdbin), 0);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Could not read EF.PRKD");
memset(&prkd, 0, sizeof(prkd));
const u8 *ptr = prkdbin;
size_t len = r;
sc_pkcs15_decode_prkdf_entry(p15card, &prkd, &ptr, &len);
/* All keys require user PIN authentication */
prkd.auth_id.len = 1;
prkd.auth_id.value[0] = 1;
/*
* Set private key flag as all keys are private anyway
*/
prkd.flags |= SC_PKCS15_CO_FLAG_PRIVATE;
sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *)prkd.data;
key_info->key_reference = keyid;
/*
* Set path.aid.len to 0 to prevent re-selection of applet when using the key
*/
key_info->path.aid.len = 0;
if (prkd.type == SC_PKCS15_TYPE_PRKEY_RSA) {
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkd, key_info);
} else {
r = sc_pkcs15emu_add_ec_prkey(p15card, &prkd, key_info);
}
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Could not decode EF.PRKD");
/* Check if we also have a certificate for the private key */
fid[0] = EE_CERTIFICATE_PREFIX;
sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0);
r = sc_select_file(card, &path, &file);
if (r != SC_SUCCESS) {
continue;
}
sc_file_free(file);
struct sc_pkcs15_cert_info cert_info;
struct sc_pkcs15_object cert_obj;
memset(&cert_info, 0, sizeof(cert_info));
memset(&cert_obj, 0, sizeof(cert_obj));
cert_info.id.value[0] = keyid;
cert_info.id.len = 1;
cert_info.path = path;
cert_info.path.count = -1;
strlcpy(cert_obj.label, prkd.label, sizeof(cert_obj.label));
r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Could not add certificate");
}
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS);
}
int sc_pkcs15emu_sc_hsm_init_ex(sc_pkcs15_card_t *p15card,
sc_pkcs15emu_opt_t *opts)
{
if (opts && (opts->flags & SC_PKCS15EMU_FLAGS_NO_CHECK)) {
return sc_pkcs15emu_sc_hsm_init(p15card);
} else {
if (p15card->card->type != SC_CARD_TYPE_SC_HSM) {
return SC_ERROR_WRONG_CARD;
}
return sc_pkcs15emu_sc_hsm_init(p15card);
}
}

View File

@ -65,6 +65,8 @@ extern int sc_pkcs15emu_oberthur_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
extern int sc_pkcs15emu_itacns_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
extern int sc_pkcs15emu_sc_hsm_init_ex(sc_pkcs15_card_t *,
sc_pkcs15emu_opt_t *);
static struct {
const char * name;
@ -87,6 +89,7 @@ static struct {
{ "entersafe", sc_pkcs15emu_entersafe_init_ex },
{ "pteid", sc_pkcs15emu_pteid_init_ex },
{ "oberthur", sc_pkcs15emu_oberthur_init_ex },
{ "sc-hsm", sc_pkcs15emu_sc_hsm_init_ex },
{ NULL, NULL }
};
@ -109,6 +112,7 @@ int sc_pkcs15_is_emulation_only(sc_card_t *card)
case SC_CARD_TYPE_GEMSAFEV1_PTEID:
case SC_CARD_TYPE_OPENPGP_V1:
case SC_CARD_TYPE_OPENPGP_V2:
case SC_CARD_TYPE_SC_HSM:
return 1;
default:
return 0;