summaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
authorTodd Short <tshort@akamai.com>2021-08-09 16:56:29 -0400
committerTodd Short <todd.short@me.com>2022-10-18 09:30:18 -0400
commit12e96a23604a7aa1cd8f83486b02f1bcab6d468f (patch)
tree0b6be9589eaab31798122128c1237d40bff9bfe2 /crypto
parent846975f367f75f3503b44c12e49d980dca181647 (diff)
downloadopenssl-new-12e96a23604a7aa1cd8f83486b02f1bcab6d468f.tar.gz
Add brotli compression support (RFC7924)
Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Hugo Landau <hlandau@openssl.org> (Merged from https://github.com/openssl/openssl/pull/18186)
Diffstat (limited to 'crypto')
-rw-r--r--crypto/comp/build.info1
-rw-r--r--crypto/comp/c_brotli.c770
-rw-r--r--crypto/comp/comp_err.c10
-rw-r--r--crypto/err/openssl.txt5
-rw-r--r--crypto/init.c2
-rw-r--r--crypto/objects/obj_dat.h9
-rw-r--r--crypto/objects/obj_mac.num1
-rw-r--r--crypto/objects/objects.txt3
8 files changed, 798 insertions, 3 deletions
diff --git a/crypto/comp/build.info b/crypto/comp/build.info
index 65df46a175..014628e45d 100644
--- a/crypto/comp/build.info
+++ b/crypto/comp/build.info
@@ -1,4 +1,5 @@
LIBS=../../libcrypto
SOURCE[../../libcrypto]= \
comp_lib.c comp_err.c \
+ c_brotli.c \
c_zlib.c
diff --git a/crypto/comp/c_brotli.c b/crypto/comp/c_brotli.c
new file mode 100644
index 0000000000..ace6f221b8
--- /dev/null
+++ b/crypto/comp/c_brotli.c
@@ -0,0 +1,770 @@
+/*
+ * Copyright 1998-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ *
+ * Uses brotli compression library from https://github.com/google/brotli
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/objects.h>
+#include "internal/comp.h"
+#include <openssl/err.h>
+#include "crypto/cryptlib.h"
+#include "internal/bio.h"
+#include "internal/thread_once.h"
+#include "comp_local.h"
+
+COMP_METHOD *COMP_brotli(void);
+
+static COMP_METHOD brotli_method_nobrotli = {
+ NID_undef,
+ "(undef)",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+#ifdef OPENSSL_NO_BROTLI
+# undef BROTLI_SHARED
+#else
+
+# include <brotli/decode.h>
+# include <brotli/encode.h>
+
+/* memory allocations functions for brotli initialisation */
+static void *brotli_alloc(void *opaque, size_t size)
+{
+ return OPENSSL_zalloc(size);
+}
+
+static void brotli_free(void *opaque, void *address)
+{
+ OPENSSL_free(address);
+}
+
+/*
+ * When OpenSSL is built on Windows, we do not want to require that
+ * the BROTLI.DLL be available in order for the OpenSSL DLLs to
+ * work. Therefore, all BROTLI routines are loaded at run time
+ * and we do not link to a .LIB file when BROTLI_SHARED is set.
+ */
+# if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
+# include <windows.h>
+# endif
+
+# ifdef BROTLI_SHARED
+# include "internal/dso.h"
+
+/* Function pointers */
+typedef BrotliEncoderState *(*encode_init_ft)(brotli_alloc_func, brotli_free_func, void *);
+typedef BROTLI_BOOL (*encode_stream_ft)(BrotliEncoderState *, BrotliEncoderOperation, size_t *, const uint8_t **, size_t *, uint8_t **, size_t *);
+typedef BROTLI_BOOL (*encode_has_more_ft)(BrotliEncoderState *);
+typedef void (*encode_end_ft)(BrotliEncoderState *);
+typedef BROTLI_BOOL (*encode_oneshot_ft)(int, int, BrotliEncoderMode, size_t, const uint8_t in[], size_t *, uint8_t out[]);
+
+typedef BrotliDecoderState *(*decode_init_ft)(brotli_alloc_func, brotli_free_func, void *);
+typedef BROTLI_BOOL (*decode_stream_ft)(BrotliDecoderState *, size_t *, const uint8_t **, size_t *, uint8_t **, size_t *);
+typedef BROTLI_BOOL (*decode_has_more_ft)(BrotliDecoderState *);
+typedef void (*decode_end_ft)(BrotliDecoderState *);
+typedef BrotliDecoderErrorCode (*decode_error_ft)(BrotliDecoderState *);
+typedef const char *(*decode_error_string_ft)(BrotliDecoderErrorCode);
+typedef BROTLI_BOOL (*decode_is_finished_ft)(BrotliDecoderState *);
+typedef BrotliDecoderResult (*decode_oneshot_ft)(size_t, const uint8_t in[], size_t *, uint8_t out[]);
+
+static encode_init_ft p_encode_init = NULL;
+static encode_stream_ft p_encode_stream = NULL;
+static encode_has_more_ft p_encode_has_more = NULL;
+static encode_end_ft p_encode_end = NULL;
+static encode_oneshot_ft p_encode_oneshot = NULL;
+
+static decode_init_ft p_decode_init = NULL;
+static decode_stream_ft p_decode_stream = NULL;
+static decode_has_more_ft p_decode_has_more = NULL;
+static decode_end_ft p_decode_end = NULL;
+static decode_error_ft p_decode_error = NULL;
+static decode_error_string_ft p_decode_error_string = NULL;
+static decode_is_finished_ft p_decode_is_finished = NULL;
+static decode_oneshot_ft p_decode_oneshot = NULL;
+
+static DSO *brotli_encode_dso = NULL;
+static DSO *brotli_decode_dso = NULL;
+
+# define BrotliEncoderCreateInstance p_encode_init
+# define BrotliEncoderCompressStream p_encode_stream
+# define BrotliEncoderHasMoreOutput p_encode_has_more
+# define BrotliEncoderDestroyInstance p_encode_end
+# define BrotliEncoderCompress p_encode_oneshot
+
+# define BrotliDecoderCreateInstance p_decode_init
+# define BrotliDecoderDecompressStream p_decode_stream
+# define BrotliDecoderHasMoreOutput p_decode_has_more
+# define BrotliDecoderDestroyInstance p_decode_end
+# define BrotliDecoderGetErrorCode p_decode_error
+# define BrotliDecoderErrorString p_decode_error_string
+# define BrotliDecoderIsFinished p_decode_is_finished
+# define BrotliDecoderDecompress p_decode_oneshot
+
+# endif /* ifdef BROTLI_SHARED */
+
+
+struct brotli_state {
+ BrotliEncoderState *encoder;
+ BrotliDecoderState *decoder;
+};
+
+static int brotli_stateful_init(COMP_CTX *ctx)
+{
+ struct brotli_state *state = OPENSSL_zalloc(sizeof(*state));
+
+ if (state == NULL)
+ return 0;
+
+ state->encoder = BrotliEncoderCreateInstance(brotli_alloc, brotli_free, NULL);
+ if (state->encoder == NULL)
+ goto err;
+
+ state->decoder = BrotliDecoderCreateInstance(brotli_alloc, brotli_free, NULL);
+ if (state->decoder == NULL)
+ goto err;
+
+ ctx->data = state;
+ return 1;
+ err:
+ BrotliDecoderDestroyInstance(state->decoder);
+ BrotliEncoderDestroyInstance(state->encoder);
+ OPENSSL_free(state);
+ return 0;
+}
+
+static void brotli_stateful_finish(COMP_CTX *ctx)
+{
+ struct brotli_state *state = ctx->data;
+
+ if (state != NULL) {
+ BrotliDecoderDestroyInstance(state->decoder);
+ BrotliEncoderDestroyInstance(state->encoder);
+ OPENSSL_free(state);
+ ctx->data = NULL;
+ }
+}
+
+static int brotli_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
+ unsigned int olen, unsigned char *in,
+ unsigned int ilen)
+{
+ BROTLI_BOOL done;
+ struct brotli_state *state = ctx->data;
+ size_t in_avail = ilen;
+ size_t out_avail = olen;
+
+ if (state == NULL)
+ return -1;
+
+ if (ilen == 0)
+ return 0;
+
+ /*
+ * The finish API does not provide a final output buffer,
+ * so each compress operation has to be flushed, if all
+ * the input data can't be accepted, or there is more output,
+ * this has to be considered an error, since there is no more
+ * output buffer space
+ */
+ done = BrotliEncoderCompressStream(state->encoder, BROTLI_OPERATION_FLUSH,
+ &in_avail, (const uint8_t**)&in, &out_avail, &out, NULL);
+ if (done == BROTLI_FALSE || in_avail != 0
+ || BrotliEncoderHasMoreOutput(state->encoder))
+ return -1;
+
+ return (int)(olen - out_avail);
+}
+
+static int brotli_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
+ unsigned int olen, unsigned char *in,
+ unsigned int ilen)
+{
+ BrotliDecoderResult result;
+ struct brotli_state *state = ctx->data;
+ size_t in_avail = ilen;
+ size_t out_avail = olen;
+
+ if (state == NULL)
+ return -1;
+
+ if (ilen == 0)
+ return 0;
+
+ result = BrotliDecoderDecompressStream(state->decoder, &in_avail, (const uint8_t**)&in, &out_avail, &out, NULL);
+ if (result == BROTLI_DECODER_RESULT_ERROR || in_avail != 0
+ || BrotliDecoderHasMoreOutput(state->decoder))
+ return -1;
+
+ return (int)(olen - out_avail);
+}
+
+static COMP_METHOD brotli_stateful_method = {
+ NID_brotli,
+ LN_brotli,
+ brotli_stateful_init,
+ brotli_stateful_finish,
+ brotli_stateful_compress_block,
+ brotli_stateful_expand_block
+};
+
+static int brotli_oneshot_init(COMP_CTX *ctx)
+{
+ return 1;
+}
+
+static void brotli_oneshot_finish(COMP_CTX *ctx)
+{
+}
+
+static int brotli_oneshot_compress_block(COMP_CTX *ctx, unsigned char *out,
+ unsigned int olen, unsigned char *in,
+ unsigned int ilen)
+{
+ size_t out_size = olen;
+
+ if (ilen == 0)
+ return 0;
+
+ if (BrotliEncoderCompress(BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW,
+ BROTLI_DEFAULT_MODE, ilen, in,
+ &out_size, out) == BROTLI_FALSE)
+ return -1;
+
+ return (int)out_size;
+}
+
+static int brotli_oneshot_expand_block(COMP_CTX *ctx, unsigned char *out,
+ unsigned int olen, unsigned char *in,
+ unsigned int ilen)
+{
+ size_t out_size = olen;
+
+ if (ilen == 0)
+ return 0;
+
+ if (BrotliDecoderDecompress(ilen, in, &out_size, out) != BROTLI_DECODER_RESULT_SUCCESS)
+ return -1;
+
+ return (int)out_size;
+}
+
+static COMP_METHOD brotli_oneshot_method = {
+ NID_brotli,
+ LN_brotli,
+ brotli_oneshot_init,
+ brotli_oneshot_finish,
+ brotli_oneshot_compress_block,
+ brotli_oneshot_expand_block
+};
+
+static CRYPTO_ONCE brotli_once = CRYPTO_ONCE_STATIC_INIT;
+DEFINE_RUN_ONCE_STATIC(ossl_comp_brotli_init)
+{
+# ifdef BROTLI_SHARED
+# if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
+# define LIBBROTLIENC "BROTLIENC"
+# define LIBBROTLIDEC "BROTLIDEC"
+# else
+# define LIBBROTLIENC "brotlienc"
+# define LIBBROTLIDEC "brotlidec"
+# endif
+
+ brotli_encode_dso = DSO_load(NULL, LIBBROTLIENC, NULL, 0);
+ if (brotli_encode_dso != NULL) {
+ p_encode_init = (encode_init_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderCreateInstance");
+ p_encode_stream = (encode_stream_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderCompressStream");
+ p_encode_has_more = (encode_has_more_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderHasMoreOutput");
+ p_encode_end = (encode_end_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderDestroyInstance");
+ p_encode_oneshot = (encode_oneshot_ft)DSO_bind_func(brotli_encode_dso, "BrotliEncoderCompress");
+ }
+
+ brotli_decode_dso = DSO_load(NULL, LIBBROTLIDEC, NULL, 0);
+ if (brotli_decode_dso != NULL) {
+ p_decode_init = (decode_init_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderCreateInstance");
+ p_decode_stream = (decode_stream_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderDecompressStream");
+ p_decode_has_more = (decode_has_more_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderHasMoreOutput");
+ p_decode_end = (decode_end_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderDestroyInstance");
+ p_decode_error = (decode_error_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderGetErrorCode");
+ p_decode_error_string = (decode_error_string_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderErrorString");
+ p_decode_is_finished = (decode_is_finished_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderIsFinished");
+ p_decode_oneshot = (decode_oneshot_ft)DSO_bind_func(brotli_decode_dso, "BrotliDecoderDecompress");
+ }
+
+ if (p_encode_init == NULL || p_encode_stream == NULL || p_encode_has_more == NULL
+ || p_encode_end == NULL || p_encode_oneshot == NULL || p_decode_init == NULL
+ || p_decode_stream == NULL || p_decode_has_more == NULL || p_decode_end == NULL
+ || p_decode_error == NULL || p_decode_error_string == NULL || p_decode_is_finished == NULL
+ || p_decode_oneshot == NULL) {
+ ossl_comp_brotli_cleanup();
+ return 0;
+ }
+# endif
+ return 1;
+}
+#endif /* ifndef BROTLI / else */
+
+COMP_METHOD *COMP_brotli(void)
+{
+ COMP_METHOD *meth = &brotli_method_nobrotli;
+
+#ifndef OPENSSL_NO_BROTLI
+ if (RUN_ONCE(&brotli_once, ossl_comp_brotli_init))
+ meth = &brotli_stateful_method;
+#endif
+ return meth;
+}
+
+COMP_METHOD *COMP_brotli_oneshot(void)
+{
+ COMP_METHOD *meth = &brotli_method_nobrotli;
+
+#ifndef OPENSSL_NO_BROTLI
+ if (RUN_ONCE(&brotli_once, ossl_comp_brotli_init))
+ meth = &brotli_oneshot_method;
+#endif
+ return meth;
+}
+
+/* Also called from OPENSSL_cleanup() */
+void ossl_comp_brotli_cleanup(void)
+{
+#ifdef BROTLI_SHARED
+ DSO_free(brotli_encode_dso);
+ brotli_encode_dso = NULL;
+ DSO_free(brotli_decode_dso);
+ brotli_decode_dso = NULL;
+ p_encode_init = NULL;
+ p_encode_stream = NULL;
+ p_encode_has_more = NULL;
+ p_encode_end = NULL;
+ p_encode_oneshot = NULL;
+ p_decode_init = NULL;
+ p_decode_stream = NULL;
+ p_decode_has_more = NULL;
+ p_decode_end = NULL;
+ p_decode_error = NULL;
+ p_decode_error_string = NULL;
+ p_decode_is_finished = NULL;
+ p_decode_oneshot = NULL;
+#endif
+}
+
+#ifndef OPENSSL_NO_BROTLI
+
+/* Brotli-based compression/decompression filter BIO */
+
+typedef struct {
+ struct { /* input structure */
+ size_t avail_in;
+ unsigned char *next_in;
+ size_t avail_out;
+ unsigned char *next_out;
+ unsigned char *buf;
+ size_t bufsize;
+ BrotliDecoderState *state;
+ } decode;
+ struct { /* output structure */
+ size_t avail_in;
+ unsigned char *next_in;
+ size_t avail_out;
+ unsigned char *next_out;
+ unsigned char *buf;
+ size_t bufsize;
+ BrotliEncoderState *state;
+ int mode; /* Encoder mode to use */
+ int done;
+ unsigned char *ptr;
+ size_t count;
+ } encode;
+} BIO_BROTLI_CTX;
+
+# define BROTLI_DEFAULT_BUFSIZE 1024
+
+static int bio_brotli_new(BIO *bi);
+static int bio_brotli_free(BIO *bi);
+static int bio_brotli_read(BIO *b, char *out, int outl);
+static int bio_brotli_write(BIO *b, const char *in, int inl);
+static long bio_brotli_ctrl(BIO *b, int cmd, long num, void *ptr);
+static long bio_brotli_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp);
+
+static const BIO_METHOD bio_meth_brotli = {
+ BIO_TYPE_COMP,
+ "brotli",
+ /* TODO: Convert to new style write function */
+ bwrite_conv,
+ bio_brotli_write,
+ /* TODO: Convert to new style read function */
+ bread_conv,
+ bio_brotli_read,
+ NULL, /* bio_brotli_puts, */
+ NULL, /* bio_brotli_gets, */
+ bio_brotli_ctrl,
+ bio_brotli_new,
+ bio_brotli_free,
+ bio_brotli_callback_ctrl
+};
+#endif
+
+const BIO_METHOD *BIO_f_brotli(void)
+{
+#ifndef OPENSSL_NO_BROTLI
+ return &bio_meth_brotli;
+#else
+ return NULL;
+#endif
+}
+
+#ifndef OPENSSL_NO_BROTLI
+
+static int bio_brotli_new(BIO *bi)
+{
+ BIO_BROTLI_CTX *ctx;
+
+# ifdef BROTLI_SHARED
+ if (!RUN_ONCE(&brotli_once, ossl_comp_brotli_init)) {
+ ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_NOT_SUPPORTED);
+ return 0;
+ }
+# endif
+ ctx = OPENSSL_zalloc(sizeof(*ctx));
+ if (ctx == NULL) {
+ ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ ctx->decode.bufsize = BROTLI_DEFAULT_BUFSIZE;
+ ctx->decode.state = BrotliDecoderCreateInstance(brotli_alloc, brotli_free, NULL);
+ if (ctx->decode.state == NULL)
+ goto err;
+ ctx->encode.bufsize = BROTLI_DEFAULT_BUFSIZE;
+ ctx->encode.state = BrotliEncoderCreateInstance(brotli_alloc, brotli_free, NULL);
+ if (ctx->encode.state == NULL)
+ goto err;
+ ctx->encode.mode = BROTLI_DEFAULT_MODE;
+ BIO_set_init(bi, 1);
+ BIO_set_data(bi, ctx);
+
+ return 1;
+
+ err:
+ ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
+ BrotliDecoderDestroyInstance(ctx->decode.state);
+ BrotliEncoderDestroyInstance(ctx->encode.state);
+ OPENSSL_free(ctx);
+ return 0;
+}
+
+static int bio_brotli_free(BIO *bi)
+{
+ BIO_BROTLI_CTX *ctx;
+
+ if (bi == NULL)
+ return 0;
+
+ ctx = BIO_get_data(bi);
+ if (ctx != NULL) {
+ BrotliDecoderDestroyInstance(ctx->decode.state);
+ OPENSSL_free(ctx->decode.buf);
+ BrotliEncoderDestroyInstance(ctx->encode.state);
+ OPENSSL_free(ctx->encode.buf);
+ OPENSSL_free(ctx);
+ }
+ BIO_set_data(bi, NULL);
+ BIO_set_init(bi, 0);
+
+ return 1;
+}
+
+static int bio_brotli_read(BIO *b, char *out, int outl)
+{
+ BIO_BROTLI_CTX *ctx;
+ BrotliDecoderResult bret;
+ int ret;
+ BIO *next = BIO_next(b);
+
+ if (out == NULL || outl <= 0)
+ return 0;
+
+ ctx = BIO_get_data(b);
+ BIO_clear_retry_flags(b);
+ if (ctx->decode.buf == NULL) {
+ ctx->decode.buf = OPENSSL_malloc(ctx->decode.bufsize);
+ if (ctx->decode.buf == NULL) {
+ ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ ctx->decode.next_in = ctx->decode.buf;
+ ctx->decode.avail_in = 0;
+ }
+
+ /* Copy output data directly to supplied buffer */
+ ctx->decode.next_out = (unsigned char *)out;
+ ctx->decode.avail_out = (size_t)outl;
+ for (;;) {
+ /* Decompress while data available */
+ while (ctx->decode.avail_in > 0 || BrotliDecoderHasMoreOutput(ctx->decode.state)) {
+ bret = BrotliDecoderDecompressStream(ctx->decode.state, &ctx->decode.avail_in, (const uint8_t**)&ctx->decode.next_in,
+ &ctx->decode.avail_out, &ctx->decode.next_out, NULL);
+ if (bret == BROTLI_DECODER_RESULT_ERROR) {
+ ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_DECODE_ERROR);
+ ERR_add_error_data(1, BrotliDecoderErrorString(BrotliDecoderGetErrorCode(ctx->decode.state)));
+ return 0;
+ }
+ /* If EOF or we've read everything then return */
+ if (BrotliDecoderIsFinished(ctx->decode.state) || ctx->decode.avail_out == 0)
+ return (int)(outl - ctx->decode.avail_out);
+ }
+
+ /* If EOF */
+ if (BrotliDecoderIsFinished(ctx->decode.state))
+ return 0;
+
+ /*
+ * No data in input buffer try to read some in, if an error then
+ * return the total data read.
+ */
+ ret = BIO_read(next, ctx->decode.buf, ctx->decode.bufsize);
+ if (ret <= 0) {
+ /* Total data read */
+ int tot = outl - ctx->decode.avail_out;
+
+ BIO_copy_next_retry(b);
+ if (ret < 0)
+ return (tot > 0) ? tot : ret;
+ return tot;
+ }
+ ctx->decode.avail_in = ret;
+ ctx->decode.next_in = ctx->decode.buf;
+ }
+}
+
+static int bio_brotli_write(BIO *b, const char *in, int inl)
+{
+ BIO_BROTLI_CTX *ctx;
+ BROTLI_BOOL brret;
+ int ret;
+ BIO *next = BIO_next(b);
+
+ if (in == NULL || inl <= 0)
+ return 0;
+
+ ctx = BIO_get_data(b);
+ if (ctx->encode.done)
+ return 0;
+
+ BIO_clear_retry_flags(b);
+ if (ctx->encode.buf == NULL) {
+ ctx->encode.buf = OPENSSL_malloc(ctx->encode.bufsize);
+ if (ctx->encode.buf == NULL) {
+ ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ ctx->encode.ptr = ctx->encode.buf;
+ ctx->encode.count = 0;
+ ctx->encode.next_out = ctx->encode.buf;
+ ctx->encode.avail_out = ctx->encode.bufsize;
+ }
+ /* Obtain input data directly from supplied buffer */
+ ctx->encode.next_in = (unsigned char *)in;
+ ctx->encode.avail_in = inl;
+ for (;;) {
+ /* If data in output buffer write it first */
+ while (ctx->encode.count > 0) {
+ ret = BIO_write(next, ctx->encode.ptr, ctx->encode.count);
+ if (ret <= 0) {
+ /* Total data written */
+ int tot = inl - ctx->encode.avail_in;
+
+ BIO_copy_next_retry(b);
+ if (ret < 0)
+ return (tot > 0) ? tot : ret;
+ return tot;
+ }
+ ctx->encode.ptr += ret;
+ ctx->encode.count -= ret;
+ }
+
+ /* Have we consumed all supplied data? */
+ if (ctx->encode.avail_in == 0 && !BrotliEncoderHasMoreOutput(ctx->encode.state))
+ return inl;
+
+ /* Compress some more */
+
+ /* Reset buffer */
+ ctx->encode.ptr = ctx->encode.buf;
+ ctx->encode.next_out = ctx->encode.buf;
+ ctx->encode.avail_out = ctx->encode.bufsize;
+ /* Compress some more */
+ brret = BrotliEncoderCompressStream(ctx->encode.state, BROTLI_OPERATION_FLUSH, &ctx->encode.avail_in, (const uint8_t**)&ctx->encode.next_in,
+ &ctx->encode.avail_out, &ctx->encode.next_out, NULL);
+ if (brret != BROTLI_TRUE) {
+ ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_ENCODE_ERROR);
+ ERR_add_error_data(1, "brotli encoder error");
+ return 0;
+ }
+ ctx->encode.count = ctx->encode.bufsize - ctx->encode.avail_out;
+ }
+}
+
+static int bio_brotli_flush(BIO *b)
+{
+ BIO_BROTLI_CTX *ctx;
+ BROTLI_BOOL brret;
+ int ret;
+ BIO *next = BIO_next(b);
+
+ ctx = BIO_get_data(b);
+
+ /* If no data written or already flush show success */
+ if (ctx->encode.buf == NULL || (ctx->encode.done && ctx->encode.count == 0))
+ return 1;
+
+ BIO_clear_retry_flags(b);
+ /* No more input data */
+ ctx->encode.next_in = NULL;
+ ctx->encode.avail_in = 0;
+ for (;;) {
+ /* If data in output buffer write it first */
+ while (ctx->encode.count > 0) {
+ ret = BIO_write(next, ctx->encode.ptr, ctx->encode.count);
+ if (ret <= 0) {
+ BIO_copy_next_retry(b);
+ return ret;
+ }
+ ctx->encode.ptr += ret;
+ ctx->encode.count -= ret;
+ }
+ if (ctx->encode.done)
+ return 1;
+
+ /* Compress some more */
+
+ /* Reset buffer */
+ ctx->encode.ptr = ctx->encode.buf;
+ ctx->encode.next_out = ctx->encode.buf;
+ ctx->encode.avail_out = ctx->encode.bufsize;
+ /* Compress some more */
+ brret = BrotliEncoderCompressStream(ctx->encode.state, BROTLI_OPERATION_FINISH, &ctx->encode.avail_in,
+ (const uint8_t**)&ctx->encode.next_in, &ctx->encode.avail_out, &ctx->encode.next_out, NULL);
+ if (brret != BROTLI_TRUE) {
+ ERR_raise(ERR_LIB_COMP, COMP_R_BROTLI_DECODE_ERROR);
+ ERR_add_error_data(1, "brotli encoder error");
+ return 0;
+ }
+ if (!BrotliEncoderHasMoreOutput(ctx->encode.state) && ctx->encode.avail_in == 0)
+ ctx->encode.done = 1;
+ ctx->encode.count = ctx->encode.bufsize - ctx->encode.avail_out;
+ }
+}
+
+static long bio_brotli_ctrl(BIO *b, int cmd, long num, void *ptr)
+{
+ BIO_BROTLI_CTX *ctx;
+ unsigned char *tmp;
+ int ret = 0, *ip;
+ size_t ibs, obs;
+ BIO *next = BIO_next(b);
+
+ if (next == NULL)
+ return 0;
+ ctx = BIO_get_data(b);
+ switch (cmd) {
+
+ case BIO_CTRL_RESET:
+ ctx->encode.count = 0;
+ ctx->encode.done = 0;
+ ret = 1;
+ break;
+
+ case BIO_CTRL_FLUSH:
+ ret = bio_brotli_flush(b);
+ if (ret > 0)
+ ret = BIO_flush(next);
+ break;
+
+ case BIO_C_SET_BUFF_SIZE:
+ ibs = ctx->decode.bufsize;
+ obs = ctx->encode.bufsize;
+ if (ptr != NULL) {
+ ip = ptr;
+ if (*ip == 0)
+ ibs = (size_t)num;
+ else
+ obs = (size_t)num;
+ } else {
+ ibs = (size_t)num;
+ obs = ibs;
+ }
+
+ if (ibs > 0 && ibs != ctx->decode.bufsize) {
+ /* Do not free/alloc, only reallocate */
+ if (ctx->decode.buf != NULL) {
+ tmp = OPENSSL_realloc(ctx->decode.buf, ibs);
+ if (tmp == NULL)
+ return 0;
+ ctx->decode.buf = tmp;
+ }
+ ctx->decode.bufsize = ibs;
+ }
+
+ if (obs > 0 && obs != ctx->encode.bufsize) {
+ /* Do not free/alloc, only reallocate */
+ if (ctx->encode.buf != NULL) {
+ tmp = OPENSSL_realloc(ctx->encode.buf, obs);
+ if (tmp == NULL)
+ return 0;
+ ctx->encode.buf = tmp;
+ }
+ ctx->encode.bufsize = obs;
+ }
+ ret = 1;
+ break;
+
+ case BIO_C_DO_STATE_MACHINE:
+ BIO_clear_retry_flags(b);
+ ret = BIO_ctrl(next, cmd, num, ptr);
+ BIO_copy_next_retry(b);
+ break;
+
+ case BIO_CTRL_WPENDING:
+ if (BrotliEncoderHasMoreOutput(ctx->encode.state))
+ ret = 1;
+ else
+ ret = BIO_ctrl(next, cmd, num, ptr);
+ break;
+
+ case BIO_CTRL_PENDING:
+ if (!BrotliDecoderIsFinished(ctx->decode.state))
+ ret = 1;
+ else
+ ret = BIO_ctrl(next, cmd, num, ptr);
+ break;
+
+ default:
+ ret = BIO_ctrl(next, cmd, num, ptr);
+ break;
+
+ }
+
+ return ret;
+}
+
+static long bio_brotli_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
+{
+ BIO *next = BIO_next(b);
+ if (next == NULL)
+ return 0;
+ return BIO_callback_ctrl(next, cmd, fp);
+}
+
+#endif
diff --git a/crypto/comp/comp_err.c b/crypto/comp/comp_err.c
index 70a6eea0f0..4f55f820da 100644
--- a/crypto/comp/comp_err.c
+++ b/crypto/comp/comp_err.c
@@ -17,6 +17,16 @@
# ifndef OPENSSL_NO_ERR
static const ERR_STRING_DATA COMP_str_reasons[] = {
+ {ERR_PACK(ERR_LIB_COMP, 0, COMP_R_BROTLI_DECODE_ERROR),
+ "brotli decode error"},
+ {ERR_PACK(ERR_LIB_COMP, 0, COMP_R_BROTLI_DEFLATE_ERROR),
+ "brotli deflate error"},
+ {ERR_PACK(ERR_LIB_COMP, 0, COMP_R_BROTLI_ENCODE_ERROR),
+ "brotli encode error"},
+ {ERR_PACK(ERR_LIB_COMP, 0, COMP_R_BROTLI_INFLATE_ERROR),
+ "brotli inflate error"},
+ {ERR_PACK(ERR_LIB_COMP, 0, COMP_R_BROTLI_NOT_SUPPORTED),
+ "brotli not supported"},
{ERR_PACK(ERR_LIB_COMP, 0, COMP_R_ZLIB_DEFLATE_ERROR),
"zlib deflate error"},
{ERR_PACK(ERR_LIB_COMP, 0, COMP_R_ZLIB_INFLATE_ERROR),
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index c2978074a6..67179fa9ae 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -382,6 +382,11 @@ CMS_R_UNWRAP_ERROR:157:unwrap error
CMS_R_UNWRAP_FAILURE:180:unwrap failure
CMS_R_VERIFICATION_FAILURE:158:verification failure
CMS_R_WRAP_ERROR:159:wrap error
+COMP_R_BROTLI_DECODE_ERROR:102:brotli decode error
+COMP_R_BROTLI_DEFLATE_ERROR:103:brotli deflate error
+COMP_R_BROTLI_ENCODE_ERROR:106:brotli encode error
+COMP_R_BROTLI_INFLATE_ERROR:104:brotli inflate error
+COMP_R_BROTLI_NOT_SUPPORTED:105:brotli not supported
COMP_R_ZLIB_DEFLATE_ERROR:99:zlib deflate error
COMP_R_ZLIB_INFLATE_ERROR:100:zlib inflate error
COMP_R_ZLIB_NOT_SUPPORTED:101:zlib not supported
diff --git a/crypto/init.c b/crypto/init.c
index a224542e03..fa8f0d694a 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -389,6 +389,8 @@ void OPENSSL_cleanup(void)
#ifndef OPENSSL_NO_COMP
OSSL_TRACE(INIT, "OPENSSL_cleanup: ossl_comp_zlib_cleanup()\n");
ossl_comp_zlib_cleanup();
+ OSSL_TRACE(INIT, "OPENSSL_cleanup: ossl_comp_brotli_cleanup()\n");
+ ossl_comp_brotli_cleanup();
#endif
if (async_inited) {
diff --git a/crypto/objects/obj_dat.h b/crypto/objects/obj_dat.h
index b97118922c..115c707cd1 100644
--- a/crypto/objects/obj_dat.h
+++ b/crypto/objects/obj_dat.h
@@ -1154,7 +1154,7 @@ static const unsigned char so[8356] = {
0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x10,0x01,0x32, /* [ 8344] OBJ_id_ct_signedTAL */
};
-#define NUM_NID 1288
+#define NUM_NID 1289
static const ASN1_OBJECT nid_objs[NUM_NID] = {
{"UNDEF", "undefined", NID_undef},
{"rsadsi", "RSA Data Security, Inc.", NID_rsadsi, 6, &so[0]},
@@ -2444,9 +2444,10 @@ static const ASN1_OBJECT nid_objs[NUM_NID] = {
{"brainpoolP256r1tls13", "brainpoolP256r1tls13", NID_brainpoolP256r1tls13},
{"brainpoolP384r1tls13", "brainpoolP384r1tls13", NID_brainpoolP384r1tls13},
{"brainpoolP512r1tls13", "brainpoolP512r1tls13", NID_brainpoolP512r1tls13},
+ {"brotli", "Brotli compression", NID_brotli},
};
-#define NUM_SN 1279
+#define NUM_SN 1280
static const unsigned int sn_objs[NUM_SN] = {
364, /* "AD_DVCS" */
419, /* "AES-128-CBC" */
@@ -2794,6 +2795,7 @@ static const unsigned int sn_objs[NUM_SN] = {
933, /* "brainpoolP512r1" */
1287, /* "brainpoolP512r1tls13" */
934, /* "brainpoolP512t1" */
+ 1288, /* "brotli" */
494, /* "buildingName" */
860, /* "businessCategory" */
691, /* "c2onb191v4" */
@@ -3729,7 +3731,7 @@ static const unsigned int sn_objs[NUM_SN] = {
1093, /* "x509ExtAdmission" */
};
-#define NUM_LN 1279
+#define NUM_LN 1280
static const unsigned int ln_objs[NUM_LN] = {
363, /* "AD Time Stamping" */
405, /* "ANSI X9.62" */
@@ -3741,6 +3743,7 @@ static const unsigned int ln_objs[NUM_LN] = {
365, /* "Basic OCSP Response" */
285, /* "Biometric Info" */
1221, /* "Brand Indicator for Message Identification" */
+ 1288, /* "Brotli compression" */
179, /* "CA Issuers" */
785, /* "CA Repository" */
1219, /* "CMC Archive Server" */
diff --git a/crypto/objects/obj_mac.num b/crypto/objects/obj_mac.num
index 64dffcb7c1..5940f6911b 100644
--- a/crypto/objects/obj_mac.num
+++ b/crypto/objects/obj_mac.num
@@ -1285,3 +1285,4 @@ id_ct_signedTAL 1284
brainpoolP256r1tls13 1285
brainpoolP384r1tls13 1286
brainpoolP512r1tls13 1287
+brotli 1288
diff --git a/crypto/objects/objects.txt b/crypto/objects/objects.txt
index b627cfdfd1..a0991529b9 100644
--- a/crypto/objects/objects.txt
+++ b/crypto/objects/objects.txt
@@ -1802,3 +1802,6 @@ dstu4145le 2 9 : uacurve9 : DSTU curve 9
joint-iso-itu-t 16 840 1 113894 : oracle-organization : Oracle organization
# Jdk trustedKeyUsage attribute
oracle 746875 1 1 : oracle-jdk-trustedkeyusage : Trusted key usage (Oracle)
+
+# NID for brotli
+ : brotli : Brotli compression