2 * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
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
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>
15 #include <openssl/safestack.h>
16 #include "internal/provider.h"
17 #include "internal/property.h"
18 #include "crypto/evp.h"
19 #include "serializer_local.h"
21 DEFINE_STACK_OF_CSTRING()
23 int OSSL_SERIALIZER_CTX_set_cipher(OSSL_SERIALIZER_CTX *ctx,
24 const char *cipher_name,
25 const char *propquery)
27 OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };
30 OSSL_PARAM_construct_utf8_string(OSSL_SERIALIZER_PARAM_CIPHER,
31 (void *)cipher_name, 0);
33 OSSL_PARAM_construct_utf8_string(OSSL_SERIALIZER_PARAM_PROPERTIES,
34 (void *)propquery, 0);
36 return OSSL_SERIALIZER_CTX_set_params(ctx, params);
39 int OSSL_SERIALIZER_CTX_set_passphrase(OSSL_SERIALIZER_CTX *ctx,
40 const unsigned char *kstr,
43 OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
45 params[0] = OSSL_PARAM_construct_octet_string(OSSL_SERIALIZER_PARAM_PASS,
48 return OSSL_SERIALIZER_CTX_set_params(ctx, params);
51 static void serializer_ctx_reset_passphrase_ui(OSSL_SERIALIZER_CTX *ctx)
53 UI_destroy_method(ctx->allocated_ui_method);
54 ctx->allocated_ui_method = NULL;
55 ctx->ui_method = NULL;
59 int OSSL_SERIALIZER_CTX_set_passphrase_ui(OSSL_SERIALIZER_CTX *ctx,
60 const UI_METHOD *ui_method,
63 if (!ossl_assert(ctx != NULL)) {
64 ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
68 serializer_ctx_reset_passphrase_ui(ctx);
69 ctx->ui_method = ui_method;
70 ctx->ui_data = ui_data;
74 int OSSL_SERIALIZER_CTX_set_passphrase_cb(OSSL_SERIALIZER_CTX *ctx,
75 pem_password_cb *cb, void *cbarg)
77 if (!ossl_assert(ctx != NULL)) {
78 ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
82 serializer_ctx_reset_passphrase_ui(ctx);
86 ctx->allocated_ui_method = UI_UTIL_wrap_read_pem_callback(cb, 1);
89 return ctx->ui_method != NULL;
93 * Support for OSSL_SERIALIZER_CTX_new_by_TYPE:
94 * finding a suitable serializer
97 struct selected_serializer_st {
98 STACK_OF(OPENSSL_CSTRING) *names;
102 static void cache_serializers(const char *name, void *data)
104 struct selected_serializer_st *d = data;
106 if (sk_OPENSSL_CSTRING_push(d->names, name) <= 0)
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)
116 struct serializer_write_data_st {
117 OSSL_SERIALIZER_CTX *ctx;
121 static int serializer_write_cb(const OSSL_PARAM params[], void *arg)
123 struct serializer_write_data_st *write_data = arg;
124 OSSL_SERIALIZER_CTX *ctx = write_data->ctx;
125 BIO *out = write_data->out;
127 return ctx->ser->serialize_data(ctx->serctx, params, (OSSL_CORE_BIO *)out,
128 ossl_serializer_passphrase_out_cb, ctx);
132 * Support for OSSL_SERIALIZER_to_bio:
133 * Perform the actual output.
136 static int serializer_EVP_PKEY_to_bio(OSSL_SERIALIZER_CTX *ctx, BIO *out)
138 const EVP_PKEY *pkey = ctx->object;
139 void *keydata = pkey->keydata;
140 EVP_KEYMGMT *keymgmt = pkey->keymgmt;
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.
150 if (ctx->ser == NULL)
153 if (ctx->ser->serialize_object == NULL) {
154 struct serializer_write_data_st write_data;
156 write_data.ctx = ctx;
157 write_data.out = out;
159 return evp_keymgmt_export(keymgmt, keydata, ctx->selection,
160 &serializer_write_cb, &write_data);
163 return ctx->ser->serialize_object(ctx->serctx, keydata,
164 (OSSL_CORE_BIO *)out,
165 ossl_serializer_passphrase_out_cb, ctx);
169 * OSSL_SERIALIZER_CTX_new_by_EVP_PKEY() returns a ctx with no serializer if
170 * it couldn't find a suitable serializer. This allows a caller to detect if
171 * a suitable serializer was found, with OSSL_SERIALIZER_CTX_get_serializer(),
172 * and to use fallback methods if the result is NULL.
174 OSSL_SERIALIZER_CTX *OSSL_SERIALIZER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey,
175 const char *propquery)
177 OSSL_SERIALIZER_CTX *ctx = NULL;
178 OSSL_SERIALIZER *ser = NULL;
179 EVP_KEYMGMT *keymgmt = pkey->keymgmt;
180 int selection = OSSL_KEYMGMT_SELECT_ALL;
182 if (!ossl_assert(pkey != NULL && propquery != NULL)) {
183 ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
187 if (keymgmt != NULL) {
188 const OSSL_PROVIDER *desired_prov = EVP_KEYMGMT_provider(keymgmt);
189 OPENSSL_CTX *libctx = ossl_provider_library_context(desired_prov);
190 struct selected_serializer_st sel_data;
191 OSSL_SERIALIZER *first = NULL;
196 * Select the serializer in two steps. First, get the names of all of
197 * the serializers. Then determine which is the best one to use.
198 * This has to be broken because it isn't possible to fetch the
199 * serialisers inside EVP_KEYMGMT_names_do_all() due to locking
200 * order inversions with the store lock.
203 sel_data.names = sk_OPENSSL_CSTRING_new_null();
204 if (sel_data.names == NULL)
206 EVP_KEYMGMT_names_do_all(keymgmt, cache_serializers, &sel_data);
208 * Ignore memory allocation errors that are indicated in sel_data.error
209 * in case a suitable provider does get found regardless.
213 * Serializers offer two functions, one that handles object data in
214 * the form of a OSSL_PARAM array, and one that directly handles a
215 * provider side object. The latter requires that the serializer
216 * is offered by the same provider that holds that object, but is
217 * more desirable because it usually provides faster serialization.
219 * When looking up possible serializers, we save the first that can
220 * handle an OSSL_PARAM array in |first| and use that if nothing
223 for (i = 0; i < sk_OPENSSL_CSTRING_num(sel_data.names); i++) {
224 name = sk_OPENSSL_CSTRING_value(sel_data.names, i);
225 ser = OSSL_SERIALIZER_fetch(libctx, name, propquery);
227 if (OSSL_SERIALIZER_provider(ser) == desired_prov
228 && ser->serialize_object != NULL) {
229 OSSL_SERIALIZER_free(first);
232 if (first == NULL && ser->serialize_data != NULL)
235 OSSL_SERIALIZER_free(ser);
239 sk_OPENSSL_CSTRING_free(sel_data.names);
244 OSSL_PROPERTY_LIST *check = NULL, *current_props = NULL;
246 check = ossl_parse_query(libctx, "type=parameters");
248 ossl_parse_property(libctx, OSSL_SERIALIZER_properties(ser));
249 if (ossl_property_match_count(check, current_props) > 0)
250 selection = OSSL_KEYMGMT_SELECT_ALL_PARAMETERS;
251 ossl_property_free(current_props);
252 ossl_property_free(check);
255 ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE);
257 ERR_raise(ERR_LIB_OSSL_SERIALIZER,
258 OSSL_SERIALIZER_R_SERIALIZER_NOT_FOUND);
262 ctx = OSSL_SERIALIZER_CTX_new(ser); /* refcnt(ser)++ */
263 OSSL_SERIALIZER_free(ser); /* refcnt(ser)-- */
266 /* Setup for OSSL_SERIALIZE_to_bio() */
267 ctx->selection = selection;
269 ctx->do_output = serializer_EVP_PKEY_to_bio;