Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:24
erlang
2597-crypto-ec_generate_key_nif-use-old-code-fo...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 2597-crypto-ec_generate_key_nif-use-old-code-for-the-fail.patch of Package erlang
From f896a9c595666820dcd6c4585953ac246475d1fd Mon Sep 17 00:00:00 2001 From: Hans Nilsson <hans@erlang.org> Date: Thu, 28 Apr 2022 20:53:51 +0200 Subject: [PATCH 7/7] crypto: ec_generate_key_nif - use old code for the failing case --- lib/crypto/c_src/ec.c | 278 ++++++++++++++++++++++++++++++++---------- lib/crypto/c_src/ec.h | 8 +- 2 files changed, 219 insertions(+), 67 deletions(-) diff --git a/lib/crypto/c_src/ec.c b/lib/crypto/c_src/ec.c index 58a51f862c..f14768d134 100644 --- a/lib/crypto/c_src/ec.c +++ b/lib/crypto/c_src/ec.c @@ -22,7 +22,6 @@ #include "bn.h" #ifdef HAVE_EC - # if defined(HAS_3_0_API) int get_curve_definition(ErlNifEnv* env, ERL_NIF_TERM *ret, ERL_NIF_TERM def, @@ -205,7 +204,7 @@ int get_curve_definition(ErlNifEnv* env, ERL_NIF_TERM *ret, ERL_NIF_TERM def, } int get_ec_public_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey) -{ +{ /* key :: {CurveDef::{_,_,_,_,_}, PubKey::binary()} */ ERL_NIF_TERM ret = atom_undefined; const ERL_NIF_TERM *tpl_terms; int tpl_arity; @@ -248,40 +247,41 @@ int get_ec_public_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey) } -int get_ec_private_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey) +int get_ec_private_key_2(ErlNifEnv* env, + ERL_NIF_TERM curve, ERL_NIF_TERM key, + EVP_PKEY **pkey, + ERL_NIF_TERM *ret, + size_t *order_size); + +int get_ec_private_key_2(ErlNifEnv* env, + ERL_NIF_TERM curve, ERL_NIF_TERM key, + EVP_PKEY **pkey, + ERL_NIF_TERM *ret, + size_t *order_size) { - ERL_NIF_TERM ret = atom_undefined; - const ERL_NIF_TERM *tpl_terms; - int tpl_arity; int i = 0; OSSL_PARAM params[15]; EVP_PKEY_CTX *pctx = NULL; - if (!enif_get_tuple(env, key, &tpl_arity, &tpl_terms) || - (tpl_arity != 2) || - !enif_is_tuple(env, tpl_terms[0]) || - !enif_is_binary(env, tpl_terms[1]) ) - assign_goto(ret, err, EXCP_BADARG_N(env, 0, "Bad private key format")); - - if (!get_ossl_BN_param_from_bin(env, "priv", tpl_terms[1], ¶ms[i++])) - assign_goto(ret, err, EXCP_BADARG_N(env, 0, "Bad private key")); + if (!get_ossl_BN_param_from_bin(env, "priv", key, ¶ms[i++])) + assign_goto(*ret, err, EXCP_BADARG_N(env, 0, "Bad private key")); - if (!get_curve_definition(env, &ret, tpl_terms[0], params, &i, NULL)) + if (!get_curve_definition(env, ret, curve, params, &i, order_size)) goto err; params[i++] = OSSL_PARAM_construct_end(); if (!(pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL))) - assign_goto(ret, err, EXCP_ERROR(env, "Can't make EVP_PKEY_CTX")); + assign_goto(*ret, err, EXCP_ERROR(env, "Can't make EVP_PKEY_CTX")); if (EVP_PKEY_fromdata_init(pctx) <= 0) - assign_goto(ret, err, EXCP_ERROR(env, "Can't init fromdata")); + assign_goto(*ret, err, EXCP_ERROR(env, "Can't init fromdata")); if (EVP_PKEY_fromdata(pctx, pkey, EVP_PKEY_KEYPAIR, params) <= 0) - assign_goto(ret, err, EXCP_ERROR(env, "Can't do fromdata")); + assign_goto(*ret, err, EXCP_ERROR(env, "Can't do fromdata")); if (!*pkey) - assign_goto(ret, err, EXCP_ERROR(env, "Couldn't get a private key")); + assign_goto(*ret, err, EXCP_ERROR(env, "Couldn't get a private key")); if (pctx) EVP_PKEY_CTX_free(pctx); return 1; @@ -291,29 +291,180 @@ int get_ec_private_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey) return 0; } -# endif /* HAS_3_0_API */ +int get_ec_private_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey) +{ /* key :: {CurveDef::{_,_,_,_,_}, PrivKey::binary()} */ + ERL_NIF_TERM ret = atom_undefined; + const ERL_NIF_TERM *tpl_terms; + int tpl_arity; + if (!enif_get_tuple(env, key, &tpl_arity, &tpl_terms) || + (tpl_arity != 2) || + !enif_is_tuple(env, tpl_terms[0]) || + !enif_is_binary(env, tpl_terms[1]) ) + assign_goto(ret, err, EXCP_BADARG_N(env, 0, "Bad private key format")); + + if (!get_ec_private_key_2(env, tpl_terms[0], tpl_terms[1], pkey, &ret, NULL)) + goto err; + return 1; -/*---------------------------------------------------------------- - Non 3.0-specific functions -*/ + err: + return 0; +} -static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg, size_t *size); -static ERL_NIF_TERM point2term(ErlNifEnv* env, - const EC_GROUP *group, - const EC_POINT *point, - point_conversion_form_t form); +int mk_pub_key_binary(ErlNifEnv* env, EVP_PKEY **peer_pkey, ErlNifBinary *pubkey_bin, ERL_NIF_TERM *ret); -ERL_NIF_TERM make_badarg_maybe(ErlNifEnv* env) +ERL_NIF_TERM ec_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ /* (Curve, PrivKey|undefined) */ + ERL_NIF_TERM ret = atom_undefined; + int i = 0; + OSSL_PARAM params[15]; + EVP_PKEY_CTX *pctx = NULL; + EVP_PKEY *pkey = NULL, *peer_pkey = NULL; + size_t sz, order_size; + BIGNUM *priv_bn = NULL; + ErlNifBinary pubkey_bin; + + if (argv[1] != atom_undefined) + { + if (!get_ec_private_key_2(env, argv[0], argv[1], &peer_pkey, &ret, &order_size)) + goto err; + + /* Get the two keys, pub as binary and priv as BN. + Since the private key is explicitly given, it must be calculated. + I haven't found any way to do that with the pure 3.0 interface yet. + */ + if (!mk_pub_key_binary(env, &peer_pkey, &pubkey_bin, &ret)) + goto err; + + if (!EVP_PKEY_get_bn_param(peer_pkey, "priv", &priv_bn)) + assign_goto(ret, err, EXCP_BADARG_N(env, 1, "Couldn't get peer priv key bytes")); + } + else + { + /* PrivKey (that is, argv[1]) == atom_undefined */ + if (!get_curve_definition(env, &ret, argv[0], params, &i, &order_size)) + // INSERT "ret" parameter in get_curve_definition !! + assign_goto(ret, err, EXCP_BADARG_N(env, 0, "Couldn't get Curve definition")); + + params[i++] = OSSL_PARAM_construct_end(); + + /* Neither the private nor the public key is known, so we generate the pair: */ + if (!(pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL))) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_new_from_name")); + + if (EVP_PKEY_keygen_init(pctx) <= 0) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_keygen_init")); + + if (!EVP_PKEY_CTX_set_params(pctx, params)) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_set_params")); + + if (!EVP_PKEY_generate(pctx, &pkey)) + assign_goto(ret, err, EXCP_ERROR(env, "Couldn't generate EC key")); + + /* Get the two keys, pub as binary and priv as BN */ + if (!EVP_PKEY_get_octet_string_param(pkey, "encoded-pub-key", NULL, 0, &sz)) + assign_goto(ret, err, EXCP_ERROR(env, "Can't get pub octet string size")); + + if (!enif_alloc_binary(sz, &pubkey_bin)) + assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate pub octet string")); + + if (!EVP_PKEY_get_octet_string_param(pkey, "encoded-pub-key", + pubkey_bin.data, + sz, + &pubkey_bin.size)) + assign_goto(ret, err, EXCP_ERROR(env, "Can't get pub octet string")); + + if (!EVP_PKEY_get_bn_param(pkey, "priv", &priv_bn)) + assign_goto(ret, err, EXCP_BADARG_N(env, 1, "Couldn't get priv key bytes")); + } + + ret = enif_make_tuple2(env, + enif_make_binary(env, &pubkey_bin), + bn2term(env, order_size, priv_bn)); + err: + if (pkey) EVP_PKEY_free(pkey); + if (peer_pkey) EVP_PKEY_free(peer_pkey); + if (pctx) EVP_PKEY_CTX_free(pctx); + if (priv_bn) BN_free(priv_bn); + + return ret; +} + +int mk_pub_key_binary(ErlNifEnv* env, EVP_PKEY **peer_pkey, ErlNifBinary *pubkey_bin, ERL_NIF_TERM *ret) { - ERL_NIF_TERM reason; - if (enif_has_pending_exception(env, &reason)) - return reason; /* dummy return value ignored */ + EC_KEY *ec_key = NULL; + EC_POINT *public_key = NULL; + EC_GROUP *group = NULL; + BIGNUM *priv_bn = NULL; + + *ret = atom_undefined; + + /* Use the deprecated interface to get the curve and + private key in pre 3.0 form: */ + if ((ec_key = EVP_PKEY_get1_EC_KEY(*peer_pkey)) == NULL) + assign_goto(*ret, err, EXCP_ERROR(env, "Couldn't get EC key")); + + if ((group = EC_GROUP_dup(EC_KEY_get0_group(ec_key))) == NULL) + assign_goto(*ret, err, EXCP_ERROR(env, "Couldn't get EC_GROUP")); + + if ((public_key = EC_POINT_new(group)) == NULL) + assign_goto(*ret, err, EXCP_ERROR(env, "Couldn't create POINT")); + + if (!EC_POINT_copy(public_key, EC_GROUP_get0_generator(group))) + assign_goto(*ret, err, EXCP_ERROR(env, "Couldn't copy POINT")); + + /* Make the corresponding public key */ + if (!EVP_PKEY_get_bn_param(*peer_pkey, "priv", &priv_bn)) + assign_goto(*ret, err, EXCP_BADARG_N(env, 1, "Couldn't get peer priv key bytes")); + + if (BN_is_zero(priv_bn)) + assign_goto(*ret, err, EXCP_BADARG_N(env, 1, "peer priv key must not be 0")); + + if (!EC_POINT_mul(group, public_key, priv_bn, NULL, NULL, NULL)) + assign_goto(*ret, err, EXCP_ERROR(env, "Couldn't multiply POINT")); + + if (!EC_KEY_set_public_key(ec_key, public_key)) + assign_goto(*ret, err, EXCP_ERROR(env, "Couldn't set EC_KEY")); + + if (!EVP_PKEY_assign_EC_KEY(*peer_pkey, ec_key)) + assign_goto(*ret, err, EXCP_ERROR(env, "Couldn't assign EC_KEY to PKEY")); + + /* And now get the binary representation (by some reason we can't read it from + peer_pubkey in the calling function with 3.0-functions.) + */ + { + point_conversion_form_t form = EC_KEY_get_conv_form(ec_key); + size_t dlen = EC_POINT_point2oct(group, public_key, form, NULL, 0, NULL); + + if (!enif_alloc_binary(dlen, pubkey_bin) || + !EC_POINT_point2oct(group, public_key, form, pubkey_bin->data, pubkey_bin->size, NULL) + ) + assign_goto(*ret, err, EXCP_ERROR(env, "Couldn't get public key")); + } + + err: + if (public_key) EC_POINT_free(public_key); + if (group) EC_GROUP_free(group); + if (priv_bn) BN_free(priv_bn); + + if (*ret == atom_undefined) + return 1; else - return enif_make_badarg(env); + return 0; } + +# endif /* HAS_3_0_API */ + + + + +/*---------------------------------------------------------------- + Non 3.0-specific functions +*/ + +# if ! defined(HAS_3_0_API) static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg, size_t *size) { @@ -509,6 +660,33 @@ static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg, size_t *size) return key; } +int term2point(ErlNifEnv* env, ERL_NIF_TERM term, EC_GROUP *group, EC_POINT **pptr) +{ + ErlNifBinary bin; + EC_POINT *point = NULL; + + if (!enif_inspect_binary(env, term, &bin)) + goto err; + + if ((point = EC_POINT_new(group)) == NULL) + goto err; + + /* set the point conversion form */ + EC_GROUP_set_point_conversion_form(group, (point_conversion_form_t)(bin.data[0] & ~0x01)); + + /* extract the ec point */ + if (!EC_POINT_oct2point(group, point, bin.data, bin.size, NULL)) + goto err; + + *pptr = point; + return 1; + + err: + if (point) + EC_POINT_free(point); + return 0; +} + static ERL_NIF_TERM point2term(ErlNifEnv* env, const EC_GROUP *group, const EC_POINT *point, @@ -544,35 +722,6 @@ static ERL_NIF_TERM point2term(ErlNifEnv* env, return ret; } -int term2point(ErlNifEnv* env, ERL_NIF_TERM term, EC_GROUP *group, EC_POINT **pptr) -{ - ErlNifBinary bin; - EC_POINT *point = NULL; - - if (!enif_inspect_binary(env, term, &bin)) - goto err; - - if ((point = EC_POINT_new(group)) == NULL) - goto err; - - /* set the point conversion form */ - EC_GROUP_set_point_conversion_form(group, (point_conversion_form_t)(bin.data[0] & ~0x01)); - - /* extract the ec point */ - if (!EC_POINT_oct2point(group, point, bin.data, bin.size, NULL)) - goto err; - - *pptr = point; - return 1; - - err: - if (point) - EC_POINT_free(point); - return 0; -} - -# if ! defined(HAS_3_0_API) - int get_ec_private_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey) { const ERL_NIF_TERM *tpl_terms; @@ -633,7 +782,6 @@ int get_ec_public_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey) return 0; } -# endif /* ! HAS_3_0_API */ int get_ec_key_sz(ErlNifEnv* env, ERL_NIF_TERM curve, ERL_NIF_TERM priv, ERL_NIF_TERM pub, @@ -707,7 +855,6 @@ int get_ec_key_sz(ErlNifEnv* env, return 1; } - ERL_NIF_TERM ec_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { /* (Curve, PrivKey) */ EC_KEY *key = NULL; @@ -747,6 +894,9 @@ ERL_NIF_TERM ec_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar EC_KEY_free(key); return ret; } + +# endif /* ! HAS_3_0_API */ + #endif /* HAVE_EC */ diff --git a/lib/crypto/c_src/ec.h b/lib/crypto/c_src/ec.h index 3b010f0c42..e53986d64e 100644 --- a/lib/crypto/c_src/ec.h +++ b/lib/crypto/c_src/ec.h @@ -31,13 +31,15 @@ int get_curve_definition(ErlNifEnv* env, ERL_NIF_TERM *ret, ERL_NIF_TERM def, size_t *order_size); # endif /* HAS_3_0_API */ +# if ! defined(HAS_3_0_API) +int get_ec_key_sz(ErlNifEnv* env, ERL_NIF_TERM curve, ERL_NIF_TERM priv, ERL_NIF_TERM pub, + EC_KEY** res, size_t* size); +# endif + int get_ec_public_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey); int get_ec_private_key(ErlNifEnv* env, ERL_NIF_TERM key, EVP_PKEY **pkey); -int get_ec_key_sz(ErlNifEnv* env, ERL_NIF_TERM curve, ERL_NIF_TERM priv, ERL_NIF_TERM pub, - EC_KEY** res, size_t* size); int term2point(ErlNifEnv* env, ERL_NIF_TERM term, EC_GROUP *group, EC_POINT **pptr); -ERL_NIF_TERM make_badarg_maybe(ErlNifEnv* env); #endif ERL_NIF_TERM ec_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -- 2.35.3
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