From 24af5238589a2b0c4a153ead9e2f37506870f94c Mon Sep 17 00:00:00 2001
From: Wim Lewis
Date: Sun, 8 Jan 2017 18:40:32 -0800
Subject: Add RSA key generation
Support RSA key generation using generate_key(rsa, {bits, e}). This depends
on the currently-experimental "dirty scheduler" support because key
generation is a potentially lengthy process.
---
lib/crypto/c_src/crypto.c | 200 ++++++++++++++++++++++++++++++++++++++-
lib/crypto/doc/src/crypto.xml | 15 +--
lib/crypto/src/crypto.erl | 9 ++
lib/crypto/test/crypto_SUITE.erl | 26 ++++-
4 files changed, 240 insertions(+), 10 deletions(-)
(limited to 'lib/crypto')
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 38b49c7a76..ba011c3317 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -42,6 +42,7 @@
#endif /* #ifndef OPENSSL_NO_DES */
/* #include This is not supported on the openssl OTP requires */
#include
+#include
#include
#include
#include
@@ -238,9 +239,19 @@ static void HMAC_CTX_free(HMAC_CTX *ctx)
#define EVP_MD_CTX_new() EVP_MD_CTX_create()
#define EVP_MD_CTX_free(ctx) EVP_MD_CTX_destroy(ctx)
+static INLINE void *BN_GENCB_get_arg(BN_GENCB *cb);
+
+static INLINE void *BN_GENCB_get_arg(BN_GENCB *cb)
+{
+ return cb->arg;
+}
+
static INLINE int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
+static INLINE void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
static INLINE int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
+static INLINE void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
static INLINE int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
+static INLINE void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp);
static INLINE int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
{
@@ -250,6 +261,13 @@ static INLINE int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
return 1;
}
+static INLINE void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
+{
+ *n = r->n;
+ *e = r->e;
+ *d = r->d;
+}
+
static INLINE int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
{
r->p = p;
@@ -257,6 +275,12 @@ static INLINE int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
return 1;
}
+static INLINE void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
+{
+ *p = r->p;
+ *q = r->q;
+}
+
static INLINE int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
{
r->dmp1 = dmp1;
@@ -265,6 +289,13 @@ static INLINE int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM
return 1;
}
+static INLINE void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp)
+{
+ *dmp1 = r->dmp1;
+ *dmq1 = r->dmq1;
+ *iqmp = r->iqmp;
+}
+
static INLINE int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
static INLINE int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
@@ -320,7 +351,11 @@ DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
*priv_key = dh->priv_key;
}
-#endif /* End of compatibility definitions. */
+#else /* End of compatibility definitions. */
+
+#define HAVE_OPAQUE_BN_GENCB
+
+#endif
/* NIF interface declarations */
static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
@@ -358,6 +393,7 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -391,6 +427,7 @@ static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg);
static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
EC_GROUP *group, EC_POINT **pptr);
#endif
+static ERL_NIF_TERM bin_from_bn(ErlNifEnv* env, const BIGNUM *bn);
static int library_refc = 0; /* number of users of this dynamic library */
@@ -428,6 +465,7 @@ static ErlNifFunc nif_funcs[] = {
{"dss_sign_nif", 3, dss_sign_nif},
{"rsa_public_crypt", 4, rsa_public_crypt},
{"rsa_private_crypt", 4, rsa_private_crypt},
+ {"rsa_generate_key_nif", 2, rsa_generate_key_nif},
{"dh_generate_parameters_nif", 2, dh_generate_parameters_nif},
{"dh_check", 1, dh_check},
{"dh_generate_key_nif", 3, dh_generate_key_nif},
@@ -462,6 +500,7 @@ static ERL_NIF_TERM atom_true;
static ERL_NIF_TERM atom_false;
static ERL_NIF_TERM atom_sha;
static ERL_NIF_TERM atom_error;
+static ERL_NIF_TERM atom_openssl;
static ERL_NIF_TERM atom_rsa_pkcs1_padding;
static ERL_NIF_TERM atom_rsa_pkcs1_oaep_padding;
static ERL_NIF_TERM atom_rsa_no_padding;
@@ -791,6 +830,7 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_sha = enif_make_atom(env,"sha");
atom_error = enif_make_atom(env,"error");
+ atom_openssl = enif_make_atom(env, "openssl"),
atom_rsa_pkcs1_padding = enif_make_atom(env,"rsa_pkcs1_padding");
atom_rsa_pkcs1_oaep_padding = enif_make_atom(env,"rsa_pkcs1_oaep_padding");
atom_rsa_no_padding = enif_make_atom(env,"rsa_no_padding");
@@ -877,6 +917,9 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
CRYPTO_set_dynlock_destroy_callback(ccb->dyn_destroy_function);
}
#endif /* OPENSSL_THREADS */
+
+ ERR_load_crypto_strings();
+
return 0;
}
@@ -1630,6 +1673,34 @@ static ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
#endif
}
+static ERL_NIF_TERM raise_openssl_error(ErlNifEnv* env)
+{
+ ERL_NIF_TERM error_stack, error_triplet, error_tuple;
+
+ error_stack = enif_make_list(env, 0);
+ for(;;) {
+ unsigned long next_error;
+ const char *libname, *funcname, *reason;
+
+ next_error = ERR_get_error();
+ if (!next_error)
+ break;
+
+ libname = ERR_lib_error_string(next_error);
+ funcname = ERR_func_error_string(next_error);
+ reason = ERR_reason_error_string(next_error);
+
+#define TO_STRING(s) ((s)? enif_make_string(env, s, ERL_NIF_LATIN1) : atom_unknown)
+ error_triplet = enif_make_tuple3(env, TO_STRING(libname), TO_STRING(funcname), TO_STRING(reason));
+#undef TO_STRING
+
+ error_stack = enif_make_list_cell(env, error_triplet, error_stack);
+ }
+
+ error_tuple = enif_make_tuple2(env, atom_openssl, error_stack);
+ return enif_raise_exception(env, enif_make_tuple2(env, atom_error, error_tuple));
+}
+
static ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type, Key, Ivec, Text, IsEncrypt) or (Type, Key, Text, IsEncrypt) */
struct cipher_type_t *cipherp = NULL;
@@ -2231,6 +2302,20 @@ static int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
return 1;
}
+static ERL_NIF_TERM bin_from_bn(ErlNifEnv* env, const BIGNUM *bn)
+{
+ int bn_len;
+ unsigned char *bin_ptr;
+ ERL_NIF_TERM term;
+
+ /* Copy the bignum into an erlang binary. */
+ bn_len = BN_num_bytes(bn);
+ bin_ptr = enif_make_new_binary(env, bn_len, &term);
+ BN_bn2bin(bn, bin_ptr);
+
+ return term;
+}
+
static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Lo,Hi) */
BIGNUM *bn_from = NULL, *bn_to, *bn_rand;
@@ -2802,6 +2887,119 @@ static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TE
}
}
+/* 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, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
+
+ /* Return at least [E,N,D] */
+ n = NULL; e = NULL; d = NULL;
+ RSA_get0_key(rsa, &n, &e, &d);
+
+ result[0] = bin_from_bn(env, e); // Exponent E
+ result[1] = bin_from_bn(env, n); // Modulus N = p*q
+ result[2] = bin_from_bn(env, d); // Exponent D
+
+ /* Check whether the optional additional parameters are available */
+ p = NULL; q = NULL;
+ RSA_get0_factors(rsa, &p, &q);
+ dmp1 = NULL; dmq1 = NULL; iqmp = NULL;
+ RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
+
+ if (p && q && dmp1 && dmq1 && iqmp) {
+ result[3] = bin_from_bn(env, p); // Factor p
+ result[4] = bin_from_bn(env, q); // Factor q
+ result[5] = bin_from_bn(env, dmp1); // D mod (p-1)
+ result[6] = bin_from_bn(env, dmq1); // D mod (q-1)
+ result[7] = bin_from_bn(env, iqmp); // (1/q) mod p
+
+ return enif_make_list_from_array(env, result, 8);
+ } else {
+ return enif_make_list_from_array(env, result, 3);
+ }
+}
+
+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) */
+ int modulus_bits;
+ BIGNUM *pub_exp, *three;
+ RSA *rsa;
+ int success;
+ ERL_NIF_TERM result;
+ BN_GENCB *intr_cb;
+#ifndef HAVE_OPAQUE_BN_GENCB
+ BN_GENCB intr_cb_buf;
+#endif
+
+ if (!enif_get_int(env, argv[0], &modulus_bits) || modulus_bits < 256) {
+ return enif_make_badarg(env);
+ }
+
+ if (!get_bn_from_bin(env, argv[1], &pub_exp)) {
+ return enif_make_badarg(env);
+ }
+
+ /* Make sure the public exponent is large enough (at least 3).
+ * Without this, RSA_generate_key_ex() can run forever. */
+ three = BN_new();
+ BN_set_word(three, 3);
+ success = BN_cmp(pub_exp, three);
+ BN_free(three);
+ if (success < 0) {
+ BN_free(pub_exp);
+ return enif_make_badarg(env);
+ }
+
+ /* For large keys, prime generation can take many seconds. Set up
+ * the callback which we use to test whether the process has been
+ * interrupted. */
+#ifdef HAVE_OPAQUE_BN_GENCB
+ intr_cb = BN_GENCB_new();
+#else
+ intr_cb = &intr_cb_buf;
+#endif
+ BN_GENCB_set(intr_cb, check_erlang_interrupt, env);
+
+ rsa = RSA_new();
+ success = RSA_generate_key_ex(rsa, modulus_bits, pub_exp, intr_cb);
+ BN_free(pub_exp);
+
+#ifdef HAVE_OPAQUE_BN_GENCB
+ BN_GENCB_free(intr_cb);
+#endif
+
+ if (!success) {
+ RSA_free(rsa);
+ return raise_openssl_error(env);
+ }
+
+ result = put_rsa_private_key(env, rsa);
+ RSA_free(rsa);
+
+ return result;
+}
+
+static 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
+ * modulus), so schedule it as a CPU-bound operation. */
+ return enif_schedule_nif(env, "rsa_generate_key",
+ ERL_NIF_DIRTY_JOB_CPU_BOUND,
+ rsa_generate_key, argc, argv);
+}
+
static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (PrimeLen, Generator) */
int prime_len, generator;
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index cbf141b3b0..102db8984a 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -298,22 +298,25 @@
generate_key(Type, Params) -> {PublicKey, PrivKeyOut}
generate_key(Type, Params, PrivKeyIn) -> {PublicKey, PrivKeyOut}
- Generates a public keys of type Type
+ Generates a public key of type Type
- Type = dh | ecdh | srp
- Params = dh_params() | ecdh_params() | SrpUserParams | SrpHostParams
+ Type = dh | ecdh | rsa | srp
+ Params = dh_params() | ecdh_params() | RsaParams | SrpUserParams | SrpHostParams
+ RsaParams = {ModulusSizeInBits::integer(), PublicExponent::key_value()}
SrpUserParams = {user, [Generator::binary(), Prime::binary(), Version::atom()]}
SrpHostParams = {host, [Verifier::binary(), Generator::binary(), Prime::binary(), Version::atom()]}
- PublicKey = dh_public() | ecdh_public() | srp_public()
+ PublicKey = dh_public() | ecdh_public() | rsa_public() | srp_public()
PrivKeyIn = undefined | dh_private() | ecdh_private() | srp_private()
- PrivKeyOut = dh_private() | ecdh_private() | srp_private()
+ PrivKeyOut = dh_private() | ecdh_private() | rsa_private() | srp_private()
- Generates public keys of type Type.
+
Generates a public key of type Type.
See also public_key:generate_key/1
May throw exception low_entropy in case the random generator
failed due to lack of secure "randomness".
+ RSA key generation is only available if the runtime was built with the
+ experimental dirty scheduler feature.
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 0b62964efa..d4a2a51697 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -445,6 +445,10 @@ generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg)
end,
user_srp_gen_key(Private, Generator, Prime);
+generate_key(rsa, {ModulusSize, PublicExponent}, undefined) ->
+ Private = rsa_generate_key_nif(ModulusSize, ensure_int_as_bin(PublicExponent)),
+ { lists:sublist(Private, 2), Private };
+
generate_key(ecdh, Curve, PrivKey) ->
ec_key_generate(nif_curve_params(Curve), ensure_int_as_bin(PrivKey)).
@@ -780,6 +784,11 @@ rsa_verify_nif(_Type, _Digest, _Signature, _Key) -> ?nif_stub.
ecdsa_verify_nif(_Type, _Digest, _Signature, _Curve, _Key) -> ?nif_stub.
%% Public Keys --------------------------------------------------------------------
+%% RSA Rivest-Shamir-Adleman functions
+%%
+
+rsa_generate_key_nif(_Bits, _Exp) -> ?nif_stub.
+
%% DH Diffie-Hellman functions
%%
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 31f4e89ffe..fbee0ad9b7 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -119,7 +119,8 @@ groups() ->
{sha384, [], [hash, hmac]},
{sha512, [], [hash, hmac]},
{rsa, [], [sign_verify,
- public_encrypt
+ public_encrypt,
+ generate
]},
{dss, [], [sign_verify]},
{ecdsa, [], [sign_verify]},
@@ -247,6 +248,21 @@ init_per_testcase(cmac, Config) ->
% The CMAC functionality was introduced in OpenSSL 1.0.1
{skip, "OpenSSL is too old"}
end;
+init_per_testcase(generate, Config) ->
+ case proplists:get_value(type, Config) of
+ rsa ->
+ % RSA key generation is a lengthy process, and is only available
+ % if dirty CPU scheduler support was enabled for this runtime.
+ case try erlang:system_info(dirty_cpu_schedulers) of
+ N -> N > 0
+ catch
+ error:badarg -> false
+ end of
+ true -> Config;
+ false -> {skip, "RSA key generation requires dirty scheduler support."}
+ end;
+ _ -> Config
+ end;
init_per_testcase(_Name,Config) ->
Config.
@@ -756,7 +772,10 @@ do_generate({ecdh = Type, Curve, Priv, Pub}) ->
ok;
{Other, _} ->
ct:fail({{crypto, generate_key, [Type, Priv, Curve]}, {expected, Pub}, {got, Other}})
- end.
+ end;
+do_generate({rsa = Type, Mod, Exp}) ->
+ {Pub,Priv} = crypto:generate_key(Type, {Mod,Exp}),
+ do_sign_verify({rsa, sha256, Pub, Priv, rsa_plain()}).
notsup(Fun, Args) ->
Result =
@@ -1008,7 +1027,8 @@ group_config(rsa = Type, Config) ->
rsa_oaep(),
no_padding()
],
- [{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc} | Config];
+ Generate = [{rsa, 1024, 3}, {rsa, 2048, 17}, {rsa, 3072, 65537}],
+ [{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc}, {generate, Generate} | Config];
group_config(dss = Type, Config) ->
Msg = dss_plain(),
Public = dss_params() ++ [dss_public()],
--
cgit v1.2.3
From 81da5f7f12eb1da9d9e8f4508d76681f527ad57c Mon Sep 17 00:00:00 2001
From: Wim Lewis
Date: Tue, 17 Jan 2017 22:55:16 -0800
Subject: Remove the RSA-1024 test case. If the underlying library is in FIPS
mode, it'll refuse to generate keys shorter than 2048 bits.
---
lib/crypto/test/crypto_SUITE.erl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/crypto')
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index fbee0ad9b7..1d7037d003 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -1027,7 +1027,7 @@ group_config(rsa = Type, Config) ->
rsa_oaep(),
no_padding()
],
- Generate = [{rsa, 1024, 3}, {rsa, 2048, 17}, {rsa, 3072, 65537}],
+ Generate = [{rsa, 2048, 3}, {rsa, 3072, 65537}],
[{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc}, {generate, Generate} | Config];
group_config(dss = Type, Config) ->
Msg = dss_plain(),
--
cgit v1.2.3
From a00ff322e4cbe72c698eff22e4a4d5f6bb33e067 Mon Sep 17 00:00:00 2001
From: Wim Lewis
Date: Wed, 18 Jan 2017 21:41:50 -0800
Subject: Update the documentation for RSA key generation to reflect that dirty
schedulers are no longer considered "experimental", per a comment from
sverker.
---
lib/crypto/doc/src/crypto.xml | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
(limited to 'lib/crypto')
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 102db8984a..32144613e0 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -315,8 +315,11 @@
May throw exception low_entropy in case the random generator
failed due to lack of secure "randomness".
- RSA key generation is only available if the runtime was built with the
- experimental dirty scheduler feature.
+
+ RSA key generation is only available if the runtime was
+ built with dirty scheduler support. Otherwise, attempting to
+ generate an RSA key will throw exception notsup.
+
--
cgit v1.2.3
From fcbcc330e733e62ae75c7748ae254e368ce97033 Mon Sep 17 00:00:00 2001
From: Wim Lewis
Date: Wed, 18 Jan 2017 21:43:27 -0800
Subject: Minor punctuation fixes in the crypto documentation.
---
lib/crypto/doc/src/crypto.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'lib/crypto')
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 32144613e0..440c5bd204 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -77,7 +77,7 @@
rsa_private() = [key_value()] = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]
Where E is the public exponent, N is public modulus and D is
- the private exponent.The longer key format contains redundant
+ the private exponent. The longer key format contains redundant
information that will make the calculation faster. P1,P2 are first
and second prime factors. E1,E2 are first and second exponents. C
is the CRT coefficient. Terminology is taken from RFC 3447.
@@ -311,7 +311,7 @@
Generates a public key of type Type.
- See also public_key:generate_key/1
+ See also public_key:generate_key/1.
May throw exception low_entropy in case the random generator
failed due to lack of secure "randomness".
--
cgit v1.2.3
From f7610977cb2370e2bf54531ad7d6bcd051e6b27c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Tue, 7 Mar 2017 16:31:30 +0100
Subject: crypto: removed error function from PR and added error handling in
crypto.erl
---
lib/crypto/c_src/crypto.c | 35 +----------------------------------
lib/crypto/src/crypto.erl | 9 +++++++--
2 files changed, 8 insertions(+), 36 deletions(-)
(limited to 'lib/crypto')
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index ba011c3317..42cf7ac37b 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -42,7 +42,6 @@
#endif /* #ifndef OPENSSL_NO_DES */
/* #include This is not supported on the openssl OTP requires */
#include
-#include
#include
#include
#include
@@ -500,7 +499,6 @@ static ERL_NIF_TERM atom_true;
static ERL_NIF_TERM atom_false;
static ERL_NIF_TERM atom_sha;
static ERL_NIF_TERM atom_error;
-static ERL_NIF_TERM atom_openssl;
static ERL_NIF_TERM atom_rsa_pkcs1_padding;
static ERL_NIF_TERM atom_rsa_pkcs1_oaep_padding;
static ERL_NIF_TERM atom_rsa_no_padding;
@@ -830,7 +828,6 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_sha = enif_make_atom(env,"sha");
atom_error = enif_make_atom(env,"error");
- atom_openssl = enif_make_atom(env, "openssl"),
atom_rsa_pkcs1_padding = enif_make_atom(env,"rsa_pkcs1_padding");
atom_rsa_pkcs1_oaep_padding = enif_make_atom(env,"rsa_pkcs1_oaep_padding");
atom_rsa_no_padding = enif_make_atom(env,"rsa_no_padding");
@@ -918,8 +915,6 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
}
#endif /* OPENSSL_THREADS */
- ERR_load_crypto_strings();
-
return 0;
}
@@ -1673,34 +1668,6 @@ static ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
#endif
}
-static ERL_NIF_TERM raise_openssl_error(ErlNifEnv* env)
-{
- ERL_NIF_TERM error_stack, error_triplet, error_tuple;
-
- error_stack = enif_make_list(env, 0);
- for(;;) {
- unsigned long next_error;
- const char *libname, *funcname, *reason;
-
- next_error = ERR_get_error();
- if (!next_error)
- break;
-
- libname = ERR_lib_error_string(next_error);
- funcname = ERR_func_error_string(next_error);
- reason = ERR_reason_error_string(next_error);
-
-#define TO_STRING(s) ((s)? enif_make_string(env, s, ERL_NIF_LATIN1) : atom_unknown)
- error_triplet = enif_make_tuple3(env, TO_STRING(libname), TO_STRING(funcname), TO_STRING(reason));
-#undef TO_STRING
-
- error_stack = enif_make_list_cell(env, error_triplet, error_stack);
- }
-
- error_tuple = enif_make_tuple2(env, atom_openssl, error_stack);
- return enif_raise_exception(env, enif_make_tuple2(env, atom_error, error_tuple));
-}
-
static ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type, Key, Ivec, Text, IsEncrypt) or (Type, Key, Text, IsEncrypt) */
struct cipher_type_t *cipherp = NULL;
@@ -2982,7 +2949,7 @@ static ERL_NIF_TERM rsa_generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TER
if (!success) {
RSA_free(rsa);
- return raise_openssl_error(env);
+ return atom_error;
}
result = put_rsa_private_key(env, rsa);
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index d4a2a51697..046fae674b 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -446,8 +446,13 @@ generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg)
user_srp_gen_key(Private, Generator, Prime);
generate_key(rsa, {ModulusSize, PublicExponent}, undefined) ->
- Private = rsa_generate_key_nif(ModulusSize, ensure_int_as_bin(PublicExponent)),
- { lists:sublist(Private, 2), Private };
+ case rsa_generate_key_nif(ModulusSize, ensure_int_as_bin(PublicExponent)) of
+ error ->
+ erlang:error(computation_failed,
+ [rsa,{ModulusSize,PublicExponent}]);
+ Private ->
+ {lists:sublist(Private, 2), Private}
+ end;
generate_key(ecdh, Curve, PrivKey) ->
ec_key_generate(nif_curve_params(Curve), ensure_int_as_bin(PrivKey)).
--
cgit v1.2.3
From 7c8bcb4ea083d2c4c9893fc0597528c39b5f845c Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 9 Mar 2017 15:41:11 +0100
Subject: crypto: Uppdate crypto.app.src for dirty_scheduler dependency in ERTS
---
lib/crypto/src/crypto.app.src | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib/crypto')
diff --git a/lib/crypto/src/crypto.app.src b/lib/crypto/src/crypto.app.src
index 460894c012..3bf4279ae1 100644
--- a/lib/crypto/src/crypto.app.src
+++ b/lib/crypto/src/crypto.app.src
@@ -25,6 +25,6 @@
{registered, []},
{applications, [kernel, stdlib]},
{env, [{fips_mode, false}]},
- {runtime_dependencies, ["erts-6.0","stdlib-2.0","kernel-3.0"]}]}.
+ {runtime_dependencies, ["erts-9.0","stdlib-3.4","kernel-5.3"]}]}.
--
cgit v1.2.3
From c6270678e0c4297440c2b191ad500b33ed18af5f Mon Sep 17 00:00:00 2001
From: Hans Nilsson
Date: Thu, 9 Mar 2017 15:25:21 +0100
Subject: crypto: Document exceptions thrown in crypto:generate_key
---
lib/crypto/doc/src/crypto.xml | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
(limited to 'lib/crypto')
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 440c5bd204..3192ec0de8 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -312,13 +312,17 @@
Generates a public key of type Type.
See also public_key:generate_key/1.
- May throw exception low_entropy in case the random generator
- failed due to lack of secure "randomness".
-
+ May throw exception an exception of class error:
+
+
+ - badarg: an argument is of wrong type or has an illegal value,
+ - low_entropy: the random generator failed due to lack of secure "randomness",
+ - computation_failed: the computation fails of another reason than low_entropy.
+
RSA key generation is only available if the runtime was
built with dirty scheduler support. Otherwise, attempting to
- generate an RSA key will throw exception notsup.
+ generate an RSA key will throw exception error:notsup.
--
cgit v1.2.3