Coverage Report

Created: 2026-02-14 06:49

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