Modifications to support EC and ECDSA for

emulated cards. True PKCS#15 cards with EC 
will need additional changes. 

Main changes are in framework-pkcs15.c, mechanism.c,
padding.c, pkcs15-algo.c and pkcs15-sec.c 
where switch statements for key type, and testing
of flags was modified to make it easier to add 
additional key types in the future. 

The code was tested using RSA and ECDSA using a PIV card 
from pkcs11-tool, OpenSSL and Thunderbird with 
modifications to NSS-3.12.7 to get ECDSA to sign e-mail. 

Only named curves are supported for ECDSA, ECDH is still 
needed. pkcs11-tool has only minimal changes need to work 
with the -O option to list EC keys. 

One additional line was added to pkcs15-sec.c which 
should get GOSTR sign to work. 

libp11 and engine do not yet have EC support. 

 --This line, and those below, will be ignored--

M    src/tools/piv-tool.c
M    src/tools/pkcs11-tool.c
M    src/pkcs11/framework-pkcs15.c
M    src/pkcs11/mechanism.c
M    src/pkcs11/pkcs11-object.c
M    src/libopensc/pkcs15-prkey.c
M    src/libopensc/card-piv.c
M    src/libopensc/padding.c
M    src/libopensc/cardctl.h
M    src/libopensc/pkcs15-algo.c
M    src/libopensc/libopensc.exports
M    src/libopensc/pkcs15-piv.c
M    src/libopensc/pkcs15-sec.c


git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4904 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
dengert 2010-12-01 20:08:42 +00:00
parent e2bd16ecd0
commit c2fe4609a9
13 changed files with 1097 additions and 435 deletions

View File

@ -46,7 +46,7 @@
enum { enum {
PIV_OBJ_CCC = 0, PIV_OBJ_CCC = 0,
PIV_OBJ_CHUI, PIV_OBJ_CHUI,
PIV_OBJ_UCHUI, /* new with 800-73-2 */ /* PIV_OBJ_UCHUI is not in new with 800-73-2 */
PIV_OBJ_X509_PIV_AUTH, PIV_OBJ_X509_PIV_AUTH,
PIV_OBJ_CHF, PIV_OBJ_CHF,
PIV_OBJ_PI, PIV_OBJ_PI,
@ -137,6 +137,7 @@ typedef struct piv_private_data {
int rwb_state; /* first time -1, 0, in middle, 1 at eof */ int rwb_state; /* first time -1, 0, in middle, 1 at eof */
int key_ref; /* saved from set_security_env and */ int key_ref; /* saved from set_security_env and */
int alg_id; /* used in decrypt, signature */ int alg_id; /* used in decrypt, signature */
int key_size; /* RSA: modulus_bits EC: field_length in bits */
u8* w_buf; /* write_binary buffer */ u8* w_buf; /* write_binary buffer */
size_t w_buf_len; /* length of w_buff */ size_t w_buf_len; /* length of w_buff */
piv_obj_cache_t obj_cache[PIV_OBJ_LAST_ENUM]; piv_obj_cache_t obj_cache[PIV_OBJ_LAST_ENUM];
@ -173,6 +174,10 @@ static struct piv_aid piv_aids[] = {
{0, 9, 0, NULL } {0, 9, 0, NULL }
}; };
/* The EC curves supported by PIV */
static u8 oid_prime256v1[] = {"\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"};
static u8 oid_secp384r1[] = {"\x06\x05\x2b\x81\x04\x00\x22"};
/* /*
* Flags in the piv_object: * Flags in the piv_object:
* PIV_OBJECT_NOT_PRESENT: the presents of the object is * PIV_OBJECT_NOT_PRESENT: the presents of the object is
@ -199,8 +204,6 @@ static const struct piv_object piv_objects[] = {
"2.16.840.1.101.3.7.1.219.0", 3, "\x5F\xC1\x07", "\xDB\x00", 0}, "2.16.840.1.101.3.7.1.219.0", 3, "\x5F\xC1\x07", "\xDB\x00", 0},
{ PIV_OBJ_CHUI, "Card Holder Unique Identifier", { PIV_OBJ_CHUI, "Card Holder Unique Identifier",
"2.16.840.1.101.3.7.2.48.0", 3, "\x5F\xC1\x02", "\x30\x00", 0}, "2.16.840.1.101.3.7.2.48.0", 3, "\x5F\xC1\x02", "\x30\x00", 0},
{ PIV_OBJ_UCHUI, "Unsigned Card Holder Unique Identifier",
"2.16.840.1.101.3.7.2.48.1", 3, "\x5F\xC1\x04", "\x30\x10", 0},
{ PIV_OBJ_X509_PIV_AUTH, "X.509 Certificate for PIV Authentication", { PIV_OBJ_X509_PIV_AUTH, "X.509 Certificate for PIV Authentication",
"2.16.840.1.101.3.7.2.1.1", 3, "\x5F\xC1\x05", "\x01\x01", PIV_OBJECT_TYPE_CERT} , "2.16.840.1.101.3.7.2.1.1", 3, "\x5F\xC1\x05", "\x01\x01", PIV_OBJECT_TYPE_CERT} ,
{ PIV_OBJ_CHF, "Card Holder Fingerprints", { PIV_OBJ_CHF, "Card Holder Fingerprints",
@ -344,7 +347,6 @@ static const struct piv_object piv_objects[] = {
"2.16.840.1.101.3.7.2.9999.119", 2, "\x94\x06", "\x94\x06", PIV_OBJECT_TYPE_PUBKEY}, "2.16.840.1.101.3.7.2.9999.119", 2, "\x94\x06", "\x94\x06", PIV_OBJECT_TYPE_PUBKEY},
{ PIV_OBJ_9506, "Pub 95 key ", { PIV_OBJ_9506, "Pub 95 key ",
"2.16.840.1.101.3.7.2.9999.120", 2, "\x95\x06", "\x95\x06", PIV_OBJECT_TYPE_PUBKEY}, "2.16.840.1.101.3.7.2.9999.120", 2, "\x95\x06", "\x95\x06", PIV_OBJECT_TYPE_PUBKEY},
{ PIV_OBJ_LAST_ENUM, "", "", 0, "", "", 0} { PIV_OBJ_LAST_ENUM, "", "", 0, "", "", 0}
}; };
@ -491,8 +493,7 @@ static int piv_general_io(sc_card_t *card, int ins, int p1, int p2,
r = sc_check_sw(card, apdu.sw1, apdu.sw2); r = sc_check_sw(card, apdu.sw1, apdu.sw2);
/*TODO may be 6c nn if reading only the length */ /* TODO: - DEE look later at tag vs size read too */
/* TODO look later at tag vs size read too */
if (r < 0) { if (r < 0) {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Card returned error "); sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Card returned error ");
goto err; goto err;
@ -549,7 +550,7 @@ err:
/* Add the PIV-II operations */ /* Add the PIV-II operations */
/* Should use our own keydata, actually should be common to all cards */ /* Should use our own keydata, actually should be common to all cards */
/* only do RSA for now */ /* RSA and EC are added. */
static int piv_generate_key(sc_card_t *card, static int piv_generate_key(sc_card_t *card,
sc_cardctl_piv_genkey_info_t *keydata) sc_cardctl_piv_genkey_info_t *keydata)
@ -573,6 +574,10 @@ static int piv_generate_key(sc_card_t *card,
keydata->exponent = 0; keydata->exponent = 0;
keydata->pubkey = NULL; keydata->pubkey = NULL;
keydata->pubkey_len = 0; keydata->pubkey_len = 0;
keydata->ecparam = NULL; /* will show size as we only support 2 curves */
keydata->ecparam_len = 0;
keydata->ecpoint = NULL;
keydata->ecpoint_len = 0;
out_len = 3; out_len = 3;
outdata[0] = 0x80; outdata[0] = 0x80;
@ -582,7 +587,15 @@ static int piv_generate_key(sc_card_t *card,
case 0x05: keydata->key_bits = 3072; break; case 0x05: keydata->key_bits = 3072; break;
case 0x06: keydata->key_bits = 1024; break; case 0x06: keydata->key_bits = 1024; break;
case 0x07: keydata->key_bits = 2048; break; case 0x07: keydata->key_bits = 2048; break;
/* TODO for EC, also set then curve parameter as the OID */ /* TODO: - DEE For EC, also set the curve parameter as the OID */
case 0x11: keydata->key_bits = 0;
keydata->ecparam =0; /* we only support prime256v1 for 11 */
keydata->ecparam_len =0;
break;
case 0x14: keydata->key_bits = 0;
keydata->ecparam = 0; /* we only support secp384r1 */
keydata->ecparam_len = 0;
break;
default: default:
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS);
} }
@ -634,12 +647,19 @@ static int piv_generate_key(sc_card_t *card,
keydata->pubkey_len = taglen; keydata->pubkey_len = taglen;
memcpy (keydata->pubkey, tag, taglen); memcpy (keydata->pubkey, tag, taglen);
} }
} else { } else { /* must be EC */
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Requires OpenSSL"); tag = sc_asn1_find_tag(card->ctx, cp, in_len, 0x86, &taglen);
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED); if (tag != NULL && taglen > 0) {
keydata->ecpoint = malloc(taglen);
if (keydata->ecpoint == NULL)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
keydata->ecpoint_len = taglen;
memcpy (keydata->ecpoint, tag, taglen);
}
} }
/* TODO could add key to cache so could use engine to generate key, and */ /* TODO: -DEE Could add key to cache so could use engine to generate key,
* and sign req in single operation */
r = 0; r = 0;
} }
@ -867,186 +887,46 @@ static int piv_get_data(sc_card_t * card, int enumtag,
memcpy(p, piv_objects[enumtag].tag_value, tag_len); memcpy(p, piv_objects[enumtag].tag_value, tag_len);
p += tag_len; p += tag_len;
if (*buf_len == 1 && *buf == NULL) { /* we need to get the length */
u8 rbufinitbuf[8]; /* tag of 53 with 82 xx xx will fit in 4 */
u8 *rbuf;
size_t rbuflen;
size_t bodylen;
unsigned int cla_out, tag_out;
const u8 *body;
/* sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"get len of #%d", enumtag);
* the PIV card will only recover the public key during a generate rbuf = rbufinitbuf;
* key operation. If the piv-tool was used it would save this rbuflen = sizeof(rbufinitbuf);
* as an OpenSSL EVP_KEY PEM using the -o parameter r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf,
* we will look to see if there is a file then load it &rbuf, &rbuflen);
* this is ugly, and maybe the pkcs15 cache would work if (r > 0) {
* but we only need it to get the OpenSSL req with engine to work. body = rbuf;
* Each of the 4 keys with certs has its own file. if (sc_asn1_read_tag(&body, 0xffff, &cla_out, &tag_out, &bodylen) != SC_SUCCESS) {
* Any other request for a pub key will return not found. sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "***** received buffer tag MISSING ");
*/
switch (piv_objects[enumtag].enumtag) {
#ifdef PIV_TEST_WITH_OLD_CARDS
/*
* For testing 800-73-3 History and/or Discovery objects
* we can simulate reading them from a file and
* test with an older card. Since the older card
* does not have the keys, we can only do partial testing.
*/
/* read them from a file */
case PIV_OBJ_DISCOVERY:
dataenvname = "PIV_TEST_OBJ_DISCOVERY";
break;
case PIV_OBJ_HISTORY:
dataenvname = "PIV_TEST_OBJ_HISTORY";
break;
#endif
/*
* If we used the piv-tool to generate a key,
* we would have saved the public key as a file.
* This code is only used while signing a request
* After the certificate is loaded on the card,
* the public key is extracted from the certificate.
*/
case PIV_OBJ_9A06:
keyenvname = "PIV_9A06_KEY";
break;
case PIV_OBJ_9C06:
keyenvname = "PIV_9C06_KEY";
break;
case PIV_OBJ_9D06:
keyenvname = "PIV_9D06_KEY";
break;
case PIV_OBJ_9E06:
keyenvname = "PIV_9E06_KEY";
break;
default:
if (piv_objects[enumtag].flags & PIV_OBJECT_TYPE_PUBKEY) {
r = SC_ERROR_FILE_NOT_FOUND; r = SC_ERROR_FILE_NOT_FOUND;
goto err; goto err;
} }
} *buf_len = r;
} else if ( r == 0) {
if (dataenvname) {
filename = (char *)getenv(dataenvname);
if (filename) {
r = piv_read_obj_from_file(card, filename, buf, buf_len);
if (r == SC_ERROR_FILE_NOT_FOUND) /* ignore if not found */
r = 0;
goto err; /* return error, or length */
}
}
if (keyenvname) {
/* This code is only used for card administration */
#ifdef ENABLE_OPENSSL
BIO * bp = NULL;
RSA * rsa = NULL;
u8 *q;
size_t derlen;
size_t taglen;
char * keyfilename = NULL;
keyfilename = getenv(keyenvname);
if (keyfilename == NULL) {
r = SC_ERROR_FILE_NOT_FOUND; r = SC_ERROR_FILE_NOT_FOUND;
goto err; goto err;
} } else {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "USING PUB KEY FROM FILE %s",keyfilename);
bp = BIO_new(BIO_s_file());
if (bp == NULL) {
r = SC_ERROR_INTERNAL;
goto err; goto err;
} }
if (BIO_read_filename(bp, keyfilename) <= 0) { }
BIO_free(bp); sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"get buffer for #%d len %d", enumtag, *buf_len);
r = SC_ERROR_FILE_NOT_FOUND; if (*buf == NULL && *buf_len > 0) {
goto err;
}
rsa = PEM_read_bio_RSAPublicKey(bp, &rsa, NULL, NULL);
BIO_free(bp);
if (!rsa) {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Unable to load the public key");
r = SC_ERROR_DATA_OBJECT_NOT_FOUND;
goto err;
}
derlen = i2d_RSAPublicKey(rsa, NULL);
if (derlen <= 0) {
r = SC_ERROR_DATA_OBJECT_NOT_FOUND;
goto err;
}
taglen = put_tag_and_len(0x99, derlen, NULL);
*buf_len = put_tag_and_len(0x53, taglen, NULL);
*buf = malloc(*buf_len); *buf = malloc(*buf_len);
if (*buf == NULL) { if (*buf == NULL ) {
r = SC_ERROR_OUT_OF_MEMORY; r = SC_ERROR_OUT_OF_MEMORY;
goto err; goto err;
} }
q = *buf;
put_tag_and_len(0x53, taglen, &q);
put_tag_and_len(0x99, derlen, &q);
i2d_RSAPublicKey(rsa, &q);
RSA_free(rsa);
r = *buf_len;
/* end of read pub key from file */
#else
if (getenv(keyenvname))
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Requires OpenSSL");
r = SC_ERROR_FILE_NOT_FOUND;
goto err;
#endif /* ENABLE_OPENSSL */
} else {
if (*buf_len == 1 && *buf == NULL) { /* we need to get the length */
u8 rbufinitbuf[8]; /* tag of 53 with 82 xx xx will fit in 4 */
u8 *rbuf;
size_t rbuflen;
size_t bodylen;
unsigned int cla_out, tag_out;
const u8 *body;
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"get len of #%d", enumtag);
rbuf = rbufinitbuf;
rbuflen = sizeof(rbufinitbuf);
r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf,
&rbuf, &rbuflen);
if (r > 0) {
body = rbuf;
if (sc_asn1_read_tag(&body, 0xffff, &cla_out, &tag_out, &bodylen) != SC_SUCCESS) {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "***** received buffer tag MISSING ");
r = SC_ERROR_FILE_NOT_FOUND;
goto err;
}
*buf_len = r;
} else if ( r == 0) {
r = SC_ERROR_FILE_NOT_FOUND;
goto err;
} else {
goto err;
}
}
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"get buffer for #%d len %d", enumtag, *buf_len);
if (*buf == NULL && *buf_len > 0) {
*buf = malloc(*buf_len);
if (*buf == NULL ) {
r = SC_ERROR_OUT_OF_MEMORY;
goto err;
}
}
r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf,
buf, buf_len);
} }
r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf,
buf, buf_len);
err: err:
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
@ -1195,6 +1075,7 @@ static int piv_cache_internal_data(sc_card_t *card, int enumtag)
} }
/* convert pub key to internal */ /* convert pub key to internal */
/* TODO: -DEE need to fix ... would only be used if we cache the pub key, but we don't today */
} else if (piv_objects[enumtag].flags & PIV_OBJECT_TYPE_PUBKEY) { } else if (piv_objects[enumtag].flags & PIV_OBJECT_TYPE_PUBKEY) {
tag = sc_asn1_find_tag(card->ctx, body, bodylen, *body, &taglen); tag = sc_asn1_find_tag(card->ctx, body, bodylen, *body, &taglen);
@ -1250,7 +1131,7 @@ static int piv_read_binary(sc_card_t *card, unsigned int idx,
r = piv_get_cached_data(card, enumtag, &rbuf, &rbuflen); r = piv_get_cached_data(card, enumtag, &rbuf, &rbuflen);
if (r >=0) { if (r >=0) {
/* an object wih no data will be considered not found */ /* an object with no data will be considered not found */
/* Discovery tag = 0x73, all others are 0x53 */ /* Discovery tag = 0x73, all others are 0x53 */
if (!rbuf || rbuf[0] == 0x00 || ((rbuf[0]&0xDF) == 0x53 && rbuf[1] == 0x00)) { if (!rbuf || rbuf[0] == 0x00 || ((rbuf[0]&0xDF) == 0x53 && rbuf[1] == 0x00)) {
r = SC_ERROR_FILE_NOT_FOUND; r = SC_ERROR_FILE_NOT_FOUND;
@ -1271,7 +1152,7 @@ static int piv_read_binary(sc_card_t *card, unsigned int idx,
r = SC_ERROR_INVALID_DATA; r = SC_ERROR_INVALID_DATA;
goto err; goto err;
} }
/* if chached obj has internal interesting data (cert or pub key) */ /* if cached obj has internal interesting data (cert or pub key) */
if (priv->return_only_cert || piv_objects[enumtag].flags & PIV_OBJECT_TYPE_PUBKEY) { if (priv->return_only_cert || piv_objects[enumtag].flags & PIV_OBJECT_TYPE_PUBKEY) {
r = piv_cache_internal_data(card, enumtag); r = piv_cache_internal_data(card, enumtag);
if (r < 0) if (r < 0)
@ -1337,7 +1218,6 @@ static int piv_put_data(sc_card_t *card, int tag,
r = piv_general_io(card, 0xDB, 0x3F, 0xFF, r = piv_general_io(card, 0xDB, 0x3F, 0xFF,
sbuf, p - sbuf, NULL, NULL); sbuf, p - sbuf, NULL, NULL);
/* TODO add to cache */
if (sbuf) if (sbuf)
free(sbuf); free(sbuf);
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
@ -1389,10 +1269,16 @@ static int piv_write_certificate(sc_card_t *card,
* For certs we need to add the 0x53 tag and other specific tags, * For certs we need to add the 0x53 tag and other specific tags,
* and call the piv_put_data * and call the piv_put_data
* Note: the select file will have saved the object type for us * Note: the select file will have saved the object type for us
* Write is only used by piv-tool, so we will use flags: * Write is used by piv-tool, so we will use flags:
* length << 8 | compress < 1 | cert * length << 8 | 8bits:
* to indicate we are writing a cert and if is compressed. * object xxxx0000
* if its not a cert its an object. * uncompresed cert xxx00001
* compressed cert xxx10001
* pubkey xxxx0010
*
* to indicate we are writing a cert and if is compressed
* or if we are writing a pubkey in to the cache.
* if its not a cert or pubkey its an object.
* *
* Therefore when idx=0, we will get the length of the object * Therefore when idx=0, we will get the length of the object
* and allocate a buffer, so we can support partial writes. * and allocate a buffer, so we can support partial writes.
@ -1459,11 +1345,18 @@ static int piv_write_binary(sc_card_t *card, unsigned int idx,
priv-> rwb_state = 1; /* at end of object */ priv-> rwb_state = 1; /* at end of object */
if ( flags & 1) { switch (flags & 0x0f) {
case 1:
r = piv_write_certificate(card, priv->w_buf, priv->w_buf_len, r = piv_write_certificate(card, priv->w_buf, priv->w_buf_len,
flags & 0x02); flags & 0x10);
} else { break;
r = piv_put_data(card, enumtag, priv->w_buf, priv->w_buf_len); case 2: /* pubkey to be added to cache, it should have 0x53 and 0x99 tags. */
/* TODO: -DEE this is not fully implemented and not used */
r = priv->w_buf_len;
break;
default:
r = piv_put_data(card, enumtag, priv->w_buf, priv->w_buf_len);
break;
} }
/* if it worked, will cache it */ /* if it worked, will cache it */
if (r >= 0 && priv->w_buf) { if (r >= 0 && priv->w_buf) {
@ -1963,7 +1856,8 @@ static int piv_get_challenge(sc_card_t *card, u8 *rnd, size_t len)
while (len > 0) { while (len > 0) {
size_t n = len > 8 ? 8 : len; size_t n = len > 8 ? 8 : len;
r = piv_general_io(card, 0x87, 0x00, 0x00, sbuf, p - sbuf, /* NIST 800-73-3 says use 9B, previous verisons used 00 */
r = piv_general_io(card, 0x87, 0x00, 0x9B, sbuf, p - sbuf,
&rbuf, &rbuflen); &rbuf, &rbuflen);
if (r < 0) { if (r < 0) {
sc_unlock(card); sc_unlock(card);
@ -1996,6 +1890,7 @@ static int piv_set_security_env(sc_card_t *card,
int se_num) int se_num)
{ {
piv_private_data_t * priv = PIV_DATA(card); piv_private_data_t * priv = PIV_DATA(card);
int r = 0;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
@ -2003,13 +1898,29 @@ static int piv_set_security_env(sc_card_t *card,
env->flags, env->operation, env->algorithm, env->algorithm_flags, env->flags, env->operation, env->algorithm, env->algorithm_flags,
env->algorithm_ref, env->key_ref[0], env->key_ref_len); env->algorithm_ref, env->key_ref[0], env->key_ref_len);
if (env->algorithm == SC_ALGORITHM_RSA) if (env->algorithm == SC_ALGORITHM_RSA) {
priv->alg_id = 0x06; /* Say it is RSA, set 5, 6, 7 later */ priv->alg_id = 0x06; /* Say it is RSA, set 5, 6, 7 later */
else } else if (env->algorithm == SC_ALGORITHM_EC) {
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NO_CARD_SUPPORT); if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT) {
switch (env->algorithm_ref) {
case 256:
priv->alg_id = 0x11; /* Say it is EC 256 */
priv->key_size = 256;
break;
case 384:
priv->alg_id = 0x14;
priv->key_size = 384;
break;
default:
r = SC_ERROR_NO_CARD_SUPPORT;
}
} else
r = SC_ERROR_NO_CARD_SUPPORT;
} else
r = SC_ERROR_NO_CARD_SUPPORT;
priv->key_ref = env->key_ref[0]; priv->key_ref = env->key_ref[0];
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
} }
@ -2066,6 +1977,7 @@ static int piv_validate_general_authentication(sc_card_t *card,
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NO_CARD_SUPPORT); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NO_CARD_SUPPORT);
} }
} }
/* EC alg_id was already set */
r = piv_general_io(card, 0x87, real_alg_id, priv->key_ref, r = piv_general_io(card, 0x87, real_alg_id, priv->key_ref,
sbuf, p - sbuf, &rbuf, &rbuflen); sbuf, p - sbuf, &rbuf, &rbuflen);
@ -2093,8 +2005,77 @@ static int piv_compute_signature(sc_card_t *card,
const u8 * data, size_t datalen, const u8 * data, size_t datalen,
u8 * out, size_t outlen) u8 * out, size_t outlen)
{ {
piv_private_data_t * priv = PIV_DATA(card);
int r;
int i;
int nLen;
u8 * outp = out;
u8 rbuf[128]; /* For EC conversions 384 will fit */
size_t rbuflen = sizeof(rbuf);
const u8 * body;
size_t bodylen;
const u8 * tag;
size_t taglen;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, piv_validate_general_authentication(card, data, datalen, out, outlen));
/* The PIV returns a DER SEQUENCE{INTEGER, INTEGER}
* Which may have leading 00 to force positive
* TODO: -DEE should check if PKCS15 want the same
* But PKCS11 just wants 2* filed_length in bytes
* So we have to strip out the integers
* if present and pad on left if too short.
*/
if (priv->alg_id == 0x11 || priv->alg_id == 0x14 ) {
nLen = (priv->key_size + 7) / 8;
if (outlen < 2*nLen) {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL," output too small for EC signature %d < %d", outlen, 2*nLen);
r = SC_ERROR_INVALID_DATA;
goto err;
}
memset(out, 0, outlen);
r = piv_validate_general_authentication(card, data, datalen, rbuf, rbuflen);
if (r < 0)
goto err;
if ( r >= 0) {
body = sc_asn1_find_tag(card->ctx, rbuf, rbuflen, 0x30, &bodylen);
for (i = 0; i<2; i++) {
if (body) {
tag = sc_asn1_find_tag(card->ctx, body, bodylen, 0x02, &taglen);
if (tag) {
bodylen -= taglen - (tag - body);
body = tag + taglen;
if (taglen > nLen) { /* drop leading 00 if present */
if (*tag != 0x00) {
r = SC_ERROR_INVALID_DATA;
goto err;
}
tag++;
taglen--;
}
memcpy(out + nLen*i + nLen - taglen , tag, taglen);
} else {
r = SC_ERROR_INVALID_DATA;
goto err;
}
} else {
r = SC_ERROR_INVALID_DATA;
goto err;
}
}
r = 2 * nLen;
}
} else { /* RSA is all set */
r = piv_validate_general_authentication(card, data, datalen, out, outlen);
}
err:
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
} }
static int piv_decipher(sc_card_t *card, static int piv_decipher(sc_card_t *card,
@ -2263,7 +2244,7 @@ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Discovery pinp flags=0x%2.2x 0x%2.2x",*
* The history object lists what retired keys and certs are on the card * The history object lists what retired keys and certs are on the card
* or listed in the offCardCertURL. The user may have read the offCardURL file, * or listed in the offCardCertURL. The user may have read the offCardURL file,
* ahead of time, and if so will use it for the certs listed. * ahead of time, and if so will use it for the certs listed.
* TODO: * TODO: -DEE
* If the offCardCertURL is not cached by the user, should we wget it here? * If the offCardCertURL is not cached by the user, should we wget it here?
* Its may be out of scope to have OpenSC read the URL. * Its may be out of scope to have OpenSC read the URL.
*/ */
@ -2515,7 +2496,6 @@ static int piv_finish(sc_card_t *card)
} }
free(priv); free(priv);
} }
/* TODO temp see piv_init */
return 0; return 0;
} }
@ -2539,6 +2519,7 @@ static int piv_init(sc_card_t *card)
{ {
int r, i; int r, i;
unsigned long flags; unsigned long flags;
unsigned long ext_flags;
piv_private_data_t *priv; piv_private_data_t *priv;
SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
@ -2576,6 +2557,12 @@ static int piv_init(sc_card_t *card)
_sc_card_add_rsa_alg(card, 2048, flags, 0); /* optional */ _sc_card_add_rsa_alg(card, 2048, flags, 0); /* optional */
_sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */ _sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */
flags = SC_ALGORITHM_ECDSA_RAW | SC_ALGORITHM_ONBOARD_KEY_GEN;
ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES;
_sc_card_add_ec_alg(card, 256, flags, ext_flags);
_sc_card_add_ec_alg(card, 384, flags, ext_flags);
card->caps |= SC_CARD_CAP_RNG; card->caps |= SC_CARD_CAP_RNG;
/* /*

View File

@ -755,6 +755,11 @@ typedef struct sc_cardctl_piv_genkey_info_st {
unsigned long exponent; /* RSA */ unsigned long exponent; /* RSA */
unsigned char * pubkey; /* RSA */ unsigned char * pubkey; /* RSA */
unsigned int pubkey_len; /* RSA */ unsigned int pubkey_len; /* RSA */
unsigned char * ecparam; /* EC */
unsigned int ecparam_len; /* EC */
unsigned char * ecpoint; /* EC */
unsigned int ecpoint_len; /* EC */
} sc_cardctl_piv_genkey_info_t; } sc_cardctl_piv_genkey_info_t;
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -137,6 +137,7 @@ sc_pkcs15_decode_prkey
sc_pkcs15_decode_pubkey sc_pkcs15_decode_pubkey
sc_pkcs15_decode_pubkey_dsa sc_pkcs15_decode_pubkey_dsa
sc_pkcs15_decode_pubkey_rsa sc_pkcs15_decode_pubkey_rsa
sc_pkcs15_decode_pubkey_ec
sc_pkcs15_decode_pubkey_gostr3410 sc_pkcs15_decode_pubkey_gostr3410
sc_pkcs15_decode_pukdf_entry sc_pkcs15_decode_pukdf_entry
sc_pkcs15_encode_aodf_entry sc_pkcs15_encode_aodf_entry
@ -150,6 +151,7 @@ sc_pkcs15_encode_prkey
sc_pkcs15_encode_pubkey sc_pkcs15_encode_pubkey
sc_pkcs15_encode_pubkey_dsa sc_pkcs15_encode_pubkey_dsa
sc_pkcs15_encode_pubkey_rsa sc_pkcs15_encode_pubkey_rsa
sc_pkcs15_encode_pubkey_ec
sc_pkcs15_encode_pubkey_gostr3410 sc_pkcs15_encode_pubkey_gostr3410
sc_pkcs15_encode_pukdf_entry sc_pkcs15_encode_pukdf_entry
sc_pkcs15_encode_tokeninfo sc_pkcs15_encode_tokeninfo
@ -210,6 +212,8 @@ sc_pkcs15emu_add_data_object
sc_pkcs15emu_add_pin_obj sc_pkcs15emu_add_pin_obj
sc_pkcs15emu_add_rsa_prkey sc_pkcs15emu_add_rsa_prkey
sc_pkcs15emu_add_rsa_pubkey sc_pkcs15emu_add_rsa_pubkey
sc_pkcs15emu_add_ec_prkey
sc_pkcs15emu_add_ec_pubkey
sc_pkcs15emu_add_x509_cert sc_pkcs15emu_add_x509_cert
sc_pkcs15emu_object_add sc_pkcs15emu_object_add
sc_print_path sc_print_path

View File

@ -286,12 +286,13 @@ int sc_get_encoding_flags(sc_context_t *ctx,
else else
*pflags |= SC_ALGORITHM_RSA_PAD_PKCS1; *pflags |= SC_ALGORITHM_RSA_PAD_PKCS1;
} else if ((iflags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) { } else if ((iflags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) {
if (!(caps & SC_ALGORITHM_RSA_RAW)) {
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "raw RSA is not supported"); /* Work with RSA, EC and maybe GOSTR? */
if (!(caps & SC_ALGORITHM_RAW_MASK)) {
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "raw encryption is not supported");
return SC_ERROR_NOT_SUPPORTED; return SC_ERROR_NOT_SUPPORTED;
} }
*sflags |= SC_ALGORITHM_RSA_RAW; *sflags |= (caps & SC_ALGORITHM_RAW_MASK); /* adds in the one raw type */
/* in case of raw RSA there is nothing to pad */
*pflags = 0; *pflags = 0;
} else { } else {
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "unsupported algorithm"); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "unsupported algorithm");

View File

@ -235,6 +235,89 @@ asn1_free_pbes2_params(void *ptr)
free(params); free(params);
} }
static const struct sc_asn1_entry c_asn1_ec_params[] = {
{ "ecParameters", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
{ "namedCurve", SC_ASN1_OBJECT, SC_ASN1_TAG_OBJECT, 0, NULL, NULL},
{ "implicityCA", SC_ASN1_NULL, SC_ASN1_TAG_NULL, 0, NULL, NULL },
{ NULL, 0, 0, 0, NULL, NULL }
};
static int
asn1_decode_ec_params(sc_context_t *ctx, void **paramp,
const u8 *buf, size_t buflen, int depth)
{
int r;
struct sc_object_id curve;
struct sc_asn1_entry asn1_ec_params[4];
struct sc_ec_params * ecp;
sc_debug(ctx, SC_LOG_DEBUG_ASN1, "DEE - asn1_decode_ec_params %p:%d %d", buf, buflen, depth);
memset(&curve, 0, sizeof(curve));
ecp = malloc(sizeof(struct sc_ec_params));
if (ecp == NULL)
return SC_ERROR_OUT_OF_MEMORY;
memset(ecp,9,sizeof(struct sc_ec_params));
/* We only want to copy the parms if they are a namedCurve
* or ecParameters nullParam aka implicityCA is not to be
* used with PKCS#11 2.20 */
sc_copy_asn1_entry(c_asn1_ec_params, asn1_ec_params);
sc_format_asn1_entry(asn1_ec_params + 1, &curve, 0, 0);
/* Some signature algorithms will not have any data */
if (buflen == 0 | buf == NULL )
return 0;
r = sc_asn1_decode_choice(ctx, asn1_ec_params, buf, buflen, NULL, NULL);
/* r = index into asn1_ec_params */
sc_debug(ctx, SC_LOG_DEBUG_ASN1, "DEE - asn1_decode_ec_params r=%d", r);
if (r < 0)
return r;
if (r <= 1) {
ecp->der = malloc(buflen);
if (ecp->der == NULL)
return SC_ERROR_OUT_OF_MEMORY;
ecp->der_len = buflen;
sc_debug(ctx, SC_LOG_DEBUG_ASN1, "DEE - asn1_decode_ec_params paramp=%p %p:%d %d",
ecp, ecp->der, ecp->der_len, ecp->type);
memcpy(ecp->der, buf, buflen); /* copy der parameters */
} else
r = 0;
ecp->type = r; /* but 0 = ecparams if any, 1=named curve */
*paramp = ecp;
return 0;
};
static int
asn1_encode_ec_params(sc_context_t *ctx, void *params,
u8 **buf, size_t *buflen, int depth)
{
int r;
/* TODO: -DEE EC paramameters are DER so is there anything to do? */
/* I have not needed this yet */
sc_debug(ctx, SC_LOG_DEBUG_ASN1, "DEE - asn1_encode_ec_params");
r = SC_ERROR_NOT_IMPLEMENTED;
return r;
}
static void
asn1_free_ec_params(void *params)
{
struct sc_ec_params * ecp = (struct sc_ec_params *) params;
if (ecp) {
if (ecp->der)
free(ecp->der);
free(ecp);
}
}
static struct sc_asn1_pkcs15_algorithm_info algorithm_table[] = { static struct sc_asn1_pkcs15_algorithm_info algorithm_table[] = {
#ifdef SC_ALGORITHM_SHA1 #ifdef SC_ALGORITHM_SHA1
/* hmacWithSHA1 */ /* hmacWithSHA1 */
@ -303,6 +386,33 @@ static struct sc_asn1_pkcs15_algorithm_info algorithm_table[] = {
asn1_encode_pbes2_params, asn1_encode_pbes2_params,
asn1_free_pbes2_params }, asn1_free_pbes2_params },
#endif #endif
#ifdef SC_ALGORITHM_EC
{ SC_ALGORITHM_EC, {{ 1, 2, 840, 10045, 2, 1 }},
asn1_decode_ec_params, asn1_encode_ec_params, asn1_free_ec_params },
#endif
/* TODO: -DEE Not clear of we need the next five or not */
#ifdef SC_ALGORITHM_ECDSA_SHA1
/* Note RFC 3279 says no ecParameters */
{ SC_ALGORITHM_ECDSA_SHA1, {{ 1, 2, 840, 10045, 4, 1 }}, NULL, NULL, NULL},
#endif
#ifdef SC_ALGORITHM_ECDSA_SHA224
/* These next 4 are defined in RFC 5758 */
{ SC_ALGORITHM_ECDSA_SHA224, {{ 1, 2, 840, 10045, 4, 3, 1 }},
asn1_decode_ec_params, asn1_encode_ec_params, asn1_free_ec_params },
#endif
#ifdef SC_ALGORITHM_ECDSA_SHA256
{ SC_ALGORITHM_ECDSA_SHA256, {{ 1, 2, 840, 10045, 4, 3, 2 }},
asn1_decode_ec_params, asn1_encode_ec_params, asn1_free_ec_params },
#endif
#ifdef SC_ALGORITHM_ECDSA_SHA384
{ SC_ALGORITHM_ECDSA_SHA384, {{ 1, 2, 840, 10045, 4, 3, 3 }},
asn1_decode_ec_params, asn1_encode_ec_params, asn1_free_ec_params },
#endif
#ifdef SC_ALGORITHM_ECDSA_SHA512
{ SC_ALGORITHM_ECDSA_SHA512, {{ 1, 2, 840, 10045, 4, 3, 4 }},
asn1_decode_ec_params, asn1_encode_ec_params, asn1_free_ec_params },
#endif
{ -1, {{ -1 }}, NULL, NULL, NULL } { -1, {{ -1 }}, NULL, NULL, NULL }
}; };
@ -368,8 +478,13 @@ sc_asn1_decode_algorithm_id(sc_context_t *ctx, const u8 *in,
if ((alg_info = sc_asn1_get_algorithm_info(id)) != NULL) { if ((alg_info = sc_asn1_get_algorithm_info(id)) != NULL) {
id->algorithm = alg_info->id; id->algorithm = alg_info->id;
if (alg_info->decode) { if (alg_info->decode) {
if (asn1_alg_id[1].flags & SC_ASN1_PRESENT) /* TODO: -DEE why the test for SC_ASN1_PRESENT?
* If it looking for SC_ASN1_NULL, thats valid for EC, in some cases
*/
if (asn1_alg_id[1].flags & SC_ASN1_PRESENT) {
sc_debug( ctx,SC_LOG_DEBUG_NORMAL,"SC_ASN1_PRESENT was set, so invalid");
return SC_ERROR_INVALID_ASN1_OBJECT; return SC_ERROR_INVALID_ASN1_OBJECT;
}
r = alg_info->decode(ctx, &id->params, in, len, depth); r = alg_info->decode(ctx, &id->params, in, len, depth);
} }
} }

View File

@ -33,13 +33,13 @@
#include "internal.h" #include "internal.h"
#include "cardctl.h" #include "cardctl.h"
#include "asn1.h"
#include "pkcs15.h" #include "pkcs15.h"
#define MANU_ID "piv_II " #define MANU_ID "piv_II "
int sc_pkcs15emu_piv_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *); int sc_pkcs15emu_piv_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
typedef struct objdata_st { typedef struct objdata_st {
const char *id; const char *id;
const char *label; const char *label;
@ -75,28 +75,32 @@ typedef struct pdata_st {
typedef struct pubdata_st { typedef struct pubdata_st {
const char *id; const char *id;
const char *label; const char *label;
int usage; int usage_rsa;
int usage_ec;
const char *path; const char *path;
int ref; int ref;
const char *auth_id; const char *auth_id;
int obj_flags; int obj_flags;
const char *getenvname;
} pubdata; } pubdata;
typedef struct prdata_st { typedef struct prdata_st {
const char *id; const char *id;
const char *label; const char *label;
int usage; int usage_rsa;
int usage_ec;
const char *path; const char *path;
int ref; int ref;
const char *auth_id; const char *auth_id;
int obj_flags; int obj_flags;
int user_consent;
} prdata; } prdata;
typedef struct common_key_info_st { typedef struct common_key_info_st {
int cert_found; int cert_found;
int pubkey_found; int pubkey_found;
int key_alg; int key_alg;
unsigned int modulus_len; unsigned int pubkey_len;
int not_present; int not_present;
} common_key_info; } common_key_info;
@ -111,6 +115,7 @@ static int piv_detect_card(sc_pkcs15_card_t *p15card)
return SC_SUCCESS; return SC_SUCCESS;
} }
static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card) static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
{ {
@ -252,171 +257,225 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
* but can be derived from the certificates. * but can be derived from the certificates.
* the cert, pubkey and privkey are a set. * the cert, pubkey and privkey are a set.
* Key usages bits taken from pkcs15v1_1 Table 2 * Key usages bits taken from pkcs15v1_1 Table 2
* RSA and EC hav differents set of usage
*/ */
static const pubdata pubkeys[PIV_NUM_CERTS_AND_KEYS] = { static const pubdata pubkeys[PIV_NUM_CERTS_AND_KEYS] = {
{ "1", "PIV AUTH pubkey", { "1", "PIV AUTH pubkey",
SC_PKCS15_PRKEY_USAGE_ENCRYPT | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT |
SC_PKCS15_PRKEY_USAGE_WRAP | SC_PKCS15_PRKEY_USAGE_WRAP |
SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFY |
SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER, SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER,
"9A06", 0x9A, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY,
"9A06", 0x9A, "1", 0, "PIV_9A_KEY"},
{ "2", "SIGN pubkey", { "2", "SIGN pubkey",
SC_PKCS15_PRKEY_USAGE_ENCRYPT | /*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT |
SC_PKCS15_PRKEY_USAGE_VERIFY | SC_PKCS15_PRKEY_USAGE_VERIFY |
SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER | SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION, SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
"9C06", 0x9C, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
"9C06", 0x9C, "1", 0, "PIV_9C_KEY"},
{ "3", "KEY MAN pubkey", { "3", "KEY MAN pubkey",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"9D06", 0x9D, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"9D06", 0x9D, "1", 0, "PIV_9D_KEY"},
{ "4", "CARD AUTH pubkey", { "4", "CARD AUTH pubkey",
SC_PKCS15_PRKEY_USAGE_VERIFY | /*RSA*/SC_PKCS15_PRKEY_USAGE_VERIFY |
SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER, SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER,
"9E06", 0x9E, "0", 0}, /* no pin, and avail in contactless */ /*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY,
"9E06", 0x9E, "0", 0, "PIV_9E_KEY"}, /* no pin, and avail in contactless */
{ "5", "Retired KEY MAN 1", { "5", "Retired KEY MAN 1",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8206", 0x82, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8206", 0x82, "1", 0, NULL},
{ "6", "Retired KEY MAN 2", { "6", "Retired KEY MAN 2",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8306", 0x83, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8306", 0x83, "1", 0, NULL},
{ "7", "Retired KEY MAN 3", { "7", "Retired KEY MAN 3",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8406", 0x84, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8406", 0x84, "1", 0, NULL},
{ "8", "Retired KEY MAN 4", { "8", "Retired KEY MAN 4",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8506", 0x85, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8506", 0x85, "1", 0, NULL},
{ "9", "Retired KEY MAN 5", { "9", "Retired KEY MAN 5",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8606", 0x86, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8606", 0x86, "1", 0, NULL},
{ "10", "Retired KEY MAN 6", { "10", "Retired KEY MAN 6",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8706", 0x87, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8706", 0x87, "1", 0, NULL},
{ "11", "Retired KEY MAN 7", { "11", "Retired KEY MAN 7",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8806", 0x88, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8806", 0x88, "1", 0, NULL},
{ "12", "Retired KEY MAN 8", { "12", "Retired KEY MAN 8",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8906", 0x89, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8906", 0x89, "1", 0, NULL},
{ "13", "Retired KEY MAN 9", { "13", "Retired KEY MAN 9",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8A06", 0x8A, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8A06", 0x8A, "1", 0, NULL},
{ "14", "Retired KEY MAN 10", { "14", "Retired KEY MAN 10",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8B06", 0x8B, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8B06", 0x8B, "1", 0, NULL},
{ "15", "Retired KEY MAN 11", { "15", "Retired KEY MAN 11",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8C06", 0x8C, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8C06", 0x8C, "1", 0, NULL},
{ "16", "Retired KEY MAN 12", { "16", "Retired KEY MAN 12",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8D06", 0x8D, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8D06", 0x8D, "1", 0, NULL},
{ "17", "Retired KEY MAN 13", { "17", "Retired KEY MAN 13",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8E06", 0x8E, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8E06", 0x8E, "1", 0, NULL},
{ "18", "Retired KEY MAN 14", { "18", "Retired KEY MAN 14",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"8F06", 0x8F, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8F06", 0x8F, "1", 0, NULL},
{ "19", "Retired KEY MAN 15", { "19", "Retired KEY MAN 15",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"9006", 0x90, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"9006", 0x90, "1", 0, NULL},
{ "20", "Retired KEY MAN 16", { "20", "Retired KEY MAN 16",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"9106", 0x91, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"9106", 0x91, "1", 0, NULL},
{ "21", "Retired KEY MAN 17", { "21", "Retired KEY MAN 17",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"9206", 0x92, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"9206", 0x92, "1", 0, NULL},
{ "22", "Retired KEY MAN 18", { "22", "Retired KEY MAN 18",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"9306", 0x93, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"9306", 0x93, "1", 0, NULL},
{ "23", "Retired KEY MAN 19", { "23", "Retired KEY MAN 19",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"9406", 0x94, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"9406", 0x94, "1", 0, NULL},
{ "24", "Retired KEY MAN 20", { "24", "Retired KEY MAN 20",
SC_PKCS15_PRKEY_USAGE_WRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
"9506", 0x95, "1", 0} /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
}; "9506", 0x95, "1", 0, NULL} };
/*
* note some of the SC_PKCS15_PRKEY values are dependent
* on the key algorithm, and will be reset.
*/
static const prdata prkeys[PIV_NUM_CERTS_AND_KEYS] = { static const prdata prkeys[PIV_NUM_CERTS_AND_KEYS] = {
{ "1", "PIV AUTH key", { "1", "PIV AUTH key",
SC_PKCS15_PRKEY_USAGE_DECRYPT | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT |
SC_PKCS15_PRKEY_USAGE_UNWRAP | SC_PKCS15_PRKEY_USAGE_UNWRAP |
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGN |
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER, SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
"", 0x9A, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_SIGN,
"", 0x9A, "1", SC_PKCS15_CO_FLAG_PRIVATE, 0},
{ "2", "SIGN key", { "2", "SIGN key",
SC_PKCS15_PRKEY_USAGE_DECRYPT | /*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT |
SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGN |
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION, SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
"", 0x9C, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_SIGN |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
"", 0x9C, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "3", "KEY MAN key", { "3", "KEY MAN key",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x9D, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x9D, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "4", "CARD AUTH key", { "4", "CARD AUTH key",
SC_PKCS15_PRKEY_USAGE_SIGN | /*RSA*/SC_PKCS15_PRKEY_USAGE_SIGN |
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER, SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
"", 0x9E, NULL, 0}, /* no PIN needed, works with wireless */ /*EC*/SC_PKCS15_PRKEY_USAGE_SIGN,
"", 0x9E, NULL, 0, 0}, /* no PIN needed, works with wireless */
{ "5", "Retired KEY MAN 1", { "5", "Retired KEY MAN 1",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x82, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x82, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "6", "Retired KEY MAN 2", { "6", "Retired KEY MAN 2",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x83, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x83, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "7", "Retired KEY MAN 3", { "7", "Retired KEY MAN 3",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x84, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x84, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "8", "Retired KEY MAN 4", { "8", "Retired KEY MAN 4",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x85, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x85, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "9", "Retired KEY MAN 5", { "9", "Retired KEY MAN 5",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x86, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x86, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "10", "Retired KEY MAN 6", { "10", "Retired KEY MAN 6",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x87, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x87, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "11", "Retired KEY MAN 7", { "11", "Retired KEY MAN 7",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x88, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x88, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "12", "Retired KEY MAN 8", { "12", "Retired KEY MAN 8",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x89, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x89, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "13", "Retired KEY MAN 9", { "13", "Retired KEY MAN 9",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x8A, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x8A, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "14", "Retired KEY MAN 10", { "14", "Retired KEY MAN 10",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x8B, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x8B, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "15", "Retired KEY MAN 11", { "15", "Retired KEY MAN 11",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x8C, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x8C, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "16", "Retired KEY MAN 12", { "16", "Retired KEY MAN 12",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x8D, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x8D, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "17", "Retired KEY MAN 13", { "17", "Retired KEY MAN 13",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x8E, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x8E, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "18", "Retired KEY MAN 14", { "18", "Retired KEY MAN 14",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x8F, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x8F, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "19", "Retired KEY MAN 15", { "19", "Retired KEY MAN 15",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x90, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x90, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "20", "Retired KEY MAN 16", { "20", "Retired KEY MAN 16",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x91, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x91, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "21", "Retired KEY MAN 17", { "21", "Retired KEY MAN 17",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x92, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x92, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "22", "Retired KEY MAN 18", { "22", "Retired KEY MAN 18",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x93, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x93, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "23", "Retired KEY MAN 19", { "23", "Retired KEY MAN 19",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x94, "1", 0}, /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x94, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "24", "Retired KEY MAN 20", { "24", "Retired KEY MAN 20",
SC_PKCS15_PRKEY_USAGE_UNWRAP, /*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x95, "1", 0} /*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x95, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1}
}; };
int r, i; int r, i;
@ -484,6 +543,19 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
&obj_obj, &obj_info); &obj_obj, &obj_info);
if (r < 0) if (r < 0)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
/* TODO
* PIV keys 9C and 9D require the pin verify be done just befor any
* crypto operation using these keys.
*
* Nss 3.12.7 does not check the CKA_ALWAYS_AUTHENTICATE attribute of a key
* and will do a C_FindObjects with only CKA_VALUE looking for a certificate
* it had found earlier after c_Login. The template does not add CKA_TYPE=cert.
* This will cause the card-piv to read all the objects and will reset
* the security status for the 9C and 9D keys.
* Mozilla Bug 457025
*
* We can not read all the objects, as some need the PIN!
*/
} }
/* /*
@ -507,7 +579,7 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
ckis[i].cert_found = 0; ckis[i].cert_found = 0;
ckis[i].key_alg = -1; ckis[i].key_alg = -1;
ckis[i].pubkey_found = 0; ckis[i].pubkey_found = 0;
ckis[i].modulus_len = 0; ckis[i].pubkey_len = 0;
if ((card->flags & 0x20) && (exposed_cert[i] == 0)) if ((card->flags & 0x20) && (exposed_cert[i] == 0))
continue; continue;
@ -552,20 +624,22 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
} }
/* following will find the cached cert in cert_info */ /* following will find the cached cert in cert_info */
r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out); r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
if (r < 0) { if (r < 0 || cert_out->key == NULL) {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Failed to read/parse the certificate r=%d",r); sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Failed to read/parse the certificate r=%d",r);
continue; continue;
} }
/* TODO support EC keys */
ckis[i].key_alg = cert_out->key->algorithm; ckis[i].key_alg = cert_out->key->algorithm;
if (cert_out->key->algorithm == SC_ALGORITHM_RSA) { switch (cert_out->key->algorithm) {
/* save modulus_len for pub and priv */ case SC_ALGORITHM_RSA:
ckis[i].modulus_len = cert_out->key->u.rsa.modulus.len * 8; /* save pubkey_len for pub and priv */
} else { ckis[i].pubkey_len = cert_out->key->u.rsa.modulus.len * 8;
/*TODO add the SC_ALGORITHM_EC */ break;
case SC_ALGORITHM_EC:
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsuported key.algorithm %d", cert_out->key->algorithm); ckis[i].pubkey_len = cert_out->key->u.ec.field_length;
ckis[i].modulus_len = 1024; /* set some value for now */ break;
default:
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsuported key.algorithm %d", cert_out->key->algorithm);
ckis[i].pubkey_len = 0; /* set some value for now */
} }
sc_pkcs15_free_certificate(cert_out); sc_pkcs15_free_certificate(cert_out);
@ -620,7 +694,7 @@ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DEE Adding pin %d label=%s",i, label);
/* set public keys */ /* set public keys */
/* We may only need this during initialzation when genkey /* We may only need this during initialzation when genkey
* gets the pubkey, but it can not be read from the card * gets the pubkey, but it can not be read from the card
* at a later time. The piv-tool can stach in file * at a later time. The piv-tool can stach pubkey in file
*/ */
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "PIV-II adding pub keys..."); sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "PIV-II adding pub keys...");
for (i = 0; i < PIV_NUM_CERTS_AND_KEYS; i++) { for (i = 0; i < PIV_NUM_CERTS_AND_KEYS; i++) {
@ -636,11 +710,10 @@ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DEE Adding pin %d label=%s",i, label);
sc_pkcs15_format_id(pubkeys[i].id, &pubkey_info.id); sc_pkcs15_format_id(pubkeys[i].id, &pubkey_info.id);
pubkey_info.usage = pubkeys[i].usage;
pubkey_info.native = 1; pubkey_info.native = 1;
pubkey_info.key_reference = pubkeys[i].ref; pubkey_info.key_reference = pubkeys[i].ref;
sc_format_path(pubkeys[i].path, &pubkey_info.path); // sc_format_path(pubkeys[i].path, &pubkey_info.path);
strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
@ -650,45 +723,102 @@ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DEE Adding pin %d label=%s",i, label);
if (pubkeys[i].auth_id) if (pubkeys[i].auth_id)
sc_pkcs15_format_id(pubkeys[i].auth_id, &pubkey_obj.auth_id); sc_pkcs15_format_id(pubkeys[i].auth_id, &pubkey_obj.auth_id);
if (ckis[i].cert_found == 0) { /* no cert found */ /* If no cert found, piv-tool may have stached the pubkey
* so we can use it when generating a certificate request
* The file is a OpenSSL DER EVP_KEY, which looks like
* a certificate subjectPublicKeyInfo.
*
*/
if (ckis[i].cert_found == 0 ) { /* no cert found */
char * filename = NULL;
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"No cert for this pub key i=%d",i); sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"No cert for this pub key i=%d",i);
/* TODO EC */
pubkey_obj.type = SC_PKCS15_TYPE_PUBKEY_RSA; /*
pubkey_obj.data = &pubkey_info; * If we used the piv-tool to generate a key,
r = sc_pkcs15_read_pubkey(p15card, &pubkey_obj, &p15_key); * we would have saved the public key as a file.
pubkey_obj.data = NULL; * This code is only used while signing a request
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL," READING PUB KEY r=%d",r); * After the certificate is loaded on the card,
if (r < 0 ) { * the public key is extracted from the certificate.
continue;
}
/* Only get here if no cert, and the card-piv.c found
* there is a pub key file. This only happens when trying
* initializing a card and have set env to point at file
*/ */
if (p15_key->algorithm == SC_ALGORITHM_RSA) {
/* save modulus_len in pub and priv */
ckis[i].key_alg = SC_ALGORITHM_RSA; sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"DEE look for env %s",
ckis[i].modulus_len = p15_key->u.rsa.modulus.len * 8; pubkeys[i].getenvname?pubkeys[i].getenvname:"NULL");
ckis[i].pubkey_found = 1;
if (pubkeys[i].getenvname == NULL)
continue;
filename = getenv(pubkeys[i].getenvname);
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"DEE look for file %s", filename?filename:"NULL");
if (filename == NULL)
continue;
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Adding pubkey from file %s",filename);
r = sc_pkcs15_pubkey_from_spki_filename(card->ctx,
filename,
&p15_key);
if (r < 0)
continue;
/* Only get here if no cert, and the the above found the
* pub key file (actually the SPKI version). This only
* happens when trying initializing a card and have set
* env PIV_9A_KEY or 9C, 9D, 9E to point at the file.
*
* We will cache it using the PKCS15 emulation objects
*/
pubkey_info.path.len = 0;
ckis[i].key_alg = p15_key->algorithm;
switch (p15_key->algorithm) {
case SC_ALGORITHM_RSA:
/* save pubkey_len in pub and priv */
ckis[i].pubkey_len = p15_key->u.rsa.modulus.len * 8;
ckis[i].pubkey_found = 1;
break;
case SC_ALGORITHM_EC:
ckis[i].key_alg = SC_ALGORITHM_EC;
ckis[i].pubkey_len = p15_key->u.ec.field_length;
ckis[i].pubkey_found = 1;
break;
default:
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Unsupported key_alg %d",p15_key->algorithm);
continue;
} }
pubkey_obj.emulated = p15_key;
} p15_key = NULL;
/* TODO need to support EC */
if (ckis[i].key_alg != SC_ALGORITHM_RSA) {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"key_alg for %d not RSA %d",i, ckis[i].key_alg);
continue;
} }
pubkey_info.modulus_length = ckis[i].modulus_len;
strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
/* TODO EC keys */
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"adding pubkey for %d keyalg=%d",i, ckis[i].key_alg); sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"adding pubkey for %d keyalg=%d",i, ckis[i].key_alg);
r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info); switch (ckis[i].key_alg) {
if (r < 0) case SC_ALGORITHM_RSA:
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); /* should not fail */ pubkey_info.usage = pubkeys[i].usage_rsa;
pubkey_info.modulus_length = ckis[i].pubkey_len;
strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
ckis[i].pubkey_found = 1; r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
if (r < 0)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); /* should not fail */
ckis[i].pubkey_found = 1;
break;
case SC_ALGORITHM_EC:
pubkey_info.usage = pubkeys[i].usage_ec;
pubkey_info.field_length = ckis[i].pubkey_len;
strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info);
if (r < 0)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); /* should not fail */
ckis[i].pubkey_found = 1;
break;
default:
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"key_alg %d not supported", ckis[i].key_alg);
continue;
}
} }
@ -708,22 +838,34 @@ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DEE Adding pin %d label=%s",i, label);
continue; /* i.e. no cert or pubkey */ continue; /* i.e. no cert or pubkey */
sc_pkcs15_format_id(prkeys[i].id, &prkey_info.id); sc_pkcs15_format_id(prkeys[i].id, &prkey_info.id);
prkey_info.usage = prkeys[i].usage;
prkey_info.native = 1; prkey_info.native = 1;
prkey_info.key_reference = prkeys[i].ref; prkey_info.key_reference = prkeys[i].ref;
prkey_info.modulus_length= ckis[i].modulus_len;
/* The cert or pubkey should have filled modulus_len */
/* TODO EC keys */
sc_format_path(prkeys[i].path, &prkey_info.path); sc_format_path(prkeys[i].path, &prkey_info.path);
strncpy(prkey_obj.label, prkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1); strncpy(prkey_obj.label, prkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
prkey_obj.flags = prkeys[i].obj_flags; prkey_obj.flags = prkeys[i].obj_flags;
prkey_obj.user_consent = prkeys[i].user_consent;
if (prkeys[i].auth_id) if (prkeys[i].auth_id)
sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id); sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id);
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info); switch (ckis[i].key_alg) {
case SC_ALGORITHM_RSA:
prkey_info.usage = prkeys[i].usage_rsa;
prkey_info.modulus_length= ckis[i].pubkey_len;
r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
break;
case SC_ALGORITHM_EC:
prkey_info.usage = prkeys[i].usage_ec;
prkey_info.field_length = ckis[i].pubkey_len;
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DEE added key_alg %2.2x prkey_obj.flags %8.8x",
ckis[i].key_alg, prkey_obj.flags);
r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info);
break;
default:
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsupported key_alg %d", ckis[i].key_alg);
r = 0; /* we just skip this one */
}
if (r < 0) if (r < 0)
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
} }

View File

@ -497,6 +497,9 @@ sc_pkcs15_erase_prkey(struct sc_pkcs15_prkey *key)
assert(key->u.gostr3410.d.data); assert(key->u.gostr3410.d.data);
free(key->u.gostr3410.d.data); free(key->u.gostr3410.d.data);
break; break;
case SC_ALGORITHM_EC:
/* TODO: -DEE may not need much */
break;
} }
sc_mem_clear(key, sizeof(key)); sc_mem_clear(key, sizeof(key));
} }

View File

@ -74,6 +74,9 @@ int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
unsigned long pad_flags = 0, sec_flags = 0; unsigned long pad_flags = 0, sec_flags = 0;
SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
memset(&senv, 0, sizeof(senv));
/* If the key is not native, we can't operate with it. */ /* If the key is not native, we can't operate with it. */
if (!prkey->native) if (!prkey->native)
return SC_ERROR_NOT_SUPPORTED; return SC_ERROR_NOT_SUPPORTED;
@ -83,6 +86,8 @@ int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
return SC_ERROR_NOT_ALLOWED; return SC_ERROR_NOT_ALLOWED;
} }
/* Note ECDSA can not decrypt, so code is assuming RSA */
alg_info = sc_card_find_rsa_alg(p15card->card, prkey->modulus_length); alg_info = sc_card_find_rsa_alg(p15card->card, prkey->modulus_length);
if (alg_info == NULL) { if (alg_info == NULL) {
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Card does not support RSA with key length %d\n", prkey->modulus_length); sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Card does not support RSA with key length %d\n", prkey->modulus_length);
@ -157,11 +162,18 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
sc_algorithm_info_t *alg_info; sc_algorithm_info_t *alg_info;
const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data; const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data;
u8 buf[512], *tmp; u8 buf[512], *tmp;
size_t modlen = prkey->modulus_length / 8; size_t modlen;
unsigned long pad_flags = 0, sec_flags = 0; unsigned long pad_flags = 0, sec_flags = 0;
SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
memset(&senv, 0, sizeof(senv));
if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) != SC_PKCS15_TYPE_PRKEY) {
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "This is not a private key");
return SC_ERROR_NOT_ALLOWED;
}
/* If the key is not native, we can't operate with it. */ /* If the key is not native, we can't operate with it. */
if (!prkey->native) if (!prkey->native)
return SC_ERROR_NOT_SUPPORTED; return SC_ERROR_NOT_SUPPORTED;
@ -172,12 +184,41 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
return SC_ERROR_NOT_ALLOWED; return SC_ERROR_NOT_ALLOWED;
} }
alg_info = sc_card_find_rsa_alg(p15card->card, prkey->modulus_length); switch (obj->type) {
if (alg_info == NULL) { /* FIXME -DEE GOSTR is misusing the sc_card_find_rsa_alg */
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Card does not support RSA with key length %d\n", prkey->modulus_length); case SC_PKCS15_TYPE_PRKEY_GOSTR3410:
return SC_ERROR_NOT_SUPPORTED; case SC_PKCS15_TYPE_PRKEY_RSA:
modlen = prkey->modulus_length / 8;
alg_info = sc_card_find_rsa_alg(p15card->card, prkey->modulus_length);
if (alg_info == NULL) {
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Card does not support RSA with key length %d\n", prkey->modulus_length);
return SC_ERROR_NOT_SUPPORTED;
}
senv.flags |= SC_SEC_ENV_ALG_PRESENT;
senv.algorithm = SC_ALGORITHM_RSA;
break;
case SC_PKCS15_TYPE_PRKEY_EC:
modlen = ((prkey->field_length +7) / 8) * 2; /* 2*nLen */
alg_info = sc_card_find_ec_alg(p15card->card, prkey->field_length);
if (alg_info == NULL) {
sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
"Card does not support EC with field_size %d",
prkey->field_length);
return SC_ERROR_NOT_SUPPORTED;
}
senv.algorithm = SC_ALGORITHM_EC;
senv.flags |= SC_SEC_ENV_ALG_PRESENT;
senv.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
senv.algorithm_ref = prkey->field_length;
break;
/* add other crypto types here */
default:
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Key type not supported");
return SC_ERROR_NOT_SUPPORTED;
} }
senv.algorithm = SC_ALGORITHM_RSA;
/* Probably never happens, but better make sure */ /* Probably never happens, but better make sure */
if (inlen > sizeof(buf) || outlen < modlen) if (inlen > sizeof(buf) || outlen < modlen)
@ -191,6 +232,7 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
/* if the card has SC_ALGORITHM_NEED_USAGE set, and the /* if the card has SC_ALGORITHM_NEED_USAGE set, and the
key is for signing and decryption, we need to emulate signing */ key is for signing and decryption, we need to emulate signing */
/* TODO: -DEE assume only RSA keys will ever use _NEED_USAGE */
if ((alg_info->flags & SC_ALGORITHM_NEED_USAGE) && if ((alg_info->flags & SC_ALGORITHM_NEED_USAGE) &&
((prkey->usage & USAGE_ANY_SIGN) && ((prkey->usage & USAGE_ANY_SIGN) &&
@ -241,13 +283,18 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
} }
senv.algorithm_flags = sec_flags; senv.algorithm_flags = sec_flags;
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "DEE flags:0x%8.8x alg_info->flags:0x%8.8x pad:0x%8.8x sec:0x%8.8x",
flags, alg_info->flags, pad_flags, sec_flags);
/* add the padding bytes (if necessary) */ /* add the padding bytes (if necessary) */
if (pad_flags != 0) { if (pad_flags != 0) {
size_t tmplen = sizeof(buf); size_t tmplen = sizeof(buf);
r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen, modlen); r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen, modlen);
SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Unable to add padding"); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Unable to add padding");
inlen = tmplen; inlen = tmplen;
} else if ((flags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) { } else if ( senv.algorithm == SC_ALGORITHM_RSA &&
(flags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) {
/* Add zero-padding if input is shorter than the modulus */ /* Add zero-padding if input is shorter than the modulus */
if (inlen < modlen) { if (inlen < modlen) {
if (modlen > sizeof(buf)) if (modlen > sizeof(buf))
@ -258,14 +305,13 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
} }
senv.operation = SC_SEC_OPERATION_SIGN; senv.operation = SC_SEC_OPERATION_SIGN;
senv.flags = 0;
/* optional keyReference attribute (the default value is -1) */ /* optional keyReference attribute (the default value is -1) */
if (prkey->key_reference >= 0) { if (prkey->key_reference >= 0) {
senv.key_ref_len = 1; senv.key_ref_len = 1;
senv.key_ref[0] = prkey->key_reference & 0xFF; senv.key_ref[0] = prkey->key_reference & 0xFF;
senv.flags |= SC_SEC_ENV_KEY_REF_PRESENT; senv.flags |= SC_SEC_ENV_KEY_REF_PRESENT;
} }
senv.flags |= SC_SEC_ENV_ALG_PRESENT;
r = sc_lock(p15card->card); r = sc_lock(p15card->card);
SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "sc_lock() failed"); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "sc_lock() failed");

View File

@ -102,8 +102,8 @@ struct pkcs15_pubkey_object {
#define pub_genfrom base.related_cert #define pub_genfrom base.related_cert
#define __p15_type(obj) (((obj) && (obj)->p15_object)? ((obj)->p15_object->type) : (unsigned int)-1) #define __p15_type(obj) (((obj) && (obj)->p15_object)? ((obj)->p15_object->type) : (unsigned int)-1)
#define is_privkey(obj) (__p15_type(obj) == SC_PKCS15_TYPE_PRKEY_RSA || __p15_type(obj) == SC_PKCS15_TYPE_PRKEY_GOSTR3410) #define is_privkey(obj) ((__p15_type(obj) & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_PRKEY)
#define is_pubkey(obj) (__p15_type(obj) == SC_PKCS15_TYPE_PUBKEY_RSA || __p15_type(obj) == SC_PKCS15_TYPE_PUBKEY_GOSTR3410) #define is_pubkey(obj) ((__p15_type(obj) & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_PUBKEY)
#define is_cert(obj) (__p15_type(obj) == SC_PKCS15_TYPE_CERT_X509) #define is_cert(obj) (__p15_type(obj) == SC_PKCS15_TYPE_CERT_X509)
struct pkcs15_data_object { struct pkcs15_data_object {
@ -145,6 +145,8 @@ static CK_RV get_modulus_bits(struct sc_pkcs15_pubkey *,
static CK_RV get_usage_bit(unsigned int usage, CK_ATTRIBUTE_PTR attr); static CK_RV get_usage_bit(unsigned int usage, CK_ATTRIBUTE_PTR attr);
static CK_RV asn1_sequence_wrapper(const u8 *, size_t, CK_ATTRIBUTE_PTR); static CK_RV asn1_sequence_wrapper(const u8 *, size_t, CK_ATTRIBUTE_PTR);
static CK_RV get_gostr3410_params(const u8 *, size_t, CK_ATTRIBUTE_PTR); static CK_RV get_gostr3410_params(const u8 *, size_t, CK_ATTRIBUTE_PTR);
static CK_RV get_ec_pubkey_point(struct sc_pkcs15_pubkey *, CK_ATTRIBUTE_PTR);
static CK_RV get_ec_pubkey_params(struct sc_pkcs15_pubkey *, CK_ATTRIBUTE_PTR);
static int lock_card(struct pkcs15_fw_data *); static int lock_card(struct pkcs15_fw_data *);
static int unlock_card(struct pkcs15_fw_data *); static int unlock_card(struct pkcs15_fw_data *);
static int reselect_app_df(sc_pkcs15_card_t *p15card); static int reselect_app_df(sc_pkcs15_card_t *p15card);
@ -368,6 +370,7 @@ static int public_key_created(struct pkcs15_fw_data *fw_data,
if ((fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY) && if ((fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY) &&
(fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY_RSA) && (fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY_RSA) &&
(fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY_DSA) && (fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY_DSA) &&
(fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY_EC) &&
(fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY_GOSTR3410)) { (fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY_GOSTR3410)) {
ii++; ii++;
continue; continue;
@ -858,28 +861,43 @@ static CK_RV pkcs15_create_tokens(struct sc_pkcs11_card *p11card)
rv = pkcs15_create_pkcs11_objects(fw_data, rv = pkcs15_create_pkcs11_objects(fw_data,
SC_PKCS15_TYPE_PRKEY_RSA, SC_PKCS15_TYPE_PRKEY_RSA,
"private key", "RSA private key",
__pkcs15_create_prkey_object); __pkcs15_create_prkey_object);
if (rv < 0) if (rv < 0)
return sc_to_cryptoki_error(rv, NULL); return sc_to_cryptoki_error(rv, NULL);
rv = pkcs15_create_pkcs11_objects(fw_data, rv = pkcs15_create_pkcs11_objects(fw_data,
SC_PKCS15_TYPE_PUBKEY_RSA, SC_PKCS15_TYPE_PUBKEY_RSA,
"public key", "RSA public key",
__pkcs15_create_pubkey_object); __pkcs15_create_pubkey_object);
if (rv < 0) if (rv < 0)
return sc_to_cryptoki_error(rv, NULL); return sc_to_cryptoki_error(rv, NULL);
rv = pkcs15_create_pkcs11_objects(fw_data,
SC_PKCS15_TYPE_PRKEY_EC,
"EC private key",
__pkcs15_create_prkey_object);
if (rv < 0)
return sc_to_cryptoki_error(rv, NULL);
rv = pkcs15_create_pkcs11_objects(fw_data,
SC_PKCS15_TYPE_PUBKEY_EC,
"EC public key",
__pkcs15_create_pubkey_object);
if (rv < 0)
return sc_to_cryptoki_error(rv, NULL);
rv = pkcs15_create_pkcs11_objects(fw_data, rv = pkcs15_create_pkcs11_objects(fw_data,
SC_PKCS15_TYPE_PRKEY_GOSTR3410, SC_PKCS15_TYPE_PRKEY_GOSTR3410,
"private key", "GOSTR3410 private key",
__pkcs15_create_prkey_object); __pkcs15_create_prkey_object);
if (rv < 0) if (rv < 0)
return sc_to_cryptoki_error(rv, NULL); return sc_to_cryptoki_error(rv, NULL);
rv = pkcs15_create_pkcs11_objects(fw_data, rv = pkcs15_create_pkcs11_objects(fw_data,
SC_PKCS15_TYPE_PUBKEY_GOSTR3410, SC_PKCS15_TYPE_PUBKEY_GOSTR3410,
"public key", "GOSTR3410 public key",
__pkcs15_create_pubkey_object); __pkcs15_create_pubkey_object);
if (rv < 0) if (rv < 0)
return sc_to_cryptoki_error(rv, NULL); return sc_to_cryptoki_error(rv, NULL);
@ -1115,6 +1133,7 @@ static CK_RV pkcs15_login(struct sc_pkcs11_slot *slot,
return CKR_PIN_INCORRECT; return CKR_PIN_INCORRECT;
} }
/* By default, we make the reader resource manager keep other /* By default, we make the reader resource manager keep other
* processes from accessing the card while we're logged in. * processes from accessing the card while we're logged in.
* Otherwise an attacker could perform some crypto operation * Otherwise an attacker could perform some crypto operation
@ -1339,6 +1358,7 @@ static CK_RV pkcs15_create_private_key(struct sc_pkcs11_card *p11card,
struct sc_pkcs15_pin_info *pin; struct sc_pkcs15_pin_info *pin;
CK_KEY_TYPE key_type; CK_KEY_TYPE key_type;
struct sc_pkcs15_prkey_rsa *rsa; struct sc_pkcs15_prkey_rsa *rsa;
struct sc_pkcs15_prkey_ec *ec;
int rc, rv; int rc, rv;
char label[SC_PKCS15_MAX_LABEL_SIZE]; char label[SC_PKCS15_MAX_LABEL_SIZE];
@ -1353,10 +1373,20 @@ static CK_RV pkcs15_create_private_key(struct sc_pkcs11_card *p11card,
rv = attr_find(pTemplate, ulCount, CKA_KEY_TYPE, &key_type, NULL); rv = attr_find(pTemplate, ulCount, CKA_KEY_TYPE, &key_type, NULL);
if (rv != CKR_OK) if (rv != CKR_OK)
return rv; return rv;
if (key_type != CKK_RSA) switch (key_type) {
return CKR_ATTRIBUTE_VALUE_INVALID; case CKK_RSA:
args.key.algorithm = SC_ALGORITHM_RSA; args.key.algorithm = SC_ALGORITHM_RSA;
rsa = &args.key.u.rsa; rsa = &args.key.u.rsa;
break;
case CKK_EC:
args.key.algorithm = SC_ALGORITHM_EC;
ec = &args.key.u.ec;
/* TODO: -DEE Do not have PKCS15 card with EC to test this */
/* fall through */
default:
return CKR_ATTRIBUTE_VALUE_INVALID;
}
rv = CKR_OK; rv = CKR_OK;
while (ulCount--) { while (ulCount--) {
@ -1450,10 +1480,17 @@ static CK_RV pkcs15_create_public_key(struct sc_pkcs11_card *p11card,
rv = attr_find(pTemplate, ulCount, CKA_KEY_TYPE, &key_type, NULL); rv = attr_find(pTemplate, ulCount, CKA_KEY_TYPE, &key_type, NULL);
if (rv != CKR_OK) if (rv != CKR_OK)
return rv; return rv;
if (key_type != CKK_RSA) switch (key_type) {
return CKR_ATTRIBUTE_VALUE_INVALID; case CKK_RSA:
args.key.algorithm = SC_ALGORITHM_RSA; args.key.algorithm = SC_ALGORITHM_RSA;
rsa = &args.key.u.rsa; rsa = &args.key.u.rsa;
break;
case CKK_EC:
/* TODO: -DEE Do not have real pkcs15 card with EC */
/* fall through */
default:
return CKR_ATTRIBUTE_VALUE_INVALID;
}
rv = CKR_OK; rv = CKR_OK;
while (ulCount--) { while (ulCount--) {
@ -2298,9 +2335,11 @@ static CK_RV pkcs15_prkey_get_attribute(struct sc_pkcs11_session *session,
* applications assume they can get that from the private * applications assume they can get that from the private
* key, something PKCS#11 doesn't guarantee. * key, something PKCS#11 doesn't guarantee.
*/ */
if ((attr->type == CKA_MODULUS) || (attr->type == CKA_PUBLIC_EXPONENT)) { if ((attr->type == CKA_MODULUS) || (attr->type == CKA_PUBLIC_EXPONENT) ||
((attr->type == CKA_MODULUS_BITS) && (prkey->prv_p15obj->type == SC_PKCS15_TYPE_PRKEY_EC)) ||
(attr->type == CKA_ECDSA_PARAMS)) {
/* First see if we have a associated public key */ /* First see if we have a associated public key */
if (prkey->prv_pubkey) if (prkey->prv_pubkey && prkey->prv_pubkey->pub_data)
key = prkey->prv_pubkey->pub_data; key = prkey->prv_pubkey->pub_data;
else { else {
/* Try to find a certificate with the public key */ /* Try to find a certificate with the public key */
@ -2357,10 +2396,19 @@ static CK_RV pkcs15_prkey_get_attribute(struct sc_pkcs11_session *session,
break; break;
case CKA_KEY_TYPE: case CKA_KEY_TYPE:
check_attribute_buffer(attr, sizeof(CK_KEY_TYPE)); check_attribute_buffer(attr, sizeof(CK_KEY_TYPE));
if (prkey->prv_p15obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410) switch (prkey->prv_p15obj->type) {
*(CK_KEY_TYPE*)attr->pValue = CKK_GOSTR3410; case SC_PKCS15_TYPE_PRKEY_RSA:
else *(CK_KEY_TYPE*)attr->pValue = CKK_RSA;
*(CK_KEY_TYPE*)attr->pValue = CKK_RSA; break;
case SC_PKCS15_TYPE_PRKEY_GOSTR3410:
*(CK_KEY_TYPE*)attr->pValue = CKK_GOSTR3410;
break;
case SC_PKCS15_TYPE_PRKEY_EC:
*(CK_KEY_TYPE*)attr->pValue = CKK_EC;
break;
default:
return CKR_GENERAL_ERROR; /* Internal error*/
}
break; break;
case CKA_ID: case CKA_ID:
check_attribute_buffer(attr, prkey->prv_info->id.len); check_attribute_buffer(attr, prkey->prv_info->id.len);
@ -2390,8 +2438,17 @@ static CK_RV pkcs15_prkey_get_attribute(struct sc_pkcs11_session *session,
* on this -- Nils */ * on this -- Nils */
case CKA_MODULUS_BITS: case CKA_MODULUS_BITS:
check_attribute_buffer(attr, sizeof(CK_ULONG)); check_attribute_buffer(attr, sizeof(CK_ULONG));
*(CK_ULONG *) attr->pValue = prkey->prv_info->modulus_length; switch (prkey->prv_p15obj->type) {
return CKR_OK; case SC_PKCS15_TYPE_PRKEY_EC:
if (key)
*(CK_ULONG *) attr->pValue = key->u.ec.field_length;
else
*(CK_ULONG *) attr->pValue = 384; /* TODO -DEE needs work */
return CKR_OK;
default:
*(CK_ULONG *) attr->pValue = prkey->prv_info->modulus_length;
return CKR_OK;
}
case CKA_PUBLIC_EXPONENT: case CKA_PUBLIC_EXPONENT:
return get_public_exponent(key, attr); return get_public_exponent(key, attr);
case CKA_PRIVATE_EXPONENT: case CKA_PRIVATE_EXPONENT:
@ -2412,6 +2469,8 @@ static CK_RV pkcs15_prkey_get_attribute(struct sc_pkcs11_session *session,
prkey->prv_info->params_len, attr); prkey->prv_info->params_len, attr);
else else
return CKR_ATTRIBUTE_TYPE_INVALID; return CKR_ATTRIBUTE_TYPE_INVALID;
case CKA_EC_PARAMS:
return get_ec_pubkey_params(key, attr); /* get from pubkey for now */
default: default:
return CKR_ATTRIBUTE_TYPE_INVALID; return CKR_ATTRIBUTE_TYPE_INVALID;
} }
@ -2472,7 +2531,28 @@ static CK_RV pkcs15_prkey_sign(struct sc_pkcs11_session *ses, void *obj,
case CKM_GOSTR3410_WITH_GOSTR3411: case CKM_GOSTR3410_WITH_GOSTR3411:
flags = SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411; flags = SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411;
break; break;
case CKM_ECDSA:
flags = SC_ALGORITHM_ECDSA_HASH_NONE;
break;
case CKM_ECDSA_SHA1:
flags = SC_ALGORITHM_ECDSA_HASH_SHA1;
break;
#if 0
case CKM_ECDSA_SHA224:
flags = SC_ALGORITHM_ECDSA_HASH_SHA224;
break;
case CKM_ECDSA_SHA256:
flags = SC_ALGORITHM_ECDSA_HASH_SHA256;
break;
case CKM_ECDSA_SHA384:
flags = SC_ALGORITHM_ECDSA_HASH_SHA384;
break;
case CKM_ECDSA_SHA512:
flags = SC_ALGORITHM_ECDSA_HASH_SHA512;
break;
#endif
default: default:
sc_debug(context, SC_LOG_DEBUG_NORMAL, "DEE - need EC for %d",pMechanism->mechanism);
return CKR_MECHANISM_INVALID; return CKR_MECHANISM_INVALID;
} }
@ -2627,6 +2707,8 @@ static CK_RV pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session,
case CKA_MODULUS_BITS: case CKA_MODULUS_BITS:
case CKA_VALUE: case CKA_VALUE:
case CKA_PUBLIC_EXPONENT: case CKA_PUBLIC_EXPONENT:
case CKA_EC_PARAMS:
case CKA_EC_POINT:
if (pubkey->pub_data == NULL) if (pubkey->pub_data == NULL)
/* FIXME: check the return value? */ /* FIXME: check the return value? */
check_cert_data_read(fw_data, cert); check_cert_data_read(fw_data, cert);
@ -2678,8 +2760,12 @@ static CK_RV pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session,
break; break;
case CKA_KEY_TYPE: case CKA_KEY_TYPE:
check_attribute_buffer(attr, sizeof(CK_KEY_TYPE)); check_attribute_buffer(attr, sizeof(CK_KEY_TYPE));
/* TODO: -DEE why would we not have a pubkey->pub_data? */
/* even if we do not, we should not assume RSA */
if (pubkey->pub_data && pubkey->pub_data->algorithm == SC_ALGORITHM_GOSTR3410) if (pubkey->pub_data && pubkey->pub_data->algorithm == SC_ALGORITHM_GOSTR3410)
*(CK_KEY_TYPE*)attr->pValue = CKK_GOSTR3410; *(CK_KEY_TYPE*)attr->pValue = CKK_GOSTR3410;
else if (pubkey->pub_data && pubkey->pub_data->algorithm == SC_ALGORITHM_EC)
*(CK_KEY_TYPE*)attr->pValue = CKK_EC;
else else
*(CK_KEY_TYPE*)attr->pValue = CKK_RSA; *(CK_KEY_TYPE*)attr->pValue = CKK_RSA;
break; break;
@ -2723,6 +2809,10 @@ static CK_RV pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session,
return get_public_exponent(pubkey->pub_data, attr); return get_public_exponent(pubkey->pub_data, attr);
case CKA_VALUE: case CKA_VALUE:
if (pubkey->pub_data) { if (pubkey->pub_data) {
/* TODO: -DEE Not all pubkeys have CKA_VALUE attribute. RSA and EC
* for example don't. So why is this here?
* Why checking for cert in this pkcs15_pubkey_get_attribute?
*/
check_attribute_buffer(attr, pubkey->pub_data->data.len); check_attribute_buffer(attr, pubkey->pub_data->data.len);
memcpy(attr->pValue, pubkey->pub_data->data.value, memcpy(attr->pValue, pubkey->pub_data->data.value,
pubkey->pub_data->data.len); pubkey->pub_data->data.len);
@ -2737,6 +2827,11 @@ static CK_RV pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session,
pubkey->pub_info->params_len, attr); pubkey->pub_info->params_len, attr);
else else
return CKR_ATTRIBUTE_TYPE_INVALID; return CKR_ATTRIBUTE_TYPE_INVALID;
case CKA_EC_PARAMS:
return get_ec_pubkey_params(pubkey->pub_data, attr);
case CKA_EC_POINT:
return get_ec_pubkey_point(pubkey->pub_data, attr);
default: default:
return CKR_ATTRIBUTE_TYPE_INVALID; return CKR_ATTRIBUTE_TYPE_INVALID;
} }
@ -2959,6 +3054,40 @@ get_public_exponent(struct sc_pkcs15_pubkey *key, CK_ATTRIBUTE_PTR attr)
return CKR_ATTRIBUTE_TYPE_INVALID; return CKR_ATTRIBUTE_TYPE_INVALID;
} }
static CK_RV
get_ec_pubkey_params(struct sc_pkcs15_pubkey *key, CK_ATTRIBUTE_PTR attr)
{
struct sc_ec_params * ecp;
if (key == NULL)
return CKR_ATTRIBUTE_TYPE_INVALID;
if (key->alg_id == NULL)
return CKR_ATTRIBUTE_TYPE_INVALID;
ecp = (struct sc_ec_params *) key->alg_id->params;
switch (key->algorithm) {
case SC_ALGORITHM_EC:
check_attribute_buffer(attr, ecp->der_len);
memcpy(attr->pValue, ecp->der, ecp->der_len);
return CKR_OK;
}
return CKR_ATTRIBUTE_TYPE_INVALID;
}
static CK_RV
get_ec_pubkey_point(struct sc_pkcs15_pubkey *key, CK_ATTRIBUTE_PTR attr)
{
if (key == NULL)
return CKR_ATTRIBUTE_TYPE_INVALID;
switch (key->algorithm) {
case SC_ALGORITHM_EC:
check_attribute_buffer(attr, key->u.ec.ecpointQ.len);
memcpy(attr->pValue, key->u.ec.ecpointQ.value, key->u.ec.ecpointQ.len);
return CKR_OK;
}
return CKR_ATTRIBUTE_TYPE_INVALID;
}
static CK_RV static CK_RV
get_gostr3410_params(const u8 *params, size_t params_len, CK_ATTRIBUTE_PTR attr) get_gostr3410_params(const u8 *params, size_t params_len, CK_ATTRIBUTE_PTR attr)
{ {
@ -3089,6 +3218,60 @@ static int register_gost_mechanisms(struct sc_pkcs11_card *p11card, int flags)
return CKR_OK; return CKR_OK;
} }
static int register_ec_mechanisms(struct sc_pkcs11_card *p11card, int flags,
unsigned long ext_flags, int min_key_size, int max_key_size)
{
CK_MECHANISM_INFO mech_info;
sc_pkcs11_mechanism_type_t *mt;
int rc;
mech_info.flags = CKF_HW | CKF_SIGN; /* check for more */
if (ext_flags & SC_ALGORITHM_EXT_EC_F_P)
mech_info.flags |= CKF_EC_F_P;
if (ext_flags & SC_ALGORITHM_EXT_EC_F_2M)
mech_info.flags |= CKF_EC_F_2M;
if (ext_flags & SC_ALGORITHM_EXT_EC_ECPARAMETERS)
mech_info.flags |= CKF_EC_ECPARAMETERS;
if (ext_flags & SC_ALGORITHM_EXT_EC_NAMEDCURVE)
mech_info.flags |= CKF_EC_NAMEDCURVE;
if (ext_flags & SC_ALGORITHM_EXT_EC_UNCOMPRESES)
mech_info.flags |= CKF_EC_UNCOMPRESES;
if (ext_flags & SC_ALGORITHM_EXT_EC_COMPRESS)
mech_info.flags |= CKF_EC_COMPRESS;
mech_info.ulMinKeySize = min_key_size;
mech_info.ulMaxKeySize = max_key_size;
mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA,
&mech_info, CKK_EC, NULL);
if (!mt)
return CKR_HOST_MEMORY;
rc = sc_pkcs11_register_mechanism(p11card, mt);
if (rc != CKR_OK)
return rc;
#if ENABLE_OPENSSL
mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA1,
&mech_info, CKK_EC, NULL);
if (!mt)
return CKR_HOST_MEMORY;
rc = sc_pkcs11_register_mechanism(p11card, mt);
if (rc != CKR_OK)
return rc;
#endif
#if 0
/* TODO: -DEE Add CKM_ECDH1_COFACTOR_DERIVE as PIV can do this */
/* TODO: -DEE But this requires C_DeriveKey to be implemented */
mech_info.flags &= ~CKF_SIGN;
mech_info.flags |= CKF_DRIVE;
sc_pkcs11_new_fw_mechanism(CKM_ECDH1_COFACTOR_DERIVE,
CKM_ECDH1_COFACTOR_DERIVE, NULL);
#endif
return CKR_OK;
}
/* /*
* Mechanism handling * Mechanism handling
* FIXME: We should consult the card's algorithm list to * FIXME: We should consult the card's algorithm list to
@ -3099,6 +3282,8 @@ static int register_mechanisms(struct sc_pkcs11_card *p11card)
sc_card_t *card = p11card->card; sc_card_t *card = p11card->card;
sc_algorithm_info_t *alg_info; sc_algorithm_info_t *alg_info;
CK_MECHANISM_INFO mech_info; CK_MECHANISM_INFO mech_info;
int ec_min_key_size, ec_max_key_size;
unsigned long ec_ext_flags;
sc_pkcs11_mechanism_type_t *mt; sc_pkcs11_mechanism_type_t *mt;
unsigned int num; unsigned int num;
int rc, flags = 0; int rc, flags = 0;
@ -3113,27 +3298,50 @@ static int register_mechanisms(struct sc_pkcs11_card *p11card)
#endif #endif
mech_info.ulMinKeySize = ~0; mech_info.ulMinKeySize = ~0;
mech_info.ulMaxKeySize = 0; mech_info.ulMaxKeySize = 0;
ec_min_key_size = ~0;
ec_max_key_size = 0;
ec_ext_flags = 0;
/* For now, we just OR all the algorithm specific /* For now, we just OR all the algorithm specific
* flags, based on the assumption that cards don't * flags, based on the assumption that cards don't
* support different modes for different key sizes * support different modes for different key sizes
* But we need to do this by type of key as
* each has different min/max and different flags.
*
* TODO: -DEE This code assumed RSA, but the GOST
* and EC code was forced in. There should be a
* routine for each key type.
*/ */
num = card->algorithm_count; num = card->algorithm_count;
alg_info = card->algorithms; alg_info = card->algorithms;
while (num--) { while (num--) {
if (alg_info->algorithm == SC_ALGORITHM_RSA) { switch (alg_info->algorithm) {
if (alg_info->key_length < mech_info.ulMinKeySize) case SC_ALGORITHM_RSA:
mech_info.ulMinKeySize = alg_info->key_length; if (alg_info->key_length < mech_info.ulMinKeySize)
if (alg_info->key_length > mech_info.ulMaxKeySize) mech_info.ulMinKeySize = alg_info->key_length;
mech_info.ulMaxKeySize = alg_info->key_length; if (alg_info->key_length > mech_info.ulMaxKeySize)
mech_info.ulMaxKeySize = alg_info->key_length;
flags |= alg_info->flags; flags |= alg_info->flags;
break;
case SC_ALGORITHM_EC:
if (alg_info->key_length < ec_min_key_size)
ec_min_key_size = alg_info->key_length;
if (alg_info->key_length > ec_max_key_size)
ec_max_key_size = alg_info->key_length;
flags |= alg_info->flags;
ec_ext_flags |= alg_info->u._ec.ext_flags;
break;
case SC_ALGORITHM_GOSTR3410:
flags |= alg_info->flags;
break;
} }
if (alg_info->algorithm == SC_ALGORITHM_GOSTR3410)
flags |= alg_info->flags;
alg_info++; alg_info++;
} }
if (flags & SC_ALGORITHM_ECDSA_RAW) {
rc = register_ec_mechanisms(p11card, flags, ec_ext_flags, ec_min_key_size, ec_max_key_size);
}
if (flags & (SC_ALGORITHM_GOSTR3410_RAW if (flags & (SC_ALGORITHM_GOSTR3410_RAW
| SC_ALGORITHM_GOSTR3410_HASH_NONE | SC_ALGORITHM_GOSTR3410_HASH_NONE
| SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411)) { | SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411)) {

View File

@ -429,22 +429,42 @@ static CK_RV
sc_pkcs11_signature_size(sc_pkcs11_operation_t *operation, CK_ULONG_PTR pLength) sc_pkcs11_signature_size(sc_pkcs11_operation_t *operation, CK_ULONG_PTR pLength)
{ {
struct sc_pkcs11_object *key; struct sc_pkcs11_object *key;
CK_ULONG ec_point_size = 0;
CK_BYTE_PTR ec_point = NULL;
CK_ATTRIBUTE attr = { CKA_MODULUS_BITS, pLength, sizeof(*pLength) }; CK_ATTRIBUTE attr = { CKA_MODULUS_BITS, pLength, sizeof(*pLength) };
CK_KEY_TYPE key_type; CK_KEY_TYPE key_type;
CK_ATTRIBUTE attr_key_type = { CKA_KEY_TYPE, &key_type, sizeof(key_type) }; CK_ATTRIBUTE attr_key_type = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
CK_RV rv; CK_RV rv;
key = ((struct signature_data *) operation->priv_data)->key; key = ((struct signature_data *) operation->priv_data)->key;
rv = key->ops->get_attribute(operation->session, key, &attr); /*
* EC (and maybe GOSTR) do not have CKA_MODULUS_BITS attribute.
/* convert bits to bytes */ * But other code in framework treats them as if they do.
if (rv == CKR_OK) * So should do switch(key_type)
*pLength = (*pLength + 7) / 8; * and then get what ever attributes are needed.
*/
rv = key->ops->get_attribute(operation->session, key, &attr_key_type);
if (rv == CKR_OK) { if (rv == CKR_OK) {
rv = key->ops->get_attribute(operation->session, key, &attr_key_type); switch(key_type) {
if (rv == CKR_OK && key_type == CKK_GOSTR3410) case CKK_RSA:
*pLength *= 2; rv = key->ops->get_attribute(operation->session, key, &attr);
/* convert bits to bytes */
if (rv == CKR_OK)
*pLength = (*pLength + 7) / 8;
break;
case CKK_EC:
/* TODO: -DEE we should use something other then CKA_MODULUS_BITS... */
rv = key->ops->get_attribute(operation->session, key, &attr);
*pLength = ((*pLength + 7)/8) * 2 ; /* 2*nLen in bytes */
break;
case CKK_GOSTR3410:
rv = key->ops->get_attribute(operation->session, key, &attr);
if (rv == CKR_OK)
*pLength *= 2;
break;
default:
rv = CKR_MECHANISM_INVALID;
}
} }
return rv; return rv;
@ -795,6 +815,9 @@ sc_pkcs11_new_fw_mechanism(CK_MECHANISM_TYPE mech,
if (pInfo->flags & CKF_UNWRAP) { if (pInfo->flags & CKF_UNWRAP) {
/* TODO */ /* TODO */
} }
if (pInfo->flags & CKF_DERIVE) {
/* TODO: -DEE CKM_ECDH1_COFACTOR_DERIVE for PIV */
}
if (pInfo->flags & CKF_DECRYPT) { if (pInfo->flags & CKF_DECRYPT) {
mt->decrypt_init = sc_pkcs11_decrypt_init; mt->decrypt_init = sc_pkcs11_decrypt_init;
mt->decrypt = sc_pkcs11_decrypt; mt->decrypt = sc_pkcs11_decrypt;

View File

@ -103,7 +103,7 @@ CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, /* the session's handle */
pTemplate, ulCount, phObject); pTemplate, ulCount, phObject);
out: sc_pkcs11_unlock(); out: sc_pkcs11_unlock();
return rv; SC_FUNC_RETURN(context, SC_LOG_DEBUG_VERBOSE, rv);
} }
CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, /* the session's handle */
@ -985,6 +985,7 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_ULONG ulAttributeCount, /* # of attributes in template */ CK_ULONG ulAttributeCount, /* # of attributes in template */
CK_OBJECT_HANDLE_PTR phKey) CK_OBJECT_HANDLE_PTR phKey)
{ /* gets handle of derived key */ { /* gets handle of derived key */
/* TODO: -DEE ECDH with Cofactor on PIV is an example */
return CKR_FUNCTION_NOT_SUPPORTED; return CKR_FUNCTION_NOT_SUPPORTED;
} }

View File

@ -31,11 +31,14 @@
#include <ctype.h> #include <ctype.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/x509.h> #include <openssl/x509.h>
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/bio.h> #include <openssl/bio.h>
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/obj_mac.h>
#include "libopensc/opensc.h" #include "libopensc/opensc.h"
#include "libopensc/cardctl.h" #include "libopensc/cardctl.h"
@ -94,6 +97,7 @@ static const char *option_help[] = {
static sc_context_t *ctx = NULL; static sc_context_t *ctx = NULL;
static sc_card_t *card = NULL; static sc_card_t *card = NULL;
static BIO * bp = NULL; static BIO * bp = NULL;
static EVP_PKEY * evpkey = NULL;
static int load_object(const char * object_id, const char * object_file) static int load_object(const char * object_id, const char * object_file)
{ {
@ -211,7 +215,7 @@ static int load_cert(const char * cert_id, const char * cert_file,
} }
/* we pass length and 8 bits of flag to card-piv.c write_binary */ /* we pass length and 8 bits of flag to card-piv.c write_binary */
/* pass in its a cert and if needs compress */ /* pass in its a cert and if needs compress */
r = sc_write_binary(card, 0, der, derlen, (derlen<<8) | (compress<1) | 1); r = sc_write_binary(card, 0, der, derlen, (derlen<<8) | (compress<<4) | 1);
return r; return r;
@ -248,9 +252,10 @@ static int gen_key(const char * key_info)
u8 buf[2]; u8 buf[2];
size_t buflen = 2; size_t buflen = 2;
sc_cardctl_piv_genkey_info_t sc_cardctl_piv_genkey_info_t
keydata = {0, 0, 0, 0, NULL, 0}; keydata = {0, 0, 0, 0, NULL, 0, NULL, 0, NULL, 0};
unsigned long expl; unsigned long expl;
u8 expc[4]; u8 expc[4];
int nid;
sc_hex_to_bin(key_info, buf, &buflen); sc_hex_to_bin(key_info, buf, &buflen);
if (buflen != 2) { if (buflen != 2) {
@ -273,8 +278,14 @@ static int gen_key(const char * key_info)
case 0x05: keydata.key_bits = 3072; break; case 0x05: keydata.key_bits = 3072; break;
case 0x06: keydata.key_bits = 1024; break; case 0x06: keydata.key_bits = 1024; break;
case 0x07: keydata.key_bits = 2048; break; case 0x07: keydata.key_bits = 2048; break;
case 0x11: keydata.key_bits = 0;
nid = NID_X9_62_prime256v1; /* We only support one curve per algid */
break;
case 0x14: keydata.key_bits = 0;
nid = NID_secp384r1;
break;
default: default:
fprintf(stderr, "<keyref>:<algid> algid:05, 06, 07 for 3072, 1024, 2048\n"); fprintf(stderr, "<keyref>:<algid> algid=RSA - 05, 06, 07 for 3072, 1024, 2048;EC - 11, 14 for 256, 384\n");
return 2; return 2;
} }
@ -287,6 +298,8 @@ static int gen_key(const char * key_info)
return r; return r;
} }
evpkey = EVP_PKEY_new();
if (keydata.key_bits > 0) { /* RSA key */ if (keydata.key_bits > 0) { /* RSA key */
RSA * newkey = NULL; RSA * newkey = NULL;
@ -306,24 +319,48 @@ static int gen_key(const char * key_info)
if (verbose) if (verbose)
RSA_print_fp(stdout, newkey,0); RSA_print_fp(stdout, newkey,0);
if (bp) EVP_PKEY_assign_RSA(evpkey, newkey);
PEM_write_bio_RSAPublicKey(bp, newkey);
} else { /* EC key */
int i;
BIGNUM *x;
BIGNUM *y;
EC_KEY * eckey = NULL;
EC_GROUP * ecgroup = NULL;
EC_POINT * ecpoint = NULL;
ecgroup = EC_GROUP_new_by_curve_name(nid);
EC_GROUP_set_asn1_flag(ecgroup, OPENSSL_EC_NAMED_CURVE);
ecpoint = EC_POINT_new(ecgroup);
/* PIV returns 04||x||y and x and y are the same size */
i = (keydata.ecpoint_len - 1)/2;
x = BN_bin2bn(keydata.ecpoint + 1, i, x);
y = BN_bin2bn(keydata.ecpoint + 1 + i, i, y) ;
r = EC_POINT_set_affine_coordinates_GFp(ecgroup, ecpoint, x, y, NULL);
eckey = EC_KEY_new();
r = EC_KEY_set_group(eckey, ecgroup);
r = EC_KEY_set_public_key(eckey, ecpoint);
if (verbose)
EC_KEY_print_fp(stdout, eckey, 0);
EVP_PKEY_assign_EC_KEY(evpkey, eckey);
} else {
fprintf(stderr, "Unsuported key type\n");
r = SC_ERROR_UNKNOWN;
} }
if (bp)
r = i2d_PUBKEY_bio(bp, evpkey);
if (evpkey)
EVP_PKEY_free(evpkey);
return r; return r;
} }
static int send_apdu(void) static int send_apdu(void)
{ {
sc_apdu_t apdu; sc_apdu_t apdu;
u8 buf[SC_MAX_APDU_BUFFER_SIZE], sbuf[SC_MAX_APDU_BUFFER_SIZE], u8 buf[SC_MAX_APDU_BUFFER_SIZE+3], sbuf[SC_MAX_APDU_BUFFER_SIZE],
rbuf[SC_MAX_APDU_BUFFER_SIZE], *p; rbuf[SC_MAX_APDU_BUFFER_SIZE], *p;
size_t len, len0, r; size_t len, len0, r;
int c; int c;
@ -331,6 +368,11 @@ static int send_apdu(void)
for (c = 0; c < opt_apdu_count; c++) { for (c = 0; c < opt_apdu_count; c++) {
len0 = sizeof(buf); len0 = sizeof(buf);
sc_hex_to_bin(opt_apdus[c], buf, &len0); sc_hex_to_bin(opt_apdus[c], buf, &len0);
if (len0 > SC_MAX_APDU_BUFFER_SIZE+2) {
fprintf(stderr, "APDU too long, (must be at most %d bytes).\n",
SC_MAX_APDU_BUFFER_SIZE+2);
return 2;
}
if (len0 < 4) { if (len0 < 4) {
fprintf(stderr, "APDU too short (must be at least 4 bytes).\n"); fprintf(stderr, "APDU too short (must be at least 4 bytes).\n");
return 2; return 2;
@ -517,7 +559,8 @@ int main(int argc, char * const argv[])
return 1; return 1;
} }
if (verbose > 1) { /* Only change if not in opensc.conf */
if (verbose > 1 && ctx->debug == 0) {
ctx->debug = verbose; ctx->debug = verbose;
ctx->debug_file = stderr; ctx->debug_file = stderr;
} }
@ -585,5 +628,7 @@ end:
} }
if (ctx) if (ctx)
sc_release_context(ctx); sc_release_context(ctx);
ERR_print_errors_fp(stderr);
return err; return err;
} }

View File

@ -24,6 +24,7 @@
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/x509.h> #include <openssl/x509.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>
#include <openssl/ec.h>
#include <openssl/bn.h> #include <openssl/bn.h>
#include <openssl/err.h> #include <openssl/err.h>
#endif #endif
@ -1239,6 +1240,32 @@ static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
util_fatal("failed to open %s: %m", opt_output); util_fatal("failed to open %s: %m", opt_output);
} }
#if ENABLE_OPENSSL
/*
* PKCS11 implies the ECDSA sig is 2nLen,
* OpenSSL expects sequence of {integer, integer}
* so we will write it for OpenSSL if built with OpenSSL
*/
if (opt_mechanism == CKM_ECDSA) {
int nLen;
ECDSA_SIG * ecsig = NULL;
unsigned char *p = NULL;
int der_len;
nLen = sig_len/2;
ecsig = ECDSA_SIG_new();
ecsig->r = BN_bin2bn(buffer, nLen, ecsig->r);
ecsig->s = BN_bin2bn(buffer + nLen, nLen, ecsig->s);
der_len = i2d_ECDSA_SIG(ecsig, &p);
printf("Writing OpenSSL ECDSA_SIG\n");
r = write(fd, p, der_len);
free(p);
ECDSA_SIG_free(ecsig);
} else
#endif
r = write(fd, buffer, sig_len); r = write(fd, buffer, sig_len);
if (r < 0) if (r < 0)
util_fatal("Failed to write to %s: %m", opt_output); util_fatal("Failed to write to %s: %m", opt_output);
@ -1953,8 +1980,8 @@ ATTR_METHOD(VERIFY_RECOVER, CK_BBOOL);
#endif #endif
ATTR_METHOD(WRAP, CK_BBOOL); ATTR_METHOD(WRAP, CK_BBOOL);
ATTR_METHOD(UNWRAP, CK_BBOOL); ATTR_METHOD(UNWRAP, CK_BBOOL);
#if 0
ATTR_METHOD(DERIVE, CK_BBOOL); ATTR_METHOD(DERIVE, CK_BBOOL);
#if 0
ATTR_METHOD(EXTRACTABLE, CK_BBOOL); ATTR_METHOD(EXTRACTABLE, CK_BBOOL);
#endif #endif
ATTR_METHOD(KEY_TYPE, CK_KEY_TYPE); ATTR_METHOD(KEY_TYPE, CK_KEY_TYPE);
@ -1968,6 +1995,8 @@ VARATTR_METHOD(MODULUS, CK_BYTE);
VARATTR_METHOD(PUBLIC_EXPONENT, CK_BYTE); VARATTR_METHOD(PUBLIC_EXPONENT, CK_BYTE);
VARATTR_METHOD(VALUE, unsigned char); VARATTR_METHOD(VALUE, unsigned char);
VARATTR_METHOD(GOSTR3410_PARAMS, unsigned char); VARATTR_METHOD(GOSTR3410_PARAMS, unsigned char);
VARATTR_METHOD(EC_POINT, unsigned char);
VARATTR_METHOD(EC_PARAMS, unsigned char);
static void show_object(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj) static void show_object(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
{ {
@ -2022,6 +2051,51 @@ static void show_key(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int pub)
free(oid); free(oid);
} }
break; break;
case CKK_EC:
printf("; EC");
if (pub) {
unsigned char *bytes = NULL;
int ksize;
int n;
bytes = getEC_POINT(sess, obj, &size);
/*
* (We only support uncompressed for now)
* Uncompresed EC_POINT is DER OCTET STRING of "04||x||y"
* So a "256" bit key has x and y of 32 bytes each
* something like: "04 41 04||x||y"
* Do simple size calculation based on DER encoding
*/
if ((size - 2) <= 127)
ksize = (size - 3) * 4;
else if ((size - 3) <= 255)
ksize = (size - 4) * 4;
else
ksize = (size - 5) * 4;
printf(" EC_POINT %d bits\n", ksize);
if (bytes) {
if (size > 0) { /* Will print the point here */
printf(" EC_POINT: ");
for (n = 0; n < size; n++)
printf("%02x", bytes[n]);
printf("\n");
}
free(bytes);
}
bytes = NULL;
bytes = getEC_PARAMS(sess, obj, &size);
if (bytes){
if (size > 0) {
printf(" EC_PARAMS: ");
for (n = 0; n < size; n++)
printf("%02x", bytes[n]);
printf("\n");
}
free(bytes);
}
} else
printf("\n");
break;
default: default:
printf("; unknown key algorithm %lu\n", printf("; unknown key algorithm %lu\n",
(unsigned long) key_type); (unsigned long) key_type);
@ -2069,6 +2143,10 @@ static void show_key(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int pub)
printf("%sunwrap", sepa); printf("%sunwrap", sepa);
sepa = ", "; sepa = ", ";
} }
if (!pub && getDERIVE(sess, obj)) {
printf("%sderive", sepa);
sepa = ", ";
}
if (!*sepa) if (!*sepa)
printf("none"); printf("none");
printf("\n"); printf("\n");
@ -2261,6 +2339,10 @@ static int read_object(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
else if (obj==CK_INVALID_HANDLE) else if (obj==CK_INVALID_HANDLE)
util_fatal("object not found\n"); util_fatal("object not found\n");
/* TODO: -DEE should look at object class, and get appropriate values
* based on the object, and other attributes. For example EC keys do
* not have a VALUE But have a EC_POINT.
*/
value = getVALUE(session, obj, &len); value = getVALUE(session, obj, &len);
if (value == NULL) if (value == NULL)
util_fatal("get CKA_VALUE failed\n"); util_fatal("get CKA_VALUE failed\n");