diff options
Diffstat (limited to 'lib/crypto/c_src')
-rw-r--r-- | lib/crypto/c_src/Makefile.in | 49 | ||||
-rw-r--r-- | lib/crypto/c_src/crypto.c | 326 | ||||
-rw-r--r-- | lib/crypto/c_src/crypto_callback.c | 165 | ||||
-rw-r--r-- | lib/crypto/c_src/crypto_callback.h | 46 |
4 files changed, 434 insertions, 152 deletions
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in index ffd556ca1a..e19d6617f3 100644 --- a/lib/crypto/c_src/Makefile.in +++ b/lib/crypto/c_src/Makefile.in @@ -59,8 +59,6 @@ TYPE_FLAGS = $(CFLAGS) endif endif -ALL_CFLAGS = $(TYPE_FLAGS) $(INCLUDES) - # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -69,13 +67,16 @@ RELSYSDIR = $(RELEASE_PATH)/lib/crypto-$(VSN) # ---------------------------------------------------- # Misc Macros # ---------------------------------------------------- -OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o +CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o +CALLBACK_OBJS = $(OBJDIR)/crypto_callback$(TYPEMARKER).o NIF_MAKEFILE = $(PRIVDIR)/Makefile ifeq ($(findstring win32,$(TARGET)), win32) NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).dll +CALLBACK_LIB = $(LIBDIR)/crypto_callback$(TYPEMARKER).dll else NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).so +CALLBACK_LIB = $(LIBDIR)/crypto_callback$(TYPEMARKER).so endif ifeq ($(HOST_OS),) @@ -86,43 +87,69 @@ DYNAMIC_CRYPTO_LIB=@SSL_DYNAMIC_ONLY@ ifeq ($(DYNAMIC_CRYPTO_LIB),yes) SSL_DED_LD_RUNTIME_LIBRARY_PATH = @SSL_DED_LD_RUNTIME_LIBRARY_PATH@ CRYPTO_LINK_LIB=$(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -l$(SSL_CRYPTO_LIBNAME) +EXTRA_FLAGS = -DHAVE_DYNAMIC_CRYPTO_LIB else SSL_DED_LD_RUNTIME_LIBRARY_PATH= CRYPTO_LINK_LIB=$(SSL_LIBDIR)/lib$(SSL_CRYPTO_LIBNAME).a +EXTRA_FLAGS = +CRYPTO_OBJS := $(CRYPTO_OBJS) $(CALLBACK_OBJS) +CALLBACK_OBJS = +CALLBACK_LIB = endif +ALL_CFLAGS = $(TYPE_FLAGS) $(EXTRA_FLAGS) $(INCLUDES) + # ---------------------------------------------------- # Targets # ---------------------------------------------------- _create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR)) -debug opt valgrind: $(NIF_LIB) +debug opt valgrind: $(NIF_LIB) $(CALLBACK_LIB) $(OBJDIR)/%$(TYPEMARKER).o: %.c $(INSTALL_DIR) $(OBJDIR) $(CC) -c -o $@ $(ALL_CFLAGS) $< -$(LIBDIR)/crypto$(TYPEMARKER).so: $(OBJS) - $(INSTALL_DIR) $(LIBDIR) +$(LIBDIR)/crypto$(TYPEMARKER).so: $(CRYPTO_OBJS) + $(INSTALL_DIR) $(LIBDIR) $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CRYPTO_LINK_LIB) -$(LIBDIR)/crypto$(TYPEMARKER).dll: $(OBJS) +$(LIBDIR)/crypto$(TYPEMARKER).dll: $(CRYPTO_OBJS) + $(INSTALL_DIR) $(LIBDIR) + $(LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(CRYPTO_OBJS) -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME) + +ifeq ($(DYNAMIC_CRYPTO_LIB),yes) +$(LIBDIR)/crypto_callback$(TYPEMARKER).so: $(CALLBACK_OBJS) + $(INSTALL_DIR) $(LIBDIR) + $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +$(LIBDIR)/crypto_callback$(TYPEMARKER).dll: $(CALLBACK_OBJS) $(INSTALL_DIR) $(LIBDIR) - $(LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(OBJS) -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME) + $(LD) $(LDFLAGS) -o $@ $(CALLBACK_OBJS) +endif + clean: ifeq ($(findstring win32,$(TARGET)), win32) rm -f $(LIBDIR)/crypto.dll rm -f $(LIBDIR)/crypto.debug.dll + rm -f $(LIBDIR)/crypto_callback.dll + rm -f $(LIBDIR)/crypto_callback.debug.dll else rm -f $(LIBDIR)/crypto.so rm -f $(LIBDIR)/crypto.debug.so rm -f $(LIBDIR)/crypto.valgrind.so + rm -f $(LIBDIR)/crypto_callback.so + rm -f $(LIBDIR)/crypto_callback.debug.so + rm -f $(LIBDIR)/crypto_callback.valgrind.so endif rm -f $(OBJDIR)/crypto.o rm -f $(OBJDIR)/crypto.debug.o rm -f $(OBJDIR)/crypto.valgrind.o + rm -f $(OBJDIR)/crypto_callback.o + rm -f $(OBJDIR)/crypto_callback.debug.o + rm -f $(OBJDIR)/crypto_callback.valgrind.o rm -f core *~ docs: @@ -136,8 +163,12 @@ release_spec: opt $(INSTALL_DIR) "$(RELSYSDIR)/priv/obj" $(INSTALL_DIR) "$(RELSYSDIR)/priv/lib" $(INSTALL_DATA) $(NIF_MAKEFILE) "$(RELSYSDIR)/priv/obj" - $(INSTALL_PROGRAM) $(OBJS) "$(RELSYSDIR)/priv/obj" + $(INSTALL_PROGRAM) $(CRYPTO_OBJS) "$(RELSYSDIR)/priv/obj" $(INSTALL_PROGRAM) $(NIF_LIB) "$(RELSYSDIR)/priv/lib" +ifeq ($(DYNAMIC_CRYPTO_LIB),yes) + $(INSTALL_PROGRAM) $(CALLBACK_OBJS) "$(RELSYSDIR)/priv/obj" + $(INSTALL_PROGRAM) $(CALLBACK_LIB) "$(RELSYSDIR)/priv/lib" +endif release_docs_spec: diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 91ab244620..e77e5fb8f0 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -44,6 +44,7 @@ #include <openssl/md5.h> #include <openssl/md4.h> #include <openssl/sha.h> +#include <openssl/ripemd.h> #include <openssl/bn.h> #include <openssl/objects.h> #include <openssl/rc4.h> @@ -53,6 +54,8 @@ #include <openssl/evp.h> #include <openssl/hmac.h> +#include "crypto_callback.h" + #if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA224) && defined(NID_sha224)\ && !defined(OPENSSL_NO_SHA256) /* disabled like this in my sha.h (?) */ # define HAVE_SHA224 @@ -67,6 +70,9 @@ #if OPENSSL_VERSION_NUMBER >= 0x00908000L && !defined(OPENSSL_NO_SHA512) && defined(NID_sha512) # define HAVE_SHA512 #endif +#if OPENSSL_VERSION_NUMBER >= 0x0090705FL +# define HAVE_DES_ede3_cfb_encrypt +#endif #ifdef VALGRIND # include <valgrind/memcheck.h> @@ -125,7 +131,6 @@ /* NIF interface declarations */ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); -static int reload(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); @@ -135,6 +140,10 @@ static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM md5_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM ripemd160(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM ripemd160_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM ripemd160_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM ripemd160_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -172,7 +181,7 @@ static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a static ERL_NIF_TERM des_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM des_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM des_ede3_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM des_ede3_cfb_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_ctr_encrypt(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[]); @@ -204,17 +213,6 @@ static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -/* openssl callbacks */ -#ifdef OPENSSL_THREADS -static void locking_function(int mode, int n, const char *file, int line); -static unsigned long id_function(void); -static struct CRYPTO_dynlock_value* dyn_create_function(const char *file, - int line); -static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value* ptr, - const char *file, int line); -static void dyn_destroy_function(struct CRYPTO_dynlock_value *ptr, - const char *file, int line); -#endif /* OPENSSL_THREADS */ /* helpers */ static void init_digest_types(ErlNifEnv* env); @@ -253,6 +251,10 @@ static ErlNifFunc nif_funcs[] = { {"md5_init", 0, md5_init}, {"md5_update", 2, md5_update}, {"md5_final", 1, md5_final}, + {"ripemd160", 1, ripemd160}, + {"ripemd160_init", 0, ripemd160_init}, + {"ripemd160_update", 2, ripemd160_update}, + {"ripemd160_final", 1, ripemd160_final}, {"sha", 1, sha}, {"sha_init", 0, sha_init}, {"sha_update", 2, sha_update}, @@ -291,7 +293,7 @@ static ErlNifFunc nif_funcs[] = { {"des_cfb_crypt", 4, des_cfb_crypt}, {"des_ecb_crypt", 3, des_ecb_crypt}, {"des_ede3_cbc_crypt", 6, des_ede3_cbc_crypt}, - {"des_ede3_cfb_crypt", 6, des_ede3_cfb_crypt}, + {"des_ede3_cfb_crypt_nif", 6, des_ede3_cfb_crypt_nif}, {"aes_cfb_128_crypt", 4, aes_cfb_128_crypt}, {"aes_ctr_encrypt", 3, aes_ctr_encrypt}, {"aes_ctr_decrypt", 3, aes_ctr_encrypt}, @@ -325,7 +327,7 @@ static ErlNifFunc nif_funcs[] = { {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt} }; -ERL_NIF_INIT(crypto,nif_funcs,load,reload,upgrade,unload) +ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload) #define MD5_CTX_LEN (sizeof(MD5_CTX)) @@ -333,6 +335,8 @@ ERL_NIF_INIT(crypto,nif_funcs,load,reload,upgrade,unload) #define MD5_LEN_96 12 #define MD4_CTX_LEN (sizeof(MD4_CTX)) #define MD4_LEN 16 +#define RIPEMD160_CTX_LEN (sizeof(RIPEMD160_CTX)) +#define RIPEMD160_LEN 20 #define SHA_CTX_LEN (sizeof(SHA_CTX)) #define SHA_LEN 20 #define SHA_LEN_96 12 @@ -347,7 +351,6 @@ ERL_NIF_INIT(crypto,nif_funcs,load,reload,upgrade,unload) #define HMAC_OPAD 0x5c -static ErlNifRWLock** lock_vec = NULL; /* Static locks used by openssl */ static ERL_NIF_TERM atom_true; static ERL_NIF_TERM atom_false; static ERL_NIF_TERM atom_sha; @@ -374,55 +377,60 @@ static ERL_NIF_TERM atom_none; static ERL_NIF_TERM atom_notsup; static ERL_NIF_TERM atom_digest; +/* +#define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n") +#define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1) +*/ +#define PRINTF_ERR0(FMT) +#define PRINTF_ERR1(FMT,A1) -static int is_ok_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info) +#ifdef HAVE_DYNAMIC_CRYPTO_LIB +static int change_basename(char* buf, int bufsz, const char* newfile) { - int i; - return enif_get_int(env,load_info,&i) && i == 101; -} -static void* crypto_alloc(size_t size) -{ - return enif_alloc(size); + char* p = strrchr(buf, '/'); + p = (p == NULL) ? buf : p + 1; + + if ((p - buf) + strlen(newfile) >= bufsz) { + PRINTF_ERR0("CRYPTO: lib name too long"); + return 0; + } + strcpy(p, newfile); + return 1; } -static void* crypto_realloc(void* ptr, size_t size) + +static void error_handler(void* null, const char* errstr) { - return enif_realloc(ptr, size); -} -static void crypto_free(void* ptr) -{ - enif_free(ptr); + PRINTF_ERR1("CRYPTO LOADING ERROR: '%s'", errstr); } +#endif /* HAVE_DYNAMIC_CRYPTO_LIB */ -static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +static int init(ErlNifEnv* env, ERL_NIF_TERM load_info) { ErlNifSysInfo sys_info; - CRYPTO_set_mem_functions(crypto_alloc, crypto_realloc, crypto_free); - - if (!is_ok_load_info(env, load_info)) { - return -1; + get_crypto_callbacks_t* funcp; + struct crypto_callbacks* ccb; + int nlocks = 0; + int tpl_arity; + const ERL_NIF_TERM* tpl_array; + int vernum; + char lib_buf[1000]; + + /* load_info: {201, "/full/path/of/this/library"} */ + if (!enif_get_tuple(env, load_info, &tpl_arity, &tpl_array) + || tpl_arity != 2 + || !enif_get_int(env, tpl_array[0], &vernum) + || vernum != 201 + || enif_get_string(env, tpl_array[1], lib_buf, sizeof(lib_buf), ERL_NIF_LATIN1) <= 0) { + + PRINTF_ERR1("CRYPTO: Invalid load_info '%T'", load_info); + return 0; } - -#ifdef OPENSSL_THREADS - enif_system_info(&sys_info, sizeof(sys_info)); - - if (sys_info.scheduler_threads > 1) { - int i; - lock_vec = enif_alloc(CRYPTO_num_locks()*sizeof(*lock_vec)); - if (lock_vec==NULL) return -1; - memset(lock_vec,0,CRYPTO_num_locks()*sizeof(*lock_vec)); - - for (i=CRYPTO_num_locks()-1; i>=0; --i) { - lock_vec[i] = enif_rwlock_create("crypto_stat"); - if (lock_vec[i]==NULL) return -1; - } - CRYPTO_set_locking_callback(locking_function); - CRYPTO_set_id_callback(id_function); - CRYPTO_set_dynlock_create_callback(dyn_create_function); - CRYPTO_set_dynlock_lock_callback(dyn_lock_function); - CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function); + if (library_refc > 0) { + /* Repeated loading of this library (module upgrade). + * Atoms and callbacks are already set, we are done. + */ + return 1; } - /* else no need for locks */ -#endif /* OPENSSL_THREADS */ atom_true = enif_make_atom(env,"true"); atom_false = enif_make_atom(env,"false"); @@ -451,37 +459,75 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) init_digest_types(env); - *priv_data = NULL; - library_refc++; - return 0; -} - -static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) -{ - if (*priv_data != NULL) { - return -1; /* Don't know how to do that */ +#ifdef HAVE_DYNAMIC_CRYPTO_LIB + { + void* handle; + if (!change_basename(lib_buf, sizeof(lib_buf), "crypto_callback")) { + return 0; + } + if (!(handle = enif_dlopen(lib_buf, &error_handler, NULL))) { + return 0; + } + if (!(funcp = (get_crypto_callbacks_t*) enif_dlsym(handle, "get_crypto_callbacks", + &error_handler, NULL))) { + return 0; + } } - if (library_refc == 0) { - /* No support for real library upgrade. The tricky thing is to know - when to (re)set the callbacks for allocation and locking. */ - return -2; +#else /* !HAVE_DYNAMIC_CRYPTO_LIB */ + funcp = &get_crypto_callbacks; +#endif + +#ifdef OPENSSL_THREADS + enif_system_info(&sys_info, sizeof(sys_info)); + if (sys_info.scheduler_threads > 1) { + nlocks = CRYPTO_num_locks(); } - if (!is_ok_load_info(env, load_info)) { + /* else no need for locks */ +#endif + + ccb = (*funcp)(nlocks); + + if (!ccb || ccb->sizeof_me != sizeof(*ccb)) { + PRINTF_ERR0("Invalid 'crypto_callbacks'"); + return 0; + } + + CRYPTO_set_mem_functions(ccb->crypto_alloc, ccb->crypto_realloc, ccb->crypto_free); + +#ifdef OPENSSL_THREADS + if (nlocks > 0) { + CRYPTO_set_locking_callback(ccb->locking_function); + CRYPTO_set_id_callback(ccb->id_function); + CRYPTO_set_dynlock_create_callback(ccb->dyn_create_function); + CRYPTO_set_dynlock_lock_callback(ccb->dyn_lock_function); + CRYPTO_set_dynlock_destroy_callback(ccb->dyn_destroy_function); + } +#endif /* OPENSSL_THREADS */ + return 1; +} + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + if (!init(env, load_info)) { return -1; } - return 0; + + *priv_data = NULL; + library_refc++; + return 0; } static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) { - int i; if (*old_priv_data != NULL) { return -1; /* Don't know how to do that */ } - i = reload(env,priv_data,load_info); - if (i != 0) { - return i; + if (*priv_data != NULL) { + return -1; /* Don't know how to do that */ + } + if (!init(env, load_info)) { + return -1; } library_refc++; return 0; @@ -489,20 +535,7 @@ static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, static void unload(ErlNifEnv* env, void* priv_data) { - if (--library_refc <= 0) { - CRYPTO_cleanup_all_ex_data(); - - if (lock_vec != NULL) { - int i; - for (i=CRYPTO_num_locks()-1; i>=0; --i) { - if (lock_vec[i] != NULL) { - enif_rwlock_destroy(lock_vec[i]); - } - } - enif_free(lock_vec); - } - } - /*else NIF library still used by other (new) module code */ + --library_refc; } static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -514,12 +547,21 @@ static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[] 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, SSLeay()), + enif_make_int(env, ver_num), ver_term)); } @@ -569,6 +611,53 @@ static ERL_NIF_TERM md5_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ return ret; } +static ERL_NIF_TERM ripemd160(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Data) */ + ErlNifBinary ibin; + ERL_NIF_TERM ret; + + if (!enif_inspect_iolist_as_binary(env, argv[0], &ibin)) { + return enif_make_badarg(env); + } + RIPEMD160((unsigned char *) ibin.data, ibin.size, + enif_make_new_binary(env,RIPEMD160_LEN, &ret)); + return ret; +} +static ERL_NIF_TERM ripemd160_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* () */ + ERL_NIF_TERM ret; + RIPEMD160_Init((RIPEMD160_CTX *) enif_make_new_binary(env, RIPEMD160_CTX_LEN, &ret)); + return ret; +} +static ERL_NIF_TERM ripemd160_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Context, Data) */ + RIPEMD160_CTX* new_ctx; + ErlNifBinary ctx_bin, data_bin; + ERL_NIF_TERM ret; + if (!enif_inspect_binary(env, argv[0], &ctx_bin) + || ctx_bin.size != RIPEMD160_CTX_LEN + || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) { + return enif_make_badarg(env); + } + new_ctx = (RIPEMD160_CTX*) enif_make_new_binary(env,RIPEMD160_CTX_LEN, &ret); + memcpy(new_ctx, ctx_bin.data, RIPEMD160_CTX_LEN); + RIPEMD160_Update(new_ctx, data_bin.data, data_bin.size); + return ret; +} +static ERL_NIF_TERM ripemd160_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Context) */ + ErlNifBinary ctx_bin; + RIPEMD160_CTX ctx_clone; + ERL_NIF_TERM ret; + if (!enif_inspect_binary(env, argv[0], &ctx_bin) || ctx_bin.size != RIPEMD160_CTX_LEN) { + return enif_make_badarg(env); + } + memcpy(&ctx_clone, ctx_bin.data, RIPEMD160_CTX_LEN); /* writable */ + RIPEMD160_Final(enif_make_new_binary(env, RIPEMD160_LEN, &ret), &ctx_clone); + return ret; +} + + static ERL_NIF_TERM sha(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Data) */ ErlNifBinary ibin; @@ -1199,8 +1288,9 @@ static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_T return ret; } -static ERL_NIF_TERM des_ede3_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +static ERL_NIF_TERM des_ede3_cfb_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key1, Key2, Key3, IVec, Text/Cipher, IsEncrypt) */ +#ifdef HAVE_DES_ede3_cfb_encrypt ErlNifBinary key1, key2, key3, ivec, text; DES_key_schedule schedule1, schedule2, schedule3; DES_cblock ivec_clone; /* writable copy */ @@ -1222,6 +1312,9 @@ static ERL_NIF_TERM des_ede3_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_T 8, text.size, &schedule1, &schedule2, &schedule3, &ivec_clone, (argv[5] == atom_true)); return ret; +#else + return atom_notsup; +#endif } static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -2338,59 +2431,6 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N -#ifdef OPENSSL_THREADS /* vvvvvvvvvvvvvvv OPENSSL_THREADS vvvvvvvvvvvvvvvv */ - -static INLINE void locking(int mode, ErlNifRWLock* lock) -{ - switch (mode) { - case CRYPTO_LOCK|CRYPTO_READ: - enif_rwlock_rlock(lock); - break; - case CRYPTO_LOCK|CRYPTO_WRITE: - enif_rwlock_rwlock(lock); - break; - case CRYPTO_UNLOCK|CRYPTO_READ: - enif_rwlock_runlock(lock); - break; - case CRYPTO_UNLOCK|CRYPTO_WRITE: - enif_rwlock_rwunlock(lock); - break; - default: - ASSERT(!"Invalid lock mode"); - } -} - -/* Callback from openssl for static locking - */ -static void locking_function(int mode, int n, const char *file, int line) -{ - ASSERT(n>=0 && n<CRYPTO_num_locks()); - - locking(mode, lock_vec[n]); -} - -/* Callback from openssl for thread id - */ -static unsigned long id_function(void) -{ - return(unsigned long) enif_thread_self(); -} - -/* Callbacks for dynamic locking, not used by current openssl version (0.9.8) - */ -static struct CRYPTO_dynlock_value* dyn_create_function(const char *file, int line) { - return(struct CRYPTO_dynlock_value*) enif_rwlock_create("crypto_dyn"); -} -static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value* ptr,const char *file, int line) -{ - locking(mode, (ErlNifRWLock*)ptr); -} -static void dyn_destroy_function(struct CRYPTO_dynlock_value *ptr, const char *file, int line) -{ - enif_rwlock_destroy((ErlNifRWLock*)ptr); -} - -#endif /* ^^^^^^^^^^^^^^^^^^^^^^ OPENSSL_THREADS ^^^^^^^^^^^^^^^^^^^^^^ */ /* HMAC */ diff --git a/lib/crypto/c_src/crypto_callback.c b/lib/crypto/c_src/crypto_callback.c new file mode 100644 index 0000000000..81106b4cc2 --- /dev/null +++ b/lib/crypto/c_src/crypto_callback.c @@ -0,0 +1,165 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2012. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#include <string.h> +#include <openssl/opensslconf.h> + +#include "erl_nif.h" +#include "crypto_callback.h" + +#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 + +#ifdef __WIN32__ +# define DLLEXPORT __declspec(dllexport) +#else +# define DLLEXPORT +#endif + +/* to be dlsym'ed */ +DLLEXPORT struct crypto_callbacks* get_crypto_callbacks(int nlocks); + + +static ErlNifRWLock** lock_vec = NULL; /* Static locks used by openssl */ + +static void* crypto_alloc(size_t size) +{ + return enif_alloc(size); +} +static void* crypto_realloc(void* ptr, size_t size) +{ + return enif_realloc(ptr, size); +} +static void crypto_free(void* ptr) +{ + enif_free(ptr); +} + + +#ifdef OPENSSL_THREADS /* vvvvvvvvvvvvvvv OPENSSL_THREADS vvvvvvvvvvvvvvvv */ + +#include <openssl/crypto.h> + +static INLINE void locking(int mode, ErlNifRWLock* lock) +{ + switch (mode) { + case CRYPTO_LOCK|CRYPTO_READ: + enif_rwlock_rlock(lock); + break; + case CRYPTO_LOCK|CRYPTO_WRITE: + enif_rwlock_rwlock(lock); + break; + case CRYPTO_UNLOCK|CRYPTO_READ: + enif_rwlock_runlock(lock); + break; + case CRYPTO_UNLOCK|CRYPTO_WRITE: + enif_rwlock_rwunlock(lock); + break; + default: + ASSERT(!"Invalid lock mode"); + } +} + +static void locking_function(int mode, int n, const char *file, int line) +{ + ASSERT(n>=0 && n<CRYPTO_num_locks()); + + locking(mode, lock_vec[n]); +} + +static unsigned long id_function(void) +{ + return (unsigned long) enif_thread_self(); +} + +/* Dynamic locking, not used by current openssl version (0.9.8) + */ +static struct CRYPTO_dynlock_value* dyn_create_function(const char *file, int line) +{ + return (struct CRYPTO_dynlock_value*) enif_rwlock_create("crypto_dyn"); +} +static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value* ptr,const char *file, int line) +{ + locking(mode, (ErlNifRWLock*)ptr); +} +static void dyn_destroy_function(struct CRYPTO_dynlock_value *ptr, const char *file, int line) +{ + enif_rwlock_destroy((ErlNifRWLock*)ptr); +} + +#endif /* ^^^^^^^^^^^^^^^^^^^^^^ OPENSSL_THREADS ^^^^^^^^^^^^^^^^^^^^^^ */ + +DLLEXPORT struct crypto_callbacks* get_crypto_callbacks(int nlocks) +{ + static int is_initialized = 0; + static struct crypto_callbacks the_struct = { + sizeof(struct crypto_callbacks), + + &crypto_alloc, + &crypto_realloc, + &crypto_free, + +#ifdef OPENSSL_THREADS + &locking_function, + &id_function, + &dyn_create_function, + &dyn_lock_function, + &dyn_destroy_function +#endif /* OPENSSL_THREADS */ + }; + + if (!is_initialized) { +#ifdef OPENSSL_THREADS + if (nlocks > 0) { + int i; + lock_vec = enif_alloc(nlocks*sizeof(*lock_vec)); + if (lock_vec==NULL) return NULL; + memset(lock_vec, 0, nlocks*sizeof(*lock_vec)); + + for (i=nlocks-1; i>=0; --i) { + lock_vec[i] = enif_rwlock_create("crypto_stat"); + if (lock_vec[i]==NULL) return NULL; + } + } +#endif + is_initialized = 1; + } + return &the_struct; +} + +#ifdef HAVE_DYNAMIC_CRYPTO_LIB +/* This is not really a NIF library, but we use ERL_NIF_INIT in order to + * get access to the erl_nif API (on Windows). + */ +ERL_NIF_INIT(dummy, (ErlNifFunc*)NULL , NULL, NULL, NULL, NULL) +#endif + diff --git a/lib/crypto/c_src/crypto_callback.h b/lib/crypto/c_src/crypto_callback.h new file mode 100644 index 0000000000..23ecba3e5d --- /dev/null +++ b/lib/crypto/c_src/crypto_callback.h @@ -0,0 +1,46 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2012. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +struct crypto_callbacks +{ + size_t sizeof_me; + + void* (*crypto_alloc)(size_t size); + void* (*crypto_realloc)(void* ptr, size_t size); + void (*crypto_free)(void* ptr); + + /* openssl callbacks */ + #ifdef OPENSSL_THREADS + void (*locking_function)(int mode, int n, const char *file, int line); + unsigned long (*id_function)(void); + struct CRYPTO_dynlock_value* (*dyn_create_function)(const char *file, + int line); + void (*dyn_lock_function)(int mode, struct CRYPTO_dynlock_value* ptr, + const char *file, int line); + void (*dyn_destroy_function)(struct CRYPTO_dynlock_value *ptr, + const char *file, int line); + #endif /* OPENSSL_THREADS */ +}; + +typedef struct crypto_callbacks* get_crypto_callbacks_t(int nlocks); + +#ifndef HAVE_DYNAMIC_CRYPTO_LIB +struct crypto_callbacks* get_crypto_callbacks(int nlocks); +#endif + |