a88d65dc5eda19ab5a6673f95e3a76e291ef16e2
[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 }