Browse Source

Add zlib oneshot compression

Fixes #19520

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19603)
Todd Short 1 year ago
parent
commit
3840271e98

+ 83 - 2
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)
 {

+ 8 - 2
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<COMP_METHOD> for stream-based ZLIB compression.
 
 =item *
 
+COMP_zlib_oneshot() returns a B<COMP_METHOD> for one-shot ZLIB compression.
+
+=item *
+
 COMP_brotli() returns a B<COMP_METHOD> 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<COMP_CTX> 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<COMP_METHOD> on success,
 or NULL on failure.
 

+ 1 - 0
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);

+ 1 - 1
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();

+ 1 - 1
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();

+ 1 - 1
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();

+ 1 - 0
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