Coverage Report

Created: 2023-03-26 07:33

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