openssl/crypto/provider_conf.c
Shane Lontis 22e27978b2 Add support for passing the libctx to the config loader
The self tests for the fips module are triggered on startup and they need to know the
core's libctx in order to function correctly. As the provider can be autoloaded via configuration
it then needs to propagate the callers libctx down to the provider via the config load.

Note that OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, ..) is still called, but will only load the default
configuration if the OPENSSL_CONF environment variable is set.

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/11240)
2020-03-20 20:25:39 +10:00

187 lines
5.2 KiB
C

/*
* Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <string.h>
#include <openssl/trace.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <openssl/safestack.h>
#include "internal/provider.h"
/* PROVIDER config module */
DEFINE_STACK_OF(OSSL_PROVIDER)
static STACK_OF(OSSL_PROVIDER) *activated_providers = NULL;
static const char *skip_dot(const char *name)
{
const char *p = strchr(name, '.');
if (p != NULL)
return p + 1;
return name;
}
static int provider_conf_params(OSSL_PROVIDER *prov,
const char *name, const char *value,
const CONF *cnf)
{
STACK_OF(CONF_VALUE) *sect;
int ok = 1;
sect = NCONF_get_section(cnf, value);
if (sect != NULL) {
int i;
char buffer[512];
size_t buffer_len = 0;
OSSL_TRACE1(CONF, "Provider params: start section %s\n", value);
if (name != NULL) {
OPENSSL_strlcpy(buffer, name, sizeof(buffer));
OPENSSL_strlcat(buffer, ".", sizeof(buffer));
buffer_len = strlen(buffer);
}
for (i = 0; i < sk_CONF_VALUE_num(sect); i++) {
CONF_VALUE *sectconf = sk_CONF_VALUE_value(sect, i);
if (buffer_len + strlen(sectconf->name) >= sizeof(buffer))
return 0;
buffer[buffer_len] = '\0';
OPENSSL_strlcat(buffer, sectconf->name, sizeof(buffer));
if (!provider_conf_params(prov, buffer, sectconf->value, cnf))
return 0;
}
OSSL_TRACE1(CONF, "Provider params: finish section %s\n", value);
} else {
OSSL_TRACE2(CONF, "Provider params: %s = %s\n", name, value);
ok = ossl_provider_add_parameter(prov, name, value);
}
return ok;
}
static int provider_conf_load(OPENSSL_CTX *libctx, const char *name,
const char *value, const CONF *cnf)
{
int i;
STACK_OF(CONF_VALUE) *ecmds;
int soft = 0;
OSSL_PROVIDER *prov = NULL;
const char *path = NULL;
long activate = 0;
int ok = 0;
name = skip_dot(name);
OSSL_TRACE1(CONF, "Configuring provider %s\n", name);
/* Value is a section containing PROVIDER commands */
ecmds = NCONF_get_section(cnf, value);
if (!ecmds) {
CRYPTOerr(CRYPTO_F_PROVIDER_CONF_LOAD, CRYPTO_R_PROVIDER_SECTION_ERROR);
return 0;
}
/* Find the needed data first */
for (i = 0; i < sk_CONF_VALUE_num(ecmds); i++) {
CONF_VALUE *ecmd = sk_CONF_VALUE_value(ecmds, i);
const char *confname = skip_dot(ecmd->name);
const char *confvalue = ecmd->value;
OSSL_TRACE2(CONF, "Provider command: %s = %s\n",
confname, confvalue);
/* First handle some special pseudo confs */
/* Override provider name to use */
if (strcmp(confname, "identity") == 0)
name = confvalue;
else if (strcmp(confname, "soft_load") == 0)
soft = 1;
/* Load a dynamic PROVIDER */
else if (strcmp(confname, "module") == 0)
path = confvalue;
else if (strcmp(confname, "activate") == 0)
activate = 1;
}
prov = ossl_provider_find(libctx, name, 1);
if (prov == NULL)
prov = ossl_provider_new(libctx, name, NULL, 1);
if (prov == NULL) {
if (soft)
ERR_clear_error();
return 0;
}
if (path != NULL)
ossl_provider_set_module_path(prov, path);
ok = provider_conf_params(prov, NULL, value, cnf);
if (ok && activate) {
if (!ossl_provider_activate(prov)) {
ok = 0;
} else {
if (activated_providers == NULL)
activated_providers = sk_OSSL_PROVIDER_new_null();
sk_OSSL_PROVIDER_push(activated_providers, prov);
ok = 1;
}
}
if (!(activate && ok))
ossl_provider_free(prov);
return ok;
}
static int provider_conf_init(CONF_IMODULE *md, const CONF *cnf)
{
STACK_OF(CONF_VALUE) *elist;
CONF_VALUE *cval;
int i;
OSSL_TRACE1(CONF, "Loading providers module: section %s\n",
CONF_imodule_get_value(md));
/* Value is a section containing PROVIDERs to configure */
elist = NCONF_get_section(cnf, CONF_imodule_get_value(md));
if (!elist) {
CRYPTOerr(CRYPTO_F_PROVIDER_CONF_INIT,
CRYPTO_R_PROVIDER_SECTION_ERROR);
return 0;
}
for (i = 0; i < sk_CONF_VALUE_num(elist); i++) {
cval = sk_CONF_VALUE_value(elist, i);
if (!provider_conf_load(cnf->libctx, cval->name, cval->value, cnf))
return 0;
}
return 1;
}
static void provider_conf_deinit(CONF_IMODULE *md)
{
sk_OSSL_PROVIDER_pop_free(activated_providers, ossl_provider_free);
activated_providers = NULL;
OSSL_TRACE(CONF, "Cleaned up providers\n");
}
void ossl_provider_add_conf_module(void)
{
OSSL_TRACE(CONF, "Adding config module 'providers'\n");
CONF_module_add("providers", provider_conf_init, provider_conf_deinit);
}