]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/provider_conf.c
Replumbing: add a configuration module for providers
[thirdparty/openssl.git] / crypto / provider_conf.c
CommitLineData
abbc2c40
RL
1/*
2 * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include <string.h>
11#include <openssl/trace.h>
12#include <openssl/err.h>
13#include <openssl/conf.h>
14#include <openssl/safestack.h>
15#include "internal/provider.h"
16
17/* PROVIDER config module */
18
19DEFINE_STACK_OF(OSSL_PROVIDER)
20static STACK_OF(OSSL_PROVIDER) *activated_providers = NULL;
21
22static const char *skip_dot(const char *name)
23{
24 const char *p = strchr(name, '.');
25
26 if (p != NULL)
27 return p + 1;
28 return name;
29}
30
31static int provider_conf_params(OSSL_PROVIDER *prov,
32 const char *name, const char *value,
33 const CONF *cnf)
34{
35 STACK_OF(CONF_VALUE) *sect;
36 int ok = 1;
37
38 OSSL_TRACE2(PROVIDER_CONF, "PROVIDER conf: %s = %s\n", name, value);
39
40 sect = NCONF_get_section(cnf, value);
41 if (sect != NULL) {
42 int i;
43 char buffer[512];
44 size_t buffer_len = 0;
45
46 if (name != NULL) {
47 OPENSSL_strlcpy(buffer, name, sizeof(buffer));
48 OPENSSL_strlcat(buffer, ".", sizeof(buffer));
49 buffer_len = strlen(buffer);
50 }
51
52 for (i = 0; i < sk_CONF_VALUE_num(sect); i++) {
53 CONF_VALUE *sectconf = sk_CONF_VALUE_value(sect, i);
54
55 if (buffer_len + strlen(sectconf->name) >= sizeof(buffer))
56 return 0;
57 buffer[buffer_len] = '\0';
58 OPENSSL_strlcat(buffer, sectconf->name, sizeof(buffer));
59 if (!provider_conf_params(prov, buffer, sectconf->value, cnf))
60 return 0;
61 }
62 } else {
63 ok = ossl_provider_add_parameter(prov, name, value);
64 }
65
66 return ok;
67}
68
69static int provider_conf_load(OPENSSL_CTX *libctx, const char *name,
70 const char *value, const CONF *cnf)
71{
72 int i;
73 STACK_OF(CONF_VALUE) *ecmds;
74 int soft = 0;
75 OSSL_PROVIDER *prov = NULL;
76 const char *path = NULL;
77 long activate = 0;
78 int ok = 0;
79
80 name = skip_dot(name);
81 OSSL_TRACE1(PROVIDER_CONF, "Configuring provider %s\n", name);
82 /* Value is a section containing PROVIDER commands */
83 ecmds = NCONF_get_section(cnf, value);
84
85 if (!ecmds) {
86 CRYPTOerr(CRYPTO_F_PROVIDER_CONF_LOAD, CRYPTO_R_PROVIDER_SECTION_ERROR);
87 return 0;
88 }
89
90 /* Find the needed data first */
91 for (i = 0; i < sk_CONF_VALUE_num(ecmds); i++) {
92 CONF_VALUE *ecmd = sk_CONF_VALUE_value(ecmds, i);
93 const char *confname = skip_dot(ecmd->name);
94 const char *confvalue = ecmd->value;
95
96 OSSL_TRACE2(PROVIDER_CONF, "PROVIDER conf: %s = %s\n",
97 confname, confvalue);
98
99 /* First handle some special pseudo confs */
100
101 /* Override provider name to use */
102 if (strcmp(confname, "identity") == 0)
103 name = confvalue;
104 else if (strcmp(confname, "soft_load") == 0)
105 soft = 1;
106 /* Load a dynamic PROVIDER */
107 else if (strcmp(confname, "module") == 0)
108 path = confvalue;
109 else if (strcmp(confname, "activate") == 0)
110 activate = 1;
111 }
112
113 prov = ossl_provider_new(libctx, name, NULL);
114 if (prov == NULL) {
115 if (soft)
116 ERR_clear_error();
117 return 0;
118 }
119
120 if (path != NULL)
121 ossl_provider_set_module_path(prov, path);
122
123 ok = provider_conf_params(prov, NULL, value, cnf);
124
125 if (ok && activate) {
126 if (!ossl_provider_activate(prov)) {
127 ok = 0;
128 } else {
129 if (activated_providers == NULL)
130 activated_providers = sk_OSSL_PROVIDER_new_null();
131 sk_OSSL_PROVIDER_push(activated_providers, prov);
132 ok = 1;
133 }
134 }
135
136 if (!(activate && ok))
137 ossl_provider_free(prov);
138
139 return ok;
140}
141
142static int provider_conf_init(CONF_IMODULE *md, const CONF *cnf)
143{
144 STACK_OF(CONF_VALUE) *elist;
145 CONF_VALUE *cval;
146 int i;
147
148 OSSL_TRACE2(PROVIDER_CONF, "Loading provider module: name %s, value %s\n",
149 CONF_imodule_get_name(md), CONF_imodule_get_value(md));
150 /* Value is a section containing PROVIDERs to configure */
151 elist = NCONF_get_section(cnf, CONF_imodule_get_value(md));
152
153 if (!elist) {
154 CRYPTOerr(CRYPTO_F_PROVIDER_CONF_INIT,
155 CRYPTO_R_PROVIDER_SECTION_ERROR);
156 return 0;
157 }
158
159 for (i = 0; i < sk_CONF_VALUE_num(elist); i++) {
160 cval = sk_CONF_VALUE_value(elist, i);
161 if (!provider_conf_load(NULL, cval->name, cval->value, cnf))
162 return 0;
163 }
164
165 return 1;
166}
167
168
169static void provider_conf_deinit(CONF_IMODULE *md)
170{
171 sk_OSSL_PROVIDER_pop_free(activated_providers, ossl_provider_free);
172 activated_providers = NULL;
173 OSSL_TRACE(PROVIDER_CONF, "Cleaned up providers\n");
174}
175
176void ossl_provider_add_conf_module(void)
177{
178 CONF_module_add("providers", provider_conf_init, provider_conf_deinit);
179}