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:
parent
feb2b96127
commit
1a7ca32865
@ -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
367
src/libopensc/card-sc-hsm.c
Normal 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();
|
||||
}
|
||||
|
42
src/libopensc/card-sc-hsm.h
Normal file
42
src/libopensc/card-sc-hsm.h
Normal 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_ */
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
205
src/libopensc/pkcs15-sc-hsm.c
Normal file
205
src/libopensc/pkcs15-sc-hsm.c
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user