diff --git a/src/objects.c b/src/objects.c index 9fe0f33b..640e1d4c 100644 --- a/src/objects.c +++ b/src/objects.c @@ -2502,11 +2502,21 @@ static CK_RV prep_rsa_find(P11PROV_CTX *ctx, const OSSL_PARAM params[], return CKR_OK; } +/* P-521 ~ 133 bytes, this should suffice */ +#define MAX_EC_PUB_KEY_SIZE 150 static CK_RV prep_ec_find(P11PROV_CTX *ctx, const OSSL_PARAM params[], struct pool_find_ctx *findctx) { EC_GROUP *group = NULL; + EC_POINT *point = NULL; + BN_CTX *bn_ctx = NULL; + int ret, plen; + OSSL_PARAM tmp; + const OSSL_PARAM *p; + OSSL_PARAM pub_key[2] = { 0 }; + uint8_t pub_data[MAX_EC_PUB_KEY_SIZE]; + const char *curve_name = NULL; int curve_nid; unsigned char *ecparams = NULL; @@ -2518,13 +2528,6 @@ static CK_RV prep_ec_find(P11PROV_CTX *ctx, const OSSL_PARAM params[], } findctx->numattrs = 0; - rv = param_to_attr(ctx, params, OSSL_PKEY_PARAM_PUB_KEY, &findctx->attrs[0], - CKA_P11PROV_PUB_KEY, false); - if (rv != CKR_OK) { - return rv; - } - findctx->numattrs++; - group = EC_GROUP_new_from_params(params, p11prov_ctx_get_libctx(ctx), NULL); if (!group) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Unable to decode ec group"); @@ -2532,6 +2535,60 @@ static CK_RV prep_ec_find(P11PROV_CTX *ctx, const OSSL_PARAM params[], goto done; } + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY); + if (!p) { + P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s", + OSSL_PKEY_PARAM_PUB_KEY); + EC_GROUP_free(group); + return CKR_KEY_INDIGESTIBLE; + } + + /* Providers may export in any format - OpenSSL < 3.0.8 + * ignores the "point-format" OSSL_PARAM and unconditionally uses + * compressed format: + * - https://github.com/openssl/openssl/pull/16624 + * - https://github.com/openssl/openssl/issues/16595 + * + * Convert from compressed to uncompressed if necessary + */ + if (((char *)p->data)[0] == '\x02' || ((char *)p->data)[0] == '\x03') { + P11PROV_debug("OpenSSL 3.0.7 BUG - received compressed EC public key"); + pub_key[0].key = OSSL_PKEY_PARAM_PUB_KEY; + pub_key[0].data_type = p->data_type; + pub_key[0].data = pub_data; + + point = EC_POINT_new(group); + bn_ctx = BN_CTX_new(); + ret = EC_POINT_oct2point(group, point, p->data, p->data_size, bn_ctx); + if (!ret) { + goto done0; + } + + plen = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, + pub_key[0].data, MAX_EC_PUB_KEY_SIZE, bn_ctx); + if (!plen) { + ret = CKR_KEY_INDIGESTIBLE; + goto done0; + } + + pub_key[0].data_size = plen; + ret = param_to_attr(ctx, pub_key, OSSL_PKEY_PARAM_PUB_KEY, + &findctx->attrs[0], CKA_P11PROV_PUB_KEY, false); + if (ret != CKR_OK) { + goto done0; + } + EC_POINT_free(point); + BN_CTX_free(bn_ctx); + } else { + rv = param_to_attr(ctx, params, OSSL_PKEY_PARAM_PUB_KEY, + &findctx->attrs[0], CKA_P11PROV_PUB_KEY, false); + if (rv != CKR_OK) { + return rv; + } + } + + findctx->numattrs++; + curve_nid = EC_GROUP_get_curve_name(group); if (curve_nid != NID_undef) { curve_name = OSSL_EC_curve_nid2name(curve_nid); @@ -2583,11 +2640,17 @@ static CK_RV prep_ec_find(P11PROV_CTX *ctx, const OSSL_PARAM params[], findctx->bit_size = EC_GROUP_order_bits(group); findctx->key_size = (findctx->bit_size + 7) / 8; rv = CKR_OK; - done: OPENSSL_free(ecparams); EC_GROUP_free(group); return rv; + +done0: + + EC_GROUP_free(group); + EC_POINT_free(point); + BN_CTX_free(bn_ctx); + return ret; } static CK_RV return_dup_key(P11PROV_OBJ *dst, P11PROV_OBJ *src)