]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/serializer/deserializer_lib.c
Rename OSSL_SERIALIZER / OSSL_DESERIALIZER to OSSL_ENCODE / OSSL_DECODE
[thirdparty/openssl.git] / crypto / serializer / deserializer_lib.c
CommitLineData
c3e4c1f3
RL
1/*
2 * Copyright 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/core_names.h>
11#include <openssl/bio.h>
12#include <openssl/params.h>
13#include <openssl/provider.h>
14#include "serializer_local.h"
15#include "e_os.h"
16
17struct deser_process_data_st {
18 OSSL_DESERIALIZER_CTX *ctx;
19
20 /* Current BIO */
21 BIO *bio;
22
23 /* Index of the current deserializer instance to be processed */
24 size_t current_deser_inst_index;
25};
26
27static int deser_process(const OSSL_PARAM params[], void *arg);
28
29int OSSL_DESERIALIZER_from_bio(OSSL_DESERIALIZER_CTX *ctx, BIO *in)
30{
31 struct deser_process_data_st data;
7524b7b7 32 int ok = 0;
c3e4c1f3
RL
33
34 memset(&data, 0, sizeof(data));
35 data.ctx = ctx;
36 data.bio = in;
37
7524b7b7
RL
38 ok = deser_process(NULL, &data);
39
4701f0a9
RL
40 /* Clear any internally cached passphrase */
41 if (!ctx->flag_user_passphrase) {
42 OSSL_DESERIALIZER_CTX_set_passphrase(ctx, NULL, 0);
43 ctx->flag_user_passphrase = 0;
44 }
7524b7b7 45 return ok;
c3e4c1f3
RL
46}
47
48#ifndef OPENSSL_NO_STDIO
49static BIO *bio_from_file(FILE *fp)
50{
51 BIO *b;
52
53 if ((b = BIO_new(BIO_s_file())) == NULL) {
54 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_BIO_LIB);
55 return NULL;
56 }
57 BIO_set_fp(b, fp, BIO_NOCLOSE);
58 return b;
59}
60
61int OSSL_DESERIALIZER_from_fp(OSSL_DESERIALIZER_CTX *ctx, FILE *fp)
62{
63 BIO *b = bio_from_file(fp);
64 int ret = 0;
65
66 if (b != NULL)
67 ret = OSSL_DESERIALIZER_from_bio(ctx, b);
68
69 BIO_free(b);
70 return ret;
71}
72#endif
73
74int OSSL_DESERIALIZER_CTX_set_input_type(OSSL_DESERIALIZER_CTX *ctx,
75 const char *input_type)
76{
77 if (!ossl_assert(ctx != NULL)) {
78 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
79 return 0;
80 }
81
82 /*
83 * NULL is a valid starting input type, and means that the caller leaves
84 * it to code to discover what the starting input type is.
85 */
86 ctx->start_input_type = input_type;
87 return 1;
88}
89
90int OSSL_DESERIALIZER_CTX_add_deserializer(OSSL_DESERIALIZER_CTX *ctx,
91 OSSL_DESERIALIZER *deser)
92{
93 OSSL_DESERIALIZER_INSTANCE *deser_inst = NULL;
94 const OSSL_PROVIDER *prov = NULL;
95 OSSL_PARAM params[2];
96 void *provctx = NULL;
97
98 if (!ossl_assert(ctx != NULL) || !ossl_assert(deser != NULL)) {
99 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
100 return 0;
101 }
102
103 if (deser->get_params == NULL) {
104 ERR_raise(ERR_LIB_OSSL_DESERIALIZER,
105 OSSL_DESERIALIZER_R_MISSING_GET_PARAMS);
106 return 0;
107 }
108
109 if (ctx->deser_insts == NULL
110 && (ctx->deser_insts =
111 sk_OSSL_DESERIALIZER_INSTANCE_new_null()) == NULL) {
112 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_MALLOC_FAILURE);
113 return 0;
114 }
115 if ((deser_inst = OPENSSL_zalloc(sizeof(*deser_inst))) == NULL) {
116 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_MALLOC_FAILURE);
117 return 0;
118 }
119 if (!OSSL_DESERIALIZER_up_ref(deser)) {
120 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_INTERNAL_ERROR);
121 goto err;
122 }
123 deser_inst->deser = deser;
124
125 prov = OSSL_DESERIALIZER_provider(deser_inst->deser);
126 provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
127
128 /* Cache the input type for this serializer */
129 params[0] =
130 OSSL_PARAM_construct_utf8_ptr(OSSL_DESERIALIZER_PARAM_INPUT_TYPE,
131 (char **)&deser_inst->input_type, 0);
132 params[1] = OSSL_PARAM_construct_end();
133
134 if (!deser_inst->deser->get_params(params)
135 || !OSSL_PARAM_modified(&params[0]))
136 goto err;
137
138 if ((deser_inst->deserctx = deser_inst->deser->newctx(provctx))
139 == NULL)
140 goto err;
141
142 if (sk_OSSL_DESERIALIZER_INSTANCE_push(ctx->deser_insts, deser_inst) <= 0)
143 goto err;
144
145 return 1;
146 err:
147 if (deser_inst != NULL) {
148 if (deser_inst->deser != NULL)
149 deser_inst->deser->freectx(deser_inst->deserctx);
150 OSSL_DESERIALIZER_free(deser_inst->deser);
151 OPENSSL_free(deser_inst);
152 }
153 return 0;
154}
155
156int OSSL_DESERIALIZER_CTX_add_extra(OSSL_DESERIALIZER_CTX *ctx,
157 OPENSSL_CTX *libctx, const char *propq)
158{
159 /*
160 * This function goes through existing deserializer methods in
161 * |ctx->deser_insts|, and tries to fetch new deserializers that produce
162 * what the existing ones want as input, and push those newly fetched
163 * deserializers on top of the same stack.
164 * Then it does the same again, but looping over the newly fetched
165 * deserializers, until there are no more serializers to be fetched, or
166 * when we have done this 10 times.
167 *
168 * we do this with sliding windows on the stack by keeping track of indexes
169 * and of the end.
170 *
171 * +----------------+
172 * | DER to RSA | <--- w_prev_start
173 * +----------------+
174 * | DER to DSA |
175 * +----------------+
176 * | DER to DH |
177 * +----------------+
178 * | PEM to DER | <--- w_prev_end, w_new_start
179 * +----------------+
180 * <--- w_new_end
181 */
182 size_t w_prev_start, w_prev_end; /* "previous" deserializers */
183 size_t w_new_start, w_new_end; /* "new" deserializers */
184 size_t count = 0; /* Calculates how many were added in each iteration */
185 size_t depth = 0; /* Counts the number of iterations */
186
187 if (!ossl_assert(ctx != NULL)) {
188 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
189 return 0;
190 }
191
192 /*
193 * If there is no stack of OSSL_DESERIALIZER_INSTANCE, we have nothing
194 * more to add. That's fine.
195 */
196 if (ctx->deser_insts == NULL)
197 return 1;
198
199 w_prev_start = 0;
200 w_prev_end = sk_OSSL_DESERIALIZER_INSTANCE_num(ctx->deser_insts);
201 do {
202 size_t i;
203
204 w_new_start = w_new_end = w_prev_end;
205
206 for (i = w_prev_start; i < w_prev_end; i++) {
207 OSSL_DESERIALIZER_INSTANCE *deser_inst =
208 sk_OSSL_DESERIALIZER_INSTANCE_value(ctx->deser_insts, i);
209 const char *name = deser_inst->input_type;
210 OSSL_DESERIALIZER *deser = NULL;
211
212 /*
213 * If the caller has specified what the initial input should be,
214 * and the deserializer implementation we're looking at has that
215 * input type, there's no point adding on more implementations
216 * on top of this one, so we don't.
217 */
218 if (ctx->start_input_type != NULL
219 && strcasecmp(ctx->start_input_type,
220 deser_inst->input_type) != 0)
221 continue;
222
223 ERR_set_mark();
224 deser = OSSL_DESERIALIZER_fetch(libctx, name, propq);
225 ERR_pop_to_mark();
226
227 if (deser != NULL) {
228 size_t j;
229
230 /*
231 * Check that we don't already have this deserializer in our
232 * stack We only need to check among the newly added ones.
233 */
234 for (j = w_new_start; j < w_new_end; j++) {
235 OSSL_DESERIALIZER_INSTANCE *check_inst =
236 sk_OSSL_DESERIALIZER_INSTANCE_value(ctx->deser_insts, j);
237
238 if (deser == check_inst->deser) {
239 /* We found it, so drop the new fetch */
240 OSSL_DESERIALIZER_free(deser);
241 deser = NULL;
242 break;
243 }
244 }
245 }
246
247 if (deser == NULL)
248 continue;
249
250 /*
251 * Apart from keeping w_new_end up to date, We don't care about
252 * errors here. If it doesn't collect, then it doesn't...
253 */
254 if (OSSL_DESERIALIZER_CTX_add_deserializer(ctx, deser)) /* ref++ */
255 w_new_end++;
256 OSSL_DESERIALIZER_free(deser); /* ref-- */
257 }
258 /* How many were added in this iteration */
259 count = w_new_end - w_new_start;
260
261 /* Slide the "previous deserializer" windows */
262 w_prev_start = w_new_start;
263 w_prev_end = w_new_end;
264
265 depth++;
266 } while (count != 0 && depth <= 10);
267
268 return 1;
269}
270
271int OSSL_DESERIALIZER_CTX_num_deserializers(OSSL_DESERIALIZER_CTX *ctx)
272{
273 if (ctx == NULL || ctx->deser_insts == NULL)
274 return 0;
275 return sk_OSSL_DESERIALIZER_INSTANCE_num(ctx->deser_insts);
276}
277
3c033c5b
RL
278int OSSL_DESERIALIZER_CTX_set_construct(OSSL_DESERIALIZER_CTX *ctx,
279 OSSL_DESERIALIZER_CONSTRUCT *construct)
c3e4c1f3
RL
280{
281 if (!ossl_assert(ctx != NULL)) {
282 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
283 return 0;
284 }
3c033c5b 285 ctx->construct = construct;
c3e4c1f3
RL
286 return 1;
287}
288
3c033c5b
RL
289int OSSL_DESERIALIZER_CTX_set_construct_data(OSSL_DESERIALIZER_CTX *ctx,
290 void *construct_data)
291{
292 if (!ossl_assert(ctx != NULL)) {
293 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
294 return 0;
295 }
296 ctx->construct_data = construct_data;
297 return 1;
298}
299
300int OSSL_DESERIALIZER_CTX_set_cleanup(OSSL_DESERIALIZER_CTX *ctx,
301 OSSL_DESERIALIZER_CLEANUP *cleanup)
302{
303 if (!ossl_assert(ctx != NULL)) {
304 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
305 return 0;
306 }
307 ctx->cleanup = cleanup;
308 return 1;
309}
310
311OSSL_DESERIALIZER_CONSTRUCT *
312OSSL_DESERIALIZER_CTX_get_construct(OSSL_DESERIALIZER_CTX *ctx)
313{
314 if (ctx == NULL)
315 return NULL;
316 return ctx->construct;
317}
318
319void *OSSL_DESERIALIZER_CTX_get_construct_data(OSSL_DESERIALIZER_CTX *ctx)
320{
321 if (ctx == NULL)
322 return NULL;
323 return ctx->construct_data;
324}
325
326OSSL_DESERIALIZER_CLEANUP *
327OSSL_DESERIALIZER_CTX_get_cleanup(OSSL_DESERIALIZER_CTX *ctx)
328{
329 if (ctx == NULL)
330 return NULL;
331 return ctx->cleanup;
332}
333
c3e4c1f3
RL
334int OSSL_DESERIALIZER_export(OSSL_DESERIALIZER_INSTANCE *deser_inst,
335 void *reference, size_t reference_sz,
336 OSSL_CALLBACK *export_cb, void *export_cbarg)
337{
338 if (!(ossl_assert(deser_inst != NULL)
339 && ossl_assert(reference != NULL)
340 && ossl_assert(export_cb != NULL)
341 && ossl_assert(export_cbarg != NULL))) {
342 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
343 return 0;
344 }
345
346 return deser_inst->deser->export_object(deser_inst->deserctx,
347 reference, reference_sz,
348 export_cb, export_cbarg);
349}
350
351OSSL_DESERIALIZER *OSSL_DESERIALIZER_INSTANCE_deserializer
352 (OSSL_DESERIALIZER_INSTANCE *deser_inst)
353{
354 if (deser_inst == NULL)
355 return NULL;
356 return deser_inst->deser;
357}
358
359void *OSSL_DESERIALIZER_INSTANCE_deserializer_ctx
360 (OSSL_DESERIALIZER_INSTANCE *deser_inst)
361{
362 if (deser_inst == NULL)
363 return NULL;
364 return deser_inst->deserctx;
365}
366
367static int deser_process(const OSSL_PARAM params[], void *arg)
368{
369 struct deser_process_data_st *data = arg;
370 OSSL_DESERIALIZER_CTX *ctx = data->ctx;
371 OSSL_DESERIALIZER_INSTANCE *deser_inst = NULL;
372 OSSL_DESERIALIZER *deser = NULL;
373 BIO *bio = data->bio;
374 long loc;
375 size_t i;
376 int ok = 0;
377 /* For recursions */
378 struct deser_process_data_st new_data;
379
380 memset(&new_data, 0, sizeof(new_data));
381 new_data.ctx = data->ctx;
382
383 if (params == NULL) {
384 /* First iteration, where we prepare for what is to come */
385
386 data->current_deser_inst_index =
387 OSSL_DESERIALIZER_CTX_num_deserializers(ctx);
388
389 bio = data->bio;
390 } else {
391 const OSSL_PARAM *p;
392
393 deser_inst =
394 sk_OSSL_DESERIALIZER_INSTANCE_value(ctx->deser_insts,
395 data->current_deser_inst_index);
396 deser = OSSL_DESERIALIZER_INSTANCE_deserializer(deser_inst);
397
3c033c5b
RL
398 if (ctx->construct != NULL
399 && ctx->construct(deser_inst, params, ctx->construct_data)) {
c3e4c1f3
RL
400 ok = 1;
401 goto end;
402 }
403
3c033c5b 404 /* The constructor didn't return success */
c3e4c1f3
RL
405
406 /*
407 * so we try to use the object we got and feed it to any next
408 * deserializer that will take it. Object references are not
409 * allowed for this.
410 * If this data isn't present, deserialization has failed.
411 */
412
413 p = OSSL_PARAM_locate_const(params, OSSL_DESERIALIZER_PARAM_DATA);
414 if (p == NULL || p->data_type != OSSL_PARAM_OCTET_STRING)
415 goto end;
416 new_data.bio = BIO_new_mem_buf(p->data, (int)p->data_size);
417 if (new_data.bio == NULL)
418 goto end;
419 bio = new_data.bio;
420 }
421
422 /*
423 * If we have no more deserializers to look through at this point,
424 * we failed
425 */
426 if (data->current_deser_inst_index == 0)
427 goto end;
428
429 if ((loc = BIO_tell(bio)) < 0) {
430 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_BIO_LIB);
431 goto end;
432 }
433
434 for (i = data->current_deser_inst_index; i-- > 0;) {
435 OSSL_DESERIALIZER_INSTANCE *new_deser_inst =
436 sk_OSSL_DESERIALIZER_INSTANCE_value(ctx->deser_insts, i);
437 OSSL_DESERIALIZER *new_deser =
438 OSSL_DESERIALIZER_INSTANCE_deserializer(new_deser_inst);
439
440 /*
441 * If |deser| is NULL, it means we've just started, and the caller
442 * may have specified what it expects the initial input to be. If
443 * that's the case, we do this extra check.
444 */
445 if (deser == NULL && ctx->start_input_type != NULL
790a1b03
RL
446 && strcasecmp(ctx->start_input_type,
447 new_deser_inst->input_type) != 0)
c3e4c1f3
RL
448 continue;
449
450 /*
451 * If we have a previous deserializer, we check that the input type
452 * of the next to be used matches the type of this previous one.
453 * deser_inst->input_type is a cache of the parameter "input-type"
454 * value for that deserializer.
455 */
456 if (deser != NULL
457 && !OSSL_DESERIALIZER_is_a(deser, new_deser_inst->input_type))
458 continue;
459
1dbf4537
RL
460 /*
461 * Checking the return value of BIO_reset() or BIO_seek() is unsafe.
462 * Furthermore, BIO_reset() is unsafe to use if the source BIO happens
463 * to be a BIO_s_mem(), because the earlier BIO_tell() gives us zero
464 * no matter where we are in the underlying buffer we're reading from.
465 *
466 * So, we simply do a BIO_seek(), and use BIO_tell() that we're back
467 * at the same position. This is a best effort attempt, but BIO_seek()
468 * and BIO_tell() should come as a pair...
469 */
470 (void)BIO_seek(bio, loc);
471 if (BIO_tell(bio) != loc)
472 goto end;
c3e4c1f3
RL
473
474 /* Recurse */
475 new_data.current_deser_inst_index = i;
476 ok = new_deser->deserialize(new_deser_inst->deserctx,
477 (OSSL_CORE_BIO *)bio,
478 deser_process, &new_data,
4701f0a9 479 ctx->passphrase_cb,
c3e4c1f3
RL
480 new_data.ctx);
481 if (ok)
482 break;
483 }
484
485 end:
486 BIO_free(new_data.bio);
487 return ok;
488}