EVP: Add support for copying provided EVP_PKEYs
[openssl.git] / crypto / evp / keymgmt_lib.c
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 <openssl/core_names.h>
11 #include "internal/cryptlib.h"
12 #include "internal/nelem.h"
13 #include "crypto/evp.h"
14 #include "crypto/asn1.h"
15 #include "internal/core.h"
16 #include "internal/provider.h"
17 #include "evp_local.h"
18
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
31 struct import_data_st {
32     EVP_KEYMGMT *keymgmt;
33     void *keydata;
34
35     int selection;
36 };
37
38 static int try_import(const OSSL_PARAM params[], void *arg)
39 {
40     struct import_data_st *data = arg;
41
42     return evp_keymgmt_import(data->keymgmt, data->keydata, data->selection,
43                               params);
44 }
45
46 void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
47 {
48     void *keydata = NULL;
49     struct import_data_st import_data;
50     size_t i = 0;
51
52     /* Export to where? */
53     if (keymgmt == NULL)
54         return NULL;
55
56     /* If we have an unassigned key, give up */
57     if (pk->keymgmt == NULL)
58         return NULL;
59
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 */
71     /*
72      * TODO(3.0) consider an evp_keymgmt_export() return value that indicates
73      * that the method is unsupported.
74      */
75     if (pk->keymgmt->export == NULL)
76         return NULL;
77
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;
86
87     /*
88      * Make sure that the type of the keymgmt to export to matches the type
89      * of the "origin"
90      */
91     if (!ossl_assert(match_type(pk->keymgmt, keymgmt)))
92         return NULL;
93
94     /* Create space to import data into */
95     if ((keydata = evp_keymgmt_newdata(keymgmt)) == NULL)
96         return NULL;
97
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
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)) {
115         /* If there was an error, bail out */
116         evp_keymgmt_freedata(keymgmt, keydata);
117         return NULL;
118     }
119
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);
123         return NULL;
124     }
125
126     return keydata;
127 }
128
129 void evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk)
130 {
131     size_t i, end = OSSL_NELEM(pk->operation_cache);
132
133     if (pk != NULL) {
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;
137
138             pk->operation_cache[i].keymgmt = NULL;
139             pk->operation_cache[i].keydata = NULL;
140             evp_keymgmt_freedata(keymgmt, keydata);
141             EVP_KEYMGMT_free(keymgmt);
142         }
143     }
144 }
145
146 size_t evp_keymgmt_util_find_operation_cache_index(EVP_PKEY *pk,
147                                                    EVP_KEYMGMT *keymgmt)
148 {
149     size_t i, end = OSSL_NELEM(pk->operation_cache);
150
151     for (i = 0; i < end && pk->operation_cache[i].keymgmt != NULL; i++) {
152         if (keymgmt == pk->operation_cache[i].keymgmt)
153             break;
154     }
155
156     return i;
157 }
158
159 int evp_keymgmt_util_cache_keydata(EVP_PKEY *pk, size_t index,
160                                    EVP_KEYMGMT *keymgmt, void *keydata)
161 {
162     if (keydata != NULL) {
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;
193         }
194     }
195 }
196
197 void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
198                                 int selection, const OSSL_PARAM params[])
199 {
200     void *keydata = evp_keymgmt_newdata(keymgmt);
201
202     if (keydata != NULL) {
203         if (!evp_keymgmt_import(keymgmt, keydata, selection, params)
204             || !EVP_KEYMGMT_up_ref(keymgmt)) {
205             evp_keymgmt_freedata(keymgmt, keydata);
206             return NULL;
207         }
208
209         evp_keymgmt_util_clear_operation_cache(target);
210         target->keymgmt = keymgmt;
211         target->keydata = keydata;
212         evp_keymgmt_util_cache_keyinfo(target);
213     }
214
215     return keydata;
216 }
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 }
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 }
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 }