10afa8e06SEd Maste /*
2*2ccfa855SEd Maste * Copyright (c) 2020-2022 Yubico AB. All rights reserved.
30afa8e06SEd Maste * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste */
70afa8e06SEd Maste
80afa8e06SEd Maste #include <zlib.h>
90afa8e06SEd Maste #include "fido.h"
100afa8e06SEd Maste
110afa8e06SEd Maste #define BOUND (1024UL * 1024UL)
120afa8e06SEd Maste
13*2ccfa855SEd Maste /* zlib inflate (raw + headers) */
140afa8e06SEd Maste static int
rfc1950_inflate(fido_blob_t * out,const fido_blob_t * in,size_t origsiz)15*2ccfa855SEd Maste rfc1950_inflate(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
160afa8e06SEd Maste {
170afa8e06SEd Maste u_long ilen, olen;
18*2ccfa855SEd Maste int z;
190afa8e06SEd Maste
200afa8e06SEd Maste memset(out, 0, sizeof(*out));
21*2ccfa855SEd Maste
220afa8e06SEd Maste if (in->len > ULONG_MAX || (ilen = (u_long)in->len) > BOUND ||
23*2ccfa855SEd Maste origsiz > ULONG_MAX || (olen = (u_long)origsiz) > BOUND) {
24*2ccfa855SEd Maste fido_log_debug("%s: in->len=%zu, origsiz=%zu", __func__,
25*2ccfa855SEd Maste in->len, origsiz);
260afa8e06SEd Maste return FIDO_ERR_INVALID_ARGUMENT;
27*2ccfa855SEd Maste }
28*2ccfa855SEd Maste
290afa8e06SEd Maste if ((out->ptr = calloc(1, olen)) == NULL)
300afa8e06SEd Maste return FIDO_ERR_INTERNAL;
310afa8e06SEd Maste out->len = olen;
32*2ccfa855SEd Maste
33*2ccfa855SEd Maste if ((z = uncompress(out->ptr, &olen, in->ptr, ilen)) != Z_OK ||
34*2ccfa855SEd Maste olen > SIZE_MAX || olen != out->len) {
35*2ccfa855SEd Maste fido_log_debug("%s: uncompress: %d, olen=%lu, out->len=%zu",
36*2ccfa855SEd Maste __func__, z, olen, out->len);
370afa8e06SEd Maste fido_blob_reset(out);
380afa8e06SEd Maste return FIDO_ERR_COMPRESS;
390afa8e06SEd Maste }
400afa8e06SEd Maste
410afa8e06SEd Maste return FIDO_OK;
420afa8e06SEd Maste }
430afa8e06SEd Maste
44*2ccfa855SEd Maste /* raw inflate */
45*2ccfa855SEd Maste static int
rfc1951_inflate(fido_blob_t * out,const fido_blob_t * in,size_t origsiz)46*2ccfa855SEd Maste rfc1951_inflate(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
47*2ccfa855SEd Maste {
48*2ccfa855SEd Maste z_stream zs;
49*2ccfa855SEd Maste u_int ilen, olen;
50*2ccfa855SEd Maste int r, z;
51*2ccfa855SEd Maste
52*2ccfa855SEd Maste memset(&zs, 0, sizeof(zs));
53*2ccfa855SEd Maste memset(out, 0, sizeof(*out));
54*2ccfa855SEd Maste
55*2ccfa855SEd Maste if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND ||
56*2ccfa855SEd Maste origsiz > UINT_MAX || (olen = (u_int)origsiz) > BOUND) {
57*2ccfa855SEd Maste fido_log_debug("%s: in->len=%zu, origsiz=%zu", __func__,
58*2ccfa855SEd Maste in->len, origsiz);
59*2ccfa855SEd Maste return FIDO_ERR_INVALID_ARGUMENT;
60*2ccfa855SEd Maste }
61*2ccfa855SEd Maste if ((z = inflateInit2(&zs, -MAX_WBITS)) != Z_OK) {
62*2ccfa855SEd Maste fido_log_debug("%s: inflateInit2: %d", __func__, z);
63*2ccfa855SEd Maste return FIDO_ERR_COMPRESS;
64*2ccfa855SEd Maste }
65*2ccfa855SEd Maste
66*2ccfa855SEd Maste if ((out->ptr = calloc(1, olen)) == NULL) {
67*2ccfa855SEd Maste r = FIDO_ERR_INTERNAL;
68*2ccfa855SEd Maste goto fail;
69*2ccfa855SEd Maste }
70*2ccfa855SEd Maste out->len = olen;
71*2ccfa855SEd Maste zs.next_in = in->ptr;
72*2ccfa855SEd Maste zs.avail_in = ilen;
73*2ccfa855SEd Maste zs.next_out = out->ptr;
74*2ccfa855SEd Maste zs.avail_out = olen;
75*2ccfa855SEd Maste
76*2ccfa855SEd Maste if ((z = inflate(&zs, Z_FINISH)) != Z_STREAM_END) {
77*2ccfa855SEd Maste fido_log_debug("%s: inflate: %d", __func__, z);
78*2ccfa855SEd Maste r = FIDO_ERR_COMPRESS;
79*2ccfa855SEd Maste goto fail;
80*2ccfa855SEd Maste }
81*2ccfa855SEd Maste if (zs.avail_out != 0) {
82*2ccfa855SEd Maste fido_log_debug("%s: %u != 0", __func__, zs.avail_out);
83*2ccfa855SEd Maste r = FIDO_ERR_COMPRESS;
84*2ccfa855SEd Maste goto fail;
85*2ccfa855SEd Maste }
86*2ccfa855SEd Maste
87*2ccfa855SEd Maste r = FIDO_OK;
88*2ccfa855SEd Maste fail:
89*2ccfa855SEd Maste if ((z = inflateEnd(&zs)) != Z_OK) {
90*2ccfa855SEd Maste fido_log_debug("%s: inflateEnd: %d", __func__, z);
91*2ccfa855SEd Maste r = FIDO_ERR_COMPRESS;
92*2ccfa855SEd Maste }
93*2ccfa855SEd Maste if (r != FIDO_OK)
94*2ccfa855SEd Maste fido_blob_reset(out);
95*2ccfa855SEd Maste
96*2ccfa855SEd Maste return r;
97*2ccfa855SEd Maste }
98*2ccfa855SEd Maste
99*2ccfa855SEd Maste /* raw deflate */
100*2ccfa855SEd Maste static int
rfc1951_deflate(fido_blob_t * out,const fido_blob_t * in)101*2ccfa855SEd Maste rfc1951_deflate(fido_blob_t *out, const fido_blob_t *in)
102*2ccfa855SEd Maste {
103*2ccfa855SEd Maste z_stream zs;
104*2ccfa855SEd Maste u_int ilen, olen;
105*2ccfa855SEd Maste int r, z;
106*2ccfa855SEd Maste
107*2ccfa855SEd Maste memset(&zs, 0, sizeof(zs));
108*2ccfa855SEd Maste memset(out, 0, sizeof(*out));
109*2ccfa855SEd Maste
110*2ccfa855SEd Maste if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND) {
111*2ccfa855SEd Maste fido_log_debug("%s: in->len=%zu", __func__, in->len);
112*2ccfa855SEd Maste return FIDO_ERR_INVALID_ARGUMENT;
113*2ccfa855SEd Maste }
114*2ccfa855SEd Maste if ((z = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
115*2ccfa855SEd Maste -MAX_WBITS, 8, Z_DEFAULT_STRATEGY)) != Z_OK) {
116*2ccfa855SEd Maste fido_log_debug("%s: deflateInit2: %d", __func__, z);
117*2ccfa855SEd Maste return FIDO_ERR_COMPRESS;
118*2ccfa855SEd Maste }
119*2ccfa855SEd Maste
120*2ccfa855SEd Maste olen = BOUND;
121*2ccfa855SEd Maste if ((out->ptr = calloc(1, olen)) == NULL) {
122*2ccfa855SEd Maste r = FIDO_ERR_INTERNAL;
123*2ccfa855SEd Maste goto fail;
124*2ccfa855SEd Maste }
125*2ccfa855SEd Maste out->len = olen;
126*2ccfa855SEd Maste zs.next_in = in->ptr;
127*2ccfa855SEd Maste zs.avail_in = ilen;
128*2ccfa855SEd Maste zs.next_out = out->ptr;
129*2ccfa855SEd Maste zs.avail_out = olen;
130*2ccfa855SEd Maste
131*2ccfa855SEd Maste if ((z = deflate(&zs, Z_FINISH)) != Z_STREAM_END) {
132*2ccfa855SEd Maste fido_log_debug("%s: inflate: %d", __func__, z);
133*2ccfa855SEd Maste r = FIDO_ERR_COMPRESS;
134*2ccfa855SEd Maste goto fail;
135*2ccfa855SEd Maste }
136*2ccfa855SEd Maste if (zs.avail_out >= out->len) {
137*2ccfa855SEd Maste fido_log_debug("%s: %u > %zu", __func__, zs.avail_out,
138*2ccfa855SEd Maste out->len);
139*2ccfa855SEd Maste r = FIDO_ERR_COMPRESS;
140*2ccfa855SEd Maste goto fail;
141*2ccfa855SEd Maste }
142*2ccfa855SEd Maste out->len -= zs.avail_out;
143*2ccfa855SEd Maste
144*2ccfa855SEd Maste r = FIDO_OK;
145*2ccfa855SEd Maste fail:
146*2ccfa855SEd Maste if ((z = deflateEnd(&zs)) != Z_OK) {
147*2ccfa855SEd Maste fido_log_debug("%s: deflateEnd: %d", __func__, z);
148*2ccfa855SEd Maste r = FIDO_ERR_COMPRESS;
149*2ccfa855SEd Maste }
150*2ccfa855SEd Maste if (r != FIDO_OK)
151*2ccfa855SEd Maste fido_blob_reset(out);
152*2ccfa855SEd Maste
153*2ccfa855SEd Maste return r;
154*2ccfa855SEd Maste }
155*2ccfa855SEd Maste
1560afa8e06SEd Maste int
fido_compress(fido_blob_t * out,const fido_blob_t * in)1570afa8e06SEd Maste fido_compress(fido_blob_t *out, const fido_blob_t *in)
1580afa8e06SEd Maste {
159*2ccfa855SEd Maste return rfc1951_deflate(out, in);
1600afa8e06SEd Maste }
1610afa8e06SEd Maste
1620afa8e06SEd Maste int
fido_uncompress(fido_blob_t * out,const fido_blob_t * in,size_t origsiz)1630afa8e06SEd Maste fido_uncompress(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
1640afa8e06SEd Maste {
165*2ccfa855SEd Maste if (rfc1950_inflate(out, in, origsiz) == FIDO_OK)
166*2ccfa855SEd Maste return FIDO_OK; /* backwards compat with libfido2 < 1.11 */
167*2ccfa855SEd Maste return rfc1951_inflate(out, in, origsiz);
1680afa8e06SEd Maste }
169