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