## Coverage Report

#### Created: 2023-09-23 17:42

    /libfido2/src/compress.c

    Line
    Count
    Source (jump to first uncovered line)
    1
    /*
    2
     * Copyright (c) 2020-2022 Yubico AB. All rights reserved.
    3
     * Use of this source code is governed by a BSD-style
    4
     * license that can be found in the LICENSE file.
    5
     * SPDX-License-Identifier: BSD-2-Clause
    6
     */
    7
    8
    #include <zlib.h>
    9
    #include "fido.h"
    10
    11
    1.29k
    #define BOUND (1024UL * 1024UL)
    12
    13
    /* zlib inflate (raw + headers) */
    14
    static int
    15
    rfc1950_inflate(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
    16
    8
    {
    17
    8
            u_long ilen, olen;
    18
    8
            int z;
    19
    20
    8
            memset(out, 0, sizeof(*out));
    21
    22
    8
            if (in->len > ULONG_MAX || (ilen = (u_long)in->len) > BOUND ||
    23
    8
                origsiz > ULONG_MAX || (olen = (u_long)origsiz) > BOUND) {
    24
    0
                    fido_log_debug("%s: in->len=%zu, origsiz=%zu", __func__,
    25
    0
                        in->len, origsiz);
    26
    0
                    return FIDO_ERR_INVALID_ARGUMENT;
    27
    0
            }
    28
    29
    8
            if ((out->ptr = calloc(1, olen)) == NULL)
    30
    1
                    return FIDO_ERR_INTERNAL;
    31
    7
            out->len = olen;
    32
    33
    7
            if ((z = uncompress(out->ptr, &olen, in->ptr, ilen)) != Z_OK ||
    34
    7
                olen > SIZE_MAX || olen != out->len) {
    35
    4
                    fido_log_debug("%s: uncompress: %d, olen=%lu, out->len=%zu",
    36
    4
                        __func__, z, olen, out->len);
    37
    4
                    fido_blob_reset(out);
    38
    4
                    return FIDO_ERR_COMPRESS;
    39
    4
            }
    40
    41
    3
            return FIDO_OK;
    42
    7
    }
    43
    44
    /* raw inflate */
    45
    static int
    46
    rfc1951_inflate(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
    47
    5
    {
    48
    5
            z_stream zs;
    49
    5
            u_int ilen, olen;
    50
    5
            int r, z;
    51
    52
    5
            memset(&zs, 0, sizeof(zs));
    53
    5
            memset(out, 0, sizeof(*out));
    54
    55
    5
            if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND ||
    56
    5
                origsiz > UINT_MAX || (olen = (u_int)origsiz) > BOUND) {
    57
    0
                    fido_log_debug("%s: in->len=%zu, origsiz=%zu", __func__,
    58
    0
                        in->len, origsiz);
    59
    0
                    return FIDO_ERR_INVALID_ARGUMENT;
    60
    0
            }
    61
    5
            if ((z = inflateInit2(&zs, -MAX_WBITS)) != Z_OK) {
    62
    0
                    fido_log_debug("%s: inflateInit2: %d", __func__, z);
    63
    0
                    return FIDO_ERR_COMPRESS;
    64
    0
            }
    65
    66
    5
            if ((out->ptr = calloc(1, olen)) == NULL) {
    67
    1
                    r = FIDO_ERR_INTERNAL;
    68
    1
                    goto fail;
    69
    1
            }
    70
    4
            out->len = olen;
    71
    4
            zs.next_in = in->ptr;
    72
    4
            zs.avail_in = ilen;
    73
    4
            zs.next_out = out->ptr;
    74
    4
            zs.avail_out = olen;
    75
    76
    4
            if ((z = inflate(&zs, Z_FINISH)) != Z_STREAM_END) {
    77
    1
                    fido_log_debug("%s: inflate: %d", __func__, z);
    78
    1
                    r = FIDO_ERR_COMPRESS;
    79
    1
                    goto fail;
    80
    1
            }
    81
    3
            if (zs.avail_out != 0) {
    82
    0
                    fido_log_debug("%s: %u != 0", __func__, zs.avail_out);
    83
    0
                    r = FIDO_ERR_COMPRESS;
    84
    0
                    goto fail;
    85
    0
            }
    86
    87
    3
            r = FIDO_OK;
    88
    5
    fail:
    89
    5
            if ((z = inflateEnd(&zs)) != Z_OK) {
    90
    0
                    fido_log_debug("%s: inflateEnd: %d", __func__, z);
    91
    0
                    r = FIDO_ERR_COMPRESS;
    92
    0
            }
    93
    5
            if (r != FIDO_OK)
    94
    2
                    fido_blob_reset(out);
    95
    96
    5
            return r;
    97
    3
    }
    98
    99
    /* raw deflate */
    100
    static int
    101
    rfc1951_deflate(fido_blob_t *out, const fido_blob_t *in)
    102
    628
    {
    103
    628
            z_stream zs;
    104
    628
            u_int ilen, olen;
    105
    628
            int r, z;
    106
    107
    628
            memset(&zs, 0, sizeof(zs));
    108
    628
            memset(out, 0, sizeof(*out));
    109
    110
    628
            if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND) {
    111
    0
                    fido_log_debug("%s: in->len=%zu", __func__, in->len);
    112
    0
                    return FIDO_ERR_INVALID_ARGUMENT;
    113
    0
            }
    114
    628
            if ((z = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
    115
    628
                -MAX_WBITS, 8, Z_DEFAULT_STRATEGY)) != Z_OK) {
    116
    1
                    fido_log_debug("%s: deflateInit2: %d", __func__, z);
    117
    1
                    return FIDO_ERR_COMPRESS;
    118
    1
            }
    119
    120
    627
            olen = BOUND;
    121
    627
            if ((out->ptr = calloc(1, olen)) == NULL) {
    122
    2
                    r = FIDO_ERR_INTERNAL;
    123
    2
                    goto fail;
    124
    2
            }
    125
    625
            out->len = olen;
    126
    625
            zs.next_in = in->ptr;
    127
    625
            zs.avail_in = ilen;
    128
    625
            zs.next_out = out->ptr;
    129
    625
            zs.avail_out = olen;
    130
    131
    625
            if ((z = deflate(&zs, Z_FINISH)) != Z_STREAM_END) {
    132
    1
                    fido_log_debug("%s: inflate: %d", __func__, z);
    133
    1
                    r = FIDO_ERR_COMPRESS;
    134
    1
                    goto fail;
    135
    1
            }
    136
    624
            if (zs.avail_out >= out->len) {
    137
    1
                    fido_log_debug("%s: %u > %zu", __func__, zs.avail_out,
    138
    1
                        out->len);
    139
    1
                    r = FIDO_ERR_COMPRESS;
    140
    1
                    goto fail;
    141
    1
            }
    142
    623
            out->len -= zs.avail_out;
    143
    144
    623
            r = FIDO_OK;
    145
    627
    fail:
    146
    627
            if ((z = deflateEnd(&zs)) != Z_OK) {
    147
    0
                    fido_log_debug("%s: deflateEnd: %d", __func__, z);
    148
    0
                    r = FIDO_ERR_COMPRESS;
    149
    0
            }
    150
    627
            if (r != FIDO_OK)
    151
    4
                    fido_blob_reset(out);
    152
    153
    627
            return r;
    154
    623
    }
    155
    156
    int
    157
    fido_compress(fido_blob_t *out, const fido_blob_t *in)
    158
    628
    {
    159
    628
            return rfc1951_deflate(out, in);
    160
    628
    }
    161
    162
    int
    163
    fido_uncompress(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
    164
    8
    {
    165
    8
            if (rfc1950_inflate(out, in, origsiz) == FIDO_OK)
    166
    3
                    return FIDO_OK; /* backwards compat with libfido2 < 1.11 */
    167
    5
            return rfc1951_inflate(out, in, origsiz);
    168
    8
    }