diff --git a/doc/tools/pkcs15-init.1.xml b/doc/tools/pkcs15-init.1.xml index 5ddaad56a3..9c5018297c 100644 --- a/doc/tools/pkcs15-init.1.xml +++ b/doc/tools/pkcs15-init.1.xml @@ -139,7 +139,13 @@ where keyspec describes the algorithm and the parameters of the key to be created. For example, rsa:2048 generates a RSA key with 2048-bit modulus. If you are generating an EC key, the curve designation must - be specified, for example ec:prime256v1. For symmetric key, + be specified, for example ec:prime256v1. + The following curves do not need parameters: + Edwards 25519 curves use one of these equivalent names: Ed25519(preferred), ed25519 or edwards25519 + and for the 448 curve use: Ed448. + For Montgomery 25519 curves use one of these equivalent names: X25519(preferred), cv25519 or curve25519 + and for the 448 curve use: X448. + For symmetric key, the length of key is specified in bytes, for example AES:32 or DES3:24. diff --git a/doc/tools/tools.html b/doc/tools/tools.html index 4294dc16fd..173469fdc2 100644 --- a/doc/tools/tools.html +++ b/doc/tools/tools.html @@ -1989,7 +1989,13 @@ where keyspec describes the algorithm and the parameters of the key to be created. For example, rsa:2048 generates a RSA key with 2048-bit modulus. If you are generating an EC key, the curve designation must - be specified, for example ec:prime256v1. For symmetric key, + be specified, for example ec:prime256v1. + The following curves do not need parameters: + Edwards 25519 curves use one of these equivalent names: Ed25519(preferred), ed25519 or edwards25519 + and for the 448 curve use: Ed448. + For Montgomery 25519 curves use one of these equivalent names: X25519(preferred), cv25519 or curve25519 + and for the 448 curve use: X448. + For symmetric key, the length of key is specified in bytes, for example AES:32 or DES3:24.

diff --git a/src/libopensc/card-openpgp.c b/src/libopensc/card-openpgp.c index 7df722cdb7..0b903ca124 100644 --- a/src/libopensc/card-openpgp.c +++ b/src/libopensc/card-openpgp.c @@ -86,34 +86,49 @@ static struct sc_card_driver pgp_drv = { NULL, 0, NULL }; - -static pgp_ec_curves_t ec_curves_openpgp34[] = { +// clang-format off +static pgp_ec_curves_t ec_curves_openpgp34[] = { /* OpenPGP 3.4+ Ed25519 and Curve25519 */ - {{{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, 256}, /* curve25519 for encryption => CKK_EC_MONTGOMERY */ - {{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, 256}, /* ed25519 for signatures => CKK_EC_EDWARDS */ + {{{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, 255, SC_ALGORITHM_XEDDSA}, /* curve25519 for encryption => CKK_EC_MONTGOMERY */ + {{{1, 3, 101, 110, -1}}, 255, SC_ALGORITHM_XEDDSA}, /* RFC8410 OID equivalent to curve25519 */ + {{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, 255, SC_ALGORITHM_EDDSA}, /* ed25519 for signatures => CKK_EC_EDWARDS */ + {{{1, 3, 101, 112, -1}}, 255, SC_ALGORITHM_EDDSA}, /* RFC8410 OID equivalent to ed25519 */ + /* v3.0+ supports: [RFC 4880 & 6637] 0x12 = ECDH, 0x13 = ECDSA */ - {{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256}, /* ansiX9p256r1 */ - {{{1, 3, 132, 0, 34, -1}}, 384}, /* ansiX9p384r1 */ - {{{1, 3, 132, 0, 35, -1}}, 521}, /* ansiX9p521r1 */ - {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 7, -1}}, 256}, /* brainpoolP256r1 */ - {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 11, -1}}, 384}, /* brainpoolP384r1 */ - {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 13, -1}}, 512}, /* brainpoolP512r1 */ - {{{-1}}, 0} /* This entry must not be touched. */ + {{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256, SC_ALGORITHM_EC}, /* ansiX9p256r1 */ + {{{1, 3, 132, 0, 34, -1}}, 384, SC_ALGORITHM_EC}, /* ansiX9p384r1 */ + {{{1, 3, 132, 0, 35, -1}}, 521, SC_ALGORITHM_EC}, /* ansiX9p521r1 */ + {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 7, -1}}, 256, SC_ALGORITHM_EC}, /* brainpoolP256r1 */ + {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 11, -1}}, 384, SC_ALGORITHM_EC}, /* brainpoolP384r1 */ + {{{1, 3, 36, 3, 3, 2, 8, 1, 1, 13, -1}}, 512, SC_ALGORITHM_EC}, /* brainpoolP512r1 */ + {{{-1}}, 0, 0 } /* This entry must not be touched. */ }; -static pgp_ec_curves_t *ec_curves_openpgp = ec_curves_openpgp34 + 2; +#ifdef ENABLE_OPENSSL +static pgp_ec_curves_alt_t ec_curves_alt[] = { + {{{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, {{1, 3, 101, 110, -1}}, 255}, /* curve25519 CKK_EC_MONTGOMERY X25519 */ + {{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, {{1, 3, 101, 112, -1}}, 255}, /* ed25519 CKK_EC_EDWARDS Ed25519 */ + {{{-1}}, {{-1}}, 0 } /* This entry must not be touched. */ +}; + +#endif /* ENABLE_OPENSSL */ + +static pgp_ec_curves_t *ec_curves_openpgp = ec_curves_openpgp34 + 4; struct sc_object_id curve25519_oid = {{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}; +struct sc_object_id X25519_oid = {{1, 3, 101, 110, -1}}; /* need to check for RFC8410 version? */ /* Gnuk supports NIST, SECG and Curve25519 since version 1.2 */ -static pgp_ec_curves_t ec_curves_gnuk[] = { - {{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256}, /* ansiX9p256r1 */ - {{{1, 3, 132, 0, 10, -1}}, 256}, /* secp256k1 */ - {{{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, 256}, /* curve25519 for encryption => CKK_EC_MONTGOMERY */ - {{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, 256}, /* ed25519 for signatures => CKK_EC_EDWARDS */ - {{{-1}}, 0} /* This entry must not be touched. */ +static pgp_ec_curves_t ec_curves_gnuk[] = { + {{{1, 2, 840, 10045, 3, 1, 7, -1}}, 256, SC_ALGORITHM_EC}, /* ansiX9p256r1 */ + {{{1, 3, 132, 0, 10, -1}}, 256, SC_ALGORITHM_EC}, /* secp256k1 */ + {{{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1, -1}}, 255, SC_ALGORITHM_XEDDSA}, /* curve25519 for encryption => CKK_EC_MONTGOMERY */ + {{{1, 3, 101, 110, -1}}, 255, SC_ALGORITHM_XEDDSA}, /* RFC8410 OID equivalent to curve25519 */ + {{{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, 255, SC_ALGORITHM_EDDSA}, /* ed25519 for signatures => CKK_EC_EDWARDS */ + {{{1, 3, 101, 112, -1}}, 255, SC_ALGORITHM_EDDSA}, /* RFC8410 OID equivalent to ed25519 */ + {{{-1}}, 0, 0} /* This entry must not be touched. */ }; - +// clang-format on /* * The OpenPGP card doesn't have a file system, instead everything @@ -516,9 +531,11 @@ pgp_init(sc_card_t *card) /* if algorithm attributes can be changed, * add supported algorithms based on specification for pkcs15-init */ - if ((priv->ext_caps & EXT_CAP_ALG_ATTR_CHANGEABLE) && - (strcmp(card->ctx->app_name, "pkcs15-init") == 0)) { + /* pkcs11 or other utilities may need all the algs registered */ + if ((priv->ext_caps & EXT_CAP_ALG_ATTR_CHANGEABLE) + /* && (strcmp(card->ctx->app_name, "pkcs15-init") == 0) */) { unsigned long flags_rsa, flags_ecc, ext_flags; + unsigned long flags_eddsa, flags_xeddsa; /* OpenPGP card spec 1.1 & 2.x, section 7.2.9 & 7.2.10 / v3.x section 7.2.11 & 7.2.12 */ flags_rsa = SC_ALGORITHM_RSA_PAD_PKCS1| @@ -530,6 +547,12 @@ pgp_init(sc_card_t *card) SC_ALGORITHM_ONBOARD_KEY_GEN; ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE; + flags_eddsa = SC_ALGORITHM_EDDSA_RAW | + SC_ALGORITHM_ONBOARD_KEY_GEN; + /* xeddsa may allow signing at some time */ + flags_xeddsa = SC_ALGORITHM_ECDH_CDH_RAW | + SC_ALGORITHM_ONBOARD_KEY_GEN; + switch (card->type) { case SC_CARD_TYPE_OPENPGP_V3: /* RSA 1024 was removed for v3+ */ @@ -540,8 +563,15 @@ pgp_init(sc_card_t *card) _sc_card_add_rsa_alg(card, 2048, flags_rsa, 0); for (i=0; priv->ec_curves[i].oid.value[0] >= 0; i++) { - _sc_card_add_ec_alg(card, priv->ec_curves[i].size, - flags_ecc, ext_flags, &priv->ec_curves[i].oid); + if (priv->ec_curves[i].key_type == SC_ALGORITHM_EC) + _sc_card_add_ec_alg(card, priv->ec_curves[i].size, + flags_ecc, ext_flags, &priv->ec_curves[i].oid); + else if (priv->ec_curves[i].key_type == SC_ALGORITHM_EDDSA) + _sc_card_add_eddsa_alg(card, priv->ec_curves[i].size, + flags_eddsa, ext_flags, &priv->ec_curves[i].oid); + else + _sc_card_add_xeddsa_alg(card, priv->ec_curves[i].size, + flags_xeddsa, ext_flags, &priv->ec_curves[i].oid); } break; case SC_CARD_TYPE_OPENPGP_V2: @@ -680,14 +710,15 @@ pgp_parse_algo_attr_blob(sc_card_t *card, const pgp_blob_t *blob, int _pgp_handle_curve25519(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t key_info, unsigned int do_num) { - if (!sc_compare_oid(&key_info.u.ec.oid, &curve25519_oid)) + if (!sc_compare_oid(&key_info.u.ec.oid, &curve25519_oid) && + !sc_compare_oid(&key_info.u.ec.oid, &X25519_oid)) return 0; /* CKM_XEDDSA supports both Sign and Derive, but * OpenPGP card supports only derivation using these * keys as far as I know */ _sc_card_add_xeddsa_alg(card, key_info.u.ec.key_length, - SC_ALGORITHM_ECDH_CDH_RAW, 0, &key_info.u.ec.oid); + SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_ONBOARD_KEY_GEN, 0, &key_info.u.ec.oid); sc_log(card->ctx, "DO %uX: Added XEDDSA algorithm (%d), mod_len = %zu", do_num, SC_ALGORITHM_XEDDSA, key_info.u.ec.key_length); return 1; @@ -739,7 +770,7 @@ int _pgp_add_algo(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t key_info, un if (_pgp_handle_curve25519(card, key_info, do_num)) break; _sc_card_add_eddsa_alg(card, key_info.u.ec.key_length, - SC_ALGORITHM_EDDSA_RAW, 0, &key_info.u.ec.oid); + SC_ALGORITHM_EDDSA_RAW | SC_ALGORITHM_ONBOARD_KEY_GEN, 0, &key_info.u.ec.oid); sc_log(card->ctx, "DO %uX: Added EDDSA algorithm (%d), mod_len = %zu" , do_num, key_info.algorithm, key_info.u.ec.key_length); @@ -1709,8 +1740,8 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len) /* In EDDSA key case we do not have to care about OIDs * as we support only one for now */ p15pubkey.algorithm = SC_ALGORITHM_EDDSA; - p15pubkey.u.eddsa.pubkey.value = pubkey_blob->data; - p15pubkey.u.eddsa.pubkey.len = pubkey_blob->len; + p15pubkey.u.ec.ecpointQ.value = pubkey_blob->data; + p15pubkey.u.ec.ecpointQ.len = pubkey_blob->len; /* PKCS#11 3.0: 2.3.5 Edwards EC public keys only support the use * of the curveName selection to specify a curve name as defined * in [RFC 8032] */ @@ -1720,8 +1751,8 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len) /* This yields either EC(DSA) key or EC_MONTGOMERY (curve25519) key */ if (sc_compare_oid(&key_info.u.ec.oid, &curve25519_oid)) { p15pubkey.algorithm = SC_ALGORITHM_XEDDSA; - p15pubkey.u.eddsa.pubkey.value = pubkey_blob->data; - p15pubkey.u.eddsa.pubkey.len = pubkey_blob->len; + p15pubkey.u.ec.ecpointQ.value = pubkey_blob->data; + p15pubkey.u.ec.ecpointQ.len = pubkey_blob->len; /* PKCS#11 3.0 2.3.7 Montgomery EC public keys only support * the use of the curveName selection to specify a curve * name as defined in [RFC7748] */ @@ -1762,14 +1793,12 @@ pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len) p15pubkey.u.rsa.modulus.len = 0; p15pubkey.u.rsa.exponent.data = NULL; p15pubkey.u.rsa.exponent.len = 0; - } else if (p15pubkey.algorithm == SC_ALGORITHM_EC) { + } else if (p15pubkey.algorithm == SC_ALGORITHM_EC || + p15pubkey.algorithm == SC_ALGORITHM_EDDSA || + p15pubkey.algorithm == SC_ALGORITHM_XEDDSA) { p15pubkey.u.ec.ecpointQ.value = NULL; p15pubkey.u.ec.ecpointQ.len = 0; /* p15pubkey.u.ec.params.der and named_curve will be freed by sc_pkcs15_erase_pubkey */ - } else if (p15pubkey.algorithm == SC_ALGORITHM_EDDSA - || p15pubkey.algorithm == SC_ALGORITHM_XEDDSA) { - p15pubkey.u.eddsa.pubkey.value = NULL; - p15pubkey.u.eddsa.pubkey.len = 0; } sc_pkcs15_erase_pubkey(&p15pubkey); @@ -2502,7 +2531,7 @@ static int pgp_update_new_algo_attr(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info) { struct pgp_priv_data *priv = DRVDATA(card); - pgp_blob_t *algo_blob; + pgp_blob_t *algo_blob = NULL; const unsigned int tag = 0x00C0 | key_info->key_id; u8 *data; size_t data_len; @@ -2519,16 +2548,42 @@ pgp_update_new_algo_attr(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_ if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH || key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA || key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA){ - data_len = key_info->u.ec.oid_len+1; + /* Note OpenPGP or current cards do not support 448 size keys yet */ + unsigned char *aoid = NULL; /* ASN1 */ + size_t aoid_len; + struct sc_object_id *scoid = NULL; + + scoid = &key_info->u.ec.oid; + /* + * Current OpenPGP cards use pre RFC8410 OIDs for ECDH and EdDSA + * so convert to older versions of the OIDs. + */ + for (i = 0; ec_curves_alt[i].size > 0; i++) { + if (sc_compare_oid(scoid, &ec_curves_alt[i].oid_alt)) { + scoid = &ec_curves_alt[i].oid; + break; + } + } + + r = sc_encode_oid(card->ctx, scoid, &aoid, &aoid_len); + LOG_TEST_RET(card->ctx, r, "invalid ec oid"); + if (aoid == NULL || aoid_len < 3 || aoid[1] > 127) { + free(aoid); + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); + } + + data_len = aoid_len + 1 - 2; /* +1 for algorithm -2 drop 06 len */ data = malloc(data_len); - if (!data) + if (!data) { + free(aoid); LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY); + } data[0] = key_info->algorithm; - /* oid.value is type int, therefore we need to loop over the values */ - for (i=0; i < key_info->u.ec.oid_len; i++){ - data[i+1] = key_info->u.ec.oid.value[i]; - } + for (i = 0; i < aoid_len - 2; i++) + data[i + 1] = aoid[i + 2]; + + free(aoid); } /* RSA */ @@ -2557,10 +2612,9 @@ pgp_update_new_algo_attr(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_ LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); } - pgp_set_blob(algo_blob, data, data_len); + r = pgp_put_data(card, tag, data, data_len); + /* Note: pgp_put_data calls pgp_set_blob */ free(data); - r = pgp_put_data(card, tag, algo_blob->data, data_len); - /* Note: Don't use pgp_set_blob to set data, because it won't touch the real DO */ LOG_TEST_RET(card->ctx, r, "Cannot set new algorithm attributes"); } else { sc_cardctl_openpgp_keygen_info_t old_key_info; @@ -2665,8 +2719,9 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime, } /* ECC */ - else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH - || key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA) { + else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH || /* also includes XEDDSA */ + key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA || + key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA) { if (key_info->u.ec.ecpoint == NULL || (key_info->u.ec.ecpoint_len) == 0) { sc_log(card->ctx, "Error: ecpoint required!"); LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); @@ -2674,12 +2729,12 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime, /* https://tools.ietf.org/html/rfc4880 page 41, 72 * and https://tools.ietf.org/html/rfc6637 section 9 (page 8 and 9) */ - pk_packet_len = 1 /* version number */ - + 4 /* creation time */ - + 1 /* algorithm */ - + 1 /* oid len */ - + (key_info->u.ec.oid_len) /* oid */ - + (key_info->u.ec.ecpoint_len); /* ecpoint */ + pk_packet_len = 1 /* version number */ + + 4 /* creation time */ + + 1 /* algorithm */ + + 1 /* oid len */ + + (key_info->u.ec.oid_len) /* oid */ + + BYTES4BITS(key_info->u.ec.ecpoint_len); /* ecpoint */ /* KDF parameters for ECDH */ if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH) { @@ -2689,8 +2744,7 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime, + 1 /* KDF algo */ + 1; /* KEK algo */ } - } - else + } else LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); sc_log(card->ctx, "pk_packet_len is %"SC_FORMAT_LEN_SIZE_T"u", pk_packet_len); @@ -2729,9 +2783,9 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime, memcpy(p, key_info->u.rsa.exponent, bytes_length); } /* ECC */ - else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH - || key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA - || key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA) { + else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH || /* includes XEDDSA */ + key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA || + key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA) { /* Algorithm ID, see https://tools.ietf.org/html/rfc6637#section-5 */ *p = key_info->algorithm + 6; p += 1; @@ -2739,13 +2793,13 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime, p += 1; memcpy(p, key_info->u.ec.oid.value, key_info->u.ec.oid_len); p += key_info->u.ec.oid_len; - memcpy(p, key_info->u.ec.ecpoint, key_info->u.ec.ecpoint_len); + memcpy(p, key_info->u.ec.ecpoint, BYTES4BITS(key_info->u.ec.ecpoint_len)); /* KDF parameters for ECDH */ if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH) { /* https://tools.ietf.org/html/rfc6637#section-8 * This is copied from GnuPG's ecdh_params() function in app-openpgp.c */ - p += key_info->u.ec.ecpoint_len; + p += BYTES4BITS(key_info->u.ec.ecpoint_len); *p = 0x03; /* number of bytes following */ p += 1; *p = 0x01; /* version of this format */ @@ -2763,8 +2817,7 @@ pgp_calculate_and_store_fingerprint(sc_card_t *card, time_t ctime, *(p+1) = 0x09; /* KEK algo */ } } - } - else + } else LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); p = NULL; @@ -2847,14 +2900,15 @@ pgp_update_pubkey_blob(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_in p15pubkey.u.rsa.exponent.len = BYTES4BITS(key_info->u.rsa.exponent_len); } /* ECC */ - else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH - || key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA){ + /* TODO FIXME? */ + else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH || /* includes XEDDSA */ + key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA || + key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA) { memset(&p15pubkey, 0, sizeof(p15pubkey)); - p15pubkey.algorithm = SC_ALGORITHM_EC; + p15pubkey.algorithm = key_info->key_type; p15pubkey.u.ec.ecpointQ.value = key_info->u.ec.ecpoint; p15pubkey.u.ec.ecpointQ.len = key_info->u.ec.ecpoint_len; - } - else + } else LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); r = sc_pkcs15_encode_pubkey(card->ctx, &p15pubkey, &data, &len); @@ -2882,7 +2936,8 @@ pgp_parse_and_set_pubkey_output(sc_card_t *card, u8* data, size_t data_len, /* store creation time */ r = pgp_store_creationtime(card, key_info->key_id, &ctime); - LOG_TEST_RET(card->ctx, r, "Cannot store creation time"); + /* TODO for now with GNUK at least, log but do not return error */ + sc_log(card->ctx, "Cannot store creation time"); /* parse response. Ref: pgp_enumerate_blob() */ while (data_len > (size_t) (in - data)) { @@ -2934,16 +2989,30 @@ pgp_parse_and_set_pubkey_output(sc_card_t *card, u8* data, size_t data_len, /* ECC public key */ else if (tag == 0x0086) { /* set the output data */ - /* len is ecpoint length + format byte - * see section 7.2.14 of 3.3.1 specs */ - if ((key_info->u.ec.ecpoint_len) != (len - 1) - || key_info->u.ec.ecpoint == NULL) { - free(key_info->u.ec.ecpoint); - key_info->u.ec.ecpoint = malloc(len); - if (key_info->u.ec.ecpoint == NULL) - LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY); + /* EC is in 04||x||y format + * (field_length + 7)/8 * 2 + 1 in bytes + * len is ecpoint length + format byte + * see section 7.2.14 of 3.3.1 specs + * EDDSA and XEDDSA have no format byte and one number + * (field_length + 7)/8 in bytes + */ + /* GNUK returns 04|x|y */ + + /* TODO check len is reasonable */ + key_info->u.ec.ecpoint = malloc(len); + if (key_info->u.ec.ecpoint == NULL) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ENOUGH_MEMORY); + + switch (key_info->key_type) { + case SC_ALGORITHM_EC: + case SC_ALGORITHM_EDDSA: + case SC_ALGORITHM_XEDDSA: + memcpy(key_info->u.ec.ecpoint, part, len); + key_info->u.ec.ecpoint_len = len; + break; + default: + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); } - memcpy(key_info->u.ec.ecpoint, part + 1, len - 1); } /* go to next part to parse */ @@ -2958,6 +3027,7 @@ pgp_parse_and_set_pubkey_output(sc_card_t *card, u8* data, size_t data_len, /* update pubkey blobs (B601, B801, A401) */ sc_log(card->ctx, "Update blobs holding pubkey info."); r = pgp_update_pubkey_blob(card, key_info); + LOG_FUNC_RETURN(card->ctx, r); } @@ -2975,8 +3045,9 @@ pgp_update_card_algorithms(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *ke LOG_FUNC_CALLED(card->ctx); /* protect incompatible cards against non-RSA */ - if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA - && priv->bcd_version < OPENPGP_CARD_3_0) + if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA && + priv->bcd_version < OPENPGP_CARD_3_0 && + card->type != SC_CARD_TYPE_OPENPGP_GNUK) LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); if (id > card->algorithm_count) { @@ -2993,12 +3064,13 @@ pgp_update_card_algorithms(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *ke algo->algorithm = SC_ALGORITHM_RSA; algo->key_length = (unsigned int)key_info->u.rsa.modulus_len; } - else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH - || key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA) { + /* TODO FIXME */ + else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH || /* includes XEDDSA */ + key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA || + key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA) { algo->algorithm = SC_ALGORITHM_EC; algo->key_length = (unsigned int)((key_info->u.ec.ecpoint_len)); - } - else + } else LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); @@ -3023,11 +3095,9 @@ pgp_gen_key(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t *key_info) LOG_FUNC_CALLED(card->ctx); /* protect incompatible cards against non-RSA */ - if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA - && priv->bcd_version < OPENPGP_CARD_3_0) - LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); - if (key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA - && card->type != SC_CARD_TYPE_OPENPGP_GNUK) + if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA && + priv->bcd_version < OPENPGP_CARD_3_0 && + card->type != SC_CARD_TYPE_OPENPGP_GNUK) LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); /* set Control Reference Template for key */ @@ -3243,12 +3313,12 @@ pgp_build_extended_header_list(sc_card_t *card, sc_cardctl_openpgp_keystore_info componenttags[3] = 0x97; componentnames[3] = "modulus"; comp_to_add = 4; - } - /* validate */ - if (comp_to_add == 4 && (key_info->u.rsa.n == NULL || key_info->u.rsa.n_len == 0)){ - sc_log(ctx, "Error: Modulus required!"); - LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + /* validate */ + if (comp_to_add == 4 && (key_info->u.rsa.n == NULL || key_info->u.rsa.n_len == 0)) { + sc_log(ctx, "Error: Modulus required!"); + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + } } /* Cardholder private key template's data part */ @@ -3284,18 +3354,18 @@ pgp_build_extended_header_list(sc_card_t *card, sc_cardctl_openpgp_keystore_info comp_to_add = 1; /* import public key as well */ - if (key_info->u.ec.keyformat == SC_OPENPGP_KEYFORMAT_EC_STDPUB){ + if (key_info->u.ec.keyformat == SC_OPENPGP_KEYFORMAT_EC_STDPUB) { components[1] = key_info->u.ec.ecpointQ; componentlens[1] = key_info->u.ec.ecpointQ_len; componenttags[1] = 0x99; componentnames[1] = "public key"; comp_to_add = 2; - } - /* validate */ - if ((key_info->u.ec.ecpointQ == NULL || key_info->u.ec.ecpointQ_len == 0)){ - sc_log(ctx, "Error: ecpointQ required!"); - LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + /* validate */ + if ((key_info->u.ec.ecpointQ == NULL || key_info->u.ec.ecpointQ_len == 0)) { + sc_log(ctx, "Error: ecpointQ required!"); + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + } } /* Cardholder private key template's data part */ @@ -3383,14 +3453,25 @@ pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info) sc_cardctl_openpgp_keygen_info_t pubkey; u8 *data = NULL; size_t len = 0; - int r; + int r = 0; + int has_pubkey = 0, has_privkey = 0; struct pgp_priv_data *priv = DRVDATA(card); LOG_FUNC_CALLED(card->ctx); + /* PKCS11 loads privkey separately from pubkey as two diffrent operations + * So this routine will be called twice to create two different objects. + * pkcs15init only calls once, with both. + * OpenPGP 4.3.1 says modulus and ecpointQ are optional when + * creating the extended header. + * So we can tell the difference and only do appropriate parts of this + * routine. + */ + /* protect incompatible cards against non-RSA */ - if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA - && priv->bcd_version < OPENPGP_CARD_3_0) + if (key_info->algorithm != SC_OPENPGP_KEYALGO_RSA && + priv->bcd_version < OPENPGP_CARD_3_0 && + card->type != SC_CARD_TYPE_OPENPGP_GNUK) LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); /* Validate */ @@ -3401,18 +3482,29 @@ pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info) /* set algorithm attributes */ /* RSA */ if (key_info->algorithm == SC_OPENPGP_KEYALGO_RSA){ + has_pubkey = (key_info->u.rsa.n && key_info->u.rsa.n_len && + key_info->u.rsa.e && key_info->u.rsa.e_len); + has_privkey = (has_pubkey && + key_info->u.rsa.p && key_info->u.rsa.p_len && + key_info->u.rsa.q && key_info->u.rsa.q_len); + + if (!has_pubkey && !has_privkey) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); + /* we just support standard key format */ - switch (key_info->u.rsa.keyformat) { - case SC_OPENPGP_KEYFORMAT_RSA_STD: - case SC_OPENPGP_KEYFORMAT_RSA_STDN: - break; + if (has_privkey) { + switch (key_info->u.rsa.keyformat) { + case SC_OPENPGP_KEYFORMAT_RSA_STD: + case SC_OPENPGP_KEYFORMAT_RSA_STDN: + break; - case SC_OPENPGP_KEYFORMAT_RSA_CRT: - case SC_OPENPGP_KEYFORMAT_RSA_CRTN: - LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); + case SC_OPENPGP_KEYFORMAT_RSA_CRT: + case SC_OPENPGP_KEYFORMAT_RSA_CRTN: + LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); - default: - LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); + default: + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); + } } /* we only support exponent of maximum 32 bits */ @@ -3426,59 +3518,68 @@ pgp_store_key(sc_card_t *card, sc_cardctl_openpgp_keystore_info_t *key_info) memset(&pubkey, 0, sizeof(pubkey)); pubkey.key_id = key_info->key_id; pubkey.algorithm = key_info->algorithm; - if (key_info->u.rsa.n && key_info->u.rsa.n_len - && key_info->u.rsa.e && key_info->u.rsa.e_len) { - pubkey.u.rsa.modulus = key_info->u.rsa.n; - pubkey.u.rsa.modulus_len = key_info->u.rsa.n_len; - pubkey.u.rsa.exponent = key_info->u.rsa.e; - pubkey.u.rsa.exponent_len = key_info->u.rsa.e_len; - } - else - LOG_FUNC_RETURN(card->ctx,SC_ERROR_INVALID_ARGUMENTS); + pubkey.u.rsa.modulus = key_info->u.rsa.n; + pubkey.u.rsa.modulus_len = key_info->u.rsa.n_len; + pubkey.u.rsa.exponent = key_info->u.rsa.e; + pubkey.u.rsa.exponent_len = key_info->u.rsa.e_len; + } /* ECC */ - else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH - || key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA){ + else if (key_info->algorithm == SC_OPENPGP_KEYALGO_ECDSA || + key_info->algorithm == SC_OPENPGP_KEYALGO_ECDH || /* includes XEDDSA */ + key_info->algorithm == SC_OPENPGP_KEYALGO_EDDSA) { + has_pubkey = (key_info->u.ec.ecpointQ && key_info->u.ec.ecpointQ_len); + has_privkey = (key_info->u.ec.privateD && key_info->u.ec.privateD_len); + + if (!has_pubkey && !has_privkey) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); + memset(&pubkey, 0, sizeof(pubkey)); pubkey.key_id = key_info->key_id; pubkey.algorithm = key_info->algorithm; - if (key_info->u.ec.ecpointQ && key_info->u.ec.ecpointQ_len){ - pubkey.u.ec.ecpoint = key_info->u.ec.ecpointQ; - pubkey.u.ec.ecpoint_len = key_info->u.ec.ecpointQ_len; - pubkey.u.ec.oid = key_info->u.ec.oid; - pubkey.u.ec.oid_len = key_info->u.ec.oid_len; - } - else - LOG_FUNC_RETURN(card->ctx,SC_ERROR_INVALID_ARGUMENTS); + pubkey.u.ec.oid = key_info->u.ec.oid; + pubkey.u.ec.oid_len = key_info->u.ec.oid_len; + pubkey.u.ec.ecpoint = key_info->u.ec.ecpointQ; + pubkey.u.ec.ecpoint_len = key_info->u.ec.ecpointQ_len; + pubkey.u.ec.oid = key_info->u.ec.oid; + pubkey.u.ec.oid_len = key_info->u.ec.oid_len; } - else - LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); - r = pgp_update_new_algo_attr(card, &pubkey); - LOG_TEST_RET(card->ctx, r, "Failed to update new algorithm attributes"); + /* TODO where is curve_name are */ + if (has_pubkey) { + r = pgp_update_new_algo_attr(card, &pubkey); + LOG_TEST_RET(card->ctx, r, "Failed to update new algorithm attributes"); + } /* build Extended Header list */ - r = pgp_build_extended_header_list(card, key_info, &data, &len); - LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to build Extended Header list"); + if (has_privkey) { + r = pgp_build_extended_header_list(card, key_info, &data, &len); + LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to build Extended Header list"); + } /* write to DO */ - r = pgp_put_data(card, 0x4D, data, len); - LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to write to DO 004D"); + if (has_privkey) { + r = pgp_put_data(card, 0x4D, data, len); + LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to write to DO 004D"); - /* store creation time */ - r = pgp_store_creationtime(card, key_info->key_id, &key_info->creationtime); - LOG_TEST_RET(card->ctx, r, "Cannot store creation time"); + /* store creation time */ + r = pgp_store_creationtime(card, key_info->key_id, &key_info->creationtime); + LOG_TEST_RET(card->ctx, r, "Cannot store creation time"); + } - /* calculate and store fingerprint */ - sc_log(card->ctx, "Calculate and store fingerprint"); - r = pgp_calculate_and_store_fingerprint(card, key_info->creationtime, &pubkey); - LOG_TEST_RET(card->ctx, r, "Cannot store fingerprint"); - /* update pubkey blobs (B601,B801, A401) */ - sc_log(card->ctx, "Update blobs holding pubkey info."); - r = pgp_update_pubkey_blob(card, &pubkey); + if (has_pubkey) { + /* calculate and store fingerprint */ + sc_log(card->ctx, "Calculate and store fingerprint"); + r = pgp_calculate_and_store_fingerprint(card, key_info->creationtime, &pubkey); - sc_log(card->ctx, "Update card algorithms"); - pgp_update_card_algorithms(card, &pubkey); + LOG_TEST_RET(card->ctx, r, "Cannot store fingerprint"); + /* update pubkey blobs (B601,B801, A401) */ + sc_log(card->ctx, "Update blobs holding pubkey info."); + r = pgp_update_pubkey_blob(card, &pubkey); + + sc_log(card->ctx, "Update card algorithms"); + pgp_update_card_algorithms(card, &pubkey); + } err: free(data); diff --git a/src/libopensc/card-openpgp.h b/src/libopensc/card-openpgp.h index 36a84086bf..85fc14865a 100644 --- a/src/libopensc/card-openpgp.h +++ b/src/libopensc/card-openpgp.h @@ -163,8 +163,16 @@ typedef struct pgp_blob { typedef struct _pgp_ec_curves { struct sc_object_id oid; size_t size; + unsigned int key_type; } pgp_ec_curves_t; +#ifdef ENABLE_OPENSSL +typedef struct _pgp_ec_curves_alt { + struct sc_object_id oid; + struct sc_object_id oid_alt; /* RFC8410 OIDs to be mapped to oid */ + size_t size; +} pgp_ec_curves_alt_t; +#endif /* ENABLE_OPENSSL */ #define DRVDATA(card) ((struct pgp_priv_data *) ((card)->drv_data)) diff --git a/src/libopensc/card.c b/src/libopensc/card.c index 7f4ef98f91..ea3e4cd2da 100644 --- a/src/libopensc/card.c +++ b/src/libopensc/card.c @@ -163,11 +163,10 @@ static void sc_card_free(sc_card_t *card) int i; for (i=0; ialgorithm_count; i++) { struct sc_algorithm_info *info = (card->algorithms + i); - if (info->algorithm == SC_ALGORITHM_EC) { - struct sc_ec_parameters ep = info->u._ec.params; - - free(ep.named_curve); - free(ep.der.value); + if (info->algorithm == SC_ALGORITHM_EC || + info->algorithm == SC_ALGORITHM_EDDSA || + info->algorithm == SC_ALGORITHM_XEDDSA) { + sc_clear_ec_params(&info->u._ec.params); } } free(card->algorithms); @@ -1167,6 +1166,7 @@ _sc_card_add_ec_alg_int(sc_card_t *card, size_t key_length, int algorithm) { sc_algorithm_info_t info; + int r; memset(&info, 0, sizeof(info)); sc_init_oid(&info.u._ec.params.id); @@ -1176,10 +1176,19 @@ _sc_card_add_ec_alg_int(sc_card_t *card, size_t key_length, info.flags = flags; info.u._ec.ext_flags = ext_flags; - if (curve_oid) + if (curve_oid) { info.u._ec.params.id = *curve_oid; + r = sc_encode_oid(card->ctx, &info.u._ec.params.id, &info.u._ec.params.der.value, &info.u._ec.params.der.len); + LOG_TEST_GOTO_ERR(card->ctx, r, "sc_encode_oid failed"); + r = sc_pkcs15_fix_ec_parameters(card->ctx, &info.u._ec.params); + LOG_TEST_GOTO_ERR(card->ctx, r, "sc_pkcs15_fix_ec_parameters failed"); + } - return _sc_card_add_algorithm(card, &info); + r = _sc_card_add_algorithm(card, &info); + return r; +err: + sc_clear_ec_params(&info.u._ec.params); + return r; } int _sc_card_add_ec_alg(sc_card_t *card, size_t key_length, @@ -1216,13 +1225,13 @@ sc_algorithm_info_t *sc_card_find_alg(sc_card_t *card, for (i = 0; i < card->algorithm_count; i++) { sc_algorithm_info_t *info = &card->algorithms[i]; - if (info->algorithm != algorithm) - continue; if (param && (info->algorithm == SC_ALGORITHM_EC || info->algorithm == SC_ALGORITHM_EDDSA || info->algorithm == SC_ALGORITHM_XEDDSA)) { if (sc_compare_oid((struct sc_object_id *)param, &info->u._ec.params.id)) return info; + } else if (info->algorithm != algorithm) { + continue; } else if (info->key_length == key_length) return info; } @@ -1507,6 +1516,17 @@ void sc_print_cache(struct sc_card *card) sc_print_path(&card->cache.current_df->path)); } +void +sc_clear_ec_params(struct sc_ec_parameters *ecp) +{ + if (ecp) { + free(ecp->named_curve); + free(ecp->der.value); + memset(ecp, 0, sizeof(struct sc_ec_parameters)); + } + return; +} + int sc_copy_ec_params(struct sc_ec_parameters *dst, struct sc_ec_parameters *src) { if (!dst || !src) @@ -1528,8 +1548,9 @@ int sc_copy_ec_params(struct sc_ec_parameters *dst, struct sc_ec_parameters *src memcpy(dst->der.value, src->der.value, src->der.len); dst->der.len = src->der.len; } - src->type = dst->type; - src->field_length = dst->field_length; + dst->type = src->type; + dst->field_length = src->field_length; + dst->key_type = src->key_type; return SC_SUCCESS; } diff --git a/src/libopensc/cardctl.h b/src/libopensc/cardctl.h index 70115977a7..a9c90efe91 100644 --- a/src/libopensc/cardctl.h +++ b/src/libopensc/cardctl.h @@ -882,6 +882,7 @@ typedef struct sc_cardctl_piv_genkey_info_st { typedef struct sc_cardctl_openpgp_keygen_info { u8 key_id; /* SC_OPENPGP_KEY_... */ u8 algorithm; /* SC_OPENPGP_KEYALGO_... */ + unsigned long key_type; /* SC_ALGORITHM_... */ union { struct { u8 keyformat; /* SC_OPENPGP_KEYFORMAT_RSA_... */ diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index b5f0b1cb27..fbc0ea96c4 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -64,6 +64,7 @@ sc_cancel sc_card_ctl sc_change_reference_data sc_check_sw +sc_clear_ec_params sc_compare_oid sc_compare_path sc_compare_path_prefix diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index cbcb3bebb3..36ba1722dc 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -280,14 +280,20 @@ struct sc_pbes2_params { }; /* + * PKCS11 2.3 Elliptic Curve lists mechanisms that use CKA_ECPARMS + * which implies the type of key and size needed in the OID * The ecParameters can be presented as * - name of curve; * - OID of named curve; * - implicit parameters. + * - printable string for non standard OIDS - added in pkcs11 3.0 * * type - type(choice) of 'EC domain parameters' as it present in CKA_EC_PARAMS (PKCS#11). - Recommended value '1' -- namedCurve. + * Recommended value '1' -- namedCurve. * field_length - EC key size in bits. + * key_type - 0 implies SC_ALGORITHM_EC, SC_ALGORITHM_EDDSA or SC_ALGORITHM_XEDDSA + * Not actually part of CKA_EC_PARAMS - used in OpenSC to differentiate key types that use ec_params + * will be set by, sc_pkcs15_fix_ec_parameters */ struct sc_ec_parameters { char *named_curve; @@ -296,6 +302,7 @@ struct sc_ec_parameters { int type; size_t field_length; + unsigned int key_type; }; typedef struct sc_algorithm_info { @@ -1646,6 +1653,11 @@ const u8 *sc_compacttlv_find_tag(const u8 *buf, size_t len, u8 tag, size_t *outl */ void sc_remote_data_init(struct sc_remote_data *rdata); +/** + * Clear ec_params + * @ecp + */ +void sc_clear_ec_params(struct sc_ec_parameters *); /** * Copy and allocate if needed EC parameters data diff --git a/src/libopensc/pkcs15-algo.c b/src/libopensc/pkcs15-algo.c index 3b1b3ba031..d39ca853a9 100644 --- a/src/libopensc/pkcs15-algo.c +++ b/src/libopensc/pkcs15-algo.c @@ -347,116 +347,136 @@ asn1_free_ec_params(void *params) } } - static struct sc_asn1_pkcs15_algorithm_info algorithm_table[] = { #ifdef SC_ALGORITHM_SHA1 /* hmacWithSHA1 */ - { SC_ALGORITHM_SHA1, {{ 1, 2, 840, 113549, 2, 7, -1}}, NULL, NULL, NULL }, - { SC_ALGORITHM_SHA1, {{ 1, 3, 6, 1, 5, 5, 8, 1, 2, -1}}, NULL, NULL, NULL }, - /* SHA1 */ - { SC_ALGORITHM_SHA1, {{ 1, 3, 14, 3, 2, 26, -1}}, NULL, NULL, NULL }, + {SC_ALGORITHM_SHA1, {{1, 2, 840, 113549, 2, 7, -1}}, NULL, NULL, NULL}, + {SC_ALGORITHM_SHA1, {{1, 3, 6, 1, 5, 5, 8, 1, 2, -1}}, NULL, NULL, NULL}, + /* SHA1 */ + {SC_ALGORITHM_SHA1, {{1, 3, 14, 3, 2, 26, -1}}, NULL, NULL, NULL}, #endif #ifdef SC_ALGORITHM_MD5 - { SC_ALGORITHM_MD5, {{ 1, 2, 840, 113549, 2, 5, -1}}, NULL, NULL, NULL }, + {SC_ALGORITHM_MD5, {{1, 2, 840, 113549, 2, 5, -1}}, NULL, NULL, NULL}, #endif #ifdef SC_ALGORITHM_RSA /* really rsaEncryption */ - { SC_ALGORITHM_RSA, {{ 1, 2, 840, 113549, 1, 1, 1, -1}}, NULL, NULL, NULL }, + {SC_ALGORITHM_RSA, {{1, 2, 840, 113549, 1, 1, 1, -1}}, NULL, NULL, NULL}, #endif #ifdef SC_ALGORITHM_DH - { SC_ALGORITHM_DH, {{ 1, 2, 840, 10046, 2, 1, -1}}, NULL, NULL, NULL }, + {SC_ALGORITHM_DH, {{1, 2, 840, 10046, 2, 1, -1}}, NULL, NULL, NULL}, #endif #ifdef SC_ALGORITHM_RC2_WRAP /* from CMS */ - { SC_ALGORITHM_RC2_WRAP, {{ 1, 2, 840, 113549, 1, 9, 16, 3, 7, -1}}, NULL, NULL, NULL }, + {SC_ALGORITHM_RC2_WRAP, {{1, 2, 840, 113549, 1, 9, 16, 3, 7, -1}}, NULL, NULL, NULL}, #endif #ifdef SC_ALGORITHM_RC2 /* CBC mode */ - { SC_ALGORITHM_RC2, {{ 1, 2, 840, 113549, 3, 2, -1}}, + {SC_ALGORITHM_RC2, {{1, 2, 840, 113549, 3, 2, -1}}, asn1_decode_rc2_params, - asn1_encode_rc2_params }, + asn1_encode_rc2_params}, #endif #ifdef SC_ALGORITHM_DES /* CBC mode */ - { SC_ALGORITHM_DES, {{ 1, 3, 14, 3, 2, 7, -1}}, + {SC_ALGORITHM_DES, {{1, 3, 14, 3, 2, 7, -1}}, asn1_decode_des_params, asn1_encode_des_params, - free }, + free}, #endif #ifdef SC_ALGORITHM_3DES_WRAP /* from CMS */ - { SC_ALGORITHM_3DES_WRAP, {{ 1, 2, 840, 113549, 1, 9, 16, 3, 6, -1}}, NULL, NULL, NULL }, + {SC_ALGORITHM_3DES_WRAP, {{1, 2, 840, 113549, 1, 9, 16, 3, 6, -1}}, NULL, NULL, NULL}, #endif #ifdef SC_ALGORITHM_3DES /* EDE CBC mode */ - { SC_ALGORITHM_3DES, {{ 1, 2, 840, 113549, 3, 7, -1}}, + {SC_ALGORITHM_3DES, {{1, 2, 840, 113549, 3, 7, -1}}, asn1_decode_des_params, asn1_encode_des_params, - free }, + free}, #endif #ifdef SC_ALGORITHM_GOST /* EDE CBC mode */ - { SC_ALGORITHM_GOST, {{ 1, 2, 4434, 66565, 3, 7, -1}}, NULL, NULL, NULL }, + {SC_ALGORITHM_GOST, {{1, 2, 4434, 66565, 3, 7, -1}}, NULL, NULL, NULL}, #endif #ifdef SC_ALGORITHM_GOSTR3410 - { SC_ALGORITHM_GOSTR3410, {{ 1, 2, 643, 2, 2, 19, -1}}, + {SC_ALGORITHM_GOSTR3410, {{1, 2, 643, 2, 2, 19, -1}}, asn1_decode_gostr3410_params, asn1_encode_gostr3410_params, - NULL }, + NULL}, #endif /* We do not support PBES1 because the encryption is weak */ #ifdef SC_ALGORITHM_PBKDF2 - { SC_ALGORITHM_PBKDF2, {{ 1, 2, 840, 113549, 1, 5, 12, -1}}, + {SC_ALGORITHM_PBKDF2, {{1, 2, 840, 113549, 1, 5, 12, -1}}, asn1_decode_pbkdf2_params, asn1_encode_pbkdf2_params, - free }, + free}, #endif #ifdef SC_ALGORITHM_PBES2 - { SC_ALGORITHM_PBES2, {{ 1, 2, 840, 113549, 1, 5, 13, -1}}, + {SC_ALGORITHM_PBES2, {{1, 2, 840, 113549, 1, 5, 13, -1}}, asn1_decode_pbes2_params, asn1_encode_pbes2_params, - asn1_free_pbes2_params }, + asn1_free_pbes2_params}, #endif #ifdef SC_ALGORITHM_EC - { SC_ALGORITHM_EC, {{ 1, 2, 840, 10045, 2, 1, -1}}, + {SC_ALGORITHM_EC, {{1, 2, 840, 10045, 2, 1, -1}}, asn1_decode_ec_params, asn1_encode_ec_params, - asn1_free_ec_params }, + asn1_free_ec_params}, #endif -/* TODO: -DEE Not clear if 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, -1}}, NULL, NULL, NULL}, + {SC_ALGORITHM_ECDSA_SHA1, {{1, 2, 840, 10045, 4, 1, -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, -1}}, + /* These next 4 are defined in RFC 5758 */ + {SC_ALGORITHM_ECDSA_SHA224, {{1, 2, 840, 10045, 4, 3, 1, -1}}, asn1_decode_ec_params, asn1_encode_ec_params, - asn1_free_ec_params }, + asn1_free_ec_params}, #endif #ifdef SC_ALGORITHM_ECDSA_SHA256 - { SC_ALGORITHM_ECDSA_SHA256, {{ 1, 2, 840, 10045, 4, 3, 2, -1}}, + {SC_ALGORITHM_ECDSA_SHA256, {{1, 2, 840, 10045, 4, 3, 2, -1}}, asn1_decode_ec_params, asn1_encode_ec_params, - asn1_free_ec_params }, + asn1_free_ec_params}, #endif #ifdef SC_ALGORITHM_ECDSA_SHA384 - { SC_ALGORITHM_ECDSA_SHA384, {{ 1, 2, 840, 10045, 4, 3, 3, -1}}, + {SC_ALGORITHM_ECDSA_SHA384, {{1, 2, 840, 10045, 4, 3, 3, -1}}, asn1_decode_ec_params, asn1_encode_ec_params, - asn1_free_ec_params }, + asn1_free_ec_params}, #endif #ifdef SC_ALGORITHM_ECDSA_SHA512 - { SC_ALGORITHM_ECDSA_SHA512, {{ 1, 2, 840, 10045, 4, 3, 4, -1}}, + {SC_ALGORITHM_ECDSA_SHA512, {{1, 2, 840, 10045, 4, 3, 4, -1}}, asn1_decode_ec_params, asn1_encode_ec_params, - asn1_free_ec_params }, + asn1_free_ec_params}, #endif #ifdef SC_ALGORITHM_EDDSA /* aka Ed25519 */ - /* RFC 8410, needed to parse/create X509 certs/pubkeys */ - { SC_ALGORITHM_EDDSA, {{1, 3, 101, 112, -1}}, NULL, NULL, NULL }, + /* RFC 8410, needed to parse/create X509 certs/pubkeys */ + {SC_ALGORITHM_EDDSA, {{1, 3, 101, 112, -1}}, + asn1_decode_ec_params, + asn1_encode_ec_params, + asn1_free_ec_params}, /* Ed25119 */ + {SC_ALGORITHM_EDDSA, {{1, 3, 6, 1, 4, 1, 11591, 15, 1, -1}}, + asn1_decode_ec_params, + asn1_encode_ec_params, + asn1_free_ec_params}, /* Ed25519 OID used by OpenPGP */ + {SC_ALGORITHM_EDDSA, {{1, 3, 101, 113, -1}}, + asn1_decode_ec_params, + asn1_encode_ec_params, + asn1_free_ec_params}, /* Ed448 */ #endif #ifdef SC_ALGORITHM_XEDDSA /* aka curve25519 */ - /* RFC 8410, needed to parse/create X509 certs/pubkeys */ - { SC_ALGORITHM_XEDDSA, {{1, 3, 101, 110, -1}}, NULL, NULL, NULL }, + /* RFC 8410, needed to parse/create X509 certs/pubkeys ec_parms*/ + {SC_ALGORITHM_XEDDSA, {{1, 3, 101, 110, -1}}, + asn1_decode_ec_params, + asn1_encode_ec_params, + asn1_free_ec_params}, /* X25519 */ + {SC_ALGORITHM_XEDDSA, {{1, 3, 6, 1, 4, 1, 3029, 1, 5, 1 - 1}}, + asn1_decode_ec_params, + asn1_encode_ec_params, + asn1_free_ec_params}, /* X25519 OID used by OpenPGP */ + {SC_ALGORITHM_XEDDSA, {{1, 3, 101, 111, -1}}, + asn1_decode_ec_params, + asn1_encode_ec_params, + asn1_free_ec_params}, /* X448 */ #endif - { -1, {{ -1 }}, NULL, NULL, NULL } + {-1, {{-1}}, NULL, NULL, NULL} }; @@ -554,6 +574,7 @@ sc_asn1_encode_algorithm_id(struct sc_context *ctx, u8 **buf, size_t *len, /* no parameters, write NULL tag */ /* If it's EDDSA/XEDDSA, according to RFC8410, params * MUST be absent */ + /* PKCS11 3.0 list them under ec_params */ if (id->algorithm != SC_ALGORITHM_EDDSA && id->algorithm != SC_ALGORITHM_XEDDSA && (!id->params || !alg_info->encode)) diff --git a/src/libopensc/pkcs15-prkey.c b/src/libopensc/pkcs15-prkey.c index 70834713a1..63e0566787 100644 --- a/src/libopensc/pkcs15-prkey.c +++ b/src/libopensc/pkcs15-prkey.c @@ -570,19 +570,13 @@ sc_pkcs15_erase_prkey(struct sc_pkcs15_prkey *key) free(key->u.gostr3410.d.data); break; case SC_ALGORITHM_EC: - free(key->u.ec.params.der.value); - free(key->u.ec.params.named_curve); + case SC_ALGORITHM_EDDSA: + case SC_ALGORITHM_XEDDSA: + /* EC, Edwards and Montgomery use common ec params */ + sc_clear_ec_params(&key->u.ec.params); free(key->u.ec.privateD.data); free(key->u.ec.ecpointQ.value); break; - case SC_ALGORITHM_EDDSA: - free(key->u.eddsa.pubkey.value); - key->u.eddsa.pubkey.value = NULL; - key->u.eddsa.pubkey.len = 0; - free(key->u.eddsa.value.value); - key->u.eddsa.value.value = NULL; - key->u.eddsa.value.len = 0; - break; } sc_mem_clear(key, sizeof(*key)); } diff --git a/src/libopensc/pkcs15-pubkey.c b/src/libopensc/pkcs15-pubkey.c index 1f9c2c46d9..4b2c3b17b3 100644 --- a/src/libopensc/pkcs15-pubkey.c +++ b/src/libopensc/pkcs15-pubkey.c @@ -517,6 +517,7 @@ sc_pkcs15_encode_pukdf_entry(struct sc_context *ctx, const struct sc_pkcs15_obje return r; } +// clang-format off #define C_ASN1_PUBLIC_KEY_SIZE 2 static struct sc_asn1_entry c_asn1_public_key[C_ASN1_PUBLIC_KEY_SIZE] = { { "publicKeyCoefficients", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, @@ -536,18 +537,23 @@ static struct sc_asn1_entry c_asn1_gostr3410_pub_coefficients[C_ASN1_GOSTR3410_P { NULL, 0, 0, 0, NULL, NULL } }; -#define C_ASN1_EC_POINTQ_SIZE 2 +/* older incorrect implementation may have encoded as OCTET STRING */ +/* accept either */ +#define C_ASN1_EC_POINTQ_SIZE 3 static struct sc_asn1_entry c_asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE] = { - { "ecpointQ", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_ALLOC, NULL, NULL }, + { "ecpointQ", SC_ASN1_BIT_STRING_NI, SC_ASN1_TAG_BIT_STRING, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL }, + { "ecpointQ-OS", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } }; -#define C_ASN1_EDDSA_PUBKEY_SIZE 2 +/* See RFC8410 */ +#define C_ASN1_EDDSA_PUBKEY_SIZE 3 static struct sc_asn1_entry c_asn1_eddsa_pubkey[C_ASN1_EDDSA_PUBKEY_SIZE] = { - { "pubkey", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_ALLOC, NULL, NULL }, + { "ecpointQ", SC_ASN1_BIT_STRING_NI, SC_ASN1_TAG_BIT_STRING, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL }, + { "ecpointQ-OS", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, NULL, NULL }, { NULL, 0, 0, 0, NULL, NULL } }; - +// clang-format on int sc_pkcs15_decode_pubkey_rsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_rsa *key, @@ -636,7 +642,8 @@ sc_pkcs15_encode_pubkey_gostr3410(sc_context_t *ctx, } /* - * We are storing the ec_pointQ as u8 string. not as DER + * We are storing the ec_pointQ as u8 string not as DER + * Will accept either BIT STRING or OCTET STRING */ int sc_pkcs15_decode_pubkey_ec(sc_context_t *ctx, @@ -645,19 +652,20 @@ sc_pkcs15_decode_pubkey_ec(sc_context_t *ctx, { int r; u8 * ecpoint_data = NULL; - size_t ecpoint_len; + size_t ecpoint_len = 0; struct sc_asn1_entry asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE]; LOG_FUNC_CALLED(ctx); sc_copy_asn1_entry(c_asn1_ec_pointQ, asn1_ec_pointQ); sc_format_asn1_entry(asn1_ec_pointQ + 0, &ecpoint_data, &ecpoint_len, 1); - r = sc_asn1_decode(ctx, asn1_ec_pointQ, buf, buflen, NULL, NULL); - if (r < 0) { + sc_format_asn1_entry(asn1_ec_pointQ + 1, &ecpoint_data, &ecpoint_len, 1); + r = sc_asn1_decode_choice(ctx, asn1_ec_pointQ, buf, buflen, NULL, NULL); + if (r < 0 || ecpoint_len == 0 || ecpoint_data == NULL) { free(ecpoint_data); - LOG_TEST_RET(ctx, r, "ASN.1 decoding failed"); + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT); } - if (ecpoint_len == 0 || *ecpoint_data != 0x04) { + if (*ecpoint_data != 0x04) { free(ecpoint_data); LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Supported only uncompressed EC pointQ value"); } @@ -665,11 +673,6 @@ sc_pkcs15_decode_pubkey_ec(sc_context_t *ctx, key->ecpointQ.len = ecpoint_len; key->ecpointQ.value = ecpoint_data; - /* - * Only get here if raw point is stored in pkcs15 without curve name - * spki has the curvename, so we can get the field_length - * Following only true for curves that are multiple of 8 - */ key->params.field_length = (ecpoint_len - 1)/2 * 8; LOG_FUNC_RETURN(ctx, SC_SUCCESS); } @@ -680,57 +683,70 @@ sc_pkcs15_encode_pubkey_ec(sc_context_t *ctx, struct sc_pkcs15_pubkey_ec *key, u8 **buf, size_t *buflen) { struct sc_asn1_entry asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE]; + size_t key_len; + volatile int gdb_test = 1; /* so can reset via gdb for testing new way */ LOG_FUNC_CALLED(ctx); sc_copy_asn1_entry(c_asn1_ec_pointQ, asn1_ec_pointQ); - sc_format_asn1_entry(asn1_ec_pointQ + 0, key->ecpointQ.value, &key->ecpointQ.len, 1); + + if (gdb_test == 1) { + key_len = key->ecpointQ.len * 8; /* encode in bit string */ + sc_format_asn1_entry(asn1_ec_pointQ + 0, key->ecpointQ.value, &key_len, 1); + } else { + key_len = key->ecpointQ.len; + sc_format_asn1_entry(asn1_ec_pointQ + 1, key->ecpointQ.value, &key_len, 1); + } LOG_FUNC_RETURN(ctx, sc_asn1_encode(ctx, asn1_ec_pointQ, buf, buflen)); } /* - * EdDSA keys are just byte strings. For now only - * for Ed25519 keys 32B length are supported + * all "ec" keys uses same pubkey format, keep this external entrypoint + * keys are just byte strings. + * will accept in either BIT STRING or OCTET STRING */ int sc_pkcs15_decode_pubkey_eddsa(sc_context_t *ctx, - struct sc_pkcs15_pubkey_eddsa *key, + struct sc_pkcs15_pubkey_ec *key, const u8 *buf, size_t buflen) { int r; - u8 * pubkey = NULL; - size_t pubkey_len; - struct sc_asn1_entry asn1_eddsa_pubkey[C_ASN1_EDDSA_PUBKEY_SIZE]; + u8 *ecpoint_data = NULL; + size_t ecpoint_len = 0; + struct sc_asn1_entry asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE]; LOG_FUNC_CALLED(ctx); - sc_copy_asn1_entry(c_asn1_eddsa_pubkey, asn1_eddsa_pubkey); - sc_format_asn1_entry(asn1_eddsa_pubkey + 0, &pubkey, &pubkey_len, 1); - r = sc_asn1_decode(ctx, asn1_eddsa_pubkey, buf, buflen, NULL, NULL); - if (r < 0) - LOG_TEST_RET(ctx, r, "ASN.1 decoding failed"); + sc_copy_asn1_entry(c_asn1_ec_pointQ, asn1_ec_pointQ); + sc_format_asn1_entry(asn1_ec_pointQ + 0, &ecpoint_data, &ecpoint_len, 1); + sc_format_asn1_entry(asn1_ec_pointQ + 1, &ecpoint_data, &ecpoint_len, 1); + r = sc_asn1_decode_choice(ctx, asn1_ec_pointQ, buf, buflen, NULL, NULL); + if (r < 0 || ecpoint_len == 0 || ecpoint_data == NULL) { + free(ecpoint_data); + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT); + } - key->pubkey.len = pubkey_len; - key->pubkey.value = pubkey; + key->ecpointQ.len = ecpoint_len; + key->ecpointQ.value = ecpoint_data; + key->params.field_length = ecpoint_len * 8; LOG_FUNC_RETURN(ctx, SC_SUCCESS); } int -sc_pkcs15_encode_pubkey_eddsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_eddsa *key, +sc_pkcs15_encode_pubkey_eddsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_ec *key, u8 **buf, size_t *buflen) { struct sc_asn1_entry asn1_eddsa_pubkey[C_ASN1_EDDSA_PUBKEY_SIZE]; LOG_FUNC_CALLED(ctx); sc_copy_asn1_entry(c_asn1_eddsa_pubkey, asn1_eddsa_pubkey); - sc_format_asn1_entry(asn1_eddsa_pubkey + 0, key->pubkey.value, &key->pubkey.len, 1); + sc_format_asn1_entry(asn1_eddsa_pubkey + 0, key->ecpointQ.value, &key->ecpointQ.len, 1); LOG_FUNC_RETURN(ctx, sc_asn1_encode(ctx, asn1_eddsa_pubkey, buf, buflen)); } - int sc_pkcs15_encode_pubkey(sc_context_t *ctx, struct sc_pkcs15_pubkey *key, u8 **buf, size_t *len) @@ -741,9 +757,8 @@ sc_pkcs15_encode_pubkey(sc_context_t *ctx, struct sc_pkcs15_pubkey *key, return sc_pkcs15_encode_pubkey_gostr3410(ctx, &key->u.gostr3410, buf, len); if (key->algorithm == SC_ALGORITHM_EC) return sc_pkcs15_encode_pubkey_ec(ctx, &key->u.ec, buf, len); - if (key->algorithm == SC_ALGORITHM_EDDSA || - key->algorithm == SC_ALGORITHM_XEDDSA) /* XXX encoding is the same here */ - return sc_pkcs15_encode_pubkey_eddsa(ctx, &key->u.eddsa, buf, len); + if (key->algorithm == SC_ALGORITHM_EDDSA || key->algorithm == SC_ALGORITHM_XEDDSA) + return sc_pkcs15_encode_pubkey_eddsa(ctx, &key->u.ec, buf, len); sc_log(ctx, "Encoding of public key type %lu not supported", key->algorithm); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); @@ -789,6 +804,8 @@ sc_pkcs15_encode_pubkey_as_spki(sc_context_t *ctx, struct sc_pkcs15_pubkey *pubk switch (pubkey->algorithm) { case SC_ALGORITHM_EC: + case SC_ALGORITHM_EDDSA: + case SC_ALGORITHM_XEDDSA: /* * most keys, but not EC have only one encoding. * For a SPKI, the ecpoint is placed directly in the @@ -826,14 +843,6 @@ sc_pkcs15_encode_pubkey_as_spki(sc_context_t *ctx, struct sc_pkcs15_pubkey *pubk r = sc_pkcs15_encode_pubkey(ctx, pubkey, &pkey.value, &pkey.len); key_len = pkey.len * 8; break; - case SC_ALGORITHM_EDDSA: - case SC_ALGORITHM_XEDDSA: - /* For a SPKI, the pubkey is placed directly in the BIT STRING */ - pkey.value = malloc(pubkey->u.eddsa.pubkey.len); - memcpy(pkey.value, pubkey->u.eddsa.pubkey.value, pubkey->u.eddsa.pubkey.len); - // Should be pkey.len = 0 there? - key_len = pubkey->u.eddsa.pubkey.len * 8; - break; default: r = sc_pkcs15_encode_pubkey(ctx, pubkey, &pkey.value, &pkey.len); key_len = pkey.len * 8; @@ -867,9 +876,8 @@ sc_pkcs15_decode_pubkey(sc_context_t *ctx, struct sc_pkcs15_pubkey *key, return sc_pkcs15_decode_pubkey_gostr3410(ctx, &key->u.gostr3410, buf, len); if (key->algorithm == SC_ALGORITHM_EC) return sc_pkcs15_decode_pubkey_ec(ctx, &key->u.ec, buf, len); - if (key->algorithm == SC_ALGORITHM_EDDSA || - key->algorithm == SC_ALGORITHM_XEDDSA) - return sc_pkcs15_decode_pubkey_eddsa(ctx, &key->u.eddsa, buf, len); + if (key->algorithm == SC_ALGORITHM_EDDSA || key->algorithm == SC_ALGORITHM_XEDDSA) + return sc_pkcs15_decode_pubkey_eddsa(ctx, &key->u.ec, buf, len); sc_log(ctx, "Decoding of public key type %lu not supported", key->algorithm); return SC_ERROR_NOT_SUPPORTED; @@ -1030,29 +1038,20 @@ sc_pkcs15_pubkey_from_prvkey(struct sc_context *ctx, struct sc_pkcs15_prkey *prv case SC_ALGORITHM_GOSTR3410: break; case SC_ALGORITHM_EC: - pubkey->u.ec.ecpointQ.value = malloc(prvkey->u.ec.ecpointQ.len); - if (!pubkey->u.ec.ecpointQ.value) { - sc_pkcs15_free_pubkey(pubkey); - LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); - } - memcpy(pubkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.len); - pubkey->u.ec.ecpointQ.len = prvkey->u.ec.ecpointQ.len; - break; case SC_ALGORITHM_EDDSA: case SC_ALGORITHM_XEDDSA: /* Copy pubkey */ - if (prvkey->u.eddsa.pubkey.value == NULL || prvkey->u.eddsa.pubkey.len <= 0) { + if (prvkey->u.ec.ecpointQ.value == NULL || prvkey->u.ec.ecpointQ.len <= 0) { sc_pkcs15_free_pubkey(pubkey); LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA); } - pubkey->u.eddsa.pubkey.value = malloc(prvkey->u.eddsa.pubkey.len); - if (!pubkey->u.eddsa.pubkey.value) { + pubkey->u.ec.ecpointQ.value = malloc(prvkey->u.ec.ecpointQ.len); + if (!pubkey->u.ec.ecpointQ.value) { sc_pkcs15_free_pubkey(pubkey); LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); } - memcpy(pubkey->u.eddsa.pubkey.value, prvkey->u.eddsa.pubkey.value, prvkey->u.eddsa.pubkey.len); - pubkey->u.eddsa.pubkey.len = prvkey->u.eddsa.pubkey.len; - + memcpy(pubkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.value, prvkey->u.ec.ecpointQ.len); + pubkey->u.ec.ecpointQ.len = prvkey->u.ec.ecpointQ.len; break; default: sc_log(ctx, "Unsupported private key algorithm"); @@ -1111,6 +1110,8 @@ sc_pkcs15_dup_pubkey(struct sc_context *ctx, struct sc_pkcs15_pubkey *key, struc case SC_ALGORITHM_GOSTR3410: break; case SC_ALGORITHM_EC: + case SC_ALGORITHM_EDDSA: + case SC_ALGORITHM_XEDDSA: pubkey->u.ec.ecpointQ.value = malloc(key->u.ec.ecpointQ.len); if (!pubkey->u.ec.ecpointQ.value) { rv = SC_ERROR_OUT_OF_MEMORY; @@ -1119,6 +1120,12 @@ sc_pkcs15_dup_pubkey(struct sc_context *ctx, struct sc_pkcs15_pubkey *key, struc memcpy(pubkey->u.ec.ecpointQ.value, key->u.ec.ecpointQ.value, key->u.ec.ecpointQ.len); pubkey->u.ec.ecpointQ.len = key->u.ec.ecpointQ.len; + if (key->u.ec.params.named_curve) { + rv = sc_pkcs15_fix_ec_parameters(ctx, &key->u.ec.params); + if (rv) + break; + } + pubkey->u.ec.params.der.value = malloc(key->u.ec.params.der.len); if (!pubkey->u.ec.params.der.value) { rv = SC_ERROR_OUT_OF_MEMORY; @@ -1127,27 +1134,17 @@ sc_pkcs15_dup_pubkey(struct sc_context *ctx, struct sc_pkcs15_pubkey *key, struc memcpy(pubkey->u.ec.params.der.value, key->u.ec.params.der.value, key->u.ec.params.der.len); pubkey->u.ec.params.der.len = key->u.ec.params.der.len; - if (key->u.ec.params.named_curve){ - pubkey->u.ec.params.named_curve = strdup(key->u.ec.params.named_curve); - if (!pubkey->u.ec.params.named_curve) - rv = SC_ERROR_OUT_OF_MEMORY; - } - else { - sc_log(ctx, "named_curve parameter missing"); - rv = SC_ERROR_NOT_SUPPORTED; - } - - break; - case SC_ALGORITHM_EDDSA: - case SC_ALGORITHM_XEDDSA: - /* Copy pubkey */ - pubkey->u.eddsa.pubkey.value = malloc(key->u.eddsa.pubkey.len); - if (!pubkey->u.eddsa.pubkey.value) { - rv = SC_ERROR_OUT_OF_MEMORY; - break; + /* RFC4810 no named_curve */ + if ((key->algorithm != SC_ALGORITHM_EDDSA) && (key->algorithm != SC_ALGORITHM_XEDDSA)) { + if (key->u.ec.params.named_curve) { + pubkey->u.ec.params.named_curve = strdup(key->u.ec.params.named_curve); + if (!pubkey->u.ec.params.named_curve) + rv = SC_ERROR_OUT_OF_MEMORY; + } else { + sc_log(ctx, "named_curve parameter missing"); + rv = SC_ERROR_NOT_SUPPORTED; + } } - memcpy(pubkey->u.eddsa.pubkey.value, key->u.eddsa.pubkey.value, key->u.eddsa.pubkey.len); - pubkey->u.eddsa.pubkey.len = key->u.eddsa.pubkey.len; break; default: @@ -1177,28 +1174,18 @@ sc_pkcs15_erase_pubkey(struct sc_pkcs15_pubkey *key) } switch (key->algorithm) { case SC_ALGORITHM_RSA: - if (key->u.rsa.modulus.data) - free(key->u.rsa.modulus.data); - if (key->u.rsa.exponent.data) - free(key->u.rsa.exponent.data); + free(key->u.rsa.modulus.data); + free(key->u.rsa.exponent.data); break; case SC_ALGORITHM_GOSTR3410: - if (key->u.gostr3410.xy.data) - free(key->u.gostr3410.xy.data); + free(key->u.gostr3410.xy.data); break; case SC_ALGORITHM_EC: - if (key->u.ec.params.der.value) - free(key->u.ec.params.der.value); - if (key->u.ec.params.named_curve) - free(key->u.ec.params.named_curve); - if (key->u.ec.ecpointQ.value) - free(key->u.ec.ecpointQ.value); - break; case SC_ALGORITHM_EDDSA: case SC_ALGORITHM_XEDDSA: - free(key->u.eddsa.pubkey.value); - key->u.eddsa.pubkey.value = NULL; - key->u.eddsa.pubkey.len = 0; + free(key->u.ec.params.der.value); + free(key->u.ec.params.named_curve); + free(key->u.ec.ecpointQ.value); break; } sc_mem_clear(key, sizeof(*key)); @@ -1402,9 +1389,9 @@ sc_pkcs15_pubkey_from_spki_fields(struct sc_context *ctx, struct sc_pkcs15_pubke } else if (pk_alg.algorithm == SC_ALGORITHM_EDDSA || pk_alg.algorithm == SC_ALGORITHM_XEDDSA) { /* EDDSA/XEDDSA public key is not encapsulated into BIT STRING -- it's a BIT STRING */ - pubkey->u.eddsa.pubkey.value = malloc(pk.len); - memcpy(pubkey->u.eddsa.pubkey.value, pk.value, pk.len); - pubkey->u.eddsa.pubkey.len = pk.len; + pubkey->u.ec.ecpointQ.value = malloc(pk.len); + memcpy(pubkey->u.ec.ecpointQ.value, pk.value, pk.len); + pubkey->u.ec.ecpointQ.len = pk.len; } else { /* Public key is expected to be encapsulated into BIT STRING */ r = sc_pkcs15_decode_pubkey(ctx, pubkey, pk.value, pk.len); @@ -1471,82 +1458,134 @@ sc_pkcs15_pubkey_from_spki_file(struct sc_context *ctx, char * filename, LOG_FUNC_RETURN(ctx, r); } - +// clang-format off static struct ec_curve_info { const char *name; const char *oid_str; const char *oid_encoded; size_t size; -} ec_curve_infos[] = { - {"secp192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, - {"prime192v1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, - {"nistp192", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, - {"ansiX9p192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192}, - - {"secp224r1", "1.3.132.0.33", "06052b81040021", 224}, - {"nistp224", "1.3.132.0.33", "06052b81040021", 224}, - - {"secp256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256}, - {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256}, - {"nistp256", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256}, - {"ansiX9p256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256}, - - {"secp384r1", "1.3.132.0.34", "06052B81040022", 384}, - {"prime384v1", "1.3.132.0.34", "06052B81040022", 384}, - {"nistp384", "1.3.132.0.34", "06052B81040022", 384}, - {"ansiX9p384r1", "1.3.132.0.34", "06052B81040022", 384}, - - {"secp521r1", "1.3.132.0.35", "06052B81040023", 521}, - {"nistp521", "1.3.132.0.35", "06052B81040023", 521}, + const unsigned int key_type; - {"brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3", "06092B2403030208010103", 192}, - {"brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5", "06092B2403030208010105", 224}, - {"brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", "06092B2403030208010107", 256}, - {"brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9", "06092B2403030208010109", 320}, - {"brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", "06092B240303020801010B", 384}, - {"brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", "06092B240303020801010D", 512}, - - {"secp192k1", "1.3.132.0.31", "06052B8104001F", 192}, - {"secp256k1", "1.3.132.0.10", "06052B8104000A", 256}, - - {"ed25519", "1.3.6.1.4.1.11591.15.1", "06092B06010401DA470F01", 255}, - {"curve25519", "1.3.6.1.4.1.3029.1.5.1", "060A2B060104019755010501", 255}, - - {NULL, NULL, NULL, 0}, /* Do not touch this */ +} ec_curve_infos[] = { + {"secp192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, SC_ALGORITHM_EC}, + {"prime192v1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, SC_ALGORITHM_EC}, + {"nistp192", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, SC_ALGORITHM_EC}, + {"ansiX9p192r1", "1.2.840.10045.3.1.1", "06082A8648CE3D030101", 192, SC_ALGORITHM_EC}, + + {"secp224r1", "1.3.132.0.33", "06052b81040021", 224, SC_ALGORITHM_EC}, + {"nistp224", "1.3.132.0.33", "06052b81040021", 224, SC_ALGORITHM_EC}, + + {"secp256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, SC_ALGORITHM_EC}, + {"prime256v1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, SC_ALGORITHM_EC}, + {"nistp256", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, SC_ALGORITHM_EC}, + {"ansiX9p256r1", "1.2.840.10045.3.1.7", "06082A8648CE3D030107", 256, SC_ALGORITHM_EC}, + + {"secp384r1", "1.3.132.0.34", "06052B81040022", 384, SC_ALGORITHM_EC}, + {"prime384v1", "1.3.132.0.34", "06052B81040022", 384, SC_ALGORITHM_EC}, + {"nistp384", "1.3.132.0.34", "06052B81040022", 384, SC_ALGORITHM_EC}, + {"ansiX9p384r1", "1.3.132.0.34", "06052B81040022", 384, SC_ALGORITHM_EC}, + + {"secp521r1", "1.3.132.0.35", "06052B81040023", 521, SC_ALGORITHM_EC}, + {"nistp521", "1.3.132.0.35", "06052B81040023", 521, SC_ALGORITHM_EC}, + + {"brainpoolP192r1", "1.3.36.3.3.2.8.1.1.3", "06092B2403030208010103", 192, SC_ALGORITHM_EC}, + {"brainpoolP224r1", "1.3.36.3.3.2.8.1.1.5", "06092B2403030208010105", 224, SC_ALGORITHM_EC}, + {"brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", "06092B2403030208010107", 256, SC_ALGORITHM_EC}, + {"brainpoolP320r1", "1.3.36.3.3.2.8.1.1.9", "06092B2403030208010109", 320, SC_ALGORITHM_EC}, + {"brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", "06092B240303020801010B", 384, SC_ALGORITHM_EC}, + {"brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", "06092B240303020801010D", 512, SC_ALGORITHM_EC}, + + {"secp192k1", "1.3.132.0.31", "06052B8104001F", 192, SC_ALGORITHM_EC}, + {"secp256k1", "1.3.132.0.10", "06052B8104000A", 256, SC_ALGORITHM_EC}, + + /* OpenPGP extensions by Yubikey and GNUK are not defined in RFCs but we know the oid written to card */ + + {"edwards25519", "1.3.6.1.4.1.11591.15.1", "06092B06010401DA470F01", 255, SC_ALGORITHM_EDDSA}, + {"curve25519", "1.3.6.1.4.1.3029.1.5.1", "060A2B060104019755010501", 255, SC_ALGORITHM_XEDDSA}, + + /* RFC 8410 defined curves */ + {"X25519", "1.3.101.110", "06032b656e", 255, SC_ALGORITHM_XEDDSA}, + {"X448", "1.3.101.111", "06032b656f", 448, SC_ALGORITHM_XEDDSA}, + {"Ed25519", "1.3.101.112", "06032b6570", 255, SC_ALGORITHM_EDDSA}, + {"Ed448", "1.3.101.113", "06032b6571", 448, SC_ALGORITHM_EDDSA}, + /* GnuPG openpgp curves as used in gnupg-card are equivalent to RFC8410 OIDs */ + {"cv25519", "1.3.101.110", "06032b656e", 255, SC_ALGORITHM_XEDDSA}, + {"ed25519", "1.3.101.112", "06032b6570", 255, SC_ALGORITHM_EDDSA}, + + {NULL, NULL, NULL, 0, 0}, /* Do not touch this */ }; - +// clang-format on int sc_pkcs15_fix_ec_parameters(struct sc_context *ctx, struct sc_ec_parameters *ecparams) { int rv, ii; + int mapped_string = 0; /* der is printable string that can be replaced with der of OID */ LOG_FUNC_CALLED(ctx); /* In PKCS#11 EC parameters arrives in DER encoded form */ - if (ecparams->der.value && ecparams->der.len) { - for (ii=0; ec_curve_infos[ii].name; ii++) { - struct sc_object_id id; - unsigned char *buf = NULL; - size_t len = 0; - - sc_format_oid(&id, ec_curve_infos[ii].oid_str); - sc_encode_oid (ctx, &id, &buf, &len); + if (ecparams->der.value && ecparams->der.len && ecparams->der.len > 2) { + + /* caller provided a der version of OID */ + switch (ecparams->der.value[0]) { + case 0x06: /* der.value is an OID */ + for (ii = 0; ec_curve_infos[ii].name; ii++) { + struct sc_object_id id; + unsigned char *buf = NULL; + size_t len = 0; + + sc_format_oid(&id, ec_curve_infos[ii].oid_str); + sc_encode_oid(ctx, &id, &buf, &len); + + if (ecparams->der.len == len && !memcmp(ecparams->der.value, buf, len)) { + free(buf); + break; /* found ec_curve_infos[ii] */ + } + free(buf); /* ii points at {NULL, NULL, NULL, 0} entry */ + } + break; - if (ecparams->der.len == len && !memcmp(ecparams->der.value, buf, len)) { - free(buf); - break; + case 0x13: + /* printable string as per PKCS11 V 3.0 for experimental curves */ + { + int r_tag; + const u8 *body = ecparams->der.value; + size_t len = ecparams->der.len; + unsigned int cla_out, tag_out; + size_t bodylen; + + r_tag = sc_asn1_read_tag(&body, len, &cla_out, &tag_out, &bodylen); + if (r_tag != SC_SUCCESS || tag_out != 0x13) { + sc_log(ctx, "Invalid printable string"); + LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); + } + for (ii = 0; ec_curve_infos[ii].name; ii++) { + size_t len = strlen(ec_curve_infos[ii].name); + if (bodylen != len || memcmp(ec_curve_infos[ii].name, body, len) != 0) + continue; + /* found replacement of printable string to OID */ + mapped_string = 1; + break; + } } + break; - free(buf); + default: + sc_log(ctx, "Unsupported ec params"); + LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); } - /* TODO: support of explicit EC parameters form */ if (!ec_curve_infos[ii].name) LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported named curve"); sc_log(ctx, "Found known curve '%s'", ec_curve_infos[ii].name); - if (!ecparams->named_curve) { + if (mapped_string) { /* free der of printable string replace below with OID */ + free(ecparams->named_curve); + ecparams->named_curve = NULL; + } + + if (!ecparams->named_curve) { ecparams->named_curve = strdup(ec_curve_infos[ii].name); if (!ecparams->named_curve) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); @@ -1554,21 +1593,34 @@ sc_pkcs15_fix_ec_parameters(struct sc_context *ctx, struct sc_ec_parameters *ecp sc_log(ctx, "Curve name: '%s'", ecparams->named_curve); } - if (!sc_valid_oid(&ecparams->id)) + if (!sc_valid_oid(&ecparams->id) || mapped_string) sc_format_oid(&ecparams->id, ec_curve_infos[ii].oid_str); ecparams->field_length = ec_curve_infos[ii].size; - sc_log(ctx, "Curve length %"SC_FORMAT_LEN_SIZE_T"u", - ecparams->field_length); - } - else if (ecparams->named_curve) { /* it can be name of curve or OID in ASCII form */ - for (ii=0; ec_curve_infos[ii].name; ii++) { + ecparams->key_type = ec_curve_infos[ii].key_type; + sc_log(ctx, "Curve length %" SC_FORMAT_LEN_SIZE_T "u key_type %d", + ecparams->field_length, ecparams->key_type); + if (mapped_string) { + /* replace the printable string version with the oid */ + free(ecparams->der.value); + ecparams->der.len = strlen(ec_curve_infos[ii].oid_encoded) / 2; + ecparams->der.value = malloc(ecparams->der.len); + if (!ecparams->der.value) + LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); + if (sc_hex_to_bin(ec_curve_infos[ii].oid_encoded, ecparams->der.value, &ecparams->der.len) < 0) { + free(ecparams->der.value); + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + } + } + } else if (ecparams->named_curve) { /* it can be name of curve or OID in ASCII form */ + /* caller did not provide an OID, look for a name or oid_string */ + for (ii = 0; ec_curve_infos[ii].name; ii++) { if (!strcmp(ec_curve_infos[ii].name, ecparams->named_curve)) break; if (!strcmp(ec_curve_infos[ii].oid_str, ecparams->named_curve)) break; } - if (!ec_curve_infos[ii].name) { + if (!ec_curve_infos[ii].name) { sc_log(ctx, "Named curve '%s' not supported", ecparams->named_curve); LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); } @@ -1577,13 +1629,18 @@ sc_pkcs15_fix_ec_parameters(struct sc_context *ctx, struct sc_ec_parameters *ecp LOG_TEST_RET(ctx, rv, "Invalid OID format"); ecparams->field_length = ec_curve_infos[ii].size; + ecparams->key_type = ec_curve_infos[ii].key_type; + sc_log(ctx, "Curve length %" SC_FORMAT_LEN_SIZE_T "u key_type %d", + ecparams->field_length, ecparams->key_type); if (!ecparams->der.value || !ecparams->der.len) { + free(ecparams->der.value); /* just in case */ + ecparams->der.value = NULL; + /* if caller did not provide der OID, fill in */ rv = sc_encode_oid (ctx, &ecparams->id, &ecparams->der.value, &ecparams->der.len); LOG_TEST_RET(ctx, rv, "Cannot encode object ID"); } - } - else + } else LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "EC parameters has to be presented as a named curve or explicit data"); LOG_FUNC_RETURN(ctx, SC_SUCCESS); diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index ce107c02a0..e2832600cd 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -203,19 +203,10 @@ struct sc_pkcs15_pubkey_ec { struct sc_pkcs15_u8 ecpointQ; /* This is NOT DER, just value and length */ }; -struct sc_pkcs15_pubkey_eddsa { - struct sc_pkcs15_u8 pubkey; -}; - struct sc_pkcs15_prkey_ec { struct sc_ec_parameters params; - sc_pkcs15_bignum_t privateD; /* note this is bignum */ - struct sc_pkcs15_u8 ecpointQ; /* This is NOT DER, just value and length */ -}; - -struct sc_pkcs15_prkey_eddsa { - struct sc_pkcs15_u8 pubkey; - struct sc_pkcs15_u8 value; + struct sc_pkcs15_u8 ecpointQ; /* This is NOT DER, just value and length */ + sc_pkcs15_bignum_t privateD; /* note this is bignum */ }; struct sc_pkcs15_pubkey_gostr3410 { @@ -236,7 +227,6 @@ struct sc_pkcs15_pubkey { union { struct sc_pkcs15_pubkey_rsa rsa; struct sc_pkcs15_pubkey_ec ec; - struct sc_pkcs15_pubkey_eddsa eddsa; struct sc_pkcs15_pubkey_gostr3410 gostr3410; } u; }; @@ -249,7 +239,6 @@ struct sc_pkcs15_prkey { union { struct sc_pkcs15_prkey_rsa rsa; struct sc_pkcs15_prkey_ec ec; - struct sc_pkcs15_prkey_eddsa eddsa; struct sc_pkcs15_prkey_gostr3410 gostr3410; struct sc_pkcs15_skey secret; } u; @@ -712,7 +701,7 @@ int sc_pkcs15_decode_pubkey_ec(struct sc_context *, int sc_pkcs15_encode_pubkey_ec(struct sc_context *, struct sc_pkcs15_pubkey_ec *, u8 **, size_t *); int sc_pkcs15_encode_pubkey_eddsa(struct sc_context *, - struct sc_pkcs15_pubkey_eddsa *, u8 **, size_t *); + struct sc_pkcs15_pubkey_ec *, u8 **, size_t *); int sc_pkcs15_decode_pubkey(struct sc_context *, struct sc_pkcs15_pubkey *, const u8 *, size_t); int sc_pkcs15_encode_pubkey(struct sc_context *, diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index 68b7a790dd..400f03cf73 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -163,6 +163,15 @@ const unsigned int gostr3410_paramset_B_oid[] = {1, 2, 643, 2, 2, 35, 2, (unsign const CK_BYTE gostr3410_paramset_C_encoded_oid[] = { 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x03 }; const unsigned int gostr3410_paramset_C_oid[] = {1, 2, 643, 2, 2, 35, 3, (unsigned int)-1}; +#ifdef ENABLE_OPENSSL +// clang-format off +static const struct sc_object_id oid_ED25519 = { { 1, 3, 101, 112, -1 } }; +static const struct sc_object_id oid_ED448 = { { 1, 3, 101, 113, -1 } }; +static const struct sc_object_id oid_X25519 = { { 1, 3, 101, 110, -1 } }; +static const struct sc_object_id oid_X448 = { { 1, 3, 101, 111, -1 } }; +// clang-format on +#endif /* ENABLE_OPENSSL */ + static const struct { const CK_BYTE *encoded_oid; const unsigned int encoded_oid_size; @@ -2339,12 +2348,12 @@ pkcs15_create_private_key(struct sc_pkcs11_slot *slot, struct sc_profile *profil break; case CKK_EC_EDWARDS: args.key.algorithm = SC_ALGORITHM_EDDSA; - /* TODO */ - return CKR_ATTRIBUTE_VALUE_INVALID; + ec = &args.key.u.ec; + break; case CKK_EC_MONTGOMERY: args.key.algorithm = SC_ALGORITHM_XEDDSA; - /* TODO */ - return CKR_ATTRIBUTE_VALUE_INVALID; + ec = &args.key.u.ec; + break; case CKK_EC: args.key.algorithm = SC_ALGORITHM_EC; ec = &args.key.u.ec; @@ -2386,15 +2395,21 @@ pkcs15_create_private_key(struct sc_pkcs11_slot *slot, struct sc_profile *profil case CKA_VALUE: if (key_type == CKK_GOSTR3410) bn = &gost->d; - if (key_type == CKK_EC) + else if (key_type == CKK_EC || + key_type == CKK_EC_EDWARDS || + key_type == CKK_EC_MONTGOMERY) { bn = &ec->privateD; + } break; case CKA_EC_PARAMS: ec->params.der.value = calloc(1, attr->ulValueLen); ec->params.der.len = attr->ulValueLen; rv = attr_extract(attr, ec->params.der.value, &ec->params.der.len); - if (rv != CKR_OK) + if (rv != CKR_OK) { + free(ec->params.der.value); + ec->params.der.value = NULL; goto out; + } if (sc_pkcs15_fix_ec_parameters(p11card->card->ctx, &ec->params) != SC_SUCCESS) return CKR_ATTRIBUTE_VALUE_INVALID; break; @@ -2448,9 +2463,10 @@ pkcs15_create_private_key(struct sc_pkcs11_slot *slot, struct sc_profile *profil rv = sc_to_cryptoki_error(rc, "C_CreateObject"); goto out; } - } - else if (key_type == CKK_EC) { - if (!ec->privateD.len || !ec->params.field_length) { + } else if (key_type == CKK_EC || + key_type == CKK_EC_EDWARDS || + key_type == CKK_EC_MONTGOMERY) { + if (!ec->privateD.len || !ec->params.field_length) { sc_log(context, "Template to store the EC private key is incomplete"); return CKR_TEMPLATE_INCOMPLETE; } @@ -2458,11 +2474,11 @@ pkcs15_create_private_key(struct sc_pkcs11_slot *slot, struct sc_profile *profil rc = sc_pkcs15init_store_private_key(fw_data->p15_card, profile, &args, &key_obj); /* free args now */ - if (key_type == CKK_EC) { + if (key_type == CKK_EC || + key_type == CKK_EC_EDWARDS || + key_type == CKK_EC_MONTGOMERY) { + sc_clear_ec_params(&ec->params); /* allocated above */ - free(ec->params.der.value); - /* in sc_pkcs15_fix_ec_parameters() */ - free(ec->params.named_curve); } if (rc < 0) { rv = sc_to_cryptoki_error(rc, "C_CreateObject"); @@ -2720,9 +2736,13 @@ pkcs15_create_public_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile ec = &args.key.u.ec; break; case CKK_EC_EDWARDS: + args.key.algorithm = SC_ALGORITHM_EDDSA; + ec = &args.key.u.ec; + break; case CKK_EC_MONTGOMERY: - /* TODO: -DEE Do not have real pkcs15 card with EC */ - /* fall through */ + args.key.algorithm = SC_ALGORITHM_XEDDSA; + ec = &args.key.u.ec; + break; default: return CKR_ATTRIBUTE_VALUE_INVALID; } @@ -2764,17 +2784,39 @@ pkcs15_create_public_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile args.usage |= pkcs15_check_bool_cka(attr, SC_PKCS15_PRKEY_USAGE_WRAP); break; case CKA_EC_POINT: - if (key_type == CKK_EC) { + switch (key_type) { + case CKK_EC: if (sc_pkcs15_decode_pubkey_ec(p11card->card->ctx, ec, attr->pValue, attr->ulValueLen) < 0) return CKR_ATTRIBUTE_VALUE_INVALID; + break; + case CKK_EC_EDWARDS: + case CKK_EC_MONTGOMERY: + /* Difference between 25519 and 448 versions set by ec->ecpointQ.len below */ + ec->ecpointQ.value = calloc(1, attr->ulValueLen); + ec->ecpointQ.len = attr->ulValueLen; + rv = attr_extract(attr, ec->ecpointQ.value, &ec->ecpointQ.len); + if (rv != CKR_OK) { + free(ec->ecpointQ.value); + ec->ecpointQ.value = NULL; + ec->ecpointQ.len = 0; + sc_clear_ec_params(&ec->params); + return CKR_ATTRIBUTE_VALUE_INVALID; + } + break; + + default: + return CKR_ATTRIBUTE_VALUE_INVALID; } break; case CKA_EC_PARAMS: ec->params.der.value = calloc(1, attr->ulValueLen); ec->params.der.len = attr->ulValueLen; rv = attr_extract(attr, ec->params.der.value, &ec->params.der.len); - if (rv != CKR_OK) + if (rv != CKR_OK) { + sc_clear_ec_params(&ec->params); + free(ec->params.der.value); return CKR_ATTRIBUTE_VALUE_INVALID; + } break; default: /* ignore unknown attrs, or flag error? */ @@ -2789,12 +2831,27 @@ pkcs15_create_public_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile } } + if (key_type == CKK_EC_EDWARDS) { + if (ec->ecpointQ.len == 32) + ec->params.id = oid_ED25519; + else + ec->params.id = oid_ED448; + } else if (key_type == CKK_EC_MONTGOMERY) { + if (ec->ecpointQ.len == 32) + ec->params.id = oid_X25519; + else + ec->params.id = oid_X448; + } + if (key_type == CKK_RSA) { if (!rsa->modulus.len || !rsa->exponent.len) return CKR_TEMPLATE_INCOMPLETE; - } - else if (key_type == CKK_EC) { - if (!ec->ecpointQ.len || !ec->params.der.value) { + } else if (key_type == CKK_EC || + key_type == CKK_EC_EDWARDS || + key_type == CKK_EC_MONTGOMERY) { + rc = sc_pkcs15_fix_ec_parameters(p11card->card->ctx, &ec->params); + + if (rc || !ec->ecpointQ.len || !ec->params.der.value) { sc_log(context, "Template to store the EC public key is incomplete"); return CKR_TEMPLATE_INCOMPLETE; } @@ -2802,13 +2859,10 @@ pkcs15_create_public_key(struct sc_pkcs11_slot *slot, struct sc_profile *profile rc = sc_pkcs15init_store_public_key(fw_data->p15_card, profile, &args, &key_obj); /* free args now */ - if (key_type == CKK_EC) { - /* allocated above */ - free(ec->params.der.value); - /* in sc_pkcs15_fix_ec_parameters() */ - free(ec->params.named_curve); - /* in sc_pkcs15_decode_pubkey_ec() */ - free(ec->ecpointQ.value); + if (key_type == CKK_EC || + key_type == CKK_EC_EDWARDS || + key_type == CKK_EC_MONTGOMERY) { + sc_clear_ec_params(&ec->params); } if (rc < 0) return sc_to_cryptoki_error(rc, "C_CreateObject"); @@ -3356,8 +3410,7 @@ pkcs15_gen_keypair(struct sc_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism, if (rv != CKR_OK) keybits = 1024; /* Default key size */ /* TODO: check allowed values of keybits */ - } - else if (keytype == CKK_EC) { + } else if (keytype == CKK_EC || keytype == CKK_EC_EDWARDS || keytype == CKK_EC_MONTGOMERY) { struct sc_lv_data *der = &keygen_args.prkey_args.key.u.ec.params.der; void *ptr = NULL; @@ -3368,29 +3421,21 @@ pkcs15_gen_keypair(struct sc_pkcs11_slot *slot, CK_MECHANISM_PTR pMechanism, sc_unlock(p11card->card); return rv; } + } + if (keytype == CKK_EC) { keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_EC; pub_args.key.algorithm = SC_ALGORITHM_EC; - } - else if (keytype == CKK_EC_EDWARDS) { - /* TODO Validate EC_PARAMS contains curveName "edwards25519" or "edwards448" (from RFC 8032) - * or id-Ed25519 or id-Ed448 (or equivalent OIDs in oId field) (from RFC 8410) - * otherwise return CKR_CURVE_NOT_SUPPORTED - */ + } else if (keytype == CKK_EC_EDWARDS) { keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_EDDSA; - pub_args.key.algorithm = SC_ALGORITHM_EDDSA; - return CKR_CURVE_NOT_SUPPORTED; - } - else if (keytype == CKK_EC_MONTGOMERY) { - /* TODO Validate EC_PARAMS contains curveName "curve25519" or "curve448" (from RFC 7748) - * or id-X25519 or id-X448 (or equivalent OIDs in oId field) (from RFC 8410) - * otherwise return CKR_CURVE_NOT_SUPPORTED - */ + keygen_args.prkey_args.usage |= SC_PKCS15_PRKEY_USAGE_SIGN; + pub_args.key.algorithm = SC_ALGORITHM_EDDSA; + } else if (keytype == CKK_EC_MONTGOMERY) { keygen_args.prkey_args.key.algorithm = SC_ALGORITHM_XEDDSA; - pub_args.key.algorithm = SC_ALGORITHM_XEDDSA; - return CKR_CURVE_NOT_SUPPORTED; - } - else { + /* Can not sign. To created a cert, see: openssl x509 -force_pubkey */ + keygen_args.prkey_args.usage |= SC_PKCS15_PRKEY_USAGE_DERIVE; + pub_args.key.algorithm = SC_ALGORITHM_XEDDSA; + } else { /* CKA_KEY_TYPE is set, but keytype isn't correct */ rv = CKR_ATTRIBUTE_VALUE_INVALID; goto kpgen_done; @@ -4909,6 +4954,7 @@ pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, void *object, CK_ case CKA_MODULUS_BITS: case CKA_VALUE: case CKA_SPKI: + case CKA_PUBLIC_KEY_INFO: case CKA_PUBLIC_EXPONENT: case CKA_EC_PARAMS: case CKA_EC_POINT: @@ -5035,26 +5081,25 @@ pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, void *object, CK_ */ case CKA_VALUE: case CKA_SPKI: + case CKA_PUBLIC_KEY_INFO: - if (attr->type != CKA_SPKI && pubkey->pub_info && pubkey->pub_info->direct.raw.value && pubkey->pub_info->direct.raw.len) { + if (attr->type != CKA_SPKI && attr->type != CKA_PUBLIC_KEY_INFO && pubkey->pub_info && pubkey->pub_info->direct.raw.value && pubkey->pub_info->direct.raw.len) { check_attribute_buffer(attr, pubkey->pub_info->direct.raw.len); memcpy(attr->pValue, pubkey->pub_info->direct.raw.value, pubkey->pub_info->direct.raw.len); - } - else if (pubkey->pub_info && pubkey->pub_info->direct.spki.value && pubkey->pub_info->direct.spki.len) { + } else if (pubkey->pub_info && pubkey->pub_info->direct.spki.value && pubkey->pub_info->direct.spki.len) { check_attribute_buffer(attr, pubkey->pub_info->direct.spki.len); memcpy(attr->pValue, pubkey->pub_info->direct.spki.value, pubkey->pub_info->direct.spki.len); - } - else if (pubkey->pub_data) { + } else if (pubkey->pub_data) { unsigned char *value = NULL; size_t len; - if (attr->type != CKA_SPKI) { + if (attr->type != CKA_SPKI && attr->type != CKA_PUBLIC_KEY_INFO) { if (sc_pkcs15_encode_pubkey(context, pubkey->pub_data, &value, &len)) return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_GetAttributeValue"); - } else { - if (sc_pkcs15_encode_pubkey_as_spki(context, pubkey->pub_data, &value, &len)) + } else { + if (sc_pkcs15_encode_pubkey_as_spki(context, pubkey->pub_data, &value, &len)) return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_GetAttributeValue"); - } + } if (attr->pValue == NULL_PTR) { attr->ulValueLen = len; @@ -5070,16 +5115,13 @@ pkcs15_pubkey_get_attribute(struct sc_pkcs11_session *session, void *object, CK_ memcpy(attr->pValue, value, len); free(value); - } - else if (attr->type != CKA_SPKI && pubkey->base.p15_object && pubkey->base.p15_object->content.value && pubkey->base.p15_object->content.len) { + } else if (attr->type != CKA_SPKI && attr->type != CKA_PUBLIC_KEY_INFO && pubkey->base.p15_object && pubkey->base.p15_object->content.value && pubkey->base.p15_object->content.len) { check_attribute_buffer(attr, pubkey->base.p15_object->content.len); memcpy(attr->pValue, pubkey->base.p15_object->content.value, pubkey->base.p15_object->content.len); - } - else if (cert && cert->cert_data) { + } else if (cert && cert->cert_data) { check_attribute_buffer(attr, cert->cert_data->data.len); memcpy(attr->pValue, cert->cert_data->data.value, cert->cert_data->data.len); - } - else { + } else { return CKR_ATTRIBUTE_TYPE_INVALID; } break; @@ -5989,7 +6031,7 @@ get_ec_pubkey_point(struct sc_pkcs15_pubkey *key, CK_ATTRIBUTE_PTR attr) switch (key->algorithm) { case SC_ALGORITHM_EDDSA: case SC_ALGORITHM_XEDDSA: - rc = sc_pkcs15_encode_pubkey_eddsa(context, &key->u.eddsa, &value, &value_len); + rc = sc_pkcs15_encode_pubkey_eddsa(context, &key->u.ec, &value, &value_len); if (rc != SC_SUCCESS) return sc_to_cryptoki_error(rc, NULL); diff --git a/src/pkcs15init/pkcs15-isoApplet.c b/src/pkcs15init/pkcs15-isoApplet.c index 632989d142..64c73e46d9 100644 --- a/src/pkcs15init/pkcs15-isoApplet.c +++ b/src/pkcs15init/pkcs15-isoApplet.c @@ -571,17 +571,7 @@ isoApplet_generate_key_ec(const sc_pkcs15_prkey_info_t *key_info, sc_card_t *car free(pubkey->alg_id); pubkey->alg_id = NULL; } - if(pubkey->u.ec.params.der.value) - { - free(pubkey->u.ec.params.der.value); - pubkey->u.ec.params.der.value = NULL; - pubkey->u.ec.params.der.len = 0; - } - if(pubkey->u.ec.params.named_curve) - { - free(pubkey->u.ec.params.named_curve); - pubkey->u.ec.params.named_curve = NULL; - } + sc_clear_ec_params(&pubkey->u.ec.params); if(pubkey->u.ec.ecpointQ.value) { free(pubkey->u.ec.ecpointQ.value); diff --git a/src/pkcs15init/pkcs15-lib.c b/src/pkcs15init/pkcs15-lib.c index dbb5748b25..b74520c969 100644 --- a/src/pkcs15init/pkcs15-lib.c +++ b/src/pkcs15init/pkcs15-lib.c @@ -176,10 +176,7 @@ static void sc_pkcs15init_free_ec_params(void *ptr) { struct sc_ec_parameters *ecparams = (struct sc_ec_parameters *)ptr; if (ecparams) { - if (ecparams->der.value) - free(ecparams->der.value); - if (ecparams->named_curve) - free(ecparams->named_curve); + sc_clear_ec_params(ecparams); free(ecparams); } } @@ -1303,10 +1300,12 @@ sc_pkcs15init_init_prkdf(struct sc_pkcs15_card *p15card, struct sc_profile *prof keyinfo_gostparams->gostr3410 = keyargs->params.gost.gostr3410; keyinfo_gostparams->gostr3411 = keyargs->params.gost.gostr3411; keyinfo_gostparams->gost28147 = keyargs->params.gost.gost28147; - } - else if (key->algorithm == SC_ALGORITHM_EC) { + } else if (key->algorithm == SC_ALGORITHM_EC || + key->algorithm == SC_ALGORITHM_EDDSA || + key->algorithm == SC_ALGORITHM_XEDDSA) { /* keyargs->key.u.ec.params.der.value is allocated in keyargs, which is on stack */ struct sc_ec_parameters *ecparams = &keyargs->key.u.ec.params; + new_ecparams = calloc(1, sizeof(struct sc_ec_parameters)); if (!new_ecparams) { r = SC_ERROR_OUT_OF_MEMORY; @@ -1603,9 +1602,9 @@ sc_pkcs15init_generate_key(struct sc_pkcs15_card *p15card, struct sc_profile *pr pubkey_args.params.gost = keygen_args->prkey_args.params.gost; r = sc_copy_gost_params(&(pubkey_args.key.u.gostr3410.params), &(keygen_args->prkey_args.key.u.gostr3410.params)); LOG_TEST_GOTO_ERR(ctx, r, "Cannot allocate GOST parameters"); - } - else if (algorithm == SC_ALGORITHM_EC) { - /* needs to be freed in case of failure when pubkey is not set yet */ + } else if (algorithm == SC_ALGORITHM_EC || + algorithm == SC_ALGORITHM_EDDSA || + algorithm == SC_ALGORITHM_XEDDSA) { r = sc_copy_ec_params(&pubkey_args.key.u.ec.params, &keygen_args->prkey_args.key.u.ec.params); LOG_TEST_GOTO_ERR(ctx, r, "Cannot allocate EC parameters"); } @@ -1630,7 +1629,6 @@ sc_pkcs15init_generate_key(struct sc_pkcs15_card *p15card, struct sc_profile *pr if (iid.len) key_info->id = iid; } - pubkey = &pubkey_args.key; if (!pubkey->alg_id) { pubkey->alg_id = calloc(1, sizeof(struct sc_algorithm_id)); @@ -1673,11 +1671,6 @@ sc_pkcs15init_generate_key(struct sc_pkcs15_card *p15card, struct sc_profile *pr err: sc_pkcs15_free_object(object); sc_pkcs15_erase_pubkey(&pubkey_args.key); - if (algorithm == SC_ALGORITHM_EC) { - /* allocated in check_keygen_params_consistency() */ - free(keygen_args->prkey_args.key.u.ec.params.der.value); - keygen_args->prkey_args.key.u.ec.params.der.value = NULL; - } LOG_FUNC_RETURN(ctx, r); } @@ -1913,13 +1906,29 @@ sc_pkcs15init_store_public_key(struct sc_pkcs15_card *p15card, struct sc_profile type = SC_PKCS15_TYPE_PUBKEY_GOSTR3410; break; case SC_ALGORITHM_EC: - type = SC_PKCS15_TYPE_PUBKEY_EC; + case SC_ALGORITHM_EDDSA: + case SC_ALGORITHM_XEDDSA: r = sc_copy_ec_params(&key.u.ec.params, &keyargs->key.u.ec.params); LOG_TEST_GOTO_ERR(ctx, r, "Failed to copy EC public key parameters"); r = sc_pkcs15_fix_ec_parameters(ctx, &key.u.ec.params); LOG_TEST_GOTO_ERR(ctx, r, "Failed to fix EC public key parameters"); + if (keyargs->key.u.ec.ecpointQ.value) { + key.u.ec.ecpointQ.value = malloc(keyargs->key.u.ec.ecpointQ.len); + if (!key.u.ec.ecpointQ.value) { + r = SC_ERROR_OUT_OF_MEMORY; + LOG_TEST_GOTO_ERR(ctx, r, "Failed to copy EC... public key parameters"); + } + } + + if (key.algorithm == SC_ALGORITHM_EC) + type = SC_PKCS15_TYPE_PUBKEY_EC; + else if (key.algorithm == SC_ALGORITHM_EDDSA) + type = SC_PKCS15_TYPE_PUBKEY_EDDSA; + else if (key.algorithm == SC_ALGORITHM_XEDDSA) + type = SC_PKCS15_TYPE_PUBKEY_XEDDSA; + keybits = key.u.ec.params.field_length; break; default: @@ -1960,8 +1969,10 @@ sc_pkcs15init_store_public_key(struct sc_pkcs15_card *p15card, struct sc_profile keyinfo_gostparams->gostr3410 = keyargs->params.gost.gostr3410; keyinfo_gostparams->gostr3411 = keyargs->params.gost.gostr3411; keyinfo_gostparams->gost28147 = keyargs->params.gost.gost28147; - } - else if (key.algorithm == SC_ALGORITHM_EC) { + } else if (key.algorithm == SC_ALGORITHM_EC || + key.algorithm == SC_ALGORITHM_EDDSA || + key.algorithm == SC_ALGORITHM_XEDDSA) { + /* TODO if EC don't write the 0x04 byte to card */ key_info->field_length = keybits; if (key.u.ec.params.der.value) { key_info->params.data = malloc(key.u.ec.params.der.len); @@ -2526,7 +2537,9 @@ check_keygen_params_consistency(struct sc_card *card, struct sc_context *ctx = card->ctx; int i, rv; - if (alg == SC_ALGORITHM_EC && prkey) { + if (prkey && (alg == SC_ALGORITHM_EC || + alg == SC_ALGORITHM_EDDSA || + alg == SC_ALGORITHM_XEDDSA)) { struct sc_ec_parameters *ecparams = &prkey->key.u.ec.params; rv = sc_pkcs15_fix_ec_parameters(ctx, ecparams); @@ -2549,14 +2562,17 @@ check_keygen_params_consistency(struct sc_card *card, LOG_FUNC_RETURN(ctx, SC_SUCCESS); } - if (alg == SC_ALGORITHM_EC && prkey) + if (prkey && (alg == SC_ALGORITHM_EC || + alg == SC_ALGORITHM_EDDSA || + alg == SC_ALGORITHM_XEDDSA)) { /* allocated in sc_pkcs15_fix_ec_parameters */ free(prkey->key.u.ec.params.der.value); + prkey->key.u.ec.params.der.value = NULL; + } LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); } - /* * Check whether the card has native crypto support for this key. */ @@ -2568,13 +2584,21 @@ check_key_compatibility(struct sc_pkcs15_card *p15card, unsigned long alg, struct sc_context *ctx = p15card->card->ctx; struct sc_algorithm_info *info; unsigned int count; + unsigned long talg = alg; LOG_FUNC_CALLED(ctx); + + if (alg == SC_ALGORITHM_EDDSA || alg == SC_ALGORITHM_XEDDSA) + talg = SC_ALGORITHM_EC; /* really testing ecparams */ + count = p15card->card->algorithm_count; for (info = p15card->card->algorithms; count--; info++) { /* don't check flags if none was specified */ - if (info->algorithm != alg || info->key_length != key_length) - continue; + + if (alg != SC_ALGORITHM_EDDSA && alg != SC_ALGORITHM_XEDDSA) { + if (info->algorithm != alg || info->key_length != key_length) + continue; + } if (flags != 0 && ((info->flags & flags) != flags)) continue; @@ -2593,8 +2617,7 @@ check_key_compatibility(struct sc_pkcs15_card *p15card, unsigned long alg, if (info->u._rsa.exponent != exponent) continue; } - } - else if (alg == SC_ALGORITHM_EC) { + } else if (talg == SC_ALGORITHM_EC) { /* includes EDDSA and XEDDSA */ if (!sc_valid_oid(&prkey->u.ec.params.id)) if (sc_pkcs15_fix_ec_parameters(ctx, &prkey->u.ec.params)) LOG_FUNC_RETURN(ctx, SC_ERROR_OBJECT_NOT_VALID); @@ -2754,8 +2777,10 @@ prkey_bits(struct sc_pkcs15_card *p15card, struct sc_pkcs15_prkey *key) } return SC_PKCS15_GOSTR3410_KEYSIZE; case SC_ALGORITHM_EC: - sc_log(ctx, "Private EC key length %"SC_FORMAT_LEN_SIZE_T"u", - key->u.ec.params.field_length); + case SC_ALGORITHM_EDDSA: + case SC_ALGORITHM_XEDDSA: + sc_log(ctx, "Private EC type key length %" SC_FORMAT_LEN_SIZE_T "u", + key->u.ec.params.field_length); if (key->u.ec.params.field_length == 0) { sc_log(ctx, "Invalid EC key length"); return SC_ERROR_OBJECT_NOT_VALID; @@ -2779,6 +2804,10 @@ key_pkcs15_algo(struct sc_pkcs15_card *p15card, unsigned long algorithm) return SC_PKCS15_TYPE_PRKEY_GOSTR3410; case SC_ALGORITHM_EC: return SC_PKCS15_TYPE_PRKEY_EC; + case SC_ALGORITHM_EDDSA: + return SC_PKCS15_TYPE_PRKEY_EDDSA; + case SC_ALGORITHM_XEDDSA: + return SC_PKCS15_TYPE_PRKEY_XEDDSA; case SC_ALGORITHM_DES: return SC_PKCS15_TYPE_SKEY_DES; case SC_ALGORITHM_3DES: diff --git a/src/pkcs15init/pkcs15-openpgp.c b/src/pkcs15init/pkcs15-openpgp.c index 553c8acea8..5a767fd41c 100644 --- a/src/pkcs15init/pkcs15-openpgp.c +++ b/src/pkcs15init/pkcs15-openpgp.c @@ -117,9 +117,8 @@ static int openpgp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, { sc_card_t *card = p15card->card; sc_pkcs15_prkey_info_t *kinfo = (sc_pkcs15_prkey_info_t *) obj->data; - sc_cardctl_openpgp_keystore_info_t key_info; + sc_cardctl_openpgp_keystore_info_t key_info = {0}; int r; - unsigned int i; LOG_FUNC_CALLED(card->ctx); @@ -140,7 +139,10 @@ static int openpgp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_STORE_KEY, &key_info); break; case SC_PKCS15_TYPE_PRKEY_EC: - if (card->type < SC_CARD_TYPE_OPENPGP_V3) { + case SC_PKCS15_TYPE_PRKEY_EDDSA: + case SC_PKCS15_TYPE_PRKEY_XEDDSA: + if (card->type != SC_CARD_TYPE_OPENPGP_GNUK && + card->type < SC_CARD_TYPE_OPENPGP_V3) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "only RSA is supported on this card"); LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); } @@ -151,35 +153,14 @@ static int openpgp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, key_info.key_id = kinfo->id.value[0]; key_info.u.ec.privateD = key->u.ec.privateD.data; key_info.u.ec.privateD_len = key->u.ec.privateD.len; - key_info.u.ec.ecpointQ = key->u.ec.ecpointQ.value; - key_info.u.ec.ecpointQ_len = key->u.ec.ecpointQ.len; - /* extract oid the way we need to import it to OpenPGP Card */ - if (key->u.ec.params.der.len > 2) - key_info.u.ec.oid_len = key->u.ec.params.der.value[1]; - else - LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS); - - for (i=0; (i < key_info.u.ec.oid_len) && (i+2 < key->u.ec.params.der.len); i++){ - key_info.u.ec.oid.value[i] = key->u.ec.params.der.value[i+2]; + if (key->u.ec.ecpointQ.len) { + key_info.u.ec.ecpointQ = malloc(key->u.ec.ecpointQ.len); + if (!key_info.u.ec.ecpointQ) + LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); + memcpy(&key_info.u.ec.ecpointQ, key->u.ec.ecpointQ.value, key->u.ec.ecpointQ.len); } - key_info.u.ec.oid.value[key_info.u.ec.oid_len] = -1; - r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_STORE_KEY, &key_info); - break; - case SC_PKCS15_TYPE_PRKEY_EDDSA: - if (card->type != SC_CARD_TYPE_OPENPGP_GNUK) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "EdDSA keys not supported on this card"); - LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); - } - memset(&key_info, 0, sizeof(sc_cardctl_openpgp_keystore_info_t)); - key_info.algorithm = (kinfo->id.value[0] == SC_OPENPGP_KEY_ENCR) - ? SC_OPENPGP_KEYALGO_ECDH /* ECDH for slot 2 only */ - : SC_OPENPGP_KEYALGO_EDDSA; /* EdDSA for slot 1 and 3 */ - key_info.key_id = kinfo->id.value[0]; - /* TODO Test -- might not work */ - key_info.u.ec.privateD = key->u.ec.privateD.data; - key_info.u.ec.privateD_len = key->u.ec.privateD.len; - key_info.u.ec.ecpointQ = key->u.ec.ecpointQ.value; key_info.u.ec.ecpointQ_len = key->u.ec.ecpointQ.len; + key_info.u.ec.oid = key->u.ec.params.id; r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_STORE_KEY, &key_info); break; default: @@ -286,9 +267,8 @@ static int openpgp_generate_key_ec(sc_card_t *card, sc_pkcs15_object_t *obj, sc_cardctl_openpgp_keygen_info_t key_info; sc_pkcs15_prkey_info_t *required = (sc_pkcs15_prkey_info_t *)obj->data; sc_pkcs15_id_t *kid = &(required->id); - const struct sc_ec_parameters *info_ec = - (struct sc_ec_parameters *) required->params.data; - unsigned int i; + struct sc_ec_parameters *info_ec = + (struct sc_ec_parameters *)required->params.data; int r; LOG_FUNC_CALLED(ctx); @@ -310,29 +290,42 @@ static int openpgp_generate_key_ec(sc_card_t *card, sc_pkcs15_object_t *obj, if (!key_info.key_id) key_info.key_id = kid->value[0]; + key_info.key_type = pubkey->algorithm; + /* set algorithm id based on key reference and key type */ + switch (pubkey->algorithm) { + /* EC is in 04||x||y format + * (field_length + 7)/8 * 2 + 1 in bytes + * len is ecpoint length + format byte + * see section 7.2.14 of 3.3.1 specs + * EDDSA and XEDDSA have no format byte and one number + * (field_length + 7)/8 in bytes + */ + + case SC_ALGORITHM_EC: + key_info.algorithm = (key_info.key_id == SC_OPENPGP_KEY_ENCR) + ? SC_OPENPGP_KEYALGO_ECDH /* ECDH for slot 2 only */ + : SC_OPENPGP_KEYALGO_ECDSA; /* ECDSA for slot 1 and 3 */ + key_info.u.ec.ecpoint_len = 1 + 2 * BYTES4BITS(required->field_length); + break; + case SC_ALGORITHM_EDDSA: + key_info.algorithm = SC_OPENPGP_KEYALGO_EDDSA; /* only sign */ + key_info.u.ec.ecpoint_len = BYTES4BITS(required->field_length); + break; + case SC_ALGORITHM_XEDDSA: + /* TODO may need to look at MSE, and how sign XEDDSA certificate */ + key_info.algorithm = SC_OPENPGP_KEYALGO_ECDH; /* but could be used to sign too */ + key_info.u.ec.ecpoint_len = BYTES4BITS(required->field_length); + break; + } - - /* set algorithm id based on key reference */ - key_info.algorithm = (key_info.key_id == SC_OPENPGP_KEY_ENCR) - ? SC_OPENPGP_KEYALGO_ECDH /* ECDH for slot 2 only */ - : SC_OPENPGP_KEYALGO_ECDSA; /* ECDSA for slot 1 and 3 */ - - /* extract oid the way we need to import it to OpenPGP Card */ + /* copying info_ec.id works for any EC ECDH EdDSA keys */ if (info_ec->der.len > 2) - key_info.u.ec.oid_len = info_ec->der.value[1]; + key_info.u.ec.oid = info_ec->id; /* copy sc_object_id */ else LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); - for (i=0; (i < key_info.u.ec.oid_len) && (i+2 < info_ec->der.len); i++){ - key_info.u.ec.oid.value[i] = info_ec->der.value[i+2]; - } - key_info.u.ec.oid.value[key_info.u.ec.oid_len] = -1; - - /* Prepare buffer */ - key_info.u.ec.ecpoint_len = required->field_length; - key_info.u.ec.ecpoint = malloc(key_info.u.ec.ecpoint_len); - if (key_info.u.ec.ecpoint == NULL) - LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY); + /* save expected length */ + key_info.u.ec.ecpoint_len = BYTES4BITS(required->field_length); /* generate key on card */ r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info); @@ -340,11 +333,13 @@ static int openpgp_generate_key_ec(sc_card_t *card, sc_pkcs15_object_t *obj, /* set pubkey according to response of card */ sc_log(ctx, "Set output ecpoint info"); - pubkey->algorithm = SC_ALGORITHM_EC; + + pubkey->algorithm = key_info.key_type; pubkey->u.ec.ecpointQ.len = key_info.u.ec.ecpoint_len; pubkey->u.ec.ecpointQ.value = malloc(key_info.u.ec.ecpoint_len); if (pubkey->u.ec.ecpointQ.value == NULL) - goto err; + LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY); + memcpy(pubkey->u.ec.ecpointQ.value, key_info.u.ec.ecpoint, key_info.u.ec.ecpoint_len); err: @@ -385,8 +380,9 @@ static int openpgp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card r = openpgp_generate_key_ec(card, obj, pubkey); break; case SC_PKCS15_TYPE_PRKEY_EDDSA: - if (card->type != SC_CARD_TYPE_OPENPGP_GNUK) { - sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "EdDSA is not supported on this card"); + case SC_PKCS15_TYPE_PRKEY_XEDDSA: + if (card->type != SC_CARD_TYPE_OPENPGP_GNUK && card->type < SC_CARD_TYPE_OPENPGP_V3) { + sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "EdDSA or XEDDSA are not supported on this card"); return SC_ERROR_NOT_SUPPORTED; } r = openpgp_generate_key_ec(card, obj, pubkey); diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c index 46f8b735e5..91cfa45c1a 100644 --- a/src/tools/pkcs11-tool.c +++ b/src/tools/pkcs11-tool.c @@ -147,8 +147,23 @@ static struct ec_curve_info { {"secp256k1", "1.3.132.0.10", "06052B8104000A", 256, 0}, {"secp521k1", "1.3.132.0.35", "06052B81040023", 521, 0}, - {"edwards25519","1.3.6.1.4.1159.15.1", "130c656477617264733235353139", 255, CKM_EC_EDWARDS_KEY_PAIR_GEN}, - {"curve25519", "1.3.6.1.4.3029.1.5.1", "130b63757276653235353139", 255, CKM_EC_MONTGOMERY_KEY_PAIR_GEN}, + /* Some of the following may not yet be supported by the OpenSC module, but may be other modules */ + /* OpenPGP extensions by Yubikey and GNUK are not defined in RFCs, so pass by printable string */ + /* See PKCS#11 3.0 2.3.7 */ + {"edwards25519", "1.3.6.1.4.1.11591.15.1", "130c656477617264733235353139", 255, CKM_EC_EDWARDS_KEY_PAIR_GEN}, /* send by curve name */ + {"curve25519", "1.3.6.1.4.1.3029.1.5.1", "130a63757276653235353139", 255, CKM_EC_MONTGOMERY_KEY_PAIR_GEN}, /* send by curve name */ + + /* RFC8410, EDWARDS and MONTGOMERY curves are used by GnuPG and also by OpenSSL */ + + {"X25519", "1.3.101.110", "06032b656e", 255, CKM_EC_MONTGOMERY_KEY_PAIR_GEN}, /* RFC 4810 send by OID */ + {"X448", "1.3.101.111", "06032b656f", 448, CKM_EC_MONTGOMERY_KEY_PAIR_GEN}, /* RFC 4810 send by OID */ + {"Ed25519", "1.3.101.112", "06032b6570", 255, CKM_EC_EDWARDS_KEY_PAIR_GEN}, /* RFC 4810 send by OID */ + {"Ed448", "1.3.101.113", "06032b6571", 448, CKM_EC_EDWARDS_KEY_PAIR_GEN}, /* RFC 4810 send by OID */ + + /* GnuPG openpgp curves as used in gnupg-card are equivalent to RFC8410 OIDs */ + {"cv25519", "1.3.101.110", "06032b656e", 255, CKM_EC_MONTGOMERY_KEY_PAIR_GEN}, + {"ed25519", "1.3.101.112", "06032b6570", 255, CKM_EC_EDWARDS_KEY_PAIR_GEN}, + /* OpenSC card-openpgp.c will map these to what is need on the card */ {NULL, NULL, NULL, 0, 0}, }; @@ -2436,6 +2451,7 @@ static void verify_signature(CK_SLOT_ID slot, CK_SESSION_HANDLE session, unsigned char rs_buffer[512]; bytes = getEC_POINT(session, key, &len); free(bytes); + /* TODO DEE EDDSA and EC_POINT returned in BIT STRING needs some work */ /* * (We only support uncompressed for now) * Uncompressed EC_POINT is DER OCTET STRING of "04||x||y" @@ -4232,12 +4248,24 @@ static CK_RV write_object(CK_SESSION_HANDLE session) n_privkey_attr++; } #if !defined(OPENSSL_NO_EC) -#ifdef EVP_PKEY_ED448 - else if ((pk_type == EVP_PKEY_EC) || (pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448)) { -#else - else if ((pk_type == EVP_PKEY_EC) || (pk_type == EVP_PKEY_ED25519)) { +/* aappeas the precompiler */ +#ifndef EVP_PKEY_ED448 +#define EVP_PKEY_ED448 EVP_PKEY_ED25519 +#endif +#ifndef EVP_PKEY_X448 +#define EVP_PKEY_X448 EVP_PKEY_X25519 #endif - type = (pk_type == EVP_PKEY_EC) ? CKK_EC : CKK_EC_EDWARDS; + + else if ((pk_type == EVP_PKEY_EC) || + (pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448) || + (pk_type == EVP_PKEY_X25519) || (pk_type == EVP_PKEY_X448)) { + + if ((pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448)) + type = CKK_EC_EDWARDS; + else if ((pk_type == EVP_PKEY_X25519) || (pk_type == EVP_PKEY_X448)) + type = CKK_EC_MONTGOMERY; + else + type = CKK_EC; FILL_ATTR(privkey_templ[n_privkey_attr], CKA_KEY_TYPE, &type, sizeof(type)); n_privkey_attr++; @@ -4245,8 +4273,7 @@ static CK_RV write_object(CK_SESSION_HANDLE session) n_privkey_attr++; FILL_ATTR(privkey_templ[n_privkey_attr], CKA_VALUE, gost.private.value, gost.private.len); n_privkey_attr++; - } - else if (pk_type == NID_id_GostR3410_2001) { + } else if (pk_type == NID_id_GostR3410_2001) { type = CKK_GOSTR3410; FILL_ATTR(privkey_templ[n_privkey_attr], CKA_KEY_TYPE, &type, sizeof(type)); @@ -4273,12 +4300,11 @@ static CK_RV write_object(CK_SESSION_HANDLE session) #if !defined(OPENSSL_NO_EC) else if (pk_type == EVP_PKEY_EC) type = CKK_EC; -#ifdef EVP_PKEY_ED448 else if ((pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448)) -#else - else if (pk_type == EVP_PKEY_ED25519) -#endif type = CKK_EC_EDWARDS; + else if ((pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448)) + type = CKK_EC_MONTGOMERY; + else if (pk_type == NID_id_GostR3410_2001) type = CKK_GOSTR3410; #endif @@ -4342,12 +4368,16 @@ static CK_RV write_object(CK_SESSION_HANDLE session) n_pubkey_attr++; } #if !defined(OPENSSL_NO_EC) -#ifdef EVP_PKEY_ED448 - else if ((pk_type == EVP_PKEY_EC) || (pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448)) { -#else - else if ((pk_type == EVP_PKEY_EC) || (pk_type == EVP_PKEY_ED25519)) { -#endif - type = (pk_type == EVP_PKEY_EC) ? CKK_EC : CKK_EC_EDWARDS; + else if ((pk_type == EVP_PKEY_EC) || + (pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448) || + (pk_type == EVP_PKEY_X25519) || (pk_type == EVP_PKEY_X448)) { + + if ((pk_type == EVP_PKEY_ED25519) || (pk_type == EVP_PKEY_ED448)) + type = CKK_EC_EDWARDS; + else if ((pk_type == EVP_PKEY_X25519) || (pk_type == EVP_PKEY_X448)) + type = CKK_EC_MONTGOMERY; + else + type = CKK_EC; FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_KEY_TYPE, &type, sizeof(type)); n_pubkey_attr++; @@ -4355,8 +4385,7 @@ static CK_RV write_object(CK_SESSION_HANDLE session) n_pubkey_attr++; FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_EC_POINT, gost.public.value, gost.public.len); n_pubkey_attr++; - } - else if (pk_type == NID_id_GostR3410_2001) { + } else if (pk_type == NID_id_GostR3410_2001) { type = CKK_GOSTR3410; FILL_ATTR(pubkey_templ[n_pubkey_attr], CKA_KEY_TYPE, &type, sizeof(type)); @@ -4856,18 +4885,17 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE CK_BBOOL _true = TRUE; CK_BBOOL _false = FALSE; CK_OBJECT_HANDLE newkey = 0; + + // clang-format off CK_ATTRIBUTE newkey_template[20] = { - {CKA_TOKEN, &_false, sizeof(_false)}, /* session only object */ - {CKA_CLASS, &newkey_class, sizeof(newkey_class)}, - {CKA_KEY_TYPE, &newkey_type, sizeof(newkey_type)}, - {CKA_SENSITIVE, &_false, sizeof(_false)}, - {CKA_EXTRACTABLE, &_true, sizeof(_true)}, - {CKA_ENCRYPT, &_true, sizeof(_true)}, - {CKA_DECRYPT, &_true, sizeof(_true)}, - {CKA_WRAP, &_true, sizeof(_true)}, - {CKA_UNWRAP, &_true, sizeof(_true)} - }; - int n_attrs = 9; + {CKA_TOKEN, &_false, sizeof(_false) }, /* session only object */ + {CKA_CLASS, &newkey_class, sizeof(newkey_class)}, + {CKA_KEY_TYPE, &newkey_type, sizeof(newkey_type) }, + {CKA_SENSITIVE, &_false, sizeof(_false) }, + {CKA_EXTRACTABLE, &_true, sizeof(_true) }, + }; + // clang-format on + int n_attrs = 5; CK_ECDH1_DERIVE_PARAMS ecdh_parms; CK_RV rv; BIO *bio_in = NULL; @@ -4879,6 +4907,7 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE unsigned char * derp = NULL; size_t der_size = 0; EVP_PKEY *pkey = NULL; + int key_id = 0; /* nid of peer key */ #if OPENSSL_VERSION_NUMBER < 0x30000000L EC_KEY *eckey = NULL; const EC_GROUP *ecgroup = NULL; @@ -4889,7 +4918,7 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE int nid = 0; #endif - printf("Using derive algorithm 0x%8.8lx %s\n", opt_mechanism, p11_mechanism_to_name(mech_mech)); + printf("Using derive algorithm 0x%8.8lx %s\n", mech_mech, p11_mechanism_to_name(mech_mech)); memset(&mech, 0, sizeof(mech)); mech.mechanism = mech_mech; @@ -4905,26 +4934,31 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE #endif if (!pkey) - util_fatal("Cannot read EC key from %s", opt_input); + util_fatal("Cannot read peer EC key from %s", opt_input); + + key_id = EVP_PKEY_id(pkey); + + switch (key_id) { + case EVP_PKEY_EC: /* CKK_EC*/ #if OPENSSL_VERSION_NUMBER < 0x30000000L - eckey = EVP_PKEY_get0_EC_KEY(pkey); - ecpoint = EC_KEY_get0_public_key(eckey); - ecgroup = EC_KEY_get0_group(eckey); + eckey = EVP_PKEY_get0_EC_KEY(pkey); + ecpoint = EC_KEY_get0_public_key(eckey); + ecgroup = EC_KEY_get0_group(eckey); - if (!ecpoint || !ecgroup) - util_fatal("Failed to parse other EC key from %s", opt_input); + if (!ecpoint || !ecgroup) + util_fatal("Failed to parse peer EC key from %s", opt_input); #else - if (EVP_PKEY_get_group_name(pkey, name, sizeof(name), &len) != 1 - || (nid = OBJ_txt2nid(name)) == NID_undef - || (ecgroup = EC_GROUP_new_by_curve_name(nid)) == NULL) - util_fatal("Failed to parse other EC key from %s", opt_input); + if (EVP_PKEY_get_group_name(pkey, name, sizeof(name), &len) != 1 || (nid = OBJ_txt2nid(name)) == NID_undef || (ecgroup = EC_GROUP_new_by_curve_name(nid)) == NULL) + util_fatal("Failed to parse peer EC key from %s", opt_input); #endif - /* both eckeys must be same curve */ - key_len = (EC_GROUP_get_degree(ecgroup) + 7) / 8; - FILL_ATTR(newkey_template[n_attrs], CKA_VALUE_LEN, &key_len, sizeof(key_len)); - n_attrs++; + /* both eckeys must be same curve */ + key_len = (EC_GROUP_get_degree(ecgroup) + 7) / 8; + FILL_ATTR(newkey_template[n_attrs], CKA_VALUE_LEN, &key_len, sizeof(key_len)); + n_attrs++; + break; + } if (opt_allowed_mechanisms_len > 0) { FILL_ATTR(newkey_template[n_attrs], @@ -4934,11 +4968,29 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE } #if OPENSSL_VERSION_NUMBER < 0x30000000L - buf_size = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); - buf = (unsigned char *)malloc(buf_size); - if (buf == NULL) - util_fatal("malloc() failure\n"); - buf_size = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, buf_size, NULL); + switch (key_id) { + case EVP_PKEY_EC: + buf_size = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); + buf = (unsigned char *)malloc(buf_size); + if (buf == NULL) + util_fatal("malloc() failure\n"); + buf_size = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, buf_size, NULL); + break; + case EVP_PKEY_X25519: +#if defined(EVP_PKEY_X448) + case EVP_PKEY_X448: +#endif + EVP_PKEY_get_raw_public_key(pkey, NULL, &buf_size); + if (buf_size == 0) + util_fatal("Unable to get of peer key\n"); + buf = (unsigned char *)malloc(buf_size); + if (buf == NULL) + util_fatal("malloc() failure\n"); + EVP_PKEY_get_raw_public_key(pkey, buf, &buf_size); + break; + default: + util_fatal("Unknown EVP_PKEY_id\n"); + } #else EC_GROUP_free(ecgroup); EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0, &buf_size); @@ -4947,10 +4999,27 @@ derive_ec_key(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, CK_MECHANISM_TYPE if (EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, buf, buf_size, NULL) != 1) { free(buf); - util_fatal("Failed to parse other EC key from %s", opt_input); + util_fatal("Failed to parse peer EC key from %s", opt_input); } #endif + switch (key_id) { + case EVP_PKEY_EC: /* CKK_EC*/ + if (mech_mech != CKM_ECDH1_DERIVE && mech_mech != CKM_ECDH1_COFACTOR_DERIVE) + util_fatal("Peer key %s not usable with %s", "CKK_EC", p11_mechanism_to_name(mech_mech)); + break; + case EVP_PKEY_X25519: /* "CKK_EC_MONTGOMERY */ +#if defined(EVP_PKEY_X448) + case EVP_PKEY_X448: +#endif + if (mech_mech != CKM_ECDH1_DERIVE) + util_fatal("Peer key %s not usable with %s", "CKK_EC_MONTGOMERY", p11_mechanism_to_name(mech_mech)); + break; + default: + util_fatal("Peer key not usable with derive or unknown %i", key_id); + break; + } + if (opt_derive_pass_der) { octet = ASN1_OCTET_STRING_new(); if (octet == NULL) @@ -5005,18 +5074,19 @@ derive_key(CK_SLOT_ID slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key) CK_OBJECT_HANDLE derived_key = 0; int fd; ssize_t sz; + CK_KEY_TYPE key_type = getKEY_TYPE(session, key); if (!opt_mechanism_used) if (!find_mechanism(slot, CKF_DERIVE|opt_allow_sw, NULL, 0, &opt_mechanism)) util_fatal("Derive mechanism not supported"); - switch(opt_mechanism) { - case CKM_ECDH1_COFACTOR_DERIVE: - case CKM_ECDH1_DERIVE: - derived_key= derive_ec_key(session, key, opt_mechanism); + switch (key_type) { + case CKK_EC: + case CKK_EC_MONTGOMERY: + derived_key = derive_ec_key(session, key, opt_mechanism); break; default: - util_fatal("mechanism not supported for derive"); + util_fatal("Key type %lu does not support derive", key_type); break; } @@ -5139,30 +5209,50 @@ show_key(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj) } if (pub) { unsigned char *bytes = NULL; - unsigned long ksize; + unsigned long ksize = 0; unsigned int n; + unsigned long body_len = 0; + + bytes = getEC_POINT(sess, obj, &ksize); + /* + * simple parse of DER BIT STRING 0x03 or OCTET STRING 0x04 + * good to 65K bytes + */ + if (ksize > 3 && (bytes[0] == 0x03 || bytes[0] == 0x04)) { + if (bytes[1] <= 127 && ksize == (unsigned long)(bytes[1] + 2)) { + body_len = ksize - 2; + } else if (bytes[1] == 0x81 && size == ((unsigned long)bytes[2] + 3)) { + body_len = ksize - 3; + } else if (bytes[1] == 0x82 && size == ((unsigned long)(bytes[2] << 8) + (unsigned long)bytes[3] + 4)) { + body_len = ksize - 4; + } + } + /* With BIT STRING remove unused bits in last byte indicator */ + if (body_len > 0 && bytes[0] == 0x03) + body_len--; - bytes = getEC_POINT(sess, obj, &size); - if (key_type == CKK_EC) { + if (key_type == CKK_EC && body_len > 0) { /* - * (We only support uncompressed for now) - * Uncompressed 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; - } else { - /* This should be 255 for ed25519 and 448 for ed448 curves so roughly */ - ksize = size * 8; + * (We only support uncompressed for now) + * Uncompressed EC_POINT is DER OCTET STRING + * or DER BIT STRING "04||x||y" + * So a "256" bit key has x and y of 32 bytes each + * something like: "03 42 00 04|x|y" or "04 41 04||x||y" + * Do simple size calculation based on DER encoding + */ + ksize = (body_len - 1) * 4; + } else if (body_len > 0) { + /* + * EDDSA and XEDDSA in PKCS11 and only one coordinate + */ + ksize = (body_len) * 8; } - printf(" EC_POINT %lu bits\n", ksize); + if (ksize) + printf(" EC_POINT %lu bits\n", ksize); + else + printf(" EC_POINT size unknown"); + if (bytes) { if ((CK_LONG)size > 0) { /* Will print the point here */ printf(" EC_POINT: "); @@ -5779,6 +5869,7 @@ static int read_object(CK_SESSION_HANDLE session) value = getEC_POINT(session, obj, &len); /* PKCS#11-compliant modules should return ASN1_OCTET_STRING */ + /* TODO DEE Should be returned encoded in BIT STRING, Need to accept both */ a = value; os = d2i_ASN1_OCTET_STRING(NULL, &a, (long)len); #if OPENSSL_VERSION_NUMBER < 0x30000000L @@ -5885,8 +5976,13 @@ static int read_object(CK_SESSION_HANDLE session) value = getEC_POINT(session, obj, &len); /* PKCS#11-compliant modules should return ASN1_OCTET_STRING */ + /* TODO DEE should be in BIT STRING accept both */ a = value; os = d2i_ASN1_OCTET_STRING(NULL, &a, (long)len); + if (!os) { + os = d2i_ASN1_BIT_STRING(NULL, &a, (long)&len); + len = (len + 7) / 8; + } if (!os) { util_fatal("cannot decode EC_POINT"); } @@ -8110,6 +8206,7 @@ static void test_ec(CK_SLOT_ID slot, CK_SESSION_HANDLE session) return; } getEC_POINT(session, pub_key, &ec_point_len); + /* TODO only looking at length of encoded EC_POINT. May be in BIT STRING or OCTET STRING */ if (ec_point_len < 5 || ec_point_len > 10000) { printf("ERR: GetAttribute(pubkey, CKA_EC_POINT) doesn't seem to work\n"); return; diff --git a/src/tools/pkcs15-init.c b/src/tools/pkcs15-init.c index 3759e252ee..7bf7b1dcde 100644 --- a/src/tools/pkcs15-init.c +++ b/src/tools/pkcs15-init.c @@ -720,21 +720,42 @@ static const struct alg_spec alg_types_sym[] = { { NULL, -1, 0 } }; +// clang-format off +/* RSA can have a number , default is 2048 */ +/* EC require a curve name */ +/* EDDSA and XEDDSA without a size require a size or curve name or OID */ +/* other EDDSA and XEDDSA can be used alone */ static const struct alg_spec alg_types_asym[] = { - { "rsa", SC_ALGORITHM_RSA, 1024 }, + { "rsa", SC_ALGORITHM_RSA, 2048 }, /* new default */ { "gost2001", SC_ALGORITHM_GOSTR3410, SC_PKCS15_GOSTR3410_KEYSIZE }, { "ec", SC_ALGORITHM_EC, 0 }, + { "EdDSA", SC_ALGORITHM_EDDSA, 0 }, /* RFC 8410 section 8 */ + { "xeddsa", SC_ALGORITHM_XEDDSA, 0 }, + { "ECDH", SC_ALGORITHM_XEDDSA, 0 }, /* RFC 8410 section 8 */ + /* RFC 8410 */ + { "Ed25519", SC_ALGORITHM_EDDSA, 255 }, /* RFC 8410 and gunpg */ + { "Ed448", SC_ALGORITHM_EDDSA, 448 }, + { "X25519", SC_ALGORITHM_XEDDSA, 255 }, + { "X448", SC_ALGORITHM_XEDDSA, 448 }, + /* used by Yubikey and GNUK */ + { "edwards25519", SC_ALGORITHM_EDDSA, 255 }, + { "curve25519", SC_ALGORITHM_XEDDSA, 255 }, + /* gnupg */ + { "cv25519", SC_ALGORITHM_XEDDSA, 255 }, + { NULL, -1, 0 } }; +// clang-format on static int parse_alg_spec(const struct alg_spec *types, const char *spec, unsigned int *keybits, struct sc_pkcs15_prkey *prkey) { - int i, algorithm = -1; + int i, types_idx = -1, algorithm = -1; char *end; for (i = 0; types[i].spec; i++) { if (!strncasecmp(spec, types[i].spec, strlen(types[i].spec))) { + types_idx = i; /* save index of types array */ algorithm = types[i].algorithm; *keybits = types[i].keybits; spec += strlen(types[i].spec); @@ -749,9 +770,18 @@ parse_alg_spec(const struct alg_spec *types, const char *spec, unsigned int *key if (*spec == '/' || *spec == '-' || *spec == ':') spec++; + /* if we have everything for EDDSA or XEDDSA */ + if (*spec == 0x00 && *keybits && (algorithm == SC_ALGORITHM_EDDSA || algorithm == SC_ALGORITHM_XEDDSA) && prkey) { + prkey->u.ec.params.named_curve = strdup(types[types_idx].spec); /* correct case */ + *keybits = types[types_idx].keybits; + return algorithm; + } + if (*spec) { - if (isalpha((unsigned char)*spec) && algorithm == SC_ALGORITHM_EC && prkey) { + if (isalpha((unsigned char)*spec) && algorithm == SC_ALGORITHM_EC && prkey) prkey->u.ec.params.named_curve = strdup(spec); + else if (isalpha((unsigned char)*spec) && (algorithm == SC_ALGORITHM_EDDSA || algorithm == SC_ALGORITHM_XEDDSA) && prkey) { + prkey->u.ec.params.named_curve = strdup(types[types_idx].spec); /* copy correct case */ } else { *keybits = (unsigned)strtoul(spec, &end, 10); if (*end) { diff --git a/src/tools/pkcs15-tool.c b/src/tools/pkcs15-tool.c index 59551c97e5..fc5df6b5eb 100644 --- a/src/tools/pkcs15-tool.c +++ b/src/tools/pkcs15-tool.c @@ -1021,7 +1021,7 @@ static int read_ssh_key(void) unsigned char buf[64]; size_t n, len; - n = pubkey->u.eddsa.pubkey.len; + n = pubkey->u.ec.ecpointQ.len; if (n != 32) { fprintf(stderr, "Wrong public key length\n"); goto fail2; @@ -1039,7 +1039,7 @@ static int read_ssh_key(void) buf[len++] = 0; buf[len++] = 0; buf[len++] = n & 0xff; - memcpy(buf + len, pubkey->u.eddsa.pubkey.value, n); + memcpy(buf + len, pubkey->u.ec.ecpointQ.value, n); len += n; print_ssh_key(outf, alg, obj, buf, len);