diff options
Diffstat (limited to 'lib/crypto/c_src/crypto.c')
-rw-r--r-- | lib/crypto/c_src/crypto.c | 397 |
1 files changed, 330 insertions, 67 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 149387bcee..e4eb2bc3b6 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -60,7 +60,6 @@ #include <openssl/rand.h> #include <openssl/evp.h> #include <openssl/hmac.h> -#include <openssl/engine.h> #include <openssl/err.h> /* Helper macro to construct a OPENSSL_VERSION_NUMBER. @@ -102,8 +101,10 @@ # undef FIPS_SUPPORT # endif +# if LIBRESSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(2,7,0) /* LibreSSL wants the 1.0.1 API */ # define NEED_EVP_COMPATIBILITY_FUNCTIONS +# endif #endif @@ -112,8 +113,10 @@ #endif -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0) -# define HAS_EVP_PKEY_CTX +#ifndef HAS_LIBRESSL +# if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0) +# define HAS_EVP_PKEY_CTX +# endif #endif @@ -121,10 +124,6 @@ #include <openssl/modes.h> #endif -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'h') -#define HAS_ENGINE_SUPPORT -#endif - #include "crypto_callback.h" #if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(0,9,8) \ @@ -156,6 +155,14 @@ # define HAVE_EC #endif +// (test for == 1.1.1pre8) +#if OPENSSL_VERSION_NUMBER == (PACKED_OPENSSL_VERSION_PLAIN(1,1,1) - 7) \ + && !defined(HAS_LIBRESSL) \ + && defined(HAVE_EC) +// EXPERIMENTAL: +# define HAVE_EDDH +#endif + #if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'c') # define HAVE_AES_IGE #endif @@ -185,6 +192,19 @@ # undef HAVE_RSA_SSLV23_PADDING #endif +#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'h') \ + && defined(HAVE_EC) +/* If OPENSSL_NO_EC is set, there will be an error in ec.h included from engine.h + So if EC is disabled, you can't use Engine either.... +*/ +# define HAS_ENGINE_SUPPORT +#endif + + +#if defined(HAS_ENGINE_SUPPORT) +# include <openssl/engine.h> +#endif + #if defined(HAVE_CMAC) #include <openssl/cmac.h> #endif @@ -489,6 +509,9 @@ static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_ static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM evp_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + static ERL_NIF_TERM rand_seed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_gcm_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -500,7 +523,6 @@ static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_N static ERL_NIF_TERM chacha20_poly1305_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM chacha20_poly1305_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i); static ERL_NIF_TERM engine_by_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM engine_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM engine_finish_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -528,10 +550,12 @@ static int term2point(ErlNifEnv* env, ERL_NIF_TERM term, static ERL_NIF_TERM bin_from_bn(ErlNifEnv* env, const BIGNUM *bn); #ifdef HAS_ENGINE_SUPPORT +static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i); static int zero_terminate(ErlNifBinary bin, char **buf); #endif static int library_refc = 0; /* number of users of this dynamic library */ +static int library_initialized = 0; static ErlNifFunc nif_funcs[] = { {"info_lib", 0, info_lib}, @@ -568,6 +592,10 @@ static ErlNifFunc nif_funcs[] = { {"rsa_generate_key_nif", 2, rsa_generate_key_nif}, {"dh_generate_key_nif", 4, dh_generate_key_nif}, {"dh_compute_key_nif", 3, dh_compute_key_nif}, + + {"evp_compute_key_nif", 3, evp_compute_key_nif}, + {"evp_generate_key_nif", 1, evp_generate_key_nif}, + {"privkey_to_pubkey_nif", 2, privkey_to_pubkey_nif}, {"srp_value_B_nif", 5, srp_value_B_nif}, {"srp_user_secret_nif", 7, srp_user_secret_nif}, @@ -655,6 +683,13 @@ static ERL_NIF_TERM atom_blowfish_ecb; static ERL_NIF_TERM atom_rsa; static ERL_NIF_TERM atom_dss; static ERL_NIF_TERM atom_ecdsa; + +#ifdef HAVE_EDDH +static ERL_NIF_TERM atom_eddh; +static ERL_NIF_TERM atom_x25519; +static ERL_NIF_TERM atom_x448; +#endif + static ERL_NIF_TERM atom_rsa_mgf1_md; static ERL_NIF_TERM atom_rsa_oaep_label; static ERL_NIF_TERM atom_rsa_oaep_md; @@ -993,14 +1028,14 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info) PRINTF_ERR0("CRYPTO: Could not open resource type 'ENGINE_CTX'"); return __LINE__; } +#endif - if (library_refc > 0) { + if (library_initialized) { /* Repeated loading of this library (module upgrade). * Atoms and callbacks are already set, we are done. */ return 0; } -#endif atom_true = enif_make_atom(env,"true"); atom_false = enif_make_atom(env,"false"); @@ -1062,6 +1097,11 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info) atom_rsa = enif_make_atom(env,"rsa"); atom_dss = enif_make_atom(env,"dss"); atom_ecdsa = enif_make_atom(env,"ecdsa"); +#ifdef HAVE_EDDH + atom_eddh = enif_make_atom(env,"eddh"); + atom_x25519 = enif_make_atom(env,"x25519"); + atom_x448 = enif_make_atom(env,"x448"); +#endif atom_rsa_mgf1_md = enif_make_atom(env,"rsa_mgf1_md"); atom_rsa_oaep_label = enif_make_atom(env,"rsa_oaep_label"); atom_rsa_oaep_md = enif_make_atom(env,"rsa_oaep_md"); @@ -1107,9 +1147,6 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info) atom_password = enif_make_atom(env,"password"); #endif - init_digest_types(env); - init_cipher_types(env); - init_algorithms_types(env); #ifdef HAVE_DYNAMIC_CRYPTO_LIB { @@ -1156,6 +1193,11 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info) } #endif /* OPENSSL_THREADS */ + init_digest_types(env); + init_cipher_types(env); + init_algorithms_types(env); + + library_initialized = 1; return 0; } @@ -1197,11 +1239,13 @@ static void unload(ErlNifEnv* env, void* priv_data) static int algo_hash_cnt, algo_hash_fips_cnt; static ERL_NIF_TERM algo_hash[8]; /* increase when extending the list */ static int algo_pubkey_cnt, algo_pubkey_fips_cnt; -static ERL_NIF_TERM algo_pubkey[7]; /* increase when extending the list */ +static ERL_NIF_TERM algo_pubkey[11]; /* increase when extending the list */ static int algo_cipher_cnt, algo_cipher_fips_cnt; static ERL_NIF_TERM algo_cipher[24]; /* increase when extending the list */ static int algo_mac_cnt, algo_mac_fips_cnt; static ERL_NIF_TERM algo_mac[2]; /* increase when extending the list */ +static int algo_curve_cnt, algo_curve_fips_cnt; +static ERL_NIF_TERM algo_curve[87]; /* increase when extending the list */ static void init_algorithms_types(ErlNifEnv* env) { @@ -1239,6 +1283,9 @@ static void init_algorithms_types(ErlNifEnv* env) #endif // Non-validated algorithms follow algo_pubkey_fips_cnt = algo_pubkey_cnt; +#ifdef HAVE_EDDH + algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "eddh"); +#endif algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "srp"); // Validated algorithms first @@ -1294,10 +1341,23 @@ static void init_algorithms_types(ErlNifEnv* env) // Non-validated algorithms follow algo_mac_fips_cnt = algo_mac_cnt; + + // Validated algorithms first + algo_curve_cnt = 0; + // Non-validated algorithms follow + algo_curve_fips_cnt = algo_curve_cnt; + //-- +#ifdef HAVE_EDDH + algo_curve[algo_curve_cnt++] = enif_make_atom(env,"x25519"); + algo_curve[algo_curve_cnt++] = enif_make_atom(env,"x448"); +#endif + + // Check that the max number of algos is updated ASSERT(algo_hash_cnt <= sizeof(algo_hash)/sizeof(ERL_NIF_TERM)); ASSERT(algo_pubkey_cnt <= sizeof(algo_pubkey)/sizeof(ERL_NIF_TERM)); ASSERT(algo_cipher_cnt <= sizeof(algo_cipher)/sizeof(ERL_NIF_TERM)); ASSERT(algo_mac_cnt <= sizeof(algo_mac)/sizeof(ERL_NIF_TERM)); + ASSERT(algo_curve_cnt <= sizeof(algo_curve)/sizeof(ERL_NIF_TERM)); } static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -1308,17 +1368,20 @@ static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv int pubkey_cnt = fips_mode ? algo_pubkey_fips_cnt : algo_pubkey_cnt; int cipher_cnt = fips_mode ? algo_cipher_fips_cnt : algo_cipher_cnt; int mac_cnt = fips_mode ? algo_mac_fips_cnt : algo_mac_cnt; + int curve_cnt = fips_mode ? algo_curve_fips_cnt : algo_curve_cnt; #else int hash_cnt = algo_hash_cnt; int pubkey_cnt = algo_pubkey_cnt; int cipher_cnt = algo_cipher_cnt; int mac_cnt = algo_mac_cnt; + int curve_cnt = algo_curve_cnt; #endif - return enif_make_tuple4(env, - enif_make_list_from_array(env, algo_hash, hash_cnt), + return enif_make_tuple5(env, + enif_make_list_from_array(env, algo_hash, hash_cnt), enif_make_list_from_array(env, algo_pubkey, pubkey_cnt), enif_make_list_from_array(env, algo_cipher, cipher_cnt), - enif_make_list_from_array(env, algo_mac, mac_cnt) + enif_make_list_from_array(env, algo_mac, mac_cnt), + enif_make_list_from_array(env, algo_curve, curve_cnt) ); } @@ -1739,6 +1802,7 @@ static ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM } #endif /* OPENSSL_VERSION_NUMBER < 1.0 */ + static ERL_NIF_TERM hmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Type, Key, Data) or (Type, Key, Data, MacSize) */ struct digest_type_t *digp = NULL; @@ -3004,16 +3068,21 @@ static ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (PrivKey|undefined, DHParams=[P,G], Mpint, Len|0) */ - DH* dh_params; + DH* dh_params = NULL; int pub_len, prv_len; unsigned char *pub_ptr, *prv_ptr; ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail; int mpint; /* 0 or 4 */ - BIGNUM *priv_key = NULL; + BIGNUM *priv_key_in = NULL; BIGNUM *dh_p = NULL, *dh_g = NULL; unsigned long len = 0; +#ifdef HAS_EVP_PKEY_CTX + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *dhkey = NULL, + *params = NULL; +#endif - if (!(get_bn_from_bin(env, argv[0], &priv_key) + if (!(get_bn_from_bin(env, argv[0], &priv_key_in) || argv[0] == atom_undefined) || !enif_get_list_cell(env, argv[1], &head, &tail) || !get_bn_from_bin(env, head, &dh_p) @@ -3021,40 +3090,64 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_ || !get_bn_from_bin(env, head, &dh_g) || !enif_is_empty_list(env, tail) || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4) - || !enif_get_ulong(env, argv[3], &len) ) { - - if (priv_key) BN_free(priv_key); + || !enif_get_ulong(env, argv[3], &len) + + /* Load dh_params with values to use by the generator. + Mem mgmnt transfered from dh_p etc to dh_params */ + || !(dh_params = DH_new()) + || (priv_key_in && !DH_set0_key(dh_params, NULL, priv_key_in)) + || !DH_set0_pqg(dh_params, dh_p, NULL, dh_g) + ) { + if (priv_key_in) BN_free(priv_key_in); if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); + if (dh_params) DH_free(dh_params); return enif_make_badarg(env); } - dh_params = DH_new(); - DH_set0_key(dh_params, NULL, priv_key); - DH_set0_pqg(dh_params, dh_p, NULL, dh_g); - if (len) { if (len < BN_num_bits(dh_p)) DH_set_length(dh_params, len); else { - DH_free(dh_params); + if (priv_key_in) BN_free(priv_key_in); + if (dh_p) BN_free(dh_p); + if (dh_g) BN_free(dh_g); + if (dh_params) DH_free(dh_params); return enif_make_badarg(env); } } +#ifdef HAS_EVP_PKEY_CTX + if ((dhkey = EVP_PKEY_new()) + && (params = EVP_PKEY_new()) + && EVP_PKEY_set1_DH(params, dh_params) /* set the key referenced by params to dh_params. + dh_params (and params) must be freed */ + && (ctx = EVP_PKEY_CTX_new(params, NULL)) + && EVP_PKEY_keygen_init(ctx) + && EVP_PKEY_keygen(ctx, &dhkey) /* "performs a key generation operation, the + generated key is written to ppkey." (=last arg) */ + && (dh_params = EVP_PKEY_get1_DH(dhkey)) /* return the referenced key. dh_params and dhkey must be freed */ + ) { +#else if (DH_generate_key(dh_params)) { - const BIGNUM *pub_key, *priv_key; - DH_get0_key(dh_params, &pub_key, &priv_key); - pub_len = BN_num_bytes(pub_key); - prv_len = BN_num_bytes(priv_key); +#endif + const BIGNUM *pub_key_gen, *priv_key_gen; + + DH_get0_key(dh_params, + &pub_key_gen, &priv_key_gen); /* Get pub_key_gen and priv_key_gen. + "The values point to the internal representation of + the public key and private key values. This memory + should not be freed directly." says man */ + pub_len = BN_num_bytes(pub_key_gen); + prv_len = BN_num_bytes(priv_key_gen); pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub); prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv); if (mpint) { put_int32(pub_ptr, pub_len); pub_ptr += 4; put_int32(prv_ptr, prv_len); prv_ptr += 4; } - BN_bn2bin(pub_key, pub_ptr); - BN_bn2bin(priv_key, prv_ptr); + BN_bn2bin(pub_key_gen, pub_ptr); + BN_bn2bin(priv_key_gen, prv_ptr); 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); @@ -3062,21 +3155,33 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_ else { ret = atom_error; } + DH_free(dh_params); +#ifdef HAS_EVP_PKEY_CTX + if (ctx) EVP_PKEY_CTX_free(ctx); + if (dhkey) EVP_PKEY_free(dhkey); + if (params) EVP_PKEY_free(params); +#endif return ret; } static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (OthersPublicKey, MyPrivateKey, DHParams=[P,G]) */ - DH* dh_params; - BIGNUM *dummy_pub_key = NULL, *priv_key = NULL; - BIGNUM *other_pub_key; - BIGNUM *dh_p = NULL, *dh_g = NULL; - int i; + BIGNUM *dummy_pub_key = NULL, + *priv_key = NULL, + *other_pub_key = NULL, + *dh_p = NULL, + *dh_g = NULL; ErlNifBinary ret_bin; ERL_NIF_TERM ret, head, tail; - - dh_params = DH_new(); + DH *dh_priv = DH_new(), *dh_pub = DH_new(); +#ifdef HAS_EVP_PKEY_CTX + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *my_priv_key = NULL, *peer_pub_key = NULL; + size_t skeylen; +#else + int i; +#endif if (!get_bn_from_bin(env, argv[0], &other_pub_key) || !get_bn_from_bin(env, argv[1], &priv_key) @@ -3084,35 +3189,78 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T || !get_bn_from_bin(env, head, &dh_p) || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_bin(env, head, &dh_g) - || !enif_is_empty_list(env, tail)) { + || !enif_is_empty_list(env, tail) + + /* Note: DH_set0_key() does not allow setting only the + * private key, although DH_compute_key() does not use the + * public key. Work around this limitation by setting + * the public key to a copy of the private key. + */ + || !(dummy_pub_key = BN_dup(priv_key)) + || !DH_set0_key(dh_priv, dummy_pub_key, priv_key) + || !DH_set0_pqg(dh_priv, dh_p, NULL, dh_g) + ) { if (dh_p) BN_free(dh_p); if (dh_g) BN_free(dh_g); - ret = enif_make_badarg(env); + if (other_pub_key) BN_free(other_pub_key); + if (dummy_pub_key) BN_free(dummy_pub_key); + if (priv_key) BN_free(priv_key); + return enif_make_badarg(env); + } + +#ifdef HAS_EVP_PKEY_CTX + if (!(my_priv_key = EVP_PKEY_new()) + || !EVP_PKEY_set1_DH(my_priv_key, dh_priv) /* set the key referenced by my_priv_key to dh_priv. + dh_priv (and my_priv_key) must be freed by us*/ + + || !(peer_pub_key = EVP_PKEY_new()) + || !DH_set0_key(dh_pub, other_pub_key, NULL) + || !DH_set0_pqg(dh_pub, dh_p, NULL, dh_g) + || !EVP_PKEY_set1_DH(peer_pub_key, dh_pub) + + || !(ctx = EVP_PKEY_CTX_new(my_priv_key, NULL)) + || (EVP_PKEY_derive_init(ctx) <= 0) + || (EVP_PKEY_derive_set_peer(ctx, peer_pub_key) <= 0) + || (EVP_PKEY_derive(ctx, NULL, &skeylen) <= 0)) { + + ret = atom_error; } else { - /* Note: DH_set0_key() does not allow setting only the - * private key, although DH_compute_key() does not use the - * public key. Work around this limitation by setting - * the public key to a copy of the private key. - */ - dummy_pub_key = BN_dup(priv_key); - DH_set0_key(dh_params, dummy_pub_key, priv_key); - DH_set0_pqg(dh_params, dh_p, NULL, dh_g); - enif_alloc_binary(DH_size(dh_params), &ret_bin); - i = DH_compute_key(ret_bin.data, other_pub_key, dh_params); - if (i > 0) { - if (i != ret_bin.size) { - enif_realloc_binary(&ret_bin, i); - } - ret = enif_make_binary(env, &ret_bin); - } - else { + enif_alloc_binary(skeylen, &ret_bin); + + if ((EVP_PKEY_derive(ctx, ret_bin.data, &skeylen) > 0) + && (ret_bin.size >= skeylen)) { + /* Derivation succeded */ + if (ret_bin.size > skeylen) enif_realloc_binary(&ret_bin, skeylen); + ret = enif_make_binary(env, &ret_bin); + } + else { enif_release_binary(&ret_bin); - ret = atom_error; - } + ret = atom_error; + } } + +#else + enif_alloc_binary(DH_size(dh_priv), &ret_bin); + i = DH_compute_key(ret_bin.data, other_pub_key, dh_priv); + if (i > 0) { + if (i != ret_bin.size) enif_realloc_binary(&ret_bin, i); + ret = enif_make_binary(env, &ret_bin); + } + else { + enif_release_binary(&ret_bin); + ret = atom_error; + } +#endif + if (other_pub_key) BN_free(other_pub_key); - DH_free(dh_params); + if (dh_priv) DH_free(dh_priv); + if (dh_pub) DH_free(dh_pub); +#ifdef HAS_EVP_PKEY_CTX + if (ctx) EVP_PKEY_CTX_free(ctx); + if (my_priv_key) EVP_PKEY_free(my_priv_key); + /* if (peer_pub_key) EVP_PKEY_free(peer_pub_key); */ +#endif return ret; } @@ -3720,6 +3868,123 @@ out_err: #endif } +// EXPERIMENTAL! +static ERL_NIF_TERM evp_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) + /* (Curve, PeerBin, MyBin) */ +{ +#ifdef HAVE_EDDH + int type; + EVP_PKEY_CTX *ctx; + ErlNifBinary peer_bin, my_bin, key_bin; + EVP_PKEY *peer_key, *my_key; + size_t max_size; + + if (argv[0] == atom_x25519) type = EVP_PKEY_X25519; + else if (argv[0] == atom_x448) type = EVP_PKEY_X448; + else return enif_make_badarg(env); + + if (!enif_inspect_binary(env, argv[1], &peer_bin) || + !enif_inspect_binary(env, argv[2], &my_bin)) { + return enif_make_badarg(env); + } + + if (!(my_key = EVP_PKEY_new_raw_private_key(type, NULL, my_bin.data, my_bin.size)) || + !(ctx = EVP_PKEY_CTX_new(my_key, NULL))) { + return enif_make_badarg(env); + } + + if (!EVP_PKEY_derive_init(ctx)) { + return enif_make_badarg(env); + } + + if (!(peer_key = EVP_PKEY_new_raw_public_key(type, NULL, peer_bin.data, peer_bin.size)) || + !EVP_PKEY_derive_set_peer(ctx, peer_key)) { + return enif_make_badarg(env); + } + + if (!EVP_PKEY_derive(ctx, NULL, &max_size)) { + return enif_make_badarg(env); + } + + if (!enif_alloc_binary(max_size, &key_bin) || + !EVP_PKEY_derive(ctx, key_bin.data, &key_bin.size)) { + return enif_make_badarg(env); + } + + if (key_bin.size < max_size) { + size_t actual_size = key_bin.size; + if (!enif_realloc_binary(&key_bin, actual_size)) { + return enif_make_badarg(env); + } + } + + return enif_make_binary(env, &key_bin); + +/* Importing the other side's public key from raw binary format can be done with the EVP_PKEY_new_raw_public_key() function. Man page here: */ +/* https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_new_raw_public_key.html */ + + +/* You need two EVP_PKEY objects. One containing your private/public key pair (i.e. the one you generated in the EVP_PKEY_keygen() call in your question), and one containing the public key of the peer (e.g. created using EVP_PKEY_new_raw_public_key()). To generate the X25519 shared secret you then call EVP_PKEY_derive(). See the example on the man page: openssl.org/docs/man1.1.1/man3/EVP_PKEY_derive.html – Matt Caswell May 15 at 20:39 */ + +#else + return atom_notsup; +#endif +} + +// EXPERIMENTAL! +static ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +/* (Curve) */ +{ +#ifdef HAVE_EDDH + int type; + EVP_PKEY_CTX *ctx; + EVP_PKEY *pkey = NULL; + ERL_NIF_TERM ret_pub, ret_prv; + size_t key_len; + + if (argv[0] == atom_x25519) type = EVP_PKEY_X25519; + else if (argv[0] == atom_x448) type = EVP_PKEY_X448; + else return enif_make_badarg(env); + + if (!(ctx = EVP_PKEY_CTX_new_id(type, NULL))) return enif_make_badarg(env); + + if (!EVP_PKEY_keygen_init(ctx)) return enif_make_atom(env,"EVP_PKEY_keygen_init failed"); + if (!EVP_PKEY_keygen(ctx, &pkey)) return enif_make_atom(env,"EVP_PKEY_keygen failed"); + + /* + int EVP_PKEY_get_raw_private_key(const EVP_PKEY *pkey, unsigned char *priv, size_t *len) + int EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub, size_t *len) + + +EVP_PKEY_get_raw_private_key() fills the buffer provided by B<priv> with raw + +private key data. The number of bytes written is populated in B<*len>. If the + +buffer B<priv> is NULL then B<*len> is populated with the number of bytes + +required in the buffer. The calling application is responsible for ensuring that + +the buffer is large enough to receive the private key data. This function only + +works for algorithms that support raw private keys. Currently this is: + +B<EVP_PKEY_HMAC>, B<EVP_PKEY_POLY1305>, B<EVP_PKEY_SIPHASH>, B<EVP_PKEY_X25519>, + +B<EVP_PKEY_ED25519>, B<EVP_PKEY_X448> or B<EVP_PKEY_ED448>. + */ + + if (!EVP_PKEY_get_raw_public_key(pkey, NULL, &key_len)) + return enif_make_atom(env,"EVP_PKEY_get_raw_public_key 1 failed"); + if (!EVP_PKEY_get_raw_public_key(pkey, + enif_make_new_binary(env, key_len, &ret_pub), + &key_len)) + return enif_make_atom(env,"EVP_PKEY_get_raw_public_key 2 failed"); + + if (!EVP_PKEY_get_raw_private_key(pkey, NULL, &key_len)) + return enif_make_atom(env,"EVP_PKEY_get_raw_private_key 1 failed"); + if (!EVP_PKEY_get_raw_private_key(pkey, + enif_make_new_binary(env, key_len, &ret_prv), + &key_len)) + return enif_make_atom(env,"EVP_PKEY_get_raw_private_key 2 failed"); + + return enif_make_tuple2(env, ret_pub, ret_prv); +#else + return atom_notsup; +#endif +} + /*================================================================*/ #define PKEY_BADARG -1 #define PKEY_NOTSUP 0 @@ -5324,9 +5589,9 @@ static ERL_NIF_TERM engine_get_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE #endif } +#ifdef HAS_ENGINE_SUPPORT static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i) { -#ifdef HAS_ENGINE_SUPPORT ERL_NIF_TERM head, tail; const ERL_NIF_TERM *tmp_tuple; ErlNifBinary tmpbin; @@ -5371,10 +5636,8 @@ static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, cha cmds[i] = NULL; return 0; } -#else - return atom_notsup; -#endif } +#endif static ERL_NIF_TERM engine_get_all_methods_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* () */ |