]>
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 | } |