summaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
authorYann Ylavic <ylavic@apache.org>2018-06-12 20:11:09 +0000
committerYann Ylavic <ylavic@apache.org>2018-06-12 20:11:09 +0000
commit9aefe5db8512187e194223cd411c1b63bcf0b7a8 (patch)
treedeb423ee592da99470ce93bedf8892ab29ae785e /crypto
parentaf39a670ca00949536be1b3d615d2ec0392d63f3 (diff)
downloadapr-9aefe5db8512187e194223cd411c1b63bcf0b7a8.tar.gz
apr_crypto: follow up to r1833359.
Link underlying crypto libraries (openssl, nss, and commoncrypto) with libapr when the corresponding --with is configured. This allows to initialize, terminate or check whether initialized respectively with apr_crypto_lib_init(), apr_crypto_lib_term() or apr_crypto_lib_is_initialized(). Users can now control the (un)initialization of those libraries, notably when they also use them independently and that doing this multiple times can cause leaks or unexpected behaviour. The initialization code is moved from "apr_crypto_{openssl,nss,commoncrypto}.c" where previously loaded dynamically (DSO) to "apr_crypto_internal.c" which is linked with libapr. Also apr_crypto_prng_init() can make sure the underlying crypto lib is ready. git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1833421 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'crypto')
-rw-r--r--crypto/apr_crypto.c156
-rw-r--r--crypto/apr_crypto_commoncrypto.c15
-rw-r--r--crypto/apr_crypto_internal.c238
-rw-r--r--crypto/apr_crypto_nss.c118
-rw-r--r--crypto/apr_crypto_openssl.c28
-rw-r--r--crypto/apr_crypto_prng.c13
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) {