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