Coverage Report

Created: 2022-04-27 14:33

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