]>
Commit | Line | Data |
---|---|---|
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 | ||
19 | DEFINE_STACK_OF(OSSL_PROVIDER) | |
20 | static STACK_OF(OSSL_PROVIDER) *activated_providers = NULL; | |
21 | ||
22 | static 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 | ||
31 | static 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 | ||
69 | static 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 | ||
142 | static 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 | ||
169 | static 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 | ||
176 | void ossl_provider_add_conf_module(void) | |
177 | { | |
178 | CONF_module_add("providers", provider_conf_init, provider_conf_deinit); | |
179 | } |