diff options
author | Richard Levitte <levitte@openssl.org> | 2019-03-20 16:53:19 +0100 |
---|---|---|
committer | Richard Levitte <levitte@openssl.org> | 2019-04-03 11:42:48 +0200 |
commit | abbc2c408385326d9c9cd60b92a6c92b945c1d96 (patch) | |
tree | dff53671d8409ea59c2f0b7dbc704d6dccbf0fb9 /crypto/provider_conf.c | |
parent | ac1055ef13ccb5789e2bed7b9688c8eb16dd05ce (diff) |
Replumbing: add a configuration module for providers
This configuration module supports a configuration structure pretty
much like the engine configuration module, i.e. something like this:
openssl_conf = openssl_init
[openssl_init]
providers = provider_section
[provider_section]
# Configure the provider named "foo"
foo = foo_section
# Configure the provider named "bar"
bar = bar_section
[foo_section]
# Override name given in the provider section
identity = myfoo
# The exact path of the module. This is platform specific
module_path = /opt/openssl/modules/foo.so
# Whether it should be automatically activated. Value is unimportant
activate = whatever
# Anything else goes as well, and becomes parameters that the
# provider can get
what = 1
# sub-sections will be followed as well
ever = ever_section
[ever_section]
cookie = monster
All the configurations in a provider section and its sub-sections
become parameters for the provider to get, i.e. the "foo" provider
will be able to get values for the following keys (with associated
values shown):
identity => myfoo
module_path => /opt/openssl/modules/foo.so
activate => whatever
what => 1
ever.cookie => monster
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/8549)
Diffstat (limited to 'crypto/provider_conf.c')
-rw-r--r-- | crypto/provider_conf.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/crypto/provider_conf.c b/crypto/provider_conf.c new file mode 100644 index 0000000000..9d9b7a1348 --- /dev/null +++ b/crypto/provider_conf.c @@ -0,0 +1,179 @@ +/* + * 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; + + OSSL_TRACE2(PROVIDER_CONF, "PROVIDER conf: %s = %s\n", name, value); + + sect = NCONF_get_section(cnf, value); + if (sect != NULL) { + int i; + char buffer[512]; + size_t buffer_len = 0; + + 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; + } + } else { + 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(PROVIDER_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(PROVIDER_CONF, "PROVIDER conf: %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_new(libctx, name, NULL); + 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_TRACE2(PROVIDER_CONF, "Loading provider module: name %s, value %s\n", + CONF_imodule_get_name(md), 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(NULL, 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(PROVIDER_CONF, "Cleaned up providers\n"); +} + +void ossl_provider_add_conf_module(void) +{ + CONF_module_add("providers", provider_conf_init, provider_conf_deinit); +} |