From 3840271e984010132380892817c1e1173f4a1576 Mon Sep 17 00:00:00 2001 From: Todd Short Date: Thu, 3 Nov 2022 13:20:07 -0400 Subject: [PATCH] Add zlib oneshot compression Fixes #19520 Reviewed-by: Matt Caswell Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/19603) --- crypto/comp/c_zlib.c | 85 ++++++++++++++++++++++++++++++++++++++- doc/man3/COMP_CTX_new.pod | 10 ++++- include/openssl/comp.h | 1 + ssl/ssl_cert_comp.c | 2 +- ssl/statem/statem_clnt.c | 2 +- ssl/statem/statem_lib.c | 2 +- util/libcrypto.num | 1 + 7 files changed, 96 insertions(+), 7 deletions(-) diff --git a/crypto/comp/c_zlib.c b/crypto/comp/c_zlib.c index ba5a8d9ce4..90a1840ecd 100644 --- a/crypto/comp/c_zlib.c +++ b/crypto/comp/c_zlib.c @@ -74,8 +74,10 @@ static COMP_METHOD zlib_stateful_method = { # include "internal/dso.h" /* Function pointers */ -typedef int (*compress_ft) (Bytef *dest, uLongf * destLen, +typedef int (*compress_ft) (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen); +typedef int (*uncompress_ft) (Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); typedef int (*inflateEnd_ft) (z_streamp strm); typedef int (*inflate_ft) (z_streamp strm, int flush); typedef int (*inflateInit__ft) (z_streamp strm, @@ -86,6 +88,7 @@ typedef int (*deflateInit__ft) (z_streamp strm, int level, const char *version, int stream_size); typedef const char *(*zError__ft) (int err); static compress_ft p_compress = NULL; +static uncompress_ft p_uncompress = NULL; static inflateEnd_ft p_inflateEnd = NULL; static inflate_ft p_inflate = NULL; static inflateInit__ft p_inflateInit_ = NULL; @@ -97,6 +100,7 @@ static zError__ft p_zError = NULL; static DSO *zlib_dso = NULL; # define compress p_compress +# define uncompress p_uncompress # define inflateEnd p_inflateEnd # define inflate p_inflate # define inflateInit_ p_inflateInit_ @@ -199,6 +203,70 @@ static ossl_ssize_t zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out return (ossl_ssize_t)(olen - state->istream.avail_out); } +/* ONESHOT COMPRESSION/DECOMPRESSION */ + +static int zlib_oneshot_init(COMP_CTX *ctx) +{ + return 1; +} + +static void zlib_oneshot_finish(COMP_CTX *ctx) +{ +} + +static ossl_ssize_t zlib_oneshot_compress_block(COMP_CTX *ctx, unsigned char *out, + size_t olen, unsigned char *in, + size_t ilen) +{ + uLongf out_size; + + if (ilen == 0) + return 0; + + /* zlib's uLongf defined as unsigned long FAR */ + if (olen > ULONG_MAX) + return -1; + out_size = (uLongf)olen; + + if (compress(out, &out_size, in, ilen) != Z_OK) + return -1; + + if (out_size > OSSL_SSIZE_MAX) + return -1; + return (ossl_ssize_t)out_size; +} + +static ossl_ssize_t zlib_oneshot_expand_block(COMP_CTX *ctx, unsigned char *out, + size_t olen, unsigned char *in, + size_t ilen) +{ + uLongf out_size; + + if (ilen == 0) + return 0; + + /* zlib's uLongf defined as unsigned long FAR */ + if (olen > ULONG_MAX) + return -1; + out_size = (uLongf)olen; + + if (uncompress(out, &out_size, in, ilen) != Z_OK) + return -1; + + if (out_size > OSSL_SSIZE_MAX) + return -1; + return (ossl_ssize_t)out_size; +} + +static COMP_METHOD zlib_oneshot_method = { + NID_zlib_compression, + LN_zlib_compression, + zlib_oneshot_init, + zlib_oneshot_finish, + zlib_oneshot_compress_block, + zlib_oneshot_expand_block +}; + static CRYPTO_ONCE zlib_once = CRYPTO_ONCE_STATIC_INIT; DEFINE_RUN_ONCE_STATIC(ossl_comp_zlib_init) { @@ -217,6 +285,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_comp_zlib_init) zlib_dso = DSO_load(NULL, LIBZ, NULL, 0); if (zlib_dso != NULL) { p_compress = (compress_ft) DSO_bind_func(zlib_dso, "compress"); + p_uncompress = (compress_ft) DSO_bind_func(zlib_dso, "uncompress"); p_inflateEnd = (inflateEnd_ft) DSO_bind_func(zlib_dso, "inflateEnd"); p_inflate = (inflate_ft) DSO_bind_func(zlib_dso, "inflate"); p_inflateInit_ = (inflateInit__ft) DSO_bind_func(zlib_dso, "inflateInit_"); @@ -225,7 +294,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_comp_zlib_init) p_deflateInit_ = (deflateInit__ft) DSO_bind_func(zlib_dso, "deflateInit_"); p_zError = (zError__ft) DSO_bind_func(zlib_dso, "zError"); - if (p_compress == NULL || p_inflateEnd == NULL + if (p_compress == NULL || p_uncompress == NULL || p_inflateEnd == NULL || p_inflate == NULL || p_inflateInit_ == NULL || p_deflateEnd == NULL || p_deflate == NULL || p_deflateInit_ == NULL || p_zError == NULL) { @@ -250,6 +319,18 @@ COMP_METHOD *COMP_zlib(void) return meth; } +COMP_METHOD *COMP_zlib_oneshot(void) +{ + COMP_METHOD *meth = NULL; + +#ifndef OPENSSL_NO_ZLIB + if (RUN_ONCE(&zlib_once, ossl_comp_zlib_init)) + meth = &zlib_oneshot_method; +#endif + + return meth; +} + /* Also called from OPENSSL_cleanup() */ void ossl_comp_zlib_cleanup(void) { diff --git a/doc/man3/COMP_CTX_new.pod b/doc/man3/COMP_CTX_new.pod index d4c0e326bf..bf9973f4d2 100644 --- a/doc/man3/COMP_CTX_new.pod +++ b/doc/man3/COMP_CTX_new.pod @@ -11,6 +11,7 @@ COMP_CTX_free, COMP_compress_block, COMP_expand_block, COMP_zlib, +COMP_zlib_oneshot, COMP_brotli, COMP_brotli_oneshot, COMP_zstd, @@ -37,6 +38,7 @@ BIO_f_zstd unsigned char *in, int ilen); COMP_METHOD *COMP_zlib(void); + COMP_METHOD *COMP_zlib_oneshot(void); COMP_METHOD *COMP_brotli(void); COMP_METHOD *COMP_brotli_oneshot(void); COMP_METHOD *COMP_zstd(void); @@ -78,6 +80,10 @@ COMP_zlib() returns a B for stream-based ZLIB compression. =item * +COMP_zlib_oneshot() returns a B for one-shot ZLIB compression. + +=item * + COMP_brotli() returns a B for stream-based Brotli compression. =item * @@ -130,7 +136,7 @@ COMP_zlib(), COMP_brotli() and COMP_zstd() are 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() and COMP_zstd_oneshot() are not stream-based. These +COMP_zlib_oneshot(), COMP_brotli_oneshot() and COMP_zstd_oneshot() are not stream-based. These methods do not maintain state between calls. An error in one call does not affect future calls. @@ -138,7 +144,7 @@ future calls. COMP_CTX_new() returns a B on success, or NULL on failure. -COMP_CTX_get_method(), COMP_zlib(), COMP_brotli(), COMP_brotli_oneshot(), +COMP_CTX_get_method(), COMP_zlib(), COMP_zlib_oneshot(), COMP_brotli(), COMP_brotli_oneshot(), COMP_zstd(), and COMP_zstd_oneshot() return a B on success, or NULL on failure. diff --git a/include/openssl/comp.h b/include/openssl/comp.h index 885fdf6183..f81ba0f39c 100644 --- a/include/openssl/comp.h +++ b/include/openssl/comp.h @@ -40,6 +40,7 @@ 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_zlib_oneshot(void); COMP_METHOD *COMP_brotli(void); COMP_METHOD *COMP_brotli_oneshot(void); COMP_METHOD *COMP_zstd(void); diff --git a/ssl/ssl_cert_comp.c b/ssl/ssl_cert_comp.c index 654da2dc03..f782c4eee1 100644 --- a/ssl/ssl_cert_comp.c +++ b/ssl/ssl_cert_comp.c @@ -101,7 +101,7 @@ __owur static OSSL_COMP_CERT *OSSL_COMP_CERT_from_uncompressed_data(unsigned cha method = COMP_brotli_oneshot(); break; case TLSEXT_comp_cert_zlib: - method = COMP_zlib(); + method = COMP_zlib_oneshot(); break; case TLSEXT_comp_cert_zstd: method = COMP_zstd_oneshot(); diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index 3021bc1952..402654b7a4 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -3689,7 +3689,7 @@ CON_FUNC_RETURN tls_construct_client_compressed_certificate(SSL_CONNECTION *sc, switch (alg) { case TLSEXT_comp_cert_zlib: - method = COMP_zlib(); + method = COMP_zlib_oneshot(); break; case TLSEXT_comp_cert_brotli: method = COMP_brotli_oneshot(); diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index 1634dd8594..155afd5d91 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -2520,7 +2520,7 @@ MSG_PROCESS_RETURN tls13_process_compressed_certificate(SSL_CONNECTION *sc, } switch (comp_alg) { case TLSEXT_comp_cert_zlib: - method = COMP_zlib(); + method = COMP_zlib_oneshot(); break; case TLSEXT_comp_cert_brotli: method = COMP_brotli_oneshot(); diff --git a/util/libcrypto.num b/util/libcrypto.num index d9ed04ecb3..1db533d4a2 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5480,3 +5480,4 @@ COMP_zstd_oneshot ? 3_2_0 EXIST::FUNCTION:COMP BIO_f_zstd ? 3_2_0 EXIST::FUNCTION:COMP d2i_PUBKEY_ex_fp ? 3_2_0 EXIST::FUNCTION:STDIO d2i_PUBKEY_ex_bio ? 3_2_0 EXIST::FUNCTION: +COMP_zlib_oneshot ? 3_2_0 EXIST::FUNCTION:COMP