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, ¶ms[i++]) || // Exponent E
+ !get_ossl_param_from_bin_in_list(env, "n", &head, ¶ms[i++]) || // N = p*q
+ !get_ossl_param_from_bin_in_list(env, "d", &head, ¶ms[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, ¶ms[i++]) || // p, Factor p
+ !get_ossl_param_from_bin_in_list(env, "rsa-factor2", &head, ¶ms[i++]) || // q, Factor q
+ !get_ossl_param_from_bin_in_list(env, "rsa-exponent1", &head, ¶ms[i++]) || // dmp1, D mod (p-1)
+ !get_ossl_param_from_bin_in_list(env, "rsa-exponent2", &head, ¶ms[i++]) || // dmq1, D mod (q-1)
+ !get_ossl_param_from_bin_in_list(env, "rsa-coefficient1", &head, ¶ms[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, ¶ms[0]) )
+ goto bad_arg;
+
+ if (!get_ossl_param_from_bin_in_list(env, "n", &head, ¶ms[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