1 /*
2 * Copyright 1998-2023 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 * Uses brotli compression library from https://github.com/google/brotli
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <openssl/objects.h>
16 #include "internal/comp.h"
17 #include <openssl/err.h>
18 #include "crypto/cryptlib.h"
19 #include "internal/bio.h"
20 #include "internal/thread_once.h"
21 #include "comp_local.h"
22
23 COMP_METHOD *COMP_brotli(void);
24
25 #ifdef OPENSSL_NO_BROTLI
26 # undef BROTLI_SHARED
27 #else
28
29 # include <brotli/decode.h>
30 # include <brotli/encode.h>
31
32 /* memory allocations functions for brotli initialisation */
brotli_alloc(void * opaque,size_t size)33 static void *brotli_alloc(void *opaque, size_t size)
34 {
35 return OPENSSL_zalloc(size);
36 }
37
brotli_free(void * opaque,void * address)38 static void brotli_free(void *opaque, void *address)
39 {
40 OPENSSL_free(address);
41 }
42
43 /*
44 * When OpenSSL is built on Windows, we do not want to require that
45 * the BROTLI.DLL be available in order for the OpenSSL DLLs to
46 * work. Therefore, all BROTLI routines are loaded at run time
47 * and we do not link to a .LIB file when BROTLI_SHARED is set.
48 */
49 # if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
50 # include <windows.h>
51 # endif
52
53 # ifdef BROTLI_SHARED
54 # include "internal/dso.h"
55
56 /* Function pointers */
57 typedef BrotliEncoderState *(*encode_init_ft)(brotli_alloc_func, brotli_free_func, void *);
58 typedef BROTLI_BOOL (*encode_stream_ft)(BrotliEncoderState *, BrotliEncoderOperation, size_t *, const uint8_t **, size_t *, uint8_t **, size_t *);
59 typedef BROTLI_BOOL (*encode_has_more_ft)(BrotliEncoderState *);
60 typedef void (*encode_end_ft)(BrotliEncoderState *);
61 typedef BROTLI_BOOL (*encode_oneshot_ft)(int, int, BrotliEncoderMode, size_t, const uint8_t in[], size_t *, uint8_t out[]);
62
63 typedef BrotliDecoderState *(*decode_init_ft)(brotli_alloc_func, brotli_free_func, void *);
64 typedef BROTLI_BOOL (*decode_stream_ft)(BrotliDecoderState *, size_t *, const uint8_t **, size_t *, uint8_t **, size_t *);
65 typedef BROTLI_BOOL (*decode_has_more_ft)(BrotliDecoderState *);
66 typedef void (*decode_end_ft)(BrotliDecoderState *);
67 typedef BrotliDecoderErrorCode (*decode_error_ft)(BrotliDecoderState *);
68 typedef const char *(*decode_error_string_ft)(BrotliDecoderErrorCode);
69 typedef BROTLI_BOOL (*decode_is_finished_ft)(BrotliDecoderState *);
70 typedef BrotliDecoderResult (*decode_oneshot_ft)(size_t, const uint8_t in[], size_t *, uint8_t out[]);
71
72 static encode_init_ft p_encode_init = NULL;
73 static encode_stream_ft p_encode_stream = NULL;
74 static encode_has_more_ft p_encode_has_more = NULL;
75 static encode_end_ft p_encode_end = NULL;
76 static encode_oneshot_ft p_encode_oneshot = NULL;
77
78 static decode_init_ft p_decode_init = NULL;
79 static decode_stream_ft p_decode_stream = NULL;
80 static decode_has_more_ft p_decode_has_more = NULL;
81 static decode_end_ft p_decode_end = NULL;
82 static decode_error_ft p_decode_error = NULL;
83 static decode_error_string_ft p_decode_error_string = NULL;
84 static decode_is_finished_ft p_decode_is_finished = NULL;
85 static decode_oneshot_ft p_decode_oneshot = NULL;
86
87 static DSO *brotli_encode_dso = NULL;
88 static DSO *brotli_decode_dso = NULL;
89
90 # define BrotliEncoderCreateInstance p_encode_init
91 # define BrotliEncoderCompressStream p_encode_stream
92 # define BrotliEncoderHasMoreOutput p_encode_has_more
93 # define BrotliEncoderDestroyInstance p_encode_end
94 # define BrotliEncoderCompress p_encode_oneshot
95
96 # define BrotliDecoderCreateInstance p_decode_init
97 # define BrotliDecoderDecompressStream p_decode_stream
98 # define BrotliDecoderHasMoreOutput p_decode_has_more
99 # define BrotliDecoderDestroyInstance p_decode_end
100 # define BrotliDecoderGetErrorCode p_decode_error
101 # define BrotliDecoderErrorString p_decode_error_string
102 # define BrotliDecoderIsFinished p_decode_is_finished
103 # define BrotliDecoderDecompress p_decode_oneshot
104
105 # endif /* ifdef BROTLI_SHARED */
106
107
108 struct brotli_state {
109 BrotliEncoderState *encoder;
110 BrotliDecoderState *decoder;
111 };
112
brotli_stateful_init(COMP_CTX * ctx)113 static int brotli_stateful_init(COMP_CTX *ctx)
114 {
115 struct brotli_state *state = OPENSSL_zalloc(sizeof(*state));
116
117 if (state == NULL)
118 return 0;
119
120 state->encoder = BrotliEncoderCreateInstance(brotli_alloc, brotli_free, NULL);
121 if (state->encoder == NULL)
122 goto err;
123
124 state->decoder = BrotliDecoderCreateInstance(brotli_alloc, brotli_free, NULL);
125 if (state->decoder == NULL)
126 goto err;
127
128 ctx->data = state;
129 return 1;
130 err:
131 BrotliDecoderDestroyInstance(state->decoder);
132 BrotliEncoderDestroyInstance(state->encoder);
133 OPENSSL_free(state);
134 return 0;
135 }
136
brotli_stateful_finish(COMP_CTX * ctx)137 static void brotli_stateful_finish(COMP_CTX *ctx)
138 {
139 struct brotli_state *state = ctx->data;
140
141 if (state != NULL) {
142 BrotliDecoderDestroyInstance(state->decoder);
143 BrotliEncoderDestroyInstance(state->encoder);
144 OPENSSL_free(state);
145 ctx->data = NULL;
146 }
147 }
148
brotli_stateful_compress_block(COMP_CTX * ctx,unsigned char * out,size_t olen,unsigned char * in,size_t ilen)149 static ossl_ssize_t brotli_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
150 size_t olen, unsigned char *in,
151 size_t ilen)
152 {
153 BROTLI_BOOL done;
154 struct brotli_state *state = ctx->data;
155 size_t in_avail = ilen;
156 size_t out_avail = olen;
157
158 if (state == NULL || olen > OSSL_SSIZE_MAX)
159 return -1;
160
161 if (ilen == 0)
162 return 0;
163
164 /*
165 * The finish API does not provide a final output buffer,
166 * so each compress operation has to be flushed, if all
167 * the input data can't be accepted, or there is more output,
168 * this has to be considered an error, since there is no more
169 * output buffer space
170 */
171 done = BrotliEncoderCompressStream(state->encoder, BROTLI_OPERATION_FLUSH,
172 &in_avail, (const uint8_t**)&in,
173 &out_avail, &out, NULL);
174 if (done == BROTLI_FALSE
175 || in_avail != 0
176 || BrotliEncoderHasMoreOutput(state->encoder))
177 return -1;
178
179 if (out_avail > olen)
180 return -1;
181 return (ossl_ssize_t)(olen - out_avail);
182 }
183
brotli_stateful_expand_block(COMP_CTX * ctx,unsigned char * out,size_t olen,unsigned char * in,size_t ilen)184 static ossl_ssize_t brotli_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
185 size_t olen, unsigned char *in,
186 size_t ilen)
187 {
188 BrotliDecoderResult result;
189 struct brotli_state *state = ctx->data;
190 size_t in_avail = ilen;
191 size_t out_avail = olen;
192
193 if (state == NULL || olen > OSSL_SSIZE_MAX)
194 return -1;
195
196 if (ilen == 0)
197 return 0;
198
199 result = BrotliDecoderDecompressStream(state->decoder, &in_avail,
200 (const uint8_t**)&in, &out_avail,
201 &out, NULL);
202 if (result == BROTLI_DECODER_RESULT_ERROR
203 || in_avail != 0
204 || BrotliDecoderHasMoreOutput(state->decoder))
205 return -1;
206
207 if (out_avail > olen)
208 return -1;
209 return (ossl_ssize_t)(olen - out_avail);
210 }
211
212 static COMP_METHOD brotli_stateful_method = {
213 NID_brotli,
214 LN_brotli,
215 brotli_stateful_init,
216 brotli_stateful_finish,
217 brotli_stateful_compress_block,
218 brotli_stateful_expand_block
219 };
220
brotli_oneshot_init(COMP_CTX * ctx)221 static int brotli_oneshot_init(COMP_CTX *ctx)
222 {
223 return 1;
224 }
225
brotli_oneshot_finish(COMP_CTX * ctx)226 static void brotli_oneshot_finish(COMP_CTX *ctx)
227 {
228 }
229
brotli_oneshot_compress_block(COMP_CTX * ctx,unsigned char * out,size_t olen,unsigned char * in,size_t ilen)230 static ossl_ssize_t brotli_oneshot_compress_block(COMP_CTX *ctx, unsigned char *out,
231 size_t olen, unsigned char *in,
232 size_t ilen)
233 {
234 size_t out_size = olen;
235 ossl_ssize_t ret;
236
237 if (ilen == 0)
238 return 0;
239
240 if (BrotliEncoderCompress(BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW,
241 BROTLI_DEFAULT_MODE, ilen, in,
242 &out_size, out) == BROTLI_FALSE)
243 return -1;
244
245 if (out_size > OSSL_SSIZE_MAX)
246 return -1;
247 ret = (ossl_ssize_t)out_size;
248 if (ret < 0)
249 return -1;
250 return ret;
251 }
252
brotli_oneshot_expand_block(COMP_CTX * ctx,unsigned char * out,size_t olen,unsigned char * in,size_t ilen)253 static ossl_ssize_t brotli_oneshot_expand_block(COMP_CTX *ctx, unsigned char *out,
254 size_t olen, unsigned char *in,
255 size_t ilen)
256 {
257 size_t out_size = olen;
258 ossl_ssize_t ret;
259
260 if (ilen == 0)
261 return 0;
262
263 if (BrotliDecoderDecompress(ilen, in, &out_size, out) != BROTLI_DECODER_RESULT_SUCCESS)
264 return -1;
265
266 if (out_size > OSSL_SSIZE_MAX)
267 return -1;
268 ret = (ossl_ssize_t)out_size;
269 if (ret < 0)
270 return -1;
271 return ret;
272 }
273
274 static COMP_METHOD brotli_oneshot_method = {
275 NID_brotli,
276 LN_brotli,
277 brotli_oneshot_init,
278 brotli_oneshot_finish,
279 brotli_oneshot_compress_block,
280 brotli_oneshot_expand_block
281 };
282
283 static CRYPTO_ONCE brotli_once = CRYPTO_ONCE_STATIC_INIT;
DEFINE_RUN_ONCE_STATIC(ossl_comp_brotli_init)284 DEFINE_RUN_ONCE_STATIC(ossl_comp_brotli_init)
285 {
286 # ifdef BROTLI_SHARED
287 # if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
288 # define LIBBROTLIENC "BROTLIENC"
289 # define LIBBROTLIDEC "BROTLIDEC"
290 # else
291 # define LIBBROTLIENC "brotlienc"
292 # define LIBBROTLIDEC "brotlidec"
293 # endif
294
295 brotli_encode_dso = DSO_load(NULL, LIBBROTLIENC, NULL, 0);
296 if (brotli_encode_dso != NULL) {
297 p_encode_init = (encode_init_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderCreateInstance");
298 p_encode_stream = (encode_stream_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderCompressStream");
299 p_encode_has_more = (encode_has_more_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderHasMoreOutput");
300 p_encode_end = (encode_end_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderDestroyInstance");
301 p_encode_oneshot = (encode_oneshot_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderCompress");
302 }
303
304 brotli_decode_dso = DSO_load(NULL, LIBBROTLIDEC, NULL, 0);
305 if (brotli_decode_dso != NULL) {
306 p_decode_init = (decode_init_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderCreateInstance");
307 p_decode_stream = (decode_stream_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderDecompressStream");
308 p_decode_has_more = (decode_has_more_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderHasMoreOutput");
309 p_decode_end = (decode_end_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderDestroyInstance");
310 p_decode_error = (decode_error_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderGetErrorCode");
311 p_decode_error_string = (decode_error_string_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderErrorString");
312 p_decode_is_finished = (decode_is_finished_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderIsFinished");
313 p_decode_oneshot = (decode_oneshot_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderDecompress");
314 }
315
316 if (p_encode_init == NULL || p_encode_stream == NULL || p_encode_has_more == NULL
317 || p_encode_end == NULL || p_encode_oneshot == NULL || p_decode_init == NULL
318 || p_decode_stream == NULL || p_decode_has_more == NULL || p_decode_end == NULL
319 || p_decode_error == NULL || p_decode_error_string == NULL || p_decode_is_finished == NULL
320 || p_decode_oneshot == NULL) {
321 ossl_comp_brotli_cleanup();
322 return 0;
323 }
324 # endif
325 return 1;
326 }
327 #endif /* ifndef BROTLI / else */
328
COMP_brotli(void)329 COMP_METHOD *COMP_brotli(void)
330 {
331 COMP_METHOD *meth = NULL;
332
333 #ifndef OPENSSL_NO_BROTLI
334 if (RUN_ONCE(&brotli_once, ossl_comp_brotli_init))
335 meth = &brotli_stateful_method;
336 #endif
337 return meth;
338 }
339
COMP_brotli_oneshot(void)340 COMP_METHOD *COMP_brotli_oneshot(void)
341 {
342 COMP_METHOD *meth = NULL;
343
344 #ifndef OPENSSL_NO_BROTLI
345 if (RUN_ONCE(&brotli_once, ossl_comp_brotli_init))
346 meth = &brotli_oneshot_method;
347 #endif
348 return meth;
349 }
350
351 /* Also called from OPENSSL_cleanup() */
ossl_comp_brotli_cleanup(void)352 void ossl_comp_brotli_cleanup(void)
353 {
354 #ifdef BROTLI_SHARED
355 DSO_free(brotli_encode_dso);
356 brotli_encode_dso = NULL;
357 DSO_free(brotli_decode_dso);
358 brotli_decode_dso = NULL;
359 p_encode_init = NULL;
360 p_encode_stream = NULL;
361 p_encode_has_more = NULL;
362 p_encode_end = NULL;
363 p_encode_oneshot = NULL;
364 p_decode_init = NULL;
365 p_decode_stream = NULL;
366 p_decode_has_more = NULL;
367 p_decode_end = NULL;
368 p_decode_error = NULL;
369 p_decode_error_string = NULL;
370 p_decode_is_finished = NULL;
371 p_decode_oneshot = NULL;
372 #endif
373 }
374
375 #ifndef OPENSSL_NO_BROTLI
376
377 /* Brotli-based compression/decompression filter BIO */
378
379 typedef struct {
380 struct { /* input structure */
381 size_t avail_in;
382 unsigned char *next_in;
383 size_t avail_out;
384 unsigned char *next_out;
385 unsigned char *buf;
386 size_t bufsize;
387 BrotliDecoderState *state;
388 } decode;
389 struct { /* output structure */
390 size_t avail_in;
391 unsigned char *next_in;
392 size_t avail_out;
393 unsigned char *next_out;
394 unsigned char *buf;
395 size_t bufsize;
396 BrotliEncoderState *state;
397 int mode; /* Encoder mode to use */
398 int done;
399 unsigned char *ptr;
400 size_t count;
401 } encode;
402 } BIO_BROTLI_CTX;
403
404 # define BROTLI_DEFAULT_BUFSIZE 1024
405
406 static int bio_brotli_new(BIO *bi);
407 static int bio_brotli_free(BIO *bi);
408 static int bio_brotli_read(BIO *b, char *out, int outl);
409 static int bio_brotli_write(BIO *b, const char *in, int inl);
410 static long bio_brotli_ctrl(BIO *b, int cmd, long num, void *ptr);
411 static long bio_brotli_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp);
412
413 static const BIO_METHOD bio_meth_brotli = {
414 BIO_TYPE_COMP,
415 "brotli",
416 /* TODO: Convert to new style write function */
417 bwrite_conv,
418 bio_brotli_write,
419 /* TODO: Convert to new style read function */
420 bread_conv,
421 bio_brotli_read,
422 NULL, /* bio_brotli_puts, */
423 NULL, /* bio_brotli_gets, */
424 bio_brotli_ctrl,
425 bio_brotli_new,
426 bio_brotli_free,
427 bio_brotli_callback_ctrl
428 };
429 #endif
430
BIO_f_brotli(void)431 const BIO_METHOD *BIO_f_brotli(void)
432 {
433 #ifndef OPENSSL_NO_BROTLI
434 if (RUN_ONCE(&brotli_once, ossl_comp_brotli_init))
435 return &bio_meth_brotli;
436 #endif
437 return NULL;
438 }
439
440 #ifndef OPENSSL_NO_BROTLI
441
bio_brotli_new(BIO * bi)442 static int bio_brotli_new(BIO *bi)
443 {
444 BIO_BROTLI_CTX *ctx;
445
446 # ifdef BROTLI_SHARED
447 if (!RUN_ONCE(&brotli_once, ossl_comp_brotli_init)) {
448 ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_NOT_SUPPORTED);
449 return 0;
450 }
451 # endif
452 ctx = OPENSSL_zalloc(sizeof(*ctx));
453 if (ctx == NULL) {
454 ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
455 return 0;
456 }
457 ctx->decode.bufsize = BROTLI_DEFAULT_BUFSIZE;
458 ctx->decode.state = BrotliDecoderCreateInstance(brotli_alloc, brotli_free, NULL);
459 if (ctx->decode.state == NULL)
460 goto err;
461 ctx->encode.bufsize = BROTLI_DEFAULT_BUFSIZE;
462 ctx->encode.state = BrotliEncoderCreateInstance(brotli_alloc, brotli_free, NULL);
463 if (ctx->encode.state == NULL)
464 goto err;
465 ctx->encode.mode = BROTLI_DEFAULT_MODE;
466 BIO_set_init(bi, 1);
467 BIO_set_data(bi, ctx);
468
469 return 1;
470
471 err:
472 ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
473 BrotliDecoderDestroyInstance(ctx->decode.state);
474 BrotliEncoderDestroyInstance(ctx->encode.state);
475 OPENSSL_free(ctx);
476 return 0;
477 }
478
bio_brotli_free(BIO * bi)479 static int bio_brotli_free(BIO *bi)
480 {
481 BIO_BROTLI_CTX *ctx;
482
483 if (bi == NULL)
484 return 0;
485
486 ctx = BIO_get_data(bi);
487 if (ctx != NULL) {
488 BrotliDecoderDestroyInstance(ctx->decode.state);
489 OPENSSL_free(ctx->decode.buf);
490 BrotliEncoderDestroyInstance(ctx->encode.state);
491 OPENSSL_free(ctx->encode.buf);
492 OPENSSL_free(ctx);
493 }
494 BIO_set_data(bi, NULL);
495 BIO_set_init(bi, 0);
496
497 return 1;
498 }
499
bio_brotli_read(BIO * b,char * out,int outl)500 static int bio_brotli_read(BIO *b, char *out, int outl)
501 {
502 BIO_BROTLI_CTX *ctx;
503 BrotliDecoderResult bret;
504 int ret;
505 BIO *next = BIO_next(b);
506
507 if (out == NULL || outl <= 0) {
508 ERR_raise(ERR_LIB_COMP, ERR_R_PASSED_INVALID_ARGUMENT);
509 return 0;
510 }
511 #if INT_MAX > SIZE_MAX
512 if ((unsigned int)outl > SIZE_MAX) {
513 ERR_raise(ERR_LIB_COMP, ERR_R_PASSED_INVALID_ARGUMENT);
514 return 0;
515 }
516 #endif
517
518 ctx = BIO_get_data(b);
519 BIO_clear_retry_flags(b);
520 if (ctx->decode.buf == NULL) {
521 ctx->decode.buf = OPENSSL_malloc(ctx->decode.bufsize);
522 if (ctx->decode.buf == NULL) {
523 ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
524 return 0;
525 }
526 ctx->decode.next_in = ctx->decode.buf;
527 ctx->decode.avail_in = 0;
528 }
529
530 /* Copy output data directly to supplied buffer */
531 ctx->decode.next_out = (unsigned char *)out;
532 ctx->decode.avail_out = (size_t)outl;
533 for (;;) {
534 /* Decompress while data available */
535 while (ctx->decode.avail_in > 0 || BrotliDecoderHasMoreOutput(ctx->decode.state)) {
536 bret = BrotliDecoderDecompressStream(ctx->decode.state, &ctx->decode.avail_in, (const uint8_t**)&ctx->decode.next_in,
537 &ctx->decode.avail_out, &ctx->decode.next_out, NULL);
538 if (bret == BROTLI_DECODER_RESULT_ERROR) {
539 ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_DECODE_ERROR);
540 ERR_add_error_data(1, BrotliDecoderErrorString(BrotliDecoderGetErrorCode(ctx->decode.state)));
541 return 0;
542 }
543 /* If EOF or we've read everything then return */
544 if (BrotliDecoderIsFinished(ctx->decode.state) || ctx->decode.avail_out == 0)
545 return (int)(outl - ctx->decode.avail_out);
546 }
547
548 /* If EOF */
549 if (BrotliDecoderIsFinished(ctx->decode.state))
550 return 0;
551
552 /*
553 * No data in input buffer try to read some in, if an error then
554 * return the total data read.
555 */
556 ret = BIO_read(next, ctx->decode.buf, ctx->decode.bufsize);
557 if (ret <= 0) {
558 /* Total data read */
559 int tot = outl - ctx->decode.avail_out;
560
561 BIO_copy_next_retry(b);
562 if (ret < 0)
563 return (tot > 0) ? tot : ret;
564 return tot;
565 }
566 ctx->decode.avail_in = ret;
567 ctx->decode.next_in = ctx->decode.buf;
568 }
569 }
570
bio_brotli_write(BIO * b,const char * in,int inl)571 static int bio_brotli_write(BIO *b, const char *in, int inl)
572 {
573 BIO_BROTLI_CTX *ctx;
574 BROTLI_BOOL brret;
575 int ret;
576 BIO *next = BIO_next(b);
577
578 if (in == NULL || inl <= 0) {
579 ERR_raise(ERR_LIB_COMP, ERR_R_PASSED_INVALID_ARGUMENT);
580 return 0;
581 }
582 #if INT_MAX > SIZE_MAX
583 if ((unsigned int)inl > SIZE_MAX) {
584 ERR_raise(ERR_LIB_COMP, ERR_R_PASSED_INVALID_ARGUMENT);
585 return 0;
586 }
587 #endif
588
589 ctx = BIO_get_data(b);
590 if (ctx->encode.done)
591 return 0;
592
593 BIO_clear_retry_flags(b);
594 if (ctx->encode.buf == NULL) {
595 ctx->encode.buf = OPENSSL_malloc(ctx->encode.bufsize);
596 if (ctx->encode.buf == NULL) {
597 ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
598 return 0;
599 }
600 ctx->encode.ptr = ctx->encode.buf;
601 ctx->encode.count = 0;
602 ctx->encode.next_out = ctx->encode.buf;
603 ctx->encode.avail_out = ctx->encode.bufsize;
604 }
605 /* Obtain input data directly from supplied buffer */
606 ctx->encode.next_in = (unsigned char *)in;
607 ctx->encode.avail_in = (size_t)inl;
608 for (;;) {
609 /* If data in output buffer write it first */
610 while (ctx->encode.count > 0) {
611 ret = BIO_write(next, ctx->encode.ptr, ctx->encode.count);
612 if (ret <= 0) {
613 /* Total data written */
614 int tot = inl - ctx->encode.avail_in;
615
616 BIO_copy_next_retry(b);
617 if (ret < 0)
618 return (tot > 0) ? tot : ret;
619 return tot;
620 }
621 ctx->encode.ptr += ret;
622 ctx->encode.count -= ret;
623 }
624
625 /* Have we consumed all supplied data? */
626 if (ctx->encode.avail_in == 0 && !BrotliEncoderHasMoreOutput(ctx->encode.state))
627 return inl;
628
629 /* Compress some more */
630
631 /* Reset buffer */
632 ctx->encode.ptr = ctx->encode.buf;
633 ctx->encode.next_out = ctx->encode.buf;
634 ctx->encode.avail_out = ctx->encode.bufsize;
635 /* Compress some more */
636 brret = BrotliEncoderCompressStream(ctx->encode.state, BROTLI_OPERATION_FLUSH, &ctx->encode.avail_in, (const uint8_t**)&ctx->encode.next_in,
637 &ctx->encode.avail_out, &ctx->encode.next_out, NULL);
638 if (brret != BROTLI_TRUE) {
639 ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_ENCODE_ERROR);
640 ERR_add_error_data(1, "brotli encoder error");
641 return 0;
642 }
643 ctx->encode.count = ctx->encode.bufsize - ctx->encode.avail_out;
644 }
645 }
646
bio_brotli_flush(BIO * b)647 static int bio_brotli_flush(BIO *b)
648 {
649 BIO_BROTLI_CTX *ctx;
650 BROTLI_BOOL brret;
651 int ret;
652 BIO *next = BIO_next(b);
653
654 ctx = BIO_get_data(b);
655
656 /* If no data written or already flush show success */
657 if (ctx->encode.buf == NULL || (ctx->encode.done && ctx->encode.count == 0))
658 return 1;
659
660 BIO_clear_retry_flags(b);
661 /* No more input data */
662 ctx->encode.next_in = NULL;
663 ctx->encode.avail_in = 0;
664 for (;;) {
665 /* If data in output buffer write it first */
666 while (ctx->encode.count > 0) {
667 ret = BIO_write(next, ctx->encode.ptr, ctx->encode.count);
668 if (ret <= 0) {
669 BIO_copy_next_retry(b);
670 return ret;
671 }
672 ctx->encode.ptr += ret;
673 ctx->encode.count -= ret;
674 }
675 if (ctx->encode.done)
676 return 1;
677
678 /* Compress some more */
679
680 /* Reset buffer */
681 ctx->encode.ptr = ctx->encode.buf;
682 ctx->encode.next_out = ctx->encode.buf;
683 ctx->encode.avail_out = ctx->encode.bufsize;
684 /* Compress some more */
685 brret = BrotliEncoderCompressStream(ctx->encode.state, BROTLI_OPERATION_FINISH, &ctx->encode.avail_in,
686 (const uint8_t**)&ctx->encode.next_in, &ctx->encode.avail_out, &ctx->encode.next_out, NULL);
687 if (brret != BROTLI_TRUE) {
688 ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_DECODE_ERROR);
689 ERR_add_error_data(1, "brotli encoder error");
690 return 0;
691 }
692 if (!BrotliEncoderHasMoreOutput(ctx->encode.state) && ctx->encode.avail_in == 0)
693 ctx->encode.done = 1;
694 ctx->encode.count = ctx->encode.bufsize - ctx->encode.avail_out;
695 }
696 }
697
bio_brotli_ctrl(BIO * b,int cmd,long num,void * ptr)698 static long bio_brotli_ctrl(BIO *b, int cmd, long num, void *ptr)
699 {
700 BIO_BROTLI_CTX *ctx;
701 unsigned char *tmp;
702 int ret = 0, *ip;
703 size_t ibs, obs;
704 BIO *next = BIO_next(b);
705
706 if (next == NULL)
707 return 0;
708 ctx = BIO_get_data(b);
709 switch (cmd) {
710
711 case BIO_CTRL_RESET:
712 ctx->encode.count = 0;
713 ctx->encode.done = 0;
714 ret = 1;
715 break;
716
717 case BIO_CTRL_FLUSH:
718 ret = bio_brotli_flush(b);
719 if (ret > 0) {
720 ret = BIO_flush(next);
721 BIO_copy_next_retry(b);
722 }
723 break;
724
725 case BIO_C_SET_BUFF_SIZE:
726 ibs = ctx->decode.bufsize;
727 obs = ctx->encode.bufsize;
728 if (ptr != NULL) {
729 ip = ptr;
730 if (*ip == 0)
731 ibs = (size_t)num;
732 else
733 obs = (size_t)num;
734 } else {
735 ibs = (size_t)num;
736 obs = ibs;
737 }
738
739 if (ibs > 0 && ibs != ctx->decode.bufsize) {
740 /* Do not free/alloc, only reallocate */
741 if (ctx->decode.buf != NULL) {
742 tmp = OPENSSL_realloc(ctx->decode.buf, ibs);
743 if (tmp == NULL)
744 return 0;
745 ctx->decode.buf = tmp;
746 }
747 ctx->decode.bufsize = ibs;
748 }
749
750 if (obs > 0 && obs != ctx->encode.bufsize) {
751 /* Do not free/alloc, only reallocate */
752 if (ctx->encode.buf != NULL) {
753 tmp = OPENSSL_realloc(ctx->encode.buf, obs);
754 if (tmp == NULL)
755 return 0;
756 ctx->encode.buf = tmp;
757 }
758 ctx->encode.bufsize = obs;
759 }
760 ret = 1;
761 break;
762
763 case BIO_C_DO_STATE_MACHINE:
764 BIO_clear_retry_flags(b);
765 ret = BIO_ctrl(next, cmd, num, ptr);
766 BIO_copy_next_retry(b);
767 break;
768
769 case BIO_CTRL_WPENDING:
770 if (BrotliEncoderHasMoreOutput(ctx->encode.state))
771 ret = 1;
772 else
773 ret = BIO_ctrl(next, cmd, num, ptr);
774 break;
775
776 case BIO_CTRL_PENDING:
777 if (!BrotliDecoderIsFinished(ctx->decode.state))
778 ret = 1;
779 else
780 ret = BIO_ctrl(next, cmd, num, ptr);
781 break;
782
783 default:
784 ret = BIO_ctrl(next, cmd, num, ptr);
785 break;
786
787 }
788
789 return ret;
790 }
791
bio_brotli_callback_ctrl(BIO * b,int cmd,BIO_info_cb * fp)792 static long bio_brotli_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
793 {
794 BIO *next = BIO_next(b);
795 if (next == NULL)
796 return 0;
797 return BIO_callback_ctrl(next, cmd, fp);
798 }
799
800 #endif
801