Merge branch 'vendor/LIBRESSL'
[dragonfly.git] / crypto / libressl / crypto / comp / c_zlib.c
1 /* $OpenBSD: c_zlib.c,v 1.17 2014/11/03 16:58:28 tedu Exp $ */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <openssl/objects.h>
6 #include <openssl/comp.h>
7 #include <openssl/err.h>
8
9 COMP_METHOD *COMP_zlib(void );
10
11 static COMP_METHOD zlib_method_nozlib = {
12         .type = NID_undef,
13         .name = "(undef)"
14 };
15
16 #ifdef ZLIB
17
18 #include <zlib.h>
19
20 static int zlib_stateful_init(COMP_CTX *ctx);
21 static void zlib_stateful_finish(COMP_CTX *ctx);
22 static int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
23     unsigned int olen, unsigned char *in, unsigned int ilen);
24 static int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
25     unsigned int olen, unsigned char *in, unsigned int ilen);
26
27
28 /* memory allocations functions for zlib intialization */
29 static void*
30 zlib_zalloc(void* opaque, unsigned int no, unsigned int size)
31 {
32         return calloc(no, size);
33 }
34
35 static void
36 zlib_zfree(void* opaque, void* address)
37 {
38         free(address);
39 }
40
41 static COMP_METHOD zlib_stateful_method = {
42         .type = NID_zlib_compression,
43         .name = LN_zlib_compression,
44         .init = zlib_stateful_init,
45         .finish = zlib_stateful_finish,
46         .compress = zlib_stateful_compress_block,
47         .expand = zlib_stateful_expand_block
48 };
49
50 struct zlib_state {
51         z_stream istream;
52         z_stream ostream;
53 };
54
55 static int zlib_stateful_ex_idx = -1;
56
57 static int
58 zlib_stateful_init(COMP_CTX *ctx)
59 {
60         int err;
61         struct zlib_state *state = malloc(sizeof(struct zlib_state));
62
63         if (state == NULL)
64                 goto err;
65
66         state->istream.zalloc = zlib_zalloc;
67         state->istream.zfree = zlib_zfree;
68         state->istream.opaque = Z_NULL;
69         state->istream.next_in = Z_NULL;
70         state->istream.next_out = Z_NULL;
71         state->istream.avail_in = 0;
72         state->istream.avail_out = 0;
73         err = inflateInit_(&state->istream, ZLIB_VERSION, sizeof(z_stream));
74         if (err != Z_OK)
75                 goto err;
76
77         state->ostream.zalloc = zlib_zalloc;
78         state->ostream.zfree = zlib_zfree;
79         state->ostream.opaque = Z_NULL;
80         state->ostream.next_in = Z_NULL;
81         state->ostream.next_out = Z_NULL;
82         state->ostream.avail_in = 0;
83         state->ostream.avail_out = 0;
84         err = deflateInit_(&state->ostream, Z_DEFAULT_COMPRESSION,
85             ZLIB_VERSION, sizeof(z_stream));
86         if (err != Z_OK)
87                 goto err;
88
89         CRYPTO_new_ex_data(CRYPTO_EX_INDEX_COMP, ctx, &ctx->ex_data);
90         CRYPTO_set_ex_data(&ctx->ex_data, zlib_stateful_ex_idx, state);
91         return 1;
92
93 err:
94         free(state);
95         return 0;
96 }
97
98 static void
99 zlib_stateful_finish(COMP_CTX *ctx)
100 {
101         struct zlib_state *state =
102             (struct zlib_state *)CRYPTO_get_ex_data(&ctx->ex_data,
103             zlib_stateful_ex_idx);
104
105         inflateEnd(&state->istream);
106         deflateEnd(&state->ostream);
107         free(state);
108         CRYPTO_free_ex_data(CRYPTO_EX_INDEX_COMP, ctx, &ctx->ex_data);
109 }
110
111 static int
112 zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
113     unsigned int olen, unsigned char *in, unsigned int ilen)
114 {
115         int err = Z_OK;
116         struct zlib_state *state =
117             (struct zlib_state *)CRYPTO_get_ex_data(&ctx->ex_data,
118             zlib_stateful_ex_idx);
119
120         if (state == NULL)
121                 return -1;
122
123         state->ostream.next_in = in;
124         state->ostream.avail_in = ilen;
125         state->ostream.next_out = out;
126         state->ostream.avail_out = olen;
127         if (ilen > 0)
128                 err = deflate(&state->ostream, Z_SYNC_FLUSH);
129         if (err != Z_OK)
130                 return -1;
131
132 #ifdef DEBUG_ZLIB
133         fprintf(stderr, "compress(%4d)->%4d %s\n",
134             ilen, olen - state->ostream.avail_out,
135             (ilen != olen - state->ostream.avail_out)?"zlib":"clear");
136 #endif
137
138         return olen - state->ostream.avail_out;
139 }
140
141 static int
142 zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
143     unsigned int olen, unsigned char *in, unsigned int ilen)
144 {
145         int err = Z_OK;
146
147         struct zlib_state *state =
148             (struct zlib_state *)CRYPTO_get_ex_data(&ctx->ex_data,
149             zlib_stateful_ex_idx);
150
151         if (state == NULL)
152                 return 0;
153
154         state->istream.next_in = in;
155         state->istream.avail_in = ilen;
156         state->istream.next_out = out;
157         state->istream.avail_out = olen;
158         if (ilen > 0)
159                 err = inflate(&state->istream, Z_SYNC_FLUSH);
160         if (err != Z_OK)
161                 return -1;
162
163 #ifdef DEBUG_ZLIB
164         fprintf(stderr, "expand(%4d)->%4d %s\n",
165             ilen, olen - state->istream.avail_out,
166             (ilen != olen - state->istream.avail_out)?"zlib":"clear");
167 #endif
168
169         return olen - state->istream.avail_out;
170 }
171
172 #endif
173
174 COMP_METHOD *
175 COMP_zlib(void)
176 {
177         COMP_METHOD *meth = &zlib_method_nozlib;
178
179 #ifdef ZLIB
180         {
181                 /* init zlib_stateful_ex_idx here so that in a multi-process
182                  * application it's enough to intialize openssl before forking
183                  * (idx will be inherited in all the children) */
184                 if (zlib_stateful_ex_idx == -1) {
185                         CRYPTO_w_lock(CRYPTO_LOCK_COMP);
186                         if (zlib_stateful_ex_idx == -1)
187                                 zlib_stateful_ex_idx =
188                             CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_COMP,
189                             0, NULL, NULL, NULL, NULL);
190                         CRYPTO_w_unlock(CRYPTO_LOCK_COMP);
191                         if (zlib_stateful_ex_idx == -1)
192                                 goto err;
193                 }
194
195                 meth = &zlib_stateful_method;
196         }
197
198 err:
199 #endif
200
201         return (meth);
202 }
203
204 void
205 COMP_zlib_cleanup(void)
206 {
207 }
208
209 #ifdef ZLIB
210
211 /* Zlib based compression/decompression filter BIO */
212
213 typedef struct {
214         unsigned char *ibuf;    /* Input buffer */
215         int ibufsize;           /* Buffer size */
216         z_stream zin;           /* Input decompress context */
217         unsigned char *obuf;    /* Output buffer */
218         int obufsize;           /* Output buffer size */
219         unsigned char *optr;    /* Position in output buffer */
220         int ocount;             /* Amount of data in output buffer */
221         int odone;              /* deflate EOF */
222         int comp_level;         /* Compression level to use */
223         z_stream zout;          /* Output compression context */
224 } BIO_ZLIB_CTX;
225
226 #define ZLIB_DEFAULT_BUFSIZE 1024
227
228 static int bio_zlib_new(BIO *bi);
229 static int bio_zlib_free(BIO *bi);
230 static int bio_zlib_read(BIO *b, char *out, int outl);
231 static int bio_zlib_write(BIO *b, const char *in, int inl);
232 static long bio_zlib_ctrl(BIO *b, int cmd, long num, void *ptr);
233 static long bio_zlib_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp);
234
235 static BIO_METHOD bio_meth_zlib = {
236         .type = BIO_TYPE_COMP,
237         .name = "zlib",
238         .bwrite = bio_zlib_write,
239         .bread = bio_zlib_read,
240         .ctrl = bio_zlib_ctrl,
241         .create = bio_zlib_new,
242         .destroy = bio_zlib_free,
243         .callback_ctrl = bio_zlib_callback_ctrl
244 };
245
246 BIO_METHOD *
247 BIO_f_zlib(void)
248 {
249         return &bio_meth_zlib;
250 }
251
252
253 static int
254 bio_zlib_new(BIO *bi)
255 {
256         BIO_ZLIB_CTX *ctx;
257
258         ctx = malloc(sizeof(BIO_ZLIB_CTX));
259         if (!ctx) {
260                 COMPerr(COMP_F_BIO_ZLIB_NEW, ERR_R_MALLOC_FAILURE);
261                 return 0;
262         }
263         ctx->ibuf = NULL;
264         ctx->obuf = NULL;
265         ctx->ibufsize = ZLIB_DEFAULT_BUFSIZE;
266         ctx->obufsize = ZLIB_DEFAULT_BUFSIZE;
267         ctx->zin.zalloc = Z_NULL;
268         ctx->zin.zfree = Z_NULL;
269         ctx->zin.next_in = NULL;
270         ctx->zin.avail_in = 0;
271         ctx->zin.next_out = NULL;
272         ctx->zin.avail_out = 0;
273         ctx->zout.zalloc = Z_NULL;
274         ctx->zout.zfree = Z_NULL;
275         ctx->zout.next_in = NULL;
276         ctx->zout.avail_in = 0;
277         ctx->zout.next_out = NULL;
278         ctx->zout.avail_out = 0;
279         ctx->odone = 0;
280         ctx->comp_level = Z_DEFAULT_COMPRESSION;
281         bi->init = 1;
282         bi->ptr = (char *)ctx;
283         bi->flags = 0;
284         return 1;
285 }
286
287 static int
288 bio_zlib_free(BIO *bi)
289 {
290         BIO_ZLIB_CTX *ctx;
291
292         if (!bi)
293                 return 0;
294         ctx = (BIO_ZLIB_CTX *)bi->ptr;
295         if (ctx->ibuf) {
296                 /* Destroy decompress context */
297                 inflateEnd(&ctx->zin);
298                 free(ctx->ibuf);
299         }
300         if (ctx->obuf) {
301                 /* Destroy compress context */
302                 deflateEnd(&ctx->zout);
303                 free(ctx->obuf);
304         }
305         free(ctx);
306         bi->ptr = NULL;
307         bi->init = 0;
308         bi->flags = 0;
309         return 1;
310 }
311
312 static int
313 bio_zlib_read(BIO *b, char *out, int outl)
314 {
315         BIO_ZLIB_CTX *ctx;
316         int ret;
317         z_stream *zin;
318
319         if (!out || !outl)
320                 return 0;
321         ctx = (BIO_ZLIB_CTX *)b->ptr;
322         zin = &ctx->zin;
323         BIO_clear_retry_flags(b);
324         if (!ctx->ibuf) {
325                 ctx->ibuf = malloc(ctx->ibufsize);
326                 if (!ctx->ibuf) {
327                         COMPerr(COMP_F_BIO_ZLIB_READ, ERR_R_MALLOC_FAILURE);
328                         return 0;
329                 }
330                 inflateInit(zin);
331                 zin->next_in = ctx->ibuf;
332                 zin->avail_in = 0;
333         }
334
335         /* Copy output data directly to supplied buffer */
336         zin->next_out = (unsigned char *)out;
337         zin->avail_out = (unsigned int)outl;
338         for (;;) {
339                 /* Decompress while data available */
340                 while (zin->avail_in) {
341                         ret = inflate(zin, 0);
342                         if ((ret != Z_OK) && (ret != Z_STREAM_END)) {
343                                 COMPerr(COMP_F_BIO_ZLIB_READ,
344                                     COMP_R_ZLIB_INFLATE_ERROR);
345                                 ERR_asprintf_error_data("zlib error:%s",
346                                     zError(ret));
347                                 return 0;
348                         }
349                         /* If EOF or we've read everything then return */
350                         if ((ret == Z_STREAM_END) || !zin->avail_out)
351                                 return outl - zin->avail_out;
352                 }
353
354                 /* No data in input buffer try to read some in,
355                  * if an error then return the total data read.
356                  */
357                 ret = BIO_read(b->next_bio, ctx->ibuf, ctx->ibufsize);
358                 if (ret <= 0) {
359                         /* Total data read */
360                         int tot = outl - zin->avail_out;
361                         BIO_copy_next_retry(b);
362                         if (ret < 0)
363                                 return (tot > 0) ? tot : ret;
364                         return tot;
365                 }
366                 zin->avail_in = ret;
367                 zin->next_in = ctx->ibuf;
368         }
369 }
370
371 static int
372 bio_zlib_write(BIO *b, const char *in, int inl)
373 {
374         BIO_ZLIB_CTX *ctx;
375         int ret;
376         z_stream *zout;
377
378         if (!in || !inl)
379                 return 0;
380         ctx = (BIO_ZLIB_CTX *)b->ptr;
381         if (ctx->odone)
382                 return 0;
383         zout = &ctx->zout;
384         BIO_clear_retry_flags(b);
385         if (!ctx->obuf) {
386                 ctx->obuf = malloc(ctx->obufsize);
387                 /* Need error here */
388                 if (!ctx->obuf) {
389                         COMPerr(COMP_F_BIO_ZLIB_WRITE, ERR_R_MALLOC_FAILURE);
390                         return 0;
391                 }
392                 ctx->optr = ctx->obuf;
393                 ctx->ocount = 0;
394                 deflateInit(zout, ctx->comp_level);
395                 zout->next_out = ctx->obuf;
396                 zout->avail_out = ctx->obufsize;
397         }
398         /* Obtain input data directly from supplied buffer */
399         zout->next_in = (void *)in;
400         zout->avail_in = inl;
401         for (;;) {
402                 /* If data in output buffer write it first */
403                 while (ctx->ocount) {
404                         ret = BIO_write(b->next_bio, ctx->optr, ctx->ocount);
405                         if (ret <= 0) {
406                                 /* Total data written */
407                                 int tot = inl - zout->avail_in;
408                                 BIO_copy_next_retry(b);
409                                 if (ret < 0)
410                                         return (tot > 0) ? tot : ret;
411                                 return tot;
412                         }
413                         ctx->optr += ret;
414                         ctx->ocount -= ret;
415                 }
416
417                 /* Have we consumed all supplied data? */
418                 if (!zout->avail_in)
419                         return inl;
420
421                 /* Compress some more */
422
423                 /* Reset buffer */
424                 ctx->optr = ctx->obuf;
425                 zout->next_out = ctx->obuf;
426                 zout->avail_out = ctx->obufsize;
427                 /* Compress some more */
428                 ret = deflate(zout, 0);
429                 if (ret != Z_OK) {
430                         COMPerr(COMP_F_BIO_ZLIB_WRITE,
431                             COMP_R_ZLIB_DEFLATE_ERROR);
432                         ERR_asprintf_error_data("zlib error:%s", zError(ret));
433                         return 0;
434                 }
435                 ctx->ocount = ctx->obufsize - zout->avail_out;
436         }
437 }
438
439 static int
440 bio_zlib_flush(BIO *b)
441 {
442         BIO_ZLIB_CTX *ctx;
443         int ret;
444         z_stream *zout;
445
446         ctx = (BIO_ZLIB_CTX *)b->ptr;
447         /* If no data written or already flush show success */
448         if (!ctx->obuf || (ctx->odone && !ctx->ocount))
449                 return 1;
450         zout = &ctx->zout;
451         BIO_clear_retry_flags(b);
452         /* No more input data */
453         zout->next_in = NULL;
454         zout->avail_in = 0;
455         for (;;) {
456                 /* If data in output buffer write it first */
457                 while (ctx->ocount) {
458                         ret = BIO_write(b->next_bio, ctx->optr, ctx->ocount);
459                         if (ret <= 0) {
460                                 BIO_copy_next_retry(b);
461                                 return ret;
462                         }
463                         ctx->optr += ret;
464                         ctx->ocount -= ret;
465                 }
466                 if (ctx->odone)
467                         return 1;
468
469                 /* Compress some more */
470
471                 /* Reset buffer */
472                 ctx->optr = ctx->obuf;
473                 zout->next_out = ctx->obuf;
474                 zout->avail_out = ctx->obufsize;
475                 /* Compress some more */
476                 ret = deflate(zout, Z_FINISH);
477                 if (ret == Z_STREAM_END)
478                         ctx->odone = 1;
479                 else if (ret != Z_OK) {
480                         COMPerr(COMP_F_BIO_ZLIB_FLUSH,
481                             COMP_R_ZLIB_DEFLATE_ERROR);
482                         ERR_asprintf_error_data("zlib error:%s", zError(ret));
483                         return 0;
484                 }
485                 ctx->ocount = ctx->obufsize - zout->avail_out;
486         }
487 }
488
489 static long
490 bio_zlib_ctrl(BIO *b, int cmd, long num, void *ptr)
491 {
492         BIO_ZLIB_CTX *ctx;
493         int ret, *ip;
494         int ibs, obs;
495         if (!b->next_bio)
496                 return 0;
497         ctx = (BIO_ZLIB_CTX *)b->ptr;
498         switch (cmd) {
499
500         case BIO_CTRL_RESET:
501                 ctx->ocount = 0;
502                 ctx->odone = 0;
503                 ret = 1;
504                 break;
505
506         case BIO_CTRL_FLUSH:
507                 ret = bio_zlib_flush(b);
508                 if (ret > 0)
509                         ret = BIO_flush(b->next_bio);
510                 break;
511
512         case BIO_C_SET_BUFF_SIZE:
513                 ibs = -1;
514                 obs = -1;
515                 if (ptr != NULL) {
516                         ip = ptr;
517                         if (*ip == 0)
518                                 ibs = (int) num;
519                         else
520                                 obs = (int) num;
521                 } else {
522                         ibs = (int)num;
523                         obs = ibs;
524                 }
525
526                 if (ibs != -1) {
527                         free(ctx->ibuf);
528                         ctx->ibuf = NULL;
529                         ctx->ibufsize = ibs;
530                 }
531
532                 if (obs != -1) {
533                         free(ctx->obuf);
534                         ctx->obuf = NULL;
535                         ctx->obufsize = obs;
536                 }
537                 ret = 1;
538                 break;
539
540         case BIO_C_DO_STATE_MACHINE:
541                 BIO_clear_retry_flags(b);
542                 ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
543                 BIO_copy_next_retry(b);
544                 break;
545
546         default:
547                 ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
548                 break;
549
550         }
551
552         return ret;
553 }
554
555
556 static long
557 bio_zlib_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
558 {
559         if (!b->next_bio)
560                 return 0;
561         return BIO_callback_ctrl(b->next_bio, cmd, fp);
562 }
563
564 #endif