diff --git a/crypto/engine/Makefile.ssl b/crypto/engine/Makefile.ssl index abb8281d4e1d24b8dcd4151baf84ecad99dd6d82..df209e9436ff2697b0840dd76e3d2b18b62cbfe3 100644 --- a/crypto/engine/Makefile.ssl +++ b/crypto/engine/Makefile.ssl @@ -24,11 +24,11 @@ APPS= LIB=$(TOP)/libcrypto.a LIBSRC= engine_err.c engine_lib.c engine_list.c engine_all.c engine_openssl.c \ - engine_evp.c \ + engine_dyn.c engine_evp.c \ hw_atalla.c hw_cswift.c hw_ncipher.c hw_nuron.c hw_ubsec.c \ hw_openbsd_dev_crypto.c LIBOBJ= engine_err.o engine_lib.o engine_list.o engine_all.o engine_openssl.o \ - engine_evp.o \ + engine_dyn.o engine_evp.o \ hw_atalla.o hw_cswift.o hw_ncipher.o hw_nuron.o hw_ubsec.o \ hw_openbsd_dev_crypto.o @@ -96,6 +96,18 @@ engine_all.o: ../../include/openssl/rsa.h ../../include/openssl/safestack.h engine_all.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h engine_all.o: ../../include/openssl/types.h ../../include/openssl/ui.h engine_all.o: engine_all.c engine_int.h +engine_dyn.o: ../../e_os.h ../../include/openssl/asn1.h +engine_dyn.o: ../../include/openssl/bio.h ../../include/openssl/bn.h +engine_dyn.o: ../../include/openssl/buffer.h ../../include/openssl/crypto.h +engine_dyn.o: ../../include/openssl/dh.h ../../include/openssl/dsa.h +engine_dyn.o: ../../include/openssl/dso.h ../../include/openssl/e_os2.h +engine_dyn.o: ../../include/openssl/engine.h ../../include/openssl/err.h +engine_dyn.o: ../../include/openssl/lhash.h ../../include/openssl/opensslconf.h +engine_dyn.o: ../../include/openssl/opensslv.h ../../include/openssl/rand.h +engine_dyn.o: ../../include/openssl/rsa.h ../../include/openssl/safestack.h +engine_dyn.o: ../../include/openssl/stack.h ../../include/openssl/symhacks.h +engine_dyn.o: ../../include/openssl/types.h ../../include/openssl/ui.h +engine_dyn.o: ../cryptlib.h engine_dyn.c engine_int.h engine_err.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h engine_err.o: ../../include/openssl/bn.h ../../include/openssl/crypto.h engine_err.o: ../../include/openssl/dh.h ../../include/openssl/dsa.h diff --git a/crypto/engine/engine.h b/crypto/engine/engine.h index 0558f2018c8e1d58d73a15ac432b71384b44eeb1..4c03be3ac25a82f4c3fc7deece73cde50584f5a7 100644 --- a/crypto/engine/engine.h +++ b/crypto/engine/engine.h @@ -73,6 +73,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -487,6 +488,78 @@ void ENGINE_load_engine_ciphers(ENGINE *e); * doesn't have it */ const EVP_CIPHER *ENGINE_get_cipher_by_name(ENGINE *e,const char *name); +/**************************/ +/* DYNAMIC ENGINE SUPPORT */ +/**************************/ + +/* Binary/behaviour compatibility levels */ +#define OSSL_DYNAMIC_VERSION (unsigned long)0x00010100 +/* Binary versions older than this are too old for us (whether we're a loader or + * a loadee) */ +#define OSSL_DYNAMIC_OLDEST (unsigned long)0x00010100 + +/* When compiling an ENGINE entirely as an external shared library, loadable by + * the "dynamic" ENGINE, these types are needed. The 'dynamic_fns' structure + * type provides the calling application's (or library's) error functionality + * and memory management function pointers to the loaded library. These should + * be used/set in the loaded library code so that the loading application's + * 'state' will be used/changed in all operations. */ +typedef void *(*dynamic_MEM_malloc_cb)(size_t); +typedef void *(*dynamic_MEM_realloc_cb)(void *, size_t); +typedef void (*dynamic_MEM_free_cb)(void *); +typedef struct st_dynamic_MEM_fns { + dynamic_MEM_malloc_cb malloc_cb; + dynamic_MEM_realloc_cb realloc_cb; + dynamic_MEM_free_cb free_cb; + } dynamic_MEM_fns; +typedef struct st_dynamic_fns { + const ERR_FNS *err_fns; + const CRYPTO_EX_DATA_IMPL *ex_data_fns; + dynamic_MEM_fns mem_fns; + } dynamic_fns; + +/* The version checking function should be of this prototype. NB: The + * ossl_version value passed in is the OSSL_DYNAMIC_VERSION of the loading code. + * If this function returns zero, it indicates a (potential) version + * incompatibility and the loaded library doesn't believe it can proceed. + * Otherwise, the returned value is the (latest) version supported by the + * loading library. The loader may still decide that the loaded code's version + * is unsatisfactory and could veto the load. The function is expected to + * be implemented with the symbol name "v_check", and a default implementation + * can be fully instantiated with IMPLEMENT_DYNAMIC_CHECK_FN(). */ +typedef unsigned long (*dynamic_v_check_fn)(unsigned long ossl_version); +#define IMPLEMENT_DYNAMIC_CHECK_FN() \ + unsigned long v_check(unsigned long v) { \ + if(v >= OSSL_DYNAMIC_OLDEST) return OSSL_DYNAMIC_VERSION; \ + return 0; } + +/* This function is passed the ENGINE structure to initialise with its own + * function and command settings. It should not adjust the structural or + * functional reference counts. If this function returns zero, (a) the load will + * be aborted, (b) the previous ENGINE state will be memcpy'd back onto the + * structure, and (c) the shared library will be unloaded. So implementations + * should do their own internal cleanup in failure circumstances otherwise they + * could leak. The 'id' parameter, if non-NULL, represents the ENGINE id that + * the loader is looking for. If this is NULL, the shared library can choose to + * return failure or to initialise a 'default' ENGINE. If non-NULL, the shared + * library must initialise only an ENGINE matching the passed 'id'. The function + * is expected to be implemented with the symbol name "bind_engine". A standard + * implementation can be instantiated with IMPLEMENT_DYNAMIC_BIND_FN(fn) where + * the parameter 'fn' is a callback function that populates the ENGINE structure + * and returns an int value (zero for failure). 'fn' should have prototype; + * [static] int fn(ENGINE *e, const char *id); */ +typedef int (*dynamic_bind_engine)(ENGINE *e, const char *id, + const dynamic_fns *fns); +#define IMPLEMENT_DYNAMIC_BIND_FN(fn) \ + int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns) { \ + if(!CRYPTO_set_mem_functions(fns->mem_fns.malloc_cb, \ + fns->mem_fns.realloc_cb, fns->mem_fns.free_cb)) \ + return 0; \ + if(!CRYPTO_set_ex_data_implementation(fns->ex_data_fns)) \ + return 0; \ + if(!ERR_set_implementation(fns->err_fns)) return 0; \ + if(!fn(e,id)) return 0; \ + return 1; } /* Obligatory error function. */ void ERR_load_ENGINE_strings(void); @@ -513,6 +586,9 @@ void ERR_load_ENGINE_strings(void); #define ENGINE_F_CSWIFT_MOD_EXP 102 #define ENGINE_F_CSWIFT_MOD_EXP_CRT 103 #define ENGINE_F_CSWIFT_RSA_MOD_EXP 104 +#define ENGINE_F_DYNAMIC_CTRL 180 +#define ENGINE_F_DYNAMIC_GET_DATA_CTX 181 +#define ENGINE_F_DYNAMIC_LOAD 182 #define ENGINE_F_ENGINE_ADD 105 #define ENGINE_F_ENGINE_BY_ID 106 #define ENGINE_F_ENGINE_CMD_IS_EXECUTABLE 170 @@ -552,6 +628,7 @@ void ERR_load_ENGINE_strings(void); #define ENGINE_F_NURON_FINISH 157 #define ENGINE_F_NURON_INIT 156 #define ENGINE_F_NURON_MOD_EXP 158 +#define ENGINE_F_SET_DATA_CTX 183 #define ENGINE_F_UBSEC_CTRL 176 #define ENGINE_F_UBSEC_DSA_SIGN 163 #define ENGINE_F_UBSEC_DSA_VERIFY 164 @@ -586,6 +663,7 @@ void ERR_load_ENGINE_strings(void); #define ENGINE_R_ID_OR_NAME_MISSING 108 #define ENGINE_R_INIT_FAILED 109 #define ENGINE_R_INTERNAL_LIST_ERROR 110 +#define ENGINE_R_INVALID_ARGUMENT 143 #define ENGINE_R_INVALID_CMD_NAME 137 #define ENGINE_R_INVALID_CMD_NUMBER 138 #define ENGINE_R_MISSING_KEY_COMPONENTS 111 @@ -593,6 +671,7 @@ void ERR_load_ENGINE_strings(void); #define ENGINE_R_NOT_LOADED 112 #define ENGINE_R_NO_CALLBACK 127 #define ENGINE_R_NO_CONTROL_FUNCTION 120 +#define ENGINE_R_NO_INDEX 144 #define ENGINE_R_NO_KEY 124 #define ENGINE_R_NO_LOAD_FUNCTION 125 #define ENGINE_R_NO_REFERENCE 130 @@ -605,6 +684,7 @@ void ERR_load_ENGINE_strings(void); #define ENGINE_R_RSA_NOT_IMPLEMENTED 141 #define ENGINE_R_SIZE_TOO_LARGE_OR_TOO_SMALL 122 #define ENGINE_R_UNIT_FAILURE 115 +#define ENGINE_R_VERSION_INCOMPATIBILITY 145 #ifdef __cplusplus } diff --git a/crypto/engine/engine_dyn.c b/crypto/engine/engine_dyn.c new file mode 100644 index 0000000000000000000000000000000000000000..556e9f3a6a53efe5a5dda114ad1e3ca0994addce --- /dev/null +++ b/crypto/engine/engine_dyn.c @@ -0,0 +1,419 @@ +/* crypto/engine/engine_dyn.c */ +/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + +#include +#include +#include "cryptlib.h" +#include "engine_int.h" +#include +#include + +/* Shared libraries implementing ENGINEs for use by the "dynamic" ENGINE loader + * should implement the hook-up functions with the following prototypes. */ + +/* Our ENGINE handlers */ +static int dynamic_init(ENGINE *e); +static int dynamic_finish(ENGINE *e); +static int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()); +/* Predeclare our context type */ +typedef struct st_dynamic_data_ctx dynamic_data_ctx; +/* The implementation for the important control command */ +static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx); + +#define DYNAMIC_CMD_SO_PATH ENGINE_CMD_BASE +#define DYNAMIC_CMD_NO_VCHECK (ENGINE_CMD_BASE + 1) +#define DYNAMIC_CMD_ENGINE_ID (ENGINE_CMD_BASE + 2) +#define DYNAMIC_CMD_LIST_ADD (ENGINE_CMD_BASE + 3) +#define DYNAMIC_CMD_LOAD (ENGINE_CMD_BASE + 4) + +/* The constants used when creating the ENGINE */ +static const char *engine_dynamic_id = "dynamic"; +static const char *engine_dynamic_name = "Dynamic engine loading support"; +static const ENGINE_CMD_DEFN dynamic_cmd_defns[] = { + {DYNAMIC_CMD_SO_PATH, + "SO_PATH", + "Specifies the path to the new ENGINE shared library", + ENGINE_CMD_FLAG_STRING}, + {DYNAMIC_CMD_NO_VCHECK, + "NO_VCHECK", + "Specifies to continue even if version checking fails (boolean)", + ENGINE_CMD_FLAG_NUMERIC}, + {DYNAMIC_CMD_ENGINE_ID, + "ENGINE_ID", + "Specifies an ENGINE id name for loading", + ENGINE_CMD_FLAG_STRING}, + {DYNAMIC_CMD_LIST_ADD, + "LIST_ADD", + "Whether to add a loaded ENGINE to the internal list (0=no,1=yes,2=mandatory)", + ENGINE_CMD_FLAG_NUMERIC}, + {DYNAMIC_CMD_LOAD, + "LOAD", + "Load up the ENGINE specified by other settings", + ENGINE_CMD_FLAG_NO_INPUT}, + {0, NULL, NULL, 0} + }; + +/* Loading code stores state inside the ENGINE structure via the "ex_data" + * element. We load all our state into a single structure and use that as a + * single context in the "ex_data" stack. */ +struct st_dynamic_data_ctx + { + /* The DSO object we load that supplies the ENGINE code */ + DSO *dynamic_dso; + /* The function pointer to the version checking shared library function */ + dynamic_v_check_fn v_check; + /* The function pointer to the engine-binding shared library function */ + dynamic_bind_engine bind_engine; + /* The default name/path for loading the shared library */ + const char *DYNAMIC_LIBNAME; + /* Whether to continue loading on a version check failure */ + int no_vcheck; + /* If non-NULL, stipulates the 'id' of the ENGINE to be loaded */ + const char *engine_id; + /* If non-zero, a successfully loaded ENGINE should be added to the internal + * ENGINE list. If 2, the add must succeed or the entire load should fail. */ + int list_add_value; + /* The symbol name for the version checking function */ + const char *DYNAMIC_F1; + /* The symbol name for the "initialise ENGINE structure" function */ + const char *DYNAMIC_F2; + }; + +/* This is the "ex_data" index we obtain and reserve for use with our context + * structure. */ +static int dynamic_ex_data_idx = -1; + +/* Because our ex_data element may or may not get allocated depending on whether + * a "first-use" occurs before the ENGINE is freed, we have a memory leak + * problem to solve. We can't declare a "new" handler for the ex_data as we + * don't want a dynamic_data_ctx in *all* ENGINE structures of all types (this + * is a bug in the design of CRYPTO_EX_DATA). As such, we just declare a "free" + * handler and that will get called if an ENGINE is being destroyed and there + * was an ex_data element corresponding to our context type. */ +static void dynamic_data_ctx_free_func(void *parent, void *ptr, + CRYPTO_EX_DATA *ad, int idx, long argl, void *argp) + { + if(ptr) + { + dynamic_data_ctx *ctx = (dynamic_data_ctx *)ptr; + if(ctx->dynamic_dso) + DSO_free(ctx->dynamic_dso); + OPENSSL_free(ctx); + } + } + +/* Construct the per-ENGINE context. We create it blindly and then use a lock to + * check for a race - if so, all but one of the threads "racing" will have + * wasted their time. The alternative involves creating everything inside the + * lock which is far worse. */ +static int dynamic_set_data_ctx(ENGINE *e, dynamic_data_ctx **ctx) + { + dynamic_data_ctx *c; + c = OPENSSL_malloc(sizeof(dynamic_data_ctx)); + if(!ctx) + { + ENGINEerr(ENGINE_F_SET_DATA_CTX,ERR_R_MALLOC_FAILURE); + return 0; + } + memset(c, 0, sizeof(dynamic_data_ctx)); + c->dynamic_dso = NULL; + c->v_check = NULL; + c->bind_engine = NULL; + c->DYNAMIC_LIBNAME = NULL; + c->no_vcheck = 0; + c->engine_id = NULL; + c->list_add_value = 0; + c->DYNAMIC_F1 = "v_check"; + c->DYNAMIC_F2 = "bind_engine"; + CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); + if((*ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e, + dynamic_ex_data_idx)) == NULL) + { + /* Good, we're the first */ + ENGINE_set_ex_data(e, dynamic_ex_data_idx, c); + *ctx = c; + c = NULL; + } + CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); + /* If we lost the race to set the context, c is non-NULL and *ctx is the + * context of the thread that won. */ + if(c) + OPENSSL_free(c); + return 1; + } + +/* This function retrieves the context structure from an ENGINE's "ex_data", or + * if it doesn't exist yet, sets it up. */ +static dynamic_data_ctx *dynamic_get_data_ctx(ENGINE *e) + { + dynamic_data_ctx *ctx; + if(dynamic_ex_data_idx < 0) + { + /* Create and register the ENGINE ex_data, and associate our + * "free" function with it to ensure any allocated contexts get + * freed when an ENGINE goes underground. */ + int new_idx = ENGINE_get_ex_new_index(0, NULL, NULL, NULL, + dynamic_data_ctx_free_func); + if(new_idx == -1) + { + ENGINEerr(ENGINE_F_DYNAMIC_GET_DATA_CTX,ENGINE_R_NO_INDEX); + return NULL; + } + CRYPTO_w_lock(CRYPTO_LOCK_ENGINE); + /* Avoid a race by checking again inside this lock */ + if(dynamic_ex_data_idx < 0) + { + /* Good, someone didn't beat us to it */ + dynamic_ex_data_idx = new_idx; + new_idx = -1; + } + CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE); + /* In theory we could "give back" the index here if + * (new_idx>-1), but it's not possible and wouldn't gain us much + * if it were. */ + } + ctx = (dynamic_data_ctx *)ENGINE_get_ex_data(e, dynamic_ex_data_idx); + /* Check if the context needs to be created */ + if((ctx == NULL) && !dynamic_set_data_ctx(e, &ctx)) + /* "set_data" will set errors if necessary */ + return NULL; + return ctx; + } + +/* As this is only ever called once, there's no need for locking + * (indeed - the lock will already be held by our caller!!!) */ +ENGINE *ENGINE_dynamic() + { + ENGINE *ret = ENGINE_new(); + if(!ret) + return NULL; + if(!ENGINE_set_id(ret, engine_dynamic_id) || + !ENGINE_set_name(ret, engine_dynamic_name) || + !ENGINE_set_init_function(ret, dynamic_init) || + !ENGINE_set_finish_function(ret, dynamic_finish) || + !ENGINE_set_ctrl_function(ret, dynamic_ctrl) || + !ENGINE_set_flags(ret, ENGINE_FLAGS_BY_ID_COPY) || + !ENGINE_set_cmd_defns(ret, dynamic_cmd_defns)) + { + ENGINE_free(ret); + return NULL; + } + return ret; + } + +static int dynamic_init(ENGINE *e) + { + /* We always return failure - the "dyanamic" engine itself can't be used + * for anything. */ + return 0; + } + +static int dynamic_finish(ENGINE *e) + { + /* This should never be called on account of "dynamic_init" always + * failing. */ + return 0; + } + +static int dynamic_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)()) + { + dynamic_data_ctx *ctx = dynamic_get_data_ctx(e); + int initialised; + + if(!ctx) + { + ENGINEerr(ENGINE_F_DYNAMIC_CTRL,ENGINE_R_NOT_LOADED); + return 0; + } + initialised = ((ctx->dynamic_dso == NULL) ? 0 : 1); + /* All our control commands require the ENGINE to be uninitialised */ + if(initialised) + { + ENGINEerr(ENGINE_F_DYNAMIC_CTRL, + ENGINE_R_ALREADY_LOADED); + return 0; + } + switch(cmd) + { + case DYNAMIC_CMD_SO_PATH: + /* a NULL 'p' or a string of zero-length is the same thing */ + if(p && (strlen((const char *)p) < 1)) + p = NULL; + ctx->DYNAMIC_LIBNAME = (const char *)p; + return 1; + case DYNAMIC_CMD_NO_VCHECK: + ctx->no_vcheck = ((i == 0) ? 0 : 1); + return 1; + case DYNAMIC_CMD_ENGINE_ID: + /* a NULL 'p' or a string of zero-length is the same thing */ + if(p && (strlen((const char *)p) < 1)) + p = NULL; + ctx->engine_id = (const char *)p; + return 1; + case DYNAMIC_CMD_LIST_ADD: + if((i < 0) || (i > 2)) + { + ENGINEerr(ENGINE_F_DYNAMIC_CTRL, + ENGINE_R_INVALID_ARGUMENT); + return 0; + } + ctx->list_add_value = (int)i; + return 1; + case DYNAMIC_CMD_LOAD: + return dynamic_load(e, ctx); + default: + break; + } + ENGINEerr(ENGINE_F_DYNAMIC_CTRL,ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED); + return 0; + } + +static int dynamic_load(ENGINE *e, dynamic_data_ctx *ctx) + { + ENGINE cpy; + dynamic_fns fns; + + if(!ctx->DYNAMIC_LIBNAME || ((ctx->dynamic_dso = DSO_load(NULL, + ctx->DYNAMIC_LIBNAME, NULL, 0)) == NULL)) + { + ENGINEerr(ENGINE_F_DYNAMIC_LOAD, + ENGINE_R_DSO_NOT_FOUND); + return 0; + } + /* We have to find a bind function otherwise it'll always end badly */ + if(!(ctx->bind_engine = (dynamic_bind_engine)DSO_bind_func( + ctx->dynamic_dso, ctx->DYNAMIC_F2))) + { + ctx->bind_engine = NULL; + DSO_free(ctx->dynamic_dso); + ctx->dynamic_dso = NULL; + ENGINEerr(ENGINE_F_DYNAMIC_LOAD, + ENGINE_R_DSO_FAILURE); + return 0; + } + /* Do we perform version checking? */ + if(!ctx->no_vcheck) + { + unsigned long vcheck_res = 0; + /* Now we try to find a version checking function and decide how + * to cope with failure if/when it fails. */ + ctx->v_check = (dynamic_v_check_fn)DSO_bind_func( + ctx->dynamic_dso, ctx->DYNAMIC_F1); + if(ctx->v_check) + vcheck_res = ctx->v_check(OSSL_DYNAMIC_VERSION); + /* We fail if the version checker veto'd the load *or* if it is + * deferring to us (by returning its version) and we think it is + * too old. */ + if(vcheck_res < OSSL_DYNAMIC_OLDEST) + { + /* Fail */ + ctx->bind_engine = NULL; + ctx->v_check = NULL; + DSO_free(ctx->dynamic_dso); + ctx->dynamic_dso = NULL; + ENGINEerr(ENGINE_F_DYNAMIC_LOAD, + ENGINE_R_VERSION_INCOMPATIBILITY); + return 0; + } + } + /* First binary copy the ENGINE structure so that we can roll back if + * the hand-over fails */ + memcpy(&cpy, e, sizeof(ENGINE)); + /* Provide the ERR, "ex_data", and memory callbacks so the loaded + * library uses our own state (and locking) rather than its own. */ + fns.err_fns = ERR_get_implementation(); + fns.ex_data_fns = CRYPTO_get_ex_data_implementation(); + CRYPTO_get_mem_functions(&fns.mem_fns.malloc_cb, + &fns.mem_fns.realloc_cb, + &fns.mem_fns.free_cb); + /* Try to bind the ENGINE onto our own ENGINE structure */ + if(!ctx->bind_engine(e, ctx->engine_id, &fns)) + { + ctx->bind_engine = NULL; + ctx->v_check = NULL; + DSO_free(ctx->dynamic_dso); + ctx->dynamic_dso = NULL; + ENGINEerr(ENGINE_F_DYNAMIC_LOAD,ENGINE_R_INIT_FAILED); + /* Copy the original ENGINE structure back */ + memcpy(e, &cpy, sizeof(ENGINE)); + return 0; + } + /* Do we try to add this ENGINE to the internal list too? */ + if(ctx->list_add_value > 0) + { + if(!ENGINE_add(e)) + { + /* Do we tolerate this or fail? */ + if(ctx->list_add_value > 1) + { + /* Fail - NB: By this time, it's too late to + * rollback, and trying to do so allows the + * bind_engine() code to have created leaks. We + * just have to fail where we are, after the + * ENGINE has changed. */ + ENGINEerr(ENGINE_F_DYNAMIC_LOAD, + ENGINE_R_CONFLICTING_ENGINE_ID); + return 0; + } + /* Tolerate */ + ERR_clear_error(); + } + } + return 1; + } diff --git a/crypto/engine/engine_err.c b/crypto/engine/engine_err.c index 6f21e7c66a4cbaa0907f346388839680605ac60c..301415d980069868c7cf7fea0e385818d6d2691e 100644 --- a/crypto/engine/engine_err.c +++ b/crypto/engine/engine_err.c @@ -79,6 +79,9 @@ static ERR_STRING_DATA ENGINE_str_functs[]= {ERR_PACK(0,ENGINE_F_CSWIFT_MOD_EXP,0), "CSWIFT_MOD_EXP"}, {ERR_PACK(0,ENGINE_F_CSWIFT_MOD_EXP_CRT,0), "CSWIFT_MOD_EXP_CRT"}, {ERR_PACK(0,ENGINE_F_CSWIFT_RSA_MOD_EXP,0), "CSWIFT_RSA_MOD_EXP"}, +{ERR_PACK(0,ENGINE_F_DYNAMIC_CTRL,0), "DYNAMIC_CTRL"}, +{ERR_PACK(0,ENGINE_F_DYNAMIC_GET_DATA_CTX,0), "DYNAMIC_GET_DATA_CTX"}, +{ERR_PACK(0,ENGINE_F_DYNAMIC_LOAD,0), "DYNAMIC_LOAD"}, {ERR_PACK(0,ENGINE_F_ENGINE_ADD,0), "ENGINE_add"}, {ERR_PACK(0,ENGINE_F_ENGINE_BY_ID,0), "ENGINE_by_id"}, {ERR_PACK(0,ENGINE_F_ENGINE_CMD_IS_EXECUTABLE,0), "ENGINE_cmd_is_executable"}, @@ -118,6 +121,7 @@ static ERR_STRING_DATA ENGINE_str_functs[]= {ERR_PACK(0,ENGINE_F_NURON_FINISH,0), "NURON_FINISH"}, {ERR_PACK(0,ENGINE_F_NURON_INIT,0), "NURON_INIT"}, {ERR_PACK(0,ENGINE_F_NURON_MOD_EXP,0), "NURON_MOD_EXP"}, +{ERR_PACK(0,ENGINE_F_SET_DATA_CTX,0), "SET_DATA_CTX"}, {ERR_PACK(0,ENGINE_F_UBSEC_CTRL,0), "UBSEC_CTRL"}, {ERR_PACK(0,ENGINE_F_UBSEC_DSA_SIGN,0), "UBSEC_DSA_SIGN"}, {ERR_PACK(0,ENGINE_F_UBSEC_DSA_VERIFY,0), "UBSEC_DSA_VERIFY"}, @@ -155,6 +159,7 @@ static ERR_STRING_DATA ENGINE_str_reasons[]= {ENGINE_R_ID_OR_NAME_MISSING ,"'id' or 'name' missing"}, {ENGINE_R_INIT_FAILED ,"init failed"}, {ENGINE_R_INTERNAL_LIST_ERROR ,"internal list error"}, +{ENGINE_R_INVALID_ARGUMENT ,"invalid argument"}, {ENGINE_R_INVALID_CMD_NAME ,"invalid cmd name"}, {ENGINE_R_INVALID_CMD_NUMBER ,"invalid cmd number"}, {ENGINE_R_MISSING_KEY_COMPONENTS ,"missing key components"}, @@ -162,6 +167,7 @@ static ERR_STRING_DATA ENGINE_str_reasons[]= {ENGINE_R_NOT_LOADED ,"not loaded"}, {ENGINE_R_NO_CALLBACK ,"no callback"}, {ENGINE_R_NO_CONTROL_FUNCTION ,"no control function"}, +{ENGINE_R_NO_INDEX ,"no index"}, {ENGINE_R_NO_KEY ,"no key"}, {ENGINE_R_NO_LOAD_FUNCTION ,"no load function"}, {ENGINE_R_NO_REFERENCE ,"no reference"}, @@ -174,6 +180,7 @@ static ERR_STRING_DATA ENGINE_str_reasons[]= {ENGINE_R_RSA_NOT_IMPLEMENTED ,"rsa not implemented"}, {ENGINE_R_SIZE_TOO_LARGE_OR_TOO_SMALL ,"size too large or too small"}, {ENGINE_R_UNIT_FAILURE ,"unit failure"}, +{ENGINE_R_VERSION_INCOMPATIBILITY ,"version incompatibility"}, {0,NULL} }; diff --git a/crypto/engine/engine_int.h b/crypto/engine/engine_int.h index 126fef746e87daec98513cde96eee7e8f9f8e01d..b51d1914c0d1198da3c66966f6d0a39f71d4c96b 100644 --- a/crypto/engine/engine_int.h +++ b/crypto/engine/engine_int.h @@ -143,6 +143,10 @@ struct engine_st /* Returns a structure of software only methods (the default). */ ENGINE *ENGINE_openssl(); +/* Returns the "dynamic" ENGINE for loading entire ENGINE implementations from + * shared libraries. */ +ENGINE *ENGINE_dynamic(); + #ifndef OPENSSL_NO_HW #ifndef OPENSSL_NO_HW_CSWIFT diff --git a/crypto/engine/engine_list.c b/crypto/engine/engine_list.c index 926ff5a423fa1c8cae1b9718c7ccbfb6983ff3f3..ab5652f293707da9b9cc4323ac5e9ae4894ed2e7 100644 --- a/crypto/engine/engine_list.c +++ b/crypto/engine/engine_list.c @@ -181,17 +181,20 @@ static int engine_list_remove(ENGINE *e) static int engine_internal_check(void) { int toret = 1; - ENGINE *def_engine; + ENGINE *def_engine1, *def_engine2; if(engine_list_flag) return 1; /* This is our first time up, we need to populate the list * with our statically compiled-in engines. */ - def_engine = ENGINE_openssl(); - if(!engine_list_add(def_engine)) + def_engine1 = ENGINE_openssl(); + def_engine2 = ENGINE_dynamic(); + if(!engine_list_add(def_engine1) || + !engine_list_add(def_engine2)) toret = 0; else engine_list_flag = 1; - ENGINE_free_util(def_engine, 0); + ENGINE_free_util(def_engine1, 0); + ENGINE_free_util(def_engine2, 0); return 1; }