Coverage Report

Created: 2025-06-13 06:58

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