]>
Commit | Line | Data |
---|---|---|
70a1f7b4 | 1 | /* |
33388b44 | 2 | * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. |
70a1f7b4 RL |
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 | ||
6508e858 | 10 | #include <openssl/core_names.h> |
70a1f7b4 RL |
11 | #include "internal/cryptlib.h" |
12 | #include "internal/nelem.h" | |
25f2138b DMSP |
13 | #include "crypto/evp.h" |
14 | #include "crypto/asn1.h" | |
1640d48c | 15 | #include "internal/core.h" |
70a1f7b4 | 16 | #include "internal/provider.h" |
706457b7 | 17 | #include "evp_local.h" |
70a1f7b4 | 18 | |
3f7ce7f1 RL |
19 | /* |
20 | * match_type() checks if two EVP_KEYMGMT are matching key types. This | |
21 | * function assumes that the caller has made all the necessary NULL checks. | |
22 | */ | |
23 | static int match_type(const EVP_KEYMGMT *keymgmt1, const EVP_KEYMGMT *keymgmt2) | |
24 | { | |
25 | const OSSL_PROVIDER *prov2 = EVP_KEYMGMT_provider(keymgmt2); | |
26 | const char *name2 = evp_first_name(prov2, EVP_KEYMGMT_number(keymgmt2)); | |
27 | ||
28 | return EVP_KEYMGMT_is_a(keymgmt1, name2); | |
29 | } | |
30 | ||
1640d48c | 31 | struct import_data_st { |
b305452f RL |
32 | EVP_KEYMGMT *keymgmt; |
33 | void *keydata; | |
70a1f7b4 | 34 | |
b305452f | 35 | int selection; |
1640d48c | 36 | }; |
70a1f7b4 | 37 | |
1640d48c | 38 | static int try_import(const OSSL_PARAM params[], void *arg) |
651101e1 | 39 | { |
1640d48c | 40 | struct import_data_st *data = arg; |
70a1f7b4 | 41 | |
11391da2 MC |
42 | /* Just in time creation of keydata */ |
43 | if (data->keydata == NULL | |
44 | && (data->keydata = evp_keymgmt_newdata(data->keymgmt)) == NULL) { | |
45 | ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); | |
46 | return 0; | |
47 | } | |
48 | ||
adc9f731 RL |
49 | /* |
50 | * It's fine if there was no data to transfer, we just end up with an | |
51 | * empty destination key. | |
52 | */ | |
53 | if (params[0].key == NULL) | |
54 | return 1; | |
55 | ||
b305452f RL |
56 | return evp_keymgmt_import(data->keymgmt, data->keydata, data->selection, |
57 | params); | |
70a1f7b4 RL |
58 | } |
59 | ||
b305452f | 60 | void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) |
70a1f7b4 | 61 | { |
3f7ce7f1 | 62 | struct import_data_st import_data; |
3c6ed955 | 63 | size_t i = 0; |
70a1f7b4 | 64 | |
3f7ce7f1 RL |
65 | /* Export to where? */ |
66 | if (keymgmt == NULL) | |
67 | return NULL; | |
70a1f7b4 | 68 | |
3f7ce7f1 | 69 | /* If we have an unassigned key, give up */ |
adc9f731 | 70 | if (pk->keydata == NULL) |
3f7ce7f1 | 71 | return NULL; |
70a1f7b4 | 72 | |
3c6ed955 RL |
73 | /* If |keymgmt| matches the "origin" |keymgmt|, no more to do */ |
74 | if (pk->keymgmt == keymgmt) | |
75 | return pk->keydata; | |
76 | ||
77 | /* If this key is already exported to |keymgmt|, no more to do */ | |
78 | i = evp_keymgmt_util_find_operation_cache_index(pk, keymgmt); | |
79 | if (i < OSSL_NELEM(pk->operation_cache) | |
80 | && pk->operation_cache[i].keymgmt != NULL) | |
81 | return pk->operation_cache[i].keydata; | |
82 | ||
83 | /* If the "origin" |keymgmt| doesn't support exporting, give up */ | |
70a1f7b4 | 84 | /* |
3c6ed955 RL |
85 | * TODO(3.0) consider an evp_keymgmt_export() return value that indicates |
86 | * that the method is unsupported. | |
70a1f7b4 | 87 | */ |
3c6ed955 RL |
88 | if (pk->keymgmt->export == NULL) |
89 | return NULL; | |
3f7ce7f1 | 90 | |
3c6ed955 RL |
91 | /* Check that we have found an empty slot in the export cache */ |
92 | /* | |
93 | * TODO(3.0) Right now, we assume we have ample space. We will have to | |
94 | * think about a cache aging scheme, though, if |i| indexes outside the | |
95 | * array. | |
96 | */ | |
97 | if (!ossl_assert(i < OSSL_NELEM(pk->operation_cache))) | |
98 | return NULL; | |
3f7ce7f1 RL |
99 | |
100 | /* | |
101 | * Make sure that the type of the keymgmt to export to matches the type | |
3c6ed955 | 102 | * of the "origin" |
3f7ce7f1 | 103 | */ |
3c6ed955 | 104 | if (!ossl_assert(match_type(pk->keymgmt, keymgmt))) |
3f7ce7f1 | 105 | return NULL; |
70a1f7b4 | 106 | |
3f7ce7f1 RL |
107 | /* |
108 | * We look at the already cached provider keys, and import from the | |
109 | * first that supports it (i.e. use its export function), and export | |
110 | * the imported data to the new provider. | |
111 | */ | |
112 | ||
113 | /* Setup for the export callback */ | |
adc9f731 | 114 | import_data.keydata = NULL; /* try_import will create it */ |
3f7ce7f1 RL |
115 | import_data.keymgmt = keymgmt; |
116 | import_data.selection = OSSL_KEYMGMT_SELECT_ALL; | |
117 | ||
3c6ed955 RL |
118 | /* |
119 | * The export function calls the callback (try_import), which does the | |
120 | * import for us. If successful, we're done. | |
121 | */ | |
122 | if (!evp_keymgmt_export(pk->keymgmt, pk->keydata, OSSL_KEYMGMT_SELECT_ALL, | |
123 | &try_import, &import_data)) { | |
3f7ce7f1 | 124 | /* If there was an error, bail out */ |
adc9f731 | 125 | evp_keymgmt_freedata(keymgmt, import_data.keydata); |
3f7ce7f1 | 126 | return NULL; |
70a1f7b4 RL |
127 | } |
128 | ||
3c6ed955 | 129 | /* Add the new export to the operation cache */ |
adc9f731 RL |
130 | if (!evp_keymgmt_util_cache_keydata(pk, i, keymgmt, import_data.keydata)) { |
131 | evp_keymgmt_freedata(keymgmt, import_data.keydata); | |
d5e66eab | 132 | return NULL; |
3c6ed955 | 133 | } |
02f060d1 | 134 | |
adc9f731 | 135 | return import_data.keydata; |
70a1f7b4 | 136 | } |
4cae07fe | 137 | |
3c6ed955 | 138 | void evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk) |
4cae07fe | 139 | { |
3c6ed955 | 140 | size_t i, end = OSSL_NELEM(pk->operation_cache); |
4cae07fe RL |
141 | |
142 | if (pk != NULL) { | |
3c6ed955 RL |
143 | for (i = 0; i < end && pk->operation_cache[i].keymgmt != NULL; i++) { |
144 | EVP_KEYMGMT *keymgmt = pk->operation_cache[i].keymgmt; | |
145 | void *keydata = pk->operation_cache[i].keydata; | |
4cae07fe | 146 | |
3c6ed955 RL |
147 | pk->operation_cache[i].keymgmt = NULL; |
148 | pk->operation_cache[i].keydata = NULL; | |
b305452f | 149 | evp_keymgmt_freedata(keymgmt, keydata); |
4cae07fe RL |
150 | EVP_KEYMGMT_free(keymgmt); |
151 | } | |
6508e858 RL |
152 | } |
153 | } | |
154 | ||
3c6ed955 RL |
155 | size_t evp_keymgmt_util_find_operation_cache_index(EVP_PKEY *pk, |
156 | EVP_KEYMGMT *keymgmt) | |
3f7ce7f1 | 157 | { |
3c6ed955 | 158 | size_t i, end = OSSL_NELEM(pk->operation_cache); |
3f7ce7f1 | 159 | |
3c6ed955 RL |
160 | for (i = 0; i < end && pk->operation_cache[i].keymgmt != NULL; i++) { |
161 | if (keymgmt == pk->operation_cache[i].keymgmt) | |
3f7ce7f1 RL |
162 | break; |
163 | } | |
164 | ||
165 | return i; | |
166 | } | |
167 | ||
3c6ed955 RL |
168 | int evp_keymgmt_util_cache_keydata(EVP_PKEY *pk, size_t index, |
169 | EVP_KEYMGMT *keymgmt, void *keydata) | |
6508e858 | 170 | { |
b305452f | 171 | if (keydata != NULL) { |
3c6ed955 RL |
172 | if (!EVP_KEYMGMT_up_ref(keymgmt)) |
173 | return 0; | |
174 | pk->operation_cache[index].keydata = keydata; | |
175 | pk->operation_cache[index].keymgmt = keymgmt; | |
176 | } | |
177 | return 1; | |
178 | } | |
179 | ||
180 | void evp_keymgmt_util_cache_keyinfo(EVP_PKEY *pk) | |
181 | { | |
182 | /* | |
183 | * Cache information about the provider "origin" key. | |
184 | * | |
185 | * This services functions like EVP_PKEY_size, EVP_PKEY_bits, etc | |
186 | */ | |
adc9f731 | 187 | if (pk->keydata != NULL) { |
3c6ed955 RL |
188 | int bits = 0; |
189 | int security_bits = 0; | |
190 | int size = 0; | |
191 | OSSL_PARAM params[4]; | |
192 | ||
193 | params[0] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_BITS, &bits); | |
194 | params[1] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_SECURITY_BITS, | |
195 | &security_bits); | |
196 | params[2] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_MAX_SIZE, &size); | |
197 | params[3] = OSSL_PARAM_construct_end(); | |
198 | if (evp_keymgmt_get_params(pk->keymgmt, pk->keydata, params)) { | |
199 | pk->cache.size = size; | |
200 | pk->cache.bits = bits; | |
201 | pk->cache.security_bits = security_bits; | |
6508e858 | 202 | } |
4cae07fe RL |
203 | } |
204 | } | |
fa9faf01 | 205 | |
68552cde | 206 | void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt, |
b305452f | 207 | int selection, const OSSL_PARAM params[]) |
46e2dd05 | 208 | { |
8243d8d1 | 209 | void *keydata = NULL; |
46e2dd05 | 210 | |
8243d8d1 RL |
211 | if ((keydata = evp_keymgmt_newdata(keymgmt)) == NULL |
212 | || !evp_keymgmt_import(keymgmt, keydata, selection, params) | |
213 | || !EVP_PKEY_set_type_by_keymgmt(target, keymgmt)) { | |
214 | evp_keymgmt_freedata(keymgmt, keydata); | |
215 | keydata = NULL; | |
216 | } | |
b305452f | 217 | if (keydata != NULL) { |
3c6ed955 RL |
218 | target->keydata = keydata; |
219 | evp_keymgmt_util_cache_keyinfo(target); | |
b305452f | 220 | } |
46e2dd05 | 221 | |
b305452f | 222 | return keydata; |
46e2dd05 | 223 | } |
157ded39 RL |
224 | |
225 | int evp_keymgmt_util_has(EVP_PKEY *pk, int selection) | |
226 | { | |
227 | /* Check if key is even assigned */ | |
228 | if (pk->keymgmt == NULL) | |
229 | return 0; | |
230 | ||
231 | return evp_keymgmt_has(pk->keymgmt, pk->keydata, selection); | |
232 | } | |
1e9101c4 RL |
233 | |
234 | /* | |
235 | * evp_keymgmt_util_match() doesn't just look at the provider side "origin", | |
236 | * but also in the operation cache to see if there's any common keymgmt that | |
237 | * supplies OP_keymgmt_match. | |
238 | * | |
c74aaa39 DDO |
239 | * evp_keymgmt_util_match() adheres to the return values that EVP_PKEY_eq() |
240 | * and EVP_PKEY_parameters_eq() return, i.e.: | |
1e9101c4 RL |
241 | * |
242 | * 1 same key | |
243 | * 0 not same key | |
244 | * -1 not same key type | |
245 | * -2 unsupported operation | |
246 | */ | |
247 | int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection) | |
248 | { | |
249 | EVP_KEYMGMT *keymgmt1 = NULL, *keymgmt2 = NULL; | |
250 | void *keydata1 = NULL, *keydata2 = NULL; | |
251 | ||
252 | if (pk1 == NULL || pk2 == NULL) { | |
253 | if (pk1 == NULL && pk2 == NULL) | |
254 | return 1; | |
255 | return 0; | |
256 | } | |
257 | ||
258 | keymgmt1 = pk1->keymgmt; | |
259 | keydata1 = pk1->keydata; | |
260 | keymgmt2 = pk2->keymgmt; | |
261 | keydata2 = pk2->keydata; | |
262 | ||
263 | if (keymgmt1 != keymgmt2) { | |
adc9f731 RL |
264 | /* |
265 | * The condition for a successful cross export is that the | |
266 | * keydata to be exported is NULL (typed, but otherwise empty | |
267 | * EVP_PKEY), or that it was possible to export it with | |
268 | * evp_keymgmt_util_export_to_provider(). | |
269 | * | |
270 | * We use |ok| to determine if it's ok to cross export one way, | |
271 | * but also to determine if we should attempt a cross export | |
272 | * the other way. There's no point doing it both ways. | |
273 | */ | |
274 | int ok = 1; | |
1e9101c4 RL |
275 | |
276 | /* Complex case, where the keymgmt differ */ | |
277 | if (keymgmt1 != NULL | |
278 | && keymgmt2 != NULL | |
279 | && !match_type(keymgmt1, keymgmt2)) { | |
280 | ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES); | |
281 | return -1; /* Not the same type */ | |
282 | } | |
283 | ||
284 | /* | |
285 | * The key types are determined to match, so we try cross export, | |
286 | * but only to keymgmt's that supply a matching function. | |
287 | */ | |
288 | if (keymgmt2 != NULL | |
289 | && keymgmt2->match != NULL) { | |
adc9f731 RL |
290 | void *tmp_keydata = NULL; |
291 | ||
292 | ok = 1; | |
293 | if (keydata1 != NULL) { | |
294 | tmp_keydata = | |
295 | evp_keymgmt_util_export_to_provider(pk1, keymgmt2); | |
296 | ok = (tmp_keydata != NULL); | |
297 | } | |
298 | if (ok) { | |
1e9101c4 RL |
299 | keymgmt1 = keymgmt2; |
300 | keydata1 = tmp_keydata; | |
301 | } | |
302 | } | |
adc9f731 | 303 | /* |
8243d8d1 | 304 | * If we've successfully cross exported one way, there's no point |
adc9f731 RL |
305 | * doing it the other way, hence the |!ok| check. |
306 | */ | |
307 | if (!ok | |
1e9101c4 RL |
308 | && keymgmt1 != NULL |
309 | && keymgmt1->match != NULL) { | |
adc9f731 RL |
310 | void *tmp_keydata = NULL; |
311 | ||
312 | ok = 1; | |
313 | if (keydata2 != NULL) { | |
314 | tmp_keydata = | |
315 | evp_keymgmt_util_export_to_provider(pk2, keymgmt1); | |
316 | ok = (tmp_keydata != NULL); | |
317 | } | |
318 | if (ok) { | |
1e9101c4 RL |
319 | keymgmt2 = keymgmt1; |
320 | keydata2 = tmp_keydata; | |
321 | } | |
322 | } | |
323 | } | |
324 | ||
325 | /* If we still don't have matching keymgmt implementations, we give up */ | |
326 | if (keymgmt1 != keymgmt2) | |
327 | return -2; | |
328 | ||
adc9f731 RL |
329 | /* If both keydata are NULL, then they're the same key */ |
330 | if (keydata1 == NULL && keydata2 == NULL) | |
331 | return 1; | |
332 | /* If only one of the keydata is NULL, then they're different keys */ | |
333 | if (keydata1 == NULL || keydata2 == NULL) | |
334 | return 0; | |
335 | /* If both keydata are non-NULL, we let the backend decide */ | |
1e9101c4 RL |
336 | return evp_keymgmt_match(keymgmt1, keydata1, keydata2, selection); |
337 | } | |
ff3b59e1 RL |
338 | |
339 | int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection) | |
340 | { | |
341 | /* Save copies of pointers we want to play with without affecting |to| */ | |
342 | EVP_KEYMGMT *to_keymgmt = to->keymgmt; | |
343 | void *to_keydata = to->keydata, *alloc_keydata = NULL; | |
344 | ||
345 | /* An unassigned key can't be copied */ | |
adc9f731 | 346 | if (from == NULL || from->keydata == NULL) |
ff3b59e1 RL |
347 | return 0; |
348 | ||
036ee370 RL |
349 | /* |
350 | * If |to| is unassigned, ensure it gets the same KEYMGMT as |from|, | |
351 | * Note that the final setting of KEYMGMT is done further down, with | |
352 | * EVP_PKEY_set_type_by_keymgmt(); we don't want to do that prematurely. | |
353 | */ | |
354 | if (to_keymgmt == NULL) | |
355 | to_keymgmt = from->keymgmt; | |
356 | ||
adc9f731 RL |
357 | if (to_keymgmt == from->keymgmt && to_keymgmt->copy != NULL) { |
358 | /* Make sure there's somewhere to copy to */ | |
359 | if (to_keydata == NULL | |
036ee370 RL |
360 | && ((to_keydata = alloc_keydata = evp_keymgmt_newdata(to_keymgmt)) |
361 | == NULL)) { | |
adc9f731 | 362 | ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); |
ff3b59e1 | 363 | return 0; |
adc9f731 | 364 | } |
ff3b59e1 | 365 | |
adc9f731 RL |
366 | /* |
367 | * |to| and |from| have the same keymgmt, and the copy function is | |
368 | * implemented, so just copy and be done | |
369 | */ | |
ff3b59e1 RL |
370 | if (!evp_keymgmt_copy(to_keymgmt, to_keydata, from->keydata, |
371 | selection)) | |
372 | return 0; | |
373 | } else if (match_type(to_keymgmt, from->keymgmt)) { | |
374 | struct import_data_st import_data; | |
375 | ||
376 | import_data.keymgmt = to_keymgmt; | |
377 | import_data.keydata = to_keydata; | |
378 | import_data.selection = selection; | |
379 | ||
380 | if (!evp_keymgmt_export(from->keymgmt, from->keydata, selection, | |
381 | &try_import, &import_data)) { | |
382 | evp_keymgmt_freedata(to_keymgmt, alloc_keydata); | |
383 | return 0; | |
384 | } | |
adc9f731 RL |
385 | |
386 | /* | |
036ee370 | 387 | * In case to_keydata was previously unallocated, try_import() |
adc9f731 RL |
388 | * may have created it for us. |
389 | */ | |
036ee370 RL |
390 | if (to_keydata == NULL) |
391 | to_keydata = alloc_keydata = import_data.keydata; | |
ff3b59e1 RL |
392 | } else { |
393 | ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES); | |
394 | return 0; | |
395 | } | |
396 | ||
397 | if (to->keymgmt == NULL | |
8243d8d1 | 398 | && !EVP_PKEY_set_type_by_keymgmt(to, to_keymgmt)) { |
ff3b59e1 RL |
399 | evp_keymgmt_freedata(to_keymgmt, alloc_keydata); |
400 | return 0; | |
401 | } | |
ff3b59e1 RL |
402 | to->keydata = to_keydata; |
403 | evp_keymgmt_util_cache_keyinfo(to); | |
404 | ||
405 | return 1; | |
406 | } | |
62924755 RL |
407 | |
408 | void *evp_keymgmt_util_gen(EVP_PKEY *target, EVP_KEYMGMT *keymgmt, | |
409 | void *genctx, OSSL_CALLBACK *cb, void *cbarg) | |
410 | { | |
8243d8d1 | 411 | void *keydata = NULL; |
62924755 | 412 | |
8243d8d1 RL |
413 | if ((keydata = evp_keymgmt_gen(keymgmt, genctx, cb, cbarg)) == NULL |
414 | || !EVP_PKEY_set_type_by_keymgmt(target, keymgmt)) { | |
415 | evp_keymgmt_freedata(keymgmt, keydata); | |
416 | keydata = NULL; | |
417 | } | |
62924755 | 418 | if (keydata != NULL) { |
62924755 RL |
419 | target->keydata = keydata; |
420 | evp_keymgmt_util_cache_keyinfo(target); | |
421 | } | |
422 | ||
423 | return keydata; | |
424 | } | |
3b924da0 RL |
425 | |
426 | /* | |
427 | * Returns the same numbers as EVP_PKEY_get_default_digest_name() | |
428 | * When the string from the EVP_KEYMGMT implementation is "", we use | |
429 | * SN_undef, since that corresponds to what EVP_PKEY_get_default_nid() | |
430 | * returns for no digest. | |
431 | */ | |
432 | int evp_keymgmt_util_get_deflt_digest_name(EVP_KEYMGMT *keymgmt, | |
433 | void *keydata, | |
434 | char *mdname, size_t mdname_sz) | |
435 | { | |
436 | OSSL_PARAM params[3]; | |
437 | char mddefault[100] = ""; | |
438 | char mdmandatory[100] = ""; | |
439 | char *result = NULL; | |
440 | int rv = -2; | |
441 | ||
442 | params[0] = | |
443 | OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST, | |
444 | mddefault, sizeof(mddefault)); | |
3b924da0 RL |
445 | params[1] = |
446 | OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST, | |
447 | mdmandatory, | |
448 | sizeof(mdmandatory)); | |
3b924da0 RL |
449 | params[2] = OSSL_PARAM_construct_end(); |
450 | ||
451 | if (!evp_keymgmt_get_params(keymgmt, keydata, params)) | |
452 | return 0; | |
453 | ||
54b47afe P |
454 | if (OSSL_PARAM_modified(params + 1)) { |
455 | if (params[1].return_size <= 1) /* Only a NUL byte */ | |
3b924da0 RL |
456 | result = SN_undef; |
457 | else | |
458 | result = mdmandatory; | |
459 | rv = 2; | |
54b47afe P |
460 | } else if (OSSL_PARAM_modified(params)) { |
461 | if (params[0].return_size <= 1) /* Only a NUL byte */ | |
3b924da0 RL |
462 | result = SN_undef; |
463 | else | |
464 | result = mddefault; | |
465 | rv = 1; | |
466 | } | |
467 | if (rv > 0) | |
468 | OPENSSL_strlcpy(mdname, result, mdname_sz); | |
469 | return rv; | |
470 | } |