2 * Copyright (C) 2000, 2004, 2005, 2007, 2008, 2010 Free Software
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,
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
39 _gnutls_m_plaintext2compressed (gnutls_session_t session
,
40 gnutls_datum_t
* compressed
,
41 const gnutls_datum_t
* plaintext
)
47 _gnutls_compress (session
->connection_state
.write_compression_state
,
48 plaintext
->data
, plaintext
->size
, &data
,
49 MAX_RECORD_SEND_SIZE
+ EXTRA_COMP_SIZE
);
53 return GNUTLS_E_COMPRESSION_FAILED
;
55 compressed
->data
= data
;
56 compressed
->size
= size
;
62 _gnutls_m_compressed2plaintext (gnutls_session_t session
,
63 gnutls_datum_t
* plain
,
64 const gnutls_datum_t
* compressed
)
70 _gnutls_decompress (session
->connection_state
.read_compression_state
,
71 compressed
->data
, compressed
->size
, &data
,
72 MAX_RECORD_RECV_SIZE
);
76 return GNUTLS_E_DECOMPRESSION_FAILED
;
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),
96 /* draft-ietf-tls-compression-02 */
97 GNUTLS_COMPRESSION_ENTRY (GNUTLS_COMP_DEFLATE
, 0x01, 15, 8, 3),
102 static const gnutls_compression_method_t supported_compressions
[] = {
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.
133 gnutls_compression_get_name (gnutls_compression_method_t algorithm
)
135 const char *ret
= NULL
;
138 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->name
+ sizeof ("GNUTLS_COMP_") - 1);
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
159 (p
->name
+ sizeof ("GNUTLS_COMP_") - 1,
160 name
) == 0) ret
= p
->id
);
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
)
188 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->num
);
196 get_wbits (gnutls_compression_method_t algorithm
)
200 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->window_bits
);
205 get_mem_level (gnutls_compression_method_t algorithm
)
209 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->mem_level
);
214 get_comp_level (gnutls_compression_method_t algorithm
)
218 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->comp_level
);
224 /* returns the gnutls internal ID of the TLS compression
227 gnutls_compression_method_t
228 _gnutls_compression_get_id (int num
)
230 gnutls_compression_method_t ret
= -1;
233 GNUTLS_COMPRESSION_ALG_LOOP_NUM (ret
= p
->id
);
239 _gnutls_compression_is_ok (gnutls_compression_method_t algorithm
)
242 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->id
);
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
,
265 *comp
= gnutls_malloc (sizeof (uint8_t) * SUPPORTED_COMPRESSION_METHODS
);
267 return GNUTLS_E_MEMORY_ERROR
;
269 for (i
= j
= 0; i
< SUPPORTED_COMPRESSION_METHODS
; i
++)
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))
284 (*comp
)[j
] = (uint8_t) tmp
;
293 return GNUTLS_E_NO_COMPRESSION_ALGORITHMS
;
301 /* Get the prototypes only. Since LZO is a GPLed library, the
302 * gnutls_global_init_extra() has to be called, before LZO compression
305 # include "../libextra/minilzo/minilzo.h"
306 # elif HAVE_LZO_LZO1X_H
307 # include <lzo/lzo1x.h>
312 typedef int (*LZO_FUNC
) ();
314 LZO_FUNC _gnutls_lzo1x_decompress_safe
= NULL
;
315 LZO_FUNC _gnutls_lzo1x_1_compress
= NULL
;
319 /* The flag d is the direction (compress, decompress). Non zero is
323 _gnutls_comp_init (gnutls_compression_method_t method
, int d
)
327 ret
= gnutls_malloc (sizeof (struct comp_hd_t_STRUCT
));
339 case GNUTLS_COMP_DEFLATE
:
342 int window_bits
, mem_level
;
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
)
358 zhandle
= ret
->handle
;
360 zhandle
->zalloc
= (alloc_func
) 0;
361 zhandle
->zfree
= (free_func
) 0;
362 zhandle
->opaque
= (voidpf
) 0;
365 err
= inflateInit2 (zhandle
, window_bits
);
368 err
= deflateInit2 (zhandle
,
369 comp_level
, Z_DEFLATED
,
370 window_bits
, mem_level
, Z_DEFAULT_STRATEGY
);
375 gnutls_free (ret
->handle
);
381 case GNUTLS_COMP_LZO
:
383 /* LZO does not use memory on decompressor */
386 ret
->handle
= gnutls_malloc (LZO1X_1_MEM_COMPRESS
);
388 if (ret
->handle
== NULL
)
396 case GNUTLS_COMP_NULL
:
397 case GNUTLS_COMP_UNKNOWN
:
408 /* The flag d is the direction (compress, decompress). Non zero is
412 _gnutls_comp_deinit (comp_hd_t handle
, int d
)
416 switch (handle
->algo
)
419 case GNUTLS_COMP_DEFLATE
:
424 err
= inflateEnd (handle
->handle
);
426 err
= deflateEnd (handle
->handle
);
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
454 return GNUTLS_E_INTERNAL_ERROR
;
457 switch (handle
->algo
)
460 case GNUTLS_COMP_LZO
:
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
)
474 return GNUTLS_E_MEMORY_ERROR
;
477 err
= _gnutls_lzo1x_1_compress (plain
, plain_size
, *compressed
,
478 &out_len
, handle
->handle
);
483 gnutls_free (*compressed
);
485 return GNUTLS_E_COMPRESSION_FAILED
;
488 compressed_size
= out_len
;
493 case GNUTLS_COMP_DEFLATE
:
499 size
= (plain_size
+ plain_size
) + 10;
500 *compressed
= gnutls_malloc (size
);
501 if (*compressed
== NULL
)
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)
519 gnutls_free (*compressed
);
521 return GNUTLS_E_COMPRESSION_FAILED
;
524 compressed_size
= size
- zhandle
->avail_out
;
530 return GNUTLS_E_INTERNAL_ERROR
;
533 #ifdef COMPRESSION_DEBUG
534 _gnutls_debug_log ("Compression ratio: %f\n",
535 (float) ((float) compressed_size
/ (float) plain_size
));
538 if ((size_t) compressed_size
> max_comp_size
)
540 gnutls_free (*compressed
);
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
)
560 return GNUTLS_E_DECOMPRESSION_FAILED
;
563 /* NULL compression is not handled here
569 return GNUTLS_E_INTERNAL_ERROR
;
572 switch (handle
->algo
)
575 case GNUTLS_COMP_LZO
:
581 if (_gnutls_lzo1x_decompress_safe
== NULL
)
582 return GNUTLS_E_DECOMPRESSION_FAILED
;
585 out_size
= compressed_size
+ compressed_size
;
591 *plain
= gnutls_realloc_fast (*plain
, out_size
);
595 return GNUTLS_E_MEMORY_ERROR
;
600 _gnutls_lzo1x_decompress_safe (compressed
,
601 compressed_size
, *plain
,
605 while ((err
== LZO_E_OUTPUT_OVERRUN
&& out_size
< max_record_size
));
610 gnutls_free (*plain
);
612 return GNUTLS_E_DECOMPRESSION_FAILED
;
615 plain_size
= new_size
;
620 case GNUTLS_COMP_DEFLATE
:
628 out_size
= compressed_size
+ compressed_size
;
631 zhandle
= handle
->handle
;
633 zhandle
->next_in
= (Bytef
*) compressed
;
634 zhandle
->avail_in
= compressed_size
;
641 *plain
= gnutls_realloc_fast (*plain
, out_size
);
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));
663 gnutls_free (*plain
);
665 return GNUTLS_E_DECOMPRESSION_FAILED
;
668 plain_size
= out_size
- zhandle
->avail_out
;
674 return GNUTLS_E_INTERNAL_ERROR
;
677 if ((size_t) plain_size
> max_record_size
)
680 gnutls_free (*plain
);
682 return GNUTLS_E_DECOMPRESSION_FAILED
;