]>
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 | ||
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 | |
b305452f RL |
42 | return evp_keymgmt_import(data->keymgmt, data->keydata, data->selection, |
43 | params); | |
70a1f7b4 RL |
44 | } |
45 | ||
b305452f | 46 | void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) |
70a1f7b4 | 47 | { |
b305452f | 48 | void *keydata = NULL; |
3f7ce7f1 | 49 | struct import_data_st import_data; |
3c6ed955 | 50 | size_t i = 0; |
70a1f7b4 | 51 | |
3f7ce7f1 RL |
52 | /* Export to where? */ |
53 | if (keymgmt == NULL) | |
54 | return NULL; | |
70a1f7b4 | 55 | |
3f7ce7f1 | 56 | /* If we have an unassigned key, give up */ |
3c6ed955 | 57 | if (pk->keymgmt == NULL) |
3f7ce7f1 | 58 | return NULL; |
70a1f7b4 | 59 | |
3c6ed955 RL |
60 | /* If |keymgmt| matches the "origin" |keymgmt|, no more to do */ |
61 | if (pk->keymgmt == keymgmt) | |
62 | return pk->keydata; | |
63 | ||
64 | /* If this key is already exported to |keymgmt|, no more to do */ | |
65 | i = evp_keymgmt_util_find_operation_cache_index(pk, keymgmt); | |
66 | if (i < OSSL_NELEM(pk->operation_cache) | |
67 | && pk->operation_cache[i].keymgmt != NULL) | |
68 | return pk->operation_cache[i].keydata; | |
69 | ||
70 | /* If the "origin" |keymgmt| doesn't support exporting, give up */ | |
70a1f7b4 | 71 | /* |
3c6ed955 RL |
72 | * TODO(3.0) consider an evp_keymgmt_export() return value that indicates |
73 | * that the method is unsupported. | |
70a1f7b4 | 74 | */ |
3c6ed955 RL |
75 | if (pk->keymgmt->export == NULL) |
76 | return NULL; | |
3f7ce7f1 | 77 | |
3c6ed955 RL |
78 | /* Check that we have found an empty slot in the export cache */ |
79 | /* | |
80 | * TODO(3.0) Right now, we assume we have ample space. We will have to | |
81 | * think about a cache aging scheme, though, if |i| indexes outside the | |
82 | * array. | |
83 | */ | |
84 | if (!ossl_assert(i < OSSL_NELEM(pk->operation_cache))) | |
85 | return NULL; | |
3f7ce7f1 RL |
86 | |
87 | /* | |
88 | * Make sure that the type of the keymgmt to export to matches the type | |
3c6ed955 | 89 | * of the "origin" |
3f7ce7f1 | 90 | */ |
3c6ed955 | 91 | if (!ossl_assert(match_type(pk->keymgmt, keymgmt))) |
3f7ce7f1 | 92 | return NULL; |
70a1f7b4 | 93 | |
3f7ce7f1 | 94 | /* Create space to import data into */ |
b305452f RL |
95 | if ((keydata = evp_keymgmt_newdata(keymgmt)) == NULL) |
96 | return NULL; | |
97 | ||
3f7ce7f1 RL |
98 | /* |
99 | * We look at the already cached provider keys, and import from the | |
100 | * first that supports it (i.e. use its export function), and export | |
101 | * the imported data to the new provider. | |
102 | */ | |
103 | ||
104 | /* Setup for the export callback */ | |
105 | import_data.keydata = keydata; | |
106 | import_data.keymgmt = keymgmt; | |
107 | import_data.selection = OSSL_KEYMGMT_SELECT_ALL; | |
108 | ||
3c6ed955 RL |
109 | /* |
110 | * The export function calls the callback (try_import), which does the | |
111 | * import for us. If successful, we're done. | |
112 | */ | |
113 | if (!evp_keymgmt_export(pk->keymgmt, pk->keydata, OSSL_KEYMGMT_SELECT_ALL, | |
114 | &try_import, &import_data)) { | |
3f7ce7f1 RL |
115 | /* If there was an error, bail out */ |
116 | evp_keymgmt_freedata(keymgmt, keydata); | |
117 | return NULL; | |
70a1f7b4 RL |
118 | } |
119 | ||
3c6ed955 RL |
120 | /* Add the new export to the operation cache */ |
121 | if (!evp_keymgmt_util_cache_keydata(pk, i, keymgmt, keydata)) { | |
122 | evp_keymgmt_freedata(keymgmt, keydata); | |
d5e66eab | 123 | return NULL; |
3c6ed955 | 124 | } |
02f060d1 | 125 | |
b305452f | 126 | return keydata; |
70a1f7b4 | 127 | } |
4cae07fe | 128 | |
3c6ed955 | 129 | void evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk) |
4cae07fe | 130 | { |
3c6ed955 | 131 | size_t i, end = OSSL_NELEM(pk->operation_cache); |
4cae07fe RL |
132 | |
133 | if (pk != NULL) { | |
3c6ed955 RL |
134 | for (i = 0; i < end && pk->operation_cache[i].keymgmt != NULL; i++) { |
135 | EVP_KEYMGMT *keymgmt = pk->operation_cache[i].keymgmt; | |
136 | void *keydata = pk->operation_cache[i].keydata; | |
4cae07fe | 137 | |
3c6ed955 RL |
138 | pk->operation_cache[i].keymgmt = NULL; |
139 | pk->operation_cache[i].keydata = NULL; | |
b305452f | 140 | evp_keymgmt_freedata(keymgmt, keydata); |
4cae07fe RL |
141 | EVP_KEYMGMT_free(keymgmt); |
142 | } | |
6508e858 RL |
143 | } |
144 | } | |
145 | ||
3c6ed955 RL |
146 | size_t evp_keymgmt_util_find_operation_cache_index(EVP_PKEY *pk, |
147 | EVP_KEYMGMT *keymgmt) | |
3f7ce7f1 | 148 | { |
3c6ed955 | 149 | size_t i, end = OSSL_NELEM(pk->operation_cache); |
3f7ce7f1 | 150 | |
3c6ed955 RL |
151 | for (i = 0; i < end && pk->operation_cache[i].keymgmt != NULL; i++) { |
152 | if (keymgmt == pk->operation_cache[i].keymgmt) | |
3f7ce7f1 RL |
153 | break; |
154 | } | |
155 | ||
156 | return i; | |
157 | } | |
158 | ||
3c6ed955 RL |
159 | int evp_keymgmt_util_cache_keydata(EVP_PKEY *pk, size_t index, |
160 | EVP_KEYMGMT *keymgmt, void *keydata) | |
6508e858 | 161 | { |
b305452f | 162 | if (keydata != NULL) { |
3c6ed955 RL |
163 | if (!EVP_KEYMGMT_up_ref(keymgmt)) |
164 | return 0; | |
165 | pk->operation_cache[index].keydata = keydata; | |
166 | pk->operation_cache[index].keymgmt = keymgmt; | |
167 | } | |
168 | return 1; | |
169 | } | |
170 | ||
171 | void evp_keymgmt_util_cache_keyinfo(EVP_PKEY *pk) | |
172 | { | |
173 | /* | |
174 | * Cache information about the provider "origin" key. | |
175 | * | |
176 | * This services functions like EVP_PKEY_size, EVP_PKEY_bits, etc | |
177 | */ | |
178 | if (pk->keymgmt != NULL) { | |
179 | int bits = 0; | |
180 | int security_bits = 0; | |
181 | int size = 0; | |
182 | OSSL_PARAM params[4]; | |
183 | ||
184 | params[0] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_BITS, &bits); | |
185 | params[1] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_SECURITY_BITS, | |
186 | &security_bits); | |
187 | params[2] = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_MAX_SIZE, &size); | |
188 | params[3] = OSSL_PARAM_construct_end(); | |
189 | if (evp_keymgmt_get_params(pk->keymgmt, pk->keydata, params)) { | |
190 | pk->cache.size = size; | |
191 | pk->cache.bits = bits; | |
192 | pk->cache.security_bits = security_bits; | |
6508e858 | 193 | } |
4cae07fe RL |
194 | } |
195 | } | |
fa9faf01 | 196 | |
68552cde | 197 | void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt, |
b305452f | 198 | int selection, const OSSL_PARAM params[]) |
46e2dd05 | 199 | { |
b305452f | 200 | void *keydata = evp_keymgmt_newdata(keymgmt); |
46e2dd05 | 201 | |
b305452f | 202 | if (keydata != NULL) { |
3c6ed955 RL |
203 | if (!evp_keymgmt_import(keymgmt, keydata, selection, params) |
204 | || !EVP_KEYMGMT_up_ref(keymgmt)) { | |
b305452f RL |
205 | evp_keymgmt_freedata(keymgmt, keydata); |
206 | return NULL; | |
207 | } | |
208 | ||
3c6ed955 RL |
209 | evp_keymgmt_util_clear_operation_cache(target); |
210 | target->keymgmt = keymgmt; | |
211 | target->keydata = keydata; | |
212 | evp_keymgmt_util_cache_keyinfo(target); | |
b305452f | 213 | } |
46e2dd05 | 214 | |
b305452f | 215 | return keydata; |
46e2dd05 | 216 | } |
157ded39 RL |
217 | |
218 | int evp_keymgmt_util_has(EVP_PKEY *pk, int selection) | |
219 | { | |
220 | /* Check if key is even assigned */ | |
221 | if (pk->keymgmt == NULL) | |
222 | return 0; | |
223 | ||
224 | return evp_keymgmt_has(pk->keymgmt, pk->keydata, selection); | |
225 | } | |
1e9101c4 RL |
226 | |
227 | /* | |
228 | * evp_keymgmt_util_match() doesn't just look at the provider side "origin", | |
229 | * but also in the operation cache to see if there's any common keymgmt that | |
230 | * supplies OP_keymgmt_match. | |
231 | * | |
232 | * evp_keymgmt_util_match() adheres to the return values that EVP_PKEY_cmp() | |
233 | * and EVP_PKEY_cmp_parameters() return, i.e.: | |
234 | * | |
235 | * 1 same key | |
236 | * 0 not same key | |
237 | * -1 not same key type | |
238 | * -2 unsupported operation | |
239 | */ | |
240 | int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection) | |
241 | { | |
242 | EVP_KEYMGMT *keymgmt1 = NULL, *keymgmt2 = NULL; | |
243 | void *keydata1 = NULL, *keydata2 = NULL; | |
244 | ||
245 | if (pk1 == NULL || pk2 == NULL) { | |
246 | if (pk1 == NULL && pk2 == NULL) | |
247 | return 1; | |
248 | return 0; | |
249 | } | |
250 | ||
251 | keymgmt1 = pk1->keymgmt; | |
252 | keydata1 = pk1->keydata; | |
253 | keymgmt2 = pk2->keymgmt; | |
254 | keydata2 = pk2->keydata; | |
255 | ||
256 | if (keymgmt1 != keymgmt2) { | |
257 | void *tmp_keydata = NULL; | |
258 | ||
259 | /* Complex case, where the keymgmt differ */ | |
260 | if (keymgmt1 != NULL | |
261 | && keymgmt2 != NULL | |
262 | && !match_type(keymgmt1, keymgmt2)) { | |
263 | ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES); | |
264 | return -1; /* Not the same type */ | |
265 | } | |
266 | ||
267 | /* | |
268 | * The key types are determined to match, so we try cross export, | |
269 | * but only to keymgmt's that supply a matching function. | |
270 | */ | |
271 | if (keymgmt2 != NULL | |
272 | && keymgmt2->match != NULL) { | |
273 | tmp_keydata = evp_keymgmt_util_export_to_provider(pk1, keymgmt2); | |
274 | if (tmp_keydata != NULL) { | |
275 | keymgmt1 = keymgmt2; | |
276 | keydata1 = tmp_keydata; | |
277 | } | |
278 | } | |
279 | if (tmp_keydata == NULL | |
280 | && keymgmt1 != NULL | |
281 | && keymgmt1->match != NULL) { | |
282 | tmp_keydata = evp_keymgmt_util_export_to_provider(pk2, keymgmt1); | |
283 | if (tmp_keydata != NULL) { | |
284 | keymgmt2 = keymgmt1; | |
285 | keydata2 = tmp_keydata; | |
286 | } | |
287 | } | |
288 | } | |
289 | ||
290 | /* If we still don't have matching keymgmt implementations, we give up */ | |
291 | if (keymgmt1 != keymgmt2) | |
292 | return -2; | |
293 | ||
294 | return evp_keymgmt_match(keymgmt1, keydata1, keydata2, selection); | |
295 | } | |
ff3b59e1 RL |
296 | |
297 | int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection) | |
298 | { | |
299 | /* Save copies of pointers we want to play with without affecting |to| */ | |
300 | EVP_KEYMGMT *to_keymgmt = to->keymgmt; | |
301 | void *to_keydata = to->keydata, *alloc_keydata = NULL; | |
302 | ||
303 | /* An unassigned key can't be copied */ | |
304 | if (from == NULL || from->keymgmt == NULL) | |
305 | return 0; | |
306 | ||
307 | /* If |from| doesn't support copying, we fail */ | |
308 | if (from->keymgmt->copy == NULL) | |
309 | return 0; | |
310 | ||
311 | /* If |to| doesn't have a provider side "origin" yet, create one */ | |
312 | if (to_keymgmt == NULL) { | |
313 | to_keydata = alloc_keydata = evp_keymgmt_newdata(from->keymgmt); | |
314 | if (to_keydata == NULL) | |
315 | return 0; | |
316 | to_keymgmt = from->keymgmt; | |
317 | } | |
318 | ||
319 | if (to_keymgmt == from->keymgmt) { | |
320 | /* |to| and |from| have the same keymgmt, just copy and be done */ | |
321 | if (!evp_keymgmt_copy(to_keymgmt, to_keydata, from->keydata, | |
322 | selection)) | |
323 | return 0; | |
324 | } else if (match_type(to_keymgmt, from->keymgmt)) { | |
325 | struct import_data_st import_data; | |
326 | ||
327 | import_data.keymgmt = to_keymgmt; | |
328 | import_data.keydata = to_keydata; | |
329 | import_data.selection = selection; | |
330 | ||
331 | if (!evp_keymgmt_export(from->keymgmt, from->keydata, selection, | |
332 | &try_import, &import_data)) { | |
333 | evp_keymgmt_freedata(to_keymgmt, alloc_keydata); | |
334 | return 0; | |
335 | } | |
336 | } else { | |
337 | ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES); | |
338 | return 0; | |
339 | } | |
340 | ||
341 | if (to->keymgmt == NULL | |
342 | && !EVP_KEYMGMT_up_ref(to_keymgmt)) { | |
343 | evp_keymgmt_freedata(to_keymgmt, alloc_keydata); | |
344 | return 0; | |
345 | } | |
346 | evp_keymgmt_util_clear_operation_cache(to); | |
347 | to->keymgmt = to_keymgmt; | |
348 | to->keydata = to_keydata; | |
349 | evp_keymgmt_util_cache_keyinfo(to); | |
350 | ||
351 | return 1; | |
352 | } | |
62924755 RL |
353 | |
354 | void *evp_keymgmt_util_gen(EVP_PKEY *target, EVP_KEYMGMT *keymgmt, | |
355 | void *genctx, OSSL_CALLBACK *cb, void *cbarg) | |
356 | { | |
357 | void *keydata = evp_keymgmt_gen(keymgmt, genctx, cb, cbarg); | |
358 | ||
359 | if (keydata != NULL) { | |
360 | if (!EVP_KEYMGMT_up_ref(keymgmt)) { | |
361 | evp_keymgmt_freedata(keymgmt, keydata); | |
362 | return NULL; | |
363 | } | |
364 | ||
365 | evp_keymgmt_util_clear_operation_cache(target); | |
366 | target->keymgmt = keymgmt; | |
367 | target->keydata = keydata; | |
368 | evp_keymgmt_util_cache_keyinfo(target); | |
369 | } | |
370 | ||
371 | return keydata; | |
372 | } |