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], &params[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], &params[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

openSUSE Build Service is sponsored by