From a8aad913ecc632405096b2b61942b2c782cc74f4 Mon Sep 17 00:00:00 2001 From: Oliver Mihatsch Date: Thu, 2 Feb 2023 12:15:14 +0100 Subject: [PATCH] New function EC_GROUP_to_params to convert an EC_GROUP to an array of OSSL_PARAM. Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell Reviewed-by: Todd Short (Merged from https://github.com/openssl/openssl/pull/20205) --- CHANGES.md | 5 ++ crypto/ec/ec_lib.c | 36 ++++++++++++ doc/man3/EC_GROUP_new.pod | 13 +++++ include/openssl/ec.h | 16 ++++++ test/ectest.c | 113 ++++++++++++++++++++++++++++++++++++++ util/libcrypto.num | 1 + 6 files changed, 184 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 1f76a23d2f..77a053a425 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -25,6 +25,11 @@ OpenSSL 3.2 ### Changes between 3.1 and 3.2 [xx XXX xxxx] + * Added EC_GROUP_to_params which creates an OSSL_PARAM array + from a given EC_GROUP. + + *Oliver Mihatsch* + * Added support for Hybrid Public Key Encryption (HPKE) as defined in RFC9180. HPKE is required for TLS Encrypted ClientHello (ECH), Message Layer Security (MLS) and other IETF specifications. diff --git a/crypto/ec/ec_lib.c b/crypto/ec/ec_lib.c index 2e7139cbdd..9e262b427d 100644 --- a/crypto/ec/ec_lib.c +++ b/crypto/ec/ec_lib.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "crypto/ec.h" #include "internal/nelem.h" #include "ec_local.h" @@ -1748,3 +1749,38 @@ EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[], return group; #endif /* FIPS_MODULE */ } + +OSSL_PARAM *EC_GROUP_to_params(const EC_GROUP *group, OSSL_LIB_CTX *libctx, + const char *propq, BN_CTX *bnctx) +{ + OSSL_PARAM_BLD *tmpl = NULL; + BN_CTX *new_bnctx = NULL; + unsigned char *gen_buf = NULL; + OSSL_PARAM *params = NULL; + + if (group == NULL) + goto err; + + tmpl = OSSL_PARAM_BLD_new(); + if (tmpl == NULL) + goto err; + + if (bnctx == NULL) + bnctx = new_bnctx = BN_CTX_new_ex(libctx); + if (bnctx == NULL) + goto err; + BN_CTX_start(bnctx); + + if (!ossl_ec_group_todata( + group, tmpl, NULL, libctx, propq, bnctx, &gen_buf)) + goto err; + + params = OSSL_PARAM_BLD_to_param(tmpl); + + err: + OSSL_PARAM_BLD_free(tmpl); + OPENSSL_free(gen_buf); + BN_CTX_end(bnctx); + BN_CTX_free(new_bnctx); + return params; +} diff --git a/doc/man3/EC_GROUP_new.pod b/doc/man3/EC_GROUP_new.pod index b6d67b6176..d7f8d001c2 100644 --- a/doc/man3/EC_GROUP_new.pod +++ b/doc/man3/EC_GROUP_new.pod @@ -5,6 +5,7 @@ EC_GROUP_get_ecparameters, EC_GROUP_get_ecpkparameters, EC_GROUP_new_from_params, +EC_GROUP_to_params, EC_GROUP_new_from_ecparameters, EC_GROUP_new_from_ecpkparameters, EC_GROUP_new, @@ -30,6 +31,8 @@ Functions for creating and destroying EC_GROUP objects EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[], OSSL_LIB_CTX *libctx, const char *propq); + OSSL_PARAM *EC_GROUP_to_params(const EC_GROUP *group, OSSL_LIB_CTX *libctx, + const char *propq, BN_CTX *bnctx); EC_GROUP *EC_GROUP_new_from_ecparameters(const ECPARAMETERS *params); EC_GROUP *EC_GROUP_new_from_ecpkparameters(const ECPKPARAMETERS *params); void EC_GROUP_free(EC_GROUP *group); @@ -107,6 +110,16 @@ The values for I and I may be NULL. The I that can be used are described in L(7)|EVP_PKEY-EC(7)/Common EC parameters>. +EC_GROUP_to_params creates an OSSL_PARAM array with the corresponding parameters +describing the given EC_GROUP. The resulting parameters may contain parameters +describing a named or explicit curve depending on the EC_GROUP. +The library context I (see L) and property query string +I are used to fetch algorithms from providers. +I is an optional preallocated BN_CTX (to save the overhead of allocating +and freeing the structure in a loop). +The values for I, I and I may be NULL. +The caller is responsible for freeing the OSSL_PARAM pointer returned. + EC_GROUP_new_from_ecparameters() will create a group from the specified I and EC_GROUP_new_from_ecpkparameters() will create a group from the specific PK diff --git a/include/openssl/ec.h b/include/openssl/ec.h index be9fb2f089..3089dfccd4 100644 --- a/include/openssl/ec.h +++ b/include/openssl/ec.h @@ -460,6 +460,22 @@ EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a, EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[], OSSL_LIB_CTX *libctx, const char *propq); +/** + * Creates an OSSL_PARAM array with the parameters describing the given + * EC_GROUP. + * The resulting parameters may contain an explicit or a named curve depending + * on the EC_GROUP. + * \param group pointer to the EC_GROUP object + * \param libctx The associated library context or NULL for the default + * context + * \param propq A property query string + * \param bnctx BN_CTX object (optional) + * \return newly created OSSL_PARAM array with the parameters + * describing the given EC_GROUP or NULL if an error occurred + */ +OSSL_PARAM *EC_GROUP_to_params(const EC_GROUP *group, OSSL_LIB_CTX *libctx, + const char *propq, BN_CTX *bnctx); + /** * Creates a EC_GROUP object with a curve specified by a NID * \param libctx The associated library context or NULL for the default diff --git a/test/ectest.c b/test/ectest.c index c0337e1c95..f93fd76811 100644 --- a/test/ectest.c +++ b/test/ectest.c @@ -2054,6 +2054,118 @@ err: return r; } +/* + * This test validates converting an EC_GROUP to an OSSL_PARAM array + * using EC_GROUP_to_params(). A named and an explicit curve are tested. + */ +static int ossl_parameter_test(void) +{ + EC_GROUP *group_nmd = NULL, *group_nmd2 = NULL, *group_nmd3 = NULL; + EC_GROUP *group_exp = NULL, *group_exp2 = NULL; + OSSL_PARAM *params_nmd = NULL, *params_nmd2 = NULL; + OSSL_PARAM *params_exp = NULL, *params_exp2 = NULL; + unsigned char *buf = NULL, *buf2 = NULL; + BN_CTX *bn_ctx = NULL; + OSSL_PARAM_BLD *bld = NULL; + BIGNUM *p, *a, *b; + const EC_POINT *group_gen = NULL; + size_t bsize; + int r = 0; + + if (!TEST_ptr(bn_ctx = BN_CTX_new())) + goto err; + + /* test named curve */ + if (!TEST_ptr(group_nmd = EC_GROUP_new_by_curve_name(NID_secp384r1)) + /* test with null BN_CTX */ + || !TEST_ptr(params_nmd = EC_GROUP_to_params( + group_nmd, NULL, NULL, NULL)) + || !TEST_ptr(group_nmd2 = EC_GROUP_new_from_params( + params_nmd, NULL, NULL)) + || !TEST_int_eq(EC_GROUP_cmp(group_nmd, group_nmd2, NULL), 0) + /* test with BN_CTX set */ + || !TEST_ptr(params_nmd2 = EC_GROUP_to_params( + group_nmd, NULL, NULL, bn_ctx)) + || !TEST_ptr(group_nmd3 = EC_GROUP_new_from_params( + params_nmd2, NULL, NULL)) + || !TEST_int_eq(EC_GROUP_cmp(group_nmd, group_nmd3, NULL), 0)) + goto err; + + /* test explicit curve */ + if (!TEST_ptr(bld = OSSL_PARAM_BLD_new())) + goto err; + + BN_CTX_start(bn_ctx); + p = BN_CTX_get(bn_ctx); + a = BN_CTX_get(bn_ctx); + b = BN_CTX_get(bn_ctx); + + if (!TEST_true(EC_GROUP_get_curve(group_nmd, p, a, b, bn_ctx)) + || !TEST_true(OSSL_PARAM_BLD_push_utf8_string( + bld, OSSL_PKEY_PARAM_EC_FIELD_TYPE, SN_X9_62_prime_field, 0)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_P, p)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_A, a)) + || !TEST_true(OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_B, b))) + goto err; + + if (EC_GROUP_get0_seed(group_nmd) != NULL) { + if (!TEST_true(OSSL_PARAM_BLD_push_octet_string( + bld, OSSL_PKEY_PARAM_EC_SEED, EC_GROUP_get0_seed(group_nmd), + EC_GROUP_get_seed_len(group_nmd)))) + goto err; + } + if (EC_GROUP_get0_cofactor(group_nmd) != NULL) { + if (!TEST_true(OSSL_PARAM_BLD_push_BN( + bld, OSSL_PKEY_PARAM_EC_COFACTOR, + EC_GROUP_get0_cofactor(group_nmd)))) + goto err; + } + + if (!TEST_ptr(group_gen = EC_GROUP_get0_generator(group_nmd)) + || !TEST_size_t_gt(bsize = EC_POINT_point2oct( + group_nmd, EC_GROUP_get0_generator(group_nmd), + POINT_CONVERSION_UNCOMPRESSED, NULL, 0, bn_ctx), 0) + || !TEST_ptr(buf2 = OPENSSL_malloc(bsize)) + || !TEST_size_t_eq(EC_POINT_point2oct( + group_nmd, EC_GROUP_get0_generator(group_nmd), + POINT_CONVERSION_UNCOMPRESSED, buf2, bsize, bn_ctx), bsize) + || !TEST_true(OSSL_PARAM_BLD_push_octet_string( + bld, OSSL_PKEY_PARAM_EC_GENERATOR, buf2, bsize)) + || !TEST_true(OSSL_PARAM_BLD_push_BN( + bld, OSSL_PKEY_PARAM_EC_ORDER, EC_GROUP_get0_order(group_nmd)))) + goto err; + + if (!TEST_ptr(params_exp = OSSL_PARAM_BLD_to_param(bld)) + || !TEST_ptr(group_exp = + EC_GROUP_new_from_params(params_exp, NULL, NULL)) + || !TEST_ptr(params_exp2 = + EC_GROUP_to_params(group_exp, NULL, NULL, NULL)) + || !TEST_ptr(group_exp2 = + EC_GROUP_new_from_params(params_exp2, NULL, NULL)) + || !TEST_int_eq(EC_GROUP_cmp(group_exp, group_exp2, NULL), 0)) + goto err; + + r = 1; + +err: + EC_GROUP_free(group_nmd); + EC_GROUP_free(group_nmd2); + EC_GROUP_free(group_nmd3); + OSSL_PARAM_free(params_nmd); + OSSL_PARAM_free(params_nmd2); + OPENSSL_free(buf); + + EC_GROUP_free(group_exp); + EC_GROUP_free(group_exp2); + BN_CTX_end(bn_ctx); + BN_CTX_free(bn_ctx); + OPENSSL_free(buf2); + OSSL_PARAM_BLD_free(bld); + OSSL_PARAM_free(params_exp); + OSSL_PARAM_free(params_exp2); + return r; +} + /*- * random 256-bit explicit parameters curve, cofactor absent * order: 0x0c38d96a9f892b88772ec2e39614a82f4f (132 bit) @@ -3015,6 +3127,7 @@ int setup_tests(void) return 0; ADD_TEST(parameter_test); + ADD_TEST(ossl_parameter_test); ADD_TEST(cofactor_range_test); ADD_ALL_TESTS(cardinality_test, crv_len); ADD_TEST(prime_field_tests); diff --git a/util/libcrypto.num b/util/libcrypto.num index 2487861a18..78fd4813ee 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5512,3 +5512,4 @@ BIO_get_wpoll_descriptor ? 3_2_0 EXIST::FUNCTION: ASN1_item_unpack_ex ? 3_2_0 EXIST::FUNCTION: PKCS12_SAFEBAG_get1_cert_ex ? 3_2_0 EXIST::FUNCTION: PKCS12_SAFEBAG_get1_crl_ex ? 3_2_0 EXIST::FUNCTION: +EC_GROUP_to_params ? 3_2_0 EXIST::FUNCTION:EC -- 2.39.2