Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:24
erlang
2581-crypto-3.0-and-dh.c.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 2581-crypto-3.0-and-dh.c.patch of Package erlang
From c2fbff1fcbfbe7600de4fce177cecb2237613fb3 Mon Sep 17 00:00:00 2001 From: Hans Nilsson <hans@erlang.org> Date: Thu, 3 Mar 2022 15:57:29 +0100 Subject: [PATCH 1/2] crypto: 3.0 and dh.c --- lib/crypto/c_src/dh.c | 308 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 293 insertions(+), 15 deletions(-) diff --git a/lib/crypto/c_src/dh.c b/lib/crypto/c_src/dh.c index 8d3f53d06e..43b5c6c2aa 100644 --- a/lib/crypto/c_src/dh.c +++ b/lib/crypto/c_src/dh.c @@ -21,9 +21,287 @@ #include "dh.h" #include "bn.h" + +#if !defined(HAVE_DH) +ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return enif_raise_exception(env, atom_notsup); +} + +ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + return enif_raise_exception(env, atom_notsup); +} + +#else /* HAVE_DH */ + + +# ifdef HAS_3_0_API + +/**** Begin debug-help functions ****/ +# if 0 +ERL_NIF_TERM debug_put_pkey(ErlNifEnv* env, EVP_PKEY *pkey); + +# 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) +{ + const BIGNUM *p1 = NULL, *q1 = NULL, *g1 = NULL, *pub1 = NULL, *priv1 = NULL; + DH *dh = NULL; + ERL_NIF_TERM result[8]; + int i = 0; + + if (pkey) { + dh = EVP_PKEY_get1_DH(pkey); + DH_get0_pqg(dh, &p1, &q1, &g1); + + pub1 = DH_get0_pub_key(dh); + priv1= DH_get0_priv_key(dh); + + PUT1(env, p1, result[i++]); + PUT1(env, g1, result[i++]); + PUT1(env, q1, result[i++]); + PUT1(env, pub1, result[i++]); + PUT1(env, priv1, result[i++]); + + return enif_make_list_from_array(env,result,i); + } else + return atom_false; + + err: + return atom_error; +} +# endif +/**** End debug-help functions ****/ + + +/* Has 3_0 */ +ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (PrivKey|undefined, DHParams=[P,G], 0, Len|0) */ + unsigned long len = 0; + int i = 0; + OSSL_PARAM params[8]; + EVP_PKEY *pkey = NULL, *pkey_gen = NULL; + EVP_PKEY_CTX *pctx = NULL, *pctx_gen = NULL; + BIGNUM *pub_key_gen = NULL, *priv_key_gen = NULL; + unsigned char *pub_ptr, *prv_ptr; + int pub_len, prv_len; + ERL_NIF_TERM ret_pub, ret_prv, ret = atom_undefined; + + /* Fetch parameters and assign them to params[] */ + if (argv[0] != atom_undefined) + if (!get_ossl_param_from_bin(env, "priv", argv[0], ¶ms[i++])) { + ret = EXCP_BADARG_N(env, 0, "PrivKeyIn"); + goto done; + } + + { /*argv[1] - the lists [P,G] */ + ERL_NIF_TERM head, tail; + + head = argv[1]; + if (!get_ossl_param_from_bin_in_list(env, "p", &head, ¶ms[i++]) ) { + ret = EXCP_BADARG_N(env, 1, "Bad value of 'p'"); + goto done; + } + + if (!get_ossl_param_from_bin_in_list(env, "g", &head, ¶ms[i++]) ) { + ret = EXCP_BADARG_N(env, 1, "Bad value of 'g'"); + goto done; + } + + tail = head; + if (!enif_is_empty_list(env,tail)) { + ret = EXCP_BADARG_N(env, 1, "Not a two-element list"); + goto done; + } + } + + /* argv[2] is always hardcoded to 0 in crypto.erl. A left over from some older version? + Let's skip that one + */ + + /* argv[3] is the length of the private key that is to be generated */ + if (!enif_get_ulong(env, argv[3], &len) || + (len > LONG_MAX) ) { + ret = EXCP_BADARG_N(env, 3, "Bad value of length element"); + goto done; + } + else if (len) + params[i++] = OSSL_PARAM_construct_uint64("priv_len", &len); + + /* End of parameter fetching */ + params[i++] = OSSL_PARAM_construct_end(); + + pctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL); + + if (EVP_PKEY_fromdata_init(pctx) <= 0) { + ret = EXCP_ERROR(env, "Can't init fromdata"); + goto done; + } + if (EVP_PKEY_fromdata(pctx, &pkey, EVP_PKEY_KEYPAIR, params) <= 0) { + ret = EXCP_ERROR(env, "Can't do fromdata"); + goto done; + } + + /* Generate a new pkey from the data in the old */ + + pctx_gen = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); + + if (!EVP_PKEY_keygen_init(pctx_gen)) { + ret = EXCP_ERROR(env, "Can't init DH generation"); + goto done; + } + + if (!EVP_PKEY_CTX_set_params(pctx_gen, params)) { + ret = EXCP_ERROR(env, "Can't set params"); + goto done; + } + + if (!EVP_PKEY_generate(pctx_gen, &pkey_gen)) { + ret = EXCP_ERROR(env, "Can't generate DH key pair"); + goto done; + } + + /* Finally return the OTP representation of the keys: */ + + if (!EVP_PKEY_get_bn_param(pkey_gen, "pub", &pub_key_gen)) { + ret = EXCP_ERROR(env, "Can't get public key"); + goto done; + } + if ((pub_len = BN_num_bytes(pub_key_gen)) < 0 || + (pub_ptr = enif_make_new_binary(env, (size_t)pub_len, &ret_pub)) == NULL || + BN_bn2bin(pub_key_gen, pub_ptr) < 0) + { + ret = EXCP_ERROR(env, "Can't convert public key"); + goto done; + } + + if (!EVP_PKEY_get_bn_param(pkey_gen, "priv", &priv_key_gen)) { + ret = EXCP_ERROR(env, "Can't get private key"); + goto done; + } + if ((prv_len = BN_num_bytes(priv_key_gen)) < 0 || + (prv_ptr = enif_make_new_binary(env, (size_t)prv_len, &ret_prv)) == NULL || + BN_bn2bin(priv_key_gen, prv_ptr) < 0) + { + ret = EXCP_ERROR(env, "Can't convert private key"); + goto done; + } + + ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len); + ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len); + + ret = enif_make_tuple2(env, ret_pub, ret_prv); + + done: + if (pub_key_gen) BN_free(pub_key_gen); + if (priv_key_gen) BN_free(priv_key_gen); + if (pkey) EVP_PKEY_free(pkey); + if (pkey_gen) EVP_PKEY_free(pkey_gen); + if (pctx) EVP_PKEY_CTX_free(pctx); + if (pctx_gen) EVP_PKEY_CTX_free(pctx_gen); + + return ret; +} + +/* Has 3_0 */ +ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (OthersPublicKey, MyPrivateKey, DHParams=[P,G]) */ + ERL_NIF_TERM ret; + ErlNifBinary ret_bin; + size_t sz; + int ret_bin_alloc = 0; + int i = 0; + OSSL_PARAM params[5]; + EVP_PKEY_CTX *own_pctx = NULL, *peer_pctx = NULL, *pctx_gen = NULL; + EVP_PKEY *own_pkey = NULL, *peer_pkey = NULL; + + /* Fetch parameters */ + + /* Build peer_pkey */ + + if (!get_ossl_param_from_bin(env, "pub", argv[0], ¶ms[i++])) + assign_goto(ret, err, EXCP_BADARG_N(env, 0, "Bad peer public key; binary expected")); + + { /*argv[2] - the lists [P,G] */ + ERL_NIF_TERM head, tail; + + head = argv[2]; + if (!get_ossl_param_from_bin_in_list(env, "p", &head, ¶ms[i++])) + assign_goto(ret, err, EXCP_BADARG_N(env, 2, "Bad value of 'p'")); + + if (!get_ossl_param_from_bin_in_list(env, "g", &head, ¶ms[i++])) + assign_goto(ret, err, EXCP_BADARG_N(env, 2, "Bad value of 'g'")); + + tail = head; + if (!enif_is_empty_list(env,tail)) + assign_goto(ret, err, EXCP_BADARG_N(env, 2, "Not a two-element list")); + } + + params[i++] = OSSL_PARAM_construct_end(); + + peer_pctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", 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_KEYPAIR, params) <= 0) + assign_goto(ret, err, EXCP_ERROR(env, "Can't do fromdata")); + + /* Build own_pkey. Just replace the pub key with the priv key in params */ + if (!get_ossl_param_from_bin(env, "priv", argv[1], ¶ms[0])) + assign_goto(ret, err, EXCP_BADARG_N(env, 0, "Bad peer public key; binary expected")); + + own_pctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", 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")); + + + /* Derive the common secret */ + pctx_gen = EVP_PKEY_CTX_new(own_pkey, NULL); + + if (!EVP_PKEY_derive_init(pctx_gen)) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_derive_init")); + + if (!EVP_PKEY_derive_set_peer(pctx_gen, peer_pkey)) + assign_goto(ret, err, EXCP_ERROR(env, "Can't derive secret or set peer")); + + if (!EVP_PKEY_derive(pctx_gen, NULL, &sz)) + 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 (!EVP_PKEY_derive(pctx_gen, ret_bin.data, &ret_bin.size)) + 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; +} + +# else +/* Has not 3.0 */ ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (PrivKey|undefined, DHParams=[P,G], Mpint, Len|0) */ -#ifdef HAVE_DH DH *dh_params = NULL; unsigned int mpint; /* 0 or 4 */ ERL_NIF_TERM head, tail; @@ -36,10 +314,10 @@ ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar int pub_len, prv_len; ERL_NIF_TERM ret_pub, ret_prv, ret; const BIGNUM *pub_key_gen, *priv_key_gen; -#if defined(HAS_EVP_PKEY_CTX) && (! DISABLE_EVP_DH) +# if defined(HAS_EVP_PKEY_CTX) && (! DISABLE_EVP_DH) EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *dhkey = NULL, *params = NULL; -#endif +# endif ASSERT(argc == 4); @@ -100,7 +378,7 @@ ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar assign_goto(ret, err, EXCP_ERROR_N(env, 3, "The length is not accepted")); } -#if defined(HAS_EVP_PKEY_CTX) && (! DISABLE_EVP_DH) +# if defined(HAS_EVP_PKEY_CTX) && (! DISABLE_EVP_DH) if ((params = EVP_PKEY_new()) == NULL) assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_new")); @@ -125,10 +403,10 @@ ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar if ((dh_params = EVP_PKEY_get1_DH(dhkey)) == NULL) assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_get1_DH")); -#else +# else if (!DH_generate_key(dh_params)) assign_goto(ret, err, EXCP_ERROR(env, "Can't DH_generate_key")); -#endif +# endif DH_get0_key(dh_params, &pub_key_gen, &priv_key_gen); @@ -172,24 +450,21 @@ ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar if (dh_params) DH_free(dh_params); -#if defined(HAS_EVP_PKEY_CTX) && (! DISABLE_EVP_DH) +# if defined(HAS_EVP_PKEY_CTX) && (! DISABLE_EVP_DH) if (ctx) EVP_PKEY_CTX_free(ctx); if (dhkey) EVP_PKEY_free(dhkey); if (params) EVP_PKEY_free(params); -#endif +# endif return ret; -#else - return enif_raise_exception(env, atom_notsup); -#endif } + ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (OthersPublicKey, MyPrivateKey, DHParams=[P,G]) */ -#ifdef HAVE_DH BIGNUM *other_pub_key = NULL; BIGNUM *dh_p = NULL; BIGNUM *dh_g = NULL; @@ -287,7 +562,10 @@ ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg DH_free(dh_priv); return ret; -#else - return enif_raise_exception(env, atom_notsup); -#endif } + +# endif /* else part of HAS_3_0_API */ + + + +#endif /* HAVE_DH */ -- 2.34.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor