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
;