1 /* $NetBSD: deflate.c,v 1.26 2026/07/05 15:33:44 riastradh Exp $ */ 2 /* $FreeBSD: src/sys/opencrypto/deflate.c,v 1.1.2.1 2002/11/21 23:34:23 sam Exp $ */ 3 /* $OpenBSD: deflate.c,v 1.3 2001/08/20 02:45:22 hugh Exp $ */ 4 5 /* 6 * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj (at) wabbitt.org) 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This file contains a wrapper around the deflate algo compression 34 * functions using the zlib library (see net/zlib.{c,h}) 35 */ 36 37 #include <sys/cdefs.h> 38 __KERNEL_RCSID(0, "$NetBSD: deflate.c,v 1.26 2026/07/05 15:33:44 riastradh Exp $"); 39 40 #include <sys/param.h> 41 #include <sys/types.h> 42 43 #include <net/zlib.h> 44 #include <sys/malloc.h> 45 #include <sys/systm.h> 46 47 #include <opencrypto/cryptodev.h> 48 #include <opencrypto/deflate.h> 49 50 #define ZBUF 10 51 52 struct deflate_buf { 53 uint8_t *out; 54 uint32_t size; 55 }; 56 57 int window_inflate = -1 * MAX_WBITS; 58 int window_deflate = -12; 59 60 /* 61 * This function takes a block of data and (de)compress it using the deflate 62 * algorithm 63 */ 64 65 static void * 66 ocf_zalloc(void *nil, uint32_t type, uint32_t size) 67 { 68 void *ptr; 69 70 ptr = malloc(type *size, M_CRYPTO_DATA, M_NOWAIT); 71 return ptr; 72 } 73 74 static void 75 ocf_zfree(void *nil, void *ptr) 76 { 77 free(ptr, M_CRYPTO_DATA); 78 } 79 80 uint32_t 81 deflate_global(uint8_t *data, uint32_t size, int decomp, uint8_t **out, 82 int size_hint) 83 { 84 /* decomp indicates whether we compress (0) or decompress (1) */ 85 86 z_stream zbuf; 87 uint8_t *output; 88 uint32_t count, result, tocopy; 89 int error, i, j; 90 struct deflate_buf buf[ZBUF]; 91 92 DPRINTF("size %u\n", size); 93 94 memset(&zbuf, 0, sizeof(z_stream)); 95 zbuf.next_in = data; /* data that is going to be processed */ 96 zbuf.zalloc = ocf_zalloc; 97 zbuf.zfree = ocf_zfree; 98 zbuf.opaque = Z_NULL; 99 zbuf.avail_in = size; /* Total length of data to be processed */ 100 101 if (!decomp) { 102 buf[0].size = size; 103 } else { 104 /* 105 * Choose a buffer with 4x the size of the input buffer 106 * for the size of the output buffer in the case of 107 * decompression. If it's not sufficient, it will need to be 108 * updated while the decompression is going on 109 */ 110 111 buf[0].size = MAX(size * 4, size_hint); 112 } 113 buf[0].out = malloc(buf[0].size, M_CRYPTO_DATA, M_NOWAIT); 114 if (buf[0].out == NULL) 115 return 0; 116 i = 1; 117 118 zbuf.next_out = buf[0].out; 119 zbuf.avail_out = buf[0].size; 120 121 error = decomp ? inflateInit2(&zbuf, window_inflate) : 122 deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD, 123 window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY); 124 125 if (error != Z_OK) 126 goto bad2; 127 for (;;) { 128 error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) : 129 deflate(&zbuf, Z_FINISH); 130 if (error == Z_STREAM_END) /* success */ 131 break; 132 /* 133 * XXX compensate for two problems: 134 * -Former versions of this code didn't set Z_FINISH 135 * on compression, so the compressed data are not correctly 136 * terminated and the decompressor doesn't get Z_STREAM_END. 137 * Accept such packets for interoperability. 138 * -sys/net/zlib.c has a bug which makes that Z_BUF_ERROR is 139 * set after successful decompression under rare conditions. 140 */ 141 else if (decomp && (error == Z_OK || error == Z_BUF_ERROR) 142 && zbuf.avail_in == 0 && zbuf.avail_out != 0) 143 break; 144 else if (error != Z_OK) 145 goto bad; 146 else if (zbuf.avail_out == 0) { 147 /* we need more output space, allocate size */ 148 int nextsize = buf[i-1].size * 2; 149 if (i == ZBUF || nextsize > 1000000) 150 goto bad; 151 buf[i].out = malloc(nextsize, M_CRYPTO_DATA, M_NOWAIT); 152 if (buf[i].out == NULL) 153 goto bad; 154 zbuf.next_out = buf[i].out; 155 zbuf.avail_out = buf[i].size = nextsize; 156 i++; 157 } 158 } 159 160 result = count = zbuf.total_out; 161 162 if (i != 1) { /* copy everything into one buffer */ 163 output = malloc(result, M_CRYPTO_DATA, M_NOWAIT); 164 if (output == NULL) 165 goto bad; 166 *out = output; 167 for (j = 0; j < i; j++) { 168 tocopy = MIN(count, buf[j].size); 169 /* XXX the last buf can be empty */ 170 KASSERT(tocopy || j == (i - 1)); 171 memcpy(output, buf[j].out, tocopy); 172 output += tocopy; 173 free(buf[j].out, M_CRYPTO_DATA); 174 count -= tocopy; 175 } 176 KASSERT(count == 0); 177 } else { 178 *out = buf[0].out; 179 } 180 if (decomp) 181 inflateEnd(&zbuf); 182 else 183 deflateEnd(&zbuf); 184 return result; 185 186 bad: 187 if (decomp) 188 inflateEnd(&zbuf); 189 else 190 deflateEnd(&zbuf); 191 bad2: 192 for (j = 0; j < i; j++) 193 free(buf[j].out, M_CRYPTO_DATA); 194 return 0; 195 } 196 197 /* 198 * Initial version will perform a single gzip encapsulation, 199 * filling in the header, 200 * and appending the crc and uncompressed length. 201 * 202 * Later version will support multiple buffers with 203 * a flag indication final buffer. The crc is maintained 204 * over all buffers and appended to the output along with 205 * the uncompressed length after the final data buffer 206 * has been compressed and output. 207 * 208 * Ditto for uncompress - CRC is extracted from the final packed 209 * and compared against CRC of uncompressed data. 210 * 211 */ 212 213 /* constant header for the gzip */ 214 static const char gzip_header[10] = { 215 0x1f, 0x8b, /* ID1 ID2 */ 216 Z_DEFLATED, /* CM */ 217 0, /* FLG */ 218 0, 0, 0, 0, /* MTIME */ 219 0, /* XFL */ 220 0x03 /* OS (Unix) */ 221 }; 222 223 /* Followed by compressed payload */ 224 /* Followed by uint32_t CRC32 and uint32_t ISIZE */ 225 #define GZIP_TAIL_SIZE 8 226 227 uint32_t 228 gzip_global(uint8_t *data, uint32_t size, 229 int decomp, uint8_t **out, int size_hint) 230 { 231 /* decomp indicates whether we compress (0) or decompress (1) */ 232 z_stream zbuf; 233 uint8_t *output; 234 uint32_t count, result; 235 int error, i, j; 236 struct deflate_buf buf[ZBUF]; 237 uint32_t crc; 238 uint32_t isize = 0, icrc = 0; 239 240 DPRINTF("decomp %d, size %u\n", decomp, size); 241 242 memset(&zbuf, 0, sizeof(z_stream)); 243 zbuf.zalloc = ocf_zalloc; 244 zbuf.zfree = ocf_zfree; 245 zbuf.opaque = Z_NULL; 246 247 if (!decomp) { 248 /* compress */ 249 DPRINTF("compress malloc %u + %zu + %u = %zu\n", 250 size, sizeof(gzip_header), GZIP_TAIL_SIZE, 251 size + sizeof(gzip_header) + GZIP_TAIL_SIZE); 252 253 buf[0].size = size; 254 crc = crc32(0, data, size); 255 DPRINTF("size %u, crc 0x%x\n", size, crc); 256 zbuf.avail_in = size; /* Total length of data to be processed */ 257 zbuf.next_in = data; /* data that is going to be processed */ 258 } else { 259 /* decompress */ 260 /* check the gzip header */ 261 if (size <= sizeof(gzip_header) + GZIP_TAIL_SIZE) { 262 /* Not enough data for the header & tail */ 263 DPRINTF("not enough data (%u)\n", size); 264 return 0; 265 } 266 267 /* XXX this is pretty basic, 268 * needs to be expanded to ignore MTIME, OS, 269 * but still ensure flags are 0. 270 * Q. Do we need to support the flags and 271 * optional header fields? Likely. 272 * XXX add flag and field support too. 273 */ 274 if (memcmp(data, gzip_header, sizeof(gzip_header)) != 0) { 275 DPRINTF("unsupported gzip header (%02x%02x)\n", 276 data[0], data[1]); 277 return 0; 278 } else { 279 DPRINTF("%d: gzip header ok\n",__LINE__); 280 } 281 282 memcpy(&isize, &data[size-sizeof(uint32_t)], sizeof(uint32_t)); 283 LE32TOH(isize); 284 memcpy(&icrc, &data[size-2*sizeof(uint32_t)], sizeof(uint32_t)); 285 LE32TOH(icrc); 286 287 DPRINTF("isize = %u (%02x %02x %02x %02x)\n", 288 isize, 289 data[size-4], 290 data[size-3], 291 data[size-2], 292 data[size-1]); 293 294 buf[0].size = isize; 295 crc = crc32(0, NULL, 0); /* get initial crc value */ 296 297 /* skip over the gzip header */ 298 zbuf.next_in = data + sizeof(gzip_header); 299 300 /* actual payload size stripped of gzip header and tail */ 301 zbuf.avail_in = size - sizeof(gzip_header) - GZIP_TAIL_SIZE; 302 } 303 304 buf[0].out = malloc(buf[0].size, M_CRYPTO_DATA, M_NOWAIT); 305 if (buf[0].out == NULL) 306 return 0; 307 zbuf.next_out = buf[0].out; 308 zbuf.avail_out = buf[0].size; 309 DPRINTF("zbuf avail_in %u, avail_out %u\n", 310 zbuf.avail_in, zbuf.avail_out); 311 i = 1; 312 313 error = decomp ? inflateInit2(&zbuf, window_inflate) : 314 deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD, 315 window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY); 316 317 if (error != Z_OK) { 318 printf("deflateInit2() failed\n"); 319 goto bad2; 320 } 321 for (;;) { 322 DPRINTF("pre: %s in:%u out:%u\n", decomp ? "deflate()" : "inflate()", 323 zbuf.avail_in, zbuf.avail_out); 324 error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) : 325 deflate(&zbuf, Z_FINISH); 326 DPRINTF("post: %s in:%u out:%u\n", decomp ? "deflate()" : "inflate()", 327 zbuf.avail_in, zbuf.avail_out); 328 if (error == Z_STREAM_END) /* success */ 329 break; 330 /* 331 * XXX compensate for a zlib problem: 332 * -sys/net/zlib.c has a bug which makes that Z_BUF_ERROR is 333 * set after successful decompression under rare conditions. 334 */ 335 else if (decomp && error == Z_BUF_ERROR 336 && zbuf.avail_in == 0 && zbuf.avail_out != 0) 337 break; 338 else if (error != Z_OK) 339 goto bad; 340 else if (zbuf.avail_out == 0) { 341 /* we need more output space, allocate size */ 342 int nextsize = buf[i-1].size * 2; 343 if (i == ZBUF || nextsize > 1000000) 344 goto bad; 345 buf[i].out = malloc(nextsize, M_CRYPTO_DATA, M_NOWAIT); 346 if (buf[i].out == NULL) 347 goto bad; 348 zbuf.next_out = buf[i].out; 349 zbuf.avail_out = buf[i].size = nextsize; 350 i++; 351 } 352 } 353 354 if (decomp) { 355 count = result = zbuf.total_out; 356 } else { 357 /* need room for header, CRC, and ISIZE */ 358 result = zbuf.total_out + sizeof(gzip_header) + GZIP_TAIL_SIZE; 359 count = zbuf.total_out; 360 } 361 362 DPRINTF("in %u -> out %u\n", size, result); 363 364 *out = malloc(result, M_CRYPTO_DATA, M_NOWAIT); 365 if (*out == NULL) 366 goto bad; 367 output = *out; 368 if (decomp) 369 inflateEnd(&zbuf); 370 else { 371 deflateEnd(&zbuf); 372 373 /* fill in gzip header */ 374 memcpy(output, gzip_header, sizeof(gzip_header)); 375 output += sizeof(gzip_header); 376 } 377 for (j = 0; j < i; j++) { 378 if (decomp) { 379 /* update crc for decompressed data */ 380 crc = crc32(crc, buf[j].out, MIN(count, buf[j].size)); 381 } 382 if (count > buf[j].size) { 383 memcpy(output, buf[j].out, buf[j].size); 384 output += buf[j].size; 385 free(buf[j].out, M_CRYPTO_DATA); 386 count -= buf[j].size; 387 } else { 388 /* it should be the last buffer */ 389 memcpy(output, buf[j].out, count); 390 output += count; 391 free(buf[j].out, M_CRYPTO_DATA); 392 count = 0; 393 } 394 } 395 396 if (!decomp) { 397 /* fill in CRC and ISIZE */ 398 HTOLE32(crc); 399 memcpy(output, &crc, sizeof(uint32_t)); 400 HTOLE32(size); 401 memcpy(output + sizeof(uint32_t), &size, sizeof(uint32_t)); 402 403 DPRINTF("size = 0x%x (%02x %02x %02x %02x)\n", 404 size, 405 output[7], 406 output[3], 407 output[5], 408 output[4]); 409 } else { 410 if (crc != icrc || result != isize) { 411 DPRINTF("crc/size mismatch\n"); 412 free(*out, M_CRYPTO_DATA); 413 *out = NULL; 414 return 0; 415 } 416 } 417 418 return result; 419 420 bad: 421 if (decomp) 422 inflateEnd(&zbuf); 423 else 424 deflateEnd(&zbuf); 425 bad2: 426 *out = NULL; 427 for (j = 0; j < i; j++) 428 free(buf[j].out, M_CRYPTO_DATA); 429 return 0; 430 } 431