File 8643-crypto-3.0-API-in-rsa.c.patch of Package erlang

From d54b49e9a071ea8a1f51cd5deb6d458b5539f218 Mon Sep 17 00:00:00 2001
From: Hans Nilsson <hans@erlang.org>
Date: Tue, 1 Mar 2022 13:12:42 +0100
Subject: [PATCH 3/3] crypto: 3.0 API in rsa.c

---
 lib/crypto/c_src/rsa.c | 320 +++++++++++++++++++++++++++++------------
 1 file changed, 230 insertions(+), 90 deletions(-)

diff --git a/lib/crypto/c_src/rsa.c b/lib/crypto/c_src/rsa.c
index 3a1c4e75ac..f5f0ef2b6e 100644
--- a/lib/crypto/c_src/rsa.c
+++ b/lib/crypto/c_src/rsa.c
@@ -21,16 +21,93 @@
 #include "rsa.h"
 #include "bn.h"
 
-//#define(CHK_RSA_3_0)
-
 static ERL_NIF_TERM rsa_generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-#if !defined(HAS_3_0_API) || defined(CHK_RSA_3_0)
+#if !defined(HAS_3_0_API)
 static ERL_NIF_TERM put_rsa_private_key(ErlNifEnv* env, const RSA *rsa);
 #endif
 #if !defined(HAS_3_0_API)
 static int check_erlang_interrupt(int maj, int min, BN_GENCB *ctxt);
 #endif
 
+#define PUT1(env,bn,t) \
+    if (bn) {if ((t = bin_from_bn(env, bn)) == atom_error) goto err;}   \
+    else t = atom_undefined
+    
+
+// ERL_NIF_TERM debug_put_pkey(ErlNifEnv* env, EVP_PKEY *pkey);
+// ERL_NIF_TERM debug_put_pkey(ErlNifEnv* env, EVP_PKEY *pkey)
+// {
+//     const BIGNUM *e1 = NULL, *n1 = NULL, *d1 = NULL;
+//     RSA *rsa = NULL;
+//     ERL_NIF_TERM result[3];
+// 
+//     rsa = EVP_PKEY_get1_RSA(pkey);
+//     RSA_get0_key(rsa, &n1, &e1, &d1);
+// 
+//     PUT1(env, e1, result[0]);  // Exponent E
+//     PUT1(env, n1, result[1]);  // Modulus N = p*q
+//     PUT1(env, d1, result[2]);
+//         
+//     return enif_make_list_from_array(env,result,3);
+// 
+//  err:
+//     return atom_error;
+// }
+
+
+#if !defined(HAS_3_0_API)
+/* Creates a term which can be parsed by get_rsa_private_key(). This is a list of plain integer binaries (not mpints). */
+static ERL_NIF_TERM put_rsa_private_key(ErlNifEnv* env, const RSA *rsa)
+{
+    ERL_NIF_TERM result[8];
+    const BIGNUM *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL, *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
+
+    /* Return at least [E,N,D] */
+    RSA_get0_key(rsa, &n, &e, &d);
+
+    if ((result[0] = bin_from_bn(env, e)) == atom_error)  // Exponent E
+        goto err;
+    if ((result[1] = bin_from_bn(env, n)) == atom_error)  // Modulus N = p*q
+        goto err;
+    if ((result[2] = bin_from_bn(env, d)) == atom_error)  // Exponent D
+        goto err;
+
+    /* Check whether the optional additional parameters are available */
+    RSA_get0_factors(rsa, &p, &q);
+    RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
+
+    if (p && q && dmp1 && dmq1 && iqmp) {
+        if ((result[3] = bin_from_bn(env, p)) == atom_error)     // Factor p
+            goto err;
+        if ((result[4] = bin_from_bn(env, q)) == atom_error)     // Factor q
+            goto err;
+        if ((result[5] = bin_from_bn(env, dmp1)) == atom_error)  // D mod (p-1)
+            goto err;
+        if ((result[6] = bin_from_bn(env, dmq1)) == atom_error)  // D mod (q-1)
+            goto err;
+        if ((result[7] = bin_from_bn(env, iqmp)) == atom_error)  // (1/q) mod p
+            goto err;
+
+	return enif_make_list_from_array(env, result, 8);
+    } else {
+	return enif_make_list_from_array(env, result, 3);
+    }
+
+ err:
+    return enif_make_badarg(env);
+}
+
+static int check_erlang_interrupt(int maj, int min, BN_GENCB *ctxt)
+{
+    ErlNifEnv *env = BN_GENCB_get_arg(ctxt);
+
+    if (!enif_is_current_process_alive(env)) {
+	return 0;
+    } else {
+	return 1;
+    }
+}
+
 int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey)
 {
     /* key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C] */
@@ -56,6 +133,7 @@ int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey)
     if ((rsa = RSA_new()) == NULL)
         goto err;
 
+    *pkey = EVP_PKEY_new();
     if (!RSA_set0_key(rsa, n, e, d))
         goto err;
     /* rsa now owns n, e, and d */
@@ -135,6 +213,7 @@ int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey)
     return 0;
 }
 
+
 int get_rsa_public_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey)
 {
     /* key=[E,N] */
@@ -162,9 +241,11 @@ int get_rsa_public_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey)
     n = NULL;
     e = NULL;
 
+    *pkey = EVP_PKEY_new();
     if (EVP_PKEY_assign_RSA(*pkey, rsa) != 1)
         goto err;
 
+    // enif_fprintf(stderr, "pkey = %T\r\n", debug_put_pkey(env,*pkey));
     return 1;
 
  bad_arg:
@@ -179,63 +260,6 @@ int get_rsa_public_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey)
     return 0;
 }
 
-#if !defined(HAS_3_0_API) || defined(CHK_RSA_3_0)
-/* Creates a term which can be parsed by get_rsa_private_key(). This is a list of plain integer binaries (not mpints). */
-static ERL_NIF_TERM put_rsa_private_key(ErlNifEnv* env, const RSA *rsa)
-{
-    ERL_NIF_TERM result[8];
-    const BIGNUM *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL, *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
-
-    /* Return at least [E,N,D] */
-    RSA_get0_key(rsa, &n, &e, &d);
-
-    if ((result[0] = bin_from_bn(env, e)) == atom_error)  // Exponent E
-        goto err;
-    if ((result[1] = bin_from_bn(env, n)) == atom_error)  // Modulus N = p*q
-        goto err;
-    if ((result[2] = bin_from_bn(env, d)) == atom_error)  // Exponent D
-        goto err;
-
-    /* Check whether the optional additional parameters are available */
-    RSA_get0_factors(rsa, &p, &q);
-    RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
-
-    if (p && q && dmp1 && dmq1 && iqmp) {
-        if ((result[3] = bin_from_bn(env, p)) == atom_error)     // Factor p
-            goto err;
-        if ((result[4] = bin_from_bn(env, q)) == atom_error)     // Factor q
-            goto err;
-        if ((result[5] = bin_from_bn(env, dmp1)) == atom_error)  // D mod (p-1)
-            goto err;
-        if ((result[6] = bin_from_bn(env, dmq1)) == atom_error)  // D mod (q-1)
-            goto err;
-        if ((result[7] = bin_from_bn(env, iqmp)) == atom_error)  // (1/q) mod p
-            goto err;
-
-	return enif_make_list_from_array(env, result, 8);
-    } else {
-	return enif_make_list_from_array(env, result, 3);
-    }
-
- err:
-    return enif_make_badarg(env);
-}
-#endif
-
-#if !defined(HAS_3_0_API)
-/* Legacy API deprecated from 3.0 is used */
-
-static int check_erlang_interrupt(int maj, int min, BN_GENCB *ctxt)
-{
-    ErlNifEnv *env = BN_GENCB_get_arg(ctxt);
-
-    if (!enif_is_current_process_alive(env)) {
-	return 0;
-    } else {
-	return 1;
-    }
-}
-
 static ERL_NIF_TERM rsa_generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
 {/* (ModulusSize, PublicExponent) */
     ERL_NIF_TERM ret;
@@ -303,9 +327,127 @@ static ERL_NIF_TERM rsa_generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TER
     return ret;
 }
 
+int rsa_privkey_to_pubkey(ErlNifEnv* env,  EVP_PKEY *pkey, ERL_NIF_TERM *ret)
+{
+    const BIGNUM *n = NULL, *e = NULL, *d = NULL;
+    ERL_NIF_TERM result[2];
+    RSA *rsa = NULL;
+
+    if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
+        goto err;
+
+    RSA_get0_key(rsa, &n, &e, &d);
+
+    // Exponent E
+    if ((result[0] = bin_from_bn(env, e)) == atom_error)
+        goto err;
+    // Modulus N = p*q
+    if ((result[1] = bin_from_bn(env, n)) == atom_error)
+        goto err;
+
+    *ret = enif_make_list_from_array(env, result, 2);
+    RSA_free(rsa);
+    return 1;
+
+ err:
+    if (rsa)
+        RSA_free(rsa);
+    return 0;
+}
+
+
 #else
 /* New 3.0 API is used */
 
+int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey)
+{
+    /* key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C] */
+    ERL_NIF_TERM head, tail;
+    OSSL_PARAM params[9];
+    EVP_PKEY_CTX *ctx = NULL;
+    int i = 0;
+
+    head = key;
+
+    if (!get_ossl_param_from_bin_in_list(env, "e", &head, &params[i++]) || // Exponent E
+        !get_ossl_param_from_bin_in_list(env, "n", &head, &params[i++]) ||  // N = p*q
+        !get_ossl_param_from_bin_in_list(env, "d", &head, &params[i++]))  // Exponent D
+        goto bad_arg;
+    
+    tail = head;
+    
+    if (!enif_is_empty_list(env, tail)) {
+        if (!get_ossl_param_from_bin_in_list(env, "rsa-factor1", &head, &params[i++]) || // p, Factor p
+            !get_ossl_param_from_bin_in_list(env, "rsa-factor2", &head, &params[i++]) || // q, Factor q
+            !get_ossl_param_from_bin_in_list(env, "rsa-exponent1", &head, &params[i++]) || // dmp1, D mod (p-1)
+            !get_ossl_param_from_bin_in_list(env, "rsa-exponent2", &head, &params[i++]) || // dmq1, D mod (q-1)
+            !get_ossl_param_from_bin_in_list(env, "rsa-coefficient1", &head, &params[i++]) ) // iqmp, (1/q) mod p
+            goto bad_arg;
+
+        tail = head;
+    
+        if (!enif_is_empty_list(env, tail))
+            goto bad_arg;
+    }
+
+    params[i++] = OSSL_PARAM_construct_end();
+
+    if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) == NULL)
+        goto err;
+    if (EVP_PKEY_fromdata_init(ctx) <= 0)
+        goto err;
+    if (EVP_PKEY_fromdata(ctx, pkey, EVP_PKEY_KEYPAIR, params) <= 0)
+        goto bad_arg;
+
+    if (ctx) EVP_PKEY_CTX_free(ctx);
+    return 1;
+
+ bad_arg:
+ err:
+    if (ctx) EVP_PKEY_CTX_free(ctx);
+    return 0;
+}
+
+
+int get_rsa_public_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey)
+{
+    ERL_NIF_TERM head, tail;
+    OSSL_PARAM params[3];
+    EVP_PKEY_CTX *ctx = NULL;
+
+    head = key;
+    if (!get_ossl_param_from_bin_in_list(env, "e", &head, &params[0]) )
+        goto bad_arg;
+    
+    if (!get_ossl_param_from_bin_in_list(env, "n", &head, &params[1]) )
+        goto bad_arg;
+    
+    tail = head;
+    if (!enif_is_empty_list(env, tail))
+        goto bad_arg;
+
+    params[2] = OSSL_PARAM_construct_end();
+
+    if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) == NULL)
+        goto err;
+    if (EVP_PKEY_fromdata_init(ctx) <= 0)
+        goto err;
+    if (EVP_PKEY_fromdata(ctx, pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
+        goto bad_arg;
+
+    /* enif_fprintf(stderr, "pkey = %T\r\nn = %T\r\n", */
+    /*              debug_put_pkey(env,*pkey), */
+    /*              enif_make_binary(env,&tmp) */
+    /*              ); */
+    if (ctx) EVP_PKEY_CTX_free(ctx);
+    return 1;
+
+ bad_arg:
+ err:
+    if (ctx) EVP_PKEY_CTX_free(ctx);
+    return 0;
+}
+
 static ERL_NIF_TERM rsa_generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
 {/* (ModulusSize, PublicExponent/binary, PublicExponent) */
     ERL_NIF_TERM ret;
@@ -378,58 +520,56 @@ static ERL_NIF_TERM rsa_generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TER
             || ((result[7] = bin_from_bn(env, iqmp)) == atom_error)
             ) {
             ret = EXCP_ERROR(env, "Can't get RSA keys");
-            goto ret;
+            goto local_ret;
         }
-
         ret =  enif_make_list_from_array(env, result, 8);
-
-#ifdef CHK_RSA_3_0
-        {RSA *rsa = EVP_PKEY_get1_RSA(pkey);
-            if (!rsa)
-                ret = enif_make_tuple2(env, ret, atom_error);
-            else
-                ret = enif_make_tuple2(env, ret, put_rsa_private_key(env,rsa));
-        }
-#endif
+    local_ret:
+        if (e) BN_free(e);
+        if (n) BN_free(n);
+        if (d) BN_free(d);
+        if (p) BN_free(p);
+        if (q) BN_free(q);
+        if (dmp1) BN_free(dmp1);
+        if (dmq1) BN_free(dmq1);
+        if (iqmp) BN_free(iqmp);
     }
 
  ret:
+    if (pkey) EVP_PKEY_free(pkey);
     if (pctx) EVP_PKEY_CTX_free(pctx);
     return ret;
 }
 
-#endif /* #else-part of #if !defined(HAS_3_0_API) */
-
-
 int rsa_privkey_to_pubkey(ErlNifEnv* env,  EVP_PKEY *pkey, ERL_NIF_TERM *ret)
 {
-    const BIGNUM *n = NULL, *e = NULL, *d = NULL;
+    BIGNUM *e = NULL, *n = NULL;
     ERL_NIF_TERM result[2];
-    RSA *rsa = NULL;
-    
-    if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL)
-        goto err;
-
-    RSA_get0_key(rsa, &n, &e, &d);
 
-    // Exponent E
-    if ((result[0] = bin_from_bn(env, e)) == atom_error)
-        goto err;
-    // Modulus N = p*q
-    if ((result[1] = bin_from_bn(env, n)) == atom_error)
+    /* https://www.openssl.org/docs/man3.0/man7/EVP_PKEY-RSA.html */
+    if (
+        !EVP_PKEY_get_bn_param(pkey, "e", &e)                       // Exponent E
+        || !EVP_PKEY_get_bn_param(pkey, "n", &n)                    // Modulus N = p*q
+        || ((result[0] = bin_from_bn(env, e)) == atom_error)
+        || ((result[1] = bin_from_bn(env, n)) == atom_error)
+        )
         goto err;
 
-    *ret = enif_make_list_from_array(env, result, 2);
-    RSA_free(rsa);
+    *ret =  enif_make_list_from_array(env, result, 2);
+    if (e) BN_free(e);
+    if (n) BN_free(n);
     return 1;
 
  err:
-    if (rsa)
-        RSA_free(rsa);
+    if (e) BN_free(e);
+    if (n) BN_free(n);
     return 0;
+
 }
 
 
+#endif /* #else-part of #if !defined(HAS_3_0_API)   (That is, end of defined(HAS_3_0_API)) */
+
+
 ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
 {
     /* RSA key generation can take a long time (>1 sec for a large
-- 
2.34.1

openSUSE Build Service is sponsored by