File 8706-crypto-ecdh_compute_key_nif-for-3.0.patch of Package erlang
From 88be010b54a4ff6208aee274688e1c7b233e12ea Mon Sep 17 00:00:00 2001
From: Hans Nilsson <hans@erlang.org>
Date: Thu, 31 Mar 2022 21:42:37 +0200
Subject: [PATCH 6/7] crypto: ecdh_compute_key_nif for 3.0
---
lib/crypto/c_src/ecdh.c | 108 ++++++++++++++++++++++++++++++-
lib/crypto/test/crypto_SUITE.erl | 32 ++++++++-
2 files changed, 138 insertions(+), 2 deletions(-)
diff --git a/lib/crypto/c_src/ecdh.c b/lib/crypto/c_src/ecdh.c
index 092b59e2df..96c57f18e7 100644
--- a/lib/crypto/c_src/ecdh.c
+++ b/lib/crypto/c_src/ecdh.c
@@ -30,8 +30,113 @@ ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
#else
+# if defined(HAS_3_0_API)
+# include "bn.h"
+
ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
/* (OtherPublicKey, Curve, My) */
+{
+ ERL_NIF_TERM ret = atom_undefined;
+ ErlNifBinary ret_bin;
+ size_t sz;
+ int ret_bin_alloc = 0;
+ int i = 0, i_key = 0;
+ OSSL_PARAM params[15];
+ EVP_PKEY_CTX *own_pctx = NULL, *peer_pctx = NULL, *pctx_gen = NULL;
+ EVP_PKEY *own_pkey = NULL, *peer_pkey = NULL;
+ int err;
+
+ /**** Fetch parameters ****/
+
+ /* Build peer_pkey */
+ i_key = i;
+ 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"));
+
+ /* Curve definition/name */
+ if (!get_curve_definition(env, &ret, argv[1], params, &i, NULL))
+ 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)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't do fromdata"));
+
+ if (!peer_pkey)
+ assign_goto(ret, err, EXCP_ERROR(env, "No peer_pkey"));
+
+ /* Build the local private (and public) key in own_pkey */
+
+ /* Just replace the pub key with the priv key in params; the
+ curve definition is of course the same
+ */
+ if (!get_ossl_BN_param_from_bin(env, "priv", argv[2], ¶ms[i_key]))
+ assign_goto(ret, err, EXCP_BADARG_N(env, 0, "Bad peer public key; binary expected"));
+
+ own_pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
+
+ if (EVP_PKEY_fromdata_init(own_pctx) <= 0)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't init fromdata"));
+
+ if (EVP_PKEY_fromdata(own_pctx, &own_pkey, EVP_PKEY_KEYPAIR, params) <= 0)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't do fromdata"));
+
+ if (!own_pkey)
+ assign_goto(ret, err, EXCP_ERROR(env, "No own_pkey"));
+
+ /**** Derive the common secret from own_pkey and peer_pkey ****/
+
+ if (!(pctx_gen = EVP_PKEY_CTX_new(own_pkey, NULL)))
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_init"));
+
+ if (EVP_PKEY_derive_init(pctx_gen) <= 0)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_derive_init"));
+
+ if ((err = EVP_PKEY_derive_set_peer_ex(pctx_gen, peer_pkey, 0)) <= 0)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't derive secret or set peer"));
+
+ if ((err = EVP_PKEY_derive(pctx_gen, NULL, &sz)) <= 0)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't get result size"));
+
+ if (!enif_alloc_binary(sz, &ret_bin))
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't allcate binary"));
+ ret_bin_alloc = 1;
+
+ if ((err = EVP_PKEY_derive(pctx_gen, ret_bin.data, &ret_bin.size)) <=0)
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't get result"));
+
+ if (sz != ret_bin.size)
+ if (!enif_realloc_binary(&ret_bin, ret_bin.size))
+ assign_goto(ret, err, EXCP_ERROR(env, "Can't realloc binary"));
+
+ ret = enif_make_binary(env, &ret_bin);
+ ret_bin_alloc = 0;
+
+ err:
+ if (ret_bin_alloc) enif_release_binary(&ret_bin);
+ if (peer_pctx) EVP_PKEY_CTX_free(peer_pctx);
+ if (peer_pkey) EVP_PKEY_free(peer_pkey);
+ if (own_pctx) EVP_PKEY_CTX_free(own_pctx);
+ if (own_pkey) EVP_PKEY_free(own_pkey);
+ if (pctx_gen) EVP_PKEY_CTX_free(pctx_gen);
+ return ret;
+}
+
+# endif /* HAS_3_0_API */
+
+
+
+# if ! defined(HAS_3_0_API)
+
+ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+/* (OtherPublicKey, {CurveDef,_CurveName}, My) */
{
ERL_NIF_TERM ret = atom_undefined;
unsigned char *p;
@@ -84,5 +189,6 @@ ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
EC_KEY_free(key);
return ret;
-#endif
}
+# endif /* ! HAS_3_0_API */
+#endif /* HAVE_EC */
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 968a65318c..156b00688b 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -1194,6 +1194,18 @@ use_all_ec_sign_verify(_Config) ->
ok;
_ ->
ct:log("Fails:~n~p",[Fails]),
+ Errors = lists:usort([Err || {_,Err} <- Fails]),
+ FailedCurves = [Curve || {Curve,_} <- Fails],
+ FailedCurvesPerError = [{E, [C || {C,E0} <- Fails,
+ E0 == E]}
+ || E <- Errors],
+ ct:pal("~p failed curves: ~p", [length(FailedCurves), FailedCurves]),
+ ct:pal("Failed curves per error:~n~s",
+ [
+ [io_lib:format(" Error: ~p~n Curves: ~p~n~n", [E,Cs])
+ || {E,Cs} <- FailedCurvesPerError]
+ ]
+ ),
ct:fail("Bad curve(s)",[])
end.
@@ -1238,13 +1250,31 @@ do_dh_curves(_Config, Curves) ->
(_) -> true
end, Results),
+ Succedes =
+ lists:filter(fun({_,true}) -> true;
+ (_) -> false
+ end, Results),
+
case Fails of
[] ->
ct:comment("All ~p passed",[length(Results)]),
ok;
_ ->
- ct:comment("passed: ~p, failed: ~p",[length(Results),length(Fails)]),
+ ct:comment("passed: ~p, failed: ~p",[length(Results)-length(Fails),length(Fails)]),
+ ct:log("Succedes:~n~p",[Succedes]),
ct:log("Fails:~n~p",[Fails]),
+ Errors = lists:usort([Err || {_,Err} <- Fails]),
+ FailedCurves = [C || {C,_} <- Fails],
+ FailedCurvesPerError = [{E, [C || {C,E0} <- Fails,
+ E == E0]}
+ || E <- Errors],
+ ct:pal("~p (~p) failed curves: ~p", [length(FailedCurves), length(Results), FailedCurves]),
+ ct:pal("Failed curves per error:~n~s",
+ [
+ [io_lib:format(" Error: ~p~n Curves: ~p~n~n", [E,Cs])
+ || {E,Cs} <- FailedCurvesPerError]
+ ]
+ ),
ct:fail("Bad curve(s)",[])
end.
--
2.35.3