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