Coverage Report

Created: 2026-04-08 06:32

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