Invoke tear_down when exiting test_encode_tls_sct() prematurely
[openssl.git] / crypto / comp / c_zlib.c
index e077aa5b9142de0227afce23400ae4f9962e7159..0fbab8f014fe51b1408c6748f287a9c17145fe4d 100644 (file)
+/*
+ * Copyright 1998-2023 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 <stdlib.h>
 #include <string.h>
 #include <openssl/objects.h>
-#include <openssl/comp.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_zlib(void );
-
-static COMP_METHOD zlib_method_nozlib={
-       NID_undef,
-       "(undef)",
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       };
-
-#ifndef ZLIB
-#undef ZLIB_SHARED
+COMP_METHOD *COMP_zlib(void);
+
+#ifdef OPENSSL_NO_ZLIB
+# undef ZLIB_SHARED
 #else
 
-#include <zlib.h>
+# include <zlib.h>
 
 static int zlib_stateful_init(COMP_CTX *ctx);
 static void zlib_stateful_finish(COMP_CTX *ctx);
-static int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
-       unsigned int olen, unsigned char *in, unsigned int ilen);
-static int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
-       unsigned int olen, unsigned char *in, unsigned int ilen);
-
-#if 0
-static int zlib_compress_block(COMP_CTX *ctx, unsigned char *out,
-       unsigned int olen, unsigned char *in, unsigned int ilen);
-static int zlib_expand_block(COMP_CTX *ctx, unsigned char *out,
-       unsigned int olen, unsigned char *in, unsigned int ilen);
-
-static int zz_uncompress(Bytef *dest, uLongf *destLen, const Bytef *source,
-       uLong sourceLen);
-
-static COMP_METHOD zlib_stateless_method={
-       NID_zlib_compression,
-       LN_zlib_compression,
-       NULL,
-       NULL,
-       zlib_compress_block,
-       zlib_expand_block,
-       NULL,
-       NULL,
-       };
-#endif
+static ossl_ssize_t zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
+                                                 size_t olen, unsigned char *in,
+                                                 size_t ilen);
+static ossl_ssize_t zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
+                                               size_t olen, unsigned char *in,
+                                               size_t ilen);
+
+/* memory allocations functions for zlib initialisation */
+static void *zlib_zalloc(void *opaque, unsigned int no, unsigned int size)
+{
+    void *p;
+
+    p = OPENSSL_zalloc(no * size);
+    return p;
+}
 
-static COMP_METHOD zlib_stateful_method={
-       NID_zlib_compression,
-       LN_zlib_compression,
-       zlib_stateful_init,
-       zlib_stateful_finish,
-       zlib_stateful_compress_block,
-       zlib_stateful_expand_block,
-       NULL,
-       NULL,
-       };
-
-/* 
+static void zlib_zfree(void *opaque, void *address)
+{
+    OPENSSL_free(address);
+}
+
+
+static COMP_METHOD zlib_stateful_method = {
+    NID_zlib_compression,
+    LN_zlib_compression,
+    zlib_stateful_init,
+    zlib_stateful_finish,
+    zlib_stateful_compress_block,
+    zlib_stateful_expand_block
+};
+
+/*
  * When OpenSSL is built on Windows, we do not want to require that
  * the ZLIB.DLL be available in order for the OpenSSL DLLs to
  * work.  Therefore, all ZLIB routines are loaded at run time
- * and we do not link to a .LIB file.
+ * and we do not link to a .LIB file when ZLIB_SHARED is set.
  */
-#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
-# include <windows.h>
+# if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
+#  include <windows.h>
+# endif                         /* !(OPENSSL_SYS_WINDOWS ||
+                                 * OPENSSL_SYS_WIN32) */
 
-# define Z_CALLCONV _stdcall
-# ifndef ZLIB_SHARED
-#  define ZLIB_SHARED
-# endif
-#else
-# define Z_CALLCONV
-#endif /* !(OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32) */
-
-#ifdef ZLIB_SHARED
-#include <openssl/dso.h>
-
-/* Prototypes for built in stubs */
-#if 0
-static int stub_compress(Bytef *dest,uLongf *destLen,
-       const Bytef *source, uLong sourceLen);
-#endif
-static int stub_inflateEnd(z_streamp strm);
-static int stub_inflate(z_streamp strm, int flush);
-static int stub_inflateInit_(z_streamp strm, const char * version,
-       int stream_size);
-static int stub_deflateEnd(z_streamp strm);
-static int stub_deflate(z_streamp strm, int flush);
-static int stub_deflateInit_(z_streamp strm, int level,
-       const char * version, int stream_size);
+# ifdef ZLIB_SHARED
+#  include "internal/dso.h"
 
 /* Function pointers */
-typedef int (Z_CALLCONV *compress_ft)(Bytef *dest,uLongf *destLen,
-       const Bytef *source, uLong sourceLen);
-typedef int (Z_CALLCONV *inflateEnd_ft)(z_streamp strm);
-typedef int (Z_CALLCONV *inflate_ft)(z_streamp strm, int flush);
-typedef int (Z_CALLCONV *inflateInit__ft)(z_streamp strm,
-       const char * version, int stream_size);
-typedef int (Z_CALLCONV *deflateEnd_ft)(z_streamp strm);
-typedef int (Z_CALLCONV *deflate_ft)(z_streamp strm, int flush);
-typedef int (Z_CALLCONV *deflateInit__ft)(z_streamp strm, int level,
-       const char * version, int stream_size);
-static compress_ft     p_compress=NULL;
-static inflateEnd_ft   p_inflateEnd=NULL;
-static inflate_ft      p_inflate=NULL;
-static inflateInit__ft p_inflateInit_=NULL;
-static deflateEnd_ft   p_deflateEnd=NULL;
-static deflate_ft      p_deflate=NULL;
-static deflateInit__ft p_deflateInit_=NULL;
-
-static int zlib_loaded = 0;     /* only attempt to init func pts once */
+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,
+                                const char *version, int stream_size);
+typedef int (*deflateEnd_ft) (z_streamp strm);
+typedef int (*deflate_ft) (z_streamp strm, int flush);
+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;
+static deflateEnd_ft p_deflateEnd = NULL;
+static deflate_ft p_deflate = NULL;
+static deflateInit__ft p_deflateInit_ = NULL;
+static zError__ft p_zError = NULL;
+
 static DSO *zlib_dso = NULL;
 
-#define compress                stub_compress
-#define inflateEnd              stub_inflateEnd
-#define inflate                 stub_inflate
-#define inflateInit_            stub_inflateInit_
-#define deflateEnd              stub_deflateEnd
-#define deflate                 stub_deflate
-#define deflateInit_            stub_deflateInit_
-#endif /* ZLIB_SHARED */
-
-struct zlib_state
-       {
-       z_stream istream;
-       z_stream ostream;
-       };
-
-static int zlib_stateful_ex_idx = -1;
-
-static void zlib_stateful_free_ex_data(void *obj, void *item,
-       CRYPTO_EX_DATA *ad, int ind,long argl, void *argp)
-       {
-       struct zlib_state *state = (struct zlib_state *)item;
-       inflateEnd(&state->istream);
-       deflateEnd(&state->ostream);
-       OPENSSL_free(state);
-       }
+#  define compress                p_compress
+#  define uncompress              p_uncompress
+#  define inflateEnd              p_inflateEnd
+#  define inflate                 p_inflate
+#  define inflateInit_            p_inflateInit_
+#  define deflateEnd              p_deflateEnd
+#  define deflate                 p_deflate
+#  define deflateInit_            p_deflateInit_
+#  define zError                  p_zError
+# endif                         /* ZLIB_SHARED */
+
+struct zlib_state {
+    z_stream istream;
+    z_stream ostream;
+};
 
 static int zlib_stateful_init(COMP_CTX *ctx)
-       {
-       int err;
-       struct zlib_state *state =
-               (struct zlib_state *)OPENSSL_malloc(sizeof(struct zlib_state));
-
-       if (state == NULL)
-               goto err;
-
-       state->istream.zalloc = Z_NULL;
-       state->istream.zfree = Z_NULL;
-       state->istream.opaque = Z_NULL;
-       state->istream.next_in = Z_NULL;
-       state->istream.next_out = Z_NULL;
-       state->istream.avail_in = 0;
-       state->istream.avail_out = 0;
-       err = inflateInit_(&state->istream,
-               ZLIB_VERSION, sizeof(z_stream));
-       if (err != Z_OK)
-               goto err;
-
-       state->ostream.zalloc = Z_NULL;
-       state->ostream.zfree = Z_NULL;
-       state->ostream.opaque = Z_NULL;
-       state->ostream.next_in = Z_NULL;
-       state->ostream.next_out = Z_NULL;
-       state->ostream.avail_in = 0;
-       state->ostream.avail_out = 0;
-       err = deflateInit_(&state->ostream,Z_DEFAULT_COMPRESSION,
-               ZLIB_VERSION, sizeof(z_stream));
-       if (err != Z_OK)
-               goto err;
-
-       CRYPTO_new_ex_data(CRYPTO_EX_INDEX_COMP,ctx,&ctx->ex_data);
-       if (zlib_stateful_ex_idx == -1)
-               {
-               CRYPTO_w_lock(CRYPTO_LOCK_COMP);
-               if (zlib_stateful_ex_idx == -1)
-                       zlib_stateful_ex_idx =
-                               CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_COMP,
-                                       0,NULL,NULL,NULL,zlib_stateful_free_ex_data);
-               CRYPTO_w_unlock(CRYPTO_LOCK_COMP);
-               if (zlib_stateful_ex_idx == -1)
-                       goto err;
-               }
-       CRYPTO_set_ex_data(&ctx->ex_data,zlib_stateful_ex_idx,state);
-       return 1;
+{
+    int err;
+    struct zlib_state *state = OPENSSL_zalloc(sizeof(*state));
+
+    if (state == NULL)
+        goto err;
+
+    state->istream.zalloc = zlib_zalloc;
+    state->istream.zfree = zlib_zfree;
+    state->istream.opaque = Z_NULL;
+    state->istream.next_in = Z_NULL;
+    state->istream.next_out = Z_NULL;
+    err = inflateInit_(&state->istream, ZLIB_VERSION, sizeof(z_stream));
+    if (err != Z_OK)
+        goto err;
+
+    state->ostream.zalloc = zlib_zalloc;
+    state->ostream.zfree = zlib_zfree;
+    state->ostream.opaque = Z_NULL;
+    state->ostream.next_in = Z_NULL;
+    state->ostream.next_out = Z_NULL;
+    err = deflateInit_(&state->ostream, Z_DEFAULT_COMPRESSION,
+                       ZLIB_VERSION, sizeof(z_stream));
+    if (err != Z_OK)
+        goto err;
+
+    ctx->data = state;
+    return 1;
  err:
-       if (state) OPENSSL_free(state);
-       return 0;
-       }
+    OPENSSL_free(state);
+    return 0;
+}
 
 static void zlib_stateful_finish(COMP_CTX *ctx)
-       {
-       CRYPTO_free_ex_data(CRYPTO_EX_INDEX_COMP,ctx,&ctx->ex_data);
-       }
-
-static int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
-       unsigned int olen, unsigned char *in, unsigned int ilen)
-       {
-       int err = Z_OK;
-       struct zlib_state *state =
-               (struct zlib_state *)CRYPTO_get_ex_data(&ctx->ex_data,
-                       zlib_stateful_ex_idx);
-
-       if (state == NULL)
-               return -1;
-
-       state->ostream.next_in = in;
-       state->ostream.avail_in = ilen;
-       state->ostream.next_out = out;
-       state->ostream.avail_out = olen;
-       if (ilen > 0)
-               err = deflate(&state->ostream, Z_SYNC_FLUSH);
-       if (err != Z_OK)
-               return -1;
-#ifdef DEBUG_ZLIB
-       fprintf(stderr,"compress(%4d)->%4d %s\n",
-               ilen,olen - state->ostream.avail_out,
-               (ilen != olen - state->ostream.avail_out)?"zlib":"clear");
-#endif
-       return olen - state->ostream.avail_out;
-       }
-
-static int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
-       unsigned int olen, unsigned char *in, unsigned int ilen)
-       {
-       int err = Z_OK;
-
-       struct zlib_state *state =
-               (struct zlib_state *)CRYPTO_get_ex_data(&ctx->ex_data,
-                       zlib_stateful_ex_idx);
-
-       if (state == NULL)
-               return 0;
-
-       state->istream.next_in = in;
-       state->istream.avail_in = ilen;
-       state->istream.next_out = out;
-       state->istream.avail_out = olen;
-       if (ilen > 0)
-               err = inflate(&state->istream, Z_SYNC_FLUSH);
-       if (err != Z_OK)
-               return -1;
-#ifdef DEBUG_ZLIB
-       fprintf(stderr,"expand(%4d)->%4d %s\n",
-               ilen,olen - state->istream.avail_out,
-               (ilen != olen - state->istream.avail_out)?"zlib":"clear");
-#endif
-       return olen - state->istream.avail_out;
-       }
-
-#if 0
-static int zlib_compress_block(COMP_CTX *ctx, unsigned char *out,
-       unsigned int olen, unsigned char *in, unsigned int ilen)
-       {
-       unsigned long l;
-       int i;
-       int clear=1;
-
-       if (ilen > 128)
-               {
-               out[0]=1;
-               l=olen-1;
-               i=compress(&(out[1]),&l,in,(unsigned long)ilen);
-               if (i != Z_OK)
-                       return(-1);
-               if (ilen > l)
-                       {
-                       clear=0;
-                       l++;
-                       }
-               }
-       if (clear)
-               {
-               out[0]=0;
-               memcpy(&(out[1]),in,ilen);
-               l=ilen+1;
-               }
-#ifdef DEBUG_ZLIB
-       fprintf(stderr,"compress(%4d)->%4d %s\n",
-               ilen,(int)l,(clear)?"clear":"zlib");
-#endif
-       return((int)l);
-       }
-
-static int zlib_expand_block(COMP_CTX *ctx, unsigned char *out,
-       unsigned int olen, unsigned char *in, unsigned int ilen)
-       {
-       unsigned long l;
-       int i;
-
-       if (in[0])
-               {
-               l=olen;
-               i=zz_uncompress(out,&l,&(in[1]),(unsigned long)ilen-1);
-               if (i != Z_OK)
-                       return(-1);
-               }
-       else
-               {
-               memcpy(out,&(in[1]),ilen-1);
-               l=ilen-1;
-               }
-#ifdef DEBUG_ZLIB
-        fprintf(stderr,"expand  (%4d)->%4d %s\n",
-               ilen,(int)l,in[0]?"zlib":"clear");
-#endif
-       return((int)l);
-       }
+{
+    struct zlib_state *state = ctx->data;
+    inflateEnd(&state->istream);
+    deflateEnd(&state->ostream);
+    OPENSSL_free(state);
+}
 
-static int zz_uncompress (Bytef *dest, uLongf *destLen, const Bytef *source,
-            uLong sourceLen)
+static ossl_ssize_t zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
+                                                 size_t olen, unsigned char *in,
+                                                 size_t ilen)
 {
-    z_stream stream;
-    int err;
+    int err = Z_OK;
+    struct zlib_state *state = ctx->data;
+
+    if (state == NULL)
+        return -1;
+
+    state->ostream.next_in = in;
+    state->ostream.avail_in = ilen;
+    state->ostream.next_out = out;
+    state->ostream.avail_out = olen;
+    if (ilen > 0)
+        err = deflate(&state->ostream, Z_SYNC_FLUSH);
+    if (err != Z_OK)
+        return -1;
+    if (state->ostream.avail_out > olen)
+        return -1;
+    return (ossl_ssize_t)(olen - state->ostream.avail_out);
+}
+
+static ossl_ssize_t zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
+                                               size_t olen, unsigned char *in,
+                                               size_t ilen)
+{
+    int err = Z_OK;
+    struct zlib_state *state = ctx->data;
+
+    if (state == NULL)
+        return 0;
+
+    state->istream.next_in = in;
+    state->istream.avail_in = ilen;
+    state->istream.next_out = out;
+    state->istream.avail_out = olen;
+    if (ilen > 0)
+        err = inflate(&state->istream, Z_SYNC_FLUSH);
+    if (err != Z_OK)
+        return -1;
+    if (state->istream.avail_out > olen)
+        return -1;
+    return (ossl_ssize_t)(olen - state->istream.avail_out);
+}
+
+/* ONESHOT COMPRESSION/DECOMPRESSION */
 
-    stream.next_in = (Bytef*)source;
-    stream.avail_in = (uInt)sourceLen;
-    /* Check for source > 64K on 16-bit machine: */
-    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+static int zlib_oneshot_init(COMP_CTX *ctx)
+{
+    return 1;
+}
 
-    stream.next_out = dest;
-    stream.avail_out = (uInt)*destLen;
-    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+static void zlib_oneshot_finish(COMP_CTX *ctx)
+{
+}
 
-    stream.zalloc = (alloc_func)0;
-    stream.zfree = (free_func)0;
+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;
 
-    err = inflateInit_(&stream,
-           ZLIB_VERSION, sizeof(z_stream));
-    if (err != Z_OK) return err;
+    if (ilen == 0)
+        return 0;
 
-    err = inflate(&stream, Z_FINISH);
-    if (err != Z_STREAM_END) {
-        inflateEnd(&stream);
-        return err;
-    }
-    *destLen = stream.total_out;
+    /* 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;
 
-    err = inflateEnd(&stream);
-    return err;
+    if (out_size > OSSL_SSIZE_MAX)
+        return -1;
+    return (ossl_ssize_t)out_size;
 }
-#endif
 
+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)
+{
+# ifdef ZLIB_SHARED
+    /* LIBZ may be externally defined, and we should respect that value */
+#  ifndef LIBZ
+#   if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
+#    define LIBZ "ZLIB1"
+#   elif defined(OPENSSL_SYS_VMS)
+#    define LIBZ "LIBZ"
+#   else
+#    define LIBZ "z"
+#   endif
+#  endif
+
+    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_");
+        p_deflateEnd = (deflateEnd_ft) DSO_bind_func(zlib_dso, "deflateEnd");
+        p_deflate = (deflate_ft) DSO_bind_func(zlib_dso, "deflate");
+        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_uncompress == NULL || p_inflateEnd == NULL
+                || p_inflate == NULL || p_inflateInit_ == NULL
+                || p_deflateEnd == NULL || p_deflate == NULL
+                || p_deflateInit_ == NULL || p_zError == NULL) {
+            ossl_comp_zlib_cleanup();
+            return 0;
+        }
+    }
+# endif
+    return 1;
+}
 #endif
 
 COMP_METHOD *COMP_zlib(void)
-       {
-       COMP_METHOD *meth = &zlib_method_nozlib;
+{
+    COMP_METHOD *meth = NULL;
 
-#ifdef ZLIB_SHARED
-       if (!zlib_loaded)
-               {
-#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
-               zlib_dso = DSO_load(NULL, "ZLIB1", NULL, 0);
-               if (!zlib_dso)
-                       {
-                       zlib_dso = DSO_load(NULL, "ZLIB", NULL, 0);
-                       if (zlib_dso)
-                               {
-                               /* Clear the errors from the first failed
-                                  DSO_load() */
-                               ERR_clear_error();
-                               }
-                       }
-#else
-               zlib_dso = DSO_load(NULL, "z", NULL, 0);
+#ifndef OPENSSL_NO_ZLIB
+    if (RUN_ONCE(&zlib_once, ossl_comp_zlib_init))
+        meth = &zlib_stateful_method;
 #endif
-               if (zlib_dso != NULL)
-                       {
-                       p_compress
-                               = (compress_ft) DSO_bind_func(zlib_dso,
-                                       "compress");
-                       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_");
-                       p_deflateEnd
-                               = (deflateEnd_ft) DSO_bind_func(zlib_dso,
-                                       "deflateEnd");
-                       p_deflate
-                               = (deflate_ft) DSO_bind_func(zlib_dso,
-                                       "deflate");
-                       p_deflateInit_
-                               = (deflateInit__ft) DSO_bind_func(zlib_dso,
-                                       "deflateInit_");
-
-                       if (p_compress && p_inflateEnd && p_inflate
-                               && p_inflateInit_ && p_deflateEnd
-                               && p_deflate && p_deflateInit_)
-                               zlib_loaded++;
-                       }
-               }
 
-#endif
-#if defined(ZLIB) || defined(ZLIB_SHARED)
-       if (zlib_loaded)
-               meth = &zlib_stateful_method;
+    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);
-       }
+    return meth;
+}
 
+/* Also called from OPENSSL_cleanup() */
+void ossl_comp_zlib_cleanup(void)
+{
 #ifdef ZLIB_SHARED
-#if 0
-/* Stubs for each function to be dynamicly loaded */
-static int 
-stub_compress(Bytef *dest,uLongf *destLen,const Bytef *source, uLong sourceLen)
-       {
-       if (p_compress)
-               return(p_compress(dest,destLen,source,sourceLen));
-       else
-               return(Z_MEM_ERROR);
-       }
+    DSO_free(zlib_dso);
+    zlib_dso = NULL;
 #endif
+}
+
+#ifndef OPENSSL_NO_ZLIB
+
+/* Zlib based compression/decompression filter BIO */
+
+typedef struct {
+    unsigned char *ibuf;        /* Input buffer */
+    int ibufsize;               /* Buffer size */
+    z_stream zin;               /* Input decompress context */
+    unsigned char *obuf;        /* Output buffer */
+    int obufsize;               /* Output buffer size */
+    unsigned char *optr;        /* Position in output buffer */
+    int ocount;                 /* Amount of data in output buffer */
+    int odone;                  /* deflate EOF */
+    int comp_level;             /* Compression level to use */
+    z_stream zout;              /* Output compression context */
+} BIO_ZLIB_CTX;
+
+# define ZLIB_DEFAULT_BUFSIZE 1024
+
+static int bio_zlib_new(BIO *bi);
+static int bio_zlib_free(BIO *bi);
+static int bio_zlib_read(BIO *b, char *out, int outl);
+static int bio_zlib_write(BIO *b, const char *in, int inl);
+static long bio_zlib_ctrl(BIO *b, int cmd, long num, void *ptr);
+static long bio_zlib_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp);
+
+static const BIO_METHOD bio_meth_zlib = {
+    BIO_TYPE_COMP,
+    "zlib",
+    bwrite_conv,
+    bio_zlib_write,
+    bread_conv,
+    bio_zlib_read,
+    NULL,                      /* bio_zlib_puts, */
+    NULL,                      /* bio_zlib_gets, */
+    bio_zlib_ctrl,
+    bio_zlib_new,
+    bio_zlib_free,
+    bio_zlib_callback_ctrl
+};
+#endif
+
+const BIO_METHOD *BIO_f_zlib(void)
+{
+#ifndef OPENSSL_NO_ZLIB
+    if (RUN_ONCE(&zlib_once, ossl_comp_zlib_init))
+        return &bio_meth_zlib;
+#endif
+    return NULL;
+}
+
+#ifndef OPENSSL_NO_ZLIB
+static int bio_zlib_new(BIO *bi)
+{
+    BIO_ZLIB_CTX *ctx;
+
+# ifdef ZLIB_SHARED
+    if (!RUN_ONCE(&zlib_once, ossl_comp_zlib_init)) {
+        ERR_raise(ERR_LIB_COMP, COMP_R_ZLIB_NOT_SUPPORTED);
+        return 0;
+    }
+# endif
+    ctx = OPENSSL_zalloc(sizeof(*ctx));
+    if (ctx == NULL)
+        return 0;
+    ctx->ibufsize = ZLIB_DEFAULT_BUFSIZE;
+    ctx->obufsize = ZLIB_DEFAULT_BUFSIZE;
+    ctx->zin.zalloc = Z_NULL;
+    ctx->zin.zfree = Z_NULL;
+    ctx->zout.zalloc = Z_NULL;
+    ctx->zout.zfree = Z_NULL;
+    ctx->comp_level = Z_DEFAULT_COMPRESSION;
+    BIO_set_init(bi, 1);
+    BIO_set_data(bi, ctx);
+
+    return 1;
+}
+
+static int bio_zlib_free(BIO *bi)
+{
+    BIO_ZLIB_CTX *ctx;
+
+    if (!bi)
+        return 0;
+    ctx = BIO_get_data(bi);
+    if (ctx->ibuf) {
+        /* Destroy decompress context */
+        inflateEnd(&ctx->zin);
+        OPENSSL_free(ctx->ibuf);
+    }
+    if (ctx->obuf) {
+        /* Destroy compress context */
+        deflateEnd(&ctx->zout);
+        OPENSSL_free(ctx->obuf);
+    }
+    OPENSSL_free(ctx);
+    BIO_set_data(bi, NULL);
+    BIO_set_init(bi, 0);
+
+    return 1;
+}
+
+static int bio_zlib_read(BIO *b, char *out, int outl)
+{
+    BIO_ZLIB_CTX *ctx;
+    int ret;
+    z_stream *zin;
+    BIO *next = BIO_next(b);
+
+    if (!out || !outl)
+        return 0;
+    ctx = BIO_get_data(b);
+    zin = &ctx->zin;
+    BIO_clear_retry_flags(b);
+    if (!ctx->ibuf) {
+        ctx->ibuf = OPENSSL_malloc(ctx->ibufsize);
+        if (ctx->ibuf == NULL)
+            return 0;
+        if ((ret = inflateInit(zin)) != Z_OK) {
+            ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_INFLATE_ERROR,
+                           "zlib error: %s", zError(ret));
+            return 0;
+        }
+        zin->next_in = ctx->ibuf;
+        zin->avail_in = 0;
+    }
+
+    /* Copy output data directly to supplied buffer */
+    zin->next_out = (unsigned char *)out;
+    zin->avail_out = (unsigned int)outl;
+    for (;;) {
+        /* Decompress while data available */
+        while (zin->avail_in) {
+            ret = inflate(zin, 0);
+            if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
+                ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_INFLATE_ERROR,
+                               "zlib error: %s", zError(ret));
+                return 0;
+            }
+            /* If EOF or we've read everything then return */
+            if ((ret == Z_STREAM_END) || !zin->avail_out)
+                return outl - zin->avail_out;
+        }
+
+        /*
+         * No data in input buffer try to read some in, if an error then
+         * return the total data read.
+         */
+        ret = BIO_read(next, ctx->ibuf, ctx->ibufsize);
+        if (ret <= 0) {
+            /* Total data read */
+            int tot = outl - zin->avail_out;
+            BIO_copy_next_retry(b);
+            if (ret < 0)
+                return (tot > 0) ? tot : ret;
+            return tot;
+        }
+        zin->avail_in = ret;
+        zin->next_in = ctx->ibuf;
+    }
+}
 
-static int
-stub_inflateEnd(z_streamp strm)
-       {
-       if ( p_inflateEnd )
-               return(p_inflateEnd(strm));
-       else
-               return(Z_MEM_ERROR);
-       }
-
-static int
-stub_inflate(z_streamp strm, int flush)
-       {
-       if ( p_inflate )
-               return(p_inflate(strm,flush));
-       else
-               return(Z_MEM_ERROR);
-       }
-
-static int
-stub_inflateInit_(z_streamp strm, const char * version, int stream_size)
-       {
-       if ( p_inflateInit_ )
-               return(p_inflateInit_(strm,version,stream_size));
-       else
-               return(Z_MEM_ERROR);
-       }
-
-static int
-stub_deflateEnd(z_streamp strm)
-       {
-       if ( p_deflateEnd )
-               return(p_deflateEnd(strm));
-       else
-               return(Z_MEM_ERROR);
-       }
-
-static int
-stub_deflate(z_streamp strm, int flush)
-       {
-       if ( p_deflate )
-               return(p_deflate(strm,flush));
-       else
-               return(Z_MEM_ERROR);
-       }
-
-static int
-stub_deflateInit_(z_streamp strm, int level,
-       const char * version, int stream_size)
-       {
-       if ( p_deflateInit_ )
-               return(p_deflateInit_(strm,level,version,stream_size));
-       else
-               return(Z_MEM_ERROR);
-       }
-
-#endif /* ZLIB_SHARED */
+static int bio_zlib_write(BIO *b, const char *in, int inl)
+{
+    BIO_ZLIB_CTX *ctx;
+    int ret;
+    z_stream *zout;
+    BIO *next = BIO_next(b);
+
+    if (!in || !inl)
+        return 0;
+    ctx = BIO_get_data(b);
+    if (ctx->odone)
+        return 0;
+    zout = &ctx->zout;
+    BIO_clear_retry_flags(b);
+    if (!ctx->obuf) {
+        ctx->obuf = OPENSSL_malloc(ctx->obufsize);
+        /* Need error here */
+        if (ctx->obuf == NULL)
+            return 0;
+        ctx->optr = ctx->obuf;
+        ctx->ocount = 0;
+        if ((ret = deflateInit(zout, ctx->comp_level)) != Z_OK) {
+            ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_DEFLATE_ERROR,
+                           "zlib error: %s", zError(ret));
+            return 0;
+        }
+        zout->next_out = ctx->obuf;
+        zout->avail_out = ctx->obufsize;
+    }
+    /* Obtain input data directly from supplied buffer */
+    zout->next_in = (void *)in;
+    zout->avail_in = inl;
+    for (;;) {
+        /* If data in output buffer write it first */
+        while (ctx->ocount) {
+            ret = BIO_write(next, ctx->optr, ctx->ocount);
+            if (ret <= 0) {
+                /* Total data written */
+                int tot = inl - zout->avail_in;
+                BIO_copy_next_retry(b);
+                if (ret < 0)
+                    return (tot > 0) ? tot : ret;
+                return tot;
+            }
+            ctx->optr += ret;
+            ctx->ocount -= ret;
+        }
+
+        /* Have we consumed all supplied data? */
+        if (!zout->avail_in)
+            return inl;
+
+        /* Compress some more */
+
+        /* Reset buffer */
+        ctx->optr = ctx->obuf;
+        zout->next_out = ctx->obuf;
+        zout->avail_out = ctx->obufsize;
+        /* Compress some more */
+        ret = deflate(zout, 0);
+        if (ret != Z_OK) {
+            ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_DEFLATE_ERROR,
+                           "zlib error: %s", zError(ret));
+            return 0;
+        }
+        ctx->ocount = ctx->obufsize - zout->avail_out;
+    }
+}
+
+static int bio_zlib_flush(BIO *b)
+{
+    BIO_ZLIB_CTX *ctx;
+    int ret;
+    z_stream *zout;
+    BIO *next = BIO_next(b);
+
+    ctx = BIO_get_data(b);
+    /* If no data written or already flush show success */
+    if (!ctx->obuf || (ctx->odone && !ctx->ocount))
+        return 1;
+    zout = &ctx->zout;
+    BIO_clear_retry_flags(b);
+    /* No more input data */
+    zout->next_in = NULL;
+    zout->avail_in = 0;
+    for (;;) {
+        /* If data in output buffer write it first */
+        while (ctx->ocount) {
+            ret = BIO_write(next, ctx->optr, ctx->ocount);
+            if (ret <= 0) {
+                BIO_copy_next_retry(b);
+                return ret;
+            }
+            ctx->optr += ret;
+            ctx->ocount -= ret;
+        }
+        if (ctx->odone)
+            return 1;
+
+        /* Compress some more */
+
+        /* Reset buffer */
+        ctx->optr = ctx->obuf;
+        zout->next_out = ctx->obuf;
+        zout->avail_out = ctx->obufsize;
+        /* Compress some more */
+        ret = deflate(zout, Z_FINISH);
+        if (ret == Z_STREAM_END)
+            ctx->odone = 1;
+        else if (ret != Z_OK) {
+            ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_DEFLATE_ERROR,
+                           "zlib error: %s", zError(ret));
+            return 0;
+        }
+        ctx->ocount = ctx->obufsize - zout->avail_out;
+    }
+}
+
+static long bio_zlib_ctrl(BIO *b, int cmd, long num, void *ptr)
+{
+    BIO_ZLIB_CTX *ctx;
+    int ret, *ip;
+    int ibs, obs;
+    BIO *next = BIO_next(b);
+
+    if (next == NULL)
+        return 0;
+    ctx = BIO_get_data(b);
+    switch (cmd) {
+
+    case BIO_CTRL_RESET:
+        ctx->ocount = 0;
+        ctx->odone = 0;
+        ret = 1;
+        break;
+
+    case BIO_CTRL_FLUSH:
+        ret = bio_zlib_flush(b);
+        if (ret > 0) {
+            ret = BIO_flush(next);
+            BIO_copy_next_retry(b);
+        }
+        break;
+
+    case BIO_C_SET_BUFF_SIZE:
+        ibs = -1;
+        obs = -1;
+        if (ptr != NULL) {
+            ip = ptr;
+            if (*ip == 0)
+                ibs = (int)num;
+            else
+                obs = (int)num;
+        } else {
+            ibs = (int)num;
+            obs = ibs;
+        }
+
+        if (ibs != -1) {
+            OPENSSL_free(ctx->ibuf);
+            ctx->ibuf = NULL;
+            ctx->ibufsize = ibs;
+        }
+
+        if (obs != -1) {
+            OPENSSL_free(ctx->obuf);
+            ctx->obuf = NULL;
+            ctx->obufsize = 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 (ctx->obuf == NULL)
+            return 0;
+
+        if (ctx->odone) {
+            ret = ctx->ocount;
+        } else {
+            ret = ctx->ocount;
+            if (ret == 0)
+                /* Unknown amount pending but we are not finished */
+                ret = 1;
+        }
+        if (ret == 0)
+            ret = BIO_ctrl(next, cmd, num, ptr);
+        break;
+
+    case BIO_CTRL_PENDING:
+        ret = ctx->zin.avail_in;
+        if (ret == 0)
+            ret = BIO_ctrl(next, cmd, num, ptr);
+        break;
+
+    default:
+        ret = BIO_ctrl(next, cmd, num, ptr);
+        break;
+
+    }
+
+    return ret;
+}
+
+static long bio_zlib_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