Coverage Report

Created: 2024-06-20 06:28

/src/gnutls/lib/cipher_int.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2009-2013 Free Software Foundation, Inc.
3
 * Copyright (C) 2013 Nikos Mavrogiannopoulos
4
 *
5
 * Author: Nikos Mavrogiannopoulos
6
 *
7
 * This file is part of GnuTLS.
8
 *
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.
13
 *
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.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
21
 *
22
 */
23
24
#include "gnutls_int.h"
25
#include "errors.h"
26
#include "cipher_int.h"
27
#include "datum.h"
28
#include <gnutls/crypto.h>
29
#include "crypto.h"
30
#include "fips.h"
31
#include "algorithms.h"
32
33
#define SR_FB(x, cleanup)                                       \
34
0
  ret = (x);                                              \
35
0
  if (ret < 0) {                                          \
36
0
    if (ret == GNUTLS_E_NEED_FALLBACK) {            \
37
0
      if (handle->handle)                     \
38
0
        handle->deinit(handle->handle); \
39
0
      goto fallback;                          \
40
0
    }                                               \
41
0
    gnutls_assert();                                \
42
0
    ret = GNUTLS_E_INTERNAL_ERROR;                  \
43
0
    goto cleanup;                                   \
44
0
  }
45
46
#define SR(x, cleanup)                         \
47
0
  if ((x) < 0) {                         \
48
0
    gnutls_assert();               \
49
0
    ret = GNUTLS_E_INTERNAL_ERROR; \
50
0
    goto cleanup;                  \
51
0
  }
52
53
/* Returns true(non-zero) or false(0) if the 
54
 * provided cipher exists
55
 */
56
int _gnutls_cipher_exists(gnutls_cipher_algorithm_t cipher)
57
0
{
58
0
  const gnutls_crypto_cipher_st *cc;
59
0
  int ret;
60
61
0
  if (!is_cipher_algo_allowed(cipher))
62
0
    return 0;
63
64
  /* All the other ciphers are disabled on the back-end library.
65
   * The NULL needs to be detected here as it is not a cipher
66
   * that is provided by the back-end.
67
   */
68
0
  if (cipher == GNUTLS_CIPHER_NULL)
69
0
    return 1;
70
71
0
  cc = _gnutls_get_crypto_cipher(cipher);
72
0
  if (cc != NULL)
73
0
    return 1;
74
75
0
  ret = _gnutls_cipher_ops.exists(cipher);
76
0
  return ret;
77
0
}
78
79
int _gnutls_cipher_init(cipher_hd_st *handle, const cipher_entry_st *e,
80
      const gnutls_datum_t *key, const gnutls_datum_t *iv,
81
      int enc)
82
0
{
83
0
  int ret = GNUTLS_E_INTERNAL_ERROR;
84
0
  const gnutls_crypto_cipher_st *cc = NULL;
85
86
0
  if (unlikely(e == NULL || e->id == GNUTLS_CIPHER_NULL))
87
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
88
89
0
  FAIL_IF_LIB_ERROR;
90
91
0
  handle->e = e;
92
0
  handle->handle = NULL;
93
94
  /* check if a cipher has been registered
95
   */
96
0
  cc = _gnutls_get_crypto_cipher(e->id);
97
0
  if (cc != NULL) {
98
0
    handle->encrypt = cc->encrypt;
99
0
    handle->decrypt = cc->decrypt;
100
0
    handle->aead_encrypt = cc->aead_encrypt;
101
0
    handle->aead_decrypt = cc->aead_decrypt;
102
0
    handle->deinit = cc->deinit;
103
0
    handle->auth = cc->auth;
104
0
    handle->tag = cc->tag;
105
0
    handle->setiv = cc->setiv;
106
0
    handle->getiv = cc->getiv;
107
0
    handle->setkey = cc->setkey;
108
109
    /* if cc->init() returns GNUTLS_E_NEED_FALLBACK we
110
     * use the default ciphers */
111
0
    SR_FB(cc->init(e->id, &handle->handle, enc), cc_cleanup);
112
0
    SR_FB(cc->setkey(handle->handle, key->data, key->size),
113
0
          cc_cleanup);
114
0
    if (iv) {
115
      /* the API doesn't accept IV */
116
0
      if (unlikely(cc->setiv == NULL)) {
117
0
        if (cc->aead_encrypt) {
118
0
          if (handle->handle)
119
0
            handle->deinit(handle->handle);
120
0
          goto fallback;
121
0
        }
122
0
        return gnutls_assert_val(
123
0
          GNUTLS_E_INVALID_REQUEST);
124
0
      }
125
0
      SR(cc->setiv(handle->handle, iv->data, iv->size),
126
0
         cc_cleanup);
127
0
    }
128
129
0
    return 0;
130
0
  }
131
132
0
fallback:
133
0
  handle->encrypt = _gnutls_cipher_ops.encrypt;
134
0
  handle->decrypt = _gnutls_cipher_ops.decrypt;
135
0
  handle->aead_encrypt = _gnutls_cipher_ops.aead_encrypt;
136
0
  handle->aead_decrypt = _gnutls_cipher_ops.aead_decrypt;
137
0
  handle->deinit = _gnutls_cipher_ops.deinit;
138
0
  handle->auth = _gnutls_cipher_ops.auth;
139
0
  handle->tag = _gnutls_cipher_ops.tag;
140
0
  handle->setiv = _gnutls_cipher_ops.setiv;
141
0
  handle->getiv = _gnutls_cipher_ops.getiv;
142
0
  handle->setkey = _gnutls_cipher_ops.setkey;
143
144
  /* otherwise use generic cipher interface
145
   */
146
0
  ret = _gnutls_cipher_ops.init(e->id, &handle->handle, enc);
147
0
  if (ret < 0) {
148
0
    gnutls_assert();
149
0
    return ret;
150
0
  }
151
152
0
  ret = _gnutls_cipher_ops.setkey(handle->handle, key->data, key->size);
153
0
  if (ret < 0) {
154
0
    gnutls_assert();
155
0
    goto cc_cleanup;
156
0
  }
157
158
0
  if (iv) {
159
0
    ret = _gnutls_cipher_ops.setiv(handle->handle, iv->data,
160
0
                 iv->size);
161
0
    if (ret < 0) {
162
0
      gnutls_assert();
163
0
      goto cc_cleanup;
164
0
    }
165
0
  }
166
167
0
  return 0;
168
169
0
cc_cleanup:
170
171
0
  if (handle->handle)
172
0
    handle->deinit(handle->handle);
173
174
0
  return ret;
175
0
}
176
177
/* Auth_cipher API 
178
 */
179
int _gnutls_auth_cipher_init(auth_cipher_hd_st *handle,
180
           const cipher_entry_st *e,
181
           const gnutls_datum_t *cipher_key,
182
           const gnutls_datum_t *iv, const mac_entry_st *me,
183
           const gnutls_datum_t *mac_key, unsigned etm,
184
#ifdef ENABLE_SSL3
185
           unsigned ssl_hmac,
186
#endif
187
           int enc)
188
0
{
189
0
  int ret;
190
191
0
  if (unlikely(e == NULL))
192
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
193
194
0
  FAIL_IF_LIB_ERROR;
195
196
0
  memset(handle, 0, sizeof(*handle));
197
0
  handle->etm = etm;
198
199
0
  if (e->id != GNUTLS_CIPHER_NULL) {
200
0
    handle->non_null = 1;
201
0
    ret = _gnutls_cipher_init(&handle->cipher, e, cipher_key, iv,
202
0
            enc);
203
0
    if (ret < 0)
204
0
      return gnutls_assert_val(ret);
205
0
  } else
206
0
    handle->non_null = 0;
207
208
0
  if (me->id != GNUTLS_MAC_AEAD) {
209
0
    handle->is_mac = 1;
210
#ifdef ENABLE_SSL3
211
    handle->ssl_hmac = ssl_hmac;
212
213
    if (ssl_hmac)
214
      ret = _gnutls_mac_init_ssl3(&handle->mac.dig, me,
215
                mac_key->data,
216
                mac_key->size);
217
    else
218
#endif
219
0
      ret = _gnutls_mac_init(&handle->mac.mac, me,
220
0
                 mac_key->data, mac_key->size);
221
0
    if (ret < 0) {
222
0
      gnutls_assert();
223
0
      goto cleanup;
224
0
    }
225
0
#ifdef ENABLE_GOST
226
0
    handle->continuous_mac =
227
0
      !!(me->flags & GNUTLS_MAC_FLAG_CONTINUOUS_MAC);
228
0
#endif
229
230
0
    handle->tag_size = _gnutls_mac_get_algo_len(me);
231
0
  } else if (_gnutls_cipher_algo_is_aead(e)) {
232
0
    handle->tag_size = _gnutls_cipher_get_tag_size(e);
233
0
  } else {
234
0
    gnutls_assert();
235
0
    ret = GNUTLS_E_INVALID_REQUEST;
236
0
    goto cleanup;
237
0
  }
238
239
0
  return 0;
240
0
cleanup:
241
0
  if (handle->non_null != 0)
242
0
    _gnutls_cipher_deinit(&handle->cipher);
243
0
  return ret;
244
0
}
245
246
#ifdef ENABLE_SSL3
247
#define MAC(handle, text, textlen)                                   \
248
  if (handle->ssl_hmac) {                                      \
249
    ret = _gnutls_hash(&handle->mac.dig, text, textlen); \
250
  } else {                                                     \
251
    ret = _gnutls_mac(&handle->mac.mac, text, textlen);  \
252
  }                                                            \
253
  if (unlikely(ret < 0))                                       \
254
  return gnutls_assert_val(ret)
255
#else
256
#define MAC(handle, text, textlen)                          \
257
0
  ret = _gnutls_mac(&handle->mac.mac, text, textlen); \
258
0
  if (unlikely(ret < 0))                              \
259
0
  return gnutls_assert_val(ret)
260
#endif
261
262
int _gnutls_auth_cipher_add_auth(auth_cipher_hd_st *handle, const void *text,
263
         int textlen)
264
0
{
265
0
  int ret;
266
267
0
  if (handle->is_mac) {
268
0
    MAC(handle, text, textlen);
269
0
  } else if (_gnutls_cipher_is_aead(&handle->cipher))
270
0
    return _gnutls_cipher_auth(&handle->cipher, text, textlen);
271
0
  return 0;
272
0
}
273
274
/* The caller must make sure that textlen+pad_size+tag_size is divided by the block size of the cipher */
275
int _gnutls_auth_cipher_encrypt2_tag(auth_cipher_hd_st *handle,
276
             const uint8_t *text, int textlen,
277
             void *_ciphertext, int ciphertextlen,
278
             int pad_size)
279
0
{
280
0
  int ret;
281
0
  uint8_t *ciphertext = _ciphertext;
282
0
  unsigned blocksize = _gnutls_cipher_get_block_size(handle->cipher.e);
283
0
  unsigned l;
284
285
0
  assert(ciphertext != NULL);
286
287
0
  if (handle->is_mac) { /* cipher + mac */
288
0
    if (handle->non_null == 0) { /* NULL cipher + MAC */
289
0
      MAC(handle, text, textlen);
290
291
0
      if (unlikely(textlen + pad_size + handle->tag_size) >
292
0
          ciphertextlen)
293
0
        return gnutls_assert_val(
294
0
          GNUTLS_E_INTERNAL_ERROR);
295
296
0
      if (text != ciphertext)
297
0
        memcpy(ciphertext, text, textlen);
298
0
      ret = _gnutls_auth_cipher_tag(
299
0
        handle, ciphertext + textlen, handle->tag_size);
300
0
      if (ret < 0)
301
0
        return gnutls_assert_val(ret);
302
303
0
    } else {
304
0
      uint8_t *orig_ciphertext = ciphertext;
305
306
0
      if (handle->etm == 0 ||
307
0
          handle->cipher.e->type != CIPHER_BLOCK) {
308
0
        MAC(handle, text, textlen);
309
0
      }
310
311
0
      if (unlikely(textlen + pad_size + handle->tag_size) >
312
0
          ciphertextlen)
313
0
        return gnutls_assert_val(
314
0
          GNUTLS_E_INTERNAL_ERROR);
315
316
0
      assert(blocksize != 0);
317
0
      l = (textlen / blocksize) * blocksize;
318
0
      if (l > 0) {
319
0
        ret = _gnutls_cipher_encrypt2(&handle->cipher,
320
0
                    text, l,
321
0
                    ciphertext,
322
0
                    ciphertextlen);
323
0
        if (ret < 0)
324
0
          return gnutls_assert_val(ret);
325
326
0
        textlen -= l;
327
0
        text += l;
328
0
        ciphertext += l;
329
0
        ciphertextlen -= l;
330
0
      }
331
332
0
      if (ciphertext != text && textlen > 0)
333
0
        memcpy(ciphertext, text, textlen);
334
335
0
      if (handle->etm == 0 ||
336
0
          handle->cipher.e->type != CIPHER_BLOCK) {
337
0
        ret = _gnutls_auth_cipher_tag(
338
0
          handle, ciphertext + textlen,
339
0
          handle->tag_size);
340
0
        if (ret < 0)
341
0
          return gnutls_assert_val(ret);
342
0
        textlen += handle->tag_size;
343
0
      }
344
345
      /* TLS 1.0 style padding */
346
0
      if (pad_size > 0) {
347
0
        memset(ciphertext + textlen, pad_size - 1,
348
0
               pad_size);
349
0
        textlen += pad_size;
350
0
      }
351
352
0
      ret = _gnutls_cipher_encrypt2(&handle->cipher,
353
0
                  ciphertext, textlen,
354
0
                  ciphertext,
355
0
                  ciphertextlen);
356
0
      if (ret < 0)
357
0
        return gnutls_assert_val(ret);
358
359
0
      if (handle->etm != 0 &&
360
0
          handle->cipher.e->type == CIPHER_BLOCK) {
361
0
        MAC(handle, orig_ciphertext, l);
362
0
        MAC(handle, ciphertext, textlen);
363
364
0
        ret = _gnutls_auth_cipher_tag(
365
0
          handle, ciphertext + textlen,
366
0
          handle->tag_size);
367
0
        if (ret < 0)
368
0
          return gnutls_assert_val(ret);
369
0
      }
370
0
    }
371
0
  } else if (_gnutls_cipher_is_aead(&handle->cipher)) {
372
0
    ret = _gnutls_cipher_encrypt2(&handle->cipher, text, textlen,
373
0
                ciphertext, ciphertextlen);
374
0
    if (unlikely(ret < 0))
375
0
      return gnutls_assert_val(ret);
376
377
0
    ret = _gnutls_auth_cipher_tag(handle, ciphertext + textlen,
378
0
                handle->tag_size);
379
0
    if (unlikely(ret < 0))
380
0
      return gnutls_assert_val(ret);
381
0
  } else if (handle->non_null == 0 &&
382
0
       text != ciphertext) /* NULL cipher - no MAC */
383
0
    memcpy(ciphertext, text, textlen);
384
385
0
  return 0;
386
0
}
387
388
int _gnutls_auth_cipher_decrypt2(auth_cipher_hd_st *handle,
389
         const void *ciphertext, int ciphertextlen,
390
         void *text, int textlen)
391
0
{
392
0
  int ret;
393
394
0
  if (unlikely(ciphertextlen > textlen))
395
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
396
397
0
  if (handle->is_mac &&
398
0
      (handle->etm != 0 && handle->cipher.e->type == CIPHER_BLOCK)) {
399
    /* The MAC is not to be hashed */
400
0
    ciphertextlen -= handle->tag_size;
401
402
0
    MAC(handle, ciphertext, ciphertextlen);
403
0
  }
404
405
0
  if (handle->non_null != 0) {
406
0
    ret = _gnutls_cipher_decrypt2(&handle->cipher, ciphertext,
407
0
                ciphertextlen, text, textlen);
408
0
    if (ret < 0)
409
0
      return gnutls_assert_val(ret);
410
0
  } else if (handle->non_null == 0 && text != ciphertext)
411
0
    memcpy(text, ciphertext, ciphertextlen);
412
413
0
  if (handle->is_mac &&
414
0
      (handle->etm == 0 || handle->cipher.e->type != CIPHER_BLOCK)) {
415
    /* The MAC is not to be hashed */
416
0
    ciphertextlen -= handle->tag_size;
417
418
0
    MAC(handle, text, ciphertextlen);
419
0
  }
420
421
0
  return 0;
422
0
}
423
424
int _gnutls_auth_cipher_tag(auth_cipher_hd_st *handle, void *tag, int tag_size)
425
0
{
426
0
  if (handle->is_mac) {
427
#ifdef ENABLE_SSL3
428
    if (handle->ssl_hmac) {
429
      int ret =
430
        _gnutls_mac_output_ssl3(&handle->mac.dig, tag);
431
      if (ret < 0)
432
        return gnutls_assert_val(ret);
433
    } else
434
#endif
435
0
#ifdef ENABLE_GOST
436
      /* draft-smyshlyaev-tls12-gost-suites section 4.1.2 */
437
0
      if (handle->continuous_mac) {
438
0
        mac_hd_st temp_mac;
439
0
        int ret = _gnutls_mac_copy(&handle->mac.mac,
440
0
                 &temp_mac);
441
0
        if (ret < 0)
442
0
          return gnutls_assert_val(ret);
443
0
        _gnutls_mac_deinit(&temp_mac, tag);
444
0
      } else
445
0
#endif
446
0
        _gnutls_mac_output(&handle->mac.mac, tag);
447
0
  } else if (_gnutls_cipher_is_aead(&handle->cipher)) {
448
0
    _gnutls_cipher_tag(&handle->cipher, tag, tag_size);
449
0
  } else
450
0
    memset(tag, 0, tag_size);
451
452
0
  return 0;
453
0
}
454
455
void _gnutls_auth_cipher_deinit(auth_cipher_hd_st *handle)
456
0
{
457
0
  if (handle->is_mac) {
458
#ifdef ENABLE_SSL3
459
    if (handle->ssl_hmac) /* failure here doesn't matter */
460
      _gnutls_mac_deinit_ssl3(&handle->mac.dig, NULL);
461
    else
462
#endif
463
0
      _gnutls_mac_deinit(&handle->mac.mac, NULL);
464
0
  }
465
0
  if (handle->non_null != 0)
466
0
    _gnutls_cipher_deinit(&handle->cipher);
467
0
}