mirror of
https://github.com/openssl/openssl.git
synced 2024-11-27 12:04:38 +08:00
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)
This commit is contained in:
parent
846975f367
commit
12e96a2360
@ -48,6 +48,8 @@ my %targets=(
|
||||
defines =>
|
||||
sub {
|
||||
my @defs = ( 'OPENSSL_BUILDING_OPENSSL' );
|
||||
push @defs, "BROTLI" unless $disabled{brotli};
|
||||
push @defs, "BROTLI_SHARED" unless $disabled{"brotli-dynamic"};
|
||||
push @defs, "ZLIB" unless $disabled{zlib};
|
||||
push @defs, "ZLIB_SHARED" unless $disabled{"zlib-dynamic"};
|
||||
return [ @defs ];
|
||||
@ -55,6 +57,8 @@ my %targets=(
|
||||
includes =>
|
||||
sub {
|
||||
my @incs = ();
|
||||
push @incs, $withargs{brotli_include}
|
||||
if !$disabled{brotli} && $withargs{brotli_include};
|
||||
push @incs, $withargs{zlib_include}
|
||||
if !$disabled{zlib} && $withargs{zlib_include};
|
||||
return [ @incs ];
|
||||
@ -69,11 +73,24 @@ my %targets=(
|
||||
ARFLAGS => "qc",
|
||||
CC => "cc",
|
||||
lflags =>
|
||||
sub { $withargs{zlib_lib} ? "-L".$withargs{zlib_lib} : () },
|
||||
sub {
|
||||
my @libs = ();
|
||||
push(@libs, "-L".$withargs{zlib_lib}) if $withargs{zlib_lib};
|
||||
push(@libs, "-L".$withargs{brotli_lib}) if $withargs{brotli_lib};
|
||||
return join(" ", @libs);
|
||||
},
|
||||
ex_libs =>
|
||||
sub { !defined($disabled{zlib})
|
||||
&& defined($disabled{"zlib-dynamic"})
|
||||
? "-lz" : () },
|
||||
sub {
|
||||
my @libs = ();
|
||||
push(@libs, "-lz") if !defined($disabled{zlib}) && defined($disabled{"zlib-dynamic"});
|
||||
if (!defined($disabled{brotli}) && defined($disabled{"brotli-dynamic"})) {
|
||||
push(@libs, "-lbrotlienc");
|
||||
push(@libs, "-lbrotlidec");
|
||||
push(@libs, "-lbrotlicommon");
|
||||
push(@libs, "-lm");
|
||||
}
|
||||
return join(" ", @libs);
|
||||
},
|
||||
HASHBANGPERL => "/usr/bin/env perl", # Only Unix actually cares
|
||||
RANLIB => sub { which("$config{cross_compile_prefix}ranlib")
|
||||
? "ranlib" : "" },
|
||||
@ -100,12 +117,24 @@ my %targets=(
|
||||
},
|
||||
ex_libs =>
|
||||
sub {
|
||||
my @libs = ();
|
||||
unless ($disabled{zlib}) {
|
||||
if (defined($disabled{"zlib-dynamic"})) {
|
||||
return $withargs{zlib_lib} // "ZLIB1";
|
||||
push(@libs, $withargs{zlib_lib} // "ZLIB1");
|
||||
}
|
||||
}
|
||||
return ();
|
||||
unless ($disabled{brotli}) {
|
||||
if (defined($disabled{"brotli-dynamic"})) {
|
||||
my $path = "";
|
||||
if (defined($withargs{brotli_lib})) {
|
||||
$path = $withargs{brotli_lib} . "\\";
|
||||
}
|
||||
push(@libs, $path . "brotlicommon.lib");
|
||||
push(@libs, $path . "brotlidec.lib");
|
||||
push(@libs, $path . "brotlienc.lib");
|
||||
}
|
||||
}
|
||||
return join(" ", @libs);
|
||||
},
|
||||
|
||||
MT => "mt",
|
||||
|
23
Configure
23
Configure
@ -27,7 +27,7 @@ use OpenSSL::config;
|
||||
my $orig_death_handler = $SIG{__DIE__};
|
||||
$SIG{__DIE__} = \&death_handler;
|
||||
|
||||
my $usage="Usage: Configure [no-<cipher> ...] [enable-<cipher> ...] [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [no-hw-xxx|no-hw] [[no-]threads] [[no-]thread-pool] [[no-]default-thread-pool] [[no-]shared] [[no-]zlib|zlib-dynamic] [no-asm] [no-egd] [sctp] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--config=FILE] os/compiler[:flags]\n";
|
||||
my $usage="Usage: Configure [no-<feature> ...] [enable-<feature> ...] [-Dxxx] [-lxxx] [-Lxxx] [-fxxx] [-Kxxx] [no-hw-xxx|no-hw] [[no-]threads] [[no-]thread-pool] [[no-]default-thread-pool] [[no-]shared] [[no-]zlib|zlib-dynamic] [no-asm] [no-egd] [sctp] [386] [--prefix=DIR] [--openssldir=OPENSSLDIR] [--with-xxx[=vvv]] [--config=FILE] os/compiler[:flags]\n";
|
||||
|
||||
my $banner = <<"EOF";
|
||||
|
||||
@ -92,7 +92,7 @@ EOF
|
||||
# no-egd do not compile support for the entropy-gathering daemon APIs
|
||||
# [no-]zlib [don't] compile support for zlib compression.
|
||||
# zlib-dynamic Like "zlib", but the zlib library is expected to be a shared
|
||||
# library and will be loaded in run-time by the OpenSSL library.
|
||||
# library and will be loaded at run-time by the OpenSSL library.
|
||||
# sctp include SCTP support
|
||||
# enable-quic include QUIC support (currently just for developers as the
|
||||
# implementation is by no means complete and usable)
|
||||
@ -416,6 +416,8 @@ my @disablables = (
|
||||
"autoload-config",
|
||||
"bf",
|
||||
"blake2",
|
||||
"brotli",
|
||||
"brotli-dynamic",
|
||||
"buildtest-c++",
|
||||
"bulk",
|
||||
"cached-fetch",
|
||||
@ -546,6 +548,8 @@ my %deprecated_disablables = (
|
||||
our %disabled = ( # "what" => "comment"
|
||||
"fips" => "default",
|
||||
"asan" => "default",
|
||||
"brotli" => "default",
|
||||
"brotli-dynamic" => "default",
|
||||
"buildtest-c++" => "default",
|
||||
"crypto-mdebug" => "default",
|
||||
"crypto-mdebug-backtrace" => "default",
|
||||
@ -597,6 +601,7 @@ my @disable_cascades = (
|
||||
"ssl" => [ "ssl3" ],
|
||||
"ssl3-method" => [ "ssl3" ],
|
||||
"zlib" => [ "zlib-dynamic" ],
|
||||
"brotli" => [ "brotli-dynamic" ],
|
||||
"des" => [ "mdc2" ],
|
||||
"ec" => [ "ec2m", "ecdsa", "ecdh", "sm2", "gost" ],
|
||||
"dgram" => [ "dtls", "quic", "sctp" ],
|
||||
@ -642,7 +647,7 @@ my @disable_cascades = (
|
||||
"stdio" => [ "apps", "capieng", "egd" ],
|
||||
"apps" => [ "tests" ],
|
||||
"tests" => [ "external-tests" ],
|
||||
"comp" => [ "zlib" ],
|
||||
"comp" => [ "zlib", "brotli" ],
|
||||
"sm3" => [ "sm2" ],
|
||||
sub { !$disabled{"unit-test"} } => [ "heartbeats" ],
|
||||
|
||||
@ -903,6 +908,10 @@ while (@argvcopy)
|
||||
{
|
||||
delete $disabled{"zlib"};
|
||||
}
|
||||
elsif ($1 eq "brotli-dynamic")
|
||||
{
|
||||
delete $disabled{"brotli"};
|
||||
}
|
||||
my $algo = $1;
|
||||
delete $disabled{$algo};
|
||||
|
||||
@ -979,6 +988,14 @@ while (@argvcopy)
|
||||
{
|
||||
$withargs{zlib_include}=$1;
|
||||
}
|
||||
elsif (/^--with-brotli-lib=(.*)$/)
|
||||
{
|
||||
$withargs{brotli_lib}=$1;
|
||||
}
|
||||
elsif (/^--with-brotli-include=(.*)$/)
|
||||
{
|
||||
$withargs{brotli_include}=$1;
|
||||
}
|
||||
elsif (/^--with-fuzzer-lib=(.*)$/)
|
||||
{
|
||||
$withargs{fuzzer_lib}=$1;
|
||||
|
48
INSTALL.md
48
INSTALL.md
@ -19,7 +19,7 @@ Table of Contents
|
||||
- [Build Type](#build-type)
|
||||
- [Directories](#directories)
|
||||
- [Compiler Warnings](#compiler-warnings)
|
||||
- [ZLib Flags](#zlib-flags)
|
||||
- [Compression Algorithm Flags](#compression-algorithm-flags)
|
||||
- [Seeding the Random Generator](#seeding-the-random-generator)
|
||||
- [Setting the FIPS HMAC key](#setting-the-FIPS-HMAC-key)
|
||||
- [Enable and Disable Features](#enable-and-disable-features)
|
||||
@ -382,8 +382,39 @@ for OpenSSL development. It only works when using gcc or clang as the compiler.
|
||||
If you are developing a patch for OpenSSL then it is recommended that you use
|
||||
this option where possible.
|
||||
|
||||
ZLib Flags
|
||||
----------
|
||||
Compression Algorithm Flags
|
||||
---------------------------
|
||||
|
||||
### with-brotli-include
|
||||
|
||||
--with-brotli-include=DIR
|
||||
|
||||
The directory for the location of the brotli include files (i.e. the location
|
||||
of the **brotli** include directory). This option is only necessary if
|
||||
[enable-brotli](#enable-brotli) is used and the include files are not already
|
||||
on the system include path.
|
||||
|
||||
### with-brotli-lib
|
||||
|
||||
--with-brotli-lib=LIB
|
||||
|
||||
**On Unix**: this is the directory containing the brotli libraries.
|
||||
If not provided, the system library path will be used.
|
||||
|
||||
The names of the libraries are:
|
||||
|
||||
* libbrotlicommon.a or libbrotlicommon.so
|
||||
* libbrotlidec.a or libbrotlidec.so
|
||||
* libbrotlienc.a or libbrotlienc.so
|
||||
|
||||
**On Windows:** this is the directory containing the brotli libraries.
|
||||
If not provided, the system library path will be used.
|
||||
|
||||
The names of the libraries are:
|
||||
|
||||
* brotlicommon.lib
|
||||
* brotlidec.lib
|
||||
* brotlienc.lib
|
||||
|
||||
### with-zlib-include
|
||||
|
||||
@ -556,6 +587,17 @@ Typically OpenSSL will automatically load human readable error strings. For a
|
||||
statically linked application this may be undesirable if small executable size
|
||||
is an objective.
|
||||
|
||||
### enable-brotli
|
||||
|
||||
Build with support for brotli compression/decompression.
|
||||
|
||||
### enable-brotli-dynamic
|
||||
|
||||
Like the enable-brotli option, but has OpenSSL load the brotli library dynamically
|
||||
when needed.
|
||||
|
||||
This is only supported on systems where loading of shared libraries is supported.
|
||||
|
||||
### no-autoload-config
|
||||
|
||||
Don't automatically load the default `openssl.cnf` file.
|
||||
|
42
apps/enc.c
42
apps/enc.c
@ -134,6 +134,8 @@ int enc_main(int argc, char **argv)
|
||||
int do_zlib = 0;
|
||||
BIO *bzl = NULL;
|
||||
#endif
|
||||
int do_brotli = 0;
|
||||
BIO *bbrot = NULL;
|
||||
|
||||
/* first check the command name */
|
||||
if (strcmp(argv[0], "base64") == 0)
|
||||
@ -141,6 +143,10 @@ int enc_main(int argc, char **argv)
|
||||
#ifdef ZLIB
|
||||
else if (strcmp(argv[0], "zlib") == 0)
|
||||
do_zlib = 1;
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_BROTLI
|
||||
else if (strcmp(argv[0], "brotli") == 0)
|
||||
do_brotli = 1;
|
||||
#endif
|
||||
else if (strcmp(argv[0], "enc") != 0)
|
||||
ciphername = argv[0];
|
||||
@ -321,14 +327,18 @@ int enc_main(int argc, char **argv)
|
||||
BIO_printf(bio_err, "bufsize=%d\n", bsize);
|
||||
|
||||
#ifdef ZLIB
|
||||
if (!do_zlib)
|
||||
if (do_zlib)
|
||||
base64 = 0;
|
||||
#endif
|
||||
if (base64) {
|
||||
if (enc)
|
||||
outformat = FORMAT_BASE64;
|
||||
else
|
||||
informat = FORMAT_BASE64;
|
||||
}
|
||||
if (do_brotli)
|
||||
base64 = 0;
|
||||
|
||||
if (base64) {
|
||||
if (enc)
|
||||
outformat = FORMAT_BASE64;
|
||||
else
|
||||
informat = FORMAT_BASE64;
|
||||
}
|
||||
|
||||
strbuf = app_malloc(SIZE, "strbuf");
|
||||
buff = app_malloc(EVP_ENCODE_LENGTH(bsize), "evp buffer");
|
||||
@ -398,7 +408,8 @@ int enc_main(int argc, char **argv)
|
||||
rbio = in;
|
||||
wbio = out;
|
||||
|
||||
#ifdef ZLIB
|
||||
#ifndef OPENSSL_NO_COMP
|
||||
# ifdef ZLIB
|
||||
if (do_zlib) {
|
||||
if ((bzl = BIO_new(BIO_f_zlib())) == NULL)
|
||||
goto end;
|
||||
@ -411,6 +422,20 @@ int enc_main(int argc, char **argv)
|
||||
else
|
||||
rbio = BIO_push(bzl, rbio);
|
||||
}
|
||||
# endif
|
||||
|
||||
if (do_brotli) {
|
||||
if ((bbrot = BIO_new(BIO_f_brotli())) == NULL)
|
||||
goto end;
|
||||
if (debug) {
|
||||
BIO_set_callback_ex(bbrot, BIO_debug_callback_ex);
|
||||
BIO_set_callback_arg(bbrot, (char *)bio_err);
|
||||
}
|
||||
if (enc)
|
||||
wbio = BIO_push(bbrot, wbio);
|
||||
else
|
||||
rbio = BIO_push(bbrot, rbio);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (base64) {
|
||||
@ -656,6 +681,7 @@ int enc_main(int argc, char **argv)
|
||||
#ifdef ZLIB
|
||||
BIO_free(bzl);
|
||||
#endif
|
||||
BIO_free(bbrot);
|
||||
release_engine(e);
|
||||
OPENSSL_free(pass);
|
||||
return ret;
|
||||
|
@ -1424,6 +1424,9 @@ static void list_disabled(void)
|
||||
#ifndef ZLIB
|
||||
BIO_puts(bio_out, "ZLIB\n");
|
||||
#endif
|
||||
#ifdef OPENSSL_NO_BROTLI
|
||||
BIO_puts(bio_out, "BROTLI\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Unified enum for help and list commands. */
|
||||
|
@ -188,7 +188,7 @@ EOF
|
||||
"camellia-128-cbc", "camellia-128-ecb",
|
||||
"camellia-192-cbc", "camellia-192-ecb",
|
||||
"camellia-256-cbc", "camellia-256-ecb",
|
||||
"base64", "zlib",
|
||||
"base64", "zlib", "brotli",
|
||||
"des", "des3", "desx", "idea", "seed", "rc4", "rc4-40",
|
||||
"rc2", "bf", "cast", "rc5",
|
||||
"des-ecb", "des-ede", "des-ede3",
|
||||
|
@ -1,4 +1,5 @@
|
||||
LIBS=../../libcrypto
|
||||
SOURCE[../../libcrypto]= \
|
||||
comp_lib.c comp_err.c \
|
||||
c_brotli.c \
|
||||
c_zlib.c
|
||||
|
770
crypto/comp/c_brotli.c
Normal file
770
crypto/comp/c_brotli.c
Normal file
@ -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
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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" */
|
||||
|
@ -1285,3 +1285,4 @@ id_ct_signedTAL 1284
|
||||
brainpoolP256r1tls13 1285
|
||||
brainpoolP384r1tls13 1286
|
||||
brainpoolP512r1tls13 1287
|
||||
brotli 1288
|
||||
|
@ -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
|
||||
|
@ -859,6 +859,10 @@ DEPEND[html/man3/CMS_verify_receipt.html]=man3/CMS_verify_receipt.pod
|
||||
GENERATE[html/man3/CMS_verify_receipt.html]=man3/CMS_verify_receipt.pod
|
||||
DEPEND[man/man3/CMS_verify_receipt.3]=man3/CMS_verify_receipt.pod
|
||||
GENERATE[man/man3/CMS_verify_receipt.3]=man3/CMS_verify_receipt.pod
|
||||
DEPEND[html/man3/COMP_CTX_new.html]=man3/COMP_CTX_new.pod
|
||||
GENERATE[html/man3/COMP_CTX_new.html]=man3/COMP_CTX_new.pod
|
||||
DEPEND[man/man3/COMP_CTX_new.3]=man3/COMP_CTX_new.pod
|
||||
GENERATE[man/man3/COMP_CTX_new.3]=man3/COMP_CTX_new.pod
|
||||
DEPEND[html/man3/CONF_modules_free.html]=man3/CONF_modules_free.pod
|
||||
GENERATE[html/man3/CONF_modules_free.html]=man3/CONF_modules_free.pod
|
||||
DEPEND[man/man3/CONF_modules_free.3]=man3/CONF_modules_free.pod
|
||||
@ -2982,6 +2986,7 @@ html/man3/CMS_sign_receipt.html \
|
||||
html/man3/CMS_uncompress.html \
|
||||
html/man3/CMS_verify.html \
|
||||
html/man3/CMS_verify_receipt.html \
|
||||
html/man3/COMP_CTX_new.html \
|
||||
html/man3/CONF_modules_free.html \
|
||||
html/man3/CONF_modules_load_file.html \
|
||||
html/man3/CRYPTO_THREAD_run_once.html \
|
||||
@ -3586,6 +3591,7 @@ man/man3/CMS_sign_receipt.3 \
|
||||
man/man3/CMS_uncompress.3 \
|
||||
man/man3/CMS_verify.3 \
|
||||
man/man3/CMS_verify_receipt.3 \
|
||||
man/man3/COMP_CTX_new.3 \
|
||||
man/man3/CONF_modules_free.3 \
|
||||
man/man3/CONF_modules_load_file.3 \
|
||||
man/man3/CRYPTO_THREAD_run_once.3 \
|
||||
|
156
doc/man3/COMP_CTX_new.pod
Normal file
156
doc/man3/COMP_CTX_new.pod
Normal file
@ -0,0 +1,156 @@
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
COMP_CTX_new,
|
||||
COMP_CTX_get_method,
|
||||
COMP_CTX_get_type,
|
||||
COMP_get_type,
|
||||
COMP_get_name,
|
||||
COMP_CTX_free,
|
||||
COMP_compress_block,
|
||||
COMP_expand_block,
|
||||
COMP_zlib,
|
||||
COMP_brotli,
|
||||
COMP_brotli_oneshot,
|
||||
BIO_f_zlib,
|
||||
BIO_f_brotli
|
||||
- Compression support
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
#include <openssl/comp.h>
|
||||
|
||||
COMP_CTX *COMP_CTX_new(COMP_METHOD *meth);
|
||||
void COMP_CTX_free(COMP_CTX *ctx);
|
||||
const COMP_METHOD *COMP_CTX_get_method(const COMP_CTX *ctx);
|
||||
int COMP_CTX_get_type(const COMP_CTX* comp);
|
||||
int COMP_get_type(const COMP_METHOD *meth);
|
||||
const char *COMP_get_name(const COMP_METHOD *meth);
|
||||
|
||||
int COMP_compress_block(COMP_CTX *ctx, unsigned char *out, int olen,
|
||||
unsigned char *in, int ilen);
|
||||
int COMP_expand_block(COMP_CTX *ctx, unsigned char *out, int olen,
|
||||
unsigned char *in, int ilen);
|
||||
|
||||
COMP_METHOD *COMP_zlib(void);
|
||||
COMP_METHOD *COMP_brotli(void);
|
||||
COMP_METHOD *COMP_brotli_oneshot(void);
|
||||
|
||||
const BIO_METHOD *BIO_f_zlib(void);
|
||||
const BIO_METHOD *BIO_f_brotli(void);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
These functions provide compression support for OpenSSL. Compression is used within
|
||||
the OpenSSL library to support TLS record and certificate compression.
|
||||
|
||||
COMP_CTX_new() is used to create a new B<COMP_CTX> structure used to compress data.
|
||||
COMP_CTX_free() is used to free the returned B<COMP_CTX>.
|
||||
|
||||
COMP_CTX_get_method() returns the B<COMP_METHOD> of the given I<ctx>.
|
||||
|
||||
COMP_CTX_get_type() and COMP_get_type() return the NID for the B<COMP_CTX> and
|
||||
B<COMP_METHOD>, respectively. COMP_get_name() returns the name of the algorithm
|
||||
of the given B<COMP_METHOD>.
|
||||
|
||||
COMP_compress_block() compresses b<ilen> bytes from the buffer I<in> into the
|
||||
buffer b<out> of size I<olen> using the algorithm specified by I<ctx>.
|
||||
|
||||
COMP_expand_block() expands I<ilen> bytes from the buffer I<in> into the
|
||||
buffer I<out> of size I<olen> using the lgorithm specified by I<ctx>.
|
||||
|
||||
Methods (B<COMP_METHOD>) may be specified by one of these functions. These functions
|
||||
will be available even if their corresponding compression algorithm is not configured
|
||||
into the OpenSSL library. In such a case, a non-operative method will be returned.
|
||||
Any compression operations using a non-operative method will fail.
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
COMP_zlib() returns a B<COMP_METHOD> for stream-based ZLIB compression.
|
||||
|
||||
=item *
|
||||
|
||||
COMP_brotli() returns a B<COMP_METHOD> for stream-based Brotli compression.
|
||||
|
||||
=item *
|
||||
|
||||
COMP_brotli_oneshot() returns a B<COMP_METHOD> for one-shot Brotli compression.
|
||||
|
||||
=back
|
||||
|
||||
BIO_f_zlib() and BIO_f_brotli() each return a B<BIO_METHOD> that may be used to
|
||||
create a B<BIO> via L<BIO_new(3)> to read and write compressed files or streams.
|
||||
The functions are only available if the corresponding algorithm is compiled into
|
||||
the OpenSSL library.
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
While compressing non-compressible data, the output may be larger than the
|
||||
input. Care should be taken to size output buffers appropriate for both
|
||||
compression and expansion.
|
||||
|
||||
Compression support and compression algorithms must be enabled and built into
|
||||
the library before use. Refer to the INSTALL.md file when configuring OpenSSL.
|
||||
|
||||
ZLIB may be found at L<https://zlib.net>
|
||||
|
||||
Brotli may be found at L<https://github.com/google/brotli>.
|
||||
|
||||
Compression of SSL/TLS records is not recommended, as it has been
|
||||
shown to lead to the CRIME attack L<https://en.wikipedia.org/wiki/CRIME>.
|
||||
It is disabled by default, and may be enabled by clearing the
|
||||
SSL_OP_NO_COMPRESSION options of the L<SSL_CTX_set_options(3)> or
|
||||
L<SSL_set_options(3)> functions.
|
||||
|
||||
Compression is also used to support certificate compression as described
|
||||
in RFC8879 L<https://datatracker.ietf.org/doc/html/rfc8879>.
|
||||
It may be disabled via the SSL_OP_NO_CERTIFICATE_COMPRESSION option of
|
||||
the L<SSL_CTX_set_options(3)> or L<SSL_set_options(3)> functions.
|
||||
|
||||
COMP_zlib() and COMP_brotli() are both stream-based compression methods.
|
||||
Internal state (including compression dictionary) is maintained between calls.
|
||||
If an error is returned, the stream is corrupted, and should be closed.
|
||||
|
||||
COMP_brotli_oneshot() is not stream-based, it does not maintain state
|
||||
between calls. An error in one call does not affect future calls.
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
COMP_CTX_new() returns a B<COMP_CTX> on success, or NULL on failure.
|
||||
|
||||
COMP_CTX_get_method(), COMP_zlib(), COMP_brotli(), and COMP_brotli_oneshot()
|
||||
return a B<COMP_METHOD> on success, or NULL on failure.
|
||||
|
||||
COMP_CTX_get_type() and COMP_get_type() return a NID value. On failure,
|
||||
NID_undef is returned.
|
||||
|
||||
COMP_compress_block() and COMP_expand_block() return the number of
|
||||
bytes stored in the output buffer I<out>. This may be 0. On failure,
|
||||
-1 is returned.
|
||||
|
||||
COMP_get_name() returns a B<const char *> that must not be freed
|
||||
on success, or NULL on failure.
|
||||
|
||||
BIO_f_zlib() and BIO_f_brotli() return a B<BIO_METHOD>.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<BIO_new(3)>, L<SSL_CTX_set_options(3)>, L<SSL_set_options(3)>
|
||||
|
||||
=head1 HISTORY
|
||||
|
||||
Brotli functions were added in OpenSSL 3.1.0.
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2022 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
|
||||
L<https://www.openssl.org/source/license.html>.
|
||||
|
||||
=cut
|
@ -60,7 +60,17 @@ when a matching identifier is found. There is no way to restrict the list
|
||||
of compression methods supported on a per connection basis.
|
||||
|
||||
If enabled during compilation, the OpenSSL library will have the
|
||||
COMP_zlib() compression method available.
|
||||
following compression methods available:
|
||||
|
||||
=over 4
|
||||
|
||||
=item COMP_zlib()
|
||||
|
||||
=item COMP_brotli()
|
||||
|
||||
=item COMP_brotli_oneshot()
|
||||
|
||||
=back
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
|
@ -10,3 +10,4 @@
|
||||
#include <openssl/comp.h>
|
||||
|
||||
void ossl_comp_zlib_cleanup(void);
|
||||
void ossl_comp_brotli_cleanup(void);
|
||||
|
@ -40,6 +40,8 @@ int COMP_expand_block(COMP_CTX *ctx, unsigned char *out, int olen,
|
||||
unsigned char *in, int ilen);
|
||||
|
||||
COMP_METHOD *COMP_zlib(void);
|
||||
COMP_METHOD *COMP_brotli(void);
|
||||
COMP_METHOD *COMP_brotli_oneshot(void);
|
||||
|
||||
#ifndef OPENSSL_NO_DEPRECATED_1_1_0
|
||||
# define COMP_zlib_cleanup() while(0) continue
|
||||
@ -49,6 +51,7 @@ COMP_METHOD *COMP_zlib(void);
|
||||
# ifdef ZLIB
|
||||
const BIO_METHOD *BIO_f_zlib(void);
|
||||
# endif
|
||||
const BIO_METHOD *BIO_f_brotli(void);
|
||||
# endif
|
||||
|
||||
|
||||
|
@ -23,6 +23,11 @@
|
||||
/*
|
||||
* COMP reason codes.
|
||||
*/
|
||||
# define COMP_R_BROTLI_DECODE_ERROR 102
|
||||
# define COMP_R_BROTLI_DEFLATE_ERROR 103
|
||||
# define COMP_R_BROTLI_ENCODE_ERROR 106
|
||||
# define COMP_R_BROTLI_INFLATE_ERROR 104
|
||||
# define COMP_R_BROTLI_NOT_SUPPORTED 105
|
||||
# define COMP_R_ZLIB_DEFLATE_ERROR 99
|
||||
# define COMP_R_ZLIB_INFLATE_ERROR 100
|
||||
# define COMP_R_ZLIB_NOT_SUPPORTED 101
|
||||
|
@ -5593,6 +5593,10 @@
|
||||
#define NID_oracle_jdk_trustedkeyusage 1283
|
||||
#define OBJ_oracle_jdk_trustedkeyusage OBJ_oracle,746875L,1L,1L
|
||||
|
||||
#define SN_brotli "brotli"
|
||||
#define LN_brotli "Brotli compression"
|
||||
#define NID_brotli 1288
|
||||
|
||||
#endif /* OPENSSL_OBJ_MAC_H */
|
||||
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
|
143
test/bio_comp_test.c
Normal file
143
test/bio_comp_test.c
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2022 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
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/comp.h>
|
||||
|
||||
#include "testutil.h"
|
||||
#include "testutil/output.h"
|
||||
#include "testutil/tu_local.h"
|
||||
|
||||
#define COMPRESS 1
|
||||
#define EXPAND 0
|
||||
|
||||
#define BUFFER_SIZE 32 * 1024
|
||||
#define NUM_SIZES 4
|
||||
static int sizes[NUM_SIZES] = { 64, 512, 2048, 16 * 1024 };
|
||||
|
||||
/* using global buffers */
|
||||
uint8_t *original = NULL;
|
||||
uint8_t *result = NULL;
|
||||
|
||||
/*
|
||||
* For compression:
|
||||
* the write operation compresses
|
||||
* the read operation decompresses
|
||||
*/
|
||||
|
||||
static int do_bio_comp_test(const BIO_METHOD *meth, size_t size)
|
||||
{
|
||||
BIO *bcomp = NULL;
|
||||
BIO *bmem = NULL;
|
||||
BIO *bexp = NULL;
|
||||
int osize;
|
||||
int rsize;
|
||||
int ret = 0;
|
||||
|
||||
/* Compress */
|
||||
if (!TEST_ptr(bcomp = BIO_new(meth)))
|
||||
goto err;
|
||||
if (!TEST_ptr(bmem = BIO_new(BIO_s_mem())))
|
||||
goto err;
|
||||
BIO_push(bcomp, bmem);
|
||||
osize = BIO_write(bcomp, original, size);
|
||||
if (!TEST_int_eq(osize, size)
|
||||
|| !TEST_true(BIO_flush(bcomp)))
|
||||
goto err;
|
||||
BIO_free(bcomp);
|
||||
bcomp = NULL;
|
||||
|
||||
/* decompress */
|
||||
if (!TEST_ptr(bexp = BIO_new(meth)))
|
||||
goto err;
|
||||
BIO_push(bexp, bmem);
|
||||
rsize = BIO_read(bexp, result, size);
|
||||
|
||||
if (!TEST_int_eq(size, osize)
|
||||
|| !TEST_int_eq(size, rsize)
|
||||
|| !TEST_mem_eq(original, osize, result, rsize))
|
||||
goto err;
|
||||
|
||||
ret = 1;
|
||||
err:
|
||||
BIO_free(bexp);
|
||||
BIO_free(bcomp);
|
||||
BIO_free(bmem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_bio_comp(const BIO_METHOD *meth, int n)
|
||||
{
|
||||
int i;
|
||||
int success = 0;
|
||||
int size = sizes[n % 4];
|
||||
int type = n / 4;
|
||||
|
||||
if (!TEST_ptr(original = OPENSSL_malloc(BUFFER_SIZE))
|
||||
|| !TEST_ptr(result = OPENSSL_malloc(BUFFER_SIZE)))
|
||||
goto err;
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
test_printf_stdout("# zeros of size %d\n", size);
|
||||
memset(original, 0, BUFFER_SIZE);
|
||||
break;
|
||||
case 1:
|
||||
test_printf_stdout("# ones of size %d\n", size);
|
||||
memset(original, 0, BUFFER_SIZE);
|
||||
break;
|
||||
case 2:
|
||||
test_printf_stdout("# sequential of size %d\n", size);
|
||||
for (i = 0; i < BUFFER_SIZE; i++)
|
||||
original[i] = i & 0xFF;
|
||||
break;
|
||||
case 3:
|
||||
test_printf_stdout("# random of size %d\n", size);
|
||||
if (!TEST_int_gt(RAND_bytes(original, BUFFER_SIZE), 0))
|
||||
goto err;
|
||||
break;
|
||||
default:
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!TEST_true(do_bio_comp_test(meth, size)))
|
||||
goto err;
|
||||
success = 1;
|
||||
err:
|
||||
OPENSSL_free(original);
|
||||
OPENSSL_free(result);
|
||||
return success;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_BROTLI
|
||||
static int test_brotli(int n)
|
||||
{
|
||||
return do_bio_comp(BIO_f_brotli(), n);
|
||||
}
|
||||
#endif
|
||||
#ifdef ZLIB
|
||||
static int test_zlib(int n)
|
||||
{
|
||||
return do_bio_comp(BIO_f_zlib(), n);
|
||||
}
|
||||
#endif
|
||||
|
||||
int setup_tests(void)
|
||||
{
|
||||
#ifdef ZLIB
|
||||
ADD_ALL_TESTS(test_zlib, NUM_SIZES * 4);
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_BROTLI
|
||||
ADD_ALL_TESTS(test_brotli, NUM_SIZES * 4);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
@ -899,6 +899,13 @@ IF[{- !$disabled{tests} -}]
|
||||
INCLUDE[context_internal_test]=.. ../include ../apps/include
|
||||
DEPEND[context_internal_test]=../libcrypto.a libtestutil.a
|
||||
|
||||
IF[{- !$disabled{zlib} || !$disabled{brotli} -}]
|
||||
PROGRAMS{noinst}=bio_comp_test
|
||||
SOURCE[bio_comp_test]=bio_comp_test.c
|
||||
INCLUDE[bio_comp_test]=../include ../apps/include
|
||||
DEPEND[bio_comp_test]=../libcrypto.a libtestutil.a
|
||||
ENDIF
|
||||
|
||||
PROGRAMS{noinst}=provider_internal_test
|
||||
DEFINE[provider_internal_test]=PROVIDER_INIT_FUNCTION_NAME=p_test_init
|
||||
SOURCE[provider_internal_test]=provider_internal_test.c p_test.c
|
||||
|
19
test/recipes/07-test_bio_comp.t
Normal file
19
test/recipes/07-test_bio_comp.t
Normal file
@ -0,0 +1,19 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2022 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
|
||||
|
||||
use strict;
|
||||
use OpenSSL::Test;
|
||||
use OpenSSL::Test::Simple;
|
||||
use OpenSSL::Test::Utils;
|
||||
|
||||
setup("test_bio_comp");
|
||||
|
||||
plan skip_all => "No compression algorithms"
|
||||
if disabled("zlib") && disabled("brotli");
|
||||
|
||||
simple_test("test_bio_comp", "bio_comp_test");
|
@ -5469,3 +5469,6 @@ OSSL_sleep ? 3_2_0 EXIST::FUNCTION:
|
||||
OSSL_get_thread_support_flags ? 3_2_0 EXIST::FUNCTION:
|
||||
OSSL_set_max_threads ? 3_2_0 EXIST::FUNCTION:
|
||||
OSSL_get_max_threads ? 3_2_0 EXIST::FUNCTION:
|
||||
COMP_brotli ? 3_2_0 EXIST::FUNCTION:COMP
|
||||
COMP_brotli_oneshot ? 3_2_0 EXIST::FUNCTION:COMP
|
||||
BIO_f_brotli ? 3_2_0 EXIST::FUNCTION:COMP
|
||||
|
@ -190,7 +190,6 @@ BIO_f_asn1(3)
|
||||
BIO_f_linebuffer(3)
|
||||
BIO_f_nbio_test(3)
|
||||
BIO_f_reliable(3)
|
||||
BIO_f_zlib(3)
|
||||
BIO_fd_non_fatal_error(3)
|
||||
BIO_fd_should_retry(3)
|
||||
BIO_get_accept_socket(3)
|
||||
@ -353,15 +352,6 @@ CMS_unsigned_get_attr(3)
|
||||
CMS_unsigned_get_attr_by_NID(3)
|
||||
CMS_unsigned_get_attr_by_OBJ(3)
|
||||
CMS_unsigned_get_attr_count(3)
|
||||
COMP_CTX_free(3)
|
||||
COMP_CTX_get_method(3)
|
||||
COMP_CTX_get_type(3)
|
||||
COMP_CTX_new(3)
|
||||
COMP_compress_block(3)
|
||||
COMP_expand_block(3)
|
||||
COMP_get_name(3)
|
||||
COMP_get_type(3)
|
||||
COMP_zlib(3)
|
||||
CONF_dump_bio(3)
|
||||
CONF_dump_fp(3)
|
||||
CONF_free(3)
|
||||
|
@ -414,6 +414,7 @@ sub _parse_features {
|
||||
my $def = $';
|
||||
|
||||
if ($def =~ m{^ZLIB$}) { $features{$&} = $op; }
|
||||
if ($def =~ m{^BROTLI$}) { $features{$&} = $op; }
|
||||
if ($def =~ m{^OPENSSL_USE_}) { $features{$'} = $op; }
|
||||
if ($def =~ m{^OPENSSL_NO_}) { $features{$'} = !$op; }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user