Coverage Report

Created: 2025-12-31 06:58

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