Coverage Report

Created: 2022-07-22 12:05

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