1 /* $NetBSD: deflate.c,v 1.21 2011/07/03 01:01:06 mrg 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@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.21 2011/07/03 01:01:06 mrg Exp $"); 39 40 #include <sys/types.h> 41 #include <sys/malloc.h> 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <net/zlib.h> 45 46 #include <opencrypto/cryptodev.h> 47 #include <opencrypto/deflate.h> 48 49 #define ZBUF 10 50 51 struct deflate_buf { 52 u_int8_t *out; 53 u_int32_t size; 54 }; 55 56 int window_inflate = -1 * MAX_WBITS; 57 int window_deflate = -12; 58 59 /* 60 * This function takes a block of data and (de)compress it using the deflate 61 * algorithm 62 */ 63 64 static void * 65 ocf_zalloc(void *nil, u_int type, u_int size) 66 { 67 void *ptr; 68 69 ptr = malloc(type *size, M_CRYPTO_DATA, M_NOWAIT); 70 return ptr; 71 } 72 73 static void 74 ocf_zfree(void *nil, void *ptr) 75 { 76 free(ptr, M_CRYPTO_DATA); 77 } 78 79 u_int32_t 80 deflate_global(u_int8_t *data, u_int32_t size, int decomp, u_int8_t **out, 81 int size_hint) 82 { 83 /* decomp indicates whether we compress (0) or decompress (1) */ 84 85 z_stream zbuf; 86 u_int8_t *output; 87 u_int32_t count, result, tocopy; 88 int error, i, j; 89 struct deflate_buf buf[ZBUF]; 90 91 DPRINTF(("deflate_global: size %d\n", size)); 92 93 memset(&zbuf, 0, sizeof(z_stream)); 94 zbuf.next_in = data; /* data that is going to be processed */ 95 zbuf.zalloc = ocf_zalloc; 96 zbuf.zfree = ocf_zfree; 97 zbuf.opaque = Z_NULL; 98 zbuf.avail_in = size; /* Total length of data to be processed */ 99 100 if (!decomp) { 101 buf[0].size = size; 102 } else { 103 /* 104 * Choose a buffer with 4x the size of the input buffer 105 * for the size of the output buffer in the case of 106 * decompression. If it's not sufficient, it will need to be 107 * updated while the decompression is going on 108 */ 109 110 buf[0].size = MAX(size * 4, size_hint); 111 } 112 buf[0].out = malloc(buf[0].size, M_CRYPTO_DATA, M_NOWAIT); 113 if (buf[0].out == NULL) 114 return 0; 115 i = 1; 116 117 zbuf.next_out = buf[0].out; 118 zbuf.avail_out = buf[0].size; 119 120 error = decomp ? inflateInit2(&zbuf, window_inflate) : 121 deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD, 122 window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY); 123 124 if (error != Z_OK) 125 goto bad2; 126 for (;;) { 127 error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) : 128 deflate(&zbuf, Z_FINISH); 129 if (error == Z_STREAM_END) /* success */ 130 break; 131 /* 132 * XXX compensate for two problems: 133 * -Former versions of this code didn't set Z_FINISH 134 * on compression, so the compressed data are not correctly 135 * terminated and the decompressor doesn't get Z_STREAM_END. 136 * Accept such packets for interoperability. 137 * -sys/net/zlib.c has a bug which makes that Z_BUF_ERROR is 138 * set after successful decompression under rare conditions. 139 */ 140 else if (decomp && (error == Z_OK || error == Z_BUF_ERROR) 141 && zbuf.avail_in == 0 && zbuf.avail_out != 0) 142 break; 143 else if (error != Z_OK) 144 goto bad; 145 else if (zbuf.avail_out == 0) { 146 /* we need more output space, allocate size */ 147 int nextsize = buf[i-1].size * 2; 148 if (i == ZBUF || nextsize > 1000000) 149 goto bad; 150 buf[i].out = malloc(nextsize, M_CRYPTO_DATA, M_NOWAIT); 151 if (buf[i].out == NULL) 152 goto bad; 153 zbuf.next_out = buf[i].out; 154 zbuf.avail_out = buf[i].size = nextsize; 155 i++; 156 } 157 } 158 159 result = count = zbuf.total_out; 160 161 if (i != 1) { /* copy everything into one buffer */ 162 output = malloc(result, M_CRYPTO_DATA, M_NOWAIT); 163 if (output == NULL) 164 goto bad; 165 *out = output; 166 for (j = 0; j < i; j++) { 167 tocopy = MIN(count, buf[j].size); 168 /* XXX the last buf can be empty */ 169 KASSERT(tocopy || j == (i - 1)); 170 memcpy(output, buf[j].out, tocopy); 171 output += tocopy; 172 free(buf[j].out, M_CRYPTO_DATA); 173 count -= tocopy; 174 } 175 KASSERT(count == 0); 176 } else { 177 *out = buf[0].out; 178 } 179 if (decomp) 180 inflateEnd(&zbuf); 181 else 182 deflateEnd(&zbuf); 183 return result; 184 185 bad: 186 if (decomp) 187 inflateEnd(&zbuf); 188 else 189 deflateEnd(&zbuf); 190 bad2: 191 for (j = 0; j < i; j++) 192 free(buf[j].out, M_CRYPTO_DATA); 193 return 0; 194 } 195 196 /* 197 * Initial version will perform a single gzip encapsulation, 198 * filling in the header, 199 * and appending the crc and uncompressed length. 200 * 201 * Later version will support multiple buffers with 202 * a flag indication final buffer. The crc is maintained 203 * over all buffers and appended to the output along with 204 * the uncompressed length after the final data buffer 205 * has been compressed and output. 206 * 207 * Ditto for uncompress - CRC is extracted from the final packed 208 * and compared against CRC of uncompressed data. 209 * 210 */ 211 212 /* constant header for the gzip */ 213 static const char gzip_header[10] = { 214 0x1f, 0x8b, /* ID1 ID2 */ 215 Z_DEFLATED, /* CM */ 216 0, /* FLG */ 217 0, 0, 0, 0, /* MTIME */ 218 0, /* XFL */ 219 0x03 /* OS (Unix) */ 220 }; 221 222 /* Followed by compressed payload */ 223 /* Followed by uint32_t CRC32 and uint32_t ISIZE */ 224 #define GZIP_TAIL_SIZE 8 225 226 u_int32_t 227 gzip_global(u_int8_t *data, u_int32_t size, 228 int decomp, u_int8_t **out, int size_hint) 229 { 230 /* decomp indicates whether we compress (0) or decompress (1) */ 231 z_stream zbuf; 232 u_int8_t *output; 233 u_int32_t count, result; 234 int error, i, j; 235 struct deflate_buf buf[ZBUF]; 236 u_int32_t crc; 237 u_int32_t isize = 0, icrc = 0; 238 239 DPRINTF(("gzip_global: decomp %d, size %d\n", decomp, size)); 240 241 memset(&zbuf, 0, sizeof(z_stream)); 242 zbuf.zalloc = ocf_zalloc; 243 zbuf.zfree = ocf_zfree; 244 zbuf.opaque = Z_NULL; 245 246 if (!decomp) { 247 /* compress */ 248 DPRINTF(("gzip_global: compress malloc %d + %d + %d = %d\n", 249 size, sizeof(gzip_header), GZIP_TAIL_SIZE, 250 size + sizeof(gzip_header) + GZIP_TAIL_SIZE)); 251 252 buf[0].size = size; 253 crc = crc32(0, data, size); 254 DPRINTF(("gzip_compress: size %d, crc 0x%x\n", size, crc)); 255 zbuf.avail_in = size; /* Total length of data to be processed */ 256 zbuf.next_in = data; /* data that is going to be processed */ 257 } else { 258 /* decompress */ 259 /* check the gzip header */ 260 if (size <= sizeof(gzip_header) + GZIP_TAIL_SIZE) { 261 /* Not enough data for the header & tail */ 262 DPRINTF(("gzip_global: not enough data (%d)\n", 263 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(("gzip_global: unsupported gzip header (%02x%02x)\n", 276 data[0], data[1])); 277 return 0; 278 } else { 279 DPRINTF(("gzip_global.%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(("gzip_global: isize = %d (%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 %d, avail_out %d\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:%d out:%d\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:%d out:%d\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(("gzip_global: in %d -> out %d\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(("gzip_global: 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(("gzip_global: 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