]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/encode_decode/encoder_pkey.c
Fix stacks of OPENSSL_STRING, OPENSSL_CSTRING and OPENSSL_BLOCK
[thirdparty/openssl.git] / crypto / encode_decode / encoder_pkey.c
CommitLineData
ece9304c
RL
1/*
2 * Copyright 2019-2020 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/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"
20
ece9304c
RL
21int OSSL_ENCODER_CTX_set_cipher(OSSL_ENCODER_CTX *ctx,
22 const char *cipher_name,
23 const char *propquery)
24{
25 OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };
26
27 params[0] =
28 OSSL_PARAM_construct_utf8_string(OSSL_ENCODER_PARAM_CIPHER,
29 (void *)cipher_name, 0);
30 params[1] =
31 OSSL_PARAM_construct_utf8_string(OSSL_ENCODER_PARAM_PROPERTIES,
32 (void *)propquery, 0);
33
34 return OSSL_ENCODER_CTX_set_params(ctx, params);
35}
36
37int OSSL_ENCODER_CTX_set_passphrase(OSSL_ENCODER_CTX *ctx,
38 const unsigned char *kstr,
39 size_t klen)
40{
8ae40cf5 41 return ossl_pw_set_passphrase(&ctx->pwdata, kstr, klen);
ece9304c
RL
42}
43
ece9304c
RL
44int OSSL_ENCODER_CTX_set_passphrase_ui(OSSL_ENCODER_CTX *ctx,
45 const UI_METHOD *ui_method,
46 void *ui_data)
47{
a517edec 48 return ossl_pw_set_ui_method(&ctx->pwdata, ui_method, ui_data);
ece9304c
RL
49}
50
51int OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX *ctx,
52 pem_password_cb *cb, void *cbarg)
53{
a517edec 54 return ossl_pw_set_pem_password_cb(&ctx->pwdata, cb, cbarg);
ece9304c
RL
55}
56
57/*
58 * Support for OSSL_ENCODER_CTX_new_by_TYPE:
59 * finding a suitable encoder
60 */
61
62struct selected_encoder_st {
63 STACK_OF(OPENSSL_CSTRING) *names;
64 int error;
65};
66
67static void cache_encoders(const char *name, void *data)
68{
69 struct selected_encoder_st *d = data;
70
71 if (sk_OPENSSL_CSTRING_push(d->names, name) <= 0)
72 d->error = 1;
73}
74
75/*
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)
79 */
80
81struct encoder_write_data_st {
82 OSSL_ENCODER_CTX *ctx;
83 BIO *out;
84};
85
86static int encoder_write_cb(const OSSL_PARAM params[], void *arg)
87{
88 struct encoder_write_data_st *write_data = arg;
89 OSSL_ENCODER_CTX *ctx = write_data->ctx;
90 BIO *out = write_data->out;
91
bd7a6f16
RL
92 return ctx->encoder->encode_data(ctx->encoderctx, params,
93 (OSSL_CORE_BIO *)out,
a517edec
RL
94 ossl_pw_passphrase_callback_enc,
95 &ctx->pwdata);
ece9304c
RL
96}
97
98/*
99 * Support for OSSL_ENCODER_to_bio:
100 * Perform the actual output.
101 */
102
103static int encoder_EVP_PKEY_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out)
104{
105 const EVP_PKEY *pkey = ctx->object;
106 void *keydata = pkey->keydata;
107 EVP_KEYMGMT *keymgmt = pkey->keymgmt;
108
109 /*
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.
116 */
117 if (ctx->encoder == NULL)
118 return 0;
119
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;
124
125 write_data.ctx = ctx;
126 write_data.out = out;
127
128 return evp_keymgmt_export(keymgmt, keydata, ctx->selection,
129 &encoder_write_cb, &write_data);
130 }
131
bd7a6f16 132 return ctx->encoder->encode_object(ctx->encoderctx, keydata,
ece9304c 133 (OSSL_CORE_BIO *)out,
a517edec
RL
134 ossl_pw_passphrase_callback_enc,
135 &ctx->pwdata);
ece9304c
RL
136}
137
138/*
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.
143 */
144OSSL_ENCODER_CTX *OSSL_ENCODER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey,
145 const char *propquery)
146{
147 OSSL_ENCODER_CTX *ctx = NULL;
148 OSSL_ENCODER *encoder = NULL;
149 EVP_KEYMGMT *keymgmt = pkey->keymgmt;
150 int selection = OSSL_KEYMGMT_SELECT_ALL;
151
152 if (!ossl_assert(pkey != NULL && propquery != NULL)) {
153 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
154 return NULL;
155 }
156
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;
162 const char *name;
163 int i;
164
165 /*
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
bd7a6f16
RL
169 * encoders inside EVP_KEYMGMT_names_do_all() due to locking order
170 * inversions with the store lock.
ece9304c
RL
171 */
172 sel_data.error = 0;
173 sel_data.names = sk_OPENSSL_CSTRING_new_null();
174 if (sel_data.names == NULL)
175 return NULL;
176 EVP_KEYMGMT_names_do_all(keymgmt, cache_encoders, &sel_data);
177 /*
178 * Ignore memory allocation errors that are indicated in sel_data.error
179 * in case a suitable provider does get found regardless.
180 */
181
182 /*
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.
188 *
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
191 * better turns up.
192 */
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);
200 break;
201 }
202 if (first == NULL && encoder->encode_data != NULL)
203 first = encoder;
204 else
205 OSSL_ENCODER_free(encoder);
206 encoder = NULL;
207 }
208 }
209 sk_OPENSSL_CSTRING_free(sel_data.names);
210 if (encoder == NULL)
211 encoder = first;
212
213 if (encoder != NULL) {
214 OSSL_PROPERTY_LIST *check = NULL, *current_props = NULL;
215
216 check = ossl_parse_query(libctx, "type=parameters");
217 current_props =
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);
223 } else {
224 if (sel_data.error)
225 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
226 else
227 ERR_raise(ERR_LIB_OSSL_ENCODER,
228 OSSL_ENCODER_R_ENCODER_NOT_FOUND);
229 }
230 }
231
232 ctx = OSSL_ENCODER_CTX_new(encoder); /* refcnt(encoder)++ */
233 OSSL_ENCODER_free(encoder); /* refcnt(encoder)-- */
234
235 if (ctx != NULL) {
236 /* Setup for OSSL_ENCODE_to_bio() */
237 ctx->selection = selection;
238 ctx->object = pkey;
239 ctx->do_output = encoder_EVP_PKEY_to_bio;
240 }
241
242 return ctx;
243}
244