]>
Commit | Line | Data |
---|---|---|
866234ac | 1 | /* |
33388b44 | 2 | * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. |
866234ac RL |
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/err.h> | |
11 | #include <openssl/ui.h> | |
12 | #include <openssl/params.h> | |
13 | #include <openssl/serializer.h> | |
14 | #include <openssl/core_names.h> | |
90cf3099 | 15 | #include <openssl/safestack.h> |
866234ac RL |
16 | #include "internal/provider.h" |
17 | #include "internal/property.h" | |
18 | #include "crypto/evp.h" | |
19 | #include "serializer_local.h" | |
20 | ||
90cf3099 P |
21 | DEFINE_STACK_OF_CSTRING() |
22 | ||
866234ac RL |
23 | int OSSL_SERIALIZER_CTX_set_cipher(OSSL_SERIALIZER_CTX *ctx, |
24 | const char *cipher_name, | |
25 | const char *propquery) | |
26 | { | |
27 | OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END }; | |
28 | ||
29 | params[0] = | |
30 | OSSL_PARAM_construct_utf8_string(OSSL_SERIALIZER_PARAM_CIPHER, | |
31 | (void *)cipher_name, 0); | |
32 | params[1] = | |
33 | OSSL_PARAM_construct_utf8_string(OSSL_SERIALIZER_PARAM_PROPERTIES, | |
34 | (void *)propquery, 0); | |
35 | ||
36 | return OSSL_SERIALIZER_CTX_set_params(ctx, params); | |
37 | } | |
38 | ||
39 | int OSSL_SERIALIZER_CTX_set_passphrase(OSSL_SERIALIZER_CTX *ctx, | |
40 | const unsigned char *kstr, | |
41 | size_t klen) | |
42 | { | |
43 | OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END }; | |
44 | ||
45 | params[0] = OSSL_PARAM_construct_octet_string(OSSL_SERIALIZER_PARAM_PASS, | |
46 | (void *)kstr, klen); | |
47 | ||
48 | return OSSL_SERIALIZER_CTX_set_params(ctx, params); | |
49 | } | |
50 | ||
51 | static void serializer_ctx_reset_passphrase_ui(OSSL_SERIALIZER_CTX *ctx) | |
52 | { | |
53 | UI_destroy_method(ctx->allocated_ui_method); | |
54 | ctx->allocated_ui_method = NULL; | |
55 | ctx->ui_method = NULL; | |
56 | ctx->ui_data = NULL; | |
57 | } | |
58 | ||
59 | int OSSL_SERIALIZER_CTX_set_passphrase_ui(OSSL_SERIALIZER_CTX *ctx, | |
60 | const UI_METHOD *ui_method, | |
61 | void *ui_data) | |
62 | { | |
63 | if (!ossl_assert(ctx != NULL)) { | |
64 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER); | |
65 | return 0; | |
66 | } | |
67 | ||
68 | serializer_ctx_reset_passphrase_ui(ctx); | |
69 | ctx->ui_method = ui_method; | |
70 | ctx->ui_data = ui_data; | |
71 | return 1; | |
72 | } | |
73 | ||
45396db0 | 74 | int OSSL_SERIALIZER_CTX_set_passphrase_cb(OSSL_SERIALIZER_CTX *ctx, |
866234ac RL |
75 | pem_password_cb *cb, void *cbarg) |
76 | { | |
77 | if (!ossl_assert(ctx != NULL)) { | |
78 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER); | |
79 | return 0; | |
80 | } | |
81 | ||
82 | serializer_ctx_reset_passphrase_ui(ctx); | |
83 | if (cb == NULL) | |
84 | return 1; | |
85 | ctx->ui_method = | |
45396db0 | 86 | ctx->allocated_ui_method = UI_UTIL_wrap_read_pem_callback(cb, 1); |
866234ac RL |
87 | ctx->ui_data = cbarg; |
88 | ||
89 | return ctx->ui_method != NULL; | |
90 | } | |
91 | ||
92 | /* | |
93 | * Support for OSSL_SERIALIZER_CTX_new_by_TYPE: | |
94 | * finding a suitable serializer | |
95 | */ | |
96 | ||
97 | struct selected_serializer_st { | |
90cf3099 P |
98 | STACK_OF(OPENSSL_CSTRING) *names; |
99 | int error; | |
866234ac RL |
100 | }; |
101 | ||
90cf3099 | 102 | static void cache_serializers(const char *name, void *data) |
866234ac RL |
103 | { |
104 | struct selected_serializer_st *d = data; | |
90cf3099 P |
105 | |
106 | if (sk_OPENSSL_CSTRING_push(d->names, name) <= 0) | |
107 | d->error = 1; | |
866234ac RL |
108 | } |
109 | ||
866234ac RL |
110 | /* |
111 | * Support for OSSL_SERIALIZER_to_bio: | |
112 | * writing callback for the OSSL_PARAM (the implementation doesn't have | |
113 | * intimate knowledge of the provider side object) | |
114 | */ | |
115 | ||
116 | struct serializer_write_data_st { | |
117 | OSSL_SERIALIZER_CTX *ctx; | |
118 | BIO *out; | |
119 | }; | |
120 | ||
121 | static int serializer_write_cb(const OSSL_PARAM params[], void *arg) | |
122 | { | |
123 | struct serializer_write_data_st *write_data = arg; | |
124 | OSSL_SERIALIZER_CTX *ctx = write_data->ctx; | |
125 | BIO *out = write_data->out; | |
126 | ||
d40b42ab | 127 | return ctx->ser->serialize_data(ctx->serctx, params, (OSSL_CORE_BIO *)out, |
7524b7b7 | 128 | ossl_serializer_passphrase_out_cb, ctx); |
866234ac RL |
129 | } |
130 | ||
131 | /* | |
132 | * Support for OSSL_SERIALIZER_to_bio: | |
133 | * Perform the actual output. | |
134 | */ | |
135 | ||
136 | static int serializer_EVP_PKEY_to_bio(OSSL_SERIALIZER_CTX *ctx, BIO *out) | |
137 | { | |
138 | const EVP_PKEY *pkey = ctx->object; | |
3c6ed955 RL |
139 | void *keydata = pkey->keydata; |
140 | EVP_KEYMGMT *keymgmt = pkey->keymgmt; | |
866234ac RL |
141 | |
142 | /* | |
143 | * OSSL_SERIALIZER_CTX_new() creates a context, even when the | |
144 | * serializer it's given is NULL. Callers can detect the lack | |
145 | * of serializer with OSSL_SERIALIZER_CTX_get_serializer() and | |
146 | * should take precautions, possibly call a fallback instead of | |
147 | * OSSL_SERIALIZER_to_bio() / OSSL_SERIALIZER_to_fp(). If it's | |
148 | * come this far, we return an error. | |
149 | */ | |
150 | if (ctx->ser == NULL) | |
151 | return 0; | |
152 | ||
af88e64a SL |
153 | if (ctx->ser->serialize_object == NULL |
154 | || OSSL_SERIALIZER_provider(ctx->ser) != EVP_KEYMGMT_provider(keymgmt)) { | |
866234ac RL |
155 | struct serializer_write_data_st write_data; |
156 | ||
157 | write_data.ctx = ctx; | |
158 | write_data.out = out; | |
159 | ||
b305452f RL |
160 | return evp_keymgmt_export(keymgmt, keydata, ctx->selection, |
161 | &serializer_write_cb, &write_data); | |
866234ac RL |
162 | } |
163 | ||
d40b42ab MC |
164 | return ctx->ser->serialize_object(ctx->serctx, keydata, |
165 | (OSSL_CORE_BIO *)out, | |
7524b7b7 | 166 | ossl_serializer_passphrase_out_cb, ctx); |
866234ac RL |
167 | } |
168 | ||
169 | /* | |
170 | * OSSL_SERIALIZER_CTX_new_by_EVP_PKEY() returns a ctx with no serializer if | |
171 | * it couldn't find a suitable serializer. This allows a caller to detect if | |
172 | * a suitable serializer was found, with OSSL_SERIALIZER_CTX_get_serializer(), | |
173 | * and to use fallback methods if the result is NULL. | |
174 | */ | |
175 | OSSL_SERIALIZER_CTX *OSSL_SERIALIZER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey, | |
176 | const char *propquery) | |
177 | { | |
178 | OSSL_SERIALIZER_CTX *ctx = NULL; | |
179 | OSSL_SERIALIZER *ser = NULL; | |
3c6ed955 | 180 | EVP_KEYMGMT *keymgmt = pkey->keymgmt; |
b305452f | 181 | int selection = OSSL_KEYMGMT_SELECT_ALL; |
866234ac RL |
182 | |
183 | if (!ossl_assert(pkey != NULL && propquery != NULL)) { | |
184 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER); | |
185 | return NULL; | |
186 | } | |
187 | ||
188 | if (keymgmt != NULL) { | |
189 | const OSSL_PROVIDER *desired_prov = EVP_KEYMGMT_provider(keymgmt); | |
190 | OPENSSL_CTX *libctx = ossl_provider_library_context(desired_prov); | |
191 | struct selected_serializer_st sel_data; | |
90cf3099 P |
192 | OSSL_SERIALIZER *first = NULL; |
193 | const char *name; | |
194 | int i; | |
195 | ||
196 | /* | |
197 | * Select the serializer in two steps. First, get the names of all of | |
198 | * the serializers. Then determine which is the best one to use. | |
199 | * This has to be broken because it isn't possible to fetch the | |
200 | * serialisers inside EVP_KEYMGMT_names_do_all() due to locking | |
201 | * order inversions with the store lock. | |
202 | */ | |
203 | sel_data.error = 0; | |
204 | sel_data.names = sk_OPENSSL_CSTRING_new_null(); | |
205 | if (sel_data.names == NULL) | |
206 | return NULL; | |
207 | EVP_KEYMGMT_names_do_all(keymgmt, cache_serializers, &sel_data); | |
208 | /* | |
209 | * Ignore memory allocation errors that are indicated in sel_data.error | |
210 | * in case a suitable provider does get found regardless. | |
211 | */ | |
212 | ||
213 | /* | |
214 | * Serializers offer two functions, one that handles object data in | |
215 | * the form of a OSSL_PARAM array, and one that directly handles a | |
216 | * provider side object. The latter requires that the serializer | |
217 | * is offered by the same provider that holds that object, but is | |
218 | * more desirable because it usually provides faster serialization. | |
219 | * | |
220 | * When looking up possible serializers, we save the first that can | |
221 | * handle an OSSL_PARAM array in |first| and use that if nothing | |
222 | * better turns up. | |
223 | */ | |
224 | for (i = 0; i < sk_OPENSSL_CSTRING_num(sel_data.names); i++) { | |
225 | name = sk_OPENSSL_CSTRING_value(sel_data.names, i); | |
226 | ser = OSSL_SERIALIZER_fetch(libctx, name, propquery); | |
227 | if (ser != NULL) { | |
228 | if (OSSL_SERIALIZER_provider(ser) == desired_prov | |
229 | && ser->serialize_object != NULL) { | |
230 | OSSL_SERIALIZER_free(first); | |
231 | break; | |
232 | } | |
233 | if (first == NULL && ser->serialize_data != NULL) | |
234 | first = ser; | |
235 | else | |
236 | OSSL_SERIALIZER_free(ser); | |
237 | ser = NULL; | |
238 | } | |
866234ac | 239 | } |
90cf3099 P |
240 | sk_OPENSSL_CSTRING_free(sel_data.names); |
241 | if (ser == NULL) | |
242 | ser = first; | |
b305452f | 243 | |
55ecb812 | 244 | if (ser != NULL) { |
587e4e53 NT |
245 | OSSL_PROPERTY_LIST *check = NULL, *current_props = NULL; |
246 | ||
247 | check = ossl_parse_query(libctx, "type=parameters"); | |
55ecb812 MC |
248 | current_props = |
249 | ossl_parse_property(libctx, OSSL_SERIALIZER_properties(ser)); | |
250 | if (ossl_property_match_count(check, current_props) > 0) | |
251 | selection = OSSL_KEYMGMT_SELECT_ALL_PARAMETERS; | |
252 | ossl_property_free(current_props); | |
90cf3099 P |
253 | ossl_property_free(check); |
254 | } else { | |
255 | if (sel_data.error) | |
256 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE); | |
257 | else | |
258 | ERR_raise(ERR_LIB_OSSL_SERIALIZER, | |
259 | OSSL_SERIALIZER_R_SERIALIZER_NOT_FOUND); | |
55ecb812 | 260 | } |
866234ac RL |
261 | } |
262 | ||
263 | ctx = OSSL_SERIALIZER_CTX_new(ser); /* refcnt(ser)++ */ | |
264 | OSSL_SERIALIZER_free(ser); /* refcnt(ser)-- */ | |
265 | ||
266 | if (ctx != NULL) { | |
267 | /* Setup for OSSL_SERIALIZE_to_bio() */ | |
b305452f | 268 | ctx->selection = selection; |
866234ac RL |
269 | ctx->object = pkey; |
270 | ctx->do_output = serializer_EVP_PKEY_to_bio; | |
271 | } | |
272 | ||
273 | return ctx; | |
274 | } | |
275 |