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 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_constate.h"
34 #include <gnutls_algorithms.h>
35 #include <gnutls/gnutls.h>
37 /* These functions allocate the return value internally
40 _gnutls_m_plaintext2compressed (gnutls_session_t session
,
41 gnutls_datum_t
* compressed
,
42 const gnutls_datum_t
* plaintext
,
43 const record_parameters_st
* params
)
49 _gnutls_compress (params
->write
.compression_state
,
50 plaintext
->data
, plaintext
->size
, &data
,
51 MAX_RECORD_SEND_SIZE
+ EXTRA_COMP_SIZE
);
55 return GNUTLS_E_COMPRESSION_FAILED
;
57 compressed
->data
= data
;
58 compressed
->size
= size
;
64 _gnutls_m_compressed2plaintext (gnutls_session_t session
,
65 gnutls_datum_t
* plain
,
66 const gnutls_datum_t
* compressed
,
67 const record_parameters_st
* params
)
73 _gnutls_decompress (params
->read
.compression_state
,
74 compressed
->data
, compressed
->size
, &data
,
75 MAX_RECORD_RECV_SIZE
);
79 return GNUTLS_E_DECOMPRESSION_FAILED
;
88 /* Compression Section */
89 #define GNUTLS_COMPRESSION_ENTRY(name, id, wb, ml, cl) \
90 { #name, name, id, wb, ml, cl}
93 #define MAX_COMP_METHODS 5
94 const int _gnutls_comp_algorithms_size
= MAX_COMP_METHODS
;
96 gnutls_compression_entry _gnutls_compression_algorithms
[MAX_COMP_METHODS
] = {
97 GNUTLS_COMPRESSION_ENTRY (GNUTLS_COMP_NULL
, 0x00, 0, 0, 0),
99 /* draft-ietf-tls-compression-02 */
100 GNUTLS_COMPRESSION_ENTRY (GNUTLS_COMP_DEFLATE
, 0x01, 15, 8, 3),
105 static const gnutls_compression_method_t supported_compressions
[] = {
116 #define GNUTLS_COMPRESSION_LOOP(b) \
117 const gnutls_compression_entry *p; \
118 for(p = _gnutls_compression_algorithms; p->name != NULL; p++) { b ; }
119 #define GNUTLS_COMPRESSION_ALG_LOOP(a) \
120 GNUTLS_COMPRESSION_LOOP( if(p->id == algorithm) { a; break; } )
121 #define GNUTLS_COMPRESSION_ALG_LOOP_NUM(a) \
122 GNUTLS_COMPRESSION_LOOP( if(p->num == num) { a; break; } )
124 /* Compression Functions */
127 * gnutls_compression_get_name:
128 * @algorithm: is a Compression algorithm
130 * Convert a #gnutls_compression_method_t value to a string.
132 * Returns: a pointer to a string that contains the name of the
133 * specified compression algorithm, or %NULL.
136 gnutls_compression_get_name (gnutls_compression_method_t algorithm
)
138 const char *ret
= NULL
;
141 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->name
+ sizeof ("GNUTLS_COMP_") - 1);
147 * gnutls_compression_get_id:
148 * @name: is a compression method name
150 * The names are compared in a case insensitive way.
152 * Returns: an id of the specified in a string compression method, or
153 * %GNUTLS_COMP_UNKNOWN on error.
155 gnutls_compression_method_t
156 gnutls_compression_get_id (const char *name
)
158 gnutls_compression_method_t ret
= GNUTLS_COMP_UNKNOWN
;
160 GNUTLS_COMPRESSION_LOOP (if
162 (p
->name
+ sizeof ("GNUTLS_COMP_") - 1,
163 name
) == 0) ret
= p
->id
);
169 * gnutls_compression_list:
171 * Get a list of compression methods. Note that to be able to use LZO
172 * compression, you must link to libgnutls-extra and call
173 * gnutls_global_init_extra().
175 * Returns: a zero-terminated list of #gnutls_compression_method_t
176 * integers indicating the available compression methods.
178 const gnutls_compression_method_t
*
179 gnutls_compression_list (void)
181 return supported_compressions
;
184 /* return the tls number of the specified algorithm */
186 _gnutls_compression_get_num (gnutls_compression_method_t algorithm
)
191 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->num
);
199 get_wbits (gnutls_compression_method_t algorithm
)
203 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->window_bits
);
208 get_mem_level (gnutls_compression_method_t algorithm
)
212 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->mem_level
);
217 get_comp_level (gnutls_compression_method_t algorithm
)
221 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->comp_level
);
227 /* returns the gnutls internal ID of the TLS compression
230 gnutls_compression_method_t
231 _gnutls_compression_get_id (int num
)
233 gnutls_compression_method_t ret
= -1;
236 GNUTLS_COMPRESSION_ALG_LOOP_NUM (ret
= p
->id
);
242 _gnutls_compression_is_ok (gnutls_compression_method_t algorithm
)
245 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->id
);
255 /* For compression */
257 #define MIN_PRIVATE_COMP_ALGO 0xEF
259 /* returns the TLS numbers of the compression methods we support
261 #define SUPPORTED_COMPRESSION_METHODS session->internals.priorities.compression.algorithms
263 _gnutls_supported_compression_methods (gnutls_session_t session
,
268 *comp
= gnutls_malloc (sizeof (uint8_t) * SUPPORTED_COMPRESSION_METHODS
);
270 return GNUTLS_E_MEMORY_ERROR
;
272 for (i
= j
= 0; i
< SUPPORTED_COMPRESSION_METHODS
; i
++)
275 _gnutls_compression_get_num (session
->internals
.
276 priorities
.compression
.priority
[i
]);
278 /* remove private compression algorithms, if requested.
280 if (tmp
== -1 || (tmp
>= MIN_PRIVATE_COMP_ALGO
&&
281 session
->internals
.enable_private
== 0))
287 (*comp
)[j
] = (uint8_t) tmp
;
296 return GNUTLS_E_NO_COMPRESSION_ALGORITHMS
;
304 /* Get the prototypes only. Since LZO is a GPLed library, the
305 * gnutls_global_init_extra() has to be called, before LZO compression
308 #include "../libextra/minilzo/minilzo.h"
309 #elif HAVE_LZO_LZO1X_H
310 #include <lzo/lzo1x.h>
315 typedef int (*LZO_FUNC
) ();
317 LZO_FUNC _gnutls_lzo1x_decompress_safe
= NULL
;
318 LZO_FUNC _gnutls_lzo1x_1_compress
= NULL
;
322 /* The flag d is the direction (compress, decompress). Non zero is
326 _gnutls_comp_init (gnutls_compression_method_t method
, int d
)
330 ret
= gnutls_malloc (sizeof (struct comp_hd_t_STRUCT
));
342 case GNUTLS_COMP_DEFLATE
:
345 int window_bits
, mem_level
;
350 window_bits
= get_wbits (method
);
351 mem_level
= get_mem_level (method
);
352 comp_level
= get_comp_level (method
);
354 ret
->handle
= gnutls_malloc (sizeof (z_stream
));
355 if (ret
->handle
== NULL
)
361 zhandle
= ret
->handle
;
363 zhandle
->zalloc
= (alloc_func
) 0;
364 zhandle
->zfree
= (free_func
) 0;
365 zhandle
->opaque
= (voidpf
) 0;
368 err
= inflateInit2 (zhandle
, window_bits
);
371 err
= deflateInit2 (zhandle
,
372 comp_level
, Z_DEFLATED
,
373 window_bits
, mem_level
, Z_DEFAULT_STRATEGY
);
378 gnutls_free (ret
->handle
);
384 case GNUTLS_COMP_LZO
:
386 /* LZO does not use memory on decompressor */
389 ret
->handle
= gnutls_malloc (LZO1X_1_MEM_COMPRESS
);
391 if (ret
->handle
== NULL
)
399 case GNUTLS_COMP_NULL
:
400 case GNUTLS_COMP_UNKNOWN
:
411 /* The flag d is the direction (compress, decompress). Non zero is
415 _gnutls_comp_deinit (comp_hd_t handle
, int d
)
419 switch (handle
->algo
)
422 case GNUTLS_COMP_DEFLATE
:
425 inflateEnd (handle
->handle
);
427 deflateEnd (handle
->handle
);
434 gnutls_free (handle
->handle
);
435 gnutls_free (handle
);
440 /* These functions are memory consuming
444 _gnutls_compress (comp_hd_t handle
, const opaque
* plain
,
445 size_t plain_size
, opaque
** compressed
,
446 size_t max_comp_size
)
448 int compressed_size
= GNUTLS_E_COMPRESSION_FAILED
;
450 /* NULL compression is not handled here
455 return GNUTLS_E_INTERNAL_ERROR
;
458 switch (handle
->algo
)
461 case GNUTLS_COMP_LZO
:
467 if (_gnutls_lzo1x_1_compress
== NULL
)
468 return GNUTLS_E_COMPRESSION_FAILED
;
470 size
= plain_size
+ plain_size
/ 64 + 16 + 3;
471 *compressed
= gnutls_malloc (size
);
472 if (*compressed
== NULL
)
475 return GNUTLS_E_MEMORY_ERROR
;
478 err
= _gnutls_lzo1x_1_compress (plain
, plain_size
, *compressed
,
479 &out_len
, handle
->handle
);
484 gnutls_free (*compressed
);
486 return GNUTLS_E_COMPRESSION_FAILED
;
489 compressed_size
= out_len
;
494 case GNUTLS_COMP_DEFLATE
:
500 size
= (plain_size
+ plain_size
) + 10;
501 *compressed
= gnutls_malloc (size
);
502 if (*compressed
== NULL
)
505 return GNUTLS_E_MEMORY_ERROR
;
508 zhandle
= handle
->handle
;
510 zhandle
->next_in
= (Bytef
*) plain
;
511 zhandle
->avail_in
= plain_size
;
512 zhandle
->next_out
= (Bytef
*) * compressed
;
513 zhandle
->avail_out
= size
;
515 err
= deflate (zhandle
, Z_SYNC_FLUSH
);
517 if (err
!= Z_OK
|| zhandle
->avail_in
!= 0)
520 gnutls_free (*compressed
);
522 return GNUTLS_E_COMPRESSION_FAILED
;
525 compressed_size
= size
- zhandle
->avail_out
;
531 return GNUTLS_E_INTERNAL_ERROR
;
534 #ifdef COMPRESSION_DEBUG
535 _gnutls_debug_log ("Compression ratio: %f\n",
536 (float) ((float) compressed_size
/ (float) plain_size
));
539 if ((size_t) compressed_size
> max_comp_size
)
541 gnutls_free (*compressed
);
543 return GNUTLS_E_COMPRESSION_FAILED
;
546 return compressed_size
;
552 _gnutls_decompress (comp_hd_t handle
, opaque
* compressed
,
553 size_t compressed_size
, opaque
** plain
,
554 size_t max_record_size
)
556 int plain_size
= GNUTLS_E_DECOMPRESSION_FAILED
;
558 if (compressed_size
> max_record_size
+ EXTRA_COMP_SIZE
)
561 return GNUTLS_E_DECOMPRESSION_FAILED
;
564 /* NULL compression is not handled here
570 return GNUTLS_E_INTERNAL_ERROR
;
573 switch (handle
->algo
)
576 case GNUTLS_COMP_LZO
:
582 if (_gnutls_lzo1x_decompress_safe
== NULL
)
583 return GNUTLS_E_DECOMPRESSION_FAILED
;
586 out_size
= compressed_size
+ compressed_size
;
592 *plain
= gnutls_realloc_fast (*plain
, out_size
);
596 return GNUTLS_E_MEMORY_ERROR
;
601 _gnutls_lzo1x_decompress_safe (compressed
,
602 compressed_size
, *plain
,
606 while ((err
== LZO_E_OUTPUT_OVERRUN
&& out_size
< max_record_size
));
611 gnutls_free (*plain
);
613 return GNUTLS_E_DECOMPRESSION_FAILED
;
616 plain_size
= new_size
;
621 case GNUTLS_COMP_DEFLATE
:
629 out_size
= compressed_size
+ compressed_size
;
632 zhandle
= handle
->handle
;
634 zhandle
->next_in
= (Bytef
*) compressed
;
635 zhandle
->avail_in
= compressed_size
;
642 *plain
= gnutls_realloc_fast (*plain
, out_size
);
646 return GNUTLS_E_MEMORY_ERROR
;
649 zhandle
->next_out
= (Bytef
*) (*plain
+ cur_pos
);
650 zhandle
->avail_out
= out_size
- cur_pos
;
652 err
= inflate (zhandle
, Z_SYNC_FLUSH
);
654 cur_pos
= out_size
- zhandle
->avail_out
;
657 while ((err
== Z_BUF_ERROR
&& zhandle
->avail_out
== 0
658 && out_size
< max_record_size
)
659 || (err
== Z_OK
&& zhandle
->avail_in
!= 0));
664 gnutls_free (*plain
);
666 return GNUTLS_E_DECOMPRESSION_FAILED
;
669 plain_size
= out_size
- zhandle
->avail_out
;
675 return GNUTLS_E_INTERNAL_ERROR
;
678 if ((size_t) plain_size
> max_record_size
)
681 gnutls_free (*plain
);
683 return GNUTLS_E_DECOMPRESSION_FAILED
;