## Coverage Report

#### Created: 2025-03-01 02:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /libfido2/src/compress.c

    Line
    Count
    Source
    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
    21.8k
    #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
    33
    {
    17
    33
            u_long ilen, olen;
    18
    33
            int z;
    19
    20
    33
            memset(out, 0, sizeof(*out));
    21
    22
    33
            if (in->len > ULONG_MAX || (ilen = (u_long)in->len) > BOUND ||
    23
    33
                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
    33
            if ((out->ptr = calloc(1, olen)) == NULL)
    30
    3
                    return FIDO_ERR_INTERNAL;
    31
    30
            out->len = olen;
    32
    33
    30
            if ((z = uncompress(out->ptr, &olen, in->ptr, ilen)) != Z_OK ||
    34
    30
                olen > SIZE_MAX || olen != out->len) {
    35
    14
                    fido_log_debug("%s: uncompress: %d, olen=%lu, out->len=%zu",
    36
    14
                        __func__, z, olen, out->len);
    37
    14
                    fido_blob_reset(out);
    38
    14
                    return FIDO_ERR_COMPRESS;
    39
    14
            }
    40
    41
    16
            return FIDO_OK;
    42
    30
    }
    43
    44
    /* raw inflate */
    45
    static int
    46
    rfc1951_inflate(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
    47
    17
    {
    48
    17
            z_stream zs;
    49
    17
            u_int ilen, olen;
    50
    17
            int r, z;
    51
    52
    17
            memset(&zs, 0, sizeof(zs));
    53
    17
            memset(out, 0, sizeof(*out));
    54
    55
    17
            if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND ||
    56
    17
                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
    17
            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
    17
            if ((out->ptr = calloc(1, olen)) == NULL) {
    67
    3
                    r = FIDO_ERR_INTERNAL;
    68
    3
                    goto fail;
    69
    3
            }
    70
    14
            out->len = olen;
    71
    14
            zs.next_in = in->ptr;
    72
    14
            zs.avail_in = ilen;
    73
    14
            zs.next_out = out->ptr;
    74
    14
            zs.avail_out = olen;
    75
    76
    14
            if ((z = inflate(&zs, Z_FINISH)) != Z_STREAM_END) {
    77
    3
                    fido_log_debug("%s: inflate: %d", __func__, z);
    78
    3
                    r = FIDO_ERR_COMPRESS;
    79
    3
                    goto fail;
    80
    3
            }
    81
    11
            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
    11
            r = FIDO_OK;
    88
    17
    fail:
    89
    17
            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
    17
            if (r != FIDO_OK)
    94
    6
                    fido_blob_reset(out);
    95
    96
    17
            return r;
    97
    11
    }
    98
    99
    /* raw deflate */
    100
    static int
    101
    rfc1951_deflate(fido_blob_t *out, const fido_blob_t *in)
    102
    10.8k
    {
    103
    10.8k
            z_stream zs;
    104
    10.8k
            u_int ilen, olen;
    105
    10.8k
            int r, z;
    106
    107
    10.8k
            memset(&zs, 0, sizeof(zs));
    108
    10.8k
            memset(out, 0, sizeof(*out));
    109
    110
    10.8k
            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
    10.8k
            if ((z = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
    115
    10.8k
                -MAX_WBITS, 8, Z_DEFAULT_STRATEGY)) != Z_OK) {
    116
    9
                    fido_log_debug("%s: deflateInit2: %d", __func__, z);
    117
    9
                    return FIDO_ERR_COMPRESS;
    118
    9
            }
    119
    120
    10.8k
            olen = BOUND;
    121
    10.8k
            if ((out->ptr = calloc(1, olen)) == NULL) {
    122
    8
                    r = FIDO_ERR_INTERNAL;
    123
    8
                    goto fail;
    124
    8
            }
    125
    10.8k
            out->len = olen;
    126
    10.8k
            zs.next_in = in->ptr;
    127
    10.8k
            zs.avail_in = ilen;
    128
    10.8k
            zs.next_out = out->ptr;
    129
    10.8k
            zs.avail_out = olen;
    130
    131
    10.8k
            if ((z = deflate(&zs, Z_FINISH)) != Z_STREAM_END) {
    132
    3
                    fido_log_debug("%s: inflate: %d", __func__, z);
    133
    3
                    r = FIDO_ERR_COMPRESS;
    134
    3
                    goto fail;
    135
    3
            }
    136
    10.8k
            if (zs.avail_out >= out->len) {
    137
    15
                    fido_log_debug("%s: %u > %zu", __func__, zs.avail_out,
    138
    15
                        out->len);
    139
    15
                    r = FIDO_ERR_COMPRESS;
    140
    15
                    goto fail;
    141
    15
            }
    142
    10.8k
            out->len -= zs.avail_out;
    143
    144
    10.8k
            r = FIDO_OK;
    145
    10.8k
    fail:
    146
    10.8k
            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
    10.8k
            if (r != FIDO_OK)
    151
    26
                    fido_blob_reset(out);
    152
    153
    10.8k
            return r;
    154
    10.8k
    }
    155
    156
    int
    157
    fido_compress(fido_blob_t *out, const fido_blob_t *in)
    158
    10.8k
    {
    159
    10.8k
            return rfc1951_deflate(out, in);
    160
    10.8k
    }
    161
    162
    int
    163
    fido_uncompress(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
    164
    33
    {
    165
    33
            if (rfc1950_inflate(out, in, origsiz) == FIDO_OK)
    166
    16
                    return FIDO_OK; /* backwards compat with libfido2 < 1.11 */
    167
    17
            return rfc1951_inflate(out, in, origsiz);
    168
    33
    }