Use libtasn1 v2.4.
[gnutls.git] / lib / gnutls_compress.c
blob67044ded064bbe3175ce80c06de003d20fb7ca82
1 /*
2 * Copyright (C) 2000, 2004, 2005, 2007, 2008, 2010 Free Software
3 * Foundation, Inc.
5 * Author: Nikos Mavrogiannopoulos
7 * This file is part of GNUTLS.
9 * The GNUTLS library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22 * USA
26 /* This file contains the functions which convert the TLS plaintext
27 * packet to TLS compressed packet.
30 #include "gnutls_int.h"
31 #include "gnutls_compress.h"
32 #include "gnutls_errors.h"
33 #include <gnutls_algorithms.h>
34 #include <gnutls/gnutls.h>
36 /* These functions allocate the return value internally
38 int
39 _gnutls_m_plaintext2compressed (gnutls_session_t session,
40 gnutls_datum_t * compressed,
41 const gnutls_datum_t * plaintext)
43 int size;
44 opaque *data;
46 size =
47 _gnutls_compress (session->connection_state.write_compression_state,
48 plaintext->data, plaintext->size, &data,
49 MAX_RECORD_SEND_SIZE + EXTRA_COMP_SIZE);
50 if (size < 0)
52 gnutls_assert ();
53 return GNUTLS_E_COMPRESSION_FAILED;
55 compressed->data = data;
56 compressed->size = size;
58 return 0;
61 int
62 _gnutls_m_compressed2plaintext (gnutls_session_t session,
63 gnutls_datum_t * plain,
64 const gnutls_datum_t * compressed)
66 int size;
67 opaque *data;
69 size =
70 _gnutls_decompress (session->connection_state.read_compression_state,
71 compressed->data, compressed->size, &data,
72 MAX_RECORD_RECV_SIZE);
73 if (size < 0)
75 gnutls_assert ();
76 return GNUTLS_E_DECOMPRESSION_FAILED;
78 plain->data = data;
79 plain->size = size;
81 return 0;
85 /* Compression Section */
86 #define GNUTLS_COMPRESSION_ENTRY(name, id, wb, ml, cl) \
87 { #name, name, id, wb, ml, cl}
90 #define MAX_COMP_METHODS 5
91 const int _gnutls_comp_algorithms_size = MAX_COMP_METHODS;
93 gnutls_compression_entry _gnutls_compression_algorithms[MAX_COMP_METHODS] = {
94 GNUTLS_COMPRESSION_ENTRY (GNUTLS_COMP_NULL, 0x00, 0, 0, 0),
95 #ifdef HAVE_LIBZ
96 /* draft-ietf-tls-compression-02 */
97 GNUTLS_COMPRESSION_ENTRY (GNUTLS_COMP_DEFLATE, 0x01, 15, 8, 3),
98 #endif
99 {0, 0, 0, 0, 0, 0}
102 static const gnutls_compression_method_t supported_compressions[] = {
103 #ifdef USE_LZO
104 GNUTLS_COMP_LZO,
105 #endif
106 #ifdef HAVE_LIBZ
107 GNUTLS_COMP_DEFLATE,
108 #endif
109 GNUTLS_COMP_NULL,
113 #define GNUTLS_COMPRESSION_LOOP(b) \
114 const gnutls_compression_entry *p; \
115 for(p = _gnutls_compression_algorithms; p->name != NULL; p++) { b ; }
116 #define GNUTLS_COMPRESSION_ALG_LOOP(a) \
117 GNUTLS_COMPRESSION_LOOP( if(p->id == algorithm) { a; break; } )
118 #define GNUTLS_COMPRESSION_ALG_LOOP_NUM(a) \
119 GNUTLS_COMPRESSION_LOOP( if(p->num == num) { a; break; } )
121 /* Compression Functions */
124 * gnutls_compression_get_name - Returns a string with the name of the specified compression algorithm
125 * @algorithm: is a Compression algorithm
127 * Convert a #gnutls_compression_method_t value to a string.
129 * Returns: a pointer to a string that contains the name of the
130 * specified compression algorithm, or %NULL.
132 const char *
133 gnutls_compression_get_name (gnutls_compression_method_t algorithm)
135 const char *ret = NULL;
137 /* avoid prefix */
138 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->name + sizeof ("GNUTLS_COMP_") - 1);
140 return ret;
144 * gnutls_compression_get_id - Returns the gnutls id of the specified in string algorithm
145 * @name: is a compression method name
147 * The names are compared in a case insensitive way.
149 * Returns: an id of the specified in a string compression method, or
150 * %GNUTLS_COMP_UNKNOWN on error.
152 gnutls_compression_method_t
153 gnutls_compression_get_id (const char *name)
155 gnutls_compression_method_t ret = GNUTLS_COMP_UNKNOWN;
157 GNUTLS_COMPRESSION_LOOP (if
158 (strcasecmp
159 (p->name + sizeof ("GNUTLS_COMP_") - 1,
160 name) == 0) ret = p->id);
162 return ret;
166 * gnutls_compression_list - Get a list of supported compression methods
168 * Get a list of compression methods. Note that to be able to use LZO
169 * compression, you must link to libgnutls-extra and call
170 * gnutls_global_init_extra().
172 * Returns: a zero-terminated list of #gnutls_compression_method_t
173 * integers indicating the available compression methods.
175 const gnutls_compression_method_t *
176 gnutls_compression_list (void)
178 return supported_compressions;
181 /* return the tls number of the specified algorithm */
183 _gnutls_compression_get_num (gnutls_compression_method_t algorithm)
185 int ret = -1;
187 /* avoid prefix */
188 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->num);
190 return ret;
193 #ifdef HAVE_LIBZ
195 static int
196 get_wbits (gnutls_compression_method_t algorithm)
198 int ret = -1;
199 /* avoid prefix */
200 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->window_bits);
201 return ret;
204 static int
205 get_mem_level (gnutls_compression_method_t algorithm)
207 int ret = -1;
208 /* avoid prefix */
209 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->mem_level);
210 return ret;
213 static int
214 get_comp_level (gnutls_compression_method_t algorithm)
216 int ret = -1;
217 /* avoid prefix */
218 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->comp_level);
219 return ret;
222 #endif
224 /* returns the gnutls internal ID of the TLS compression
225 * method num
227 gnutls_compression_method_t
228 _gnutls_compression_get_id (int num)
230 gnutls_compression_method_t ret = -1;
232 /* avoid prefix */
233 GNUTLS_COMPRESSION_ALG_LOOP_NUM (ret = p->id);
235 return ret;
239 _gnutls_compression_is_ok (gnutls_compression_method_t algorithm)
241 ssize_t ret = -1;
242 GNUTLS_COMPRESSION_ALG_LOOP (ret = p->id);
243 if (ret >= 0)
244 ret = 0;
245 else
246 ret = 1;
247 return ret;
252 /* For compression */
254 #define MIN_PRIVATE_COMP_ALGO 0xEF
256 /* returns the TLS numbers of the compression methods we support
258 #define SUPPORTED_COMPRESSION_METHODS session->internals.priorities.compression.algorithms
260 _gnutls_supported_compression_methods (gnutls_session_t session,
261 uint8_t ** comp)
263 unsigned int i, j;
265 *comp = gnutls_malloc (sizeof (uint8_t) * SUPPORTED_COMPRESSION_METHODS);
266 if (*comp == NULL)
267 return GNUTLS_E_MEMORY_ERROR;
269 for (i = j = 0; i < SUPPORTED_COMPRESSION_METHODS; i++)
271 int tmp =
272 _gnutls_compression_get_num (session->internals.priorities.
273 compression.priority[i]);
275 /* remove private compression algorithms, if requested.
277 if (tmp == -1 || (tmp >= MIN_PRIVATE_COMP_ALGO &&
278 session->internals.enable_private == 0))
280 gnutls_assert ();
281 continue;
284 (*comp)[j] = (uint8_t) tmp;
285 j++;
288 if (j == 0)
290 gnutls_assert ();
291 gnutls_free (*comp);
292 *comp = NULL;
293 return GNUTLS_E_NO_COMPRESSION_ALGORITHMS;
295 return j;
299 #ifdef USE_LZO
300 # ifdef USE_MINILZO
301 /* Get the prototypes only. Since LZO is a GPLed library, the
302 * gnutls_global_init_extra() has to be called, before LZO compression
303 * can be used.
305 # include "../libextra/minilzo/minilzo.h"
306 # elif HAVE_LZO_LZO1X_H
307 # include <lzo/lzo1x.h>
308 # elif HAVE_LZO1X_H
309 # include <lzo1x.h>
310 # endif
312 typedef int (*LZO_FUNC) ();
314 LZO_FUNC _gnutls_lzo1x_decompress_safe = NULL;
315 LZO_FUNC _gnutls_lzo1x_1_compress = NULL;
317 #endif
319 /* The flag d is the direction (compress, decompress). Non zero is
320 * decompress.
322 comp_hd_t
323 _gnutls_comp_init (gnutls_compression_method_t method, int d)
325 comp_hd_t ret;
327 ret = gnutls_malloc (sizeof (struct comp_hd_t_STRUCT));
328 if (ret == NULL)
330 gnutls_assert ();
331 return NULL;
334 ret->algo = method;
335 ret->handle = NULL;
337 switch (method)
339 case GNUTLS_COMP_DEFLATE:
340 #ifdef HAVE_LIBZ
342 int window_bits, mem_level;
343 int comp_level;
344 z_stream *zhandle;
345 int err;
347 window_bits = get_wbits (method);
348 mem_level = get_mem_level (method);
349 comp_level = get_comp_level (method);
351 ret->handle = gnutls_malloc (sizeof (z_stream));
352 if (ret->handle == NULL)
354 gnutls_assert ();
355 goto cleanup_ret;
358 zhandle = ret->handle;
360 zhandle->zalloc = (alloc_func) 0;
361 zhandle->zfree = (free_func) 0;
362 zhandle->opaque = (voidpf) 0;
364 if (d)
365 err = inflateInit2 (zhandle, window_bits);
366 else
368 err = deflateInit2 (zhandle,
369 comp_level, Z_DEFLATED,
370 window_bits, mem_level, Z_DEFAULT_STRATEGY);
372 if (err != Z_OK)
374 gnutls_assert ();
375 gnutls_free (ret->handle);
376 goto cleanup_ret;
379 break;
380 #endif
381 case GNUTLS_COMP_LZO:
382 #ifdef USE_LZO
383 /* LZO does not use memory on decompressor */
384 if (!d)
386 ret->handle = gnutls_malloc (LZO1X_1_MEM_COMPRESS);
388 if (ret->handle == NULL)
390 gnutls_assert ();
391 goto cleanup_ret;
394 break;
395 #endif
396 case GNUTLS_COMP_NULL:
397 case GNUTLS_COMP_UNKNOWN:
398 break;
401 return ret;
403 cleanup_ret:
404 gnutls_free (ret);
405 return NULL;
408 /* The flag d is the direction (compress, decompress). Non zero is
409 * decompress.
411 void
412 _gnutls_comp_deinit (comp_hd_t handle, int d)
414 if (handle != NULL)
416 switch (handle->algo)
418 #ifdef HAVE_LIBZ
419 case GNUTLS_COMP_DEFLATE:
421 int err;
423 if (d)
424 err = inflateEnd (handle->handle);
425 else
426 err = deflateEnd (handle->handle);
427 break;
429 #endif
430 default:
431 break;
433 gnutls_free (handle->handle);
434 gnutls_free (handle);
439 /* These functions are memory consuming
443 _gnutls_compress (comp_hd_t handle, const opaque * plain,
444 size_t plain_size, opaque ** compressed,
445 size_t max_comp_size)
447 int compressed_size = GNUTLS_E_COMPRESSION_FAILED;
449 /* NULL compression is not handled here
451 if (handle == NULL)
453 gnutls_assert ();
454 return GNUTLS_E_INTERNAL_ERROR;
457 switch (handle->algo)
459 #ifdef USE_LZO
460 case GNUTLS_COMP_LZO:
462 lzo_uint out_len;
463 size_t size;
464 int err;
466 if (_gnutls_lzo1x_1_compress == NULL)
467 return GNUTLS_E_COMPRESSION_FAILED;
469 size = plain_size + plain_size / 64 + 16 + 3;
470 *compressed = gnutls_malloc (size);
471 if (*compressed == NULL)
473 gnutls_assert ();
474 return GNUTLS_E_MEMORY_ERROR;
477 err = _gnutls_lzo1x_1_compress (plain, plain_size, *compressed,
478 &out_len, handle->handle);
480 if (err != LZO_E_OK)
482 gnutls_assert ();
483 gnutls_free (*compressed);
484 *compressed = NULL;
485 return GNUTLS_E_COMPRESSION_FAILED;
488 compressed_size = out_len;
489 break;
491 #endif
492 #ifdef HAVE_LIBZ
493 case GNUTLS_COMP_DEFLATE:
495 uLongf size;
496 z_stream *zhandle;
497 int err;
499 size = (plain_size + plain_size) + 10;
500 *compressed = gnutls_malloc (size);
501 if (*compressed == NULL)
503 gnutls_assert ();
504 return GNUTLS_E_MEMORY_ERROR;
507 zhandle = handle->handle;
509 zhandle->next_in = (Bytef *) plain;
510 zhandle->avail_in = plain_size;
511 zhandle->next_out = (Bytef *) * compressed;
512 zhandle->avail_out = size;
514 err = deflate (zhandle, Z_SYNC_FLUSH);
516 if (err != Z_OK || zhandle->avail_in != 0)
518 gnutls_assert ();
519 gnutls_free (*compressed);
520 *compressed = NULL;
521 return GNUTLS_E_COMPRESSION_FAILED;
524 compressed_size = size - zhandle->avail_out;
525 break;
527 #endif
528 default:
529 gnutls_assert ();
530 return GNUTLS_E_INTERNAL_ERROR;
531 } /* switch */
533 #ifdef COMPRESSION_DEBUG
534 _gnutls_debug_log ("Compression ratio: %f\n",
535 (float) ((float) compressed_size / (float) plain_size));
536 #endif
538 if ((size_t) compressed_size > max_comp_size)
540 gnutls_free (*compressed);
541 *compressed = NULL;
542 return GNUTLS_E_COMPRESSION_FAILED;
545 return compressed_size;
551 _gnutls_decompress (comp_hd_t handle, opaque * compressed,
552 size_t compressed_size, opaque ** plain,
553 size_t max_record_size)
555 int plain_size = GNUTLS_E_DECOMPRESSION_FAILED;
557 if (compressed_size > max_record_size + EXTRA_COMP_SIZE)
559 gnutls_assert ();
560 return GNUTLS_E_DECOMPRESSION_FAILED;
563 /* NULL compression is not handled here
566 if (handle == NULL)
568 gnutls_assert ();
569 return GNUTLS_E_INTERNAL_ERROR;
572 switch (handle->algo)
574 #ifdef USE_LZO
575 case GNUTLS_COMP_LZO:
577 lzo_uint out_size;
578 lzo_uint new_size;
579 int err;
581 if (_gnutls_lzo1x_decompress_safe == NULL)
582 return GNUTLS_E_DECOMPRESSION_FAILED;
584 *plain = NULL;
585 out_size = compressed_size + compressed_size;
586 plain_size = 0;
590 out_size += 512;
591 *plain = gnutls_realloc_fast (*plain, out_size);
592 if (*plain == NULL)
594 gnutls_assert ();
595 return GNUTLS_E_MEMORY_ERROR;
598 new_size = out_size;
599 err =
600 _gnutls_lzo1x_decompress_safe (compressed,
601 compressed_size, *plain,
602 &new_size, NULL);
605 while ((err == LZO_E_OUTPUT_OVERRUN && out_size < max_record_size));
607 if (err != LZO_E_OK)
609 gnutls_assert ();
610 gnutls_free (*plain);
611 *plain = NULL;
612 return GNUTLS_E_DECOMPRESSION_FAILED;
615 plain_size = new_size;
616 break;
618 #endif
619 #ifdef HAVE_LIBZ
620 case GNUTLS_COMP_DEFLATE:
622 uLongf out_size;
623 z_stream *zhandle;
624 int cur_pos;
625 int err;
627 *plain = NULL;
628 out_size = compressed_size + compressed_size;
629 plain_size = 0;
631 zhandle = handle->handle;
633 zhandle->next_in = (Bytef *) compressed;
634 zhandle->avail_in = compressed_size;
636 cur_pos = 0;
640 out_size += 512;
641 *plain = gnutls_realloc_fast (*plain, out_size);
642 if (*plain == NULL)
644 gnutls_assert ();
645 return GNUTLS_E_MEMORY_ERROR;
648 zhandle->next_out = (Bytef *) (*plain + cur_pos);
649 zhandle->avail_out = out_size - cur_pos;
651 err = inflate (zhandle, Z_SYNC_FLUSH);
653 cur_pos = out_size - zhandle->avail_out;
656 while ((err == Z_BUF_ERROR && zhandle->avail_out == 0
657 && out_size < max_record_size)
658 || (err == Z_OK && zhandle->avail_in != 0));
660 if (err != Z_OK)
662 gnutls_assert ();
663 gnutls_free (*plain);
664 *plain = NULL;
665 return GNUTLS_E_DECOMPRESSION_FAILED;
668 plain_size = out_size - zhandle->avail_out;
669 break;
671 #endif
672 default:
673 gnutls_assert ();
674 return GNUTLS_E_INTERNAL_ERROR;
675 } /* switch */
677 if ((size_t) plain_size > max_record_size)
679 gnutls_assert ();
680 gnutls_free (*plain);
681 *plain = NULL;
682 return GNUTLS_E_DECOMPRESSION_FAILED;
685 return plain_size;