diff options
Diffstat (limited to 'lib/crypto/c_src/crypto.c')
-rw-r--r-- | lib/crypto/c_src/crypto.c | 489 |
1 files changed, 319 insertions, 170 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 6e855939f7..f8d1778bb9 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2017. All Rights Reserved. + * Copyright Ericsson AB 2010-2018. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -155,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 @@ -491,8 +499,6 @@ static ERL_NIF_TERM pkey_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM a static ERL_NIF_TERM pkey_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM pkey_crypt_nif(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[]); static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -503,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[]); @@ -546,6 +555,7 @@ 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}, @@ -580,10 +590,12 @@ static ErlNifFunc nif_funcs[] = { {"pkey_verify_nif", 6, pkey_verify_nif}, {"pkey_crypt_nif", 6, pkey_crypt_nif}, {"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", 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}, @@ -671,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; @@ -1009,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"); @@ -1078,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"); @@ -1123,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 { @@ -1172,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; } @@ -1213,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) { @@ -1255,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 @@ -1310,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[]) @@ -1324,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) ); } @@ -1755,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; @@ -3018,184 +3066,189 @@ static ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF 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; - DH* dh_params = NULL; - int p_len, g_len; - unsigned char *p_ptr, *g_ptr; - ERL_NIF_TERM ret_p, ret_g; - const BIGNUM *dh_p, *dh_q, *dh_g; - - if (!enif_get_int(env, argv[0], &prime_len) - || !enif_get_int(env, argv[1], &generator)) { - - return enif_make_badarg(env); - } - - if (DH_generate_parameters_ex(dh_params, prime_len, generator, NULL)) { - return atom_error; - } - DH_get0_pqg(dh_params, &dh_p, &dh_q, &dh_g); - DH_free(dh_params); - p_len = BN_num_bytes(dh_p); - g_len = BN_num_bytes(dh_g); - p_ptr = enif_make_new_binary(env, p_len, &ret_p); - g_ptr = enif_make_new_binary(env, g_len, &ret_g); - BN_bn2bin(dh_p, p_ptr); - BN_bn2bin(dh_g, g_ptr); - ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr, p_len); - ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr, g_len); - return enif_make_list2(env, ret_p, ret_g); -} - -static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* ([PrimeLen, Generator]) */ - DH* dh_params; - int i; - ERL_NIF_TERM ret, head, tail; - BIGNUM *dh_p, *dh_g; - - if (!enif_get_list_cell(env, argv[0], &head, &tail) - || !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)) { - - return enif_make_badarg(env); - } - - dh_params = DH_new(); - DH_set0_pqg(dh_params, dh_p, NULL, dh_g); - if (DH_check(dh_params, &i)) { - if (i == 0) ret = atom_ok; - else if (i & DH_CHECK_P_NOT_PRIME) ret = atom_not_prime; - else if (i & DH_CHECK_P_NOT_SAFE_PRIME) ret = atom_not_strong_prime; - else if (i & DH_UNABLE_TO_CHECK_GENERATOR) ret = atom_unable_to_check_generator; - else if (i & DH_NOT_SUITABLE_GENERATOR) ret = atom_not_suitable_generator; - else ret = enif_make_tuple2(env, atom_unknown, enif_make_uint(env, i)); - } - else { /* Check Failed */ - ret = enif_make_tuple2(env, atom_error, atom_check_failed); - } - DH_free(dh_params); - return ret; -} - 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; - int pub_len, prv_len; - unsigned char *pub_ptr, *prv_ptr; - ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail; + DH *dh_params = NULL; int mpint; /* 0 or 4 */ - BIGNUM *priv_key = NULL; - BIGNUM *dh_p = NULL, *dh_g = NULL; - unsigned long len = 0; - if (!(get_bn_from_bin(env, argv[0], &priv_key) - || argv[0] == atom_undefined) - || !enif_get_list_cell(env, argv[1], &head, &tail) - || !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_get_int(env, argv[2], &mpint) || (mpint & ~4) - || !enif_get_ulong(env, argv[3], &len) ) { - - if (priv_key) BN_free(priv_key); - if (dh_p) BN_free(dh_p); - if (dh_g) BN_free(dh_g); - return enif_make_badarg(env); + { + ERL_NIF_TERM head, tail; + BIGNUM + *dh_p = NULL, + *dh_g = NULL, + *priv_key_in = NULL; + unsigned long + len = 0; + + 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) + || !enif_get_list_cell(env, tail, &head, &tail) + || !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) + + /* 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); + } + + if (len) { + if (len < BN_num_bits(dh_p)) + DH_set_length(dh_params, len); + else { + 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); +#ifdef HAS_EVP_PKEY_CTX + { + EVP_PKEY_CTX *ctx; + EVP_PKEY *dhkey, *params; + int success; + + params = EVP_PKEY_new(); + success = EVP_PKEY_set1_DH(params, dh_params); /* set the key referenced by params to dh_params... */ + DH_free(dh_params); /* ...dh_params (and params) must be freed */ + if (!success) return atom_error; + + ctx = EVP_PKEY_CTX_new(params, NULL); + EVP_PKEY_free(params); + if (!ctx) { + return atom_error; + } + + if (!EVP_PKEY_keygen_init(ctx)) { + /* EVP_PKEY_CTX_free(ctx); */ + return atom_error; + } - if (len) { - if (len < BN_num_bits(dh_p)) - DH_set_length(dh_params, len); - else { - DH_free(dh_params); - return enif_make_badarg(env); + dhkey = EVP_PKEY_new(); + if (!EVP_PKEY_keygen(ctx, &dhkey)) { /* "performs a key generation operation, the ... */ + /*... generated key is written to ppkey." (=last arg) */ + /* EVP_PKEY_CTX_free(ctx); */ + /* EVP_PKEY_free(dhkey); */ + return atom_error; } - } - 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); - 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); - 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); + dh_params = EVP_PKEY_get1_DH(dhkey); /* return the referenced key. dh_params and dhkey must be freed */ + EVP_PKEY_free(dhkey); + if (!dh_params) { + /* EVP_PKEY_CTX_free(ctx); */ + return atom_error; + } + EVP_PKEY_CTX_free(ctx); } - else { - ret = atom_error; +#else + if (!DH_generate_key(dh_params)) return atom_error; +#endif + { + unsigned char *pub_ptr, *prv_ptr; + int pub_len, prv_len; + ERL_NIF_TERM ret_pub, ret_prv; + 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_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); + + DH_free(dh_params); + + return enif_make_tuple2(env, ret_pub, ret_prv); } - DH_free(dh_params); - 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; - ErlNifBinary ret_bin; - ERL_NIF_TERM ret, head, tail; + BIGNUM *other_pub_key = NULL, + *dh_p = NULL, + *dh_g = NULL; + DH *dh_priv = DH_new(); - dh_params = DH_new(); + /* Check the arguments and get + my private key (dh_priv), + the peer's public key (other_pub_key), + the parameters p & q + */ - if (!get_bn_from_bin(env, argv[0], &other_pub_key) - || !get_bn_from_bin(env, argv[1], &priv_key) - || !enif_get_list_cell(env, argv[2], &head, &tail) - || !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)) { - if (dh_p) BN_free(dh_p); - if (dh_g) BN_free(dh_g); - ret = enif_make_badarg(env); + { + BIGNUM *dummy_pub_key = NULL, + *priv_key = NULL; + ERL_NIF_TERM head, tail; + + if (!get_bn_from_bin(env, argv[0], &other_pub_key) + || !get_bn_from_bin(env, argv[1], &priv_key) + || !enif_get_list_cell(env, argv[2], &head, &tail) + || !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) + + /* 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); + 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); + } } - 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 { + { + ErlNifBinary ret_bin; + int size; + + enif_alloc_binary(DH_size(dh_priv), &ret_bin); + size = DH_compute_key(ret_bin.data, other_pub_key, dh_priv); + BN_free(other_pub_key); + DH_free(dh_priv); + if (size<=0) { enif_release_binary(&ret_bin); - ret = atom_error; - } + return atom_error; + } + + if (size != ret_bin.size) enif_realloc_binary(&ret_bin, size); + return enif_make_binary(env, &ret_bin); } - if (other_pub_key) BN_free(other_pub_key); - DH_free(dh_params); - return ret; } + static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Multiplier, Verifier, Generator, Exponent, Prime) */ BIGNUM *bn_verifier = NULL; @@ -3800,6 +3853,102 @@ 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); +#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"); + + 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 |