diff options
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/apr_crypto.c | 156 | ||||
-rw-r--r-- | crypto/apr_crypto_commoncrypto.c | 15 | ||||
-rw-r--r-- | crypto/apr_crypto_internal.c | 238 | ||||
-rw-r--r-- | crypto/apr_crypto_nss.c | 118 | ||||
-rw-r--r-- | crypto/apr_crypto_openssl.c | 28 | ||||
-rw-r--r-- | crypto/apr_crypto_prng.c | 13 |
6 files changed, 413 insertions, 155 deletions
diff --git a/crypto/apr_crypto.c b/crypto/apr_crypto.c index 821775f47..221792d26 100644 --- a/crypto/apr_crypto.c +++ b/crypto/apr_crypto.c @@ -33,6 +33,7 @@ #include "apr_crypto.h" #include "apr_version.h" +static apr_hash_t *crypto_libs = NULL; static apr_hash_t *drivers = NULL; #define ERROR_SIZE 1024 @@ -88,6 +89,7 @@ APR_DECLARE(apr_status_t) apr_crypto_init(apr_pool_t *pool) { apr_status_t rv; apr_pool_t *parent; + int flags = 0; if (drivers != NULL) { return APR_SUCCESS; @@ -110,7 +112,10 @@ APR_DECLARE(apr_status_t) apr_crypto_init(apr_pool_t *pool) /* apr_crypto_prng_init() may already have been called with * non-default parameters, so ignore APR_EREINIT. */ - rv = apr_crypto_prng_init(pool, 0, NULL, 0); +#if APR_HAS_THREADS + flags = APR_CRYPTO_PRNG_PER_THREAD; +#endif + rv = apr_crypto_prng_init(pool, 0, NULL, flags); if (rv != APR_SUCCESS && rv != APR_EREINIT) { return rv; } @@ -241,11 +246,15 @@ APR_DECLARE(apr_status_t) apr_crypto_get_driver( rv = APR_SUCCESS; if (d->init) { rv = d->init(pool, params, result); + if (rv == APR_EREINIT) { + rv = APR_SUCCESS; + } } - if (APR_SUCCESS == rv) { + if (rv == APR_SUCCESS) { *driver = symbol; name = apr_pstrdup(pool, name); apr_hash_set(drivers, name, APR_HASH_KEY_STRING, *driver); + rv = APR_SUCCESS; } } apu_dso_mutex_unlock(); @@ -296,6 +305,149 @@ APR_DECLARE(apr_status_t) apr_crypto_get_driver( return rv; } +static apr_status_t crypto_libs_cleanup(void *arg) +{ + apr_hash_index_t *hi; + + for (hi = apr_hash_first(NULL, crypto_libs); hi; hi = apr_hash_next(hi)) { + const char *name = apr_hash_this_key(hi); + if (name) { + apr_crypto_lib_term(name); + } + } + crypto_libs = NULL; + + return APR_SUCCESS; +} + +APR_DECLARE(int) apr_crypto_lib_is_initialized(const char *name) +{ + return crypto_libs && apr_hash_get(crypto_libs, name, APR_HASH_KEY_STRING); +} + +APR_DECLARE(apr_status_t) apr_crypto_lib_init(const char *name, + const char *params, + const apu_err_t **result, + apr_pool_t *pool) +{ + apr_status_t rv; + apr_pool_t *parent; + + if (!name) { + return APR_EINVAL; + } + + if (apr_crypto_lib_is_initialized(name)) { + return APR_EREINIT; + } + + while ((parent = apr_pool_parent_get(pool))) { + pool = parent; + } + + if (!crypto_libs) { + crypto_libs = apr_hash_make(pool); + if (!crypto_libs) { + return APR_ENOMEM; + } + apr_pool_cleanup_register(pool, NULL, crypto_libs_cleanup, + apr_pool_cleanup_null); + } + + rv = APR_ENOTIMPL; +#if APU_HAVE_OPENSSL + if (!strcmp(name, "openssl")) { + rv = apr__crypto_openssl_init(params, result, pool); + } + else +#endif +#if APU_HAVE_NSS + if (!strcmp(name, "nss")) { + rv = apr__crypto_nss_init(params, result, pool); + } + else +#endif +#if APU_HAVE_COMMONCRYPTO + if (!strcmp(name, "commoncrypto")) { + rv = apr__crypto_commoncrypto_init(params, result, pool); + } + else +#endif +#if APU_HAVE_MSCAPI + if (!strcmp(name, "mscapi")) { + rv = apr__crypto_mscapi_init(params, result, pool); + } + else +#endif +#if APU_HAVE_MSCNG + if (!strcmp(name, "mscng")) { + rv = apr__crypto_mscng_init(params, result, pool); + } + else +#endif + ; + if (rv == APR_SUCCESS) { + name = apr_pstrdup(pool, name); + apr_hash_set(crypto_libs, name, APR_HASH_KEY_STRING, name); + } + return rv; +} + +APR_DECLARE(apr_status_t) apr_crypto_lib_term(const char *name) +{ + apr_status_t rv; + + if (!crypto_libs) { + return APR_EINIT; + } + + if (!name) { + apr_pool_t *pool = apr_hash_pool_get(crypto_libs); + return apr_pool_cleanup_run(pool, NULL, crypto_libs_cleanup); + } + + if (!apr_hash_get(crypto_libs, name, APR_HASH_KEY_STRING)) { + return APR_EINIT; + } + + rv = APR_ENOTIMPL; +#if APU_HAVE_OPENSSL + if (!strcmp(name, "openssl")) { + rv = apr__crypto_openssl_term(); + } + else +#endif +#if APU_HAVE_NSS + if (!strcmp(name, "nss")) { + rv = apr__crypto_nss_term(); + } + else +#endif +#if APU_HAVE_COMMONCRYPTO + if (!strcmp(name, "commoncrypto")) { + rv = apr__crypto_commoncrypto_term(); + } + else +#endif +#if APU_HAVE_MSCAPI + if (!strcmp(name, "mscapi")) { + rv = apr__crypto_mscapi_term(); + } + else +#endif +#if APU_HAVE_MSCNG + if (!strcmp(name, "mscng")) { + rv = apr__crypto_mscng_term(); + } + else +#endif + ; + if (rv == APR_SUCCESS) { + apr_hash_set(crypto_libs, name, APR_HASH_KEY_STRING, NULL); + } + return rv; +} + /** * @brief Return the name of the driver. * diff --git a/crypto/apr_crypto_commoncrypto.c b/crypto/apr_crypto_commoncrypto.c index 913893306..83886bce3 100644 --- a/crypto/apr_crypto_commoncrypto.c +++ b/crypto/apr_crypto_commoncrypto.c @@ -95,25 +95,16 @@ static apr_status_t crypto_error(const apu_err_t **result, */ static apr_status_t crypto_shutdown(void) { - return APR_SUCCESS; -} - -static apr_status_t crypto_shutdown_helper(void *data) -{ - return crypto_shutdown(); + return apr_crypto_lib_term("commoncrypto"); } /** * Initialise the crypto library and perform one time initialisation. */ static apr_status_t crypto_init(apr_pool_t *pool, const char *params, - const apu_err_t **result) + const apu_err_t **result) { - - apr_pool_cleanup_register(pool, pool, crypto_shutdown_helper, - apr_pool_cleanup_null); - - return APR_SUCCESS; + return apr_crypto_lib_init("commoncrypto", params, result, pool); } /** diff --git a/crypto/apr_crypto_internal.c b/crypto/apr_crypto_internal.c new file mode 100644 index 000000000..66e340c05 --- /dev/null +++ b/crypto/apr_crypto_internal.c @@ -0,0 +1,238 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "apu.h" +#include "apr_crypto.h" +#include "apr_crypto_internal.h" + +#if APU_HAVE_CRYPTO + +#if APU_HAVE_OPENSSL + +#include <openssl/crypto.h> +#include <openssl/engine.h> +#include <openssl/evp.h> + +apr_status_t apr__crypto_openssl_init(const char *params, + const apu_err_t **result, + apr_pool_t *pool) +{ +#if APR_USE_OPENSSL_PRE_1_1_API + (void)CRYPTO_malloc_init(); +#else + OPENSSL_malloc_init(); +#endif + ERR_load_crypto_strings(); + /* SSL_load_error_strings(); */ + OpenSSL_add_all_algorithms(); + ENGINE_load_builtin_engines(); + ENGINE_register_all_complete(); + + return APR_SUCCESS; +} + +apr_status_t apr__crypto_openssl_term(void) +{ + ERR_free_strings(); + EVP_cleanup(); + ENGINE_cleanup(); + + return APR_SUCCESS; +} + +#endif /* APU_HAVE_OPENSSL */ + + +#if APU_HAVE_NSS + +#include <prerror.h> + +#ifdef HAVE_NSS_NSS_H +#include <nss/nss.h> +#endif +#ifdef HAVE_NSS_H +#include <nss.h> +#endif + +apr_status_t apr__crypto_nss_init(const char *params, + const apu_err_t **result, + apr_pool_t *pool) +{ + SECStatus s; + const char *dir = NULL; + const char *keyPrefix = NULL; + const char *certPrefix = NULL; + const char *secmod = NULL; + int noinit = 0; + PRUint32 flags = 0; + + struct { + const char *field; + const char *value; + int set; + } fields[] = { + { "dir", NULL, 0 }, + { "key3", NULL, 0 }, + { "cert7", NULL, 0 }, + { "secmod", NULL, 0 }, + { "noinit", NULL, 0 }, + { NULL, NULL, 0 } + }; + const char *ptr; + size_t klen; + char **elts = NULL; + char *elt; + int i = 0, j; + apr_status_t status; + + if (params) { + if (APR_SUCCESS != (status = apr_tokenize_to_argv(params, &elts, pool))) { + return status; + } + while ((elt = elts[i])) { + ptr = strchr(elt, '='); + if (ptr) { + for (klen = ptr - elt; klen && apr_isspace(elt[klen - 1]); --klen) + ; + ptr++; + } + else { + for (klen = strlen(elt); klen && apr_isspace(elt[klen - 1]); --klen) + ; + } + elt[klen] = 0; + + for (j = 0; fields[j].field != NULL; ++j) { + if (klen && !strcasecmp(fields[j].field, elt)) { + fields[j].set = 1; + if (ptr) { + fields[j].value = ptr; + } + break; + } + } + + i++; + } + dir = fields[0].value; + keyPrefix = fields[1].value; + certPrefix = fields[2].value; + secmod = fields[3].value; + noinit = fields[4].set; + } + + /* if we've been asked to bypass, do so here */ + if (noinit) { + return APR_SUCCESS; + } + + /* sanity check - we can only initialise NSS once */ + if (NSS_IsInitialized()) { + return APR_EREINIT; + } + + if (keyPrefix || certPrefix || secmod) { + s = NSS_Initialize(dir, certPrefix, keyPrefix, secmod, flags); + } + else if (dir) { + s = NSS_InitReadWrite(dir); + } + else { + s = NSS_NoDB_Init(NULL); + } + if (s != SECSuccess) { + if (result) { + /* Note: all memory must be owned by the caller, in case we're unloaded */ + apu_err_t *err = apr_pcalloc(pool, sizeof(apu_err_t)); + err->rc = PR_GetError(); + err->msg = apr_pstrdup(pool, PR_ErrorToName(s)); + err->reason = apr_pstrdup(pool, "Error during 'nss' initialisation"); + *result = err; + } + + return APR_ECRYPT; + } + + return APR_SUCCESS; +} + +apr_status_t apr__crypto_nss_term(void) +{ + if (NSS_IsInitialized()) { + SECStatus s = NSS_Shutdown(); + if (s != SECSuccess) { + fprintf(stderr, "NSS failed to shutdown, possible leak: %d: %s", + PR_GetError(), PR_ErrorToName(s)); + return APR_EINIT; + } + } + return APR_SUCCESS; +} + +#endif /* APU_HAVE_NSS */ + + +#if APU_HAVE_COMMONCRYPTO + +apr_status_t apr__crypto_commoncrypto_init(const char *params, + const apu_err_t **result, + apr_pool_t *pool) +{ + return APR_SUCCESS; +} + +apr_status_t apr__crypto_commoncrypto_term(void) +{ + return APR_SUCCESS; +} + +#endif /* APU_HAVE_COMMONCRYPTO */ + + +#if APU_HAVE_MSCAPI + +apr_status_t apr__crypto_commoncrypto_init(const char *params, + const apu_err_t **result, + apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} + +apr_status_t apr__crypto_commoncrypto_term(void) +{ + return APR_ENOTIMPL; +} + +#endif /* APU_HAVE_MSCAPI */ + + +#if APU_HAVE_MSCNG + +apr_status_t apr__crypto_commoncrypto_init(const char *params, + const apu_err_t **result, + apr_pool_t *pool) +{ + return APR_ENOTIMPL; +} + +apr_status_t apr__crypto_commoncrypto_term(void) +{ + return APR_ENOTIMPL; +} + +#endif /* APU_HAVE_MSCNG */ + +#endif /* APU_HAVE_CRYPTO */ diff --git a/crypto/apr_crypto_nss.c b/crypto/apr_crypto_nss.c index 1c3bb2c6a..52898f69d 100644 --- a/crypto/apr_crypto_nss.c +++ b/crypto/apr_crypto_nss.c @@ -112,128 +112,16 @@ static apr_status_t crypto_error(const apu_err_t **result, */ static apr_status_t crypto_shutdown(void) { - if (NSS_IsInitialized()) { - SECStatus s = NSS_Shutdown(); - if (s != SECSuccess) { - fprintf(stderr, "NSS failed to shutdown, possible leak: %d: %s", - PR_GetError(), PR_ErrorToName(s)); - return APR_EINIT; - } - } - return APR_SUCCESS; -} - -static apr_status_t crypto_shutdown_helper(void *data) -{ - return crypto_shutdown(); + return apr_crypto_lib_term("nss"); } /** * Initialise the crypto library and perform one time initialisation. */ static apr_status_t crypto_init(apr_pool_t *pool, const char *params, - const apu_err_t **result) + const apu_err_t **result) { - SECStatus s; - const char *dir = NULL; - const char *keyPrefix = NULL; - const char *certPrefix = NULL; - const char *secmod = NULL; - int noinit = 0; - PRUint32 flags = 0; - - struct { - const char *field; - const char *value; - int set; - } fields[] = { - { "dir", NULL, 0 }, - { "key3", NULL, 0 }, - { "cert7", NULL, 0 }, - { "secmod", NULL, 0 }, - { "noinit", NULL, 0 }, - { NULL, NULL, 0 } - }; - const char *ptr; - size_t klen; - char **elts = NULL; - char *elt; - int i = 0, j; - apr_status_t status; - - if (params) { - if (APR_SUCCESS != (status = apr_tokenize_to_argv(params, &elts, pool))) { - return status; - } - while ((elt = elts[i])) { - ptr = strchr(elt, '='); - if (ptr) { - for (klen = ptr - elt; klen && apr_isspace(elt[klen - 1]); --klen) - ; - ptr++; - } - else { - for (klen = strlen(elt); klen && apr_isspace(elt[klen - 1]); --klen) - ; - } - elt[klen] = 0; - - for (j = 0; fields[j].field != NULL; ++j) { - if (klen && !strcasecmp(fields[j].field, elt)) { - fields[j].set = 1; - if (ptr) { - fields[j].value = ptr; - } - break; - } - } - - i++; - } - dir = fields[0].value; - keyPrefix = fields[1].value; - certPrefix = fields[2].value; - secmod = fields[3].value; - noinit = fields[4].set; - } - - /* if we've been asked to bypass, do so here */ - if (noinit) { - return APR_SUCCESS; - } - - /* sanity check - we can only initialise NSS once */ - if (NSS_IsInitialized()) { - return APR_EREINIT; - } - - if (keyPrefix || certPrefix || secmod) { - s = NSS_Initialize(dir, certPrefix, keyPrefix, secmod, flags); - } - else if (dir) { - s = NSS_InitReadWrite(dir); - } - else { - s = NSS_NoDB_Init(NULL); - } - if (s != SECSuccess) { - if (result) { - /* Note: all memory must be owned by the caller, in case we're unloaded */ - apu_err_t *err = apr_pcalloc(pool, sizeof(apu_err_t)); - err->rc = PR_GetError(); - err->msg = apr_pstrdup(pool, PR_ErrorToName(s)); - err->reason = apr_pstrdup(pool, "Error during 'nss' initialisation"); - *result = err; - } - - return APR_ECRYPT; - } - - apr_pool_cleanup_register(pool, pool, crypto_shutdown_helper, - apr_pool_cleanup_null); - - return APR_SUCCESS; - + return apr_crypto_lib_init("nss", params, result, pool); } /** diff --git a/crypto/apr_crypto_openssl.c b/crypto/apr_crypto_openssl.c index 76f318411..7d9699242 100644 --- a/crypto/apr_crypto_openssl.c +++ b/crypto/apr_crypto_openssl.c @@ -114,38 +114,16 @@ static apr_status_t crypto_error(const apu_err_t **result, */ static apr_status_t crypto_shutdown(void) { - ERR_free_strings(); - EVP_cleanup(); - ENGINE_cleanup(); - return APR_SUCCESS; -} - -static apr_status_t crypto_shutdown_helper(void *data) -{ - return crypto_shutdown(); + return apr_crypto_lib_term("openssl"); } /** * Initialise the crypto library and perform one time initialisation. */ static apr_status_t crypto_init(apr_pool_t *pool, const char *params, - const apu_err_t **result) + const apu_err_t **result) { -#if APR_USE_OPENSSL_PRE_1_1_API - (void)CRYPTO_malloc_init(); -#else - OPENSSL_malloc_init(); -#endif - ERR_load_crypto_strings(); - /* SSL_load_error_strings(); */ - OpenSSL_add_all_algorithms(); - ENGINE_load_builtin_engines(); - ENGINE_register_all_complete(); - - apr_pool_cleanup_register(pool, pool, crypto_shutdown_helper, - apr_pool_cleanup_null); - - return APR_SUCCESS; + return apr_crypto_lib_init("openssl", params, result, pool); } /** diff --git a/crypto/apr_crypto_prng.c b/crypto/apr_crypto_prng.c index b136212c3..2c2f15f2d 100644 --- a/crypto/apr_crypto_prng.c +++ b/crypto/apr_crypto_prng.c @@ -57,6 +57,11 @@ typedef EVP_CIPHER_CTX cprng_stream_ctx_t; +static apr_status_t cprng_lib_init(apr_pool_t *pool) +{ + return apr_crypto_lib_init("openssl", NULL, NULL, pool); +} + static apr_status_t cprng_stream_ctx_make(cprng_stream_ctx_t **pctx) { EVP_CIPHER_CTX *ctx; @@ -154,15 +159,21 @@ APR_DECLARE(apr_status_t) apr_crypto_prng_init(apr_pool_t *pool, const unsigned char seed[], int flags) { + apr_status_t rv; + if (cprng_global) { return APR_EREINIT; } + rv = cprng_lib_init(pool); + if (rv != APR_SUCCESS && rv != APR_EREINIT) { + return rv; + } + if (flags & APR_CRYPTO_PRNG_PER_THREAD) { #if !APR_HAS_THREADS return APR_ENOTIMPL; #else - apr_status_t rv; rv = apr_threadkey_private_create(&cprng_thread_key, cprng_thread_destroy, pool); if (rv != APR_SUCCESS) { |