diff --git a/src/libopensc/card-piv.c b/src/libopensc/card-piv.c index 60f5bd8f..436ce701 100644 --- a/src/libopensc/card-piv.c +++ b/src/libopensc/card-piv.c @@ -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; /* diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h index ad4f4d7a..9797a95a 100644 --- a/src/libopensc/cardctl.h +++ b/src/libopensc/cardctl.h @@ -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 diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index b75b60ec..0708a7fb 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -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 diff --git a/src/libopensc/padding.c b/src/libopensc/padding.c index eac32a78..0b29f0d0 100644 --- a/src/libopensc/padding.c +++ b/src/libopensc/padding.c @@ -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"); diff --git a/src/libopensc/pkcs15-algo.c b/src/libopensc/pkcs15-algo.c index 48758f77..94d0ab29 100644 --- a/src/libopensc/pkcs15-algo.c +++ b/src/libopensc/pkcs15-algo.c @@ -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); } } diff --git a/src/libopensc/pkcs15-piv.c b/src/libopensc/pkcs15-piv.c index caef56dd..0e3adf0f 100644 --- a/src/libopensc/pkcs15-piv.c +++ b/src/libopensc/pkcs15-piv.c @@ -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); } diff --git a/src/libopensc/pkcs15-prkey.c b/src/libopensc/pkcs15-prkey.c index 467b3e4f..19edc674 100644 --- a/src/libopensc/pkcs15-prkey.c +++ b/src/libopensc/pkcs15-prkey.c @@ -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)); } diff --git a/src/libopensc/pkcs15-sec.c b/src/libopensc/pkcs15-sec.c index db3b2300..19411267 100644 --- a/src/libopensc/pkcs15-sec.c +++ b/src/libopensc/pkcs15-sec.c @@ -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"); diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index 2d136098..052d5f41 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -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)) { diff --git a/src/pkcs11/mechanism.c b/src/pkcs11/mechanism.c index 8ffe1141..76da437e 100644 --- a/src/pkcs11/mechanism.c +++ b/src/pkcs11/mechanism.c @@ -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; diff --git a/src/pkcs11/pkcs11-object.c b/src/pkcs11/pkcs11-object.c index 949da1d3..a1b478f3 100644 --- a/src/pkcs11/pkcs11-object.c +++ b/src/pkcs11/pkcs11-object.c @@ -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; } diff --git a/src/tools/piv-tool.c b/src/tools/piv-tool.c index 9cc84048..9023a7bb 100644 --- a/src/tools/piv-tool.c +++ b/src/tools/piv-tool.c @@ -31,11 +31,14 @@ #include #include #include +#include +#include #include #include #include #include #include +#include #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, ": algid:05, 06, 07 for 3072, 1024, 2048\n"); + fprintf(stderr, ": 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; } diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c index 1e6ba398..dd23e8c7 100644 --- a/src/tools/pkcs11-tool.c +++ b/src/tools/pkcs11-tool.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #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");