1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1998-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci#include <stdio.h>
11e1051a39Sopenharmony_ci#include <stdlib.h>
12e1051a39Sopenharmony_ci#include <string.h>
13e1051a39Sopenharmony_ci#include <openssl/objects.h>
14e1051a39Sopenharmony_ci#include "internal/comp.h"
15e1051a39Sopenharmony_ci#include <openssl/err.h>
16e1051a39Sopenharmony_ci#include "crypto/cryptlib.h"
17e1051a39Sopenharmony_ci#include "internal/bio.h"
18e1051a39Sopenharmony_ci#include "internal/thread_once.h"
19e1051a39Sopenharmony_ci#include "comp_local.h"
20e1051a39Sopenharmony_ci
21e1051a39Sopenharmony_ciCOMP_METHOD *COMP_zlib(void);
22e1051a39Sopenharmony_ci
23e1051a39Sopenharmony_cistatic COMP_METHOD zlib_method_nozlib = {
24e1051a39Sopenharmony_ci    NID_undef,
25e1051a39Sopenharmony_ci    "(undef)",
26e1051a39Sopenharmony_ci    NULL,
27e1051a39Sopenharmony_ci    NULL,
28e1051a39Sopenharmony_ci    NULL,
29e1051a39Sopenharmony_ci    NULL,
30e1051a39Sopenharmony_ci};
31e1051a39Sopenharmony_ci
32e1051a39Sopenharmony_ci#ifndef ZLIB
33e1051a39Sopenharmony_ci# undef ZLIB_SHARED
34e1051a39Sopenharmony_ci#else
35e1051a39Sopenharmony_ci
36e1051a39Sopenharmony_ci# include <zlib.h>
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_cistatic int zlib_stateful_init(COMP_CTX *ctx);
39e1051a39Sopenharmony_cistatic void zlib_stateful_finish(COMP_CTX *ctx);
40e1051a39Sopenharmony_cistatic int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
41e1051a39Sopenharmony_ci                                        unsigned int olen, unsigned char *in,
42e1051a39Sopenharmony_ci                                        unsigned int ilen);
43e1051a39Sopenharmony_cistatic int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
44e1051a39Sopenharmony_ci                                      unsigned int olen, unsigned char *in,
45e1051a39Sopenharmony_ci                                      unsigned int ilen);
46e1051a39Sopenharmony_ci
47e1051a39Sopenharmony_ci/* memory allocations functions for zlib initialisation */
48e1051a39Sopenharmony_cistatic void *zlib_zalloc(void *opaque, unsigned int no, unsigned int size)
49e1051a39Sopenharmony_ci{
50e1051a39Sopenharmony_ci    void *p;
51e1051a39Sopenharmony_ci
52e1051a39Sopenharmony_ci    p = OPENSSL_zalloc(no * size);
53e1051a39Sopenharmony_ci    return p;
54e1051a39Sopenharmony_ci}
55e1051a39Sopenharmony_ci
56e1051a39Sopenharmony_cistatic void zlib_zfree(void *opaque, void *address)
57e1051a39Sopenharmony_ci{
58e1051a39Sopenharmony_ci    OPENSSL_free(address);
59e1051a39Sopenharmony_ci}
60e1051a39Sopenharmony_ci
61e1051a39Sopenharmony_ci
62e1051a39Sopenharmony_cistatic COMP_METHOD zlib_stateful_method = {
63e1051a39Sopenharmony_ci    NID_zlib_compression,
64e1051a39Sopenharmony_ci    LN_zlib_compression,
65e1051a39Sopenharmony_ci    zlib_stateful_init,
66e1051a39Sopenharmony_ci    zlib_stateful_finish,
67e1051a39Sopenharmony_ci    zlib_stateful_compress_block,
68e1051a39Sopenharmony_ci    zlib_stateful_expand_block
69e1051a39Sopenharmony_ci};
70e1051a39Sopenharmony_ci
71e1051a39Sopenharmony_ci/*
72e1051a39Sopenharmony_ci * When OpenSSL is built on Windows, we do not want to require that
73e1051a39Sopenharmony_ci * the ZLIB.DLL be available in order for the OpenSSL DLLs to
74e1051a39Sopenharmony_ci * work.  Therefore, all ZLIB routines are loaded at run time
75e1051a39Sopenharmony_ci * and we do not link to a .LIB file when ZLIB_SHARED is set.
76e1051a39Sopenharmony_ci */
77e1051a39Sopenharmony_ci# if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
78e1051a39Sopenharmony_ci#  include <windows.h>
79e1051a39Sopenharmony_ci# endif                         /* !(OPENSSL_SYS_WINDOWS ||
80e1051a39Sopenharmony_ci                                 * OPENSSL_SYS_WIN32) */
81e1051a39Sopenharmony_ci
82e1051a39Sopenharmony_ci# ifdef ZLIB_SHARED
83e1051a39Sopenharmony_ci#  include "internal/dso.h"
84e1051a39Sopenharmony_ci
85e1051a39Sopenharmony_ci/* Function pointers */
86e1051a39Sopenharmony_citypedef int (*compress_ft) (Bytef *dest, uLongf * destLen,
87e1051a39Sopenharmony_ci                            const Bytef *source, uLong sourceLen);
88e1051a39Sopenharmony_citypedef int (*inflateEnd_ft) (z_streamp strm);
89e1051a39Sopenharmony_citypedef int (*inflate_ft) (z_streamp strm, int flush);
90e1051a39Sopenharmony_citypedef int (*inflateInit__ft) (z_streamp strm,
91e1051a39Sopenharmony_ci                                const char *version, int stream_size);
92e1051a39Sopenharmony_citypedef int (*deflateEnd_ft) (z_streamp strm);
93e1051a39Sopenharmony_citypedef int (*deflate_ft) (z_streamp strm, int flush);
94e1051a39Sopenharmony_citypedef int (*deflateInit__ft) (z_streamp strm, int level,
95e1051a39Sopenharmony_ci                                const char *version, int stream_size);
96e1051a39Sopenharmony_citypedef const char *(*zError__ft) (int err);
97e1051a39Sopenharmony_cistatic compress_ft p_compress = NULL;
98e1051a39Sopenharmony_cistatic inflateEnd_ft p_inflateEnd = NULL;
99e1051a39Sopenharmony_cistatic inflate_ft p_inflate = NULL;
100e1051a39Sopenharmony_cistatic inflateInit__ft p_inflateInit_ = NULL;
101e1051a39Sopenharmony_cistatic deflateEnd_ft p_deflateEnd = NULL;
102e1051a39Sopenharmony_cistatic deflate_ft p_deflate = NULL;
103e1051a39Sopenharmony_cistatic deflateInit__ft p_deflateInit_ = NULL;
104e1051a39Sopenharmony_cistatic zError__ft p_zError = NULL;
105e1051a39Sopenharmony_ci
106e1051a39Sopenharmony_cistatic DSO *zlib_dso = NULL;
107e1051a39Sopenharmony_ci
108e1051a39Sopenharmony_ci#  define compress                p_compress
109e1051a39Sopenharmony_ci#  define inflateEnd              p_inflateEnd
110e1051a39Sopenharmony_ci#  define inflate                 p_inflate
111e1051a39Sopenharmony_ci#  define inflateInit_            p_inflateInit_
112e1051a39Sopenharmony_ci#  define deflateEnd              p_deflateEnd
113e1051a39Sopenharmony_ci#  define deflate                 p_deflate
114e1051a39Sopenharmony_ci#  define deflateInit_            p_deflateInit_
115e1051a39Sopenharmony_ci#  define zError                  p_zError
116e1051a39Sopenharmony_ci# endif                         /* ZLIB_SHARED */
117e1051a39Sopenharmony_ci
118e1051a39Sopenharmony_cistruct zlib_state {
119e1051a39Sopenharmony_ci    z_stream istream;
120e1051a39Sopenharmony_ci    z_stream ostream;
121e1051a39Sopenharmony_ci};
122e1051a39Sopenharmony_ci
123e1051a39Sopenharmony_cistatic int zlib_stateful_init(COMP_CTX *ctx)
124e1051a39Sopenharmony_ci{
125e1051a39Sopenharmony_ci    int err;
126e1051a39Sopenharmony_ci    struct zlib_state *state = OPENSSL_zalloc(sizeof(*state));
127e1051a39Sopenharmony_ci
128e1051a39Sopenharmony_ci    if (state == NULL)
129e1051a39Sopenharmony_ci        goto err;
130e1051a39Sopenharmony_ci
131e1051a39Sopenharmony_ci    state->istream.zalloc = zlib_zalloc;
132e1051a39Sopenharmony_ci    state->istream.zfree = zlib_zfree;
133e1051a39Sopenharmony_ci    state->istream.opaque = Z_NULL;
134e1051a39Sopenharmony_ci    state->istream.next_in = Z_NULL;
135e1051a39Sopenharmony_ci    state->istream.next_out = Z_NULL;
136e1051a39Sopenharmony_ci    err = inflateInit_(&state->istream, ZLIB_VERSION, sizeof(z_stream));
137e1051a39Sopenharmony_ci    if (err != Z_OK)
138e1051a39Sopenharmony_ci        goto err;
139e1051a39Sopenharmony_ci
140e1051a39Sopenharmony_ci    state->ostream.zalloc = zlib_zalloc;
141e1051a39Sopenharmony_ci    state->ostream.zfree = zlib_zfree;
142e1051a39Sopenharmony_ci    state->ostream.opaque = Z_NULL;
143e1051a39Sopenharmony_ci    state->ostream.next_in = Z_NULL;
144e1051a39Sopenharmony_ci    state->ostream.next_out = Z_NULL;
145e1051a39Sopenharmony_ci    err = deflateInit_(&state->ostream, Z_DEFAULT_COMPRESSION,
146e1051a39Sopenharmony_ci                       ZLIB_VERSION, sizeof(z_stream));
147e1051a39Sopenharmony_ci    if (err != Z_OK)
148e1051a39Sopenharmony_ci        goto err;
149e1051a39Sopenharmony_ci
150e1051a39Sopenharmony_ci    ctx->data = state;
151e1051a39Sopenharmony_ci    return 1;
152e1051a39Sopenharmony_ci err:
153e1051a39Sopenharmony_ci    OPENSSL_free(state);
154e1051a39Sopenharmony_ci    return 0;
155e1051a39Sopenharmony_ci}
156e1051a39Sopenharmony_ci
157e1051a39Sopenharmony_cistatic void zlib_stateful_finish(COMP_CTX *ctx)
158e1051a39Sopenharmony_ci{
159e1051a39Sopenharmony_ci    struct zlib_state *state = ctx->data;
160e1051a39Sopenharmony_ci    inflateEnd(&state->istream);
161e1051a39Sopenharmony_ci    deflateEnd(&state->ostream);
162e1051a39Sopenharmony_ci    OPENSSL_free(state);
163e1051a39Sopenharmony_ci}
164e1051a39Sopenharmony_ci
165e1051a39Sopenharmony_cistatic int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
166e1051a39Sopenharmony_ci                                        unsigned int olen, unsigned char *in,
167e1051a39Sopenharmony_ci                                        unsigned int ilen)
168e1051a39Sopenharmony_ci{
169e1051a39Sopenharmony_ci    int err = Z_OK;
170e1051a39Sopenharmony_ci    struct zlib_state *state = ctx->data;
171e1051a39Sopenharmony_ci
172e1051a39Sopenharmony_ci    if (state == NULL)
173e1051a39Sopenharmony_ci        return -1;
174e1051a39Sopenharmony_ci
175e1051a39Sopenharmony_ci    state->ostream.next_in = in;
176e1051a39Sopenharmony_ci    state->ostream.avail_in = ilen;
177e1051a39Sopenharmony_ci    state->ostream.next_out = out;
178e1051a39Sopenharmony_ci    state->ostream.avail_out = olen;
179e1051a39Sopenharmony_ci    if (ilen > 0)
180e1051a39Sopenharmony_ci        err = deflate(&state->ostream, Z_SYNC_FLUSH);
181e1051a39Sopenharmony_ci    if (err != Z_OK)
182e1051a39Sopenharmony_ci        return -1;
183e1051a39Sopenharmony_ci    return olen - state->ostream.avail_out;
184e1051a39Sopenharmony_ci}
185e1051a39Sopenharmony_ci
186e1051a39Sopenharmony_cistatic int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
187e1051a39Sopenharmony_ci                                      unsigned int olen, unsigned char *in,
188e1051a39Sopenharmony_ci                                      unsigned int ilen)
189e1051a39Sopenharmony_ci{
190e1051a39Sopenharmony_ci    int err = Z_OK;
191e1051a39Sopenharmony_ci    struct zlib_state *state = ctx->data;
192e1051a39Sopenharmony_ci
193e1051a39Sopenharmony_ci    if (state == NULL)
194e1051a39Sopenharmony_ci        return 0;
195e1051a39Sopenharmony_ci
196e1051a39Sopenharmony_ci    state->istream.next_in = in;
197e1051a39Sopenharmony_ci    state->istream.avail_in = ilen;
198e1051a39Sopenharmony_ci    state->istream.next_out = out;
199e1051a39Sopenharmony_ci    state->istream.avail_out = olen;
200e1051a39Sopenharmony_ci    if (ilen > 0)
201e1051a39Sopenharmony_ci        err = inflate(&state->istream, Z_SYNC_FLUSH);
202e1051a39Sopenharmony_ci    if (err != Z_OK)
203e1051a39Sopenharmony_ci        return -1;
204e1051a39Sopenharmony_ci    return olen - state->istream.avail_out;
205e1051a39Sopenharmony_ci}
206e1051a39Sopenharmony_ci
207e1051a39Sopenharmony_cistatic CRYPTO_ONCE zlib_once = CRYPTO_ONCE_STATIC_INIT;
208e1051a39Sopenharmony_ciDEFINE_RUN_ONCE_STATIC(ossl_comp_zlib_init)
209e1051a39Sopenharmony_ci{
210e1051a39Sopenharmony_ci# ifdef ZLIB_SHARED
211e1051a39Sopenharmony_ci    /* LIBZ may be externally defined, and we should respect that value */
212e1051a39Sopenharmony_ci#  ifndef LIBZ
213e1051a39Sopenharmony_ci#   if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
214e1051a39Sopenharmony_ci#    define LIBZ "ZLIB1"
215e1051a39Sopenharmony_ci#   elif defined(OPENSSL_SYS_VMS)
216e1051a39Sopenharmony_ci#    define LIBZ "LIBZ"
217e1051a39Sopenharmony_ci#   else
218e1051a39Sopenharmony_ci#    define LIBZ "z"
219e1051a39Sopenharmony_ci#   endif
220e1051a39Sopenharmony_ci#  endif
221e1051a39Sopenharmony_ci
222e1051a39Sopenharmony_ci    zlib_dso = DSO_load(NULL, LIBZ, NULL, 0);
223e1051a39Sopenharmony_ci    if (zlib_dso != NULL) {
224e1051a39Sopenharmony_ci        p_compress = (compress_ft) DSO_bind_func(zlib_dso, "compress");
225e1051a39Sopenharmony_ci        p_inflateEnd = (inflateEnd_ft) DSO_bind_func(zlib_dso, "inflateEnd");
226e1051a39Sopenharmony_ci        p_inflate = (inflate_ft) DSO_bind_func(zlib_dso, "inflate");
227e1051a39Sopenharmony_ci        p_inflateInit_ = (inflateInit__ft) DSO_bind_func(zlib_dso, "inflateInit_");
228e1051a39Sopenharmony_ci        p_deflateEnd = (deflateEnd_ft) DSO_bind_func(zlib_dso, "deflateEnd");
229e1051a39Sopenharmony_ci        p_deflate = (deflate_ft) DSO_bind_func(zlib_dso, "deflate");
230e1051a39Sopenharmony_ci        p_deflateInit_ = (deflateInit__ft) DSO_bind_func(zlib_dso, "deflateInit_");
231e1051a39Sopenharmony_ci        p_zError = (zError__ft) DSO_bind_func(zlib_dso, "zError");
232e1051a39Sopenharmony_ci
233e1051a39Sopenharmony_ci        if (p_compress == NULL || p_inflateEnd == NULL
234e1051a39Sopenharmony_ci                || p_inflate == NULL || p_inflateInit_ == NULL
235e1051a39Sopenharmony_ci                || p_deflateEnd == NULL || p_deflate == NULL
236e1051a39Sopenharmony_ci                || p_deflateInit_ == NULL || p_zError == NULL) {
237e1051a39Sopenharmony_ci            ossl_comp_zlib_cleanup();
238e1051a39Sopenharmony_ci            return 0;
239e1051a39Sopenharmony_ci        }
240e1051a39Sopenharmony_ci    }
241e1051a39Sopenharmony_ci# endif
242e1051a39Sopenharmony_ci    return 1;
243e1051a39Sopenharmony_ci}
244e1051a39Sopenharmony_ci#endif
245e1051a39Sopenharmony_ci
246e1051a39Sopenharmony_ciCOMP_METHOD *COMP_zlib(void)
247e1051a39Sopenharmony_ci{
248e1051a39Sopenharmony_ci    COMP_METHOD *meth = &zlib_method_nozlib;
249e1051a39Sopenharmony_ci
250e1051a39Sopenharmony_ci#ifdef ZLIB
251e1051a39Sopenharmony_ci    if (RUN_ONCE(&zlib_once, ossl_comp_zlib_init))
252e1051a39Sopenharmony_ci        meth = &zlib_stateful_method;
253e1051a39Sopenharmony_ci#endif
254e1051a39Sopenharmony_ci
255e1051a39Sopenharmony_ci    return meth;
256e1051a39Sopenharmony_ci}
257e1051a39Sopenharmony_ci
258e1051a39Sopenharmony_ci/* Also called from OPENSSL_cleanup() */
259e1051a39Sopenharmony_civoid ossl_comp_zlib_cleanup(void)
260e1051a39Sopenharmony_ci{
261e1051a39Sopenharmony_ci#ifdef ZLIB_SHARED
262e1051a39Sopenharmony_ci    DSO_free(zlib_dso);
263e1051a39Sopenharmony_ci    zlib_dso = NULL;
264e1051a39Sopenharmony_ci#endif
265e1051a39Sopenharmony_ci}
266e1051a39Sopenharmony_ci
267e1051a39Sopenharmony_ci#ifdef ZLIB
268e1051a39Sopenharmony_ci
269e1051a39Sopenharmony_ci/* Zlib based compression/decompression filter BIO */
270e1051a39Sopenharmony_ci
271e1051a39Sopenharmony_citypedef struct {
272e1051a39Sopenharmony_ci    unsigned char *ibuf;        /* Input buffer */
273e1051a39Sopenharmony_ci    int ibufsize;               /* Buffer size */
274e1051a39Sopenharmony_ci    z_stream zin;               /* Input decompress context */
275e1051a39Sopenharmony_ci    unsigned char *obuf;        /* Output buffer */
276e1051a39Sopenharmony_ci    int obufsize;               /* Output buffer size */
277e1051a39Sopenharmony_ci    unsigned char *optr;        /* Position in output buffer */
278e1051a39Sopenharmony_ci    int ocount;                 /* Amount of data in output buffer */
279e1051a39Sopenharmony_ci    int odone;                  /* deflate EOF */
280e1051a39Sopenharmony_ci    int comp_level;             /* Compression level to use */
281e1051a39Sopenharmony_ci    z_stream zout;              /* Output compression context */
282e1051a39Sopenharmony_ci} BIO_ZLIB_CTX;
283e1051a39Sopenharmony_ci
284e1051a39Sopenharmony_ci# define ZLIB_DEFAULT_BUFSIZE 1024
285e1051a39Sopenharmony_ci
286e1051a39Sopenharmony_cistatic int bio_zlib_new(BIO *bi);
287e1051a39Sopenharmony_cistatic int bio_zlib_free(BIO *bi);
288e1051a39Sopenharmony_cistatic int bio_zlib_read(BIO *b, char *out, int outl);
289e1051a39Sopenharmony_cistatic int bio_zlib_write(BIO *b, const char *in, int inl);
290e1051a39Sopenharmony_cistatic long bio_zlib_ctrl(BIO *b, int cmd, long num, void *ptr);
291e1051a39Sopenharmony_cistatic long bio_zlib_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp);
292e1051a39Sopenharmony_ci
293e1051a39Sopenharmony_cistatic const BIO_METHOD bio_meth_zlib = {
294e1051a39Sopenharmony_ci    BIO_TYPE_COMP,
295e1051a39Sopenharmony_ci    "zlib",
296e1051a39Sopenharmony_ci    bwrite_conv,
297e1051a39Sopenharmony_ci    bio_zlib_write,
298e1051a39Sopenharmony_ci    bread_conv,
299e1051a39Sopenharmony_ci    bio_zlib_read,
300e1051a39Sopenharmony_ci    NULL,                      /* bio_zlib_puts, */
301e1051a39Sopenharmony_ci    NULL,                      /* bio_zlib_gets, */
302e1051a39Sopenharmony_ci    bio_zlib_ctrl,
303e1051a39Sopenharmony_ci    bio_zlib_new,
304e1051a39Sopenharmony_ci    bio_zlib_free,
305e1051a39Sopenharmony_ci    bio_zlib_callback_ctrl
306e1051a39Sopenharmony_ci};
307e1051a39Sopenharmony_ci
308e1051a39Sopenharmony_ciconst BIO_METHOD *BIO_f_zlib(void)
309e1051a39Sopenharmony_ci{
310e1051a39Sopenharmony_ci    return &bio_meth_zlib;
311e1051a39Sopenharmony_ci}
312e1051a39Sopenharmony_ci
313e1051a39Sopenharmony_cistatic int bio_zlib_new(BIO *bi)
314e1051a39Sopenharmony_ci{
315e1051a39Sopenharmony_ci    BIO_ZLIB_CTX *ctx;
316e1051a39Sopenharmony_ci
317e1051a39Sopenharmony_ci# ifdef ZLIB_SHARED
318e1051a39Sopenharmony_ci    if (!RUN_ONCE(&zlib_once, ossl_comp_zlib_init)) {
319e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_COMP, COMP_R_ZLIB_NOT_SUPPORTED);
320e1051a39Sopenharmony_ci        return 0;
321e1051a39Sopenharmony_ci    }
322e1051a39Sopenharmony_ci# endif
323e1051a39Sopenharmony_ci    ctx = OPENSSL_zalloc(sizeof(*ctx));
324e1051a39Sopenharmony_ci    if (ctx == NULL) {
325e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
326e1051a39Sopenharmony_ci        return 0;
327e1051a39Sopenharmony_ci    }
328e1051a39Sopenharmony_ci    ctx->ibufsize = ZLIB_DEFAULT_BUFSIZE;
329e1051a39Sopenharmony_ci    ctx->obufsize = ZLIB_DEFAULT_BUFSIZE;
330e1051a39Sopenharmony_ci    ctx->zin.zalloc = Z_NULL;
331e1051a39Sopenharmony_ci    ctx->zin.zfree = Z_NULL;
332e1051a39Sopenharmony_ci    ctx->zout.zalloc = Z_NULL;
333e1051a39Sopenharmony_ci    ctx->zout.zfree = Z_NULL;
334e1051a39Sopenharmony_ci    ctx->comp_level = Z_DEFAULT_COMPRESSION;
335e1051a39Sopenharmony_ci    BIO_set_init(bi, 1);
336e1051a39Sopenharmony_ci    BIO_set_data(bi, ctx);
337e1051a39Sopenharmony_ci
338e1051a39Sopenharmony_ci    return 1;
339e1051a39Sopenharmony_ci}
340e1051a39Sopenharmony_ci
341e1051a39Sopenharmony_cistatic int bio_zlib_free(BIO *bi)
342e1051a39Sopenharmony_ci{
343e1051a39Sopenharmony_ci    BIO_ZLIB_CTX *ctx;
344e1051a39Sopenharmony_ci
345e1051a39Sopenharmony_ci    if (!bi)
346e1051a39Sopenharmony_ci        return 0;
347e1051a39Sopenharmony_ci    ctx = BIO_get_data(bi);
348e1051a39Sopenharmony_ci    if (ctx->ibuf) {
349e1051a39Sopenharmony_ci        /* Destroy decompress context */
350e1051a39Sopenharmony_ci        inflateEnd(&ctx->zin);
351e1051a39Sopenharmony_ci        OPENSSL_free(ctx->ibuf);
352e1051a39Sopenharmony_ci    }
353e1051a39Sopenharmony_ci    if (ctx->obuf) {
354e1051a39Sopenharmony_ci        /* Destroy compress context */
355e1051a39Sopenharmony_ci        deflateEnd(&ctx->zout);
356e1051a39Sopenharmony_ci        OPENSSL_free(ctx->obuf);
357e1051a39Sopenharmony_ci    }
358e1051a39Sopenharmony_ci    OPENSSL_free(ctx);
359e1051a39Sopenharmony_ci    BIO_set_data(bi, NULL);
360e1051a39Sopenharmony_ci    BIO_set_init(bi, 0);
361e1051a39Sopenharmony_ci
362e1051a39Sopenharmony_ci    return 1;
363e1051a39Sopenharmony_ci}
364e1051a39Sopenharmony_ci
365e1051a39Sopenharmony_cistatic int bio_zlib_read(BIO *b, char *out, int outl)
366e1051a39Sopenharmony_ci{
367e1051a39Sopenharmony_ci    BIO_ZLIB_CTX *ctx;
368e1051a39Sopenharmony_ci    int ret;
369e1051a39Sopenharmony_ci    z_stream *zin;
370e1051a39Sopenharmony_ci    BIO *next = BIO_next(b);
371e1051a39Sopenharmony_ci
372e1051a39Sopenharmony_ci    if (!out || !outl)
373e1051a39Sopenharmony_ci        return 0;
374e1051a39Sopenharmony_ci    ctx = BIO_get_data(b);
375e1051a39Sopenharmony_ci    zin = &ctx->zin;
376e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
377e1051a39Sopenharmony_ci    if (!ctx->ibuf) {
378e1051a39Sopenharmony_ci        ctx->ibuf = OPENSSL_malloc(ctx->ibufsize);
379e1051a39Sopenharmony_ci        if (ctx->ibuf == NULL) {
380e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
381e1051a39Sopenharmony_ci            return 0;
382e1051a39Sopenharmony_ci        }
383e1051a39Sopenharmony_ci        if ((ret = inflateInit(zin)) != Z_OK) {
384e1051a39Sopenharmony_ci            ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_INFLATE_ERROR,
385e1051a39Sopenharmony_ci                           "zlib error: %s", zError(ret));
386e1051a39Sopenharmony_ci            return 0;
387e1051a39Sopenharmony_ci        }
388e1051a39Sopenharmony_ci        zin->next_in = ctx->ibuf;
389e1051a39Sopenharmony_ci        zin->avail_in = 0;
390e1051a39Sopenharmony_ci    }
391e1051a39Sopenharmony_ci
392e1051a39Sopenharmony_ci    /* Copy output data directly to supplied buffer */
393e1051a39Sopenharmony_ci    zin->next_out = (unsigned char *)out;
394e1051a39Sopenharmony_ci    zin->avail_out = (unsigned int)outl;
395e1051a39Sopenharmony_ci    for (;;) {
396e1051a39Sopenharmony_ci        /* Decompress while data available */
397e1051a39Sopenharmony_ci        while (zin->avail_in) {
398e1051a39Sopenharmony_ci            ret = inflate(zin, 0);
399e1051a39Sopenharmony_ci            if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
400e1051a39Sopenharmony_ci                ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_INFLATE_ERROR,
401e1051a39Sopenharmony_ci                               "zlib error: %s", zError(ret));
402e1051a39Sopenharmony_ci                return 0;
403e1051a39Sopenharmony_ci            }
404e1051a39Sopenharmony_ci            /* If EOF or we've read everything then return */
405e1051a39Sopenharmony_ci            if ((ret == Z_STREAM_END) || !zin->avail_out)
406e1051a39Sopenharmony_ci                return outl - zin->avail_out;
407e1051a39Sopenharmony_ci        }
408e1051a39Sopenharmony_ci
409e1051a39Sopenharmony_ci        /*
410e1051a39Sopenharmony_ci         * No data in input buffer try to read some in, if an error then
411e1051a39Sopenharmony_ci         * return the total data read.
412e1051a39Sopenharmony_ci         */
413e1051a39Sopenharmony_ci        ret = BIO_read(next, ctx->ibuf, ctx->ibufsize);
414e1051a39Sopenharmony_ci        if (ret <= 0) {
415e1051a39Sopenharmony_ci            /* Total data read */
416e1051a39Sopenharmony_ci            int tot = outl - zin->avail_out;
417e1051a39Sopenharmony_ci            BIO_copy_next_retry(b);
418e1051a39Sopenharmony_ci            if (ret < 0)
419e1051a39Sopenharmony_ci                return (tot > 0) ? tot : ret;
420e1051a39Sopenharmony_ci            return tot;
421e1051a39Sopenharmony_ci        }
422e1051a39Sopenharmony_ci        zin->avail_in = ret;
423e1051a39Sopenharmony_ci        zin->next_in = ctx->ibuf;
424e1051a39Sopenharmony_ci    }
425e1051a39Sopenharmony_ci}
426e1051a39Sopenharmony_ci
427e1051a39Sopenharmony_cistatic int bio_zlib_write(BIO *b, const char *in, int inl)
428e1051a39Sopenharmony_ci{
429e1051a39Sopenharmony_ci    BIO_ZLIB_CTX *ctx;
430e1051a39Sopenharmony_ci    int ret;
431e1051a39Sopenharmony_ci    z_stream *zout;
432e1051a39Sopenharmony_ci    BIO *next = BIO_next(b);
433e1051a39Sopenharmony_ci
434e1051a39Sopenharmony_ci    if (!in || !inl)
435e1051a39Sopenharmony_ci        return 0;
436e1051a39Sopenharmony_ci    ctx = BIO_get_data(b);
437e1051a39Sopenharmony_ci    if (ctx->odone)
438e1051a39Sopenharmony_ci        return 0;
439e1051a39Sopenharmony_ci    zout = &ctx->zout;
440e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
441e1051a39Sopenharmony_ci    if (!ctx->obuf) {
442e1051a39Sopenharmony_ci        ctx->obuf = OPENSSL_malloc(ctx->obufsize);
443e1051a39Sopenharmony_ci        /* Need error here */
444e1051a39Sopenharmony_ci        if (ctx->obuf == NULL) {
445e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_COMP, ERR_R_MALLOC_FAILURE);
446e1051a39Sopenharmony_ci            return 0;
447e1051a39Sopenharmony_ci        }
448e1051a39Sopenharmony_ci        ctx->optr = ctx->obuf;
449e1051a39Sopenharmony_ci        ctx->ocount = 0;
450e1051a39Sopenharmony_ci        if ((ret = deflateInit(zout, ctx->comp_level)) != Z_OK) {
451e1051a39Sopenharmony_ci            ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_DEFLATE_ERROR,
452e1051a39Sopenharmony_ci                           "zlib error: %s", zError(ret));
453e1051a39Sopenharmony_ci            return 0;
454e1051a39Sopenharmony_ci        }
455e1051a39Sopenharmony_ci        zout->next_out = ctx->obuf;
456e1051a39Sopenharmony_ci        zout->avail_out = ctx->obufsize;
457e1051a39Sopenharmony_ci    }
458e1051a39Sopenharmony_ci    /* Obtain input data directly from supplied buffer */
459e1051a39Sopenharmony_ci    zout->next_in = (void *)in;
460e1051a39Sopenharmony_ci    zout->avail_in = inl;
461e1051a39Sopenharmony_ci    for (;;) {
462e1051a39Sopenharmony_ci        /* If data in output buffer write it first */
463e1051a39Sopenharmony_ci        while (ctx->ocount) {
464e1051a39Sopenharmony_ci            ret = BIO_write(next, ctx->optr, ctx->ocount);
465e1051a39Sopenharmony_ci            if (ret <= 0) {
466e1051a39Sopenharmony_ci                /* Total data written */
467e1051a39Sopenharmony_ci                int tot = inl - zout->avail_in;
468e1051a39Sopenharmony_ci                BIO_copy_next_retry(b);
469e1051a39Sopenharmony_ci                if (ret < 0)
470e1051a39Sopenharmony_ci                    return (tot > 0) ? tot : ret;
471e1051a39Sopenharmony_ci                return tot;
472e1051a39Sopenharmony_ci            }
473e1051a39Sopenharmony_ci            ctx->optr += ret;
474e1051a39Sopenharmony_ci            ctx->ocount -= ret;
475e1051a39Sopenharmony_ci        }
476e1051a39Sopenharmony_ci
477e1051a39Sopenharmony_ci        /* Have we consumed all supplied data? */
478e1051a39Sopenharmony_ci        if (!zout->avail_in)
479e1051a39Sopenharmony_ci            return inl;
480e1051a39Sopenharmony_ci
481e1051a39Sopenharmony_ci        /* Compress some more */
482e1051a39Sopenharmony_ci
483e1051a39Sopenharmony_ci        /* Reset buffer */
484e1051a39Sopenharmony_ci        ctx->optr = ctx->obuf;
485e1051a39Sopenharmony_ci        zout->next_out = ctx->obuf;
486e1051a39Sopenharmony_ci        zout->avail_out = ctx->obufsize;
487e1051a39Sopenharmony_ci        /* Compress some more */
488e1051a39Sopenharmony_ci        ret = deflate(zout, 0);
489e1051a39Sopenharmony_ci        if (ret != Z_OK) {
490e1051a39Sopenharmony_ci            ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_DEFLATE_ERROR,
491e1051a39Sopenharmony_ci                           "zlib error: %s", zError(ret));
492e1051a39Sopenharmony_ci            return 0;
493e1051a39Sopenharmony_ci        }
494e1051a39Sopenharmony_ci        ctx->ocount = ctx->obufsize - zout->avail_out;
495e1051a39Sopenharmony_ci    }
496e1051a39Sopenharmony_ci}
497e1051a39Sopenharmony_ci
498e1051a39Sopenharmony_cistatic int bio_zlib_flush(BIO *b)
499e1051a39Sopenharmony_ci{
500e1051a39Sopenharmony_ci    BIO_ZLIB_CTX *ctx;
501e1051a39Sopenharmony_ci    int ret;
502e1051a39Sopenharmony_ci    z_stream *zout;
503e1051a39Sopenharmony_ci    BIO *next = BIO_next(b);
504e1051a39Sopenharmony_ci
505e1051a39Sopenharmony_ci    ctx = BIO_get_data(b);
506e1051a39Sopenharmony_ci    /* If no data written or already flush show success */
507e1051a39Sopenharmony_ci    if (!ctx->obuf || (ctx->odone && !ctx->ocount))
508e1051a39Sopenharmony_ci        return 1;
509e1051a39Sopenharmony_ci    zout = &ctx->zout;
510e1051a39Sopenharmony_ci    BIO_clear_retry_flags(b);
511e1051a39Sopenharmony_ci    /* No more input data */
512e1051a39Sopenharmony_ci    zout->next_in = NULL;
513e1051a39Sopenharmony_ci    zout->avail_in = 0;
514e1051a39Sopenharmony_ci    for (;;) {
515e1051a39Sopenharmony_ci        /* If data in output buffer write it first */
516e1051a39Sopenharmony_ci        while (ctx->ocount) {
517e1051a39Sopenharmony_ci            ret = BIO_write(next, ctx->optr, ctx->ocount);
518e1051a39Sopenharmony_ci            if (ret <= 0) {
519e1051a39Sopenharmony_ci                BIO_copy_next_retry(b);
520e1051a39Sopenharmony_ci                return ret;
521e1051a39Sopenharmony_ci            }
522e1051a39Sopenharmony_ci            ctx->optr += ret;
523e1051a39Sopenharmony_ci            ctx->ocount -= ret;
524e1051a39Sopenharmony_ci        }
525e1051a39Sopenharmony_ci        if (ctx->odone)
526e1051a39Sopenharmony_ci            return 1;
527e1051a39Sopenharmony_ci
528e1051a39Sopenharmony_ci        /* Compress some more */
529e1051a39Sopenharmony_ci
530e1051a39Sopenharmony_ci        /* Reset buffer */
531e1051a39Sopenharmony_ci        ctx->optr = ctx->obuf;
532e1051a39Sopenharmony_ci        zout->next_out = ctx->obuf;
533e1051a39Sopenharmony_ci        zout->avail_out = ctx->obufsize;
534e1051a39Sopenharmony_ci        /* Compress some more */
535e1051a39Sopenharmony_ci        ret = deflate(zout, Z_FINISH);
536e1051a39Sopenharmony_ci        if (ret == Z_STREAM_END)
537e1051a39Sopenharmony_ci            ctx->odone = 1;
538e1051a39Sopenharmony_ci        else if (ret != Z_OK) {
539e1051a39Sopenharmony_ci            ERR_raise_data(ERR_LIB_COMP, COMP_R_ZLIB_DEFLATE_ERROR,
540e1051a39Sopenharmony_ci                           "zlib error: %s", zError(ret));
541e1051a39Sopenharmony_ci            return 0;
542e1051a39Sopenharmony_ci        }
543e1051a39Sopenharmony_ci        ctx->ocount = ctx->obufsize - zout->avail_out;
544e1051a39Sopenharmony_ci    }
545e1051a39Sopenharmony_ci}
546e1051a39Sopenharmony_ci
547e1051a39Sopenharmony_cistatic long bio_zlib_ctrl(BIO *b, int cmd, long num, void *ptr)
548e1051a39Sopenharmony_ci{
549e1051a39Sopenharmony_ci    BIO_ZLIB_CTX *ctx;
550e1051a39Sopenharmony_ci    int ret, *ip;
551e1051a39Sopenharmony_ci    int ibs, obs;
552e1051a39Sopenharmony_ci    BIO *next = BIO_next(b);
553e1051a39Sopenharmony_ci
554e1051a39Sopenharmony_ci    if (next == NULL)
555e1051a39Sopenharmony_ci        return 0;
556e1051a39Sopenharmony_ci    ctx = BIO_get_data(b);
557e1051a39Sopenharmony_ci    switch (cmd) {
558e1051a39Sopenharmony_ci
559e1051a39Sopenharmony_ci    case BIO_CTRL_RESET:
560e1051a39Sopenharmony_ci        ctx->ocount = 0;
561e1051a39Sopenharmony_ci        ctx->odone = 0;
562e1051a39Sopenharmony_ci        ret = 1;
563e1051a39Sopenharmony_ci        break;
564e1051a39Sopenharmony_ci
565e1051a39Sopenharmony_ci    case BIO_CTRL_FLUSH:
566e1051a39Sopenharmony_ci        ret = bio_zlib_flush(b);
567e1051a39Sopenharmony_ci        if (ret > 0)
568e1051a39Sopenharmony_ci            ret = BIO_flush(next);
569e1051a39Sopenharmony_ci        break;
570e1051a39Sopenharmony_ci
571e1051a39Sopenharmony_ci    case BIO_C_SET_BUFF_SIZE:
572e1051a39Sopenharmony_ci        ibs = -1;
573e1051a39Sopenharmony_ci        obs = -1;
574e1051a39Sopenharmony_ci        if (ptr != NULL) {
575e1051a39Sopenharmony_ci            ip = ptr;
576e1051a39Sopenharmony_ci            if (*ip == 0)
577e1051a39Sopenharmony_ci                ibs = (int)num;
578e1051a39Sopenharmony_ci            else
579e1051a39Sopenharmony_ci                obs = (int)num;
580e1051a39Sopenharmony_ci        } else {
581e1051a39Sopenharmony_ci            ibs = (int)num;
582e1051a39Sopenharmony_ci            obs = ibs;
583e1051a39Sopenharmony_ci        }
584e1051a39Sopenharmony_ci
585e1051a39Sopenharmony_ci        if (ibs != -1) {
586e1051a39Sopenharmony_ci            OPENSSL_free(ctx->ibuf);
587e1051a39Sopenharmony_ci            ctx->ibuf = NULL;
588e1051a39Sopenharmony_ci            ctx->ibufsize = ibs;
589e1051a39Sopenharmony_ci        }
590e1051a39Sopenharmony_ci
591e1051a39Sopenharmony_ci        if (obs != -1) {
592e1051a39Sopenharmony_ci            OPENSSL_free(ctx->obuf);
593e1051a39Sopenharmony_ci            ctx->obuf = NULL;
594e1051a39Sopenharmony_ci            ctx->obufsize = obs;
595e1051a39Sopenharmony_ci        }
596e1051a39Sopenharmony_ci        ret = 1;
597e1051a39Sopenharmony_ci        break;
598e1051a39Sopenharmony_ci
599e1051a39Sopenharmony_ci    case BIO_C_DO_STATE_MACHINE:
600e1051a39Sopenharmony_ci        BIO_clear_retry_flags(b);
601e1051a39Sopenharmony_ci        ret = BIO_ctrl(next, cmd, num, ptr);
602e1051a39Sopenharmony_ci        BIO_copy_next_retry(b);
603e1051a39Sopenharmony_ci        break;
604e1051a39Sopenharmony_ci
605e1051a39Sopenharmony_ci    case BIO_CTRL_WPENDING:
606e1051a39Sopenharmony_ci        if (ctx->obuf == NULL)
607e1051a39Sopenharmony_ci            return 0;
608e1051a39Sopenharmony_ci
609e1051a39Sopenharmony_ci        if (ctx->odone) {
610e1051a39Sopenharmony_ci            ret = ctx->ocount;
611e1051a39Sopenharmony_ci        } else {
612e1051a39Sopenharmony_ci            ret = ctx->ocount;
613e1051a39Sopenharmony_ci            if (ret == 0)
614e1051a39Sopenharmony_ci                /* Unknown amount pending but we are not finished */
615e1051a39Sopenharmony_ci                ret = 1;
616e1051a39Sopenharmony_ci        }
617e1051a39Sopenharmony_ci        if (ret == 0)
618e1051a39Sopenharmony_ci            ret = BIO_ctrl(next, cmd, num, ptr);
619e1051a39Sopenharmony_ci        break;
620e1051a39Sopenharmony_ci
621e1051a39Sopenharmony_ci    case BIO_CTRL_PENDING:
622e1051a39Sopenharmony_ci        ret = ctx->zin.avail_in;
623e1051a39Sopenharmony_ci        if (ret == 0)
624e1051a39Sopenharmony_ci            ret = BIO_ctrl(next, cmd, num, ptr);
625e1051a39Sopenharmony_ci        break;
626e1051a39Sopenharmony_ci
627e1051a39Sopenharmony_ci    default:
628e1051a39Sopenharmony_ci        ret = BIO_ctrl(next, cmd, num, ptr);
629e1051a39Sopenharmony_ci        break;
630e1051a39Sopenharmony_ci
631e1051a39Sopenharmony_ci    }
632e1051a39Sopenharmony_ci
633e1051a39Sopenharmony_ci    return ret;
634e1051a39Sopenharmony_ci}
635e1051a39Sopenharmony_ci
636e1051a39Sopenharmony_cistatic long bio_zlib_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
637e1051a39Sopenharmony_ci{
638e1051a39Sopenharmony_ci    BIO *next = BIO_next(b);
639e1051a39Sopenharmony_ci
640e1051a39Sopenharmony_ci    if (next == NULL)
641e1051a39Sopenharmony_ci        return 0;
642e1051a39Sopenharmony_ci    return BIO_callback_ctrl(next, cmd, fp);
643e1051a39Sopenharmony_ci}
644e1051a39Sopenharmony_ci
645e1051a39Sopenharmony_ci#endif
646