erlang/otp-0020-crypto-Try-generate-ec-key-by-name-if-possible.patch
Peter Lemenkov 9aea5ce05a Reenable OpenSSL 3
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
2023-08-14 20:15:10 +02:00

285 lines
12 KiB
Diff

From: Sverker Eriksson <sverker@erlang.org>
Date: Wed, 14 Jun 2023 22:00:35 +0200
Subject: [PATCH] crypto: Try generate ec key by name if possible
OpenSSL 3 FIPS does only accept named ec curves.
So we try that first, and if it fails we retry
with the params passed down by crypto.erl.
diff --git a/lib/crypto/c_src/ec.c b/lib/crypto/c_src/ec.c
index af5f5d6f4a..49e1da4fe4 100644
--- a/lib/crypto/c_src/ec.c
+++ b/lib/crypto/c_src/ec.c
@@ -28,7 +28,8 @@
int get_curve_definition(ErlNifEnv* env, ERL_NIF_TERM *ret, ERL_NIF_TERM def,
OSSL_PARAM params[], int *i,
- size_t *order_size)
+ size_t *order_size,
+ struct get_curve_def_ctx* gcd)
{
const ERL_NIF_TERM* curve;
int c_arity = -1;
@@ -40,6 +41,7 @@ int get_curve_definition(ErlNifEnv* env, ERL_NIF_TERM *ret, ERL_NIF_TERM def,
int arity = -1;
const ERL_NIF_TERM* curve_tuple;
+
/* Here are two random curve definition examples, one prime_field and
one characteristic_two_field. Both are from the crypto/src/crypto_ec_curves.erl.
@@ -79,6 +81,23 @@ int get_curve_definition(ErlNifEnv* env, ERL_NIF_TERM *ret, ERL_NIF_TERM def,
c_arity != 5)
assign_goto(*ret, err, EXCP_ERROR_N(env, 1, "Bad curve def. Expect 5-tuple."));
+ if (gcd->use_curve_name
+ && curve_tuple[1] != atom_undefined
+ && enif_get_atom(env, curve_tuple[1], gcd->curve_name,
+ sizeof(gcd->curve_name), ERL_NIF_LATIN1)) {
+ ErlNifBinary order_bin;
+ params[(*i)++] = OSSL_PARAM_construct_utf8_string("group", gcd->curve_name, 0);
+
+ if (order_size) {
+ if (!enif_inspect_binary(env, curve[3], &order_bin))
+ assign_goto(*ret, err, EXCP_ERROR_N(env, 1, "Bad order"));
+ *order_size = order_bin.size;
+ }
+ gcd->use_curve_name = 1;
+ return 1;
+ }
+ gcd->use_curve_name = 0;
+
if (!get_ossl_octet_string_param_from_bin(env, "generator", curve[2], &params[(*i)++]))
assign_goto(*ret, err, EXCP_ERROR_N(env, 1, "Bad Generator (Point)"));
@@ -211,6 +230,7 @@ int get_ec_public_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey)
int tpl_arity;
int i = 0;
OSSL_PARAM params[15];
+ struct get_curve_def_ctx gcd;
EVP_PKEY_CTX *pctx = NULL;
if (!enif_get_tuple(env, key, &tpl_arity, &tpl_terms) ||
@@ -222,19 +242,27 @@ int get_ec_public_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey)
if (!get_ossl_octet_string_param_from_bin(env, "pub", tpl_terms[1], &params[i++]))
assign_goto(ret, err, EXCP_BADARG_N(env, 0, "Bad public key"));
- if (!get_curve_definition(env, &ret, tpl_terms[0], params, &i, NULL))
+ if (!(pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)))
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't make EVP_PKEY_CTX"));
+
+ gcd.use_curve_name = 1;
+retry_without_name:
+ if (!get_curve_definition(env, &ret, tpl_terms[0], params, &i, NULL, &gcd))
goto err;
params[i++] = OSSL_PARAM_construct_end();
- if (!(pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)))
- assign_goto(ret, err, EXCP_ERROR(env, "Can't make EVP_PKEY_CTX"));
-
if (EVP_PKEY_fromdata_init(pctx) <= 0)
assign_goto(ret, err, EXCP_ERROR(env, "Can't init fromdata"));
- if (EVP_PKEY_fromdata(pctx, pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
+ if (EVP_PKEY_fromdata(pctx, pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0) {
+ if (gcd.use_curve_name) {
+ gcd.use_curve_name = 0;
+ i = 1;
+ goto retry_without_name;
+ }
assign_goto(ret, err, EXCP_ERROR(env, "Can't do fromdata"));
+ }
if (!*pkey)
assign_goto(ret, err, EXCP_ERROR(env, "Couldn't get a public key"));
@@ -256,24 +284,33 @@ static int get_ec_private_key_2(ErlNifEnv* env,
{
int i = 0;
OSSL_PARAM params[15];
+ struct get_curve_def_ctx gcd;
EVP_PKEY_CTX *pctx = NULL;
if (!get_ossl_BN_param_from_bin(env, "priv", key, &params[i++]))
assign_goto(*ret, err, EXCP_BADARG_N(env, 0, "Bad private key"));
- if (!get_curve_definition(env, ret, curve, params, &i, order_size))
+ if (!(pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)))
+ assign_goto(*ret, err, EXCP_ERROR(env, "Can't make EVP_PKEY_CTX"));
+
+ gcd.use_curve_name = 1;
+retry_without_name:
+ if (!get_curve_definition(env, ret, curve, params, &i, order_size, &gcd))
goto err;
params[i++] = OSSL_PARAM_construct_end();
- if (!(pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)))
- assign_goto(*ret, err, EXCP_ERROR(env, "Can't make EVP_PKEY_CTX"));
-
if (EVP_PKEY_fromdata_init(pctx) <= 0)
assign_goto(*ret, err, EXCP_ERROR(env, "Can't init fromdata"));
- if (EVP_PKEY_fromdata(pctx, pkey, EVP_PKEY_KEYPAIR, params) <= 0)
+ if (EVP_PKEY_fromdata(pctx, pkey, EVP_PKEY_KEYPAIR, params) <= 0) {
+ if (gcd.use_curve_name) {
+ gcd.use_curve_name = 0;
+ i = 1;
+ goto retry_without_name;
+ }
assign_goto(*ret, err, EXCP_ERROR(env, "Can't do fromdata"));
+ }
if (!*pkey)
assign_goto(*ret, err, EXCP_ERROR(env, "Couldn't get a private key"));
@@ -316,9 +353,10 @@ ERL_NIF_TERM ec_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
ERL_NIF_TERM ret = atom_undefined;
int i = 0;
OSSL_PARAM params[15];
+ struct get_curve_def_ctx gcd;
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *pkey = NULL, *peer_pkey = NULL;
- size_t sz, order_size;
+ size_t sz, order_size = 0;
BIGNUM *priv_bn = NULL;
ErlNifBinary pubkey_bin;
@@ -338,26 +376,36 @@ ERL_NIF_TERM ec_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
}
else
{
+ /* Neither the private nor the public key is known, so we generate the pair: */
+ if (!(pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)))
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_new_from_name"));
+
+ gcd.use_curve_name = 1;
+ retry_without_name:
/* PrivKey (that is, argv[1]) == atom_undefined */
- if (!get_curve_definition(env, &ret, argv[0], params, &i, &order_size))
+ if (!get_curve_definition(env, &ret, argv[0], params, &i,
+ &order_size, &gcd))
// INSERT "ret" parameter in get_curve_definition !!
assign_goto(ret, err, EXCP_BADARG_N(env, 0, "Couldn't get Curve definition"));
params[i++] = OSSL_PARAM_construct_end();
- /* Neither the private nor the public key is known, so we generate the pair: */
- if (!(pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)))
- assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_new_from_name"));
-
if (EVP_PKEY_keygen_init(pctx) <= 0)
assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_keygen_init"));
if (!EVP_PKEY_CTX_set_params(pctx, params))
assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_set_params"));
-
- if (!EVP_PKEY_generate(pctx, &pkey))
+
+ if (!EVP_PKEY_generate(pctx, &pkey)) {
+ if (gcd.use_curve_name) {
+ gcd.use_curve_name = 0;
+ i = 0;
+ goto retry_without_name;
+ }
assign_goto(ret, err, EXCP_ERROR(env, "Couldn't generate EC key"));
-
+ }
+
+
/* Get the two keys, pub as binary and priv as BN */
if (!EVP_PKEY_get_octet_string_param(pkey, "encoded-pub-key", NULL, 0, &sz))
assign_goto(ret, err, EXCP_ERROR(env, "Can't get pub octet string size"));
@@ -375,6 +423,8 @@ ERL_NIF_TERM ec_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
assign_goto(ret, err, EXCP_BADARG_N(env, 1, "Couldn't get priv key bytes"));
}
+ if (order_size == 0)
+ order_size = BN_num_bytes(priv_bn);
ret = enif_make_tuple2(env,
enif_make_binary(env, &pubkey_bin),
bn2term(env, order_size, priv_bn));
diff --git a/lib/crypto/c_src/ec.h b/lib/crypto/c_src/ec.h
index e53986d64e..f0b0b96207 100644
--- a/lib/crypto/c_src/ec.h
+++ b/lib/crypto/c_src/ec.h
@@ -26,9 +26,17 @@
#if defined(HAVE_EC)
# if defined(HAS_3_0_API)
+
+struct get_curve_def_ctx
+{
+ char curve_name[20];
+ int use_curve_name;
+};
+
int get_curve_definition(ErlNifEnv* env, ERL_NIF_TERM *ret, ERL_NIF_TERM def,
OSSL_PARAM params[], int *i,
- size_t *order_size);
+ size_t *order_size,
+ struct get_curve_def_ctx*);
# endif /* HAS_3_0_API */
# if ! defined(HAS_3_0_API)
diff --git a/lib/crypto/c_src/ecdh.c b/lib/crypto/c_src/ecdh.c
index 7509d9cb84..f1b0f7eb28 100644
--- a/lib/crypto/c_src/ecdh.c
+++ b/lib/crypto/c_src/ecdh.c
@@ -42,6 +42,7 @@ ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
int ret_bin_alloc = 0;
int i = 0, i_key = 0;
OSSL_PARAM params[15];
+ struct get_curve_def_ctx gcd;
EVP_PKEY_CTX *own_pctx = NULL, *peer_pctx = NULL, *pctx_gen = NULL;
EVP_PKEY *own_pkey = NULL, *peer_pkey = NULL;
int err;
@@ -53,21 +54,29 @@ ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
if (!get_ossl_octet_string_param_from_bin(env, "pub", argv[0], &params[i++]))
assign_goto(ret, err, EXCP_BADARG_N(env, 0, "Bad peer public key; binary expected"));
+ /* Build the remote public key in peer_pkey */
+ peer_pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
+
+ gcd.use_curve_name = 1;
+retry_without_name:
/* Curve definition/name */
- if (!get_curve_definition(env, &ret, argv[1], params, &i, NULL))
+ if (!get_curve_definition(env, &ret, argv[1], params, &i, NULL, &gcd))
goto err;
/* End of params */
params[i++] = OSSL_PARAM_construct_end();
- /* Build the remote public key in peer_pkey */
- peer_pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
-
if (EVP_PKEY_fromdata_init(peer_pctx) <= 0)
assign_goto(ret, err, EXCP_ERROR(env, "Can't init fromdata"));
- if (EVP_PKEY_fromdata(peer_pctx, &peer_pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
+ if (EVP_PKEY_fromdata(peer_pctx, &peer_pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0) {
+ if (gcd.use_curve_name) {
+ gcd.use_curve_name = 0;
+ i = 1;
+ goto retry_without_name;
+ }
assign_goto(ret, err, EXCP_ERROR(env, "Can't do fromdata"));
+ }
if (!peer_pkey)
assign_goto(ret, err, EXCP_ERROR(env, "No peer_pkey"));
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 915a07a39e..f59aa277ca 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -3565,7 +3565,7 @@ dss_params() ->
16#e3a93c09da6f560e4d483a382a4c546f2335c36a4c35ac1463c08a3e6dd415df56fdc537f25fd5372be63e4f5300780b782f1acd01c8b4eb33414615fd0ea82573acba7ef83f5a943854151afc2d7dfe121fb8cd03335b065b549c5dcc606be9052483bc284e12ac3c8dba09b426e08402030e70bc1cc2bf8957c4ba0630f3f32ad689389ac47443176063f247d9e2296b3ea5b5bc2335828ea1a080ed35918dee212fd031279d1b894f01afec523833669eac031a420e540ba1320a59c424a3e5849a460a56bcb001647885b1433c4f992971746bfe2977ce7259c550b551a6c35761e4a41af764e8d92132fcc0a59d1684eab90d863f29f41cf7578faa908c].
ec_key_named() ->
- Curve = hd(crypto:ec_curves()),
+ Curve = secp224r1, %hd(crypto:ec_curves()),
{D2_pub, D2_priv} = crypto:generate_key(ecdh, Curve),
{[D2_priv, Curve], [D2_pub, Curve]}.