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 3 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 License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>
24 /* This file contains the functions which convert the TLS plaintext
25 * packet to TLS compressed packet.
28 #include "gnutls_int.h"
29 #include "gnutls_compress.h"
30 #include "gnutls_errors.h"
31 #include "gnutls_constate.h"
32 #include <algorithms.h>
33 #include <gnutls/gnutls.h>
35 /* Compression Section */
36 #define GNUTLS_COMPRESSION_ENTRY(name, id, wb, ml, cl) \
37 { #name, name, id, wb, ml, cl}
40 #define MAX_COMP_METHODS 5
41 const int _gnutls_comp_algorithms_size
= MAX_COMP_METHODS
;
43 gnutls_compression_entry _gnutls_compression_algorithms
[MAX_COMP_METHODS
] = {
44 GNUTLS_COMPRESSION_ENTRY (GNUTLS_COMP_NULL
, 0x00, 0, 0, 0),
46 /* draft-ietf-tls-compression-02 */
47 GNUTLS_COMPRESSION_ENTRY (GNUTLS_COMP_DEFLATE
, 0x01, 15, 8, 3),
52 static const gnutls_compression_method_t supported_compressions
[] = {
60 #define GNUTLS_COMPRESSION_LOOP(b) \
61 const gnutls_compression_entry *p; \
62 for(p = _gnutls_compression_algorithms; p->name != NULL; p++) { b ; }
63 #define GNUTLS_COMPRESSION_ALG_LOOP(a) \
64 GNUTLS_COMPRESSION_LOOP( if(p->id == algorithm) { a; break; } )
65 #define GNUTLS_COMPRESSION_ALG_LOOP_NUM(a) \
66 GNUTLS_COMPRESSION_LOOP( if(p->num == num) { a; break; } )
68 /* Compression Functions */
71 * gnutls_compression_get_name:
72 * @algorithm: is a Compression algorithm
74 * Convert a #gnutls_compression_method_t value to a string.
76 * Returns: a pointer to a string that contains the name of the
77 * specified compression algorithm, or %NULL.
80 gnutls_compression_get_name (gnutls_compression_method_t algorithm
)
82 const char *ret
= NULL
;
85 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->name
+ sizeof ("GNUTLS_COMP_") - 1);
91 * gnutls_compression_get_id:
92 * @name: is a compression method name
94 * The names are compared in a case insensitive way.
96 * Returns: an id of the specified in a string compression method, or
97 * %GNUTLS_COMP_UNKNOWN on error.
99 gnutls_compression_method_t
100 gnutls_compression_get_id (const char *name
)
102 gnutls_compression_method_t ret
= GNUTLS_COMP_UNKNOWN
;
104 GNUTLS_COMPRESSION_LOOP (if
106 (p
->name
+ sizeof ("GNUTLS_COMP_") - 1,
107 name
) == 0) ret
= p
->id
);
113 * gnutls_compression_list:
115 * Get a list of compression methods.
117 * Returns: a zero-terminated list of #gnutls_compression_method_t
118 * integers indicating the available compression methods.
120 const gnutls_compression_method_t
*
121 gnutls_compression_list (void)
123 return supported_compressions
;
126 /* return the tls number of the specified algorithm */
128 _gnutls_compression_get_num (gnutls_compression_method_t algorithm
)
133 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->num
);
141 get_wbits (gnutls_compression_method_t algorithm
)
145 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->window_bits
);
150 get_mem_level (gnutls_compression_method_t algorithm
)
154 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->mem_level
);
159 get_comp_level (gnutls_compression_method_t algorithm
)
163 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->comp_level
);
169 /* returns the gnutls internal ID of the TLS compression
172 gnutls_compression_method_t
173 _gnutls_compression_get_id (int num
)
175 gnutls_compression_method_t ret
= -1;
178 GNUTLS_COMPRESSION_ALG_LOOP_NUM (ret
= p
->id
);
184 _gnutls_compression_is_ok (gnutls_compression_method_t algorithm
)
187 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->id
);
197 /* For compression */
199 #define MIN_PRIVATE_COMP_ALGO 0xEF
201 /* returns the TLS numbers of the compression methods we support
203 #define SUPPORTED_COMPRESSION_METHODS session->internals.priorities.compression.algorithms
205 _gnutls_supported_compression_methods (gnutls_session_t session
,
206 uint8_t * comp
, size_t comp_size
)
210 if (comp_size
< SUPPORTED_COMPRESSION_METHODS
)
211 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR
);
213 for (i
= j
= 0; i
< SUPPORTED_COMPRESSION_METHODS
; i
++)
216 _gnutls_compression_get_num (session
->internals
.
217 priorities
.compression
.priority
[i
]);
219 /* remove private compression algorithms, if requested.
221 if (tmp
== -1 || (tmp
>= MIN_PRIVATE_COMP_ALGO
&&
222 session
->internals
.enable_private
== 0))
228 comp
[j
] = (uint8_t) tmp
;
235 return GNUTLS_E_NO_COMPRESSION_ALGORITHMS
;
241 /* The flag d is the direction (compress, decompress). Non zero is
244 int _gnutls_comp_init (comp_hd_st
* handle
, gnutls_compression_method_t method
, int d
)
246 handle
->algo
= method
;
247 handle
->handle
= NULL
;
251 case GNUTLS_COMP_DEFLATE
:
254 int window_bits
, mem_level
;
259 window_bits
= get_wbits (method
);
260 mem_level
= get_mem_level (method
);
261 comp_level
= get_comp_level (method
);
263 handle
->handle
= gnutls_malloc (sizeof (z_stream
));
264 if (handle
->handle
== NULL
)
265 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
267 zhandle
= handle
->handle
;
269 zhandle
->zalloc
= (alloc_func
) 0;
270 zhandle
->zfree
= (free_func
) 0;
271 zhandle
->opaque
= (voidpf
) 0;
274 err
= inflateInit2 (zhandle
, window_bits
);
277 err
= deflateInit2 (zhandle
,
278 comp_level
, Z_DEFLATED
,
279 window_bits
, mem_level
, Z_DEFAULT_STRATEGY
);
284 gnutls_free (handle
->handle
);
285 return GNUTLS_E_COMPRESSION_FAILED
;
290 case GNUTLS_COMP_NULL
:
291 case GNUTLS_COMP_UNKNOWN
:
294 return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM
;
300 /* The flag d is the direction (compress, decompress). Non zero is
304 _gnutls_comp_deinit (comp_hd_st
* handle
, int d
)
308 switch (handle
->algo
)
311 case GNUTLS_COMP_DEFLATE
:
314 inflateEnd (handle
->handle
);
316 deflateEnd (handle
->handle
);
323 gnutls_free (handle
->handle
);
324 handle
->handle
= NULL
;
328 /* These functions are memory consuming
332 _gnutls_compress (comp_hd_st
*handle
, const opaque
* plain
,
333 size_t plain_size
, opaque
* compressed
,
334 size_t max_comp_size
)
336 int compressed_size
= GNUTLS_E_COMPRESSION_FAILED
;
338 /* NULL compression is not handled here
343 return GNUTLS_E_INTERNAL_ERROR
;
346 switch (handle
->algo
)
349 case GNUTLS_COMP_DEFLATE
:
354 zhandle
= handle
->handle
;
356 zhandle
->next_in
= (Bytef
*) plain
;
357 zhandle
->avail_in
= plain_size
;
358 zhandle
->next_out
= (Bytef
*) compressed
;
359 zhandle
->avail_out
= max_comp_size
;
361 err
= deflate (zhandle
, Z_SYNC_FLUSH
);
362 if (err
!= Z_OK
|| zhandle
->avail_in
!= 0)
363 return gnutls_assert_val(GNUTLS_E_COMPRESSION_FAILED
);
366 compressed_size
= max_comp_size
- zhandle
->avail_out
;
372 return GNUTLS_E_INTERNAL_ERROR
;
375 #ifdef COMPRESSION_DEBUG
376 _gnutls_debug_log ("Compression ratio: %f\n",
377 (float) ((float) compressed_size
/ (float) plain_size
));
380 return compressed_size
;
386 _gnutls_decompress (comp_hd_st
*handle
, opaque
* compressed
,
387 size_t compressed_size
, opaque
* plain
,
388 size_t max_plain_size
)
390 int plain_size
= GNUTLS_E_DECOMPRESSION_FAILED
;
392 if (compressed_size
> max_plain_size
+ EXTRA_COMP_SIZE
)
395 return GNUTLS_E_DECOMPRESSION_FAILED
;
398 /* NULL compression is not handled here
404 return GNUTLS_E_INTERNAL_ERROR
;
407 switch (handle
->algo
)
410 case GNUTLS_COMP_DEFLATE
:
415 zhandle
= handle
->handle
;
417 zhandle
->next_in
= (Bytef
*) compressed
;
418 zhandle
->avail_in
= compressed_size
;
420 zhandle
->next_out
= (Bytef
*) plain
;
421 zhandle
->avail_out
= max_plain_size
;
422 err
= inflate (zhandle
, Z_SYNC_FLUSH
);
425 return gnutls_assert_val(GNUTLS_E_DECOMPRESSION_FAILED
);
427 plain_size
= max_plain_size
- zhandle
->avail_out
;
433 return GNUTLS_E_INTERNAL_ERROR
;