diff options
Diffstat (limited to 'lib/crypto/c_src/crypto.c')
-rw-r--r-- | lib/crypto/c_src/crypto.c | 6113 |
1 files changed, 121 insertions, 5992 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 194a3d30e9..a8014745c8 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -23,983 +23,111 @@ * Based on OpenSSL. */ -#ifdef __WIN32__ - #include <windows.h> -#endif - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include <erl_nif.h> - -#define OPENSSL_THREAD_DEFINES -#include <openssl/opensslconf.h> - -#include <openssl/crypto.h> -#ifndef OPENSSL_NO_DES -#include <openssl/des.h> -#endif /* #ifndef OPENSSL_NO_DES */ -/* #include <openssl/idea.h> This is not supported on the openssl OTP requires */ -#include <openssl/dsa.h> -#include <openssl/rsa.h> -#include <openssl/aes.h> -#include <openssl/md5.h> -#include <openssl/md4.h> -#include <openssl/sha.h> -#include <openssl/ripemd.h> -#include <openssl/bn.h> -#include <openssl/objects.h> -#ifndef OPENSSL_NO_RC4 - #include <openssl/rc4.h> -#endif /* OPENSSL_NO_RC4 */ -#ifndef OPENSSL_NO_RC2 - #include <openssl/rc2.h> -#endif -#include <openssl/blowfish.h> -#include <openssl/rand.h> -#include <openssl/evp.h> -#include <openssl/hmac.h> -#include <openssl/err.h> - -/* Helper macro to construct a OPENSSL_VERSION_NUMBER. - * See openssl/opensslv.h - */ -#define PACKED_OPENSSL_VERSION(MAJ, MIN, FIX, P) \ - ((((((((MAJ << 8) | MIN) << 8 ) | FIX) << 8) | (P-'a'+1)) << 4) | 0xf) - -#define PACKED_OPENSSL_VERSION_PLAIN(MAJ, MIN, FIX) \ - PACKED_OPENSSL_VERSION(MAJ,MIN,FIX,('a'-1)) - - -/* LibreSSL was cloned from OpenSSL 1.0.1g and claims to be API and BPI compatible - * with 1.0.1. - * - * LibreSSL has the same names on include files and symbols as OpenSSL, but defines - * the OPENSSL_VERSION_NUMBER to be >= 2.0.0 - * - * Therefor works tests like this as intendend: - * OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0) - * (The test is for example "2.4.2" >= "1.0.0" although the test - * with the cloned OpenSSL test would be "1.0.1" >= "1.0.0") - * - * But tests like this gives wrong result: - * OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0) - * (The test is false since "2.4.2" < "1.1.0". It should have been - * true because the LibreSSL API version is "1.0.1") - * - */ - -#ifdef LIBRESSL_VERSION_NUMBER -/* A macro to test on in this file */ -#define HAS_LIBRESSL -#endif - -#ifdef HAS_LIBRESSL -/* LibreSSL dislikes FIPS */ -# ifdef FIPS_SUPPORT -# 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 - - -#if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0) -# define NEED_EVP_COMPATIBILITY_FUNCTIONS -#endif - - -#ifndef HAS_LIBRESSL -# if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0) -# define HAS_EVP_PKEY_CTX -# endif -#endif - - -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0) -#include <openssl/modes.h> -#endif - -#include "crypto_callback.h" - -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(0,9,8) \ - && !defined(OPENSSL_NO_SHA224) && defined(NID_sha224) \ - && !defined(OPENSSL_NO_SHA256) /* disabled like this in my sha.h (?) */ -# define HAVE_SHA224 -#endif -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(0,9,8) \ - && !defined(OPENSSL_NO_SHA256) && defined(NID_sha256) -# define HAVE_SHA256 -#endif -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(0,9,8) \ - && !defined(OPENSSL_NO_SHA384) && defined(NID_sha384)\ - && !defined(OPENSSL_NO_SHA512) /* disabled like this in my sha.h (?) */ -# define HAVE_SHA384 -#endif -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(0,9,8) \ - && !defined(OPENSSL_NO_SHA512) && defined(NID_sha512) -# define HAVE_SHA512 -#endif -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,7,'e') -# define HAVE_DES_ede3_cfb_encrypt -#endif - -// SHA3: -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,1) -// An error in beta releases of 1.1.1 fixed in production release -# ifdef NID_sha3_224 -# define HAVE_SHA3_224 -# endif -# ifdef NID_sha3_256 -# define HAVE_SHA3_256 -# endif -#endif -# ifdef NID_sha3_384 -# define HAVE_SHA3_384 -# endif -# ifdef NID_sha3_512 -# define HAVE_SHA3_512 -# endif - -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'o') \ - && !defined(OPENSSL_NO_EC) \ - && !defined(OPENSSL_NO_ECDH) \ - && !defined(OPENSSL_NO_ECDSA) -# 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) -# define HAVE_ED_CURVE_DH -# if OPENSSL_VERSION_NUMBER >= (PACKED_OPENSSL_VERSION_PLAIN(1,1,1)) \ - && !defined(FIPS_SUPPORT) -# define HAVE_EDDSA -# endif -#endif - -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'c') -# define HAVE_AES_IGE -#endif - -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,1) -# define HAVE_EVP_AES_CTR -# define HAVE_AEAD -# define HAVE_GCM -# define HAVE_CCM -# define HAVE_CMAC -# if defined(RSA_PKCS1_OAEP_PADDING) -# define HAVE_RSA_OAEP_PADDING -# endif -# define HAVE_RSA_MGF1_MD -# if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION(1,0,1,'d') -# define HAVE_GCM_EVP_DECRYPT_BUG -# endif -#endif - -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,0) -# ifndef HAS_LIBRESSL -# define HAVE_CHACHA20 -# define HAVE_CHACHA20_POLY1305 -# define HAVE_RSA_OAEP_MD -# endif -#endif - -// OPENSSL_VERSION_NUMBER >= 1.1.1-pre8 -#if OPENSSL_VERSION_NUMBER >= (PACKED_OPENSSL_VERSION_PLAIN(1,1,1)-7) -# ifndef HAS_LIBRESSL -# define HAVE_POLY1305 -# endif -#endif - -#if OPENSSL_VERSION_NUMBER <= PACKED_OPENSSL_VERSION(0,9,8,'l') -# define HAVE_ECB_IVEC_BUG -#endif - -#ifndef HAS_LIBRESSL -# ifdef RSA_SSLV23_PADDING -# define HAVE_RSA_SSLV23_PADDING -# endif -#endif - -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0) -# ifdef RSA_PKCS1_PSS_PADDING -# define HAVE_RSA_PKCS1_PSS_PADDING -# endif -#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 - -#if defined(HAVE_EC) -#include <openssl/ec.h> -#include <openssl/ecdh.h> -#include <openssl/ecdsa.h> -#endif - -#ifdef VALGRIND - # include <valgrind/memcheck.h> - -/* libcrypto mixes supplied buffer contents into its entropy pool, - which makes valgrind complain about the use of uninitialized data. - We use this valgrind "request" to make sure that no such seemingly - undefined data is returned. -*/ - # define ERL_VALGRIND_MAKE_MEM_DEFINED(ptr,size) \ - VALGRIND_MAKE_MEM_DEFINED(ptr,size) - - # define ERL_VALGRIND_ASSERT_MEM_DEFINED(Ptr,Size) \ - do { \ - int __erl_valgrind_mem_defined = VALGRIND_CHECK_MEM_IS_DEFINED((Ptr),(Size)); \ - if (__erl_valgrind_mem_defined != 0) { \ - fprintf(stderr,"\r\n####### VALGRIND_ASSSERT(%p,%ld) failed at %s:%d\r\n", \ - (Ptr),(long)(Size), __FILE__, __LINE__); \ - abort(); \ - } \ - } while (0) - -#else - # define ERL_VALGRIND_MAKE_MEM_DEFINED(ptr,size) - # define ERL_VALGRIND_ASSERT_MEM_DEFINED(ptr,size) -#endif - -#ifdef DEBUG - # define ASSERT(e) \ - ((void) ((e) ? 1 : (fprintf(stderr,"Assert '%s' failed at %s:%d\n",\ - #e, __FILE__, __LINE__), abort(), 0))) -#else - # define ASSERT(e) ((void) 1) -#endif - -#ifdef __GNUC__ - # define INLINE __inline__ -#elif defined(__WIN32__) - # define INLINE __forceinline -#else - # define INLINE -#endif - - -#define get_int32(s) ((((unsigned char*) (s))[0] << 24) | \ - (((unsigned char*) (s))[1] << 16) | \ - (((unsigned char*) (s))[2] << 8) | \ - (((unsigned char*) (s))[3])) - -#define put_int32(s,i) \ -{ (s)[0] = (char)(((i) >> 24) & 0xff);\ - (s)[1] = (char)(((i) >> 16) & 0xff);\ - (s)[2] = (char)(((i) >> 8) & 0xff);\ - (s)[3] = (char)((i) & 0xff);\ -} - -/* This shall correspond to the similar macro in crypto.erl */ -/* Current value is: erlang:system_info(context_reductions) * 10 */ -#define MAX_BYTES_TO_NIF 20000 - -#define CONSUME_REDS(NifEnv, Ibin) \ -do { \ - int _cost = ((Ibin).size * 100) / MAX_BYTES_TO_NIF;\ - if (_cost) { \ - (void) enif_consume_timeslice((NifEnv), \ - (_cost > 100) ? 100 : _cost); \ - } \ - } while (0) - - -#ifdef NEED_EVP_COMPATIBILITY_FUNCTIONS -/* - * In OpenSSL 1.1.0, most structs are opaque. That means that - * the structs cannot be allocated as automatic variables on the - * C stack (because the size is unknown) and that it is necessary - * to use access functions. - * - * For backward compatibility to previous versions of OpenSSL, define - * on our versions of the new functions defined in 1.1.0 here, so that - * we don't have to sprinkle ifdefs throughout the code. - */ - -static HMAC_CTX *HMAC_CTX_new(void); -static void HMAC_CTX_free(HMAC_CTX *ctx); - -static HMAC_CTX *HMAC_CTX_new() -{ - HMAC_CTX *ctx = CRYPTO_malloc(sizeof(HMAC_CTX), __FILE__, __LINE__); - HMAC_CTX_init(ctx); - return ctx; -} - -static void HMAC_CTX_free(HMAC_CTX *ctx) -{ - HMAC_CTX_cleanup(ctx); - CRYPTO_free(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) -{ - r->n = n; - r->e = e; - r->d = 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; - r->q = 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; - r->dmq1 = dmq1; - r->iqmp = iqmp; - 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); -static INLINE void DSA_get0_pqg(const DSA *dsa, - const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); -static INLINE void DSA_get0_key(const DSA *dsa, - const BIGNUM **pub_key, const BIGNUM **priv_key); - -static INLINE int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) -{ - d->pub_key = pub_key; - d->priv_key = priv_key; - return 1; -} - -static INLINE int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) -{ - d->p = p; - d->q = q; - d->g = g; - return 1; -} - -static INLINE void -DSA_get0_pqg(const DSA *dsa, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) -{ - *p = dsa->p; - *q = dsa->q; - *g = dsa->g; -} - -static INLINE void -DSA_get0_key(const DSA *dsa, const BIGNUM **pub_key, const BIGNUM **priv_key) -{ - if (pub_key) *pub_key = dsa->pub_key; - if (priv_key) *priv_key = dsa->priv_key; -} - - - -static INLINE int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key); -static INLINE int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g); -static INLINE int DH_set_length(DH *dh, long length); -static INLINE void DH_get0_pqg(const DH *dh, - const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); -static INLINE void DH_get0_key(const DH *dh, - const BIGNUM **pub_key, const BIGNUM **priv_key); - -static INLINE int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) -{ - dh->pub_key = pub_key; - dh->priv_key = priv_key; - return 1; -} - -static INLINE int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) -{ - dh->p = p; - dh->q = q; - dh->g = g; - return 1; -} - -static INLINE int DH_set_length(DH *dh, long length) -{ - dh->length = length; - return 1; -} - - - -static INLINE void -DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) -{ - *p = dh->p; - *q = dh->q; - *g = dh->g; -} - -static INLINE void -DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) -{ - if (pub_key) *pub_key = dh->pub_key; - if (priv_key) *priv_key = dh->priv_key; -} - -#else /* End of compatibility definitions. */ - -#define HAVE_OPAQUE_BN_GENCB - -#endif +#include "common.h" + +#include "aead.h" +#include "aes.h" +#include "algorithms.h" +#include "api_ng.h" +#include "bn.h" +#include "cipher.h" +#include "cmac.h" +#include "dh.h" +#include "digest.h" +#include "dss.h" +#include "ec.h" +#include "ecdh.h" +#include "eddsa.h" +#include "engine.h" +#include "evp.h" +#include "fips.h" +#include "hash.h" +#include "hmac.h" +#include "info.h" +#include "math.h" +#include "pkey.h" +#include "poly1305.h" +#include "rand.h" +#include "rsa.h" +#include "srp.h" /* NIF interface declarations */ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info); static void unload(ErlNifEnv* env, void* priv_data); -/* The NIFs: */ -static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM info_fips(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM enable_fips_mode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM hmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM aes_cfb_128_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM strong_rand_range_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM pkey_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -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_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[]); -static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); - -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 aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -#ifdef HAVE_GCM_EVP_DECRYPT_BUG -static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -#endif - -static ERL_NIF_TERM chacha20_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM chacha20_stream_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); - -static ERL_NIF_TERM poly1305_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); - -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[]); -static ERL_NIF_TERM engine_free_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM engine_load_dynamic_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM engine_ctrl_cmd_strings_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM engine_register_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM engine_unregister_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM engine_add_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM engine_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM engine_get_first_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM engine_get_next_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM engine_get_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM engine_get_name_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM engine_get_all_methods_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); - -/* helpers */ -static void init_algorithms_types(ErlNifEnv*); -static void init_digest_types(ErlNifEnv* env); -static void init_cipher_types(ErlNifEnv* env); -#ifdef HAVE_EC -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); - -#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}, - {"info_fips", 0, info_fips}, - {"enable_fips_mode", 1, enable_fips_mode}, - {"algorithms", 0, algorithms}, - {"hash_nif", 2, hash_nif}, - {"hash_init_nif", 1, hash_init_nif}, - {"hash_update_nif", 2, hash_update_nif}, - {"hash_final_nif", 1, hash_final_nif}, - {"hmac_nif", 3, hmac_nif}, - {"hmac_nif", 4, hmac_nif}, - {"hmac_init_nif", 2, hmac_init_nif}, - {"hmac_update_nif", 2, hmac_update_nif}, - {"hmac_final_nif", 1, hmac_final_nif}, - {"hmac_final_nif", 2, hmac_final_nif}, - {"cmac_nif", 3, cmac_nif}, - {"block_crypt_nif", 5, block_crypt_nif}, - {"block_crypt_nif", 4, block_crypt_nif}, - {"aes_ige_crypt_nif", 4, aes_ige_crypt_nif}, - {"aes_ctr_stream_init", 2, aes_ctr_stream_init}, - {"aes_ctr_stream_encrypt", 2, aes_ctr_stream_encrypt}, - {"aes_ctr_stream_decrypt", 2, aes_ctr_stream_encrypt}, - {"strong_rand_bytes_nif", 1, strong_rand_bytes_nif}, - {"strong_rand_range_nif", 1, strong_rand_range_nif}, - {"rand_uniform_nif", 2, rand_uniform_nif}, - {"mod_exp_nif", 4, mod_exp_nif}, - {"do_exor", 2, do_exor}, - {"rc4_set_key", 1, rc4_set_key}, - {"rc4_encrypt_with_state", 2, rc4_encrypt_with_state}, - {"pkey_sign_nif", 5, pkey_sign_nif}, - {"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_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}, - {"srp_host_secret_nif", 5, srp_host_secret_nif}, - - {"ec_key_generate", 2, ec_key_generate}, - {"ecdh_compute_key_nif", 3, ecdh_compute_key_nif}, - - {"rand_seed_nif", 1, rand_seed_nif}, - - {"aead_encrypt", 6, aead_encrypt}, - {"aead_decrypt", 6, aead_decrypt}, - - {"chacha20_stream_init", 2, chacha20_stream_init}, - {"chacha20_stream_encrypt", 2, chacha20_stream_crypt}, - {"chacha20_stream_decrypt", 2, chacha20_stream_crypt}, - - {"poly1305_nif", 2, poly1305_nif}, - - {"engine_by_id_nif", 1, engine_by_id_nif}, - {"engine_init_nif", 1, engine_init_nif}, - {"engine_finish_nif", 1, engine_finish_nif}, - {"engine_free_nif", 1, engine_free_nif}, - {"engine_load_dynamic_nif", 0, engine_load_dynamic_nif}, - {"engine_ctrl_cmd_strings_nif", 3, engine_ctrl_cmd_strings_nif}, - {"engine_register_nif", 2, engine_register_nif}, - {"engine_unregister_nif", 2, engine_unregister_nif}, - {"engine_add_nif", 1, engine_add_nif}, - {"engine_remove_nif", 1, engine_remove_nif}, - {"engine_get_first_nif", 0, engine_get_first_nif}, - {"engine_get_next_nif", 1, engine_get_next_nif}, - {"engine_get_id_nif", 1, engine_get_id_nif}, - {"engine_get_name_nif", 1, engine_get_name_nif}, - {"engine_get_all_methods_nif", 0, engine_get_all_methods_nif} - + {"info_lib", 0, info_lib, 0}, + {"info_fips", 0, info_fips, 0}, + {"enable_fips_mode", 1, enable_fips_mode, 0}, + {"algorithms", 0, algorithms, 0}, + {"hash_info", 1, hash_info_nif, 0}, + {"hash_nif", 2, hash_nif, 0}, + {"hash_init_nif", 1, hash_init_nif, 0}, + {"hash_update_nif", 2, hash_update_nif, 0}, + {"hash_final_nif", 1, hash_final_nif, 0}, + {"hmac_nif", 3, hmac_nif, 0}, + {"hmac_nif", 4, hmac_nif, 0}, + {"hmac_init_nif", 2, hmac_init_nif, 0}, + {"hmac_update_nif", 2, hmac_update_nif, 0}, + {"hmac_final_nif", 1, hmac_final_nif, 0}, + {"hmac_final_nif", 2, hmac_final_nif, 0}, + {"cmac_nif", 3, cmac_nif, 0}, + {"cipher_info_nif", 1, cipher_info_nif, 0}, + {"aes_ige_crypt_nif", 4, aes_ige_crypt_nif, 0}, + {"ng_crypto_init_nif", 4, ng_crypto_init_nif, 0}, + {"ng_crypto_update_nif", 2, ng_crypto_update_nif, 0}, + {"ng_crypto_update_nif", 3, ng_crypto_update_nif, 0}, + {"ng_crypto_one_time_nif", 5, ng_crypto_one_time_nif, 0}, + {"strong_rand_bytes_nif", 1, strong_rand_bytes_nif, 0}, + {"strong_rand_range_nif", 1, strong_rand_range_nif, 0}, + {"rand_uniform_nif", 2, rand_uniform_nif, 0}, + {"mod_exp_nif", 4, mod_exp_nif, 0}, + {"do_exor", 2, do_exor, 0}, + {"pkey_sign_nif", 5, pkey_sign_nif, 0}, + {"pkey_verify_nif", 6, pkey_verify_nif, 0}, + {"pkey_crypt_nif", 6, pkey_crypt_nif, 0}, + {"rsa_generate_key_nif", 2, rsa_generate_key_nif, 0}, + {"dh_generate_key_nif", 4, dh_generate_key_nif, 0}, + {"dh_compute_key_nif", 3, dh_compute_key_nif, 0}, + {"evp_compute_key_nif", 3, evp_compute_key_nif, 0}, + {"evp_generate_key_nif", 1, evp_generate_key_nif, 0}, + {"privkey_to_pubkey_nif", 2, privkey_to_pubkey_nif, 0}, + {"srp_value_B_nif", 5, srp_value_B_nif, 0}, + {"srp_user_secret_nif", 7, srp_user_secret_nif, 0}, + {"srp_host_secret_nif", 5, srp_host_secret_nif, 0}, + + {"ec_key_generate", 2, ec_key_generate, 0}, + {"ecdh_compute_key_nif", 3, ecdh_compute_key_nif, 0}, + + {"rand_seed_nif", 1, rand_seed_nif, 0}, + + {"aead_cipher", 7, aead_cipher, 0}, + + {"poly1305_nif", 2, poly1305_nif, 0}, + + {"engine_by_id_nif", 1, engine_by_id_nif, 0}, + {"engine_init_nif", 1, engine_init_nif, 0}, + {"engine_finish_nif", 1, engine_finish_nif, 0}, + {"engine_free_nif", 1, engine_free_nif, 0}, + {"engine_load_dynamic_nif", 0, engine_load_dynamic_nif, 0}, + {"engine_ctrl_cmd_strings_nif", 3, engine_ctrl_cmd_strings_nif, 0}, + {"engine_register_nif", 2, engine_register_nif, 0}, + {"engine_unregister_nif", 2, engine_unregister_nif, 0}, + {"engine_add_nif", 1, engine_add_nif, 0}, + {"engine_remove_nif", 1, engine_remove_nif, 0}, + {"engine_get_first_nif", 0, engine_get_first_nif, 0}, + {"engine_get_next_nif", 1, engine_get_next_nif, 0}, + {"engine_get_id_nif", 1, engine_get_id_nif, 0}, + {"engine_get_name_nif", 1, engine_get_name_nif, 0}, + {"engine_get_all_methods_nif", 0, engine_get_all_methods_nif, 0} }; ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload) -#define MD5_CTX_LEN (sizeof(MD5_CTX)) -#define MD4_CTX_LEN (sizeof(MD4_CTX)) -#define RIPEMD160_CTX_LEN (sizeof(RIPEMD160_CTX)) - - -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_rsa_pkcs1_padding; -static ERL_NIF_TERM atom_rsa_pkcs1_oaep_padding; -static ERL_NIF_TERM atom_rsa_no_padding; -static ERL_NIF_TERM atom_signature_md; -static ERL_NIF_TERM atom_undefined; - -static ERL_NIF_TERM atom_ok; -static ERL_NIF_TERM atom_not_prime; -static ERL_NIF_TERM atom_not_strong_prime; -static ERL_NIF_TERM atom_unable_to_check_generator; -static ERL_NIF_TERM atom_not_suitable_generator; -static ERL_NIF_TERM atom_check_failed; -static ERL_NIF_TERM atom_unknown; -static ERL_NIF_TERM atom_none; -static ERL_NIF_TERM atom_notsup; -static ERL_NIF_TERM atom_digest; -#ifdef FIPS_SUPPORT -static ERL_NIF_TERM atom_enabled; -static ERL_NIF_TERM atom_not_enabled; -#else -static ERL_NIF_TERM atom_not_supported; -#endif - -#if defined(HAVE_EC) -static ERL_NIF_TERM atom_ec; -static ERL_NIF_TERM atom_prime_field; -static ERL_NIF_TERM atom_characteristic_two_field; -static ERL_NIF_TERM atom_tpbasis; -static ERL_NIF_TERM atom_ppbasis; -static ERL_NIF_TERM atom_onbasis; -#endif - -static ERL_NIF_TERM atom_aes_cfb8; -static ERL_NIF_TERM atom_aes_cfb128; -#ifdef HAVE_GCM -static ERL_NIF_TERM atom_aes_gcm; -#endif -#ifdef HAVE_CCM -static ERL_NIF_TERM atom_aes_ccm; -#endif -#ifdef HAVE_CHACHA20_POLY1305 -static ERL_NIF_TERM atom_chacha20_poly1305; -#endif -#ifdef HAVE_ECB_IVEC_BUG -static ERL_NIF_TERM atom_aes_ecb; -static ERL_NIF_TERM atom_des_ecb; -static ERL_NIF_TERM atom_blowfish_ecb; -#endif - -static ERL_NIF_TERM atom_rsa; -static ERL_NIF_TERM atom_dss; -static ERL_NIF_TERM atom_ecdsa; - -#ifdef HAVE_ED_CURVE_DH -static ERL_NIF_TERM atom_x25519; -static ERL_NIF_TERM atom_x448; -#endif - -static ERL_NIF_TERM atom_eddsa; -#ifdef HAVE_EDDSA -static ERL_NIF_TERM atom_ed25519; -static ERL_NIF_TERM atom_ed448; -#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; -static ERL_NIF_TERM atom_rsa_pad; /* backwards compatibility */ -static ERL_NIF_TERM atom_rsa_padding; -static ERL_NIF_TERM atom_rsa_pkcs1_pss_padding; -#ifdef HAVE_RSA_SSLV23_PADDING -static ERL_NIF_TERM atom_rsa_sslv23_padding; -#endif -static ERL_NIF_TERM atom_rsa_x931_padding; -static ERL_NIF_TERM atom_rsa_pss_saltlen; -static ERL_NIF_TERM atom_sha224; -static ERL_NIF_TERM atom_sha256; -static ERL_NIF_TERM atom_sha384; -static ERL_NIF_TERM atom_sha512; -static ERL_NIF_TERM atom_sha3_224; -static ERL_NIF_TERM atom_sha3_256; -static ERL_NIF_TERM atom_sha3_384; -static ERL_NIF_TERM atom_sha3_512; -static ERL_NIF_TERM atom_md5; -static ERL_NIF_TERM atom_ripemd160; - -#ifdef HAS_ENGINE_SUPPORT -static ERL_NIF_TERM atom_bad_engine_method; -static ERL_NIF_TERM atom_bad_engine_id; -static ERL_NIF_TERM atom_ctrl_cmd_failed; -static ERL_NIF_TERM atom_engine_init_failed; -static ERL_NIF_TERM atom_register_engine_failed; -static ERL_NIF_TERM atom_add_engine_failed; -static ERL_NIF_TERM atom_remove_engine_failed; -static ERL_NIF_TERM atom_engine_method_not_supported; - -static ERL_NIF_TERM atom_engine_method_rsa; -static ERL_NIF_TERM atom_engine_method_dsa; -static ERL_NIF_TERM atom_engine_method_dh; -static ERL_NIF_TERM atom_engine_method_rand; -static ERL_NIF_TERM atom_engine_method_ecdh; -static ERL_NIF_TERM atom_engine_method_ecdsa; -static ERL_NIF_TERM atom_engine_method_ciphers; -static ERL_NIF_TERM atom_engine_method_digests; -static ERL_NIF_TERM atom_engine_method_store; -static ERL_NIF_TERM atom_engine_method_pkey_meths; -static ERL_NIF_TERM atom_engine_method_pkey_asn1_meths; -static ERL_NIF_TERM atom_engine_method_ec; - -static ERL_NIF_TERM atom_engine; -static ERL_NIF_TERM atom_key_id; -static ERL_NIF_TERM atom_password; -#endif - -static ErlNifResourceType* hmac_context_rtype; -struct hmac_context -{ - ErlNifMutex* mtx; - int alive; - HMAC_CTX* ctx; -}; -static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context*); - -struct digest_type_t { - union { - const char* str; /* before init, NULL for end-of-table */ - ERL_NIF_TERM atom; /* after init, 'false' for end-of-table */ - }type; - union { - const EVP_MD* (*funcp)(void); /* before init, NULL if notsup */ - const EVP_MD* p; /* after init, NULL if notsup */ - }md; -}; - -static struct digest_type_t digest_types[] = -{ - {{"md4"}, {&EVP_md4}}, - {{"md5"}, {&EVP_md5}}, - {{"ripemd160"}, {&EVP_ripemd160}}, - {{"sha"}, {&EVP_sha1}}, - {{"sha224"}, -#ifdef HAVE_SHA224 - {&EVP_sha224} -#else - {NULL} -#endif - }, - {{"sha256"}, -#ifdef HAVE_SHA256 - {&EVP_sha256} -#else - {NULL} -#endif - }, - {{"sha384"}, -#ifdef HAVE_SHA384 - {&EVP_sha384} -#else - {NULL} -#endif - }, - {{"sha512"}, -#ifdef HAVE_SHA512 - {&EVP_sha512} -#else - {NULL} -#endif - }, - {{"sha3_224"}, -#ifdef HAVE_SHA3_224 - {&EVP_sha3_224} -#else - {NULL} -#endif - }, - {{"sha3_256"}, -#ifdef HAVE_SHA3_256 - {&EVP_sha3_256} -#else - {NULL} -#endif - }, - {{"sha3_384"}, -#ifdef HAVE_SHA3_384 - {&EVP_sha3_384} -#else - {NULL} -#endif - }, - {{"sha3_512"}, -#ifdef HAVE_SHA3_512 - {&EVP_sha3_512} -#else - {NULL} -#endif - }, - - {{NULL}} -}; - -static struct digest_type_t* get_digest_type(ERL_NIF_TERM type); - -struct cipher_type_t { - union { - const char* str; /* before init */ - ERL_NIF_TERM atom; /* after init */ - }type; - union { - const EVP_CIPHER* (*funcp)(void); /* before init, NULL if notsup */ - const EVP_CIPHER* p; /* after init, NULL if notsup */ - }cipher; - const size_t key_len; /* != 0 to also match on key_len */ -}; - -#ifdef OPENSSL_NO_DES -#define COND_NO_DES_PTR(Ptr) (NULL) -#else -#define COND_NO_DES_PTR(Ptr) (Ptr) -#endif - -static struct cipher_type_t cipher_types[] = -{ - {{"rc2_cbc"}, -#ifndef OPENSSL_NO_RC2 - {&EVP_rc2_cbc} -#else - {NULL} -#endif - }, - {{"des_cbc"}, {COND_NO_DES_PTR(&EVP_des_cbc)}}, - {{"des_cfb"}, {COND_NO_DES_PTR(&EVP_des_cfb8)}}, - {{"des_ecb"}, {COND_NO_DES_PTR(&EVP_des_ecb)}}, - {{"des_ede3_cbc"}, {COND_NO_DES_PTR(&EVP_des_ede3_cbc)}}, - {{"des_ede3_cbf"}, /* Misspelled, retained */ -#ifdef HAVE_DES_ede3_cfb_encrypt - {COND_NO_DES_PTR(&EVP_des_ede3_cfb8)} -#else - {NULL} -#endif - }, - {{"des_ede3_cfb"}, -#ifdef HAVE_DES_ede3_cfb_encrypt - {COND_NO_DES_PTR(&EVP_des_ede3_cfb8)} -#else - {NULL} -#endif - }, - {{"blowfish_cbc"}, {&EVP_bf_cbc}}, - {{"blowfish_cfb64"}, {&EVP_bf_cfb64}}, - {{"blowfish_ofb64"}, {&EVP_bf_ofb}}, - {{"blowfish_ecb"}, {&EVP_bf_ecb}}, - {{"aes_cbc"}, {&EVP_aes_128_cbc}, 16}, - {{"aes_cbc"}, {&EVP_aes_192_cbc}, 24}, - {{"aes_cbc"}, {&EVP_aes_256_cbc}, 32}, - {{"aes_cbc128"}, {&EVP_aes_128_cbc}}, - {{"aes_cbc256"}, {&EVP_aes_256_cbc}}, - {{"aes_cfb8"}, {&EVP_aes_128_cfb8}}, - {{"aes_cfb128"}, {&EVP_aes_128_cfb128}}, - {{"aes_ecb"}, {&EVP_aes_128_ecb}, 16}, - {{"aes_ecb"}, {&EVP_aes_192_ecb}, 24}, - {{"aes_ecb"}, {&EVP_aes_256_ecb}, 32}, - {{NULL}} -}; - -static struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len); - - -/* -#define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n") -#define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1) -#define PRINTF_ERR2(FMT, A1, A2) enif_fprintf(stderr, FMT "\n", A1, A2) -*/ - -#define PRINTF_ERR0(FMT) -#define PRINTF_ERR1(FMT,A1) -#define PRINTF_ERR2(FMT,A1,A2) - -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0) -/* Define resource types for OpenSSL context structures. */ -static ErlNifResourceType* evp_md_ctx_rtype; -struct evp_md_ctx { - EVP_MD_CTX* ctx; -}; -static void evp_md_ctx_dtor(ErlNifEnv* env, struct evp_md_ctx *ctx) { - EVP_MD_CTX_free(ctx->ctx); -} -#endif - -#ifdef HAVE_EVP_AES_CTR -static ErlNifResourceType* evp_cipher_ctx_rtype; -struct evp_cipher_ctx { - EVP_CIPHER_CTX* ctx; -}; -static void evp_cipher_ctx_dtor(ErlNifEnv* env, struct evp_cipher_ctx* ctx) { - EVP_CIPHER_CTX_free(ctx->ctx); -} -#endif - -// Engine -#ifdef HAS_ENGINE_SUPPORT -static ErlNifResourceType* engine_ctx_rtype; -struct engine_ctx { - ENGINE *engine; - char *id; -}; -static void engine_ctx_dtor(ErlNifEnv* env, struct engine_ctx* ctx) { - PRINTF_ERR0("engine_ctx_dtor"); - if(ctx->id) { - PRINTF_ERR1(" non empty ctx->id=%s", ctx->id); - enif_free(ctx->id); - } else - PRINTF_ERR0(" empty ctx->id=NULL"); -} -#endif static int verify_lib_version(void) { @@ -1016,46 +144,6 @@ static int verify_lib_version(void) return 1; } -#ifdef FIPS_SUPPORT -/* In FIPS mode non-FIPS algorithms are disabled and return badarg. */ -#define CHECK_NO_FIPS_MODE() { if (FIPS_mode()) return atom_notsup; } -#else -#define CHECK_NO_FIPS_MODE() -#endif - -#ifdef HAVE_DYNAMIC_CRYPTO_LIB - -# if defined(DEBUG) -static char crypto_callback_name[] = "crypto_callback.debug"; -# elif defined(VALGRIND) -static char crypto_callback_name[] = "crypto_callback.valgrind"; -# else -static char crypto_callback_name[] = "crypto_callback"; -# endif - -static int change_basename(ErlNifBinary* bin, char* buf, int bufsz, const char* newfile) -{ - int i; - - for (i = bin->size; i > 0; i--) { - if (bin->data[i-1] == '/') - break; - } - if (i + strlen(newfile) >= bufsz) { - PRINTF_ERR0("CRYPTO: lib name too long"); - return 0; - } - memcpy(buf, bin->data, i); - strcpy(buf+i, newfile); - return 1; -} - -static void error_handler(void* null, const char* errstr) -{ - PRINTF_ERR1("CRYPTO LOADING ERROR: '%s'", errstr); -} -#endif /* HAVE_DYNAMIC_CRYPTO_LIB */ - static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info) { #ifdef OPENSSL_THREADS @@ -1069,59 +157,37 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info) int vernum; ErlNifBinary lib_bin; char lib_buf[1000]; +#ifdef HAVE_DYNAMIC_CRYPTO_LIB + void *handle; +#endif if (!verify_lib_version()) return __LINE__; /* load_info: {302, <<"/full/path/of/this/library">>,true|false} */ - if (!enif_get_tuple(env, load_info, &tpl_arity, &tpl_array) - || tpl_arity != 3 - || !enif_get_int(env, tpl_array[0], &vernum) - || vernum != 302 - || !enif_inspect_binary(env, tpl_array[1], &lib_bin)) { - - PRINTF_ERR1("CRYPTO: Invalid load_info '%T'", load_info); - return __LINE__; - } + if (!enif_get_tuple(env, load_info, &tpl_arity, &tpl_array)) + return __LINE__; + if (tpl_arity != 3) + return __LINE__; + if (!enif_get_int(env, tpl_array[0], &vernum)) + return __LINE__; + if (vernum != 302) + return __LINE__; + if (!enif_inspect_binary(env, tpl_array[1], &lib_bin)) + return __LINE__; - hmac_context_rtype = enif_open_resource_type(env, NULL, "hmac_context", - (ErlNifResourceDtor*) hmac_context_dtor, - ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, - NULL); - if (!hmac_context_rtype) { - PRINTF_ERR0("CRYPTO: Could not open resource type 'hmac_context'"); + if (!init_hmac_ctx(env)) { return __LINE__; } -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0) - evp_md_ctx_rtype = enif_open_resource_type(env, NULL, "EVP_MD_CTX", - (ErlNifResourceDtor*) evp_md_ctx_dtor, - ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, - NULL); - if (!evp_md_ctx_rtype) { - PRINTF_ERR0("CRYPTO: Could not open resource type 'EVP_MD_CTX'"); + if (!init_hash_ctx(env)) { return __LINE__; } -#endif -#ifdef HAVE_EVP_AES_CTR - evp_cipher_ctx_rtype = enif_open_resource_type(env, NULL, "EVP_CIPHER_CTX", - (ErlNifResourceDtor*) evp_cipher_ctx_dtor, - ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, - NULL); - if (!evp_cipher_ctx_rtype) { - PRINTF_ERR0("CRYPTO: Could not open resource type 'EVP_CIPHER_CTX'"); + if (!init_cipher_ctx(env)) { return __LINE__; } -#endif -#ifdef HAS_ENGINE_SUPPORT - engine_ctx_rtype = enif_open_resource_type(env, NULL, "ENGINE_CTX", - (ErlNifResourceDtor*) engine_ctx_dtor, - ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, - NULL); - if (!engine_ctx_rtype) { - PRINTF_ERR0("CRYPTO: Could not open resource type 'ENGINE_CTX'"); + if (!init_engine_ctx(env)) { return __LINE__; } -#endif if (library_initialized) { /* Repeated loading of this library (module upgrade). @@ -1130,149 +196,18 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info) return 0; } - atom_true = enif_make_atom(env,"true"); - atom_false = enif_make_atom(env,"false"); - /* Enter FIPS mode */ - if (tpl_array[2] == atom_true) { -#ifdef FIPS_SUPPORT - if (!FIPS_mode_set(1)) { -#else - { -#endif - PRINTF_ERR0("CRYPTO: Could not setup FIPS mode"); - return 0; - } - } else if (tpl_array[2] != atom_false) { - PRINTF_ERR1("CRYPTO: Invalid load_info '%T'", load_info); - return 0; + if (!init_atoms(env, tpl_array[2], load_info)) { + return __LINE__; } - atom_sha = enif_make_atom(env,"sha"); - atom_error = enif_make_atom(env,"error"); - 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"); - atom_signature_md = enif_make_atom(env,"signature_md"); - atom_undefined = enif_make_atom(env,"undefined"); - atom_ok = enif_make_atom(env,"ok"); - atom_not_prime = enif_make_atom(env,"not_prime"); - atom_not_strong_prime = enif_make_atom(env,"not_strong_prime"); - atom_unable_to_check_generator = enif_make_atom(env,"unable_to_check_generator"); - atom_not_suitable_generator = enif_make_atom(env,"not_suitable_generator"); - atom_check_failed = enif_make_atom(env,"check_failed"); - atom_unknown = enif_make_atom(env,"unknown"); - atom_none = enif_make_atom(env,"none"); - atom_notsup = enif_make_atom(env,"notsup"); - atom_digest = enif_make_atom(env,"digest"); - -#if defined(HAVE_EC) - atom_ec = enif_make_atom(env,"ec"); - atom_prime_field = enif_make_atom(env,"prime_field"); - atom_characteristic_two_field = enif_make_atom(env,"characteristic_two_field"); - atom_tpbasis = enif_make_atom(env,"tpbasis"); - atom_ppbasis = enif_make_atom(env,"ppbasis"); - atom_onbasis = enif_make_atom(env,"onbasis"); -#endif - - atom_aes_cfb8 = enif_make_atom(env, "aes_cfb8"); - atom_aes_cfb128 = enif_make_atom(env, "aes_cfb128"); -#ifdef HAVE_GCM - atom_aes_gcm = enif_make_atom(env, "aes_gcm"); -#endif -#ifdef HAVE_CCM - atom_aes_ccm = enif_make_atom(env, "aes_ccm"); -#endif -#ifdef HAVE_CHACHA20_POLY1305 - atom_chacha20_poly1305 = enif_make_atom(env,"chacha20_poly1305"); -#endif -#ifdef HAVE_ECB_IVEC_BUG - atom_aes_ecb = enif_make_atom(env, "aes_ecb"); - atom_des_ecb = enif_make_atom(env, "des_ecb"); - atom_blowfish_ecb = enif_make_atom(env, "blowfish_ecb"); -#endif - -#ifdef FIPS_SUPPORT - atom_enabled = enif_make_atom(env,"enabled"); - atom_not_enabled = enif_make_atom(env,"not_enabled"); -#else - atom_not_supported = enif_make_atom(env,"not_supported"); -#endif - atom_rsa = enif_make_atom(env,"rsa"); - atom_dss = enif_make_atom(env,"dss"); - atom_ecdsa = enif_make_atom(env,"ecdsa"); -#ifdef HAVE_ED_CURVE_DH - atom_x25519 = enif_make_atom(env,"x25519"); - atom_x448 = enif_make_atom(env,"x448"); -#endif - atom_eddsa = enif_make_atom(env,"eddsa"); -#ifdef HAVE_EDDSA - atom_ed25519 = enif_make_atom(env,"ed25519"); - atom_ed448 = enif_make_atom(env,"ed448"); -#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"); - atom_rsa_pad = enif_make_atom(env,"rsa_pad"); /* backwards compatibility */ - atom_rsa_padding = enif_make_atom(env,"rsa_padding"); - atom_rsa_pkcs1_pss_padding = enif_make_atom(env,"rsa_pkcs1_pss_padding"); -#ifdef HAVE_RSA_SSLV23_PADDING - atom_rsa_sslv23_padding = enif_make_atom(env,"rsa_sslv23_padding"); -#endif - atom_rsa_x931_padding = enif_make_atom(env,"rsa_x931_padding"); - atom_rsa_pss_saltlen = enif_make_atom(env,"rsa_pss_saltlen"); - atom_sha224 = enif_make_atom(env,"sha224"); - atom_sha256 = enif_make_atom(env,"sha256"); - atom_sha384 = enif_make_atom(env,"sha384"); - atom_sha512 = enif_make_atom(env,"sha512"); - atom_sha3_224 = enif_make_atom(env,"sha3_224"); - atom_sha3_256 = enif_make_atom(env,"sha3_256"); - atom_sha3_384 = enif_make_atom(env,"sha3_384"); - atom_sha3_512 = enif_make_atom(env,"sha3_512"); - atom_md5 = enif_make_atom(env,"md5"); - atom_ripemd160 = enif_make_atom(env,"ripemd160"); - -#ifdef HAS_ENGINE_SUPPORT - atom_bad_engine_method = enif_make_atom(env,"bad_engine_method"); - atom_bad_engine_id = enif_make_atom(env,"bad_engine_id"); - atom_ctrl_cmd_failed = enif_make_atom(env,"ctrl_cmd_failed"); - atom_engine_init_failed = enif_make_atom(env,"engine_init_failed"); - atom_engine_method_not_supported = enif_make_atom(env,"engine_method_not_supported"); - atom_add_engine_failed = enif_make_atom(env,"add_engine_failed"); - atom_remove_engine_failed = enif_make_atom(env,"remove_engine_failed"); - - atom_engine_method_rsa = enif_make_atom(env,"engine_method_rsa"); - atom_engine_method_dsa = enif_make_atom(env,"engine_method_dsa"); - atom_engine_method_dh = enif_make_atom(env,"engine_method_dh"); - atom_engine_method_rand = enif_make_atom(env,"engine_method_rand"); - atom_engine_method_ecdh = enif_make_atom(env,"engine_method_ecdh"); - atom_engine_method_ecdsa = enif_make_atom(env,"engine_method_ecdsa"); - atom_engine_method_store = enif_make_atom(env,"engine_method_store"); - atom_engine_method_ciphers = enif_make_atom(env,"engine_method_ciphers"); - atom_engine_method_digests = enif_make_atom(env,"engine_method_digests"); - atom_engine_method_pkey_meths = enif_make_atom(env,"engine_method_pkey_meths"); - atom_engine_method_pkey_asn1_meths = enif_make_atom(env,"engine_method_pkey_asn1_meths"); - atom_engine_method_ec = enif_make_atom(env,"engine_method_ec"); - - atom_engine = enif_make_atom(env,"engine"); - atom_key_id = enif_make_atom(env,"key_id"); - atom_password = enif_make_atom(env,"password"); -#endif - - #ifdef HAVE_DYNAMIC_CRYPTO_LIB - { - void* handle; - if (!change_basename(&lib_bin, lib_buf, sizeof(lib_buf), crypto_callback_name)) { - return __LINE__; - } - if (!(handle = enif_dlopen(lib_buf, &error_handler, NULL))) { - return __LINE__; - } - if (!(funcp = (get_crypto_callbacks_t*) enif_dlsym(handle, "get_crypto_callbacks", - &error_handler, NULL))) { - return __LINE__; - } - } + if (!change_basename(&lib_bin, lib_buf, sizeof(lib_buf), crypto_callback_name)) + return __LINE__; + if ((handle = enif_dlopen(lib_buf, &error_handler, NULL)) == NULL) + return __LINE__; + if ((funcp = (get_crypto_callbacks_t*) enif_dlsym(handle, "get_crypto_callbacks", + &error_handler, NULL)) == NULL) + return __LINE__; #else /* !HAVE_DYNAMIC_CRYPTO_LIB */ funcp = &get_crypto_callbacks; #endif @@ -1292,7 +227,10 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info) return __LINE__; } - CRYPTO_set_mem_functions(ccb->crypto_alloc, ccb->crypto_realloc, ccb->crypto_free); +#ifdef HAS_CRYPTO_MEM_FUNCTIONS + if (!CRYPTO_set_mem_functions(ccb->crypto_alloc, ccb->crypto_realloc, ccb->crypto_free)) + return __LINE__; +#endif #ifdef OPENSSL_THREADS if (nlocks > 0) { @@ -1346,4812 +284,3 @@ static void unload(ErlNifEnv* env, void* priv_data) { --library_refc; } - -static int algo_hash_cnt, algo_hash_fips_cnt; -static ERL_NIF_TERM algo_hash[12]; /* increase when extending the list */ -static int algo_pubkey_cnt, algo_pubkey_fips_cnt; -static ERL_NIF_TERM algo_pubkey[12]; /* increase when extending the list */ -static int algo_cipher_cnt, algo_cipher_fips_cnt; -static ERL_NIF_TERM algo_cipher[25]; /* increase when extending the list */ -static int algo_mac_cnt, algo_mac_fips_cnt; -static ERL_NIF_TERM algo_mac[3]; /* increase when extending the list */ -static int algo_curve_cnt, algo_curve_fips_cnt; -static ERL_NIF_TERM algo_curve[89]; /* increase when extending the list */ -static int algo_rsa_opts_cnt, algo_rsa_opts_fips_cnt; -static ERL_NIF_TERM algo_rsa_opts[11]; /* increase when extending the list */ - -static void init_algorithms_types(ErlNifEnv* env) -{ - // Validated algorithms first - algo_hash_cnt = 0; - algo_hash[algo_hash_cnt++] = atom_sha; -#ifdef HAVE_SHA224 - algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha224"); -#endif -#ifdef HAVE_SHA256 - algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha256"); -#endif -#ifdef HAVE_SHA384 - algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha384"); -#endif -#ifdef HAVE_SHA512 - algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha512"); -#endif -#ifdef HAVE_SHA3_224 - algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha3_224"); -#endif -#ifdef HAVE_SHA3_256 - algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha3_256"); -#endif -#ifdef HAVE_SHA3_384 - algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha3_384"); -#endif -#ifdef HAVE_SHA3_512 - algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha3_512"); -#endif - // Non-validated algorithms follow - algo_hash_fips_cnt = algo_hash_cnt; - algo_hash[algo_hash_cnt++] = enif_make_atom(env, "md4"); - algo_hash[algo_hash_cnt++] = enif_make_atom(env, "md5"); - algo_hash[algo_hash_cnt++] = enif_make_atom(env, "ripemd160"); - - algo_pubkey_cnt = 0; - algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "rsa"); - algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "dss"); - algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "dh"); -#if defined(HAVE_EC) -#if !defined(OPENSSL_NO_EC2M) - algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "ec_gf2m"); -#endif - algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "ecdsa"); - algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "ecdh"); -#endif - // Non-validated algorithms follow - algo_pubkey_fips_cnt = algo_pubkey_cnt; - // Don't know if Edward curves are fips validated -#if defined(HAVE_EDDSA) - algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "eddsa"); -#endif - algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "srp"); - - // Validated algorithms first - algo_cipher_cnt = 0; -#ifndef OPENSSL_NO_DES - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cbc"); - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des_ede3"); -#ifdef HAVE_DES_ede3_cfb_encrypt - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cbf"); - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "des3_cfb"); -#endif -#endif - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc"); - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc128"); - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cbc256"); - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_ctr"); - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_ecb"); -#if defined(HAVE_GCM) - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_gcm"); -#endif -#if defined(HAVE_CCM) - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_ccm"); -#endif - // Non-validated algorithms follow - algo_cipher_fips_cnt = algo_cipher_cnt; -#ifdef HAVE_AES_IGE - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_ige256"); -#endif - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cfb8"); - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env, "aes_cfb128"); -#ifndef OPENSSL_NO_DES - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_cbc"); - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_cfb"); - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"des_ecb"); -#endif - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_cbc"); - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_cfb64"); - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_ofb64"); - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"blowfish_ecb"); -#ifndef OPENSSL_NO_RC2 - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"rc2_cbc"); -#endif -#ifndef OPENSSL_NO_RC4 - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"rc4"); -#endif -#if defined(HAVE_CHACHA20_POLY1305) - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"chacha20_poly1305"); -#endif -#if defined(HAVE_CHACHA20) - algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"chacha20"); -#endif - - // Validated algorithms first - algo_mac_cnt = 0; - algo_mac[algo_mac_cnt++] = enif_make_atom(env,"hmac"); -#ifdef HAVE_CMAC - algo_mac[algo_mac_cnt++] = enif_make_atom(env,"cmac"); -#endif -#ifdef HAVE_POLY1305 - algo_mac[algo_mac_cnt++] = enif_make_atom(env,"poly1305"); -#endif - // Non-validated algorithms follow - algo_mac_fips_cnt = algo_mac_cnt; - - // Validated algorithms first - algo_curve_cnt = 0; -#if defined(HAVE_EC) - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp160k1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp160r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp160r2"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp192r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp192k1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp224k1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp224r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp256k1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp256r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp384r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp521r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime192v1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime192v2"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime192v3"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime239v1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime239v2"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime239v3"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime256v1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls7"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls9"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls12"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP160r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP160t1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP192r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP192t1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP224r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP224t1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP256r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP256t1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP320r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP320t1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP384r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP384t1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP512r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP512t1"); -#if !defined(OPENSSL_NO_EC2M) - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect163k1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect163r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect163r2"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect193r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect193r2"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect233k1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect233r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect239k1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect283k1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect283r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect409k1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect409r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect571k1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect571r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb163v1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb163v2"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb163v3"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb176v1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb191v1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb191v2"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb191v3"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb208w1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb239v1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb239v2"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb239v3"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb272w1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb304w1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb359v1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb368w1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb431r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls3"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls5"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls10"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls11"); -#endif -#endif - // Non-validated algorithms follow - algo_curve_fips_cnt = algo_curve_cnt; -#if defined(HAVE_EC) - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp112r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp112r2"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp128r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp128r2"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls6"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls8"); -#if !defined(OPENSSL_NO_EC2M) - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect113r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect113r2"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect131r1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect131r2"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls1"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls4"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"ipsec3"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"ipsec4"); -#endif -#endif - //-- -#ifdef HAVE_EDDSA - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"ed25519"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"ed448"); -#endif -#ifdef HAVE_ED_CURVE_DH - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"x25519"); - algo_curve[algo_curve_cnt++] = enif_make_atom(env,"x448"); -#endif - - // Validated algorithms first - algo_rsa_opts_cnt = 0; -#ifdef HAS_EVP_PKEY_CTX -# ifdef HAVE_RSA_PKCS1_PSS_PADDING - algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_pkcs1_pss_padding"); - algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_pss_saltlen"); -# endif -# ifdef HAVE_RSA_MGF1_MD - algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_mgf1_md"); -# endif -# ifdef HAVE_RSA_OAEP_PADDING - algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_pkcs1_oaep_padding"); -# endif -# ifdef HAVE_RSA_OAEP_MD - algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_oaep_label"); - algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_oaep_md"); -# endif - algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"signature_md"); -#endif - algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_pkcs1_padding"); - algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_x931_padding"); -#ifdef HAVE_RSA_SSLV23_PADDING - algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_sslv23_padding"); -#endif - algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_no_padding"); - algo_rsa_opts_fips_cnt = algo_rsa_opts_cnt; - - - // 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)); - ASSERT(algo_rsa_opts_cnt <= sizeof(algo_rsa_opts)/sizeof(ERL_NIF_TERM)); -} - -static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ -#ifdef FIPS_SUPPORT - int fips_mode = FIPS_mode(); - int hash_cnt = fips_mode ? algo_hash_fips_cnt : algo_hash_cnt; - 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; - int rsa_opts_cnt = fips_mode ? algo_rsa_opts_fips_cnt : algo_rsa_opts_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; - int rsa_opts_cnt = algo_rsa_opts_cnt; -#endif - return enif_make_tuple6(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_curve, curve_cnt), - enif_make_list_from_array(env, algo_rsa_opts, rsa_opts_cnt) - ); -} - -static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ - /* [{<<"OpenSSL">>,9470143,<<"OpenSSL 0.9.8k 25 Mar 2009">>}] */ - - static const char libname[] = "OpenSSL"; - unsigned name_sz = strlen(libname); - const char* ver = SSLeay_version(SSLEAY_VERSION); - unsigned ver_sz = strlen(ver); - ERL_NIF_TERM name_term, ver_term; - int ver_num = OPENSSL_VERSION_NUMBER; - /* R16: - * Ignore library version number from SSLeay() and instead show header - * version. Otherwise user might try to call a function that is implemented - * by a newer library but not supported by the headers used at compile time. - * Example: DES_ede3_cfb_encrypt in 0.9.7i but not in 0.9.7d. - * - * Version string is still from library though. - */ - - memcpy(enif_make_new_binary(env, name_sz, &name_term), libname, name_sz); - memcpy(enif_make_new_binary(env, ver_sz, &ver_term), ver, ver_sz); - - return enif_make_list1(env, enif_make_tuple3(env, name_term, - enif_make_int(env, ver_num), - ver_term)); -} - -static ERL_NIF_TERM info_fips(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ -#ifdef FIPS_SUPPORT - return FIPS_mode() ? atom_enabled : atom_not_enabled; -#else - return atom_not_supported; -#endif -} - -static ERL_NIF_TERM enable_fips_mode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Boolean) */ - if (argv[0] == atom_true) { -#ifdef FIPS_SUPPORT - if (FIPS_mode_set(1)) { - return atom_true; - } -#endif - PRINTF_ERR0("CRYPTO: Could not setup FIPS mode"); - return atom_false; - } else if (argv[0] == atom_false) { -#ifdef FIPS_SUPPORT - if (!FIPS_mode_set(0)) { - return atom_false; - } -#endif - return atom_true; - } else { - return enif_make_badarg(env); - } -} - - -#if defined(HAVE_EC) -static ERL_NIF_TERM make_badarg_maybe(ErlNifEnv* env) -{ - ERL_NIF_TERM reason; - if (enif_has_pending_exception(env, &reason)) - return reason; /* dummy return value ignored */ - else - return enif_make_badarg(env); -} -#endif - -static ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Data) */ - struct digest_type_t *digp = NULL; - const EVP_MD *md; - ErlNifBinary data; - ERL_NIF_TERM ret; - unsigned ret_size; - - digp = get_digest_type(argv[0]); - if (!digp || - !enif_inspect_iolist_as_binary(env, argv[1], &data)) { - return enif_make_badarg(env); - } - md = digp->md.p; - if (!md) { - return atom_notsup; - } - - ret_size = (unsigned)EVP_MD_size(md); - ASSERT(0 < ret_size && ret_size <= EVP_MAX_MD_SIZE); - if (!EVP_Digest(data.data, data.size, - enif_make_new_binary(env, ret_size, &ret), &ret_size, - md, NULL)) { - return atom_notsup; - } - ASSERT(ret_size == (unsigned)EVP_MD_size(md)); - - CONSUME_REDS(env, data); - return ret; -} - -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0) - -static ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type) */ - struct digest_type_t *digp = NULL; - struct evp_md_ctx *ctx; - ERL_NIF_TERM ret; - - digp = get_digest_type(argv[0]); - if (!digp) { - return enif_make_badarg(env); - } - if (!digp->md.p) { - return atom_notsup; - } - - ctx = enif_alloc_resource(evp_md_ctx_rtype, sizeof(struct evp_md_ctx)); - ctx->ctx = EVP_MD_CTX_new(); - if (!EVP_DigestInit(ctx->ctx, digp->md.p)) { - enif_release_resource(ctx); - return atom_notsup; - } - ret = enif_make_resource(env, ctx); - enif_release_resource(ctx); - return ret; -} -static ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context, Data) */ - struct evp_md_ctx *ctx, *new_ctx; - ErlNifBinary data; - ERL_NIF_TERM ret; - - if (!enif_get_resource(env, argv[0], evp_md_ctx_rtype, (void**)&ctx) || - !enif_inspect_iolist_as_binary(env, argv[1], &data)) { - return enif_make_badarg(env); - } - - new_ctx = enif_alloc_resource(evp_md_ctx_rtype, sizeof(struct evp_md_ctx)); - new_ctx->ctx = EVP_MD_CTX_new(); - if (!EVP_MD_CTX_copy(new_ctx->ctx, ctx->ctx) || - !EVP_DigestUpdate(new_ctx->ctx, data.data, data.size)) { - enif_release_resource(new_ctx); - return atom_notsup; - } - - ret = enif_make_resource(env, new_ctx); - enif_release_resource(new_ctx); - CONSUME_REDS(env, data); - return ret; -} -static ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context) */ - struct evp_md_ctx *ctx; - EVP_MD_CTX *new_ctx; - ERL_NIF_TERM ret; - unsigned ret_size; - - if (!enif_get_resource(env, argv[0], evp_md_ctx_rtype, (void**)&ctx)) { - return enif_make_badarg(env); - } - - ret_size = (unsigned)EVP_MD_CTX_size(ctx->ctx); - ASSERT(0 < ret_size && ret_size <= EVP_MAX_MD_SIZE); - - new_ctx = EVP_MD_CTX_new(); - if (!EVP_MD_CTX_copy(new_ctx, ctx->ctx) || - !EVP_DigestFinal(new_ctx, - enif_make_new_binary(env, ret_size, &ret), - &ret_size)) { - EVP_MD_CTX_free(new_ctx); - return atom_notsup; - } - EVP_MD_CTX_free(new_ctx); - ASSERT(ret_size == (unsigned)EVP_MD_CTX_size(ctx->ctx)); - - return ret; -} - -#else /* if OPENSSL_VERSION_NUMBER < 1.0 */ - -static ERL_NIF_TERM hash_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type) */ - typedef int (*init_fun)(unsigned char*); - struct digest_type_t *digp = NULL; - ERL_NIF_TERM ctx; - size_t ctx_size = 0; - init_fun ctx_init = 0; - - digp = get_digest_type(argv[0]); - if (!digp) { - return enif_make_badarg(env); - } - if (!digp->md.p) { - return atom_notsup; - } - - switch (EVP_MD_type(digp->md.p)) - { - case NID_md4: - ctx_size = MD4_CTX_LEN; - ctx_init = (init_fun)(&MD4_Init); - break; - case NID_md5: - ctx_size = MD5_CTX_LEN; - ctx_init = (init_fun)(&MD5_Init); - break; - case NID_ripemd160: - ctx_size = RIPEMD160_CTX_LEN; - ctx_init = (init_fun)(&RIPEMD160_Init); - break; - case NID_sha1: - ctx_size = sizeof(SHA_CTX); - ctx_init = (init_fun)(&SHA1_Init); - break; -#ifdef HAVE_SHA224 - case NID_sha224: - ctx_size = sizeof(SHA256_CTX); - ctx_init = (init_fun)(&SHA224_Init); - break; -#endif -#ifdef HAVE_SHA256 - case NID_sha256: - ctx_size = sizeof(SHA256_CTX); - ctx_init = (init_fun)(&SHA256_Init); - break; -#endif -#ifdef HAVE_SHA384 - case NID_sha384: - ctx_size = sizeof(SHA512_CTX); - ctx_init = (init_fun)(&SHA384_Init); - break; -#endif -#ifdef HAVE_SHA512 - case NID_sha512: - ctx_size = sizeof(SHA512_CTX); - ctx_init = (init_fun)(&SHA512_Init); - break; -#endif - default: - return atom_notsup; - } - ASSERT(ctx_size); - ASSERT(ctx_init); - - ctx_init(enif_make_new_binary(env, ctx_size, &ctx)); - return enif_make_tuple2(env, argv[0], ctx); -} -static ERL_NIF_TERM hash_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* ({Type, Context}, Data) */ - typedef int (*update_fun)(unsigned char*, const unsigned char*, size_t); - ERL_NIF_TERM new_ctx; - ErlNifBinary ctx, data; - const ERL_NIF_TERM *tuple; - int arity; - struct digest_type_t *digp = NULL; - unsigned char *ctx_buff; - size_t ctx_size = 0; - update_fun ctx_update = 0; - - if (!enif_get_tuple(env, argv[0], &arity, &tuple) || - arity != 2 || - !(digp = get_digest_type(tuple[0])) || - !enif_inspect_binary(env, tuple[1], &ctx) || - !enif_inspect_iolist_as_binary(env, argv[1], &data)) { - return enif_make_badarg(env); - } - if (!digp->md.p) { - return atom_notsup; - } - - switch (EVP_MD_type(digp->md.p)) - { - case NID_md4: - ctx_size = MD4_CTX_LEN; - ctx_update = (update_fun)(&MD4_Update); - break; - case NID_md5: - ctx_size = MD5_CTX_LEN; - ctx_update = (update_fun)(&MD5_Update); - break; - case NID_ripemd160: - ctx_size = RIPEMD160_CTX_LEN; - ctx_update = (update_fun)(&RIPEMD160_Update); - break; - case NID_sha1: - ctx_size = sizeof(SHA_CTX); - ctx_update = (update_fun)(&SHA1_Update); - break; -#ifdef HAVE_SHA224 - case NID_sha224: - ctx_size = sizeof(SHA256_CTX); - ctx_update = (update_fun)(&SHA224_Update); - break; -#endif -#ifdef HAVE_SHA256 - case NID_sha256: - ctx_size = sizeof(SHA256_CTX); - ctx_update = (update_fun)(&SHA256_Update); - break; -#endif -#ifdef HAVE_SHA384 - case NID_sha384: - ctx_size = sizeof(SHA512_CTX); - ctx_update = (update_fun)(&SHA384_Update); - break; -#endif -#ifdef HAVE_SHA512 - case NID_sha512: - ctx_size = sizeof(SHA512_CTX); - ctx_update = (update_fun)(&SHA512_Update); - break; -#endif - default: - return atom_notsup; - } - ASSERT(ctx_size); - ASSERT(ctx_update); - - if (ctx.size != ctx_size) { - return enif_make_badarg(env); - } - - ctx_buff = enif_make_new_binary(env, ctx_size, &new_ctx); - memcpy(ctx_buff, ctx.data, ctx_size); - ctx_update(ctx_buff, data.data, data.size); - - CONSUME_REDS(env, data); - return enif_make_tuple2(env, tuple[0], new_ctx); -} -static ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* ({Type, Context}) */ - typedef int (*final_fun)(unsigned char*, void*); - ERL_NIF_TERM ret; - ErlNifBinary ctx; - const ERL_NIF_TERM *tuple; - int arity; - struct digest_type_t *digp = NULL; - const EVP_MD *md; - void *new_ctx; - size_t ctx_size = 0; - final_fun ctx_final = 0; - - if (!enif_get_tuple(env, argv[0], &arity, &tuple) || - arity != 2 || - !(digp = get_digest_type(tuple[0])) || - !enif_inspect_binary(env, tuple[1], &ctx)) { - return enif_make_badarg(env); - } - md = digp->md.p; - if (!md) { - return atom_notsup; - } - - - switch (EVP_MD_type(md)) - { - case NID_md4: - ctx_size = MD4_CTX_LEN; - ctx_final = (final_fun)(&MD4_Final); - break; - case NID_md5: - ctx_size = MD5_CTX_LEN; - ctx_final = (final_fun)(&MD5_Final); - break; - case NID_ripemd160: - ctx_size = RIPEMD160_CTX_LEN; - ctx_final = (final_fun)(&RIPEMD160_Final); - break; - case NID_sha1: - ctx_size = sizeof(SHA_CTX); - ctx_final = (final_fun)(&SHA1_Final); - break; -#ifdef HAVE_SHA224 - case NID_sha224: - ctx_size = sizeof(SHA256_CTX); - ctx_final = (final_fun)(&SHA224_Final); - break; -#endif -#ifdef HAVE_SHA256 - case NID_sha256: - ctx_size = sizeof(SHA256_CTX); - ctx_final = (final_fun)(&SHA256_Final); - break; -#endif -#ifdef HAVE_SHA384 - case NID_sha384: - ctx_size = sizeof(SHA512_CTX); - ctx_final = (final_fun)(&SHA384_Final); - break; -#endif -#ifdef HAVE_SHA512 - case NID_sha512: - ctx_size = sizeof(SHA512_CTX); - ctx_final = (final_fun)(&SHA512_Final); - break; -#endif - default: - return atom_notsup; - } - ASSERT(ctx_size); - ASSERT(ctx_final); - - if (ctx.size != ctx_size) { - return enif_make_badarg(env); - } - - new_ctx = enif_alloc(ctx_size); - memcpy(new_ctx, ctx.data, ctx_size); - ctx_final(enif_make_new_binary(env, (size_t)EVP_MD_size(md), &ret), - new_ctx); - enif_free(new_ctx); - - return ret; -} -#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; - ErlNifBinary key, data; - unsigned char buff[EVP_MAX_MD_SIZE]; - unsigned size = 0, req_size = 0; - ERL_NIF_TERM ret; - - digp = get_digest_type(argv[0]); - if (!digp || - !enif_inspect_iolist_as_binary(env, argv[1], &key) || - !enif_inspect_iolist_as_binary(env, argv[2], &data) || - (argc == 4 && !enif_get_uint(env, argv[3], &req_size))) { - return enif_make_badarg(env); - } - - if (!digp->md.p || - !HMAC(digp->md.p, - key.data, key.size, - data.data, data.size, - buff, &size)) { - return atom_notsup; - } - ASSERT(0 < size && size <= EVP_MAX_MD_SIZE); - CONSUME_REDS(env, data); - - if (argc == 4) { - if (req_size <= size) { - size = req_size; - } - else { - return enif_make_badarg(env); - } - } - memcpy(enif_make_new_binary(env, size, &ret), buff, size); - return ret; -} - -static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context *obj) -{ - if (obj->alive) { - HMAC_CTX_free(obj->ctx); - obj->alive = 0; - } - enif_mutex_destroy(obj->mtx); -} - -static ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Key) */ - struct digest_type_t *digp = NULL; - ErlNifBinary key; - ERL_NIF_TERM ret; - struct hmac_context *obj; - - digp = get_digest_type(argv[0]); - if (!digp || - !enif_inspect_iolist_as_binary(env, argv[1], &key)) { - return enif_make_badarg(env); - } - if (!digp->md.p) { - return atom_notsup; - } - - obj = enif_alloc_resource(hmac_context_rtype, sizeof(struct hmac_context)); - obj->mtx = enif_mutex_create("crypto.hmac"); - obj->alive = 1; - obj->ctx = HMAC_CTX_new(); -#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0) - // Check the return value of HMAC_Init: it may fail in FIPS mode - // for disabled algorithms - if (!HMAC_Init_ex(obj->ctx, key.data, key.size, digp->md.p, NULL)) { - enif_release_resource(obj); - return atom_notsup; - } -#else - HMAC_Init_ex(obj->ctx, key.data, key.size, digp->md.p, NULL); -#endif - - ret = enif_make_resource(env, obj); - enif_release_resource(obj); - return ret; -} - -static ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context, Data) */ - ErlNifBinary data; - struct hmac_context* obj; - - if (!enif_get_resource(env, argv[0], hmac_context_rtype, (void**)&obj) - || !enif_inspect_iolist_as_binary(env, argv[1], &data)) { - return enif_make_badarg(env); - } - enif_mutex_lock(obj->mtx); - if (!obj->alive) { - enif_mutex_unlock(obj->mtx); - return enif_make_badarg(env); - } - HMAC_Update(obj->ctx, data.data, data.size); - enif_mutex_unlock(obj->mtx); - - CONSUME_REDS(env,data); - return argv[0]; -} - -static ERL_NIF_TERM hmac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context) or (Context, HashLen) */ - ERL_NIF_TERM ret; - struct hmac_context* obj; - unsigned char mac_buf[EVP_MAX_MD_SIZE]; - unsigned char * mac_bin; - unsigned int req_len = 0; - unsigned int mac_len; - - if (!enif_get_resource(env,argv[0],hmac_context_rtype, (void**)&obj) - || (argc == 2 && !enif_get_uint(env, argv[1], &req_len))) { - return enif_make_badarg(env); - } - - enif_mutex_lock(obj->mtx); - if (!obj->alive) { - enif_mutex_unlock(obj->mtx); - return enif_make_badarg(env); - } - - HMAC_Final(obj->ctx, mac_buf, &mac_len); - HMAC_CTX_free(obj->ctx); - obj->alive = 0; - enif_mutex_unlock(obj->mtx); - - if (argc == 2 && req_len < mac_len) { - /* Only truncate to req_len bytes if asked. */ - mac_len = req_len; - } - mac_bin = enif_make_new_binary(env, mac_len, &ret); - memcpy(mac_bin, mac_buf, mac_len); - - return ret; -} - -static ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type, Key, Data) */ -#if defined(HAVE_CMAC) - struct cipher_type_t *cipherp = NULL; - const EVP_CIPHER *cipher; - CMAC_CTX *ctx; - ErlNifBinary key; - ErlNifBinary data; - ERL_NIF_TERM ret; - size_t ret_size; - - if (!enif_inspect_iolist_as_binary(env, argv[1], &key) - || !(cipherp = get_cipher_type(argv[0], key.size)) - || !enif_inspect_iolist_as_binary(env, argv[2], &data)) { - return enif_make_badarg(env); - } - cipher = cipherp->cipher.p; - if (!cipher) { - return enif_raise_exception(env, atom_notsup); - } - - ctx = CMAC_CTX_new(); - if (!CMAC_Init(ctx, key.data, key.size, cipher, NULL)) { - CMAC_CTX_free(ctx); - return atom_notsup; - } - - if (!CMAC_Update(ctx, data.data, data.size) || - !CMAC_Final(ctx, - enif_make_new_binary(env, EVP_CIPHER_block_size(cipher), &ret), - &ret_size)) { - CMAC_CTX_free(ctx); - return atom_notsup; - } - ASSERT(ret_size == (unsigned)EVP_CIPHER_block_size(cipher)); - - CMAC_CTX_free(ctx); - CONSUME_REDS(env, data); - return ret; -#else - /* The CMAC functionality was introduced in OpenSSL 1.0.1 - * Although OTP requires at least version 0.9.8, the versions 0.9.8 and 1.0.0 are - * no longer maintained. */ - return atom_notsup; -#endif -} - -/* For OpenSSL >= 1.1.1 the hmac_nif and cmac_nif could be integrated into poly1305 (with 'type' as parameter) */ -static ERL_NIF_TERM poly1305_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, Text) */ -#ifdef HAVE_POLY1305 - ErlNifBinary key_bin, text, ret_bin; - ERL_NIF_TERM ret = atom_error; - EVP_PKEY *key = NULL; - EVP_MD_CTX *mctx = NULL; - EVP_PKEY_CTX *pctx = NULL; - const EVP_MD *md = NULL; - size_t size; - int type; - - type = EVP_PKEY_POLY1305; - - if (!enif_inspect_binary(env, argv[0], &key_bin) || - !(key_bin.size == 32) ) { - return enif_make_badarg(env); - } - - if (!enif_inspect_binary(env, argv[1], &text) ) { - return enif_make_badarg(env); - } - - key = EVP_PKEY_new_raw_private_key(type, /*engine*/ NULL, key_bin.data, key_bin.size); - - if (!key || - !(mctx = EVP_MD_CTX_new()) || - !EVP_DigestSignInit(mctx, &pctx, md, /*engine*/ NULL, key) || - !EVP_DigestSignUpdate(mctx, text.data, text.size)) { - goto err; - } - - if (!EVP_DigestSignFinal(mctx, NULL, &size) || - !enif_alloc_binary(size, &ret_bin) || - !EVP_DigestSignFinal(mctx, ret_bin.data, &size)) { - goto err; - } - - if ((size != ret_bin.size) && - !enif_realloc_binary(&ret_bin, size)) { - goto err; - } - - ret = enif_make_binary(env, &ret_bin); - - err: - EVP_MD_CTX_free(mctx); - EVP_PKEY_free(key); - return ret; - -#else - return atom_notsup; -#endif -} - -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; - const EVP_CIPHER *cipher; - ErlNifBinary key, ivec, text; - EVP_CIPHER_CTX* ctx; - ERL_NIF_TERM ret; - unsigned char *out; - int ivec_size, out_size = 0; - - if (!enif_inspect_iolist_as_binary(env, argv[1], &key) - || !(cipherp = get_cipher_type(argv[0], key.size)) - || !enif_inspect_iolist_as_binary(env, argv[argc - 2], &text)) { - return enif_make_badarg(env); - } - cipher = cipherp->cipher.p; - if (!cipher) { - return enif_raise_exception(env, atom_notsup); - } - - if (argv[0] == atom_aes_cfb8) { - CHECK_NO_FIPS_MODE(); - if ((key.size == 24 || key.size == 32)) { - /* Why do EVP_CIPHER_CTX_set_key_length() fail on these key sizes? - * Fall back on low level API - */ - return aes_cfb_8_crypt(env, argc-1, argv+1); - } - } - else if (argv[0] == atom_aes_cfb128) { - CHECK_NO_FIPS_MODE(); - if ((key.size == 24 || key.size == 32)) { - /* Why do EVP_CIPHER_CTX_set_key_length() fail on these key sizes? - * Fall back on low level API - */ - return aes_cfb_128_crypt_nif(env, argc-1, argv+1); - } - } - ivec_size = EVP_CIPHER_iv_length(cipher); - -#ifdef HAVE_ECB_IVEC_BUG - if (argv[0] == atom_aes_ecb || argv[0] == atom_blowfish_ecb || - argv[0] == atom_des_ecb) - ivec_size = 0; /* 0.9.8l returns faulty ivec_size */ -#endif - - if (text.size % EVP_CIPHER_block_size(cipher) != 0 || - (ivec_size == 0 ? argc != 4 - : (argc != 5 || - !enif_inspect_iolist_as_binary(env, argv[2], &ivec) || - ivec.size != ivec_size))) { - return enif_make_badarg(env); - } - - out = enif_make_new_binary(env, text.size, &ret); - - ctx = EVP_CIPHER_CTX_new(); - if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, - (argv[argc - 1] == atom_true)) || - !EVP_CIPHER_CTX_set_key_length(ctx, key.size) || - !(EVP_CIPHER_type(cipher) != NID_rc2_cbc || - EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_RC2_KEY_BITS, key.size * 8, NULL)) || - !EVP_CipherInit_ex(ctx, NULL, NULL, - key.data, ivec_size ? ivec.data : NULL, -1) || - !EVP_CIPHER_CTX_set_padding(ctx, 0)) { - - EVP_CIPHER_CTX_free(ctx); - return enif_raise_exception(env, atom_notsup); - } - - if (text.size > 0 && /* OpenSSL 0.9.8h asserts text.size > 0 */ - (!EVP_CipherUpdate(ctx, out, &out_size, text.data, text.size) - || (ASSERT(out_size == text.size), 0) - || !EVP_CipherFinal_ex(ctx, out + out_size, &out_size))) { - - EVP_CIPHER_CTX_free(ctx); - return enif_raise_exception(env, atom_notsup); - } - ASSERT(out_size == 0); - EVP_CIPHER_CTX_free(ctx); - CONSUME_REDS(env, text); - - return ret; -} - -static ERL_NIF_TERM aes_cfb_8_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, IVec, Data, IsEncrypt) */ - ErlNifBinary key, ivec, text; - AES_KEY aes_key; - unsigned char ivec_clone[16]; /* writable copy */ - int new_ivlen = 0; - ERL_NIF_TERM ret; - - CHECK_NO_FIPS_MODE(); - - if (!enif_inspect_iolist_as_binary(env, argv[0], &key) - || !(key.size == 16 || key.size == 24 || key.size == 32) - || !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16 - || !enif_inspect_iolist_as_binary(env, argv[2], &text)) { - return enif_make_badarg(env); - } - - memcpy(ivec_clone, ivec.data, 16); - AES_set_encrypt_key(key.data, key.size * 8, &aes_key); - AES_cfb8_encrypt((unsigned char *) text.data, - enif_make_new_binary(env, text.size, &ret), - text.size, &aes_key, ivec_clone, &new_ivlen, - (argv[3] == atom_true)); - CONSUME_REDS(env,text); - return ret; -} - -static ERL_NIF_TERM aes_cfb_128_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, IVec, Data, IsEncrypt) */ - ErlNifBinary key, ivec, text; - AES_KEY aes_key; - unsigned char ivec_clone[16]; /* writable copy */ - int new_ivlen = 0; - ERL_NIF_TERM ret; - - if (!enif_inspect_iolist_as_binary(env, argv[0], &key) - || !(key.size == 16 || key.size == 24 || key.size == 32) - || !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 16 - || !enif_inspect_iolist_as_binary(env, argv[2], &text)) { - return enif_make_badarg(env); - } - - memcpy(ivec_clone, ivec.data, 16); - AES_set_encrypt_key(key.data, key.size * 8, &aes_key); - AES_cfb128_encrypt((unsigned char *) text.data, - enif_make_new_binary(env, text.size, &ret), - text.size, &aes_key, ivec_clone, &new_ivlen, - (argv[3] == atom_true)); - CONSUME_REDS(env,text); - return ret; -} - -static ERL_NIF_TERM aes_ige_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, IVec, Data, IsEncrypt) */ -#ifdef HAVE_AES_IGE - ErlNifBinary key_bin, ivec_bin, data_bin; - AES_KEY aes_key; - unsigned char ivec[32]; - int i; - unsigned char* ret_ptr; - ERL_NIF_TERM ret; - - CHECK_NO_FIPS_MODE(); - - if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) - || (key_bin.size != 16 && key_bin.size != 32) - || !enif_inspect_binary(env, argv[1], &ivec_bin) - || ivec_bin.size != 32 - || !enif_inspect_iolist_as_binary(env, argv[2], &data_bin) - || data_bin.size % 16 != 0) { - - return enif_make_badarg(env); - } - - if (argv[3] == atom_true) { - i = AES_ENCRYPT; - AES_set_encrypt_key(key_bin.data, key_bin.size*8, &aes_key); - } - else { - i = AES_DECRYPT; - AES_set_decrypt_key(key_bin.data, key_bin.size*8, &aes_key); - } - - ret_ptr = enif_make_new_binary(env, data_bin.size, &ret); - memcpy(ivec, ivec_bin.data, 32); /* writable copy */ - AES_ige_encrypt(data_bin.data, ret_ptr, data_bin.size, &aes_key, ivec, i); - CONSUME_REDS(env,data_bin); - return ret; -#else - return atom_notsup; -#endif -} - - -/* Initializes state for ctr streaming (de)encryption -*/ -#ifdef HAVE_EVP_AES_CTR -static ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, IVec) */ - ErlNifBinary key_bin, ivec_bin; - struct evp_cipher_ctx *ctx; - const EVP_CIPHER *cipher; - ERL_NIF_TERM ret; - - if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) - || !enif_inspect_binary(env, argv[1], &ivec_bin) - || ivec_bin.size != 16) { - return enif_make_badarg(env); - } - - switch (key_bin.size) - { - case 16: cipher = EVP_aes_128_ctr(); break; - case 24: cipher = EVP_aes_192_ctr(); break; - case 32: cipher = EVP_aes_256_ctr(); break; - default: return enif_make_badarg(env); - } - - ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx)); - ctx->ctx = EVP_CIPHER_CTX_new(); - EVP_CipherInit_ex(ctx->ctx, cipher, NULL, - key_bin.data, ivec_bin.data, 1); - EVP_CIPHER_CTX_set_padding(ctx->ctx, 0); - ret = enif_make_resource(env, ctx); - enif_release_resource(ctx); - return ret; -} -static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Context, Data) */ - struct evp_cipher_ctx *ctx, *new_ctx; - ErlNifBinary data_bin; - ERL_NIF_TERM ret, cipher_term; - unsigned char *out; - int outl = 0; - - if (!enif_get_resource(env, argv[0], evp_cipher_ctx_rtype, (void**)&ctx) - || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { - return enif_make_badarg(env); - } - new_ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx)); - new_ctx->ctx = EVP_CIPHER_CTX_new(); - EVP_CIPHER_CTX_copy(new_ctx->ctx, ctx->ctx); - out = enif_make_new_binary(env, data_bin.size, &cipher_term); - EVP_CipherUpdate(new_ctx->ctx, out, &outl, data_bin.data, data_bin.size); - ASSERT(outl == data_bin.size); - - ret = enif_make_tuple2(env, enif_make_resource(env, new_ctx), cipher_term); - enif_release_resource(new_ctx); - CONSUME_REDS(env,data_bin); - return ret; -} - -#else /* if not HAVE_EVP_AES_CTR */ - -static ERL_NIF_TERM aes_ctr_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, IVec) */ - ErlNifBinary key_bin, ivec_bin; - ERL_NIF_TERM ecount_bin; - - if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) - || !enif_inspect_binary(env, argv[1], &ivec_bin) - || !(key_bin.size == 16 || key_bin.size == 24 || key_bin.size ==32) - || ivec_bin.size != 16) { - return enif_make_badarg(env); - } - - memset(enif_make_new_binary(env, AES_BLOCK_SIZE, &ecount_bin), - 0, AES_BLOCK_SIZE); - return enif_make_tuple4(env, argv[0], argv[1], ecount_bin, enif_make_int(env, 0)); -} - -static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* ({Key, IVec, ECount, Num}, Data) */ - ErlNifBinary key_bin, ivec_bin, text_bin, ecount_bin; - AES_KEY aes_key; - unsigned int num; - ERL_NIF_TERM ret, num2_term, cipher_term, ivec2_term, ecount2_term, new_state_term; - int state_arity; - const ERL_NIF_TERM *state_term; - unsigned char * ivec2_buf; - unsigned char * ecount2_buf; - - if (!enif_get_tuple(env, argv[0], &state_arity, &state_term) - || state_arity != 4 - || !enif_inspect_iolist_as_binary(env, state_term[0], &key_bin) - || AES_set_encrypt_key(key_bin.data, key_bin.size*8, &aes_key) != 0 - || !enif_inspect_binary(env, state_term[1], &ivec_bin) || ivec_bin.size != 16 - || !enif_inspect_binary(env, state_term[2], &ecount_bin) || ecount_bin.size != AES_BLOCK_SIZE - || !enif_get_uint(env, state_term[3], &num) - || !enif_inspect_iolist_as_binary(env, argv[1], &text_bin)) { - return enif_make_badarg(env); - } - - ivec2_buf = enif_make_new_binary(env, ivec_bin.size, &ivec2_term); - ecount2_buf = enif_make_new_binary(env, ecount_bin.size, &ecount2_term); - - memcpy(ivec2_buf, ivec_bin.data, 16); - memcpy(ecount2_buf, ecount_bin.data, ecount_bin.size); - - AES_ctr128_encrypt((unsigned char *) text_bin.data, - enif_make_new_binary(env, text_bin.size, &cipher_term), - text_bin.size, &aes_key, ivec2_buf, ecount2_buf, &num); - - num2_term = enif_make_uint(env, num); - new_state_term = enif_make_tuple4(env, state_term[0], ivec2_term, ecount2_term, num2_term); - ret = enif_make_tuple2(env, new_state_term, cipher_term); - CONSUME_REDS(env,text_bin); - return ret; -} -#endif /* !HAVE_EVP_AES_CTR */ - -static ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type,Key,Iv,AAD,In) */ -#if defined(HAVE_AEAD) - EVP_CIPHER_CTX *ctx; - const EVP_CIPHER *cipher = NULL; - ErlNifBinary key, iv, aad, in; - unsigned int tag_len; - unsigned char *outp, *tagp; - ERL_NIF_TERM type, out, out_tag; - int len, ctx_ctrl_set_ivlen, ctx_ctrl_get_tag; - - type = argv[0]; - - if (!enif_is_atom(env, type) - || !enif_inspect_iolist_as_binary(env, argv[1], &key) - || !enif_inspect_binary(env, argv[2], &iv) - || !enif_inspect_iolist_as_binary(env, argv[3], &aad) - || !enif_inspect_iolist_as_binary(env, argv[4], &in) - || !enif_get_uint(env, argv[5], &tag_len)) { - return enif_make_badarg(env); - } - - /* Use cipher_type some day. Must check block_encrypt|decrypt first */ -#if defined(HAVE_GCM) - if (type == atom_aes_gcm) { - if ((iv.size > 0) - && (1 <= tag_len && tag_len <= 16)) { - ctx_ctrl_set_ivlen = EVP_CTRL_GCM_SET_IVLEN; - ctx_ctrl_get_tag = EVP_CTRL_GCM_GET_TAG; - if (key.size == 16) cipher = EVP_aes_128_gcm(); - else if (key.size == 24) cipher = EVP_aes_192_gcm(); - else if (key.size == 32) cipher = EVP_aes_256_gcm(); - else enif_make_badarg(env); - } else - enif_make_badarg(env); - } else -#endif -#if defined(HAVE_CCM) - if (type == atom_aes_ccm) { - if ((7 <= iv.size && iv.size <= 13) - && (4 <= tag_len && tag_len <= 16) - && ((tag_len & 1) == 0) - ) { - ctx_ctrl_set_ivlen = EVP_CTRL_CCM_SET_IVLEN; - ctx_ctrl_get_tag = EVP_CTRL_CCM_GET_TAG; - if (key.size == 16) cipher = EVP_aes_128_ccm(); - else if (key.size == 24) cipher = EVP_aes_192_ccm(); - else if (key.size == 32) cipher = EVP_aes_256_ccm(); - else enif_make_badarg(env); - } else - enif_make_badarg(env); - } else -#endif -#if defined(HAVE_CHACHA20_POLY1305) - if (type == atom_chacha20_poly1305) { - if ((key.size == 32) - && (1 <= iv.size && iv.size <= 16) - && (tag_len == 16) - ) { - ctx_ctrl_set_ivlen = EVP_CTRL_AEAD_SET_IVLEN; - ctx_ctrl_get_tag = EVP_CTRL_AEAD_GET_TAG, - cipher = EVP_chacha20_poly1305(); - } else enif_make_badarg(env); - } else -#endif - return enif_raise_exception(env, atom_notsup); - - ctx = EVP_CIPHER_CTX_new(); - if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1) goto out_err; - if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_ivlen, iv.size, NULL) != 1) goto out_err; - -#if defined(HAVE_CCM) - if (type == atom_aes_ccm) { - if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_len, NULL) != 1) goto out_err; - if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1) goto out_err; - if (EVP_EncryptUpdate(ctx, NULL, &len, NULL, in.size) != 1) goto out_err; - } else -#endif - if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1) goto out_err; - - if (EVP_EncryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1) goto out_err; - - outp = enif_make_new_binary(env, in.size, &out); - - if (EVP_EncryptUpdate(ctx, outp, &len, in.data, in.size) != 1) goto out_err; - if (EVP_EncryptFinal_ex(ctx, outp/*+len*/, &len) != 1) goto out_err; - - tagp = enif_make_new_binary(env, tag_len, &out_tag); - - if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_get_tag, tag_len, tagp) != 1) goto out_err; - - EVP_CIPHER_CTX_free(ctx); - CONSUME_REDS(env, in); - return enif_make_tuple2(env, out, out_tag); - -out_err: - EVP_CIPHER_CTX_free(ctx); - return atom_error; - -#else - return enif_raise_exception(env, atom_notsup); -#endif -} - -static ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type,Key,Iv,AAD,In,Tag) */ -#if defined(HAVE_AEAD) - EVP_CIPHER_CTX *ctx; - const EVP_CIPHER *cipher = NULL; - ErlNifBinary key, iv, aad, in, tag; - unsigned char *outp; - ERL_NIF_TERM type, out; - int len, ctx_ctrl_set_ivlen, ctx_ctrl_set_tag; - - type = argv[0]; -#if defined(HAVE_GCM_EVP_DECRYPT_BUG) - if (type == atom_aes_gcm) - return aes_gcm_decrypt_NO_EVP(env, argc, argv); -#endif - - if (!enif_is_atom(env, type) - || !enif_inspect_iolist_as_binary(env, argv[1], &key) - || !enif_inspect_binary(env, argv[2], &iv) - || !enif_inspect_iolist_as_binary(env, argv[3], &aad) - || !enif_inspect_iolist_as_binary(env, argv[4], &in) - || !enif_inspect_iolist_as_binary(env, argv[5], &tag)) { - return enif_make_badarg(env); - } - - /* Use cipher_type some day. Must check block_encrypt|decrypt first */ -#if defined(HAVE_GCM) - if (type == atom_aes_gcm) { - if (iv.size > 0) { - ctx_ctrl_set_ivlen = EVP_CTRL_GCM_SET_IVLEN; - ctx_ctrl_set_tag = EVP_CTRL_GCM_SET_TAG; - if (key.size == 16) cipher = EVP_aes_128_gcm(); - else if (key.size == 24) cipher = EVP_aes_192_gcm(); - else if (key.size == 32) cipher = EVP_aes_256_gcm(); - else enif_make_badarg(env); - } else - enif_make_badarg(env); - } else -#endif -#if defined(HAVE_CCM) - if (type == atom_aes_ccm) { - if (iv.size > 0) { - ctx_ctrl_set_ivlen = EVP_CTRL_CCM_SET_IVLEN; - if (key.size == 16) cipher = EVP_aes_128_ccm(); - else if (key.size == 24) cipher = EVP_aes_192_ccm(); - else if (key.size == 32) cipher = EVP_aes_256_ccm(); - else enif_make_badarg(env); - } else - enif_make_badarg(env); - } else -#endif -#if defined(HAVE_CHACHA20_POLY1305) - if (type == atom_chacha20_poly1305) { - if ((key.size == 32) - && (1 <= iv.size && iv.size <= 16) - && tag.size == 16 - ) { - ctx_ctrl_set_ivlen = EVP_CTRL_AEAD_SET_IVLEN; - ctx_ctrl_set_tag = EVP_CTRL_AEAD_SET_TAG; - cipher = EVP_chacha20_poly1305(); - } else enif_make_badarg(env); - } else -#endif - return enif_raise_exception(env, atom_notsup); - - outp = enif_make_new_binary(env, in.size, &out); - - ctx = EVP_CIPHER_CTX_new(); - if (EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1) goto out_err; - if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_ivlen, iv.size, NULL) != 1) goto out_err; - -#if defined(HAVE_CCM) - if (type == atom_aes_ccm) { - if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag.size, tag.data) != 1) goto out_err; - } -#endif - - if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1) goto out_err; - -#if defined(HAVE_CCM) - if (type == atom_aes_ccm) { - if (1 != EVP_DecryptUpdate(ctx, NULL, &len, NULL, in.size)) goto out_err; - } -#endif - - if (EVP_DecryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1) goto out_err; - if (EVP_DecryptUpdate(ctx, outp, &len, in.data, in.size) != 1) goto out_err; - -#if defined(HAVE_GCM) || defined(HAVE_CHACHA20_POLY1305) - if (type == atom_aes_gcm) { - if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_tag, tag.size, tag.data) != 1) goto out_err; - if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1) goto out_err; - } -#endif - EVP_CIPHER_CTX_free(ctx); - - CONSUME_REDS(env, in); - return out; - -out_err: - EVP_CIPHER_CTX_free(ctx); - return atom_error; -#else - return enif_raise_exception(env, atom_notsup); -#endif -} - -#ifdef HAVE_GCM_EVP_DECRYPT_BUG -static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Type,Key,Iv,AAD,In,Tag) */ - GCM128_CONTEXT *ctx; - ErlNifBinary key, iv, aad, in, tag; - AES_KEY aes_key; - unsigned char *outp; - ERL_NIF_TERM out; - - if (!enif_inspect_iolist_as_binary(env, argv[1], &key) - || AES_set_encrypt_key(key.data, key.size*8, &aes_key) != 0 - || !enif_inspect_binary(env, argv[2], &iv) || iv.size == 0 - || !enif_inspect_iolist_as_binary(env, argv[3], &aad) - || !enif_inspect_iolist_as_binary(env, argv[4], &in) - || !enif_inspect_iolist_as_binary(env, argv[5], &tag)) { - return enif_make_badarg(env); - } - - if (!(ctx = CRYPTO_gcm128_new(&aes_key, (block128_f)AES_encrypt))) - return atom_error; - - CRYPTO_gcm128_setiv(ctx, iv.data, iv.size); - - if (CRYPTO_gcm128_aad(ctx, aad.data, aad.size)) - goto out_err; - - outp = enif_make_new_binary(env, in.size, &out); - - /* decrypt */ - if (CRYPTO_gcm128_decrypt(ctx, in.data, outp, in.size)) - goto out_err; - - /* calculate and check the tag */ - if (CRYPTO_gcm128_finish(ctx, tag.data, tag.size)) - goto out_err; - - CRYPTO_gcm128_release(ctx); - CONSUME_REDS(env, in); - - return out; - -out_err: - CRYPTO_gcm128_release(ctx); - return atom_error; -} -#endif /* HAVE_GCM_EVP_DECRYPT_BUG */ - - -static ERL_NIF_TERM chacha20_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key, IV) */ -#if defined(HAVE_CHACHA20) - ErlNifBinary key_bin, ivec_bin; - struct evp_cipher_ctx *ctx; - const EVP_CIPHER *cipher; - ERL_NIF_TERM ret; - - if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin) - || !enif_inspect_binary(env, argv[1], &ivec_bin) - || key_bin.size != 32 - || ivec_bin.size != 16) { - return enif_make_badarg(env); - } - - cipher = EVP_chacha20(); - - ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx)); - ctx->ctx = EVP_CIPHER_CTX_new(); - - - EVP_CipherInit_ex(ctx->ctx, cipher, NULL, - key_bin.data, ivec_bin.data, 1); - EVP_CIPHER_CTX_set_padding(ctx->ctx, 0); - ret = enif_make_resource(env, ctx); - enif_release_resource(ctx); - return ret; -#else - return enif_raise_exception(env, atom_notsup); -#endif -}; - -static ERL_NIF_TERM chacha20_stream_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (State, Data) */ -#if defined(HAVE_CHACHA20) - struct evp_cipher_ctx *ctx, *new_ctx; - ErlNifBinary data_bin; - ERL_NIF_TERM ret, cipher_term; - unsigned char *out; - int outl = 0; - - if (!enif_get_resource(env, argv[0], evp_cipher_ctx_rtype, (void**)&ctx) - || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { - return enif_make_badarg(env); - } - new_ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx)); - new_ctx->ctx = EVP_CIPHER_CTX_new(); - EVP_CIPHER_CTX_copy(new_ctx->ctx, ctx->ctx); - out = enif_make_new_binary(env, data_bin.size, &cipher_term); - EVP_CipherUpdate(new_ctx->ctx, out, &outl, data_bin.data, data_bin.size); - ASSERT(outl == data_bin.size); - - ret = enif_make_tuple2(env, enif_make_resource(env, new_ctx), cipher_term); - enif_release_resource(new_ctx); - CONSUME_REDS(env,data_bin); - return ret; -#else - return enif_raise_exception(env, atom_notsup); -#endif -}; - - -static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Bytes) */ - unsigned bytes; - unsigned char* data; - ERL_NIF_TERM ret; - - if (!enif_get_uint(env, argv[0], &bytes)) { - return enif_make_badarg(env); - } - data = enif_make_new_binary(env, bytes, &ret); - if ( RAND_bytes(data, bytes) != 1) { - return atom_false; - } - ERL_VALGRIND_MAKE_MEM_DEFINED(data, bytes); - return ret; -} - - -static int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp) -{ - ErlNifBinary bin; - int sz; - if (!enif_inspect_binary(env,term,&bin)) { - return 0; - } - ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size); - sz = bin.size - 4; - if (sz < 0 || get_int32(bin.data) != sz) { - return 0; - } - *bnp = BN_bin2bn(bin.data+4, sz, NULL); - return 1; -} - -static int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp) -{ - ErlNifBinary bin; - if (!enif_inspect_binary(env,term,&bin)) { - return 0; - } - ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size); - *bnp = BN_bin2bn(bin.data, bin.size, NULL); - 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 strong_rand_range_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Range) */ - BIGNUM *bn_range, *bn_rand; - ERL_NIF_TERM ret; - - if(!get_bn_from_bin(env, argv[0], &bn_range)) { - return enif_make_badarg(env); - } - - bn_rand = BN_new(); - if (BN_rand_range(bn_rand, bn_range) != 1) { - ret = atom_false; - } - else { - ret = bin_from_bn(env, bn_rand); - } - BN_free(bn_rand); - BN_free(bn_range); - return ret; -} - -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; - unsigned char* data; - unsigned dlen; - ERL_NIF_TERM ret; - - if (!get_bn_from_mpint(env, argv[0], &bn_from) - || !get_bn_from_mpint(env, argv[1], &bn_rand)) { - if (bn_from) BN_free(bn_from); - return enif_make_badarg(env); - } - - bn_to = BN_new(); - BN_sub(bn_to, bn_rand, bn_from); - BN_pseudo_rand_range(bn_rand, bn_to); - BN_add(bn_rand, bn_rand, bn_from); - dlen = BN_num_bytes(bn_rand); - data = enif_make_new_binary(env, dlen+4, &ret); - put_int32(data, dlen); - BN_bn2bin(bn_rand, data+4); - ERL_VALGRIND_MAKE_MEM_DEFINED(data+4, dlen); - BN_free(bn_rand); - BN_free(bn_from); - BN_free(bn_to); - return ret; -} - -static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Base,Exponent,Modulo,bin_hdr) */ - BIGNUM *bn_base=NULL, *bn_exponent=NULL, *bn_modulo=NULL, *bn_result; - BN_CTX *bn_ctx; - unsigned char* ptr; - unsigned dlen; - unsigned bin_hdr; /* return type: 0=plain binary, 4: mpint */ - unsigned extra_byte; - ERL_NIF_TERM ret; - - if (!get_bn_from_bin(env, argv[0], &bn_base) - || !get_bn_from_bin(env, argv[1], &bn_exponent) - || !get_bn_from_bin(env, argv[2], &bn_modulo) - || !enif_get_uint(env,argv[3],&bin_hdr) || (bin_hdr & ~4)) { - - if (bn_base) BN_free(bn_base); - if (bn_exponent) BN_free(bn_exponent); - if (bn_modulo) BN_free(bn_modulo); - return enif_make_badarg(env); - } - bn_result = BN_new(); - bn_ctx = BN_CTX_new(); - BN_mod_exp(bn_result, bn_base, bn_exponent, bn_modulo, bn_ctx); - dlen = BN_num_bytes(bn_result); - extra_byte = bin_hdr && BN_is_bit_set(bn_result, dlen*8-1); - ptr = enif_make_new_binary(env, bin_hdr+extra_byte+dlen, &ret); - if (bin_hdr) { - put_int32(ptr, extra_byte+dlen); - ptr[4] = 0; /* extra zeroed byte to ensure a positive mpint */ - ptr += bin_hdr + extra_byte; - } - BN_bn2bin(bn_result, ptr); - BN_free(bn_result); - BN_CTX_free(bn_ctx); - BN_free(bn_modulo); - BN_free(bn_exponent); - BN_free(bn_base); - return ret; -} - -static void init_digest_types(ErlNifEnv* env) -{ - struct digest_type_t* p = digest_types; - - for (p = digest_types; p->type.str; p++) { - p->type.atom = enif_make_atom(env, p->type.str); - if (p->md.funcp) - p->md.p = p->md.funcp(); - } - p->type.atom = atom_false; /* end marker */ -} - -static void init_cipher_types(ErlNifEnv* env) -{ - struct cipher_type_t* p = cipher_types; - - for (p = cipher_types; p->type.str; p++) { - p->type.atom = enif_make_atom(env, p->type.str); - if (p->cipher.funcp) - p->cipher.p = p->cipher.funcp(); - } - p->type.atom = atom_false; /* end marker */ -} - -static struct digest_type_t* get_digest_type(ERL_NIF_TERM type) -{ - struct digest_type_t* p = NULL; - for (p = digest_types; p->type.atom != atom_false; p++) { - if (type == p->type.atom) { - return p; - } - } - return NULL; -} - -static struct cipher_type_t* get_cipher_type(ERL_NIF_TERM type, size_t key_len) -{ - struct cipher_type_t* p = NULL; - for (p = cipher_types; p->type.atom != atom_false; p++) { - if (type == p->type.atom && (!p->key_len || key_len == p->key_len)) { - return p; - } - } - return NULL; -} - - -static ERL_NIF_TERM do_exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Data1, Data2) */ - ErlNifBinary d1, d2; - unsigned char* ret_ptr; - int i; - ERL_NIF_TERM ret; - - if (!enif_inspect_iolist_as_binary(env,argv[0], &d1) - || !enif_inspect_iolist_as_binary(env,argv[1], &d2) - || d1.size != d2.size) { - return enif_make_badarg(env); - } - ret_ptr = enif_make_new_binary(env, d1.size, &ret); - - for (i=0; i<d1.size; i++) { - ret_ptr[i] = d1.data[i] ^ d2.data[i]; - } - CONSUME_REDS(env,d1); - return ret; -} - -static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Key) */ -#ifndef OPENSSL_NO_RC4 - ErlNifBinary key; - ERL_NIF_TERM ret; - - CHECK_NO_FIPS_MODE(); - - if (!enif_inspect_iolist_as_binary(env,argv[0], &key)) { - return enif_make_badarg(env); - } - RC4_set_key((RC4_KEY*)enif_make_new_binary(env, sizeof(RC4_KEY), &ret), - key.size, key.data); - return ret; -#else - return enif_raise_exception(env, atom_notsup); -#endif -} - -static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (State, Data) */ -#ifndef OPENSSL_NO_RC4 - ErlNifBinary state, data; - RC4_KEY* rc4_key; - ERL_NIF_TERM new_state, new_data; - - CHECK_NO_FIPS_MODE(); - - if (!enif_inspect_iolist_as_binary(env,argv[0], &state) - || state.size != sizeof(RC4_KEY) - || !enif_inspect_iolist_as_binary(env,argv[1], &data)) { - return enif_make_badarg(env); - } - rc4_key = (RC4_KEY*)enif_make_new_binary(env, sizeof(RC4_KEY), &new_state); - memcpy(rc4_key, state.data, sizeof(RC4_KEY)); - RC4(rc4_key, data.size, data.data, - enif_make_new_binary(env, data.size, &new_data)); - CONSUME_REDS(env,data); - return enif_make_tuple2(env,new_state,new_data); -#else - return enif_raise_exception(env, atom_notsup); -#endif -} - -static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa) -{ - /* key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C] */ - ERL_NIF_TERM head, tail; - BIGNUM *e, *n, *d; - BIGNUM *p, *q; - BIGNUM *dmp1, *dmq1, *iqmp; - - if (!enif_get_list_cell(env, key, &head, &tail) - || !get_bn_from_bin(env, head, &e) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &n) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &d)) { - return 0; - } - (void) RSA_set0_key(rsa, n, e, d); - if (enif_is_empty_list(env, tail)) { - return 1; - } - if (!enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &p) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &q) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &dmp1) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &dmq1) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &iqmp) - || !enif_is_empty_list(env, tail)) { - return 0; - } - (void) RSA_set0_factors(rsa, p, q); - (void) RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp); - return 1; -} - - -static int get_rsa_public_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa) -{ - /* key=[E,N] */ - ERL_NIF_TERM head, tail; - BIGNUM *e, *n; - - if (!enif_get_list_cell(env, key, &head, &tail) - || !get_bn_from_bin(env, head, &e) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &n) - || !enif_is_empty_list(env, tail)) { - return 0; - } - - (void) RSA_set0_key(rsa, n, e, NULL); - return 1; -} - -#ifdef HAVE_EDDSA - static int get_eddsa_key(ErlNifEnv* env, int public, ERL_NIF_TERM key, EVP_PKEY **pkey) -{ - /* key=[K] */ - ERL_NIF_TERM head, tail, tail2, algo; - ErlNifBinary bin; - int type; - - if (!enif_get_list_cell(env, key, &head, &tail) - || !enif_inspect_binary(env, head, &bin) - || !enif_get_list_cell(env, tail, &algo, &tail2) - || !enif_is_empty_list(env, tail2)) { - return 0; - } - if (algo == atom_ed25519) type = EVP_PKEY_ED25519; - else if (algo == atom_ed448) type = EVP_PKEY_ED448; - else - return 0; - - if (public) - *pkey = EVP_PKEY_new_raw_public_key(type, NULL, bin.data, bin.size); - else - *pkey = EVP_PKEY_new_raw_private_key(type, NULL, bin.data, bin.size); - - if (!pkey) - return 0; - return 1; -} -#endif - -static int get_dss_private_key(ErlNifEnv* env, ERL_NIF_TERM key, DSA *dsa) -{ - /* key=[P,Q,G,KEY] */ - ERL_NIF_TERM head, tail; - BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL; - BIGNUM *dummy_pub_key, *priv_key = NULL; - - if (!enif_get_list_cell(env, key, &head, &tail) - || !get_bn_from_bin(env, head, &dsa_p) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &dsa_q) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &dsa_g) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &priv_key) - || !enif_is_empty_list(env,tail)) { - if (dsa_p) BN_free(dsa_p); - if (dsa_q) BN_free(dsa_q); - if (dsa_g) BN_free(dsa_g); - if (priv_key) BN_free(priv_key); - return 0; - } - - /* Note: DSA_set0_key() does not allow setting only the - * private key, although DSA_sign() 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); - - DSA_set0_pqg(dsa, dsa_p, dsa_q, dsa_g); - DSA_set0_key(dsa, dummy_pub_key, priv_key); - return 1; -} - - -static int get_dss_public_key(ErlNifEnv* env, ERL_NIF_TERM key, DSA *dsa) -{ - /* key=[P, Q, G, Y] */ - ERL_NIF_TERM head, tail; - BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL; - - if (!enif_get_list_cell(env, key, &head, &tail) - || !get_bn_from_bin(env, head, &dsa_p) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &dsa_q) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &dsa_g) - || !enif_get_list_cell(env, tail, &head, &tail) - || !get_bn_from_bin(env, head, &dsa_y) - || !enif_is_empty_list(env,tail)) { - if (dsa_p) BN_free(dsa_p); - if (dsa_q) BN_free(dsa_q); - if (dsa_g) BN_free(dsa_g); - if (dsa_y) BN_free(dsa_y); - return 0; - } - - DSA_set0_pqg(dsa, dsa_p, dsa_q, dsa_g); - DSA_set0_key(dsa, dsa_y, NULL); - return 1; -} - -/* 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 atom_error; - } - - 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_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (PrivKey|undefined, DHParams=[P,G], Mpint, Len|0) */ - DH *dh_params = NULL; - int mpint; /* 0 or 4 */ - - { - 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); - } - } - } - -#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; - } - - 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; - } - - 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 - 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); - } -} - -static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (OthersPublicKey, MyPrivateKey, DHParams=[P,G]) */ - BIGNUM *other_pub_key = NULL, - *dh_p = NULL, - *dh_g = NULL; - DH *dh_priv = DH_new(); - - /* Check the arguments and get - my private key (dh_priv), - the peer's public key (other_pub_key), - the parameters p & q - */ - - { - 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); - } - } - { - 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); - return atom_error; - } - - if (size != ret_bin.size) enif_realloc_binary(&ret_bin, size); - return enif_make_binary(env, &ret_bin); - } -} - - -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; - BIGNUM *bn_exponent = NULL, *bn_generator = NULL, *bn_prime = NULL, *bn_multiplier = NULL, *bn_result; - BN_CTX *bn_ctx; - unsigned char* ptr; - unsigned dlen; - ERL_NIF_TERM ret; - - CHECK_NO_FIPS_MODE(); - - if (!get_bn_from_bin(env, argv[0], &bn_multiplier) - || !get_bn_from_bin(env, argv[1], &bn_verifier) - || !get_bn_from_bin(env, argv[2], &bn_generator) - || !get_bn_from_bin(env, argv[3], &bn_exponent) - || !get_bn_from_bin(env, argv[4], &bn_prime)) { - if (bn_multiplier) BN_free(bn_multiplier); - if (bn_verifier) BN_free(bn_verifier); - if (bn_generator) BN_free(bn_generator); - if (bn_exponent) BN_free(bn_exponent); - if (bn_prime) BN_free(bn_prime); - return enif_make_badarg(env); - } - - bn_result = BN_new(); - bn_ctx = BN_CTX_new(); - - /* B = k*v + g^b % N */ - - /* k * v */ - BN_mod_mul(bn_multiplier, bn_multiplier, bn_verifier, bn_prime, bn_ctx); - - /* g^b % N */ - BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx); - - /* k*v + g^b % N */ - BN_mod_add(bn_result, bn_result, bn_multiplier, bn_prime, bn_ctx); - - /* check that B % N != 0, reuse bn_multiplier */ - BN_nnmod(bn_multiplier, bn_result, bn_prime, bn_ctx); - if (BN_is_zero(bn_multiplier)) { - ret = atom_error; - } else { - dlen = BN_num_bytes(bn_result); - ptr = enif_make_new_binary(env, dlen, &ret); - BN_bn2bin(bn_result, ptr); - } - BN_free(bn_result); - BN_CTX_free(bn_ctx); - BN_free(bn_prime); - BN_free(bn_generator); - BN_free(bn_multiplier); - BN_free(bn_exponent); - BN_free(bn_verifier); - return ret; -} - -static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (a, u, B, Multiplier, Prime, Exponent, Generator) */ -/* - <premaster secret> = (B - (k * g^x)) ^ (a + (u * x)) % N -*/ - BIGNUM *bn_exponent = NULL, *bn_a = NULL; - BIGNUM *bn_u = NULL, *bn_multiplier = NULL, *bn_exp2, - *bn_base, *bn_prime = NULL, *bn_generator = NULL, - *bn_B = NULL, *bn_result; - BN_CTX *bn_ctx; - unsigned char* ptr; - unsigned dlen; - ERL_NIF_TERM ret; - - CHECK_NO_FIPS_MODE(); - - if (!get_bn_from_bin(env, argv[0], &bn_a) - || !get_bn_from_bin(env, argv[1], &bn_u) - || !get_bn_from_bin(env, argv[2], &bn_B) - || !get_bn_from_bin(env, argv[3], &bn_multiplier) - || !get_bn_from_bin(env, argv[4], &bn_generator) - || !get_bn_from_bin(env, argv[5], &bn_exponent) - || !get_bn_from_bin(env, argv[6], &bn_prime)) - { - if (bn_exponent) BN_free(bn_exponent); - if (bn_a) BN_free(bn_a); - if (bn_u) BN_free(bn_u); - if (bn_B) BN_free(bn_B); - if (bn_multiplier) BN_free(bn_multiplier); - if (bn_generator) BN_free(bn_generator); - if (bn_prime) BN_free(bn_prime); - return enif_make_badarg(env); - } - - bn_ctx = BN_CTX_new(); - bn_result = BN_new(); - - /* check that B % N != 0 */ - BN_nnmod(bn_result, bn_B, bn_prime, bn_ctx); - if (BN_is_zero(bn_result)) { - BN_free(bn_exponent); - BN_free(bn_a); - BN_free(bn_generator); - BN_free(bn_prime); - BN_free(bn_u); - BN_free(bn_B); - BN_CTX_free(bn_ctx); - - return atom_error; - } - - /* (B - (k * g^x)) */ - bn_base = BN_new(); - BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx); - BN_mod_mul(bn_result, bn_multiplier, bn_result, bn_prime, bn_ctx); - BN_mod_sub(bn_base, bn_B, bn_result, bn_prime, bn_ctx); - - /* a + (u * x) */ - bn_exp2 = BN_new(); - BN_mul(bn_result, bn_u, bn_exponent, bn_ctx); - BN_add(bn_exp2, bn_a, bn_result); - - /* (B - (k * g^x)) ^ (a + (u * x)) % N */ - BN_mod_exp(bn_result, bn_base, bn_exp2, bn_prime, bn_ctx); - - dlen = BN_num_bytes(bn_result); - ptr = enif_make_new_binary(env, dlen, &ret); - BN_bn2bin(bn_result, ptr); - BN_free(bn_result); - BN_CTX_free(bn_ctx); - - BN_free(bn_multiplier); - BN_free(bn_exp2); - BN_free(bn_u); - BN_free(bn_exponent); - BN_free(bn_a); - BN_free(bn_B); - BN_free(bn_base); - BN_free(bn_generator); - BN_free(bn_prime); - return ret; -} - -static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Verifier, b, u, A, Prime) */ -/* - <premaster secret> = (A * v^u) ^ b % N -*/ - BIGNUM *bn_b = NULL, *bn_verifier = NULL; - BIGNUM *bn_prime = NULL, *bn_A = NULL, *bn_u = NULL, *bn_base, *bn_result; - BN_CTX *bn_ctx; - unsigned char* ptr; - unsigned dlen; - ERL_NIF_TERM ret; - - CHECK_NO_FIPS_MODE(); - - if (!get_bn_from_bin(env, argv[0], &bn_verifier) - || !get_bn_from_bin(env, argv[1], &bn_b) - || !get_bn_from_bin(env, argv[2], &bn_u) - || !get_bn_from_bin(env, argv[3], &bn_A) - || !get_bn_from_bin(env, argv[4], &bn_prime)) - { - if (bn_verifier) BN_free(bn_verifier); - if (bn_b) BN_free(bn_b); - if (bn_u) BN_free(bn_u); - if (bn_A) BN_free(bn_A); - if (bn_prime) BN_free(bn_prime); - return enif_make_badarg(env); - } - - bn_ctx = BN_CTX_new(); - bn_result = BN_new(); - - /* check that A % N != 0 */ - BN_nnmod(bn_result, bn_A, bn_prime, bn_ctx); - if (BN_is_zero(bn_result)) { - BN_free(bn_b); - BN_free(bn_verifier); - BN_free(bn_prime); - BN_free(bn_A); - BN_CTX_free(bn_ctx); - - return atom_error; - } - - /* (A * v^u) */ - bn_base = BN_new(); - BN_mod_exp(bn_base, bn_verifier, bn_u, bn_prime, bn_ctx); - BN_mod_mul(bn_base, bn_A, bn_base, bn_prime, bn_ctx); - - /* (A * v^u) ^ b % N */ - BN_mod_exp(bn_result, bn_base, bn_b, bn_prime, bn_ctx); - - dlen = BN_num_bytes(bn_result); - ptr = enif_make_new_binary(env, dlen, &ret); - BN_bn2bin(bn_result, ptr); - BN_free(bn_result); - BN_CTX_free(bn_ctx); - - BN_free(bn_u); - BN_free(bn_base); - BN_free(bn_verifier); - BN_free(bn_prime); - BN_free(bn_A); - BN_free(bn_b); - return ret; -} - -#if defined(HAVE_EC) -static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg) -{ - EC_KEY *key = NULL; - int c_arity = -1; - const ERL_NIF_TERM* curve; - ErlNifBinary seed; - BIGNUM *p = NULL; - BIGNUM *a = NULL; - BIGNUM *b = NULL; - BIGNUM *bn_order = NULL; - BIGNUM *cofactor = NULL; - EC_GROUP *group = NULL; - EC_POINT *point = NULL; - - /* {Field, Prime, Point, Order, CoFactor} = Curve */ - if (enif_get_tuple(env,curve_arg,&c_arity,&curve) - && c_arity == 5 - && get_bn_from_bin(env, curve[3], &bn_order) - && (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) { - - int f_arity = -1; - const ERL_NIF_TERM* field; - int p_arity = -1; - const ERL_NIF_TERM* prime; - - long field_bits; - - /* {A, B, Seed} = Prime */ - if (!enif_get_tuple(env,curve[1],&p_arity,&prime) - || !get_bn_from_bin(env, prime[0], &a) - || !get_bn_from_bin(env, prime[1], &b)) - goto out_err; - - if (!enif_get_tuple(env,curve[0],&f_arity,&field)) - goto out_err; - - if (f_arity == 2 && field[0] == atom_prime_field) { - /* {prime_field, Prime} */ - - if (!get_bn_from_bin(env, field[1], &p)) - goto out_err; - - if (BN_is_negative(p) || BN_is_zero(p)) - goto out_err; - - field_bits = BN_num_bits(p); - if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS) - goto out_err; - - /* create the EC_GROUP structure */ - group = EC_GROUP_new_curve_GFp(p, a, b, NULL); - - } else if (f_arity == 3 && field[0] == atom_characteristic_two_field) { -#if defined(OPENSSL_NO_EC2M) - enif_raise_exception(env, atom_notsup); - goto out_err; -#else - /* {characteristic_two_field, M, Basis} */ - - int b_arity = -1; - const ERL_NIF_TERM* basis; - unsigned int k1, k2, k3; - - if ((p = BN_new()) == NULL) - goto out_err; - - if (!enif_get_long(env, field[1], &field_bits) - || field_bits > OPENSSL_ECC_MAX_FIELD_BITS) - goto out_err; - - if (enif_get_tuple(env,field[2],&b_arity,&basis)) { - if (b_arity == 2 - && basis[0] == atom_tpbasis - && enif_get_uint(env, basis[1], &k1)) { - /* {tpbasis, k} = Basis */ - - if (!(field_bits > k1 && k1 > 0)) - goto out_err; - - /* create the polynomial */ - if (!BN_set_bit(p, (int)field_bits) - || !BN_set_bit(p, (int)k1) - || !BN_set_bit(p, 0)) - goto out_err; - - } else if (b_arity == 4 - && basis[0] == atom_ppbasis - && enif_get_uint(env, basis[1], &k1) - && enif_get_uint(env, basis[2], &k2) - && enif_get_uint(env, basis[3], &k3)) { - /* {ppbasis, k1, k2, k3} = Basis */ - - if (!(field_bits > k3 && k3 > k2 && k2 > k1 && k1 > 0)) - goto out_err; - - /* create the polynomial */ - if (!BN_set_bit(p, (int)field_bits) - || !BN_set_bit(p, (int)k1) - || !BN_set_bit(p, (int)k2) - || !BN_set_bit(p, (int)k3) - || !BN_set_bit(p, 0)) - goto out_err; - - } else - goto out_err; - } else if (field[2] == atom_onbasis) { - /* onbasis = Basis */ - /* no parameters */ - goto out_err; - - } else - goto out_err; - - group = EC_GROUP_new_curve_GF2m(p, a, b, NULL); -#endif - } else - goto out_err; - - if (!group) - goto out_err; - - if (enif_inspect_binary(env, prime[2], &seed)) { - EC_GROUP_set_seed(group, seed.data, seed.size); - } - - if (!term2point(env, curve[2], group, &point)) - goto out_err; - - if (BN_is_negative(bn_order) - || BN_is_zero(bn_order) - || BN_num_bits(bn_order) > (int)field_bits + 1) - goto out_err; - - if (!EC_GROUP_set_generator(group, point, bn_order, cofactor)) - goto out_err; - - EC_GROUP_set_asn1_flag(group, 0x0); - - key = EC_KEY_new(); - if (!key) - goto out_err; - EC_KEY_set_group(key, group); - } - else { - goto out_err; - } - - - goto out; - -out_err: - if (key) EC_KEY_free(key); - key = NULL; - -out: - /* some OpenSSL structures are mem-dup'ed into the key, - so we have to free our copies here */ - if (p) BN_free(p); - if (a) BN_free(a); - if (b) BN_free(b); - if (bn_order) BN_free(bn_order); - if (cofactor) BN_free(cofactor); - if (group) EC_GROUP_free(group); - if (point) EC_POINT_free(point); - - return key; -} - - -static ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn) -{ - unsigned dlen; - unsigned char* ptr; - ERL_NIF_TERM ret; - - if (!bn) - return atom_undefined; - - dlen = BN_num_bytes(bn); - ptr = enif_make_new_binary(env, dlen, &ret); - BN_bn2bin(bn, ptr); - ERL_VALGRIND_MAKE_MEM_DEFINED(ptr, dlen); - return ret; -} - -static ERL_NIF_TERM point2term(ErlNifEnv* env, - const EC_GROUP *group, - const EC_POINT *point, - point_conversion_form_t form) -{ - unsigned dlen; - ErlNifBinary bin; - - dlen = EC_POINT_point2oct(group, point, form, NULL, 0, NULL); - if (dlen == 0) - return atom_undefined; - - if (!enif_alloc_binary(dlen, &bin)) - return enif_make_badarg(env); - - if (!EC_POINT_point2oct(group, point, form, bin.data, bin.size, NULL)) { - enif_release_binary(&bin); - return enif_make_badarg(env); - } - ERL_VALGRIND_MAKE_MEM_DEFINED(bin.data, bin.size); - return enif_make_binary(env, &bin); -} - -static int term2point(ErlNifEnv* env, ERL_NIF_TERM term, - EC_GROUP *group, EC_POINT **pptr) -{ - int ret = 0; - ErlNifBinary bin; - EC_POINT *point; - - if (!enif_inspect_binary(env,term,&bin)) { - return 0; - } - - if ((*pptr = point = EC_POINT_new(group)) == NULL) { - return 0; - } - - /* 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)) { - EC_POINT_free(point); - *pptr = NULL; - } else - ret = 1; - - return ret; -} - -static int get_ec_key(ErlNifEnv* env, - ERL_NIF_TERM curve, ERL_NIF_TERM priv, ERL_NIF_TERM pub, - EC_KEY** res) -{ - EC_KEY *key = NULL; - BIGNUM *priv_key = NULL; - EC_POINT *pub_key = NULL; - EC_GROUP *group = NULL; - - if (!(priv == atom_undefined || get_bn_from_bin(env, priv, &priv_key)) - || !(pub == atom_undefined || enif_is_binary(env, pub))) { - goto out_err; - } - - key = ec_key_new(env, curve); - - if (!key) { - goto out_err; - } - - if (!group) - group = EC_GROUP_dup(EC_KEY_get0_group(key)); - - if (term2point(env, pub, group, &pub_key)) { - if (!EC_KEY_set_public_key(key, pub_key)) { - goto out_err; - } - } - if (priv != atom_undefined - && !BN_is_zero(priv_key)) { - if (!EC_KEY_set_private_key(key, priv_key)) - goto out_err; - - /* calculate public key (if necessary) */ - if (EC_KEY_get0_public_key(key) == NULL) - { - /* the public key was not included in the SEC1 private - * key => calculate the public key */ - pub_key = EC_POINT_new(group); - if (pub_key == NULL - || !EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group)) - || !EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL) - || !EC_KEY_set_public_key(key, pub_key)) - goto out_err; - } - } - - goto out; - -out_err: - if (key) EC_KEY_free(key); - key = NULL; - -out: - /* some OpenSSL structures are mem-dup'ed into the key, - so we have to free our copies here */ - if (priv_key) BN_clear_free(priv_key); - if (pub_key) EC_POINT_free(pub_key); - if (group) EC_GROUP_free(group); - if (!key) - return 0; - *res = key; - return 1; -} -#endif /* HAVE_EC */ - -static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ -#if defined(HAVE_EC) - EC_KEY *key = NULL; - const EC_GROUP *group; - const EC_POINT *public_key; - ERL_NIF_TERM priv_key; - ERL_NIF_TERM pub_key = atom_undefined; - - if (!get_ec_key(env, argv[0], argv[1], atom_undefined, &key)) - goto badarg; - - if (argv[1] == atom_undefined) { - if (!EC_KEY_generate_key(key)) - goto badarg; - } - - group = EC_KEY_get0_group(key); - public_key = EC_KEY_get0_public_key(key); - - if (group && public_key) { - pub_key = point2term(env, group, public_key, - EC_KEY_get_conv_form(key)); - } - priv_key = bn2term(env, EC_KEY_get0_private_key(key)); - EC_KEY_free(key); - return enif_make_tuple2(env, pub_key, priv_key); - -badarg: - if (key) - EC_KEY_free(key); - return make_badarg_maybe(env); -#else - return atom_notsup; -#endif -} - -/* - (_OthersPublicKey, _MyPrivateKey) - (_OthersPublicKey, _MyEC_Point) -*/ -static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -/* (OtherPublicKey, Curve, My) */ -{ -#if defined(HAVE_EC) - ERL_NIF_TERM ret; - unsigned char *p; - EC_KEY* key = NULL; - int field_size = 0; - int i; - EC_GROUP *group; - const BIGNUM *priv_key; - EC_POINT *my_ecpoint = NULL; - EC_KEY *other_ecdh = NULL; - - if (!get_ec_key(env, argv[1], argv[2], atom_undefined, &key)) - return make_badarg_maybe(env); - - group = EC_GROUP_dup(EC_KEY_get0_group(key)); - priv_key = EC_KEY_get0_private_key(key); - - if (!term2point(env, argv[0], group, &my_ecpoint)) { - goto out_err; - } - - if ((other_ecdh = EC_KEY_new()) == NULL - || !EC_KEY_set_group(other_ecdh, group) - || !EC_KEY_set_private_key(other_ecdh, priv_key)) - goto out_err; - - field_size = EC_GROUP_get_degree(group); - if (field_size <= 0) - goto out_err; - - p = enif_make_new_binary(env, (field_size+7)/8, &ret); - i = ECDH_compute_key(p, (field_size+7)/8, my_ecpoint, other_ecdh, NULL); - - if (i < 0) - goto out_err; -out: - if (group) EC_GROUP_free(group); - if (my_ecpoint) EC_POINT_free(my_ecpoint); - if (other_ecdh) EC_KEY_free(other_ecdh); - if (key) EC_KEY_free(key); - - return ret; - -out_err: - ret = enif_make_badarg(env); - goto out; -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM evp_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) - /* (Curve, PeerBin, MyBin) */ -{ -#ifdef HAVE_ED_CURVE_DH - int type; - EVP_PKEY_CTX *ctx = NULL; - ErlNifBinary peer_bin, my_bin, key_bin; - EVP_PKEY *peer_key = NULL, *my_key = NULL; - 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)) - goto return_badarg; - - 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))) - goto return_badarg; - - if (!EVP_PKEY_derive_init(ctx)) - goto return_badarg; - - 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)) - goto return_badarg; - - if (!EVP_PKEY_derive(ctx, NULL, &max_size)) - goto return_badarg; - - if (!enif_alloc_binary(max_size, &key_bin) || - !EVP_PKEY_derive(ctx, key_bin.data, &key_bin.size)) - goto return_badarg; - - if (key_bin.size < max_size) { - size_t actual_size = key_bin.size; - if (!enif_realloc_binary(&key_bin, actual_size)) - goto return_badarg; - } - - EVP_PKEY_free(my_key); - EVP_PKEY_free(peer_key); - EVP_PKEY_CTX_free(ctx); - return enif_make_binary(env, &key_bin); - -return_badarg: - if (my_key) EVP_PKEY_free(my_key); - if (peer_key) EVP_PKEY_free(peer_key); - if (ctx) EVP_PKEY_CTX_free(ctx); - return enif_make_badarg(env); -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -/* (Curve) */ -{ -#ifdef HAVE_ED_CURVE_DH - int type; - EVP_PKEY_CTX *ctx = NULL; - 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)) goto return_error; - if (!EVP_PKEY_keygen(ctx, &pkey)) goto return_error; - - if (!EVP_PKEY_get_raw_public_key(pkey, NULL, &key_len)) goto return_error; - if (!EVP_PKEY_get_raw_public_key(pkey, - enif_make_new_binary(env, key_len, &ret_pub), - &key_len)) - goto return_error; - - if (!EVP_PKEY_get_raw_private_key(pkey, NULL, &key_len)) goto return_error; - if (!EVP_PKEY_get_raw_private_key(pkey, - enif_make_new_binary(env, key_len, &ret_prv), - &key_len)) - goto return_error; - - EVP_PKEY_free(pkey); - EVP_PKEY_CTX_free(ctx); - return enif_make_tuple2(env, ret_pub, ret_prv); - -return_error: - if (pkey) EVP_PKEY_free(pkey); - if (ctx) EVP_PKEY_CTX_free(ctx); - return atom_error; - -#else - return atom_notsup; -#endif -} - -/*================================================================*/ -#define PKEY_BADARG -1 -#define PKEY_NOTSUP 0 -#define PKEY_OK 1 - -typedef struct PKeyCryptOptions { - const EVP_MD *rsa_mgf1_md; - ErlNifBinary rsa_oaep_label; - const EVP_MD *rsa_oaep_md; - int rsa_padding; - const EVP_MD *signature_md; -} PKeyCryptOptions; - -typedef struct PKeySignOptions { - const EVP_MD *rsa_mgf1_md; - int rsa_padding; - int rsa_pss_saltlen; -} PKeySignOptions; - -static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM type, - const EVP_MD **md) -{ - struct digest_type_t *digp = NULL; - *md = NULL; - - if (type == atom_none && algorithm == atom_rsa) return PKEY_OK; - if (algorithm == atom_eddsa) -#ifdef HAVE_EDDSA - return PKEY_OK; -#else - return PKEY_NOTSUP; -#endif - digp = get_digest_type(type); - if (!digp) return PKEY_BADARG; - if (!digp->md.p) return PKEY_NOTSUP; - - *md = digp->md.p; - return PKEY_OK; -} - - -static int get_pkey_sign_digest(ErlNifEnv *env, ERL_NIF_TERM algorithm, - ERL_NIF_TERM type, ERL_NIF_TERM data, - unsigned char *md_value, const EVP_MD **mdp, - unsigned char **tbsp, size_t *tbslenp) -{ - int i; - const ERL_NIF_TERM *tpl_terms; - int tpl_arity; - ErlNifBinary tbs_bin; - EVP_MD_CTX *mdctx; - const EVP_MD *md = *mdp; - unsigned char *tbs = *tbsp; - size_t tbslen = *tbslenp; - unsigned int tbsleni; - - if ((i = get_pkey_digest_type(env, algorithm, type, &md)) != PKEY_OK) { - return i; - } - if (enif_get_tuple(env, data, &tpl_arity, &tpl_terms)) { - if (tpl_arity != 2 || tpl_terms[0] != atom_digest - || !enif_inspect_binary(env, tpl_terms[1], &tbs_bin) - || (md != NULL && tbs_bin.size != EVP_MD_size(md))) { - return PKEY_BADARG; - } - /* We have a digest (= hashed text) in tbs_bin */ - tbs = tbs_bin.data; - tbslen = tbs_bin.size; - } else if (md == NULL) { - if (!enif_inspect_binary(env, data, &tbs_bin)) { - return PKEY_BADARG; - } - /* md == NULL, that is no hashing because DigestType argument was atom_none */ - tbs = tbs_bin.data; - tbslen = tbs_bin.size; - } else { - if (!enif_inspect_binary(env, data, &tbs_bin)) { - return PKEY_BADARG; - } - /* We have the cleartext in tbs_bin and the hash algo info in md */ - tbs = md_value; - mdctx = EVP_MD_CTX_create(); - if (!mdctx) { - return PKEY_BADARG; - } - /* Looks well, now hash the plain text into a digest according to md */ - if (EVP_DigestInit_ex(mdctx, md, NULL) <= 0) { - EVP_MD_CTX_destroy(mdctx); - return PKEY_BADARG; - } - if (EVP_DigestUpdate(mdctx, tbs_bin.data, tbs_bin.size) <= 0) { - EVP_MD_CTX_destroy(mdctx); - return PKEY_BADARG; - } - if (EVP_DigestFinal_ex(mdctx, tbs, &tbsleni) <= 0) { - EVP_MD_CTX_destroy(mdctx); - return PKEY_BADARG; - } - tbslen = (size_t)(tbsleni); - EVP_MD_CTX_destroy(mdctx); - } - - *mdp = md; - *tbsp = tbs; - *tbslenp = tbslen; - - return PKEY_OK; -} - - -static int get_pkey_sign_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options, - const EVP_MD *md, PKeySignOptions *opt) -{ - ERL_NIF_TERM head, tail; - const ERL_NIF_TERM *tpl_terms; - int tpl_arity; - const EVP_MD *opt_md; - int i; - - if (!enif_is_list(env, options)) { - return PKEY_BADARG; - } - - /* defaults */ - if (algorithm == atom_rsa) { - opt->rsa_mgf1_md = NULL; - opt->rsa_padding = RSA_PKCS1_PADDING; - opt->rsa_pss_saltlen = -2; - } - - if (enif_is_empty_list(env, options)) { - return PKEY_OK; - } - - if (algorithm == atom_rsa) { - tail = options; - while (enif_get_list_cell(env, tail, &head, &tail)) { - if (enif_get_tuple(env, head, &tpl_arity, &tpl_terms) && tpl_arity == 2) { - if (tpl_terms[0] == atom_rsa_mgf1_md && enif_is_atom(env, tpl_terms[1])) { - i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md); - if (i != PKEY_OK) { - return i; - } - opt->rsa_mgf1_md = opt_md; - } else if (tpl_terms[0] == atom_rsa_padding) { - if (tpl_terms[1] == atom_rsa_pkcs1_padding) { - opt->rsa_padding = RSA_PKCS1_PADDING; - } else if (tpl_terms[1] == atom_rsa_pkcs1_pss_padding) { -#ifdef HAVE_RSA_PKCS1_PSS_PADDING - opt->rsa_padding = RSA_PKCS1_PSS_PADDING; - if (opt->rsa_mgf1_md == NULL) { - opt->rsa_mgf1_md = md; - } -#else - return PKEY_NOTSUP; -#endif - } else if (tpl_terms[1] == atom_rsa_x931_padding) { - opt->rsa_padding = RSA_X931_PADDING; - } else if (tpl_terms[1] == atom_rsa_no_padding) { - opt->rsa_padding = RSA_NO_PADDING; - } else { - return PKEY_BADARG; - } - } else if (tpl_terms[0] == atom_rsa_pss_saltlen) { - if (!enif_get_int(env, tpl_terms[1], &(opt->rsa_pss_saltlen)) - || opt->rsa_pss_saltlen < -2) { - return PKEY_BADARG; - } - } else { - return PKEY_BADARG; - } - } else { - return PKEY_BADARG; - } - } - } else { - return PKEY_BADARG; - } - - return PKEY_OK; -} - - -#ifdef HAS_ENGINE_SUPPORT -static int get_engine_and_key_id(ErlNifEnv *env, ERL_NIF_TERM key, char ** id, ENGINE **e) -{ - ERL_NIF_TERM engine_res, key_id_term; - struct engine_ctx *ctx; - ErlNifBinary key_id_bin; - - if (!enif_get_map_value(env, key, atom_engine, &engine_res) || - !enif_get_resource(env, engine_res, engine_ctx_rtype, (void**)&ctx) || - !enif_get_map_value(env, key, atom_key_id, &key_id_term) || - !enif_inspect_binary(env, key_id_term, &key_id_bin)) { - return 0; - } - else { - *e = ctx->engine; - return zero_terminate(key_id_bin, id); - } -} - - -static char *get_key_password(ErlNifEnv *env, ERL_NIF_TERM key) { - ERL_NIF_TERM tmp_term; - ErlNifBinary pwd_bin; - char *pwd = NULL; - if (enif_get_map_value(env, key, atom_password, &tmp_term) && - enif_inspect_binary(env, tmp_term, &pwd_bin) && - zero_terminate(pwd_bin, &pwd) - ) return pwd; - - return NULL; -} - -static int zero_terminate(ErlNifBinary bin, char **buf) { - *buf = enif_alloc(bin.size+1); - if (!*buf) - return 0; - memcpy(*buf, bin.data, bin.size); - *(*buf+bin.size) = 0; - return 1; -} -#endif - -static int get_pkey_private_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key, EVP_PKEY **pkey) -{ - if (enif_is_map(env, key)) { -#ifdef HAS_ENGINE_SUPPORT - /* Use key stored in engine */ - ENGINE *e; - char *id = NULL; - char *password; - - if (!get_engine_and_key_id(env, key, &id, &e)) - return PKEY_BADARG; - password = get_key_password(env, key); - *pkey = ENGINE_load_private_key(e, id, NULL, password); - if (password) enif_free(password); - enif_free(id); - if (!*pkey) - return PKEY_BADARG; -#else - return PKEY_BADARG; -#endif - } - else if (algorithm == atom_rsa) { - RSA *rsa = RSA_new(); - - if (!get_rsa_private_key(env, key, rsa)) { - RSA_free(rsa); - return PKEY_BADARG; - } - - *pkey = EVP_PKEY_new(); - if (!EVP_PKEY_assign_RSA(*pkey, rsa)) { - EVP_PKEY_free(*pkey); - RSA_free(rsa); - return PKEY_BADARG; - } - } else if (algorithm == atom_ecdsa) { -#if defined(HAVE_EC) - EC_KEY *ec = NULL; - 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]) - && get_ec_key(env, tpl_terms[0], tpl_terms[1], atom_undefined, &ec)) { - - *pkey = EVP_PKEY_new(); - if (!EVP_PKEY_assign_EC_KEY(*pkey, ec)) { - EVP_PKEY_free(*pkey); - EC_KEY_free(ec); - return PKEY_BADARG; - } - } else { - return PKEY_BADARG; - } -#else - return PKEY_NOTSUP; -#endif - } else if (algorithm == atom_eddsa) { -#if defined(HAVE_EDDSA) - if (!get_eddsa_key(env, 0, key, pkey)) { - return PKEY_BADARG; - } -#else - return PKEY_NOTSUP; -#endif - } else if (algorithm == atom_dss) { - DSA *dsa = DSA_new(); - - if (!get_dss_private_key(env, key, dsa)) { - DSA_free(dsa); - return PKEY_BADARG; - } - - *pkey = EVP_PKEY_new(); - if (!EVP_PKEY_assign_DSA(*pkey, dsa)) { - EVP_PKEY_free(*pkey); - DSA_free(dsa); - return PKEY_BADARG; - } - } else { - return PKEY_BADARG; - } - - return PKEY_OK; -} - - -static int get_pkey_public_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key, - EVP_PKEY **pkey) -{ - if (enif_is_map(env, key)) { -#ifdef HAS_ENGINE_SUPPORT - /* Use key stored in engine */ - ENGINE *e; - char *id = NULL; - char *password; - - if (!get_engine_and_key_id(env, key, &id, &e)) - return PKEY_BADARG; - password = get_key_password(env, key); - *pkey = ENGINE_load_public_key(e, id, NULL, password); - if (password) enif_free(password); - enif_free(id); - if (!pkey) - return PKEY_BADARG; -#else - return PKEY_BADARG; -#endif - } else if (algorithm == atom_rsa) { - RSA *rsa = RSA_new(); - - if (!get_rsa_public_key(env, key, rsa)) { - RSA_free(rsa); - return PKEY_BADARG; - } - - *pkey = EVP_PKEY_new(); - if (!EVP_PKEY_assign_RSA(*pkey, rsa)) { - EVP_PKEY_free(*pkey); - RSA_free(rsa); - return PKEY_BADARG; - } - } else if (algorithm == atom_ecdsa) { -#if defined(HAVE_EC) - EC_KEY *ec = NULL; - 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]) - && get_ec_key(env, tpl_terms[0], atom_undefined, tpl_terms[1], &ec)) { - - *pkey = EVP_PKEY_new(); - if (!EVP_PKEY_assign_EC_KEY(*pkey, ec)) { - EVP_PKEY_free(*pkey); - EC_KEY_free(ec); - return PKEY_BADARG; - } - } else { - return PKEY_BADARG; - } -#else - return PKEY_NOTSUP; -#endif - } else if (algorithm == atom_eddsa) { -#if defined(HAVE_EDDSA) - if (!get_eddsa_key(env, 1, key, pkey)) { - return PKEY_BADARG; - } -#else - return PKEY_NOTSUP; -#endif - } else if (algorithm == atom_dss) { - DSA *dsa = DSA_new(); - - if (!get_dss_public_key(env, key, dsa)) { - DSA_free(dsa); - return PKEY_BADARG; - } - - *pkey = EVP_PKEY_new(); - if (!EVP_PKEY_assign_DSA(*pkey, dsa)) { - EVP_PKEY_free(*pkey); - DSA_free(dsa); - return PKEY_BADARG; - } - } else { - return PKEY_BADARG; - } - - return PKEY_OK; -} - -static ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) -{/* (Algorithm, Type, Data|{digest,Digest}, Key|#{}, Options) */ - int i; - const EVP_MD *md = NULL; - unsigned char md_value[EVP_MAX_MD_SIZE]; - EVP_PKEY *pkey; -#ifdef HAS_EVP_PKEY_CTX - EVP_PKEY_CTX *ctx; - size_t siglen; -#else - unsigned len, siglen; -#endif - PKeySignOptions sig_opt; - ErlNifBinary sig_bin; /* signature */ - unsigned char *tbs; /* data to be signed */ - size_t tbslen; -/*char buf[1024]; -enif_get_atom(env,argv[0],buf,1024,ERL_NIF_LATIN1); printf("algo=%s ",buf); -enif_get_atom(env,argv[1],buf,1024,ERL_NIF_LATIN1); printf("hash=%s ",buf); -printf("\r\n"); -*/ - -#ifndef HAS_ENGINE_SUPPORT - if (enif_is_map(env, argv[3])) { - return atom_notsup; - } -#endif - - i = get_pkey_sign_digest(env, argv[0], argv[1], argv[2], md_value, &md, &tbs, &tbslen); - if (i != PKEY_OK) { - if (i == PKEY_NOTSUP) - return atom_notsup; - else - return enif_make_badarg(env); - } - - i = get_pkey_sign_options(env, argv[0], argv[4], md, &sig_opt); - if (i != PKEY_OK) { - if (i == PKEY_NOTSUP) - return atom_notsup; - else - return enif_make_badarg(env); - } - - if (get_pkey_private_key(env, argv[0], argv[3], &pkey) != PKEY_OK) { - return enif_make_badarg(env); - } - -#ifdef HAS_EVP_PKEY_CTX - ctx = EVP_PKEY_CTX_new(pkey, NULL); - if (!ctx) goto badarg; - - if (argv[0] != atom_eddsa) { - if (EVP_PKEY_sign_init(ctx) <= 0) goto badarg; - if (md != NULL && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) goto badarg; - } - - if (argv[0] == atom_rsa) { - if (EVP_PKEY_CTX_set_rsa_padding(ctx, sig_opt.rsa_padding) <= 0) goto badarg; -# ifdef HAVE_RSA_PKCS1_PSS_PADDING - if (sig_opt.rsa_padding == RSA_PKCS1_PSS_PADDING) { - if (sig_opt.rsa_mgf1_md != NULL) { -# ifdef HAVE_RSA_MGF1_MD - if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, sig_opt.rsa_mgf1_md) <= 0) goto badarg; -# else - EVP_PKEY_CTX_free(ctx); - EVP_PKEY_free(pkey); - return atom_notsup; -# endif - } - if (sig_opt.rsa_pss_saltlen > -2 - && EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sig_opt.rsa_pss_saltlen) <= 0) - goto badarg; - } -#endif - } - - if (argv[0] == atom_eddsa) { -#ifdef HAVE_EDDSA - EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); - if (!EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey)) { - if (mdctx) EVP_MD_CTX_free(mdctx); - goto badarg; - } - - if (!EVP_DigestSign(mdctx, NULL, &siglen, tbs, tbslen)) { - EVP_MD_CTX_free(mdctx); - goto badarg; - } - enif_alloc_binary(siglen, &sig_bin); - - if (!EVP_DigestSign(mdctx, sig_bin.data, &siglen, tbs, tbslen)) { - EVP_MD_CTX_free(mdctx); - goto badarg; - } - EVP_MD_CTX_free(mdctx); -#else - goto badarg; -#endif - } - else - { - if (EVP_PKEY_sign(ctx, NULL, &siglen, tbs, tbslen) <= 0) goto badarg; - enif_alloc_binary(siglen, &sig_bin); - - if (md != NULL) { - ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md)); - } - i = EVP_PKEY_sign(ctx, sig_bin.data, &siglen, tbs, tbslen); - } - - EVP_PKEY_CTX_free(ctx); -#else -/*printf("Old interface\r\n"); - */ - if (argv[0] == atom_rsa) { - RSA *rsa = EVP_PKEY_get1_RSA(pkey); - enif_alloc_binary(RSA_size(rsa), &sig_bin); - len = EVP_MD_size(md); - ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len); - i = RSA_sign(md->type, tbs, len, sig_bin.data, &siglen, rsa); - RSA_free(rsa); - } else if (argv[0] == atom_dss) { - DSA *dsa = EVP_PKEY_get1_DSA(pkey); - enif_alloc_binary(DSA_size(dsa), &sig_bin); - len = EVP_MD_size(md); - ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len); - i = DSA_sign(md->type, tbs, len, sig_bin.data, &siglen, dsa); - DSA_free(dsa); - } else if (argv[0] == atom_ecdsa) { -#if defined(HAVE_EC) - EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey); - enif_alloc_binary(ECDSA_size(ec), &sig_bin); - len = EVP_MD_size(md); - ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len); - i = ECDSA_sign(md->type, tbs, len, sig_bin.data, &siglen, ec); - EC_KEY_free(ec); -#else - EVP_PKEY_free(pkey); - return atom_notsup; -#endif - } else { - goto badarg; - } -#endif - - EVP_PKEY_free(pkey); - if (i == 1) { - ERL_VALGRIND_MAKE_MEM_DEFINED(sig_bin.data, siglen); - if (siglen != sig_bin.size) { - enif_realloc_binary(&sig_bin, siglen); - ERL_VALGRIND_ASSERT_MEM_DEFINED(sig_bin.data, siglen); - } - return enif_make_binary(env, &sig_bin); - } else { - enif_release_binary(&sig_bin); - return atom_error; - } - - badarg: -#ifdef HAS_EVP_PKEY_CTX - EVP_PKEY_CTX_free(ctx); -#endif - EVP_PKEY_free(pkey); - return enif_make_badarg(env); -} - - -static ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) -{/* (Algorithm, Type, Data|{digest,Digest}, Signature, Key, Options) */ - int i; - const EVP_MD *md = NULL; - unsigned char md_value[EVP_MAX_MD_SIZE]; - EVP_PKEY *pkey; -#ifdef HAS_EVP_PKEY_CTX - EVP_PKEY_CTX *ctx; -#else -#endif - PKeySignOptions sig_opt; - ErlNifBinary sig_bin; /* signature */ - unsigned char *tbs; /* data to be signed */ - size_t tbslen; - -#ifndef HAS_ENGINE_SUPPORT - if (enif_is_map(env, argv[4])) { - return atom_notsup; - } -#endif - - if (!enif_inspect_binary(env, argv[3], &sig_bin)) { - return enif_make_badarg(env); - } - - i = get_pkey_sign_digest(env, argv[0], argv[1], argv[2], md_value, &md, &tbs, &tbslen); - if (i != PKEY_OK) { - if (i == PKEY_NOTSUP) - return atom_notsup; - else - return enif_make_badarg(env); - } - - i = get_pkey_sign_options(env, argv[0], argv[5], md, &sig_opt); - if (i != PKEY_OK) { - if (i == PKEY_NOTSUP) - return atom_notsup; - else - return enif_make_badarg(env); - } - - if (get_pkey_public_key(env, argv[0], argv[4], &pkey) != PKEY_OK) { - return enif_make_badarg(env); - } - -#ifdef HAS_EVP_PKEY_CTX -/* printf("EVP interface\r\n"); - */ - ctx = EVP_PKEY_CTX_new(pkey, NULL); - if (!ctx) goto badarg; - - if (argv[0] != atom_eddsa) { - if (EVP_PKEY_verify_init(ctx) <= 0) goto badarg; - if (md != NULL && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) goto badarg; - } - - if (argv[0] == atom_rsa) { - if (EVP_PKEY_CTX_set_rsa_padding(ctx, sig_opt.rsa_padding) <= 0) goto badarg; - if (sig_opt.rsa_padding == RSA_PKCS1_PSS_PADDING) { - if (sig_opt.rsa_mgf1_md != NULL) { -# ifdef HAVE_RSA_MGF1_MD - if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, sig_opt.rsa_mgf1_md) <= 0) goto badarg; -# else - EVP_PKEY_CTX_free(ctx); - EVP_PKEY_free(pkey); - return atom_notsup; -# endif - } - if (sig_opt.rsa_pss_saltlen > -2 - && EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sig_opt.rsa_pss_saltlen) <= 0) - goto badarg; - } - } - - if (argv[0] == atom_eddsa) { -#ifdef HAVE_EDDSA - EVP_MD_CTX* mdctx = EVP_MD_CTX_create(); - - if (!EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey)) { - if (mdctx) EVP_MD_CTX_destroy(mdctx); - goto badarg; - } - - i = EVP_DigestVerify(mdctx, sig_bin.data, sig_bin.size, tbs, tbslen); - EVP_MD_CTX_destroy(mdctx); -#else - goto badarg; -#endif - } - else - { - if (md != NULL) { - ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md)); - } - i = EVP_PKEY_verify(ctx, sig_bin.data, sig_bin.size, tbs, tbslen); - } - - EVP_PKEY_CTX_free(ctx); -#else -/*printf("Old interface\r\n"); -*/ - if (argv[0] == atom_rsa) { - RSA *rsa = EVP_PKEY_get1_RSA(pkey); - i = RSA_verify(md->type, tbs, tbslen, sig_bin.data, sig_bin.size, rsa); - RSA_free(rsa); - } else if (argv[0] == atom_dss) { - DSA *dsa = EVP_PKEY_get1_DSA(pkey); - i = DSA_verify(0, tbs, tbslen, sig_bin.data, sig_bin.size, dsa); - DSA_free(dsa); - } else if (argv[0] == atom_ecdsa) { -#if defined(HAVE_EC) - EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey); - i = ECDSA_verify(EVP_MD_type(md), tbs, tbslen, sig_bin.data, sig_bin.size, ec); - EC_KEY_free(ec); -#else - EVP_PKEY_free(pkey); - return atom_notsup; -#endif - } else { - goto badarg; - } -#endif - - EVP_PKEY_free(pkey); - if (i == 1) { - return atom_true; - } else { - return atom_false; - } - - badarg: -#ifdef HAS_EVP_PKEY_CTX - EVP_PKEY_CTX_free(ctx); -#endif - EVP_PKEY_free(pkey); - return enif_make_badarg(env); -} - - -/*--------------------------------*/ - -static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options, - PKeyCryptOptions *opt) -{ - ERL_NIF_TERM head, tail; - const ERL_NIF_TERM *tpl_terms; - int tpl_arity; - const EVP_MD *opt_md; - int i; - - if (!enif_is_list(env, options)) { - return PKEY_BADARG; - } - - /* defaults */ - if (algorithm == atom_rsa) { - opt->rsa_mgf1_md = NULL; - opt->rsa_oaep_label.data = NULL; - opt->rsa_oaep_label.size = 0; - opt->rsa_oaep_md = NULL; - opt->rsa_padding = RSA_PKCS1_PADDING; - opt->signature_md = NULL; - } - - if (enif_is_empty_list(env, options)) { - return PKEY_OK; - } - - if (algorithm == atom_rsa) { - tail = options; - while (enif_get_list_cell(env, tail, &head, &tail)) { - if (enif_get_tuple(env, head, &tpl_arity, &tpl_terms) && tpl_arity == 2) { - if (tpl_terms[0] == atom_rsa_padding - || tpl_terms[0] == atom_rsa_pad /* Compatibility */ - ) { - if (tpl_terms[1] == atom_rsa_pkcs1_padding) { - opt->rsa_padding = RSA_PKCS1_PADDING; -#ifdef HAVE_RSA_OAEP_PADDING - } else if (tpl_terms[1] == atom_rsa_pkcs1_oaep_padding) { - opt->rsa_padding = RSA_PKCS1_OAEP_PADDING; -#endif -#ifdef HAVE_RSA_SSLV23_PADDING - } else if (tpl_terms[1] == atom_rsa_sslv23_padding) { - opt->rsa_padding = RSA_SSLV23_PADDING; -#endif - } else if (tpl_terms[1] == atom_rsa_x931_padding) { - opt->rsa_padding = RSA_X931_PADDING; - } else if (tpl_terms[1] == atom_rsa_no_padding) { - opt->rsa_padding = RSA_NO_PADDING; - } else { - return PKEY_BADARG; - } - } else if (tpl_terms[0] == atom_signature_md && enif_is_atom(env, tpl_terms[1])) { - i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md); - if (i != PKEY_OK) { - return i; - } - opt->signature_md = opt_md; - } else if (tpl_terms[0] == atom_rsa_mgf1_md && enif_is_atom(env, tpl_terms[1])) { -#ifndef HAVE_RSA_MGF1_MD - if (tpl_terms[1] != atom_sha) - return PKEY_NOTSUP; -#endif - i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md); - if (i != PKEY_OK) { - return i; - } - opt->rsa_mgf1_md = opt_md; - } else if (tpl_terms[0] == atom_rsa_oaep_label - && enif_inspect_binary(env, tpl_terms[1], &(opt->rsa_oaep_label))) { -#ifdef HAVE_RSA_OAEP_MD - continue; -#else - return PKEY_NOTSUP; -#endif - } else if (tpl_terms[0] == atom_rsa_oaep_md && enif_is_atom(env, tpl_terms[1])) { -#ifndef HAVE_RSA_OAEP_MD - if (tpl_terms[1] != atom_sha) - return PKEY_NOTSUP; -#endif - i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md); - if (i != PKEY_OK) { - return i; - } - opt->rsa_oaep_md = opt_md; - } else { - return PKEY_BADARG; - } - } else { - return PKEY_BADARG; - } - } - } else { - return PKEY_BADARG; - } - - return PKEY_OK; -} - -static size_t size_of_RSA(EVP_PKEY *pkey) { - size_t tmplen; - RSA *rsa = EVP_PKEY_get1_RSA(pkey); - if (rsa == NULL) return 0; - tmplen = RSA_size(rsa); - RSA_free(rsa); - return tmplen; -} - -static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) -{/* (Algorithm, Data, PublKey=[E,N]|[E,N,D]|[E,N,D,P1,P2,E1,E2,C], Options, IsPrivate, IsEncrypt) */ - int i; - EVP_PKEY *pkey; -#ifdef HAS_EVP_PKEY_CTX - EVP_PKEY_CTX *ctx; -#else - RSA *rsa; -#endif - PKeyCryptOptions crypt_opt; - ErlNifBinary in_bin, out_bin, tmp_bin; - size_t outlen; -#ifdef HAVE_RSA_SSLV23_PADDING - size_t tmplen; -#endif - int is_private = (argv[4] == atom_true), - is_encrypt = (argv[5] == atom_true); - int algo_init = 0; - -/* char algo[1024]; */ - -#ifndef HAS_ENGINE_SUPPORT - if (enif_is_map(env, argv[2])) { - return atom_notsup; - } -#endif - - if (!enif_inspect_binary(env, argv[1], &in_bin)) { - return enif_make_badarg(env); - } - - i = get_pkey_crypt_options(env, argv[0], argv[3], &crypt_opt); - if (i != PKEY_OK) { - if (i == PKEY_NOTSUP) - return atom_notsup; - else - return enif_make_badarg(env); - } - - if (is_private) { - if (get_pkey_private_key(env, argv[0], argv[2], &pkey) != PKEY_OK) { - return enif_make_badarg(env); - } - } else { - if (get_pkey_public_key(env, argv[0], argv[2], &pkey) != PKEY_OK) { - return enif_make_badarg(env); - } - } - - out_bin.data = NULL; - out_bin.size = 0; - tmp_bin.data = NULL; - tmp_bin.size = 0; - -#ifdef HAS_EVP_PKEY_CTX - ctx = EVP_PKEY_CTX_new(pkey, NULL); - if (!ctx) goto badarg; - -/* enif_get_atom(env,argv[0],algo,1024,ERL_NIF_LATIN1); */ - - if (is_private) { - if (is_encrypt) { - /* private encrypt */ - if ((algo_init=EVP_PKEY_sign_init(ctx)) <= 0) { - /* fprintf(stderr,"BADARG %s private encrypt algo_init=%d %s:%d\r\n", algo, algo_init, __FILE__, __LINE__); */ - goto badarg; - } - } else { - /* private decrypt */ - if ((algo_init=EVP_PKEY_decrypt_init(ctx)) <= 0) { - /* fprintf(stderr,"BADARG %s private decrypt algo_init=%d %s:%d\r\n", algo, algo_init, __FILE__, __LINE__); */ - goto badarg; - } - } - } else { - if (is_encrypt) { - /* public encrypt */ - if ((algo_init=EVP_PKEY_encrypt_init(ctx)) <= 0) { - /* fprintf(stderr,"BADARG %s public encrypt algo_init=%d %s:%d\r\n", algo,algo_init,__FILE__, __LINE__); */ - goto badarg; - } - } else { - /* public decrypt */ - if ((algo_init=EVP_PKEY_verify_recover_init(ctx)) <= 0) { - /* fprintf(stderr,"BADARG %s public decrypt algo_init=%d %s:%d\r\n", algo,algo_init,__FILE__, __LINE__); */ - goto badarg; - } - } - } - - if (argv[0] == atom_rsa) { - if (crypt_opt.signature_md != NULL - && EVP_PKEY_CTX_set_signature_md(ctx, crypt_opt.signature_md) <= 0) - goto badarg; -#ifdef HAVE_RSA_SSLV23_PADDING - if (crypt_opt.rsa_padding == RSA_SSLV23_PADDING) { - if (is_encrypt) { - tmplen = size_of_RSA(pkey); - if (tmplen == 0) goto badarg; - if (!enif_alloc_binary(tmplen, &tmp_bin)) goto badarg; - if (RSA_padding_add_SSLv23(tmp_bin.data, tmplen, in_bin.data, in_bin.size) <= 0) - goto badarg; - in_bin = tmp_bin; - } - if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0) goto badarg; - } else -#endif - { - if (EVP_PKEY_CTX_set_rsa_padding(ctx, crypt_opt.rsa_padding) <= 0) goto badarg; - } -#ifdef HAVE_RSA_OAEP_MD - if (crypt_opt.rsa_padding == RSA_PKCS1_OAEP_PADDING) { - if (crypt_opt.rsa_oaep_md != NULL - && EVP_PKEY_CTX_set_rsa_oaep_md(ctx, crypt_opt.rsa_oaep_md) <= 0) - goto badarg; - if (crypt_opt.rsa_mgf1_md != NULL - && EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, crypt_opt.rsa_mgf1_md) <= 0) goto badarg; - if (crypt_opt.rsa_oaep_label.data != NULL && crypt_opt.rsa_oaep_label.size > 0) { - unsigned char *label_copy = NULL; - label_copy = OPENSSL_malloc(crypt_opt.rsa_oaep_label.size); - if (label_copy == NULL) goto badarg; - memcpy((void *)(label_copy), (const void *)(crypt_opt.rsa_oaep_label.data), - crypt_opt.rsa_oaep_label.size); - if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, label_copy, - crypt_opt.rsa_oaep_label.size) <= 0) { - OPENSSL_free(label_copy); - label_copy = NULL; - goto badarg; - } - } - } -#endif - } - - if (is_private) { - if (is_encrypt) { - /* private_encrypt */ - i = EVP_PKEY_sign(ctx, NULL, &outlen, in_bin.data, in_bin.size); - } else { - /* private_decrypt */ - i = EVP_PKEY_decrypt(ctx, NULL, &outlen, in_bin.data, in_bin.size); - } - } else { - if (is_encrypt) { - /* public_encrypt */ - i = EVP_PKEY_encrypt(ctx, NULL, &outlen, in_bin.data, in_bin.size); - } else { - /* public_decrypt */ - i = EVP_PKEY_verify_recover(ctx, NULL, &outlen, in_bin.data, in_bin.size); - } - } - /* fprintf(stderr,"i = %d %s:%d\r\n", i, __FILE__, __LINE__); */ - - if (i != 1) goto badarg; - - enif_alloc_binary(outlen, &out_bin); - - if (is_private) { - if (is_encrypt) { - /* private_encrypt */ - i = EVP_PKEY_sign(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size); - } else { - /* private_decrypt */ - i = EVP_PKEY_decrypt(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size); - } - } else { - if (is_encrypt) { - /* public_encrypt */ - i = EVP_PKEY_encrypt(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size); - } else { - /* public_decrypt */ - i = EVP_PKEY_verify_recover(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size); - } - } - -#else - /* Non-EVP cryptolib. Only support RSA */ - - if (argv[0] != atom_rsa) { - algo_init = -2; /* exitcode: notsup */ - goto badarg; - } - rsa = EVP_PKEY_get1_RSA(pkey); - enif_alloc_binary(RSA_size(rsa), &out_bin); - - if (is_private) { - if (is_encrypt) { - /* non-evp rsa private encrypt */ - ERL_VALGRIND_ASSERT_MEM_DEFINED(in_bin.data,in_bin.size); - i = RSA_private_encrypt(in_bin.size, in_bin.data, - out_bin.data, rsa, crypt_opt.rsa_padding); - if (i > 0) { - ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, i); - } - } else { - /* non-evp rsa private decrypt */ - i = RSA_private_decrypt(in_bin.size, in_bin.data, - out_bin.data, rsa, crypt_opt.rsa_padding); - if (i > 0) { - ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, i); - enif_realloc_binary(&out_bin, i); - } - } - } else { - if (is_encrypt) { - /* non-evp rsa public encrypt */ - ERL_VALGRIND_ASSERT_MEM_DEFINED(in_bin.data,in_bin.size); - i = RSA_public_encrypt(in_bin.size, in_bin.data, - out_bin.data, rsa, crypt_opt.rsa_padding); - if (i > 0) { - ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, i); - } - } else { - /* non-evp rsa public decrypt */ - i = RSA_public_decrypt(in_bin.size, in_bin.data, - out_bin.data, rsa, crypt_opt.rsa_padding); - if (i > 0) { - ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, i); - enif_realloc_binary(&out_bin, i); - } - } - } - - outlen = i; - RSA_free(rsa); -#endif - - if ((i > 0) && argv[0] == atom_rsa && !is_encrypt) { -#ifdef HAVE_RSA_SSLV23_PADDING - if (crypt_opt.rsa_padding == RSA_SSLV23_PADDING) { - unsigned char *p; - tmplen = size_of_RSA(pkey); - if (tmplen == 0) goto badarg; - if (!enif_alloc_binary(tmplen, &tmp_bin)) - goto badarg; - p = out_bin.data; - p++; - i = RSA_padding_check_SSLv23(tmp_bin.data, tmplen, p, out_bin.size - 1, tmplen); - if (i >= 0) { - outlen = i; - in_bin = out_bin; - out_bin = tmp_bin; - tmp_bin = in_bin; - i = 1; - } - } -#endif - } - - if (tmp_bin.data != NULL) { - enif_release_binary(&tmp_bin); - } - -#ifdef HAS_EVP_PKEY_CTX - EVP_PKEY_CTX_free(ctx); -#else -#endif - EVP_PKEY_free(pkey); - if (i > 0) { - ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, outlen); - if (outlen != out_bin.size) { - enif_realloc_binary(&out_bin, outlen); - ERL_VALGRIND_ASSERT_MEM_DEFINED(out_bin.data, outlen); - } - return enif_make_binary(env, &out_bin); - } else { - enif_release_binary(&out_bin); - return atom_error; - } - - badarg: - if (out_bin.data != NULL) { - enif_release_binary(&out_bin); - } - if (tmp_bin.data != NULL) { - enif_release_binary(&tmp_bin); - } -#ifdef HAS_EVP_PKEY_CTX - EVP_PKEY_CTX_free(ctx); -#else -#endif - EVP_PKEY_free(pkey); - if (algo_init == -2) - return atom_notsup; - else - return enif_make_badarg(env); -} - - - -/*--------------------------------*/ -static ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ /* (Algorithm, PrivKey | KeyMap) */ - EVP_PKEY *pkey; - ERL_NIF_TERM alg = argv[0]; - ERL_NIF_TERM result[8]; - if (get_pkey_private_key(env, alg, argv[1], &pkey) != PKEY_OK) { - return enif_make_badarg(env); - } - - if (alg == atom_rsa) { - const BIGNUM *n = NULL, *e = NULL, *d = NULL; - RSA *rsa = EVP_PKEY_get1_RSA(pkey); - if (rsa) { - 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 - RSA_free(rsa); - EVP_PKEY_free(pkey); - return enif_make_list_from_array(env, result, 2); - } - - } else if (argv[0] == atom_dss) { - const BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub_key = NULL; - DSA *dsa = EVP_PKEY_get1_DSA(pkey); - if (dsa) { - DSA_get0_pqg(dsa, &p, &q, &g); - DSA_get0_key(dsa, &pub_key, NULL); - result[0] = bin_from_bn(env, p); - result[1] = bin_from_bn(env, q); - result[2] = bin_from_bn(env, g); - result[3] = bin_from_bn(env, pub_key); - DSA_free(dsa); - EVP_PKEY_free(pkey); - return enif_make_list_from_array(env, result, 4); - } - - } else if (argv[0] == atom_ecdsa) { -#if defined(HAVE_EC) - /* not yet implemented - EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey); - if (ec) { - / * Example of result: - { - Curve = {Field, Prime, Point, Order, CoFactor} = - { - Field = {prime_field,<<255,...,255>>}, - Prime = {<<255,...,252>>, - <<90,...,75>>, - <<196,...,144>> - }, - Point = <<4,...,245>>, - Order = <<255,...,81>>, - CoFactor = <<1>> - }, - Key = <<151,...,62>> - } - or - { - Curve = - {characteristic_two_field, - M, - Basis = {tpbasis, _} - | {ppbasis, k1, k2, k3} - }, - Key - } - * / - EVP_PKEY_free(pkey); - return enif_make_list_from_array(env, ..., ...); - */ -#endif - } - - if (pkey) EVP_PKEY_free(pkey); - return enif_make_badarg(env); -} - -/*================================================================*/ - -static ERL_NIF_TERM rand_seed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ - ErlNifBinary seed_bin; - - if (!enif_inspect_binary(env, argv[0], &seed_bin)) - return enif_make_badarg(env); - RAND_seed(seed_bin.data,seed_bin.size); - return atom_ok; -} - -/*================================================================*/ -/* Engine */ -/*================================================================*/ -static ERL_NIF_TERM engine_by_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (EngineId) */ -#ifdef HAS_ENGINE_SUPPORT - ERL_NIF_TERM ret; - ErlNifBinary engine_id_bin; - char *engine_id; - ENGINE *engine; - struct engine_ctx *ctx; - - // Get Engine Id - if(!enif_inspect_binary(env, argv[0], &engine_id_bin)) { - PRINTF_ERR0("engine_by_id_nif Leaved: badarg"); - return enif_make_badarg(env); - } else { - engine_id = enif_alloc(engine_id_bin.size+1); - (void) memcpy(engine_id, engine_id_bin.data, engine_id_bin.size); - engine_id[engine_id_bin.size] = '\0'; - } - - engine = ENGINE_by_id(engine_id); - if(!engine) { - enif_free(engine_id); - PRINTF_ERR0("engine_by_id_nif Leaved: {error, bad_engine_id}"); - return enif_make_tuple2(env, atom_error, atom_bad_engine_id); - } - - ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx)); - ctx->engine = engine; - ctx->id = engine_id; - - ret = enif_make_resource(env, ctx); - enif_release_resource(ctx); - - return enif_make_tuple2(env, atom_ok, ret); -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM engine_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Engine) */ -#ifdef HAS_ENGINE_SUPPORT - ERL_NIF_TERM ret = atom_ok; - struct engine_ctx *ctx; - - // Get Engine - if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { - PRINTF_ERR0("engine_init_nif Leaved: Parameter not an engine resource object"); - return enif_make_badarg(env); - } - if (!ENGINE_init(ctx->engine)) { - //ERR_print_errors_fp(stderr); - PRINTF_ERR0("engine_init_nif Leaved: {error, engine_init_failed}"); - return enif_make_tuple2(env, atom_error, atom_engine_init_failed); - } - - return ret; -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM engine_free_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Engine) */ -#ifdef HAS_ENGINE_SUPPORT - struct engine_ctx *ctx; - - // Get Engine - if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { - PRINTF_ERR0("engine_free_nif Leaved: Parameter not an engine resource object"); - return enif_make_badarg(env); - } - - ENGINE_free(ctx->engine); - return atom_ok; -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM engine_finish_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Engine) */ -#ifdef HAS_ENGINE_SUPPORT - struct engine_ctx *ctx; - - // Get Engine - if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { - PRINTF_ERR0("engine_finish_nif Leaved: Parameter not an engine resource object"); - return enif_make_badarg(env); - } - - ENGINE_finish(ctx->engine); - return atom_ok; -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM engine_load_dynamic_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* () */ -#ifdef HAS_ENGINE_SUPPORT - ENGINE_load_dynamic(); - return atom_ok; -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM engine_ctrl_cmd_strings_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Engine, Commands) */ -#ifdef HAS_ENGINE_SUPPORT - ERL_NIF_TERM ret = atom_ok; - unsigned int cmds_len = 0; - char **cmds = NULL; - struct engine_ctx *ctx; - int i, optional = 0; - - // Get Engine - if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { - PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: Parameter not an engine resource object"); - return enif_make_badarg(env); - } - - PRINTF_ERR1("Engine Id: %s\r\n", ENGINE_get_id(ctx->engine)); - - // Get Command List - if(!enif_get_list_length(env, argv[1], &cmds_len)) { - PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: Bad Command List"); - return enif_make_badarg(env); - } else { - cmds_len *= 2; // Key-Value list from erlang - cmds = enif_alloc((cmds_len+1)*sizeof(char*)); - if(get_engine_load_cmd_list(env, argv[1], cmds, 0)) { - PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: Couldn't read Command List"); - ret = enif_make_badarg(env); - goto error; - } - } - - if(!enif_get_int(env, argv[2], &optional)) { - PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: Parameter optional not an integer"); - return enif_make_badarg(env); - } - - for(i = 0; i < cmds_len; i+=2) { - PRINTF_ERR2("Cmd: %s:%s\r\n", - cmds[i] ? cmds[i] : "(NULL)", - cmds[i+1] ? cmds[i+1] : "(NULL)"); - if(!ENGINE_ctrl_cmd_string(ctx->engine, cmds[i], cmds[i+1], optional)) { - PRINTF_ERR2("Command failed: %s:%s\r\n", - cmds[i] ? cmds[i] : "(NULL)", - cmds[i+1] ? cmds[i+1] : "(NULL)"); - //ENGINE_free(ctx->engine); - ret = enif_make_tuple2(env, atom_error, atom_ctrl_cmd_failed); - PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: {error, ctrl_cmd_failed}"); - goto error; - } - } - - error: - for(i = 0; cmds != NULL && cmds[i] != NULL; i++) - enif_free(cmds[i]); - enif_free(cmds); - return ret; -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM engine_add_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Engine) */ -#ifdef HAS_ENGINE_SUPPORT - struct engine_ctx *ctx; - - // Get Engine - if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { - PRINTF_ERR0("engine_add_nif Leaved: Parameter not an engine resource object"); - return enif_make_badarg(env); - } - - if (!ENGINE_add(ctx->engine)) { - PRINTF_ERR0("engine_add_nif Leaved: {error, add_engine_failed}"); - return enif_make_tuple2(env, atom_error, atom_add_engine_failed); - } - return atom_ok; -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM engine_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Engine) */ -#ifdef HAS_ENGINE_SUPPORT - struct engine_ctx *ctx; - - // Get Engine - if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { - PRINTF_ERR0("engine_remove_nif Leaved: Parameter not an engine resource object"); - return enif_make_badarg(env); - } - - if (!ENGINE_remove(ctx->engine)) { - PRINTF_ERR0("engine_remove_nif Leaved: {error, remove_engine_failed}"); - return enif_make_tuple2(env, atom_error, atom_remove_engine_failed); - } - return atom_ok; -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM engine_register_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Engine, EngineMethod) */ -#ifdef HAS_ENGINE_SUPPORT - struct engine_ctx *ctx; - unsigned int method; - - // Get Engine - if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { - PRINTF_ERR0("engine_register_nif Leaved: Parameter not an engine resource object"); - return enif_make_badarg(env); - } - // Get Method - if (!enif_get_uint(env, argv[1], &method)) { - PRINTF_ERR0("engine_register_nif Leaved: Parameter Method not an uint"); - return enif_make_badarg(env); - } - - switch(method) - { -#ifdef ENGINE_METHOD_RSA - case ENGINE_METHOD_RSA: - if (!ENGINE_register_RSA(ctx->engine)) - return enif_make_tuple2(env, atom_error, atom_register_engine_failed); - break; -#endif -#ifdef ENGINE_METHOD_DSA - case ENGINE_METHOD_DSA: - if (!ENGINE_register_DSA(ctx->engine)) - return enif_make_tuple2(env, atom_error, atom_register_engine_failed); - break; -#endif -#ifdef ENGINE_METHOD_DH - case ENGINE_METHOD_DH: - if (!ENGINE_register_DH(ctx->engine)) - return enif_make_tuple2(env, atom_error, atom_register_engine_failed); - break; -#endif -#ifdef ENGINE_METHOD_RAND - case ENGINE_METHOD_RAND: - if (!ENGINE_register_RAND(ctx->engine)) - return enif_make_tuple2(env, atom_error, atom_register_engine_failed); - break; -#endif -#ifdef ENGINE_METHOD_ECDH - case ENGINE_METHOD_ECDH: - if (!ENGINE_register_ECDH(ctx->engine)) - return enif_make_tuple2(env, atom_error, atom_register_engine_failed); - break; -#endif -#ifdef ENGINE_METHOD_ECDSA - case ENGINE_METHOD_ECDSA: - if (!ENGINE_register_ECDSA(ctx->engine)) - return enif_make_tuple2(env, atom_error, atom_register_engine_failed); - break; -#endif -#ifdef ENGINE_METHOD_STORE - case ENGINE_METHOD_STORE: - if (!ENGINE_register_STORE(ctx->engine)) - return enif_make_tuple2(env, atom_error, atom_register_engine_failed); - break; -#endif -#ifdef ENGINE_METHOD_CIPHERS - case ENGINE_METHOD_CIPHERS: - if (!ENGINE_register_ciphers(ctx->engine)) - return enif_make_tuple2(env, atom_error, atom_register_engine_failed); - break; -#endif -#ifdef ENGINE_METHOD_DIGESTS - case ENGINE_METHOD_DIGESTS: - if (!ENGINE_register_digests(ctx->engine)) - return enif_make_tuple2(env, atom_error, atom_register_engine_failed); - break; -#endif -#ifdef ENGINE_METHOD_PKEY_METHS - case ENGINE_METHOD_PKEY_METHS: - if (!ENGINE_register_pkey_meths(ctx->engine)) - return enif_make_tuple2(env, atom_error, atom_register_engine_failed); - break; -#endif -#ifdef ENGINE_METHOD_PKEY_ASN1_METHS - case ENGINE_METHOD_PKEY_ASN1_METHS: - if (!ENGINE_register_pkey_asn1_meths(ctx->engine)) - return enif_make_tuple2(env, atom_error, atom_register_engine_failed); - break; -#endif -#ifdef ENGINE_METHOD_EC - case ENGINE_METHOD_EC: - if (!ENGINE_register_EC(ctx->engine)) - return enif_make_tuple2(env, atom_error, atom_register_engine_failed); - break; -#endif - default: - return enif_make_tuple2(env, atom_error, atom_engine_method_not_supported); - break; - } - return atom_ok; -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM engine_unregister_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Engine, EngineMethod) */ -#ifdef HAS_ENGINE_SUPPORT - struct engine_ctx *ctx; - unsigned int method; - - // Get Engine - if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { - PRINTF_ERR0("engine_unregister_nif Leaved: Parameter not an engine resource object"); - return enif_make_badarg(env); - } - // Get Method - if (!enif_get_uint(env, argv[1], &method)) { - PRINTF_ERR0("engine_unregister_nif Leaved: Parameter Method not an uint"); - return enif_make_badarg(env); - } - - switch(method) - { -#ifdef ENGINE_METHOD_RSA - case ENGINE_METHOD_RSA: - ENGINE_unregister_RSA(ctx->engine); - break; -#endif -#ifdef ENGINE_METHOD_DSA - case ENGINE_METHOD_DSA: - ENGINE_unregister_DSA(ctx->engine); - break; -#endif -#ifdef ENGINE_METHOD_DH - case ENGINE_METHOD_DH: - ENGINE_unregister_DH(ctx->engine); - break; -#endif -#ifdef ENGINE_METHOD_RAND - case ENGINE_METHOD_RAND: - ENGINE_unregister_RAND(ctx->engine); - break; -#endif -#ifdef ENGINE_METHOD_ECDH - case ENGINE_METHOD_ECDH: - ENGINE_unregister_ECDH(ctx->engine); - break; -#endif -#ifdef ENGINE_METHOD_ECDSA - case ENGINE_METHOD_ECDSA: - ENGINE_unregister_ECDSA(ctx->engine); - break; -#endif -#ifdef ENGINE_METHOD_STORE - case ENGINE_METHOD_STORE: - ENGINE_unregister_STORE(ctx->engine); - break; -#endif -#ifdef ENGINE_METHOD_CIPHERS - case ENGINE_METHOD_CIPHERS: - ENGINE_unregister_ciphers(ctx->engine); - break; -#endif -#ifdef ENGINE_METHOD_DIGESTS - case ENGINE_METHOD_DIGESTS: - ENGINE_unregister_digests(ctx->engine); - break; -#endif -#ifdef ENGINE_METHOD_PKEY_METHS - case ENGINE_METHOD_PKEY_METHS: - ENGINE_unregister_pkey_meths(ctx->engine); - break; -#endif -#ifdef ENGINE_METHOD_PKEY_ASN1_METHS - case ENGINE_METHOD_PKEY_ASN1_METHS: - ENGINE_unregister_pkey_asn1_meths(ctx->engine); - break; -#endif -#ifdef ENGINE_METHOD_EC - case ENGINE_METHOD_EC: - ENGINE_unregister_EC(ctx->engine); - break; -#endif - default: - break; - } - return atom_ok; -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM engine_get_first_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Engine) */ -#ifdef HAS_ENGINE_SUPPORT - ERL_NIF_TERM ret; - ENGINE *engine; - ErlNifBinary engine_bin; - struct engine_ctx *ctx; - - engine = ENGINE_get_first(); - if(!engine) { - enif_alloc_binary(0, &engine_bin); - engine_bin.size = 0; - return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_bin)); - } - - ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx)); - ctx->engine = engine; - ctx->id = NULL; - - ret = enif_make_resource(env, ctx); - enif_release_resource(ctx); - - return enif_make_tuple2(env, atom_ok, ret); -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM engine_get_next_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Engine) */ -#ifdef HAS_ENGINE_SUPPORT - ERL_NIF_TERM ret; - ENGINE *engine; - ErlNifBinary engine_bin; - struct engine_ctx *ctx, *next_ctx; - - // Get Engine - if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { - PRINTF_ERR0("engine_get_next_nif Leaved: Parameter not an engine resource object"); - return enif_make_badarg(env); - } - engine = ENGINE_get_next(ctx->engine); - if (!engine) { - enif_alloc_binary(0, &engine_bin); - engine_bin.size = 0; - return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_bin)); - } - - next_ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx)); - next_ctx->engine = engine; - next_ctx->id = NULL; - - ret = enif_make_resource(env, next_ctx); - enif_release_resource(next_ctx); - - return enif_make_tuple2(env, atom_ok, ret); -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM engine_get_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Engine) */ -#ifdef HAS_ENGINE_SUPPORT - ErlNifBinary engine_id_bin; - const char *engine_id; - int size; - struct engine_ctx *ctx; - - // Get Engine - if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { - PRINTF_ERR0("engine_get_id_nif Leaved: Parameter not an engine resource object"); - return enif_make_badarg(env); - } - - engine_id = ENGINE_get_id(ctx->engine); - if (!engine_id) { - enif_alloc_binary(0, &engine_id_bin); - engine_id_bin.size = 0; - return enif_make_binary(env, &engine_id_bin); - } - - size = strlen(engine_id); - enif_alloc_binary(size, &engine_id_bin); - engine_id_bin.size = size; - memcpy(engine_id_bin.data, engine_id, size); - - return enif_make_binary(env, &engine_id_bin); -#else - return atom_notsup; -#endif -} - -static ERL_NIF_TERM engine_get_name_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* (Engine) */ -#ifdef HAS_ENGINE_SUPPORT - ErlNifBinary engine_name_bin; - const char *engine_name; - int size; - struct engine_ctx *ctx; - - // Get Engine - if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { - PRINTF_ERR0("engine_get_id_nif Leaved: Parameter not an engine resource object"); - return enif_make_badarg(env); - } - - engine_name = ENGINE_get_name(ctx->engine); - if (!engine_name) { - enif_alloc_binary(0, &engine_name_bin); - engine_name_bin.size = 0; - return enif_make_binary(env, &engine_name_bin); - } - - size = strlen(engine_name); - enif_alloc_binary(size, &engine_name_bin); - engine_name_bin.size = size; - memcpy(engine_name_bin.data, engine_name, size); - - return enif_make_binary(env, &engine_name_bin); -#else - return atom_notsup; -#endif -} - -#ifdef HAS_ENGINE_SUPPORT -static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i) -{ - ERL_NIF_TERM head, tail; - const ERL_NIF_TERM *tmp_tuple; - ErlNifBinary tmpbin; - int arity; - char* tmpstr; - - if(!enif_is_empty_list(env, term)) { - if(!enif_get_list_cell(env, term, &head, &tail)) { - cmds[i] = NULL; - return -1; - } else { - if(!enif_get_tuple(env, head, &arity, &tmp_tuple) || arity != 2) { - cmds[i] = NULL; - return -1; - } else { - if(!enif_inspect_binary(env, tmp_tuple[0], &tmpbin)) { - cmds[i] = NULL; - return -1; - } else { - tmpstr = enif_alloc(tmpbin.size+1); - (void) memcpy(tmpstr, tmpbin.data, tmpbin.size); - tmpstr[tmpbin.size] = '\0'; - cmds[i++] = tmpstr; - } - if(!enif_inspect_binary(env, tmp_tuple[1], &tmpbin)) { - cmds[i] = NULL; - return -1; - } else { - if(tmpbin.size == 0) - cmds[i++] = NULL; - else { - tmpstr = enif_alloc(tmpbin.size+1); - (void) memcpy(tmpstr, tmpbin.data, tmpbin.size); - tmpstr[tmpbin.size] = '\0'; - cmds[i++] = tmpstr; - } - } - return get_engine_load_cmd_list(env, tail, cmds, i); - } - } - } else { - cmds[i] = NULL; - return 0; - } -} -#endif - -static ERL_NIF_TERM engine_get_all_methods_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{/* () */ -#ifdef HAS_ENGINE_SUPPORT - ERL_NIF_TERM method_array[12]; - int i = 0; - -#ifdef ENGINE_METHOD_RSA - method_array[i++] = atom_engine_method_rsa; -#endif -#ifdef ENGINE_METHOD_DSA - method_array[i++] = atom_engine_method_dsa; -#endif -#ifdef ENGINE_METHOD_DH - method_array[i++] = atom_engine_method_dh; -#endif -#ifdef ENGINE_METHOD_RAND - method_array[i++] = atom_engine_method_rand; -#endif -#ifdef ENGINE_METHOD_ECDH - method_array[i++] = atom_engine_method_ecdh; -#endif -#ifdef ENGINE_METHOD_ECDSA - method_array[i++] = atom_engine_method_ecdsa; -#endif -#ifdef ENGINE_METHOD_STORE - method_array[i++] = atom_engine_method_store; -#endif -#ifdef ENGINE_METHOD_CIPHERS - method_array[i++] = atom_engine_method_ciphers; -#endif -#ifdef ENGINE_METHOD_DIGESTS - method_array[i++] = atom_engine_method_digests; -#endif -#ifdef ENGINE_METHOD_PKEY_METHS - method_array[i++] = atom_engine_method_pkey_meths; -#endif -#ifdef ENGINE_METHOD_PKEY_ASN1_METHS - method_array[i++] = atom_engine_method_pkey_asn1_meths; -#endif -#ifdef ENGINE_METHOD_EC - method_array[i++] = atom_engine_method_ec; -#endif - - return enif_make_list_from_array(env, method_array, i); -#else - return atom_notsup; -#endif -} |