7c63a76adbb85344b18ec09574a7df6bf5cb32f5
[openssl.git] / crypto / encode_decode / encoder_pkey.c
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
21 int 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
37 int OSSL_ENCODER_CTX_set_passphrase(OSSL_ENCODER_CTX *ctx,
38                                     const unsigned char *kstr,
39                                     size_t klen)
40 {
41     return ossl_pw_set_passphrase(&ctx->pwdata, kstr, klen);
42 }
43
44 int OSSL_ENCODER_CTX_set_passphrase_ui(OSSL_ENCODER_CTX *ctx,
45                                        const UI_METHOD *ui_method,
46                                        void *ui_data)
47 {
48     return ossl_pw_set_ui_method(&ctx->pwdata, ui_method, ui_data);
49 }
50
51 int OSSL_ENCODER_CTX_set_passphrase_cb(OSSL_ENCODER_CTX *ctx,
52                                        pem_password_cb *cb, void *cbarg)
53 {
54     return ossl_pw_set_pem_password_cb(&ctx->pwdata, cb, cbarg);
55 }
56
57 /*
58  * Support for OSSL_ENCODER_CTX_new_by_TYPE:
59  * finding a suitable encoder
60  */
61
62 struct selected_encoder_st {
63     STACK_OF(OPENSSL_CSTRING) *names;
64     int error;
65 };
66
67 static 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
81 struct encoder_write_data_st {
82     OSSL_ENCODER_CTX *ctx;
83     BIO *out;
84 };
85
86 static 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
92     return ctx->encoder->encode_data(ctx->encoderctx, params,
93                                      (OSSL_CORE_BIO *)out,
94                                      ossl_pw_passphrase_callback_enc,
95                                      &ctx->pwdata);
96 }
97
98 /*
99  * Support for OSSL_ENCODER_to_bio:
100  * Perform the actual output.
101  */
102
103 static 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
132     return ctx->encoder->encode_object(ctx->encoderctx, keydata,
133                                        (OSSL_CORE_BIO *)out,
134                                        ossl_pw_passphrase_callback_enc,
135                                        &ctx->pwdata);
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  */
144 OSSL_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
169          * encoders inside EVP_KEYMGMT_names_do_all() due to locking order
170          * inversions with the store lock.
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