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 2.1 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.
78 const char *gnutls_compression_get_name(gnutls_compression_method_t
81 const char *ret = NULL;
84 GNUTLS_COMPRESSION_ALG_LOOP(ret =
85 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 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 *gnutls_compression_list(void)
121 return supported_compressions;
124 /* return the tls number of the specified algorithm */
125 int _gnutls_compression_get_num(gnutls_compression_method_t algorithm)
130 GNUTLS_COMPRESSION_ALG_LOOP(ret = p->num);
137 static int get_wbits(gnutls_compression_method_t algorithm)
141 GNUTLS_COMPRESSION_ALG_LOOP(ret = p->window_bits);
145 static int get_mem_level(gnutls_compression_method_t algorithm)
149 GNUTLS_COMPRESSION_ALG_LOOP(ret = p->mem_level);
153 static int get_comp_level(gnutls_compression_method_t algorithm)
157 GNUTLS_COMPRESSION_ALG_LOOP(ret = p->comp_level);
163 /* returns the gnutls internal ID of the TLS compression
166 gnutls_compression_method_t _gnutls_compression_get_id(int num)
168 gnutls_compression_method_t ret = -1;
171 GNUTLS_COMPRESSION_ALG_LOOP_NUM(ret = p->id);
176 int _gnutls_compression_is_ok(gnutls_compression_method_t algorithm)
179 GNUTLS_COMPRESSION_ALG_LOOP(ret = p->id);
189 /* For compression */
191 #define MIN_PRIVATE_COMP_ALGO 0xEF
193 /* returns the TLS numbers of the compression methods we support
195 #define SUPPORTED_COMPRESSION_METHODS session->internals.priorities.compression.algorithms
197 _gnutls_supported_compression_methods(gnutls_session_t session,
198 uint8_t * comp, size_t comp_size)
203 if (comp_size < SUPPORTED_COMPRESSION_METHODS)
204 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
206 for (i = j = 0; i < SUPPORTED_COMPRESSION_METHODS; i++) {
207 if (IS_DTLS(session) && session->internals.priorities.compression.priority[i] != GNUTLS_COMP_NULL) {
213 _gnutls_compression_get_num(session->
214 internals.priorities.
215 compression.priority[i]);
217 /* remove private compression algorithms, if requested.
219 if (tmp == -1 || (tmp >= MIN_PRIVATE_COMP_ALGO &&
220 session->internals.enable_private == 0))
226 comp[j] = (uint8_t) tmp;
232 return GNUTLS_E_NO_COMPRESSION_ALGORITHMS;
238 /* The flag d is the direction (compress, decompress). Non zero is
241 int _gnutls_comp_init(comp_hd_st * handle,
242 gnutls_compression_method_t method, int d)
244 handle->algo = method;
245 handle->handle = NULL;
248 case GNUTLS_COMP_DEFLATE:
251 int window_bits, mem_level;
256 window_bits = get_wbits(method);
257 mem_level = get_mem_level(method);
258 comp_level = get_comp_level(method);
260 handle->handle = gnutls_malloc(sizeof(z_stream));
261 if (handle->handle == NULL)
264 (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);
275 err = deflateInit2(zhandle,
276 comp_level, Z_DEFLATED,
277 window_bits, mem_level,
282 gnutls_free(handle->handle);
283 return GNUTLS_E_COMPRESSION_FAILED;
288 case GNUTLS_COMP_NULL:
289 case GNUTLS_COMP_UNKNOWN:
292 return GNUTLS_E_UNKNOWN_COMPRESSION_ALGORITHM;
298 /* The flag d is the direction (compress, decompress). Non zero is
301 void _gnutls_comp_deinit(comp_hd_st * handle, int d)
303 if (handle != NULL) {
304 switch (handle->algo) {
306 case GNUTLS_COMP_DEFLATE:
309 inflateEnd(handle->handle);
311 deflateEnd(handle->handle);
318 gnutls_free(handle->handle);
319 handle->handle = NULL;
323 /* These functions are memory consuming
327 _gnutls_compress(comp_hd_st * handle, const uint8_t * plain,
328 size_t plain_size, uint8_t * compressed,
329 size_t max_comp_size, unsigned int stateless)
331 int compressed_size = GNUTLS_E_COMPRESSION_FAILED;
333 /* NULL compression is not handled here
335 if (handle == NULL) {
337 return GNUTLS_E_INTERNAL_ERROR;
340 switch (handle->algo) {
342 case GNUTLS_COMP_DEFLATE:
353 zhandle = handle->handle;
355 zhandle->next_in = (Bytef *) plain;
356 zhandle->avail_in = plain_size;
357 zhandle->next_out = (Bytef *) compressed;
358 zhandle->avail_out = max_comp_size;
360 err = deflate(zhandle, type);
361 if (err != Z_OK || zhandle->avail_in != 0)
364 (GNUTLS_E_COMPRESSION_FAILED);
368 max_comp_size - zhandle->avail_out;
374 return GNUTLS_E_INTERNAL_ERROR;
377 #ifdef COMPRESSION_DEBUG
378 _gnutls_debug_log("Compression ratio: %f\n",
379 (float) ((float) compressed_size /
380 (float) plain_size));
383 return compressed_size;
389 _gnutls_decompress(comp_hd_st * handle, uint8_t * compressed,
390 size_t compressed_size, uint8_t * plain,
391 size_t max_plain_size)
393 int plain_size = GNUTLS_E_DECOMPRESSION_FAILED;
395 if (compressed_size > max_plain_size + EXTRA_COMP_SIZE) {
397 return GNUTLS_E_DECOMPRESSION_FAILED;
400 /* NULL compression is not handled here
403 if (handle == NULL) {
405 return GNUTLS_E_INTERNAL_ERROR;
408 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);
427 (GNUTLS_E_DECOMPRESSION_FAILED);
429 plain_size = max_plain_size - zhandle->avail_out;
435 return GNUTLS_E_INTERNAL_ERROR;