Coverage Report

Created: 2025-07-23 07:18

/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
#ifdef ENABLE_PKCS11
34
#include "pkcs11/p11_provider.h"
35
#endif
36
37
#define SR_FB(x, cleanup)                                       \
38
0
  ret = (x);                                              \
39
0
  if (ret < 0) {                                          \
40
0
    if (ret == GNUTLS_E_NEED_FALLBACK) {            \
41
0
      if (handle->handle)                     \
42
0
        handle->deinit(handle->handle); \
43
0
      goto fallback;                          \
44
0
    }                                               \
45
0
    gnutls_assert();                                \
46
0
    ret = GNUTLS_E_INTERNAL_ERROR;                  \
47
0
    goto cleanup;                                   \
48
0
  }
49
50
#define SR(x, cleanup)                         \
51
0
  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
0
{
82
0
  int ret = GNUTLS_E_INTERNAL_ERROR;
83
0
  const gnutls_crypto_cipher_st *cc = NULL;
84
0
  const gnutls_crypto_cipher_st *fallback_cc = _gnutls_cipher_backend();
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
#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
0
  cc = _gnutls_get_crypto_cipher(e->id);
103
0
  if (cc != NULL) {
104
0
    handle->encrypt = cc->encrypt;
105
0
    handle->decrypt = cc->decrypt;
106
0
    handle->aead_encrypt = cc->aead_encrypt;
107
0
    handle->aead_decrypt = cc->aead_decrypt;
108
0
    handle->deinit = cc->deinit;
109
0
    handle->auth = cc->auth;
110
0
    handle->tag = cc->tag;
111
0
    handle->setiv = cc->setiv;
112
0
    handle->getiv = cc->getiv;
113
0
    handle->setkey = cc->setkey;
114
115
    /* if cc->init() returns GNUTLS_E_NEED_FALLBACK we
116
     * use the default ciphers */
117
0
    SR_FB(cc->init(e->id, &handle->handle, enc), cc_cleanup);
118
0
    SR_FB(cc->setkey(handle->handle, key->data, key->size),
119
0
          cc_cleanup);
120
0
    if (iv) {
121
      /* the API doesn't accept IV */
122
0
      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
0
      SR(cc->setiv(handle->handle, iv->data, iv->size),
132
0
         cc_cleanup);
133
0
    }
134
135
0
    return 0;
136
0
  }
137
138
0
fallback:
139
0
  handle->encrypt = fallback_cc->encrypt;
140
0
  handle->decrypt = fallback_cc->decrypt;
141
0
  handle->aead_encrypt = fallback_cc->aead_encrypt;
142
0
  handle->aead_decrypt = fallback_cc->aead_decrypt;
143
0
  handle->deinit = fallback_cc->deinit;
144
0
  handle->auth = fallback_cc->auth;
145
0
  handle->tag = fallback_cc->tag;
146
0
  handle->setiv = fallback_cc->setiv;
147
0
  handle->getiv = fallback_cc->getiv;
148
0
  handle->setkey = fallback_cc->setkey;
149
150
  /* otherwise use generic cipher interface
151
   */
152
0
  ret = fallback_cc->init(e->id, &handle->handle, enc);
153
0
  if (ret < 0) {
154
0
    gnutls_assert();
155
0
    return ret;
156
0
  }
157
158
0
  ret = fallback_cc->setkey(handle->handle, key->data, key->size);
159
0
  if (ret < 0) {
160
0
    gnutls_assert();
161
0
    goto cc_cleanup;
162
0
  }
163
164
0
  if (iv) {
165
0
    ret = fallback_cc->setiv(handle->handle, iv->data, iv->size);
166
0
    if (ret < 0) {
167
0
      gnutls_assert();
168
0
      goto cc_cleanup;
169
0
    }
170
0
  }
171
172
0
  return 0;
173
174
0
cc_cleanup:
175
176
0
  if (handle->handle)
177
0
    handle->deinit(handle->handle);
178
179
0
  return ret;
180
0
}
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
0
{
194
0
  int ret;
195
196
0
  if (unlikely(e == NULL))
197
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
198
199
0
  FAIL_IF_LIB_ERROR;
200
201
0
  memset(handle, 0, sizeof(*handle));
202
0
  handle->etm = etm;
203
204
0
  if (e->id != GNUTLS_CIPHER_NULL) {
205
0
    handle->non_null = 1;
206
0
    ret = _gnutls_cipher_init(&handle->cipher, e, cipher_key, iv,
207
0
            enc);
208
0
    if (ret < 0)
209
0
      return gnutls_assert_val(ret);
210
0
  } else
211
0
    handle->non_null = 0;
212
213
0
  if (me->id != GNUTLS_MAC_AEAD) {
214
0
    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
0
      ret = _gnutls_mac_init(&handle->mac.mac, me,
225
0
                 mac_key->data, mac_key->size);
226
0
    if (ret < 0) {
227
0
      gnutls_assert();
228
0
      goto cleanup;
229
0
    }
230
0
#ifdef ENABLE_GOST
231
0
    handle->continuous_mac =
232
0
      !!(me->flags & GNUTLS_MAC_FLAG_CONTINUOUS_MAC);
233
0
#endif
234
235
0
    handle->tag_size = _gnutls_mac_get_algo_len(me);
236
0
  } else if (_gnutls_cipher_algo_is_aead(e)) {
237
0
    handle->tag_size = _gnutls_cipher_get_tag_size(e);
238
0
  } else {
239
0
    gnutls_assert();
240
0
    ret = GNUTLS_E_INVALID_REQUEST;
241
0
    goto cleanup;
242
0
  }
243
244
0
  return 0;
245
0
cleanup:
246
0
  if (handle->non_null != 0)
247
0
    _gnutls_cipher_deinit(&handle->cipher);
248
0
  return ret;
249
0
}
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
0
  ret = _gnutls_mac(&handle->mac.mac, text, textlen); \
263
0
  if (unlikely(ret < 0))                              \
264
0
  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
0
{
270
0
  int ret;
271
272
0
  if (handle->is_mac) {
273
0
    MAC(handle, text, textlen);
274
0
  } else if (_gnutls_cipher_is_aead(&handle->cipher))
275
0
    return _gnutls_cipher_auth(&handle->cipher, text, textlen);
276
0
  return 0;
277
0
}
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
0
{
285
0
  int ret;
286
0
  uint8_t *ciphertext = _ciphertext;
287
0
  unsigned blocksize = _gnutls_cipher_get_block_size(handle->cipher.e);
288
0
  unsigned l;
289
290
0
  assert(ciphertext != NULL);
291
292
0
  if (handle->is_mac) { /* cipher + mac */
293
0
    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
0
    } else {
309
0
      uint8_t *orig_ciphertext = ciphertext;
310
311
0
      if (handle->etm == 0 ||
312
0
          handle->cipher.e->type != CIPHER_BLOCK) {
313
0
        MAC(handle, text, textlen);
314
0
      }
315
316
0
      if (unlikely(textlen + pad_size + handle->tag_size) >
317
0
          ciphertextlen)
318
0
        return gnutls_assert_val(
319
0
          GNUTLS_E_INTERNAL_ERROR);
320
321
0
      assert(blocksize != 0);
322
0
      l = (textlen / blocksize) * blocksize;
323
0
      if (l > 0) {
324
0
        ret = _gnutls_cipher_encrypt2(&handle->cipher,
325
0
                    text, l,
326
0
                    ciphertext,
327
0
                    ciphertextlen);
328
0
        if (ret < 0)
329
0
          return gnutls_assert_val(ret);
330
331
0
        textlen -= l;
332
0
        text += l;
333
0
        ciphertext += l;
334
0
        ciphertextlen -= l;
335
0
      }
336
337
0
      if (ciphertext != text && textlen > 0)
338
0
        memcpy(ciphertext, text, textlen);
339
340
0
      if (handle->etm == 0 ||
341
0
          handle->cipher.e->type != CIPHER_BLOCK) {
342
0
        ret = _gnutls_auth_cipher_tag(
343
0
          handle, ciphertext + textlen,
344
0
          handle->tag_size);
345
0
        if (ret < 0)
346
0
          return gnutls_assert_val(ret);
347
0
        textlen += handle->tag_size;
348
0
      }
349
350
      /* TLS 1.0 style padding */
351
0
      if (pad_size > 0) {
352
0
        memset(ciphertext + textlen, pad_size - 1,
353
0
               pad_size);
354
0
        textlen += pad_size;
355
0
      }
356
357
0
      ret = _gnutls_cipher_encrypt2(&handle->cipher,
358
0
                  ciphertext, textlen,
359
0
                  ciphertext,
360
0
                  ciphertextlen);
361
0
      if (ret < 0)
362
0
        return gnutls_assert_val(ret);
363
364
0
      if (handle->etm != 0 &&
365
0
          handle->cipher.e->type == CIPHER_BLOCK) {
366
0
        MAC(handle, orig_ciphertext, l);
367
0
        MAC(handle, ciphertext, textlen);
368
369
0
        ret = _gnutls_auth_cipher_tag(
370
0
          handle, ciphertext + textlen,
371
0
          handle->tag_size);
372
0
        if (ret < 0)
373
0
          return gnutls_assert_val(ret);
374
0
      }
375
0
    }
376
0
  } 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
0
  } else if (handle->non_null == 0 &&
387
0
       text != ciphertext) /* NULL cipher - no MAC */
388
0
    memcpy(ciphertext, text, textlen);
389
390
0
  return 0;
391
0
}
392
393
int _gnutls_auth_cipher_decrypt2(auth_cipher_hd_st *handle,
394
         const void *ciphertext, int ciphertextlen,
395
         void *text, int textlen)
396
0
{
397
0
  int ret;
398
399
0
  if (unlikely(ciphertextlen > textlen))
400
0
    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
401
402
0
  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
0
  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
0
  } else if (handle->non_null == 0 && text != ciphertext)
416
0
    memcpy(text, ciphertext, ciphertextlen);
417
418
0
  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
0
  return 0;
427
0
}
428
429
int _gnutls_auth_cipher_tag(auth_cipher_hd_st *handle, void *tag, int tag_size)
430
0
{
431
0
  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
0
#ifdef ENABLE_GOST
441
      /* draft-smyshlyaev-tls12-gost-suites section 4.1.2 */
442
0
      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
0
#endif
451
0
        _gnutls_mac_output(&handle->mac.mac, tag);
452
0
  } else if (_gnutls_cipher_is_aead(&handle->cipher)) {
453
0
    _gnutls_cipher_tag(&handle->cipher, tag, tag_size);
454
0
  } else
455
0
    memset(tag, 0, tag_size);
456
457
0
  return 0;
458
0
}
459
460
void _gnutls_auth_cipher_deinit(auth_cipher_hd_st *handle)
461
0
{
462
0
  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
0
      _gnutls_mac_deinit(&handle->mac.mac, NULL);
469
0
  }
470
0
  if (handle->non_null != 0)
471
0
    _gnutls_cipher_deinit(&handle->cipher);
472
0
}