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/encoder.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 "encoder_local.h"
21 int OSSL_ENCODER_CTX_set_cipher(OSSL_ENCODER_CTX *ctx,
22 const char *cipher_name,
23 const char *propquery)
25 OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };
28 OSSL_PARAM_construct_utf8_string(OSSL_ENCODER_PARAM_CIPHER,
29 (void *)cipher_name, 0);
31 OSSL_PARAM_construct_utf8_string(OSSL_ENCODER_PARAM_PROPERTIES,
32 (void *)propquery, 0);
34 return OSSL_ENCODER_CTX_set_params(ctx, params);
37 int OSSL_ENCODER_CTX_set_passphrase(OSSL_ENCODER_CTX *ctx,
38 const unsigned char *kstr,
41 return ossl_pw_set_passphrase(&ctx->pwdata, kstr, klen);
44 int OSSL_ENCODER_CTX_set_passphrase_ui(OSSL_ENCODER_CTX *ctx,
45 const UI_METHOD *ui_method,
48 return ossl_pw_set_ui_method(&ctx->pwdata, ui_method, ui_data);
51 int OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX *ctx,
52 pem_password_cb *cb, void *cbarg)
54 return ossl_pw_set_pem_password_cb(&ctx->pwdata, cb, cbarg);
58 * Support for OSSL_ENCODER_CTX_new_by_TYPE:
59 * finding a suitable encoder
62 struct selected_encoder_st {
63 STACK_OF(OPENSSL_CSTRING) *names;
67 static void cache_encoders(const char *name, void *data)
69 struct selected_encoder_st *d = data;
71 if (sk_OPENSSL_CSTRING_push(d->names, name) <= 0)
76 * Support for OSSL_ENCODER_to_bio:
77 * writing callback for the OSSL_PARAM (the implementation doesn't have
78 * intimate knowledge of the provider side object)
81 struct encoder_write_data_st {
82 OSSL_ENCODER_CTX *ctx;
86 static int encoder_write_cb(const OSSL_PARAM params[], void *arg)
88 struct encoder_write_data_st *write_data = arg;
89 OSSL_ENCODER_CTX *ctx = write_data->ctx;
90 BIO *out = write_data->out;
92 return ctx->encoder->encode_data(ctx->encoderctx, params,
94 ossl_pw_passphrase_callback_enc,
99 * Support for OSSL_ENCODER_to_bio:
100 * Perform the actual output.
103 static int encoder_EVP_PKEY_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out)
105 const EVP_PKEY *pkey = ctx->object;
106 void *keydata = pkey->keydata;
107 EVP_KEYMGMT *keymgmt = pkey->keymgmt;
110 * OSSL_ENCODER_CTX_new() creates a context, even when the
111 * encoder it's given is NULL. Callers can detect the lack
112 * of encoder with OSSL_ENCODER_CTX_get_encoder() and
113 * should take precautions, possibly call a fallback instead of
114 * OSSL_ENCODER_to_bio() / OSSL_ENCODER_to_fp(). If it's
115 * come this far, we return an error.
117 if (ctx->encoder == NULL)
120 if (ctx->encoder->encode_object == NULL
121 || (OSSL_ENCODER_provider(ctx->encoder)
122 != EVP_KEYMGMT_provider(keymgmt))) {
123 struct encoder_write_data_st write_data;
125 write_data.ctx = ctx;
126 write_data.out = out;
128 return evp_keymgmt_export(keymgmt, keydata, ctx->selection,
129 &encoder_write_cb, &write_data);
132 return ctx->encoder->encode_object(ctx->encoderctx, keydata,
133 (OSSL_CORE_BIO *)out,
134 ossl_pw_passphrase_callback_enc,
139 * OSSL_ENCODER_CTX_new_by_EVP_PKEY() returns a ctx with no encoder if
140 * it couldn't find a suitable encoder. This allows a caller to detect if
141 * a suitable encoder was found, with OSSL_ENCODER_CTX_get_encoder(),
142 * and to use fallback methods if the result is NULL.
144 OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey,
145 const char *propquery)
147 OSSL_ENCODER_CTX *ctx = NULL;
148 OSSL_ENCODER *encoder = NULL;
149 EVP_KEYMGMT *keymgmt = pkey->keymgmt;
150 int selection = OSSL_KEYMGMT_SELECT_ALL;
152 if (!ossl_assert(pkey != NULL && propquery != NULL)) {
153 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
157 if (keymgmt != NULL) {
158 const OSSL_PROVIDER *desired_prov = EVP_KEYMGMT_provider(keymgmt);
159 OPENSSL_CTX *libctx = ossl_provider_library_context(desired_prov);
160 struct selected_encoder_st sel_data;
161 OSSL_ENCODER *first = NULL;
166 * Select the encoder in two steps. First, get the names of all of
167 * the encoders. Then determine which is the best one to use.
168 * This has to be broken because it isn't possible to fetch the
169 * encoders inside EVP_KEYMGMT_names_do_all() due to locking order
170 * inversions with the store lock.
173 sel_data.names = sk_OPENSSL_CSTRING_new_null();
174 if (sel_data.names == NULL)
176 EVP_KEYMGMT_names_do_all(keymgmt, cache_encoders, &sel_data);
178 * Ignore memory allocation errors that are indicated in sel_data.error
179 * in case a suitable provider does get found regardless.
183 * Encoders offer two functions, one that handles object data in
184 * the form of a OSSL_PARAM array, and one that directly handles a
185 * provider side object. The latter requires that the encoder
186 * is offered by the same provider that holds that object, but is
187 * more desirable because it usually provides faster encoding.
189 * When looking up possible encoders, we save the first that can
190 * handle an OSSL_PARAM array in |first| and use that if nothing
193 for (i = 0; i < sk_OPENSSL_CSTRING_num(sel_data.names); i++) {
194 name = sk_OPENSSL_CSTRING_value(sel_data.names, i);
195 encoder = OSSL_ENCODER_fetch(libctx, name, propquery);
196 if (encoder != NULL) {
197 if (OSSL_ENCODER_provider(encoder) == desired_prov
198 && encoder->encode_object != NULL) {
199 OSSL_ENCODER_free(first);
202 if (first == NULL && encoder->encode_data != NULL)
205 OSSL_ENCODER_free(encoder);
209 sk_OPENSSL_CSTRING_free(sel_data.names);
213 if (encoder != NULL) {
214 OSSL_PROPERTY_LIST *check = NULL, *current_props = NULL;
216 check = ossl_parse_query(libctx, "type=parameters");
218 ossl_parse_property(libctx, OSSL_ENCODER_properties(encoder));
219 if (ossl_property_match_count(check, current_props) > 0)
220 selection = OSSL_KEYMGMT_SELECT_ALL_PARAMETERS;
221 ossl_property_free(current_props);
222 ossl_property_free(check);
225 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
227 ERR_raise(ERR_LIB_OSSL_ENCODER,
228 OSSL_ENCODER_R_ENCODER_NOT_FOUND);
232 ctx = OSSL_ENCODER_CTX_new(encoder); /* refcnt(encoder)++ */
233 OSSL_ENCODER_free(encoder); /* refcnt(encoder)-- */
236 /* Setup for OSSL_ENCODE_to_bio() */
237 ctx->selection = selection;
239 ctx->do_output = encoder_EVP_PKEY_to_bio;