Refactor evp_pkey_make_provided() to do legacy to provider export
[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, j;
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->pkeys[0].keymgmt == NULL)
58         return NULL;
59
60     /*
61      * See if we have exported to this provider already.
62      * If we have, return immediately.
63      */
64     i = evp_keymgmt_util_find_pkey_cache_index(pk, keymgmt);
65
66     /* If we're already exported to the given keymgmt, no more to do */
67     if (keymgmt == pk->pkeys[i].keymgmt)
68         return pk->pkeys[i].keydata;
69
70     /*
71      * Make sure that the type of the keymgmt to export to matches the type
72      * of already cached keymgmt
73      */
74     if (!ossl_assert(match_type(pk->pkeys[0].keymgmt, keymgmt)))
75         return NULL;
76
77     /* Create space to import data into */
78     if ((keydata = evp_keymgmt_newdata(keymgmt)) == NULL)
79         return NULL;
80
81     /*
82      * We look at the already cached provider keys, and import from the
83      * first that supports it (i.e. use its export function), and export
84      * the imported data to the new provider.
85      */
86
87     /* Setup for the export callback */
88     import_data.keydata = keydata;
89     import_data.keymgmt = keymgmt;
90     import_data.selection = OSSL_KEYMGMT_SELECT_ALL;
91
92     for (j = 0; j < i && pk->pkeys[j].keymgmt != NULL; j++) {
93         EVP_KEYMGMT *exp_keymgmt = pk->pkeys[j].keymgmt;
94         void *exp_keydata = pk->pkeys[j].keydata;
95
96         /*
97          * TODO(3.0) consider an evp_keymgmt_export() return value that
98          * indicates that the method is unsupported.
99          */
100         if (exp_keymgmt->export == NULL)
101             continue;
102
103         /*
104          * The export function calls the callback (try_import), which does
105          * the import for us.  If successful, we're done.
106          */
107         if (evp_keymgmt_export(exp_keymgmt, exp_keydata,
108                                OSSL_KEYMGMT_SELECT_ALL,
109                                &try_import, &import_data))
110             break;
111
112         /* If there was an error, bail out */
113         evp_keymgmt_freedata(keymgmt, keydata);
114         return NULL;
115     }
116
117     /*
118      * TODO(3.0) Right now, we assume we have ample space.  We will
119      * have to think about a cache aging scheme, though, if |i| indexes
120      * outside the array.
121      */
122     if (!ossl_assert(i < OSSL_NELEM(pk->pkeys)))
123         return NULL;
124
125     evp_keymgmt_util_cache_pkey(pk, i, keymgmt, keydata);
126
127     return keydata;
128 }
129
130 void evp_keymgmt_util_clear_pkey_cache(EVP_PKEY *pk)
131 {
132     size_t i, end = OSSL_NELEM(pk->pkeys);
133
134     if (pk != NULL) {
135         for (i = 0; i < end && pk->pkeys[i].keymgmt != NULL; i++) {
136             EVP_KEYMGMT *keymgmt = pk->pkeys[i].keymgmt;
137             void *keydata = pk->pkeys[i].keydata;
138
139             pk->pkeys[i].keymgmt = NULL;
140             pk->pkeys[i].keydata = NULL;
141             evp_keymgmt_freedata(keymgmt, keydata);
142             EVP_KEYMGMT_free(keymgmt);
143         }
144
145         pk->cache.size = 0;
146         pk->cache.bits = 0;
147         pk->cache.security_bits = 0;
148     }
149 }
150
151 size_t evp_keymgmt_util_find_pkey_cache_index(EVP_PKEY *pk,
152                                               EVP_KEYMGMT *keymgmt)
153 {
154     size_t i, end = OSSL_NELEM(pk->pkeys);
155
156     for (i = 0; i < end && pk->pkeys[i].keymgmt != NULL; i++) {
157         if (keymgmt == pk->pkeys[i].keymgmt)
158             break;
159     }
160
161     return i;
162 }
163
164 void evp_keymgmt_util_cache_pkey(EVP_PKEY *pk, size_t index,
165                                  EVP_KEYMGMT *keymgmt, void *keydata)
166 {
167     if (keydata != NULL) {
168         EVP_KEYMGMT_up_ref(keymgmt);
169         pk->pkeys[index].keydata = keydata;
170         pk->pkeys[index].keymgmt = keymgmt;
171
172         /*
173          * Cache information about the key object.  Only needed for the
174          * "original" provider side key.
175          *
176          * This services functions like EVP_PKEY_size, EVP_PKEY_bits, etc
177          */
178         if (index == 0) {
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,
188                                                  &size);
189             params[3] = OSSL_PARAM_construct_end();
190             if (evp_keymgmt_get_params(keymgmt, keydata, params)) {
191                 pk->cache.size = size;
192                 pk->cache.bits = bits;
193                 pk->cache.security_bits = security_bits;
194             }
195         }
196     }
197 }
198
199 void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
200                                 int selection, const OSSL_PARAM params[])
201 {
202     void *keydata = evp_keymgmt_newdata(keymgmt);
203
204     if (keydata != NULL) {
205         if (!evp_keymgmt_import(keymgmt, keydata, selection, params)) {
206             evp_keymgmt_freedata(keymgmt, keydata);
207             return NULL;
208         }
209
210
211         evp_keymgmt_util_clear_pkey_cache(target);
212         evp_keymgmt_util_cache_pkey(target, 0, keymgmt, keydata);
213     }
214
215     return keydata;
216 }