]>
Commit | Line | Data |
---|---|---|
70a1f7b4 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 "internal/cryptlib.h" | |
11 | #include "internal/nelem.h" | |
25f2138b DMSP |
12 | #include "crypto/evp.h" |
13 | #include "crypto/asn1.h" | |
70a1f7b4 | 14 | #include "internal/provider.h" |
706457b7 | 15 | #include "evp_local.h" |
70a1f7b4 RL |
16 | |
17 | static OSSL_PARAM *paramdefs_to_params(const OSSL_PARAM *paramdefs) | |
18 | { | |
19 | size_t cnt; | |
20 | const OSSL_PARAM *p; | |
21 | OSSL_PARAM *params, *q; | |
22 | ||
23 | for (cnt = 1, p = paramdefs; p->key != NULL; p++, cnt++) | |
24 | continue; | |
25 | ||
26 | params = OPENSSL_zalloc(cnt * sizeof(*params)); | |
27 | ||
28 | for (p = paramdefs, q = params; ; p++, q++) { | |
29 | *q = *p; | |
30 | if (p->key == NULL) | |
31 | break; | |
32 | ||
33 | q->data = NULL; /* In case the provider used it */ | |
34 | q->return_size = 0; | |
35 | } | |
36 | ||
37 | return params; | |
38 | } | |
39 | ||
40 | typedef union align_block_un { | |
41 | OSSL_UNION_ALIGN; | |
42 | } ALIGN_BLOCK; | |
43 | ||
44 | #define ALIGN_SIZE sizeof(ALIGN_BLOCK) | |
45 | ||
46 | static void *allocate_params_space(OSSL_PARAM *params) | |
47 | { | |
48 | unsigned char *data = NULL; | |
49 | size_t space; | |
50 | OSSL_PARAM *p; | |
51 | ||
52 | for (space = 0, p = params; p->key != NULL; p++) | |
53 | space += ((p->return_size + ALIGN_SIZE - 1) / ALIGN_SIZE) * ALIGN_SIZE; | |
54 | ||
02f060d1 RL |
55 | if (space == 0) |
56 | return NULL; | |
57 | ||
70a1f7b4 RL |
58 | data = OPENSSL_zalloc(space); |
59 | ||
60 | for (space = 0, p = params; p->key != NULL; p++) { | |
61 | p->data = data + space; | |
62 | space += ((p->return_size + ALIGN_SIZE - 1) / ALIGN_SIZE) * ALIGN_SIZE; | |
63 | } | |
64 | ||
65 | return data; | |
66 | } | |
67 | ||
02f060d1 RL |
68 | void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt, |
69 | int want_domainparams) | |
70a1f7b4 | 70 | { |
02f060d1 | 71 | void *provdata = NULL; |
70a1f7b4 RL |
72 | size_t i, j; |
73 | ||
74 | /* | |
75 | * If there is an underlying legacy key and it has changed, invalidate | |
76 | * the cache of provider keys. | |
77 | */ | |
78 | if (pk->pkey.ptr != NULL) { | |
79 | /* | |
80 | * If there is no dirty counter, this key can't be used with | |
81 | * providers. | |
82 | */ | |
83 | if (pk->ameth->dirty_cnt == NULL) | |
84 | return NULL; | |
85 | ||
86 | if (pk->ameth->dirty_cnt(pk) != pk->dirty_cnt_copy) | |
4cae07fe | 87 | evp_keymgmt_clear_pkey_cache(pk); |
70a1f7b4 RL |
88 | } |
89 | ||
90 | /* | |
91 | * See if we have exported to this provider already. | |
92 | * If we have, return immediately. | |
93 | */ | |
94 | for (i = 0; | |
95 | i < OSSL_NELEM(pk->pkeys) && pk->pkeys[i].keymgmt != NULL; | |
96 | i++) { | |
02f060d1 RL |
97 | if (keymgmt == pk->pkeys[i].keymgmt |
98 | && want_domainparams == pk->pkeys[i].domainparams) | |
99 | return pk->pkeys[i].provdata; | |
70a1f7b4 RL |
100 | } |
101 | ||
102 | if (pk->pkey.ptr != NULL) { | |
103 | /* There is a legacy key, try to export that one to the provider */ | |
104 | ||
105 | /* If the legacy key doesn't have an export function, give up */ | |
106 | if (pk->ameth->export_to == NULL) | |
107 | return NULL; | |
108 | ||
02f060d1 RL |
109 | /* Otherwise, simply use it. */ |
110 | provdata = pk->ameth->export_to(pk, keymgmt, want_domainparams); | |
70a1f7b4 RL |
111 | |
112 | /* Synchronize the dirty count, but only if we exported successfully */ | |
02f060d1 | 113 | if (provdata != NULL) |
70a1f7b4 RL |
114 | pk->dirty_cnt_copy = pk->ameth->dirty_cnt(pk); |
115 | ||
116 | } else { | |
117 | /* | |
118 | * Here, there is no legacy key, so we look at the already cached | |
119 | * provider keys, and import from the first that supports it | |
120 | * (i.e. use its export function), and export the imported data to | |
121 | * the new provider. | |
122 | */ | |
123 | ||
02f060d1 RL |
124 | void *(*importfn)(void *provctx, const OSSL_PARAM params[]) = |
125 | want_domainparams ? keymgmt->importdomparams : keymgmt->importkey; | |
126 | ||
70a1f7b4 RL |
127 | /* |
128 | * If the given keymgmt doesn't have an import function, give up | |
129 | */ | |
02f060d1 | 130 | if (importfn == NULL) |
70a1f7b4 RL |
131 | return NULL; |
132 | ||
133 | for (j = 0; j < i && pk->pkeys[j].keymgmt != NULL; j++) { | |
134 | if (pk->pkeys[j].keymgmt->exportkey != NULL) { | |
135 | const OSSL_PARAM *paramdefs = NULL; | |
136 | OSSL_PARAM *params = NULL; | |
137 | void *data = NULL; | |
138 | void *provctx = | |
139 | ossl_provider_ctx(EVP_KEYMGMT_provider(keymgmt)); | |
02f060d1 RL |
140 | int (*exportfn)(void *provctx, OSSL_PARAM params[]) = NULL; |
141 | ||
142 | if (pk->pkeys[j].domainparams != want_domainparams) | |
143 | continue; | |
144 | ||
145 | exportfn = want_domainparams | |
146 | ? pk->pkeys[j].keymgmt->exportdomparams | |
147 | : pk->pkeys[j].keymgmt->exportkey; | |
70a1f7b4 RL |
148 | |
149 | paramdefs = pk->pkeys[j].keymgmt->exportkey_types(); | |
150 | /* | |
151 | * All params have 'data' set to NULL. In that case, | |
152 | * the exportkey call should just fill in 'return_size' | |
153 | * in all applicable params. | |
154 | */ | |
155 | params = paramdefs_to_params(paramdefs); | |
156 | /* Get 'return_size' filled */ | |
02f060d1 | 157 | exportfn(pk->pkeys[j].provdata, params); |
70a1f7b4 RL |
158 | |
159 | /* | |
160 | * Allocate space and assign 'data' to point into the | |
02f060d1 RL |
161 | * data block. |
162 | * If something goes wrong, go to the next cached key. | |
70a1f7b4 | 163 | */ |
02f060d1 RL |
164 | if ((data = allocate_params_space(params)) == NULL) |
165 | goto cont; | |
70a1f7b4 RL |
166 | |
167 | /* | |
168 | * Call the exportkey function a second time, to get | |
02f060d1 RL |
169 | * the data filled. |
170 | * If something goes wrong, go to the next cached key. | |
70a1f7b4 | 171 | */ |
02f060d1 RL |
172 | if (!exportfn(pk->pkeys[j].provdata, params)) |
173 | goto cont; | |
70a1f7b4 RL |
174 | |
175 | /* | |
176 | * We should have all the data at this point, so import | |
177 | * into the new provider and hope to get a key back. | |
178 | */ | |
02f060d1 RL |
179 | provdata = importfn(provctx, params); |
180 | ||
181 | cont: | |
70a1f7b4 RL |
182 | OPENSSL_free(params); |
183 | OPENSSL_free(data); | |
184 | ||
02f060d1 | 185 | if (provdata != NULL) |
70a1f7b4 RL |
186 | break; |
187 | } | |
188 | } | |
189 | } | |
190 | ||
191 | /* | |
192 | * TODO(3.0) Right now, we assume we have ample space. We will | |
193 | * have to think about a cache aging scheme, though, if |i| indexes | |
194 | * outside the array. | |
195 | */ | |
196 | j = ossl_assert(i < OSSL_NELEM(pk->pkeys)); | |
197 | ||
02f060d1 | 198 | if (provdata != NULL) { |
70a1f7b4 RL |
199 | EVP_KEYMGMT_up_ref(keymgmt); |
200 | pk->pkeys[i].keymgmt = keymgmt; | |
02f060d1 RL |
201 | pk->pkeys[i].provdata = provdata; |
202 | pk->pkeys[i].domainparams = want_domainparams; | |
70a1f7b4 | 203 | } |
02f060d1 RL |
204 | |
205 | return provdata; | |
70a1f7b4 | 206 | } |
4cae07fe RL |
207 | |
208 | void evp_keymgmt_clear_pkey_cache(EVP_PKEY *pk) | |
209 | { | |
210 | size_t i; | |
211 | ||
212 | if (pk != NULL) { | |
213 | for (i = 0; | |
214 | i < OSSL_NELEM(pk->pkeys) && pk->pkeys[i].keymgmt != NULL; | |
215 | i++) { | |
216 | EVP_KEYMGMT *keymgmt = pk->pkeys[i].keymgmt; | |
02f060d1 | 217 | void *provdata = pk->pkeys[i].provdata; |
4cae07fe RL |
218 | |
219 | pk->pkeys[i].keymgmt = NULL; | |
02f060d1 RL |
220 | pk->pkeys[i].provdata = NULL; |
221 | if (pk->pkeys[i].domainparams) | |
222 | keymgmt->freedomparams(provdata); | |
223 | else | |
224 | keymgmt->freekey(provdata); | |
4cae07fe RL |
225 | EVP_KEYMGMT_free(keymgmt); |
226 | } | |
227 | } | |
228 | } | |
fa9faf01 RL |
229 | |
230 | ||
231 | /* internal functions */ | |
232 | /* TODO(3.0) decide if these should be public or internal */ | |
233 | void *evp_keymgmt_importdomparams(const EVP_KEYMGMT *keymgmt, | |
234 | const OSSL_PARAM params[]) | |
235 | { | |
236 | void *provctx = ossl_provider_ctx(EVP_KEYMGMT_provider(keymgmt)); | |
237 | ||
238 | return keymgmt->importdomparams(provctx, params); | |
239 | } | |
240 | ||
241 | void *evp_keymgmt_gendomparams(const EVP_KEYMGMT *keymgmt, | |
242 | const OSSL_PARAM params[]) | |
243 | { | |
244 | void *provctx = ossl_provider_ctx(EVP_KEYMGMT_provider(keymgmt)); | |
245 | ||
246 | return keymgmt->gendomparams(provctx, params); | |
247 | } | |
248 | ||
249 | void evp_keymgmt_freedomparams(const EVP_KEYMGMT *keymgmt, | |
250 | void *provdomparams) | |
251 | { | |
252 | keymgmt->freedomparams(provdomparams); | |
253 | } | |
254 | ||
255 | int evp_keymgmt_exportdomparams(const EVP_KEYMGMT *keymgmt, | |
256 | void *provdomparams, OSSL_PARAM params[]) | |
257 | { | |
258 | return keymgmt->exportdomparams(provdomparams, params); | |
259 | } | |
260 | ||
261 | const OSSL_PARAM *evp_keymgmt_importdomparam_types(const EVP_KEYMGMT *keymgmt) | |
262 | { | |
263 | return keymgmt->importdomparam_types(); | |
264 | } | |
265 | ||
266 | const OSSL_PARAM *evp_keymgmt_exportdomparam_types(const EVP_KEYMGMT *keymgmt) | |
267 | { | |
268 | return keymgmt->exportdomparam_types(); | |
269 | } | |
270 | ||
271 | ||
272 | void *evp_keymgmt_importkey(const EVP_KEYMGMT *keymgmt, | |
273 | const OSSL_PARAM params[]) | |
274 | { | |
275 | void *provctx = ossl_provider_ctx(EVP_KEYMGMT_provider(keymgmt)); | |
276 | ||
277 | return keymgmt->importkey(provctx, params); | |
278 | } | |
279 | ||
280 | void *evp_keymgmt_genkey(const EVP_KEYMGMT *keymgmt, void *domparams, | |
281 | const OSSL_PARAM params[]) | |
282 | { | |
283 | void *provctx = ossl_provider_ctx(EVP_KEYMGMT_provider(keymgmt)); | |
284 | ||
285 | return keymgmt->genkey(provctx, domparams, params); | |
286 | } | |
287 | ||
288 | void *evp_keymgmt_loadkey(const EVP_KEYMGMT *keymgmt, | |
289 | void *id, size_t idlen) | |
290 | { | |
291 | void *provctx = ossl_provider_ctx(EVP_KEYMGMT_provider(keymgmt)); | |
292 | ||
293 | return keymgmt->loadkey(provctx, id, idlen); | |
294 | } | |
295 | ||
296 | void evp_keymgmt_freekey(const EVP_KEYMGMT *keymgmt, void *provkey) | |
297 | { | |
298 | keymgmt->freekey(provkey); | |
299 | } | |
300 | ||
301 | int evp_keymgmt_exportkey(const EVP_KEYMGMT *keymgmt, void *provkey, | |
302 | OSSL_PARAM params[]) | |
303 | { | |
304 | return keymgmt->exportkey(provkey, params); | |
305 | } | |
306 | ||
307 | const OSSL_PARAM *evp_keymgmt_importkey_types(const EVP_KEYMGMT *keymgmt) | |
308 | { | |
309 | return keymgmt->importkey_types(); | |
310 | } | |
311 | ||
312 | const OSSL_PARAM *evp_keymgmt_exportkey_types(const EVP_KEYMGMT *keymgmt) | |
313 | { | |
314 | return keymgmt->exportkey_types(); | |
315 | } |