diff options
Diffstat (limited to 'contrib/libfido2/src/compress.c')
-rw-r--r-- | contrib/libfido2/src/compress.c | 145 |
1 files changed, 132 insertions, 13 deletions
diff --git a/contrib/libfido2/src/compress.c b/contrib/libfido2/src/compress.c index ee5501b4a4a1..3be6fd52fc3f 100644 --- a/contrib/libfido2/src/compress.c +++ b/contrib/libfido2/src/compress.c @@ -1,7 +1,8 @@ /* - * Copyright (c) 2020 Yubico AB. All rights reserved. + * Copyright (c) 2020-2022 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. + * SPDX-License-Identifier: BSD-2-Clause */ #include <zlib.h> @@ -9,41 +10,159 @@ #define BOUND (1024UL * 1024UL) +/* zlib inflate (raw + headers) */ static int -do_compress(fido_blob_t *out, const fido_blob_t *in, size_t origsiz, int decomp) +rfc1950_inflate(fido_blob_t *out, const fido_blob_t *in, size_t origsiz) { u_long ilen, olen; - int r; + int z; memset(out, 0, sizeof(*out)); + if (in->len > ULONG_MAX || (ilen = (u_long)in->len) > BOUND || - origsiz > ULONG_MAX || (olen = decomp ? (u_long)origsiz : - compressBound(ilen)) > BOUND) + origsiz > ULONG_MAX || (olen = (u_long)origsiz) > BOUND) { + fido_log_debug("%s: in->len=%zu, origsiz=%zu", __func__, + in->len, origsiz); return FIDO_ERR_INVALID_ARGUMENT; + } + if ((out->ptr = calloc(1, olen)) == NULL) return FIDO_ERR_INTERNAL; out->len = olen; - if (decomp) - r = uncompress(out->ptr, &olen, in->ptr, ilen); - else - r = compress(out->ptr, &olen, in->ptr, ilen); - if (r != Z_OK || olen > SIZE_MAX || olen > out->len) { + + if ((z = uncompress(out->ptr, &olen, in->ptr, ilen)) != Z_OK || + olen > SIZE_MAX || olen != out->len) { + fido_log_debug("%s: uncompress: %d, olen=%lu, out->len=%zu", + __func__, z, olen, out->len); fido_blob_reset(out); return FIDO_ERR_COMPRESS; } - out->len = olen; return FIDO_OK; } +/* raw inflate */ +static int +rfc1951_inflate(fido_blob_t *out, const fido_blob_t *in, size_t origsiz) +{ + z_stream zs; + u_int ilen, olen; + int r, z; + + memset(&zs, 0, sizeof(zs)); + memset(out, 0, sizeof(*out)); + + if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND || + origsiz > UINT_MAX || (olen = (u_int)origsiz) > BOUND) { + fido_log_debug("%s: in->len=%zu, origsiz=%zu", __func__, + in->len, origsiz); + return FIDO_ERR_INVALID_ARGUMENT; + } + if ((z = inflateInit2(&zs, -MAX_WBITS)) != Z_OK) { + fido_log_debug("%s: inflateInit2: %d", __func__, z); + return FIDO_ERR_COMPRESS; + } + + if ((out->ptr = calloc(1, olen)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto fail; + } + out->len = olen; + zs.next_in = in->ptr; + zs.avail_in = ilen; + zs.next_out = out->ptr; + zs.avail_out = olen; + + if ((z = inflate(&zs, Z_FINISH)) != Z_STREAM_END) { + fido_log_debug("%s: inflate: %d", __func__, z); + r = FIDO_ERR_COMPRESS; + goto fail; + } + if (zs.avail_out != 0) { + fido_log_debug("%s: %u != 0", __func__, zs.avail_out); + r = FIDO_ERR_COMPRESS; + goto fail; + } + + r = FIDO_OK; +fail: + if ((z = inflateEnd(&zs)) != Z_OK) { + fido_log_debug("%s: inflateEnd: %d", __func__, z); + r = FIDO_ERR_COMPRESS; + } + if (r != FIDO_OK) + fido_blob_reset(out); + + return r; +} + +/* raw deflate */ +static int +rfc1951_deflate(fido_blob_t *out, const fido_blob_t *in) +{ + z_stream zs; + u_int ilen, olen; + int r, z; + + memset(&zs, 0, sizeof(zs)); + memset(out, 0, sizeof(*out)); + + if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND) { + fido_log_debug("%s: in->len=%zu", __func__, in->len); + return FIDO_ERR_INVALID_ARGUMENT; + } + if ((z = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, + -MAX_WBITS, 8, Z_DEFAULT_STRATEGY)) != Z_OK) { + fido_log_debug("%s: deflateInit2: %d", __func__, z); + return FIDO_ERR_COMPRESS; + } + + olen = BOUND; + if ((out->ptr = calloc(1, olen)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto fail; + } + out->len = olen; + zs.next_in = in->ptr; + zs.avail_in = ilen; + zs.next_out = out->ptr; + zs.avail_out = olen; + + if ((z = deflate(&zs, Z_FINISH)) != Z_STREAM_END) { + fido_log_debug("%s: inflate: %d", __func__, z); + r = FIDO_ERR_COMPRESS; + goto fail; + } + if (zs.avail_out >= out->len) { + fido_log_debug("%s: %u > %zu", __func__, zs.avail_out, + out->len); + r = FIDO_ERR_COMPRESS; + goto fail; + } + out->len -= zs.avail_out; + + r = FIDO_OK; +fail: + if ((z = deflateEnd(&zs)) != Z_OK) { + fido_log_debug("%s: deflateEnd: %d", __func__, z); + r = FIDO_ERR_COMPRESS; + } + if (r != FIDO_OK) + fido_blob_reset(out); + + return r; +} + int fido_compress(fido_blob_t *out, const fido_blob_t *in) { - return do_compress(out, in, 0, 0); + return rfc1951_deflate(out, in); } int fido_uncompress(fido_blob_t *out, const fido_blob_t *in, size_t origsiz) { - return do_compress(out, in, origsiz, 1); + if (rfc1950_inflate(out, in, origsiz) == FIDO_OK) + return FIDO_OK; /* backwards compat with libfido2 < 1.11 */ + return rfc1951_inflate(out, in, origsiz); } |