Coverage Report

Created: 2023-03-26 07:33

/src/gnutls/lib/compress.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2017-2022 Red Hat, Inc.
3
 *
4
 * Author: Nikos Mavrogiannopoulos
5
 *
6
 * This file is part of GnuTLS.
7
 *
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.
12
 *
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.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
20
 *
21
 */
22
23
#include "compress.h"
24
25
#ifdef HAVE_LIBZ
26
# include <zlib.h>
27
#endif
28
29
#ifdef HAVE_LIBBROTLI
30
# include <brotli/decode.h>
31
# include <brotli/encode.h>
32
#endif
33
34
#ifdef HAVE_LIBZSTD
35
# include <zstd.h>
36
#endif
37
38
typedef struct {
39
  gnutls_compression_method_t id;
40
  const char *name;
41
} comp_entry;
42
43
static const comp_entry comp_algs[] = {
44
  {GNUTLS_COMP_NULL, "NULL"},
45
#ifdef HAVE_LIBZ
46
  {GNUTLS_COMP_ZLIB, "ZLIB"},
47
#endif
48
#ifdef HAVE_LIBBROTLI
49
  {GNUTLS_COMP_BROTLI, "BROTLI"},
50
#endif
51
#ifdef HAVE_LIBZSTD
52
  {GNUTLS_COMP_ZSTD, "ZSTD"},
53
#endif
54
  {GNUTLS_COMP_UNKNOWN, NULL}
55
};
56
57
static const gnutls_compression_method_t alg_list[] = {
58
  GNUTLS_COMP_NULL,
59
#ifdef HAVE_LIBZ
60
  GNUTLS_COMP_ZLIB,
61
#endif
62
#ifdef HAVE_LIBBROTLI
63
  GNUTLS_COMP_BROTLI,
64
#endif
65
#ifdef HAVE_LIBZSTD
66
  GNUTLS_COMP_ZSTD,
67
#endif
68
  0
69
};
70
71
/**
72
 * gnutls_compression_get_name:
73
 * @algorithm: is a Compression algorithm
74
 *
75
 * Convert a #gnutls_compression_method_t value to a string.
76
 *
77
 * Returns: a pointer to a string that contains the name of the
78
 *   specified compression algorithm, or %NULL.
79
 **/
80
const char *gnutls_compression_get_name(gnutls_compression_method_t algorithm)
81
0
{
82
0
  const comp_entry *p;
83
84
0
  for (p = comp_algs; p->name; ++p)
85
0
    if (p->id == algorithm)
86
0
      return p->name;
87
88
0
  return NULL;
89
0
}
90
91
/**
92
 * gnutls_compression_get_id:
93
 * @name: is a compression method name
94
 *
95
 * The names are compared in a case insensitive way.
96
 *
97
 * Returns: an id of the specified in a string compression method, or
98
 *   %GNUTLS_COMP_UNKNOWN on error.
99
 **/
100
gnutls_compression_method_t gnutls_compression_get_id(const char *name)
101
0
{
102
0
  const comp_entry *p;
103
104
0
  for (p = comp_algs; p->name; ++p)
105
0
    if (!strcasecmp(p->name, name))
106
0
      return p->id;
107
108
0
  return GNUTLS_COMP_UNKNOWN;
109
0
}
110
111
/**
112
 * gnutls_compression_list:
113
 *
114
 * Get a list of compression methods.
115
 *
116
 * Returns: a zero-terminated list of #gnutls_compression_method_t
117
 *   integers indicating the available compression methods.
118
 **/
119
const gnutls_compression_method_t *gnutls_compression_list(void)
120
0
{
121
0
  return alg_list;
122
0
}
123
124
/*************************/
125
/* Compression functions */
126
/*************************/
127
128
size_t _gnutls_compress_bound(gnutls_compression_method_t alg, size_t src_len)
129
0
{
130
0
  switch (alg) {
131
0
#ifdef HAVE_LIBZ
132
0
  case GNUTLS_COMP_ZLIB:
133
0
    return compressBound(src_len);
134
0
#endif
135
#ifdef HAVE_LIBBROTLI
136
  case GNUTLS_COMP_BROTLI:
137
    return BrotliEncoderMaxCompressedSize(src_len);
138
#endif
139
#ifdef HAVE_LIBZSTD
140
  case GNUTLS_COMP_ZSTD:
141
    return ZSTD_compressBound(src_len);
142
#endif
143
0
  default:
144
0
    return 0;
145
0
  }
146
0
  return 0;
147
0
}
148
149
int
150
_gnutls_compress(gnutls_compression_method_t alg,
151
     uint8_t * dst, size_t dst_len,
152
     const uint8_t * src, size_t src_len)
153
0
{
154
0
  int ret = GNUTLS_E_COMPRESSION_FAILED;
155
156
0
  switch (alg) {
157
0
#ifdef HAVE_LIBZ
158
0
  case GNUTLS_COMP_ZLIB:
159
0
    {
160
0
      int err;
161
0
      uLongf comp_len = dst_len;
162
163
0
      err = compress(dst, &comp_len, src, src_len);
164
0
      if (err != Z_OK)
165
0
        return
166
0
            gnutls_assert_val
167
0
            (GNUTLS_E_COMPRESSION_FAILED);
168
0
      ret = comp_len;
169
0
    }
170
0
    break;
171
0
#endif
172
#ifdef HAVE_LIBBROTLI
173
  case GNUTLS_COMP_BROTLI:
174
    {
175
      BROTLI_BOOL err;
176
      size_t comp_len = dst_len;
177
178
      err = BrotliEncoderCompress(BROTLI_DEFAULT_QUALITY,
179
                BROTLI_DEFAULT_WINDOW,
180
                BROTLI_DEFAULT_MODE,
181
                src_len, src, &comp_len,
182
                dst);
183
      if (!err)
184
        return
185
            gnutls_assert_val
186
            (GNUTLS_E_COMPRESSION_FAILED);
187
      ret = comp_len;
188
    }
189
    break;
190
#endif
191
#ifdef HAVE_LIBZSTD
192
  case GNUTLS_COMP_ZSTD:
193
    {
194
      size_t comp_len;
195
196
      comp_len =
197
          ZSTD_compress(dst, dst_len, src, src_len,
198
            ZSTD_CLEVEL_DEFAULT);
199
      if (ZSTD_isError(comp_len))
200
        return
201
            gnutls_assert_val
202
            (GNUTLS_E_COMPRESSION_FAILED);
203
      ret = comp_len;
204
    }
205
    break;
206
#endif
207
0
  default:
208
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
209
0
  }
210
211
#ifdef COMPRESSION_DEBUG
212
  _gnutls_debug_log("Compression ratio: %f\n",
213
        (float)((float)ret / (float)src_len));
214
#endif
215
216
0
  return ret;
217
0
}
218
219
int
220
_gnutls_decompress(gnutls_compression_method_t alg,
221
       uint8_t * dst, size_t dst_len,
222
       const uint8_t * src, size_t src_len)
223
0
{
224
0
  int ret = GNUTLS_E_DECOMPRESSION_FAILED;
225
226
0
  switch (alg) {
227
0
#ifdef HAVE_LIBZ
228
0
  case GNUTLS_COMP_ZLIB:
229
0
    {
230
0
      int err;
231
0
      uLongf plain_len = dst_len;
232
233
0
      err = uncompress(dst, &plain_len, src, src_len);
234
0
      if (err != Z_OK)
235
0
        return
236
0
            gnutls_assert_val
237
0
            (GNUTLS_E_DECOMPRESSION_FAILED);
238
0
      ret = plain_len;
239
0
    }
240
0
    break;
241
0
#endif
242
#ifdef HAVE_LIBBROTLI
243
  case GNUTLS_COMP_BROTLI:
244
    {
245
      BrotliDecoderResult err;
246
      size_t plain_len = dst_len;
247
248
      err =
249
          BrotliDecoderDecompress(src_len, src, &plain_len,
250
                dst);
251
      if (err != BROTLI_DECODER_RESULT_SUCCESS)
252
        return
253
            gnutls_assert_val
254
            (GNUTLS_E_DECOMPRESSION_FAILED);
255
      ret = plain_len;
256
    }
257
    break;
258
#endif
259
#ifdef HAVE_LIBZSTD
260
  case GNUTLS_COMP_ZSTD:
261
    {
262
      size_t plain_len;
263
264
      plain_len = ZSTD_decompress(dst, dst_len, src, src_len);
265
      if (ZSTD_isError(plain_len))
266
        return
267
            gnutls_assert_val
268
            (GNUTLS_E_DECOMPRESSION_FAILED);
269
      ret = plain_len;
270
    }
271
    break;
272
#endif
273
0
  default:
274
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
275
0
  }
276
277
0
  return ret;
278
0
}