a0135c1679
Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
285 lines
12 KiB
Diff
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], ¶ms[(*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], ¶ms[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, ¶ms[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], ¶ms[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 15fd40be1d..cf6ef5dde3 100644
|
|
--- a/lib/crypto/test/crypto_SUITE.erl
|
|
+++ b/lib/crypto/test/crypto_SUITE.erl
|
|
@@ -3568,7 +3568,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]}.
|
|
|