summaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
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) {