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