SERIALIZER: add support for serializing EVP_PKEYs
[openssl.git] / crypto / serializer / serializer_pkey.c
1 /*
2  * Copyright 2019 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/serializer.h>
14 #include <openssl/core_names.h>
15 #include "internal/provider.h"
16 #include "internal/property.h"
17 #include "crypto/evp.h"
18 #include "serializer_local.h"
19
20 int OSSL_SERIALIZER_CTX_set_cipher(OSSL_SERIALIZER_CTX *ctx,
21                                    const char *cipher_name,
22                                    const char *propquery)
23 {
24     OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };
25
26     params[0] =
27         OSSL_PARAM_construct_utf8_string(OSSL_SERIALIZER_PARAM_CIPHER,
28                                          (void *)cipher_name, 0);
29     params[1] =
30         OSSL_PARAM_construct_utf8_string(OSSL_SERIALIZER_PARAM_PROPERTIES,
31                                          (void *)propquery, 0);
32
33     return OSSL_SERIALIZER_CTX_set_params(ctx, params);
34 }
35
36 int OSSL_SERIALIZER_CTX_set_passphrase(OSSL_SERIALIZER_CTX *ctx,
37                                        const unsigned char *kstr,
38                                        size_t klen)
39 {
40     OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
41
42     params[0] = OSSL_PARAM_construct_octet_string(OSSL_SERIALIZER_PARAM_PASS,
43                                                   (void *)kstr, klen);
44
45     return OSSL_SERIALIZER_CTX_set_params(ctx, params);
46 }
47
48 static void serializer_ctx_reset_passphrase_ui(OSSL_SERIALIZER_CTX *ctx)
49 {
50     UI_destroy_method(ctx->allocated_ui_method);
51     ctx->allocated_ui_method = NULL;
52     ctx->ui_method = NULL;
53     ctx->ui_data = NULL;
54 }
55
56 int OSSL_SERIALIZER_CTX_set_passphrase_ui(OSSL_SERIALIZER_CTX *ctx,
57                                           const UI_METHOD *ui_method,
58                                           void *ui_data)
59 {
60     if (!ossl_assert(ctx != NULL)) {
61         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
62         return 0;
63     }
64
65     serializer_ctx_reset_passphrase_ui(ctx);
66     ctx->ui_method = ui_method;
67     ctx->ui_data = ui_data;
68     return 1;
69 }
70
71 int OSSL_SERIALIZER_CTX_set_passphrase_cb(OSSL_SERIALIZER_CTX *ctx, int enc,
72                                           pem_password_cb *cb, void *cbarg)
73 {
74     if (!ossl_assert(ctx != NULL)) {
75         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
76         return 0;
77     }
78
79     serializer_ctx_reset_passphrase_ui(ctx);
80     if (cb == NULL)
81         return 1;
82     ctx->ui_method =
83         ctx->allocated_ui_method = UI_UTIL_wrap_read_pem_callback(cb, enc);
84     ctx->ui_data = cbarg;
85
86     return ctx->ui_method != NULL;
87 }
88
89 /*
90  * Support for OSSL_SERIALIZER_CTX_new_by_TYPE:
91  * finding a suitable serializer
92  */
93
94 struct selected_serializer_st {
95     OPENSSL_CTX *libctx;
96     const OSSL_PROVIDER *desired_provider;
97     const char *propquery;
98
99     /*
100      * When selecting serializers, we need to check the intended use.
101      * This is governed by the |domainparams| flag in the EVP_PKEY,
102      * we must just make sure to filter on 'type=domainparams' accordingly.
103      */
104     int want_domainparams;
105
106     /*
107      * Serializers offer two functions, one that handles object data in
108      * the form of a OSSL_PARAM array, and one that directly handles a
109      * provider side object.  The latter requires that the serializer
110      * is offered by the same provider that holds that object, but is
111      * more desirable because it usually provides faster serialization.
112      *
113      * When looking up possible serializers, we save the first that can
114      * handle an OSSL_PARAM array in |first|, and the first that can
115      * handle a provider side object in |desired|.
116      */
117     OSSL_SERIALIZER *first;
118     OSSL_SERIALIZER *desired;
119 };
120
121 static void select_serializer(const char *name, void *data)
122 {
123     struct selected_serializer_st *d = data;
124     OSSL_SERIALIZER *s = NULL;
125     OSSL_PROPERTY_LIST *check =
126         d->want_domainparams
127         ? ossl_parse_query(d->libctx, "type=domainparams")
128         : NULL;
129
130     /* No need to look further if we already have the more desirable option */
131     if (d->desired != NULL)
132         return;
133
134     if ((s = OSSL_SERIALIZER_fetch(d->libctx, name, d->propquery)) != NULL) {
135         /*
136          * Extra check if domain parameters are explicitly specified:
137          * only accept serializers that have the "type=domainparams"
138          * property.
139          *
140          * For data that isn't marked as domain parameters, a domain
141          * parameters serializer is still acceptable, because a key
142          * may hold domain parameters too.
143          */
144         if (d->want_domainparams) {
145             OSSL_PROPERTY_LIST *current_props =
146                 ossl_parse_property(d->libctx, OSSL_SERIALIZER_properties(s));
147             int check_cnt = ossl_property_match_count(check, current_props);
148
149             if (check_cnt == 0) {
150                 OSSL_SERIALIZER_free(s);
151                 return;
152             }
153         }
154
155         if (d->first == NULL && s->serialize_data != NULL) {
156             d->first = s;
157         } else if (OSSL_SERIALIZER_provider(s) == d->desired_provider
158                    && s->serialize_object != NULL) {
159             OSSL_SERIALIZER_free(d->first);
160             d->first = NULL;
161             d->desired = s;
162         } else {
163             OSSL_SERIALIZER_free(s);
164         }
165     }
166 }
167
168 /*
169  * Support for OSSL_SERIALIZER_CTX_new_by_TYPE and OSSL_SERIALIZER_to_bio:
170  * Passphrase callbacks
171  */
172
173 /*
174  * First, we define the generic passphrase function that supports both
175  * outgoing (with passphrase verify) and incoming (without passphrase verify)
176  * passphrase reading.
177  */
178 static int serializer_passphrase(char *pass, size_t pass_size,
179                                  size_t *pass_len, int verify,
180                                  const OSSL_PARAM params[], void *arg)
181 {
182     OSSL_SERIALIZER_CTX *ctx = arg;
183     const OSSL_PARAM *p;
184     const char *prompt_info = NULL;
185     char *prompt = NULL, *vpass = NULL;
186     int prompt_idx = -1, verify_idx = -1;
187     UI *ui = NULL;
188     int ret = 0;
189
190     if (!ossl_assert(ctx != NULL && pass != NULL
191                     && pass_size != 0 && pass_len != NULL)) {
192         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
193         return 0;
194     }
195
196     if ((p = OSSL_PARAM_locate_const(params,
197                                      OSSL_PASSPHRASE_PARAM_INFO)) != NULL) {
198         if (p->data_type != OSSL_PARAM_UTF8_STRING)
199             return 0;
200         prompt_info = p->data;
201     }
202
203     if ((ui = UI_new()) == NULL) {
204         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE);
205         return 0;
206     }
207
208     UI_set_method(ui, ctx->ui_method);
209     UI_add_user_data(ui, ctx->ui_data);
210
211     /* Get an application constructed prompt */
212     prompt = UI_construct_prompt(ui, "pass phrase", prompt_info);
213    if (prompt == NULL) {
214         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE);
215         goto end;
216     }
217
218     prompt_idx = UI_add_input_string(ui, prompt,
219                                      UI_INPUT_FLAG_DEFAULT_PWD,
220                                      pass, 0, pass_size - 1) - 1;
221     if (prompt_idx < 0) {
222         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_UI_LIB);
223         goto end;
224     }
225
226     if (verify) {
227         /* Get a buffer for verification prompt */
228         vpass = OPENSSL_zalloc(pass_size);
229         if (vpass == NULL) {
230             ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_MALLOC_FAILURE);
231             goto end;
232         }
233         verify_idx = UI_add_verify_string(ui, prompt,
234                                           UI_INPUT_FLAG_DEFAULT_PWD,
235                                           vpass, 0, pass_size - 1,
236                                           pass) - 1;
237         if (verify_idx < 0) {
238             ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_UI_LIB);
239             goto end;
240         }
241     }
242
243     switch (UI_process(ui)) {
244     case -2:
245         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_INTERRUPTED_OR_CANCELLED);
246         break;
247     case -1:
248         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_UI_LIB);
249         break;
250     default:
251         *pass_len = (size_t)UI_get_result_length(ui, prompt_idx);
252         ret = 1;
253         break;
254     }
255
256  end:
257     OPENSSL_free(vpass);
258     OPENSSL_free(prompt);
259     UI_free(ui);
260     return ret;
261 }
262
263 /* Ensure correct function definition for outgoing passphrase reader */
264 static OSSL_PASSPHRASE_CALLBACK serializer_passphrase_out_cb;
265 static int serializer_passphrase_out_cb(char *pass, size_t pass_size,
266                                         size_t *pass_len,
267                                         const OSSL_PARAM params[], void *arg)
268 {
269     return serializer_passphrase(pass, pass_size, pass_len, 1, params, arg);
270 }
271
272 /*
273  * Support for OSSL_SERIALIZER_to_bio:
274  * writing callback for the OSSL_PARAM (the implementation doesn't have
275  * intimate knowledge of the provider side object)
276  */
277
278 struct serializer_write_data_st {
279     OSSL_SERIALIZER_CTX *ctx;
280     BIO *out;
281 };
282
283 static int serializer_write_cb(const OSSL_PARAM params[], void *arg)
284 {
285     struct serializer_write_data_st *write_data = arg;
286     OSSL_SERIALIZER_CTX *ctx = write_data->ctx;
287     BIO *out = write_data->out;
288
289     return ctx->ser->serialize_data(ctx->serctx, params, out,
290                                     serializer_passphrase_out_cb, ctx);
291 }
292
293 /*
294  * Support for OSSL_SERIALIZER_to_bio:
295  * Perform the actual output.
296  */
297
298 static int serializer_EVP_PKEY_to_bio(OSSL_SERIALIZER_CTX *ctx, BIO *out)
299 {
300     const EVP_PKEY *pkey = ctx->object;
301     void *provdata = pkey->pkeys[0].provdata;
302     int domainparams = pkey->pkeys[0].domainparams;
303     EVP_KEYMGMT *keymgmt = pkey->pkeys[0].keymgmt;
304
305     /*
306      * OSSL_SERIALIZER_CTX_new() creates a context, even when the
307      * serializer it's given is NULL.  Callers can detect the lack
308      * of serializer with OSSL_SERIALIZER_CTX_get_serializer() and
309      * should take precautions, possibly call a fallback instead of
310      * OSSL_SERIALIZER_to_bio() / OSSL_SERIALIZER_to_fp().  If it's
311      * come this far, we return an error.
312      */
313     if (ctx->ser == NULL)
314         return 0;
315
316     if (ctx->ser->serialize_object == NULL) {
317         struct serializer_write_data_st write_data;
318
319         write_data.ctx = ctx;
320         write_data.out = out;
321
322         if (domainparams)
323             return evp_keymgmt_exportdomparams(keymgmt, provdata,
324                                                serializer_write_cb,
325                                                &write_data);
326         return evp_keymgmt_exportkey(keymgmt, provdata,
327                                      serializer_write_cb, &write_data);
328     }
329
330     return ctx->ser->serialize_object(ctx->serctx, provdata, out,
331                                       serializer_passphrase_out_cb, ctx);
332 }
333
334 /*
335  * OSSL_SERIALIZER_CTX_new_by_EVP_PKEY() returns a ctx with no serializer if
336  * it couldn't find a suitable serializer.  This allows a caller to detect if
337  * a suitable serializer was found, with OSSL_SERIALIZER_CTX_get_serializer(),
338  * and to use fallback methods if the result is NULL.
339  */
340 OSSL_SERIALIZER_CTX *OSSL_SERIALIZER_CTX_new_by_EVP_PKEY(const EVP_PKEY *pkey,
341                                                          const char *propquery)
342 {
343     OSSL_SERIALIZER_CTX *ctx = NULL;
344     OSSL_SERIALIZER *ser = NULL;
345     EVP_KEYMGMT *keymgmt = pkey->pkeys[0].keymgmt;
346
347     if (!ossl_assert(pkey != NULL && propquery != NULL)) {
348         ERR_raise(ERR_LIB_OSSL_SERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
349         return NULL;
350     }
351
352     if (keymgmt != NULL) {
353         const OSSL_PROVIDER *desired_prov = EVP_KEYMGMT_provider(keymgmt);
354         OPENSSL_CTX *libctx = ossl_provider_library_context(desired_prov);
355         struct selected_serializer_st sel_data;
356
357         memset(&sel_data, 0, sizeof(sel_data));
358         sel_data.libctx = libctx;
359         sel_data.desired_provider = desired_prov;
360         sel_data.propquery = propquery;
361         sel_data.want_domainparams = pkey->pkeys[0].domainparams;
362         EVP_KEYMGMT_names_do_all(keymgmt, select_serializer, &sel_data);
363
364         if (sel_data.desired != NULL) {
365             ser = sel_data.desired;
366             sel_data.desired = NULL;
367         } else if (sel_data.first != NULL) {
368             ser = sel_data.first;
369             sel_data.first = NULL;
370         }
371         OSSL_SERIALIZER_free(sel_data.first);
372         OSSL_SERIALIZER_free(sel_data.desired);
373     }
374
375     ctx = OSSL_SERIALIZER_CTX_new(ser); /* refcnt(ser)++ */
376     OSSL_SERIALIZER_free(ser);          /* refcnt(ser)-- */
377
378     if (ctx != NULL) {
379         /* Setup for OSSL_SERIALIZE_to_bio() */
380         ctx->object = pkey;
381         ctx->do_output = serializer_EVP_PKEY_to_bio;
382     }
383
384     return ctx;
385 }
386