2 * Copyright 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/core_names.h>
11 #include <openssl/bio.h>
12 #include <openssl/params.h>
13 #include <openssl/provider.h>
14 #include "serializer_local.h"
17 struct deser_process_data_st {
18 OSSL_DESERIALIZER_CTX *ctx;
23 /* Index of the current deserializer instance to be processed */
24 size_t current_deser_inst_index;
27 static int deser_process(const OSSL_PARAM params[], void *arg);
29 int OSSL_DESERIALIZER_from_bio(OSSL_DESERIALIZER_CTX *ctx, BIO *in)
31 struct deser_process_data_st data;
34 memset(&data, 0, sizeof(data));
38 ok = deser_process(NULL, &data);
40 /* Clear any cached passphrase */
41 OPENSSL_clear_free(ctx->cached_passphrase, ctx->cached_passphrase_len);
42 ctx->cached_passphrase = NULL;
43 ctx->cached_passphrase_len = 0;
47 #ifndef OPENSSL_NO_STDIO
48 static BIO *bio_from_file(FILE *fp)
52 if ((b = BIO_new(BIO_s_file())) == NULL) {
53 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_BIO_LIB);
56 BIO_set_fp(b, fp, BIO_NOCLOSE);
60 int OSSL_DESERIALIZER_from_fp(OSSL_DESERIALIZER_CTX *ctx, FILE *fp)
62 BIO *b = bio_from_file(fp);
66 ret = OSSL_DESERIALIZER_from_bio(ctx, b);
73 int OSSL_DESERIALIZER_CTX_set_input_type(OSSL_DESERIALIZER_CTX *ctx,
74 const char *input_type)
76 if (!ossl_assert(ctx != NULL)) {
77 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
82 * NULL is a valid starting input type, and means that the caller leaves
83 * it to code to discover what the starting input type is.
85 ctx->start_input_type = input_type;
89 int OSSL_DESERIALIZER_CTX_add_deserializer(OSSL_DESERIALIZER_CTX *ctx,
90 OSSL_DESERIALIZER *deser)
92 OSSL_DESERIALIZER_INSTANCE *deser_inst = NULL;
93 const OSSL_PROVIDER *prov = NULL;
97 if (!ossl_assert(ctx != NULL) || !ossl_assert(deser != NULL)) {
98 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
102 if (deser->get_params == NULL) {
103 ERR_raise(ERR_LIB_OSSL_DESERIALIZER,
104 OSSL_DESERIALIZER_R_MISSING_GET_PARAMS);
108 if (ctx->deser_insts == NULL
109 && (ctx->deser_insts =
110 sk_OSSL_DESERIALIZER_INSTANCE_new_null()) == NULL) {
111 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_MALLOC_FAILURE);
114 if ((deser_inst = OPENSSL_zalloc(sizeof(*deser_inst))) == NULL) {
115 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_MALLOC_FAILURE);
118 if (!OSSL_DESERIALIZER_up_ref(deser)) {
119 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_INTERNAL_ERROR);
122 deser_inst->deser = deser;
124 prov = OSSL_DESERIALIZER_provider(deser_inst->deser);
125 provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
127 /* Cache the input type for this serializer */
129 OSSL_PARAM_construct_utf8_ptr(OSSL_DESERIALIZER_PARAM_INPUT_TYPE,
130 (char **)&deser_inst->input_type, 0);
131 params[1] = OSSL_PARAM_construct_end();
133 if (!deser_inst->deser->get_params(params)
134 || !OSSL_PARAM_modified(¶ms[0]))
137 if ((deser_inst->deserctx = deser_inst->deser->newctx(provctx))
141 if (sk_OSSL_DESERIALIZER_INSTANCE_push(ctx->deser_insts, deser_inst) <= 0)
146 if (deser_inst != NULL) {
147 if (deser_inst->deser != NULL)
148 deser_inst->deser->freectx(deser_inst->deserctx);
149 OSSL_DESERIALIZER_free(deser_inst->deser);
150 OPENSSL_free(deser_inst);
155 int OSSL_DESERIALIZER_CTX_add_extra(OSSL_DESERIALIZER_CTX *ctx,
156 OPENSSL_CTX *libctx, const char *propq)
159 * This function goes through existing deserializer methods in
160 * |ctx->deser_insts|, and tries to fetch new deserializers that produce
161 * what the existing ones want as input, and push those newly fetched
162 * deserializers on top of the same stack.
163 * Then it does the same again, but looping over the newly fetched
164 * deserializers, until there are no more serializers to be fetched, or
165 * when we have done this 10 times.
167 * we do this with sliding windows on the stack by keeping track of indexes
171 * | DER to RSA | <--- w_prev_start
177 * | PEM to DER | <--- w_prev_end, w_new_start
181 size_t w_prev_start, w_prev_end; /* "previous" deserializers */
182 size_t w_new_start, w_new_end; /* "new" deserializers */
183 size_t count = 0; /* Calculates how many were added in each iteration */
184 size_t depth = 0; /* Counts the number of iterations */
186 if (!ossl_assert(ctx != NULL)) {
187 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
192 * If there is no stack of OSSL_DESERIALIZER_INSTANCE, we have nothing
193 * more to add. That's fine.
195 if (ctx->deser_insts == NULL)
199 w_prev_end = sk_OSSL_DESERIALIZER_INSTANCE_num(ctx->deser_insts);
203 w_new_start = w_new_end = w_prev_end;
205 for (i = w_prev_start; i < w_prev_end; i++) {
206 OSSL_DESERIALIZER_INSTANCE *deser_inst =
207 sk_OSSL_DESERIALIZER_INSTANCE_value(ctx->deser_insts, i);
208 const char *name = deser_inst->input_type;
209 OSSL_DESERIALIZER *deser = NULL;
212 * If the caller has specified what the initial input should be,
213 * and the deserializer implementation we're looking at has that
214 * input type, there's no point adding on more implementations
215 * on top of this one, so we don't.
217 if (ctx->start_input_type != NULL
218 && strcasecmp(ctx->start_input_type,
219 deser_inst->input_type) != 0)
223 deser = OSSL_DESERIALIZER_fetch(libctx, name, propq);
230 * Check that we don't already have this deserializer in our
231 * stack We only need to check among the newly added ones.
233 for (j = w_new_start; j < w_new_end; j++) {
234 OSSL_DESERIALIZER_INSTANCE *check_inst =
235 sk_OSSL_DESERIALIZER_INSTANCE_value(ctx->deser_insts, j);
237 if (deser == check_inst->deser) {
238 /* We found it, so drop the new fetch */
239 OSSL_DESERIALIZER_free(deser);
250 * Apart from keeping w_new_end up to date, We don't care about
251 * errors here. If it doesn't collect, then it doesn't...
253 if (OSSL_DESERIALIZER_CTX_add_deserializer(ctx, deser)) /* ref++ */
255 OSSL_DESERIALIZER_free(deser); /* ref-- */
257 /* How many were added in this iteration */
258 count = w_new_end - w_new_start;
260 /* Slide the "previous deserializer" windows */
261 w_prev_start = w_new_start;
262 w_prev_end = w_new_end;
265 } while (count != 0 && depth <= 10);
270 int OSSL_DESERIALIZER_CTX_num_deserializers(OSSL_DESERIALIZER_CTX *ctx)
272 if (ctx == NULL || ctx->deser_insts == NULL)
274 return sk_OSSL_DESERIALIZER_INSTANCE_num(ctx->deser_insts);
277 int OSSL_DESERIALIZER_CTX_set_finalizer(OSSL_DESERIALIZER_CTX *ctx,
278 OSSL_DESERIALIZER_FINALIZER *finalizer,
279 OSSL_DESERIALIZER_CLEANER *cleaner,
282 if (!ossl_assert(ctx != NULL)) {
283 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
286 ctx->finalizer = finalizer;
287 ctx->cleaner = cleaner;
288 ctx->finalize_arg = finalize_arg;
292 int OSSL_DESERIALIZER_export(OSSL_DESERIALIZER_INSTANCE *deser_inst,
293 void *reference, size_t reference_sz,
294 OSSL_CALLBACK *export_cb, void *export_cbarg)
296 if (!(ossl_assert(deser_inst != NULL)
297 && ossl_assert(reference != NULL)
298 && ossl_assert(export_cb != NULL)
299 && ossl_assert(export_cbarg != NULL))) {
300 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_PASSED_NULL_PARAMETER);
304 return deser_inst->deser->export_object(deser_inst->deserctx,
305 reference, reference_sz,
306 export_cb, export_cbarg);
309 OSSL_DESERIALIZER *OSSL_DESERIALIZER_INSTANCE_deserializer
310 (OSSL_DESERIALIZER_INSTANCE *deser_inst)
312 if (deser_inst == NULL)
314 return deser_inst->deser;
317 void *OSSL_DESERIALIZER_INSTANCE_deserializer_ctx
318 (OSSL_DESERIALIZER_INSTANCE *deser_inst)
320 if (deser_inst == NULL)
322 return deser_inst->deserctx;
325 static int deser_process(const OSSL_PARAM params[], void *arg)
327 struct deser_process_data_st *data = arg;
328 OSSL_DESERIALIZER_CTX *ctx = data->ctx;
329 OSSL_DESERIALIZER_INSTANCE *deser_inst = NULL;
330 OSSL_DESERIALIZER *deser = NULL;
331 BIO *bio = data->bio;
336 struct deser_process_data_st new_data;
338 memset(&new_data, 0, sizeof(new_data));
339 new_data.ctx = data->ctx;
341 if (params == NULL) {
342 /* First iteration, where we prepare for what is to come */
344 data->current_deser_inst_index =
345 OSSL_DESERIALIZER_CTX_num_deserializers(ctx);
352 sk_OSSL_DESERIALIZER_INSTANCE_value(ctx->deser_insts,
353 data->current_deser_inst_index);
354 deser = OSSL_DESERIALIZER_INSTANCE_deserializer(deser_inst);
356 if (ctx->finalizer(deser_inst, params, ctx->finalize_arg)) {
361 /* The finalizer didn't return success */
364 * so we try to use the object we got and feed it to any next
365 * deserializer that will take it. Object references are not
367 * If this data isn't present, deserialization has failed.
370 p = OSSL_PARAM_locate_const(params, OSSL_DESERIALIZER_PARAM_DATA);
371 if (p == NULL || p->data_type != OSSL_PARAM_OCTET_STRING)
373 new_data.bio = BIO_new_mem_buf(p->data, (int)p->data_size);
374 if (new_data.bio == NULL)
380 * If we have no more deserializers to look through at this point,
383 if (data->current_deser_inst_index == 0)
386 if ((loc = BIO_tell(bio)) < 0) {
387 ERR_raise(ERR_LIB_OSSL_DESERIALIZER, ERR_R_BIO_LIB);
391 for (i = data->current_deser_inst_index; i-- > 0;) {
392 OSSL_DESERIALIZER_INSTANCE *new_deser_inst =
393 sk_OSSL_DESERIALIZER_INSTANCE_value(ctx->deser_insts, i);
394 OSSL_DESERIALIZER *new_deser =
395 OSSL_DESERIALIZER_INSTANCE_deserializer(new_deser_inst);
398 * If |deser| is NULL, it means we've just started, and the caller
399 * may have specified what it expects the initial input to be. If
400 * that's the case, we do this extra check.
402 if (deser == NULL && ctx->start_input_type != NULL
403 && strcasecmp(ctx->start_input_type, deser_inst->input_type) != 0)
407 * If we have a previous deserializer, we check that the input type
408 * of the next to be used matches the type of this previous one.
409 * deser_inst->input_type is a cache of the parameter "input-type"
410 * value for that deserializer.
413 && !OSSL_DESERIALIZER_is_a(deser, new_deser_inst->input_type))
417 if (BIO_reset(bio) <= 0)
420 if (BIO_seek(bio, loc) <= 0)
425 new_data.current_deser_inst_index = i;
426 ok = new_deser->deserialize(new_deser_inst->deserctx,
427 (OSSL_CORE_BIO *)bio,
428 deser_process, &new_data,
429 NULL /* ossl_deserializer_passphrase_in_cb */,
436 BIO_free(new_data.bio);