2 * Copyright (C) 2000-2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 /* This file contains the functions which convert the TLS plaintext
24 * packet to TLS compressed packet.
27 #include "gnutls_int.h"
28 #include "gnutls_compress.h"
29 #include "gnutls_errors.h"
30 #include "gnutls_constate.h"
31 #include <algorithms.h>
32 #include <gnutls/gnutls.h>
34 /* Compression Section */
35 #define GNUTLS_COMPRESSION_ENTRY(name, id, wb, ml, cl) \
36 { #name, name, id, wb, ml, cl}
39 #define MAX_COMP_METHODS 5
40 const int _gnutls_comp_algorithms_size
= MAX_COMP_METHODS
;
42 gnutls_compression_entry _gnutls_compression_algorithms
[MAX_COMP_METHODS
] = {
43 GNUTLS_COMPRESSION_ENTRY (GNUTLS_COMP_NULL
, 0x00, 0, 0, 0),
45 /* draft-ietf-tls-compression-02 */
46 GNUTLS_COMPRESSION_ENTRY (GNUTLS_COMP_DEFLATE
, 0x01, 15, 8, 3),
51 static const gnutls_compression_method_t supported_compressions
[] = {
59 #define GNUTLS_COMPRESSION_LOOP(b) \
60 const gnutls_compression_entry *p; \
61 for(p = _gnutls_compression_algorithms; p->name != NULL; p++) { b ; }
62 #define GNUTLS_COMPRESSION_ALG_LOOP(a) \
63 GNUTLS_COMPRESSION_LOOP( if(p->id == algorithm) { a; break; } )
64 #define GNUTLS_COMPRESSION_ALG_LOOP_NUM(a) \
65 GNUTLS_COMPRESSION_LOOP( if(p->num == num) { a; break; } )
67 /* Compression Functions */
70 * gnutls_compression_get_name:
71 * @algorithm: is a Compression algorithm
73 * Convert a #gnutls_compression_method_t value to a string.
75 * Returns: a pointer to a string that contains the name of the
76 * specified compression algorithm, or %NULL.
79 gnutls_compression_get_name (gnutls_compression_method_t algorithm
)
81 const char *ret
= NULL
;
84 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->name
+ sizeof ("GNUTLS_COMP_") - 1);
90 * gnutls_compression_get_id:
91 * @name: is a compression method name
93 * The names are compared in a case insensitive way.
95 * Returns: an id of the specified in a string compression method, or
96 * %GNUTLS_COMP_UNKNOWN on error.
98 gnutls_compression_method_t
99 gnutls_compression_get_id (const char *name
)
101 gnutls_compression_method_t ret
= GNUTLS_COMP_UNKNOWN
;
103 GNUTLS_COMPRESSION_LOOP (if
105 (p
->name
+ sizeof ("GNUTLS_COMP_") - 1,
106 name
) == 0) ret
= p
->id
);
112 * gnutls_compression_list:
114 * Get a list of compression methods.
116 * Returns: a zero-terminated list of #gnutls_compression_method_t
117 * integers indicating the available compression methods.
119 const gnutls_compression_method_t
*
120 gnutls_compression_list (void)
122 return supported_compressions
;
125 /* return the tls number of the specified algorithm */
127 _gnutls_compression_get_num (gnutls_compression_method_t algorithm
)
132 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->num
);
140 get_wbits (gnutls_compression_method_t algorithm
)
144 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->window_bits
);
149 get_mem_level (gnutls_compression_method_t algorithm
)
153 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->mem_level
);
158 get_comp_level (gnutls_compression_method_t algorithm
)
162 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->comp_level
);
168 /* returns the gnutls internal ID of the TLS compression
171 gnutls_compression_method_t
172 _gnutls_compression_get_id (int num
)
174 gnutls_compression_method_t ret
= -1;
177 GNUTLS_COMPRESSION_ALG_LOOP_NUM (ret
= p
->id
);
183 _gnutls_compression_is_ok (gnutls_compression_method_t algorithm
)
186 GNUTLS_COMPRESSION_ALG_LOOP (ret
= p
->id
);
196 /* For compression */
198 #define MIN_PRIVATE_COMP_ALGO 0xEF
200 /* returns the TLS numbers of the compression methods we support
202 #define SUPPORTED_COMPRESSION_METHODS session->internals.priorities.compression.algorithms
204 _gnutls_supported_compression_methods (gnutls_session_t session
,
205 uint8_t * comp
, size_t comp_size
)
209 if (comp_size
< SUPPORTED_COMPRESSION_METHODS
)
210 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR
);
212 for (i
= j
= 0; i
< SUPPORTED_COMPRESSION_METHODS
; i
++)
215 _gnutls_compression_get_num (session
->internals
.
216 priorities
.compression
.priority
[i
]);
218 /* remove private compression algorithms, if requested.
220 if (tmp
== -1 || (tmp
>= MIN_PRIVATE_COMP_ALGO
&&
221 session
->internals
.enable_private
== 0))
227 comp
[j
] = (uint8_t) tmp
;
234 return GNUTLS_E_NO_COMPRESSION_ALGORITHMS
;
240 /* The flag d is the direction (compress, decompress). Non zero is
243 int _gnutls_comp_init (comp_hd_st
* handle
, gnutls_compression_method_t method
, int d
)
245 handle
->algo
= method
;
246 handle
->handle
= NULL
;
250 case GNUTLS_COMP_DEFLATE
:
253 int window_bits
, mem_level
;
258 window_bits
= get_wbits (method
);
259 mem_level
= get_mem_level (method
);
260 comp_level
= get_comp_level (method
);
262 handle
->handle
= gnutls_malloc (sizeof (z_stream
));
263 if (handle
->handle
== NULL
)
264 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
266 zhandle
= handle
->handle
;
268 zhandle
->zalloc
= (alloc_func
) 0;
269 zhandle
->zfree
= (free_func
) 0;
270 zhandle
->opaque
= (voidpf
) 0;
273 err
= inflateInit2 (zhandle
, window_bits
);
276 err
= deflateInit2 (zhandle
,
277 comp_level
, Z_DEFLATED
,
278 window_bits
, mem_level
, Z_DEFAULT_STRATEGY
);
283 gnutls_free (handle
->handle
);
284 return GNUTLS_E_COMPRESSION_FAILED
;
289 case GNUTLS_COMP_NULL
:
290 case GNUTLS_COMP_UNKNOWN
:
293 return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM
;
299 /* The flag d is the direction (compress, decompress). Non zero is
303 _gnutls_comp_deinit (comp_hd_st
* handle
, int d
)
307 switch (handle
->algo
)
310 case GNUTLS_COMP_DEFLATE
:
313 inflateEnd (handle
->handle
);
315 deflateEnd (handle
->handle
);
322 gnutls_free (handle
->handle
);
323 handle
->handle
= NULL
;
327 /* These functions are memory consuming
331 _gnutls_compress (comp_hd_st
*handle
, const uint8_t * plain
,
332 size_t plain_size
, uint8_t * compressed
,
333 size_t max_comp_size
, unsigned int stateless
)
335 int compressed_size
= GNUTLS_E_COMPRESSION_FAILED
;
337 /* NULL compression is not handled here
342 return GNUTLS_E_INTERNAL_ERROR
;
345 switch (handle
->algo
)
348 case GNUTLS_COMP_DEFLATE
:
356 fprintf(stderr
, "FULL FLUSH\n");
362 zhandle
= handle
->handle
;
364 zhandle
->next_in
= (Bytef
*) plain
;
365 zhandle
->avail_in
= plain_size
;
366 zhandle
->next_out
= (Bytef
*) compressed
;
367 zhandle
->avail_out
= max_comp_size
;
369 err
= deflate (zhandle
, type
);
370 if (err
!= Z_OK
|| zhandle
->avail_in
!= 0)
371 return gnutls_assert_val(GNUTLS_E_COMPRESSION_FAILED
);
374 compressed_size
= max_comp_size
- zhandle
->avail_out
;
380 return GNUTLS_E_INTERNAL_ERROR
;
383 #ifdef COMPRESSION_DEBUG
384 _gnutls_debug_log ("Compression ratio: %f\n",
385 (float) ((float) compressed_size
/ (float) plain_size
));
388 return compressed_size
;
394 _gnutls_decompress (comp_hd_st
*handle
, uint8_t * compressed
,
395 size_t compressed_size
, uint8_t * plain
,
396 size_t max_plain_size
)
398 int plain_size
= GNUTLS_E_DECOMPRESSION_FAILED
;
400 if (compressed_size
> max_plain_size
+ EXTRA_COMP_SIZE
)
403 return GNUTLS_E_DECOMPRESSION_FAILED
;
406 /* NULL compression is not handled here
412 return GNUTLS_E_INTERNAL_ERROR
;
415 switch (handle
->algo
)
418 case GNUTLS_COMP_DEFLATE
:
423 zhandle
= handle
->handle
;
425 zhandle
->next_in
= (Bytef
*) compressed
;
426 zhandle
->avail_in
= compressed_size
;
428 zhandle
->next_out
= (Bytef
*) plain
;
429 zhandle
->avail_out
= max_plain_size
;
430 err
= inflate (zhandle
, Z_SYNC_FLUSH
);
433 return gnutls_assert_val(GNUTLS_E_DECOMPRESSION_FAILED
);
435 plain_size
= max_plain_size
- zhandle
->avail_out
;
441 return GNUTLS_E_INTERNAL_ERROR
;