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 {
PIV_OBJ_CCC = 0,
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_CHF,
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 key_ref; /* saved from set_security_env and */
int alg_id; /* used in decrypt, signature */
int key_size; /* RSA: modulus_bits EC: field_length in bits */
u8* w_buf; /* write_binary buffer */
size_t w_buf_len; /* length of w_buff */
piv_obj_cache_t obj_cache[PIV_OBJ_LAST_ENUM];
@ -173,6 +174,10 @@ static struct piv_aid piv_aids[] = {
{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:
* 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},
{ PIV_OBJ_CHUI, "Card Holder Unique Identifier",
"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",
"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",
@ -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},
{ 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},
{ PIV_OBJ_LAST_ENUM, "", "", 0, "", "", 0}
};
@ -490,9 +492,8 @@ static int piv_general_io(sc_card_t *card, int ins, int p1, int p2,
}
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
/*TODO may be 6c nn if reading only the length */
/* TODO look later at tag vs size read too */
/* TODO: - DEE look later at tag vs size read too */
if (r < 0) {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Card returned error ");
goto err;
@ -549,7 +550,7 @@ err:
/* Add the PIV-II operations */
/* 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,
sc_cardctl_piv_genkey_info_t *keydata)
@ -573,6 +574,10 @@ static int piv_generate_key(sc_card_t *card,
keydata->exponent = 0;
keydata->pubkey = NULL;
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;
outdata[0] = 0x80;
@ -582,7 +587,15 @@ static int piv_generate_key(sc_card_t *card,
case 0x05: keydata->key_bits = 3072; break;
case 0x06: keydata->key_bits = 1024; 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:
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;
memcpy (keydata->pubkey, tag, taglen);
}
} else {
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Requires OpenSSL");
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED);
} else { /* must be EC */
tag = sc_asn1_find_tag(card->ctx, cp, in_len, 0x86, &taglen);
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;
}
@ -867,186 +887,46 @@ static int piv_get_data(sc_card_t * card, int enumtag,
memcpy(p, piv_objects[enumtag].tag_value, 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;
/*
* the PIV card will only recover the public key during a generate
* key operation. If the piv-tool was used it would save this
* as an OpenSSL EVP_KEY PEM using the -o parameter
* we will look to see if there is a file then load it
* this is ugly, and maybe the pkcs15 cache would work
* but we only need it to get the OpenSSL req with engine to work.
* Each of the 4 keys with certs has its own file.
* Any other request for a pub key will return not found.
*/
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) {
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;
}
}
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) {
*buf_len = r;
} else if ( r == 0) {
r = SC_ERROR_FILE_NOT_FOUND;
goto err;
}
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;
} else {
goto err;
}
if (BIO_read_filename(bp, keyfilename) <= 0) {
BIO_free(bp);
r = SC_ERROR_FILE_NOT_FOUND;
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);
}
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) {
if (*buf == NULL ) {
r = SC_ERROR_OUT_OF_MEMORY;
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:
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 */
/* 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) {
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);
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 */
if (!rbuf || rbuf[0] == 0x00 || ((rbuf[0]&0xDF) == 0x53 && rbuf[1] == 0x00)) {
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;
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) {
r = piv_cache_internal_data(card, enumtag);
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,
sbuf, p - sbuf, NULL, NULL);
/* TODO add to cache */
if (sbuf)
free(sbuf);
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,
* and call the piv_put_data
* Note: the select file will have saved the object type for us
* Write is only used by piv-tool, so we will use flags:
* length << 8 | compress < 1 | cert
* to indicate we are writing a cert and if is compressed.
* if its not a cert its an object.
* Write is used by piv-tool, so we will use flags:
* length << 8 | 8bits:
* object xxxx0000
* 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
* 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 */
if ( flags & 1) {
switch (flags & 0x0f) {
case 1:
r = piv_write_certificate(card, priv->w_buf, priv->w_buf_len,
flags & 0x02);
} else {
r = piv_put_data(card, enumtag, priv->w_buf, priv->w_buf_len);
flags & 0x10);
break;
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 (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) {
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);
if (r < 0) {
sc_unlock(card);
@ -1996,6 +1890,7 @@ static int piv_set_security_env(sc_card_t *card,
int se_num)
{
piv_private_data_t * priv = PIV_DATA(card);
int r = 0;
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->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 */
else
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NO_CARD_SUPPORT);
} else if (env->algorithm == SC_ALGORITHM_EC) {
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];
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0);
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
}
@ -2065,7 +1976,8 @@ static int piv_validate_general_authentication(sc_card_t *card,
default:
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,
sbuf, p - sbuf, &rbuf, &rbuflen);
@ -2093,8 +2005,77 @@ static int piv_compute_signature(sc_card_t *card,
const u8 * data, size_t datalen,
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_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,
@ -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
* 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.
* TODO:
* TODO: -DEE
* 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.
*/
@ -2515,7 +2496,6 @@ static int piv_finish(sc_card_t *card)
}
free(priv);
}
/* TODO temp see piv_init */
return 0;
}
@ -2539,6 +2519,7 @@ static int piv_init(sc_card_t *card)
{
int r, i;
unsigned long flags;
unsigned long ext_flags;
piv_private_data_t *priv;
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, 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;
/*

View File

@ -755,6 +755,11 @@ typedef struct sc_cardctl_piv_genkey_info_st {
unsigned long exponent; /* RSA */
unsigned char * pubkey; /* 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;
#ifdef __cplusplus

View File

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

View File

@ -286,12 +286,13 @@ int sc_get_encoding_flags(sc_context_t *ctx,
else
*pflags |= SC_ALGORITHM_RSA_PAD_PKCS1;
} 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;
}
*sflags |= SC_ALGORITHM_RSA_RAW;
/* in case of raw RSA there is nothing to pad */
*sflags |= (caps & SC_ALGORITHM_RAW_MASK); /* adds in the one raw type */
*pflags = 0;
} else {
sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "unsupported algorithm");

View File

@ -235,6 +235,89 @@ asn1_free_pbes2_params(void *ptr)
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[] = {
#ifdef SC_ALGORITHM_SHA1
/* hmacWithSHA1 */
@ -303,6 +386,33 @@ static struct sc_asn1_pkcs15_algorithm_info algorithm_table[] = {
asn1_encode_pbes2_params,
asn1_free_pbes2_params },
#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 }
};
@ -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) {
id->algorithm = alg_info->id;
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;
}
r = alg_info->decode(ctx, &id->params, in, len, depth);
}
}

View File

@ -33,13 +33,13 @@
#include "internal.h"
#include "cardctl.h"
#include "asn1.h"
#include "pkcs15.h"
#define MANU_ID "piv_II "
int sc_pkcs15emu_piv_init_ex(sc_pkcs15_card_t *, sc_pkcs15emu_opt_t *);
typedef struct objdata_st {
const char *id;
const char *label;
@ -75,28 +75,32 @@ typedef struct pdata_st {
typedef struct pubdata_st {
const char *id;
const char *label;
int usage;
int usage_rsa;
int usage_ec;
const char *path;
int ref;
const char *auth_id;
int obj_flags;
const char *getenvname;
} pubdata;
typedef struct prdata_st {
const char *id;
const char *label;
int usage;
int usage_rsa;
int usage_ec;
const char *path;
int ref;
const char *auth_id;
int obj_flags;
int user_consent;
} prdata;
typedef struct common_key_info_st {
int cert_found;
int pubkey_found;
int key_alg;
unsigned int modulus_len;
unsigned int pubkey_len;
int not_present;
} common_key_info;
@ -111,6 +115,7 @@ static int piv_detect_card(sc_pkcs15_card_t *p15card)
return SC_SUCCESS;
}
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.
* the cert, pubkey and privkey are a set.
* 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] = {
{ "1", "PIV AUTH pubkey",
SC_PKCS15_PRKEY_USAGE_ENCRYPT |
SC_PKCS15_PRKEY_USAGE_WRAP |
SC_PKCS15_PRKEY_USAGE_VERIFY |
SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER,
"9A06", 0x9A, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT |
SC_PKCS15_PRKEY_USAGE_WRAP |
SC_PKCS15_PRKEY_USAGE_VERIFY |
SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER,
/*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY,
"9A06", 0x9A, "1", 0, "PIV_9A_KEY"},
{ "2", "SIGN pubkey",
SC_PKCS15_PRKEY_USAGE_ENCRYPT |
SC_PKCS15_PRKEY_USAGE_VERIFY |
SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
"9C06", 0x9C, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT |
SC_PKCS15_PRKEY_USAGE_VERIFY |
SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
/*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
"9C06", 0x9C, "1", 0, "PIV_9C_KEY"},
{ "3", "KEY MAN pubkey",
SC_PKCS15_PRKEY_USAGE_WRAP,
"9D06", 0x9D, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"9D06", 0x9D, "1", 0, "PIV_9D_KEY"},
{ "4", "CARD AUTH pubkey",
SC_PKCS15_PRKEY_USAGE_VERIFY |
SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER,
"9E06", 0x9E, "0", 0}, /* no pin, and avail in contactless */
/*RSA*/SC_PKCS15_PRKEY_USAGE_VERIFY |
SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER,
/*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY,
"9E06", 0x9E, "0", 0, "PIV_9E_KEY"}, /* no pin, and avail in contactless */
{ "5", "Retired KEY MAN 1",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8206", 0x82, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8206", 0x82, "1", 0, NULL},
{ "6", "Retired KEY MAN 2",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8306", 0x83, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8306", 0x83, "1", 0, NULL},
{ "7", "Retired KEY MAN 3",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8406", 0x84, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8406", 0x84, "1", 0, NULL},
{ "8", "Retired KEY MAN 4",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8506", 0x85, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8506", 0x85, "1", 0, NULL},
{ "9", "Retired KEY MAN 5",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8606", 0x86, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8606", 0x86, "1", 0, NULL},
{ "10", "Retired KEY MAN 6",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8706", 0x87, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8706", 0x87, "1", 0, NULL},
{ "11", "Retired KEY MAN 7",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8806", 0x88, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8806", 0x88, "1", 0, NULL},
{ "12", "Retired KEY MAN 8",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8906", 0x89, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8906", 0x89, "1", 0, NULL},
{ "13", "Retired KEY MAN 9",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8A06", 0x8A, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8A06", 0x8A, "1", 0, NULL},
{ "14", "Retired KEY MAN 10",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8B06", 0x8B, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8B06", 0x8B, "1", 0, NULL},
{ "15", "Retired KEY MAN 11",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8C06", 0x8C, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8C06", 0x8C, "1", 0, NULL},
{ "16", "Retired KEY MAN 12",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8D06", 0x8D, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8D06", 0x8D, "1", 0, NULL},
{ "17", "Retired KEY MAN 13",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8E06", 0x8E, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8E06", 0x8E, "1", 0, NULL},
{ "18", "Retired KEY MAN 14",
SC_PKCS15_PRKEY_USAGE_WRAP,
"8F06", 0x8F, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"8F06", 0x8F, "1", 0, NULL},
{ "19", "Retired KEY MAN 15",
SC_PKCS15_PRKEY_USAGE_WRAP,
"9006", 0x90, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"9006", 0x90, "1", 0, NULL},
{ "20", "Retired KEY MAN 16",
SC_PKCS15_PRKEY_USAGE_WRAP,
"9106", 0x91, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"9106", 0x91, "1", 0, NULL},
{ "21", "Retired KEY MAN 17",
SC_PKCS15_PRKEY_USAGE_WRAP,
"9206", 0x92, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"9206", 0x92, "1", 0, NULL},
{ "22", "Retired KEY MAN 18",
SC_PKCS15_PRKEY_USAGE_WRAP,
"9306", 0x93, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"9306", 0x93, "1", 0, NULL},
{ "23", "Retired KEY MAN 19",
SC_PKCS15_PRKEY_USAGE_WRAP,
"9406", 0x94, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"9406", 0x94, "1", 0, NULL},
{ "24", "Retired KEY MAN 20",
SC_PKCS15_PRKEY_USAGE_WRAP,
"9506", 0x95, "1", 0}
};
/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
/*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] = {
{ "1", "PIV AUTH key",
SC_PKCS15_PRKEY_USAGE_DECRYPT |
SC_PKCS15_PRKEY_USAGE_UNWRAP |
SC_PKCS15_PRKEY_USAGE_SIGN |
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
"", 0x9A, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT |
SC_PKCS15_PRKEY_USAGE_UNWRAP |
SC_PKCS15_PRKEY_USAGE_SIGN |
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
/*EC*/SC_PKCS15_PRKEY_USAGE_SIGN,
"", 0x9A, "1", SC_PKCS15_CO_FLAG_PRIVATE, 0},
{ "2", "SIGN key",
SC_PKCS15_PRKEY_USAGE_DECRYPT |
SC_PKCS15_PRKEY_USAGE_SIGN |
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
"", 0x9C, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT |
SC_PKCS15_PRKEY_USAGE_SIGN |
SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
/*EC*/SC_PKCS15_PRKEY_USAGE_SIGN |
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
"", 0x9C, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "3", "KEY MAN key",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x9D, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x9D, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "4", "CARD AUTH key",
SC_PKCS15_PRKEY_USAGE_SIGN |
/*RSA*/SC_PKCS15_PRKEY_USAGE_SIGN |
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",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x82, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x82, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "6", "Retired KEY MAN 2",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x83, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x83, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "7", "Retired KEY MAN 3",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x84, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x84, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "8", "Retired KEY MAN 4",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x85, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x85, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "9", "Retired KEY MAN 5",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x86, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x86, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "10", "Retired KEY MAN 6",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x87, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x87, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "11", "Retired KEY MAN 7",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x88, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x88, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "12", "Retired KEY MAN 8",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x89, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x89, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "13", "Retired KEY MAN 9",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x8A, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x8A, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "14", "Retired KEY MAN 10",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x8B, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x8B, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "15", "Retired KEY MAN 11",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x8C, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x8C, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "16", "Retired KEY MAN 12",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x8D, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x8D, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "17", "Retired KEY MAN 13",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x8E, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x8E, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "18", "Retired KEY MAN 14",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x8F, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x8F, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "19", "Retired KEY MAN 15",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x90, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x90, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "20", "Retired KEY MAN 16",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x91, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x91, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "21", "Retired KEY MAN 17",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x92, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x92, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "22", "Retired KEY MAN 18",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x93, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x93, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "23", "Retired KEY MAN 19",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x94, "1", 0},
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x94, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
{ "24", "Retired KEY MAN 20",
SC_PKCS15_PRKEY_USAGE_UNWRAP,
"", 0x95, "1", 0}
/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
"", 0x95, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1}
};
int r, i;
@ -484,6 +543,19 @@ static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
&obj_obj, &obj_info);
if (r < 0)
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].key_alg = -1;
ckis[i].pubkey_found = 0;
ckis[i].modulus_len = 0;
ckis[i].pubkey_len = 0;
if ((card->flags & 0x20) && (exposed_cert[i] == 0))
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 */
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);
continue;
}
/* TODO support EC keys */
ckis[i].key_alg = cert_out->key->algorithm;
if (cert_out->key->algorithm == SC_ALGORITHM_RSA) {
/* save modulus_len for pub and priv */
ckis[i].modulus_len = cert_out->key->u.rsa.modulus.len * 8;
} else {
/*TODO add the SC_ALGORITHM_EC */
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsuported key.algorithm %d", cert_out->key->algorithm);
ckis[i].modulus_len = 1024; /* set some value for now */
switch (cert_out->key->algorithm) {
case SC_ALGORITHM_RSA:
/* save pubkey_len for pub and priv */
ckis[i].pubkey_len = cert_out->key->u.rsa.modulus.len * 8;
break;
case SC_ALGORITHM_EC:
ckis[i].pubkey_len = cert_out->key->u.ec.field_length;
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);
@ -620,7 +694,7 @@ sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DEE Adding pin %d label=%s",i, label);
/* set public keys */
/* We may only need this during initialzation when genkey
* 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...");
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);
pubkey_info.usage = pubkeys[i].usage;
pubkey_info.native = 1;
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);
@ -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)
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);
/* TODO EC */
pubkey_obj.type = SC_PKCS15_TYPE_PUBKEY_RSA;
pubkey_obj.data = &pubkey_info;
r = sc_pkcs15_read_pubkey(p15card, &pubkey_obj, &p15_key);
pubkey_obj.data = NULL;
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL," READING PUB KEY r=%d",r);
if (r < 0 ) {
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 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.
*/
if (p15_key->algorithm == SC_ALGORITHM_RSA) {
/* save modulus_len in pub and priv */
ckis[i].key_alg = SC_ALGORITHM_RSA;
ckis[i].modulus_len = p15_key->u.rsa.modulus.len * 8;
ckis[i].pubkey_found = 1;
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"DEE look for env %s",
pubkeys[i].getenvname?pubkeys[i].getenvname:"NULL");
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;
}
}
/* 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_obj.emulated = p15_key;
p15_key = NULL;
}
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);
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 */
switch (ckis[i].key_alg) {
case SC_ALGORITHM_RSA:
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 */
sc_pkcs15_format_id(prkeys[i].id, &prkey_info.id);
prkey_info.usage = prkeys[i].usage;
prkey_info.native = 1;
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);
strncpy(prkey_obj.label, prkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
prkey_obj.flags = prkeys[i].obj_flags;
prkey_obj.user_consent = prkeys[i].user_consent;
if (prkeys[i].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)
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);
free(key->u.gostr3410.d.data);
break;
case SC_ALGORITHM_EC:
/* TODO: -DEE may not need much */
break;
}
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;
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 (!prkey->native)
return SC_ERROR_NOT_SUPPORTED;
@ -83,6 +86,8 @@ int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
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);
if (alg_info == NULL) {
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;
const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data;
u8 buf[512], *tmp;
size_t modlen = prkey->modulus_length / 8;
size_t modlen;
unsigned long pad_flags = 0, sec_flags = 0;
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 (!prkey->native)
return SC_ERROR_NOT_SUPPORTED;
@ -172,12 +184,41 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
return SC_ERROR_NOT_ALLOWED;
}
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;
switch (obj->type) {
/* FIXME -DEE GOSTR is misusing the sc_card_find_rsa_alg */
case SC_PKCS15_TYPE_PRKEY_GOSTR3410:
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 */
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
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) &&
((prkey->usage & USAGE_ANY_SIGN) &&
@ -241,13 +283,18 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
}
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) */
if (pad_flags != 0) {
size_t tmplen = sizeof(buf);
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");
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 */
if (inlen < modlen) {
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.flags = 0;
/* optional keyReference attribute (the default value is -1) */
if (prkey->key_reference >= 0) {
senv.key_ref_len = 1;
senv.key_ref[0] = prkey->key_reference & 0xFF;
senv.flags |= SC_SEC_ENV_KEY_REF_PRESENT;
}
senv.flags |= SC_SEC_ENV_ALG_PRESENT;
r = sc_lock(p15card->card);
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 __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_pubkey(obj) (__p15_type(obj) == SC_PKCS15_TYPE_PUBKEY_RSA || __p15_type(obj) == SC_PKCS15_TYPE_PUBKEY_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_CLASS_MASK) == SC_PKCS15_TYPE_PUBKEY)
#define is_cert(obj) (__p15_type(obj) == SC_PKCS15_TYPE_CERT_X509)
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 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_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 unlock_card(struct pkcs15_fw_data *);
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) &&
(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_EC) &&
(fw_data->objects[ii]->p15_object->type != SC_PKCS15_TYPE_PUBKEY_GOSTR3410)) {
ii++;
continue;
@ -858,28 +861,43 @@ static CK_RV pkcs15_create_tokens(struct sc_pkcs11_card *p11card)
rv = pkcs15_create_pkcs11_objects(fw_data,
SC_PKCS15_TYPE_PRKEY_RSA,
"private key",
"RSA 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_RSA,
"public key",
"RSA public key",
__pkcs15_create_pubkey_object);
if (rv < 0)
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,
SC_PKCS15_TYPE_PRKEY_GOSTR3410,
"private key",
"GOSTR3410 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_GOSTR3410,
"public key",
"GOSTR3410 public key",
__pkcs15_create_pubkey_object);
if (rv < 0)
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;
}
/* By default, we make the reader resource manager keep other
* processes from accessing the card while we're logged in.
* 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;
CK_KEY_TYPE key_type;
struct sc_pkcs15_prkey_rsa *rsa;
struct sc_pkcs15_prkey_ec *ec;
int rc, rv;
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);
if (rv != CKR_OK)
return rv;
if (key_type != CKK_RSA)
return CKR_ATTRIBUTE_VALUE_INVALID;
args.key.algorithm = SC_ALGORITHM_RSA;
rsa = &args.key.u.rsa;
switch (key_type) {
case CKK_RSA:
args.key.algorithm = SC_ALGORITHM_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;
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);
if (rv != CKR_OK)
return rv;
if (key_type != CKK_RSA)
return CKR_ATTRIBUTE_VALUE_INVALID;
args.key.algorithm = SC_ALGORITHM_RSA;
rsa = &args.key.u.rsa;
switch (key_type) {
case CKK_RSA:
args.key.algorithm = SC_ALGORITHM_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;
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
* 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 */
if (prkey->prv_pubkey)
if (prkey->prv_pubkey && prkey->prv_pubkey->pub_data)
key = prkey->prv_pubkey->pub_data;
else {
/* 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;
case CKA_KEY_TYPE:
check_attribute_buffer(attr, sizeof(CK_KEY_TYPE));
if (prkey->prv_p15obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410)
*(CK_KEY_TYPE*)attr->pValue = CKK_GOSTR3410;
else
*(CK_KEY_TYPE*)attr->pValue = CKK_RSA;
switch (prkey->prv_p15obj->type) {
case SC_PKCS15_TYPE_PRKEY_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;
case CKA_ID:
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 */
case CKA_MODULUS_BITS:
check_attribute_buffer(attr, sizeof(CK_ULONG));
*(CK_ULONG *) attr->pValue = prkey->prv_info->modulus_length;
return CKR_OK;
switch (prkey->prv_p15obj->type) {
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:
return get_public_exponent(key, attr);
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);
else
return CKR_ATTRIBUTE_TYPE_INVALID;
case CKA_EC_PARAMS:
return get_ec_pubkey_params(key, attr); /* get from pubkey for now */
default:
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:
flags = SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411;
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:
sc_debug(context, SC_LOG_DEBUG_NORMAL, "DEE - need EC for %d",pMechanism->mechanism);
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_VALUE:
case CKA_PUBLIC_EXPONENT:
case CKA_EC_PARAMS:
case CKA_EC_POINT:
if (pubkey->pub_data == NULL)
/* FIXME: check the return value? */
check_cert_data_read(fw_data, cert);
@ -2678,8 +2760,12 @@ static CK_RV pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session,
break;
case CKA_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)
*(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
*(CK_KEY_TYPE*)attr->pValue = CKK_RSA;
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);
case CKA_VALUE:
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);
memcpy(attr->pValue, pubkey->pub_data->data.value,
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);
else
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:
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;
}
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
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;
}
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
* 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_algorithm_info_t *alg_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;
unsigned int num;
int rc, flags = 0;
@ -3113,27 +3298,50 @@ static int register_mechanisms(struct sc_pkcs11_card *p11card)
#endif
mech_info.ulMinKeySize = ~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
* flags, based on the assumption that cards don't
* 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;
alg_info = card->algorithms;
while (num--) {
if (alg_info->algorithm == SC_ALGORITHM_RSA) {
if (alg_info->key_length < mech_info.ulMinKeySize)
mech_info.ulMinKeySize = alg_info->key_length;
if (alg_info->key_length > mech_info.ulMaxKeySize)
mech_info.ulMaxKeySize = alg_info->key_length;
flags |= alg_info->flags;
switch (alg_info->algorithm) {
case SC_ALGORITHM_RSA:
if (alg_info->key_length < mech_info.ulMinKeySize)
mech_info.ulMinKeySize = alg_info->key_length;
if (alg_info->key_length > mech_info.ulMaxKeySize)
mech_info.ulMaxKeySize = alg_info->key_length;
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++;
}
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
| SC_ALGORITHM_GOSTR3410_HASH_NONE
| 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)
{
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_KEY_TYPE key_type;
CK_ATTRIBUTE attr_key_type = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
CK_RV rv;
key = ((struct signature_data *) operation->priv_data)->key;
rv = key->ops->get_attribute(operation->session, key, &attr);
/* convert bits to bytes */
if (rv == CKR_OK)
*pLength = (*pLength + 7) / 8;
if (rv == CKR_OK) {
rv = key->ops->get_attribute(operation->session, key, &attr_key_type);
if (rv == CKR_OK && key_type == CKK_GOSTR3410)
*pLength *= 2;
/*
* EC (and maybe GOSTR) do not have CKA_MODULUS_BITS attribute.
* But other code in framework treats them as if they do.
* So should do switch(key_type)
* and then get what ever attributes are needed.
*/
rv = key->ops->get_attribute(operation->session, key, &attr_key_type);
if (rv == CKR_OK) {
switch(key_type) {
case CKK_RSA:
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;
@ -795,6 +815,9 @@ sc_pkcs11_new_fw_mechanism(CK_MECHANISM_TYPE mech,
if (pInfo->flags & CKF_UNWRAP) {
/* TODO */
}
if (pInfo->flags & CKF_DERIVE) {
/* TODO: -DEE CKM_ECDH1_COFACTOR_DERIVE for PIV */
}
if (pInfo->flags & CKF_DECRYPT) {
mt->decrypt_init = sc_pkcs11_decrypt_init;
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);
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 */
@ -985,6 +985,7 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, /* the session's handle */
CK_ULONG ulAttributeCount, /* # of attributes in template */
CK_OBJECT_HANDLE_PTR phKey)
{ /* gets handle of derived key */
/* TODO: -DEE ECDH with Cofactor on PIV is an example */
return CKR_FUNCTION_NOT_SUPPORTED;
}

View File

@ -31,11 +31,14 @@
#include <ctype.h>
#include <sys/stat.h>
#include <openssl/rsa.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/bn.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/obj_mac.h>
#include "libopensc/opensc.h"
#include "libopensc/cardctl.h"
@ -94,6 +97,7 @@ static const char *option_help[] = {
static sc_context_t *ctx = NULL;
static sc_card_t *card = NULL;
static BIO * bp = NULL;
static EVP_PKEY * evpkey = NULL;
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 */
/* 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;
@ -248,9 +252,10 @@ static int gen_key(const char * key_info)
u8 buf[2];
size_t buflen = 2;
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;
u8 expc[4];
int nid;
sc_hex_to_bin(key_info, buf, &buflen);
if (buflen != 2) {
@ -273,8 +278,14 @@ static int gen_key(const char * key_info)
case 0x05: keydata.key_bits = 3072; break;
case 0x06: keydata.key_bits = 1024; 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:
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;
}
@ -287,6 +298,8 @@ static int gen_key(const char * key_info)
return r;
}
evpkey = EVP_PKEY_new();
if (keydata.key_bits > 0) { /* RSA key */
RSA * newkey = NULL;
@ -306,24 +319,48 @@ static int gen_key(const char * key_info)
if (verbose)
RSA_print_fp(stdout, newkey,0);
if (bp)
PEM_write_bio_RSAPublicKey(bp, newkey);
EVP_PKEY_assign_RSA(evpkey, 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;
}
static int send_apdu(void)
{
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;
size_t len, len0, r;
int c;
@ -331,6 +368,11 @@ static int send_apdu(void)
for (c = 0; c < opt_apdu_count; c++) {
len0 = sizeof(buf);
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) {
fprintf(stderr, "APDU too short (must be at least 4 bytes).\n");
return 2;
@ -517,7 +559,8 @@ int main(int argc, char * const argv[])
return 1;
}
if (verbose > 1) {
/* Only change if not in opensc.conf */
if (verbose > 1 && ctx->debug == 0) {
ctx->debug = verbose;
ctx->debug_file = stderr;
}
@ -585,5 +628,7 @@ end:
}
if (ctx)
sc_release_context(ctx);
ERR_print_errors_fp(stderr);
return err;
}

View File

@ -24,6 +24,7 @@
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/rsa.h>
#include <openssl/ec.h>
#include <openssl/bn.h>
#include <openssl/err.h>
#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);
}
#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);
if (r < 0)
util_fatal("Failed to write to %s: %m", opt_output);
@ -1953,8 +1980,8 @@ ATTR_METHOD(VERIFY_RECOVER, CK_BBOOL);
#endif
ATTR_METHOD(WRAP, CK_BBOOL);
ATTR_METHOD(UNWRAP, CK_BBOOL);
#if 0
ATTR_METHOD(DERIVE, CK_BBOOL);
#if 0
ATTR_METHOD(EXTRACTABLE, CK_BBOOL);
#endif
ATTR_METHOD(KEY_TYPE, CK_KEY_TYPE);
@ -1968,6 +1995,8 @@ VARATTR_METHOD(MODULUS, CK_BYTE);
VARATTR_METHOD(PUBLIC_EXPONENT, CK_BYTE);
VARATTR_METHOD(VALUE, 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)
{
@ -2022,6 +2051,51 @@ static void show_key(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj, int pub)
free(oid);
}
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:
printf("; unknown key algorithm %lu\n",
(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);
sepa = ", ";
}
if (!pub && getDERIVE(sess, obj)) {
printf("%sderive", sepa);
sepa = ", ";
}
if (!*sepa)
printf("none");
printf("\n");
@ -2261,6 +2339,10 @@ static int read_object(CK_SLOT_ID slot, CK_SESSION_HANDLE session)
else if (obj==CK_INVALID_HANDLE)
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);
if (value == NULL)
util_fatal("get CKA_VALUE failed\n");