Update copyright year
[openssl.git] / crypto / encode_decode / encoder_lib.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 "e_os.h"                /* strcasecmp on Windows */
11 #include <openssl/core_names.h>
12 #include <openssl/bio.h>
13 #include <openssl/encoder.h>
14 #include <openssl/buffer.h>
15 #include <openssl/params.h>
16 #include <openssl/provider.h>
17 #include "encoder_local.h"
18
19 static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out);
20
21 int OSSL_ENCODER_to_bio(OSSL_ENCODER_CTX *ctx, BIO *out)
22 {
23     return encoder_process(ctx, out);
24 }
25
26 #ifndef OPENSSL_NO_STDIO
27 static BIO *bio_from_file(FILE *fp)
28 {
29     BIO *b;
30
31     if ((b = BIO_new(BIO_s_file())) == NULL) {
32         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_BUF_LIB);
33         return NULL;
34     }
35     BIO_set_fp(b, fp, BIO_NOCLOSE);
36     return b;
37 }
38
39 int OSSL_ENCODER_to_fp(OSSL_ENCODER_CTX *ctx, FILE *fp)
40 {
41     BIO *b = bio_from_file(fp);
42     int ret = 0;
43
44     if (b != NULL)
45         ret = OSSL_ENCODER_to_bio(ctx, b);
46
47     BIO_free(b);
48     return ret;
49 }
50 #endif
51
52 int OSSL_ENCODER_to_data(OSSL_ENCODER_CTX *ctx, unsigned char **pdata,
53                          size_t *pdata_len)
54 {
55     BIO *out = BIO_new(BIO_s_mem());
56     BUF_MEM *buf = NULL;
57     int ret = 0;
58
59     if (pdata_len == NULL) {
60         ERR_raise(ERR_LIB_OSSL_DECODER, ERR_R_PASSED_NULL_PARAMETER);
61         return 0;
62     }
63
64     if (OSSL_ENCODER_to_bio(ctx, out)
65         && BIO_get_mem_ptr(out, &buf) > 0) {
66         ret = 1; /* Hope for the best. A too small buffer will clear this */
67
68         if (pdata != NULL && *pdata != NULL) {
69             if (*pdata_len < buf->length)
70                 /*
71                  * It's tempting to do |*pdata_len = (size_t)buf->length|
72                  * However, it's believed to be confusing more than helpful,
73                  * so we don't.
74                  */
75                 ret = 0;
76             else
77                 *pdata_len -= buf->length;
78         } else {
79             /* The buffer with the right size is already allocated for us */
80             *pdata_len = (size_t)buf->length;
81         }
82
83         if (ret) {
84             if (pdata != NULL) {
85                 if (*pdata != NULL) {
86                     memcpy(*pdata, buf->data, buf->length);
87                     *pdata += buf->length;
88                 } else {
89                     /* In this case, we steal the data from BIO_s_mem() */
90                     *pdata = (unsigned char *)buf->data;
91                     buf->data = NULL;
92                 }
93             }
94         }
95     }
96     BIO_free(out);
97     return ret;
98 }
99
100 int OSSL_ENCODER_CTX_set_output_type(OSSL_ENCODER_CTX *ctx,
101                                      const char *output_type)
102 {
103     if (!ossl_assert(ctx != NULL) || !ossl_assert(output_type != NULL)) {
104         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
105         return 0;
106     }
107
108     ctx->output_type = output_type;
109     return 1;
110 }
111
112 int OSSL_ENCODER_CTX_set_selection(OSSL_ENCODER_CTX *ctx, int selection)
113 {
114     if (!ossl_assert(ctx != NULL)) {
115         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
116         return 0;
117     }
118
119     if (!ossl_assert(selection != 0)) {
120         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_INVALID_ARGUMENT);
121         return 0;
122     }
123
124     ctx->selection = selection;
125     return 1;
126 }
127
128 static OSSL_ENCODER_INSTANCE *ossl_encoder_instance_new(OSSL_ENCODER *encoder,
129                                                         void *encoderctx)
130 {
131     OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
132     OSSL_PARAM params[3];
133
134     if (!ossl_assert(encoder != NULL)) {
135         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
136         return 0;
137     }
138
139     if (encoder->get_params == NULL) {
140         ERR_raise(ERR_LIB_OSSL_ENCODER,
141                   OSSL_ENCODER_R_MISSING_GET_PARAMS);
142         return 0;
143     }
144
145     if ((encoder_inst = OPENSSL_zalloc(sizeof(*encoder_inst))) == NULL) {
146         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
147         return 0;
148     }
149
150     /*
151      * Cache the input and output types for this encoder.  The output type
152      * is mandatory.
153      */
154     params[0] =
155         OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_OUTPUT_TYPE,
156                                       (char **)&encoder_inst->output_type, 0);
157     params[1] =
158         OSSL_PARAM_construct_utf8_ptr(OSSL_ENCODER_PARAM_INPUT_TYPE,
159                                       (char **)&encoder_inst->input_type, 0);
160     params[2] = OSSL_PARAM_construct_end();
161
162     if (!encoder->get_params(params)
163         || !OSSL_PARAM_modified(&params[1]))
164         goto err;
165
166     if (!OSSL_ENCODER_up_ref(encoder)) {
167         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
168         goto err;
169     }
170
171     encoder_inst->encoder = encoder;
172     encoder_inst->encoderctx = encoderctx;
173     return encoder_inst;
174  err:
175     ossl_encoder_instance_free(encoder_inst);
176     return NULL;
177 }
178
179 void ossl_encoder_instance_free(OSSL_ENCODER_INSTANCE *encoder_inst)
180 {
181     if (encoder_inst != NULL) {
182         if (encoder_inst->encoder != NULL)
183             encoder_inst->encoder->freectx(encoder_inst->encoderctx);
184         encoder_inst->encoderctx = NULL;
185         OSSL_ENCODER_free(encoder_inst->encoder);
186         encoder_inst->encoder = NULL;
187         OPENSSL_free(encoder_inst);
188     }
189 }
190
191 static int ossl_encoder_ctx_add_encoder_inst(OSSL_ENCODER_CTX *ctx,
192                                              OSSL_ENCODER_INSTANCE *ei)
193 {
194     if (ctx->encoder_insts == NULL
195         && (ctx->encoder_insts =
196             sk_OSSL_ENCODER_INSTANCE_new_null()) == NULL) {
197         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_MALLOC_FAILURE);
198         return 0;
199     }
200
201     return (sk_OSSL_ENCODER_INSTANCE_push(ctx->encoder_insts, ei) > 0);
202 }
203
204 int OSSL_ENCODER_CTX_add_encoder(OSSL_ENCODER_CTX *ctx, OSSL_ENCODER *encoder)
205 {
206     OSSL_ENCODER_INSTANCE *encoder_inst = NULL;
207     const OSSL_PROVIDER *prov = NULL;
208     void *encoderctx = NULL;
209     void *provctx = NULL;
210
211     if (!ossl_assert(ctx != NULL) || !ossl_assert(encoder != NULL)) {
212         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
213         return 0;
214     }
215
216     prov = OSSL_ENCODER_provider(encoder);
217     provctx = OSSL_PROVIDER_get0_provider_ctx(prov);
218
219     if ((encoderctx = encoder->newctx(provctx)) == NULL
220         || (encoder_inst =
221             ossl_encoder_instance_new(encoder, encoderctx)) == NULL)
222         goto err;
223     /* Avoid double free of encoderctx on further errors */
224     encoderctx = NULL;
225
226     if (!ossl_encoder_ctx_add_encoder_inst(ctx, encoder_inst))
227         goto err;
228
229     return 1;
230  err:
231     ossl_encoder_instance_free(encoder_inst);
232     if (encoderctx != NULL)
233         encoder->freectx(encoderctx);
234     return 0;
235 }
236
237 int OSSL_ENCODER_CTX_add_extra(OSSL_ENCODER_CTX *ctx,
238                                OSSL_LIB_CTX *libctx, const char *propq)
239 {
240     return 1;
241 }
242
243 int OSSL_ENCODER_CTX_get_num_encoders(OSSL_ENCODER_CTX *ctx)
244 {
245     if (ctx == NULL || ctx->encoder_insts == NULL)
246         return 0;
247     return sk_OSSL_ENCODER_INSTANCE_num(ctx->encoder_insts);
248 }
249
250 int OSSL_ENCODER_CTX_set_construct(OSSL_ENCODER_CTX *ctx,
251                                    OSSL_ENCODER_CONSTRUCT *construct)
252 {
253     if (!ossl_assert(ctx != NULL)) {
254         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
255         return 0;
256     }
257     ctx->construct = construct;
258     return 1;
259 }
260
261 int OSSL_ENCODER_CTX_set_construct_data(OSSL_ENCODER_CTX *ctx,
262                                         void *construct_data)
263 {
264     if (!ossl_assert(ctx != NULL)) {
265         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
266         return 0;
267     }
268     ctx->construct_data = construct_data;
269     return 1;
270 }
271
272 int OSSL_ENCODER_CTX_set_cleanup(OSSL_ENCODER_CTX *ctx,
273                                  OSSL_ENCODER_CLEANUP *cleanup)
274 {
275     if (!ossl_assert(ctx != NULL)) {
276         ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_PASSED_NULL_PARAMETER);
277         return 0;
278     }
279     ctx->cleanup = cleanup;
280     return 1;
281 }
282
283 OSSL_ENCODER *
284 OSSL_ENCODER_INSTANCE_get_encoder(OSSL_ENCODER_INSTANCE *encoder_inst)
285 {
286     if (encoder_inst == NULL)
287         return NULL;
288     return encoder_inst->encoder;
289 }
290
291 void *
292 OSSL_ENCODER_INSTANCE_get_encoder_ctx(OSSL_ENCODER_INSTANCE *encoder_inst)
293 {
294     if (encoder_inst == NULL)
295         return NULL;
296     return encoder_inst->encoderctx;
297 }
298
299 const char *
300 OSSL_ENCODER_INSTANCE_get_input_type(OSSL_ENCODER_INSTANCE *encoder_inst)
301 {
302     if (encoder_inst == NULL)
303         return NULL;
304     return encoder_inst->input_type;
305 }
306
307 const char *
308 OSSL_ENCODER_INSTANCE_get_output_type(OSSL_ENCODER_INSTANCE *encoder_inst)
309 {
310     if (encoder_inst == NULL)
311         return NULL;
312     return encoder_inst->output_type;
313 }
314
315 static int encoder_process(OSSL_ENCODER_CTX *ctx, BIO *out)
316 {
317     size_t i, end;
318     void *latest_output = NULL;
319     size_t latest_output_length = 0;
320     const char *latest_output_type = NULL;
321     const char *last_input_type = NULL;
322     int ok = 0;
323
324     end = OSSL_ENCODER_CTX_get_num_encoders(ctx);
325     for (i = 0; i < end; i++) {
326         OSSL_ENCODER_INSTANCE *encoder_inst =
327             sk_OSSL_ENCODER_INSTANCE_value(ctx->encoder_insts, i);
328         OSSL_ENCODER *encoder = OSSL_ENCODER_INSTANCE_get_encoder(encoder_inst);
329         void *encoderctx = OSSL_ENCODER_INSTANCE_get_encoder_ctx(encoder_inst);
330         const char *current_input_type =
331             OSSL_ENCODER_INSTANCE_get_input_type(encoder_inst);
332         const char *current_output_type =
333             OSSL_ENCODER_INSTANCE_get_output_type(encoder_inst);
334         BIO *current_out;
335         BIO *allocated_out = NULL;
336         const void *current_data = NULL;
337         OSSL_PARAM abstract[3];
338         OSSL_PARAM *abstract_p;
339         const OSSL_PARAM *current_abstract = NULL;
340
341         if (latest_output_type == NULL) {
342             /*
343              * This is the first iteration, so we prepare the object to be
344              * encoded
345              */
346
347             current_data = ctx->construct(encoder_inst, ctx->construct_data);
348
349             /* Assume that the constructor recorded an error */
350             if (current_data == NULL)
351                 goto loop_end;
352         } else {
353             /*
354              * Check that the latest output type matches the currently
355              * considered encoder
356              */
357             if (!OSSL_ENCODER_is_a(encoder, latest_output_type))
358                 continue;
359
360             /*
361              * If there is a latest output type, there should be a latest output
362              */
363             if (!ossl_assert(latest_output != NULL)) {
364                 ERR_raise(ERR_LIB_OSSL_ENCODER, ERR_R_INTERNAL_ERROR);
365                 goto loop_end;
366             }
367
368             /*
369              * Create an object abstraction from the latest output, which was
370              * stolen from the previous round.
371              */
372             abstract_p = abstract;
373             if (last_input_type != NULL)
374                 *abstract_p++ =
375                     OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
376                                                      (char *)last_input_type, 0);
377             *abstract_p++ =
378                 OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA,
379                                                   latest_output,
380                                                   latest_output_length);
381             *abstract_p = OSSL_PARAM_construct_end();
382             current_abstract = abstract;
383         }
384
385         /*
386          * If the desired output type matches the output type of the currently
387          * considered encoder, we're setting up final output.  Otherwise, set
388          * up an intermediary memory output.
389          */
390         if (strcasecmp(ctx->output_type, current_output_type) == 0)
391             current_out = out;
392         else if ((current_out = allocated_out = BIO_new(BIO_s_mem())) == NULL)
393             goto loop_end;     /* Assume BIO_new() recorded an error */
394
395         ok = encoder->encode(encoderctx, (OSSL_CORE_BIO *)current_out,
396                              current_data, current_abstract, ctx->selection,
397                              ossl_pw_passphrase_callback_enc, &ctx->pwdata);
398
399         if (current_input_type != NULL)
400             last_input_type = current_input_type;
401
402         if (!ok)
403             goto loop_end;
404
405         OPENSSL_free(latest_output);
406
407         /*
408          * Steal the output from the BIO_s_mem, if we did allocate one.
409          * That'll be the data for an object abstraction in the next round.
410          */
411         if (allocated_out != NULL) {
412             BUF_MEM *buf;
413
414             BIO_get_mem_ptr(allocated_out, &buf);
415             latest_output = buf->data;
416             latest_output_length = buf->length;
417             memset(buf, 0, sizeof(*buf));
418             BIO_free(allocated_out);
419         }
420
421      loop_end:
422         if (current_data != NULL)
423             ctx->cleanup(ctx->construct_data);
424
425         if (ok)
426             break;
427     }
428
429     OPENSSL_free(latest_output);
430     return ok;
431 }