Coverage Report

Created: 2026-05-16 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/crypto-api.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2000-2016 Free Software Foundation, Inc.
3
 * Copyright (C) 2016 Red Hat, Inc.
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 "algorithms.h"
30
#include "random.h"
31
#include "crypto.h"
32
#include "fips.h"
33
#include "crypto-api.h"
34
#include "iov.h"
35
#include "intprops.h"
36
37
typedef struct api_cipher_hd_st {
38
  cipher_hd_st ctx_enc;
39
  cipher_hd_st ctx_dec;
40
} api_cipher_hd_st;
41
42
/**
43
 * gnutls_cipher_init:
44
 * @handle: is a #gnutls_cipher_hd_t type
45
 * @cipher: the encryption algorithm to use
46
 * @key: the key to be used for encryption/decryption
47
 * @iv: the IV to use (if not applicable set NULL)
48
 *
49
 * This function will initialize the @handle context to be usable
50
 * for encryption/decryption of data. This will effectively use the
51
 * current crypto backend in use by gnutls or the cryptographic
52
 * accelerator in use.
53
 *
54
 * Returns: Zero or a negative error code on error.
55
 *
56
 * Since: 2.10.0
57
 **/
58
int gnutls_cipher_init(gnutls_cipher_hd_t *handle,
59
           gnutls_cipher_algorithm_t cipher,
60
           const gnutls_datum_t *key, const gnutls_datum_t *iv)
61
13.2k
{
62
13.2k
  api_cipher_hd_st *h;
63
13.2k
  int ret;
64
13.2k
  const cipher_entry_st *e;
65
13.2k
  bool not_approved = false;
66
67
13.2k
  if (!is_cipher_algo_allowed(cipher)) {
68
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
69
0
    return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
70
13.2k
  } else if (!is_cipher_algo_approved_in_fips(cipher)) {
71
7.53k
    not_approved = true;
72
7.53k
  }
73
74
13.2k
  e = cipher_to_entry(cipher);
75
13.2k
  if (e == NULL || (e->flags & GNUTLS_CIPHER_FLAG_ONLY_AEAD)) {
76
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
77
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
78
0
  }
79
80
13.2k
  h = gnutls_calloc(1, sizeof(api_cipher_hd_st));
81
13.2k
  if (h == NULL) {
82
0
    gnutls_assert();
83
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
84
0
    return GNUTLS_E_MEMORY_ERROR;
85
0
  }
86
87
13.2k
  ret = _gnutls_cipher_init(&h->ctx_enc, e, key, iv, 1);
88
13.2k
  if (ret < 0) {
89
36
    gnutls_free(h);
90
36
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
91
36
    return ret;
92
36
  }
93
94
13.1k
  if (_gnutls_cipher_type(e) == CIPHER_BLOCK) {
95
10.7k
    ret = _gnutls_cipher_init(&h->ctx_dec, e, key, iv, 0);
96
10.7k
    if (ret < 0) {
97
0
      gnutls_free(h);
98
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
99
0
      return ret;
100
0
    }
101
10.7k
  }
102
103
13.1k
  *handle = h;
104
105
13.1k
  if (not_approved) {
106
7.50k
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
107
7.50k
  } else {
108
5.65k
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
109
5.65k
  }
110
111
13.1k
  return ret;
112
13.1k
}
113
114
/**
115
 * gnutls_cipher_tag:
116
 * @handle: is a #gnutls_cipher_hd_t type
117
 * @tag: will hold the tag
118
 * @tag_size: the length of the tag to return
119
 *
120
 * This function operates on authenticated encryption with
121
 * associated data (AEAD) ciphers and will return the
122
 * output tag.
123
 *
124
 * Returns: Zero or a negative error code on error.
125
 *
126
 * Since: 3.0
127
 **/
128
int gnutls_cipher_tag(gnutls_cipher_hd_t handle, void *tag, size_t tag_size)
129
0
{
130
0
  api_cipher_hd_st *h = handle;
131
132
0
  if (_gnutls_cipher_is_aead(&h->ctx_enc) == 0)
133
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
134
135
0
  _gnutls_cipher_tag(&h->ctx_enc, tag, tag_size);
136
137
0
  return 0;
138
0
}
139
140
/**
141
 * gnutls_cipher_add_auth:
142
 * @handle: is a #gnutls_cipher_hd_t type
143
 * @ptext: the data to be authenticated
144
 * @ptext_size: the length of the data
145
 *
146
 * This function operates on authenticated encryption with
147
 * associated data (AEAD) ciphers and authenticate the
148
 * input data. This function can only be called once
149
 * and before any encryption operations.
150
 *
151
 * Returns: Zero or a negative error code on error.
152
 *
153
 * Since: 3.0
154
 **/
155
int gnutls_cipher_add_auth(gnutls_cipher_hd_t handle, const void *ptext,
156
         size_t ptext_size)
157
0
{
158
0
  api_cipher_hd_st *h = handle;
159
0
  int ret;
160
161
0
  if (_gnutls_cipher_is_aead(&h->ctx_enc) == 0) {
162
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
163
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
164
0
  }
165
166
0
  ret = _gnutls_cipher_auth(&h->ctx_enc, ptext, ptext_size);
167
0
  if (ret < 0) {
168
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
169
0
  }
170
0
  return ret;
171
0
}
172
173
/**
174
 * gnutls_cipher_set_iv:
175
 * @handle: is a #gnutls_cipher_hd_t type
176
 * @iv: the IV to set
177
 * @ivlen: the length of the IV
178
 *
179
 * This function will set the IV to be used for the next
180
 * encryption block.
181
 *
182
 * Since: 3.0
183
 **/
184
void gnutls_cipher_set_iv(gnutls_cipher_hd_t handle, void *iv, size_t ivlen)
185
0
{
186
0
  api_cipher_hd_st *h = handle;
187
188
0
  if (_gnutls_cipher_setiv(&h->ctx_enc, iv, ivlen) < 0) {
189
0
    _gnutls_switch_lib_state(LIB_STATE_ERROR);
190
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
191
0
  }
192
193
0
  if (_gnutls_cipher_type(h->ctx_enc.e) == CIPHER_BLOCK) {
194
0
    if (_gnutls_cipher_setiv(&h->ctx_dec, iv, ivlen) < 0) {
195
0
      _gnutls_switch_lib_state(LIB_STATE_ERROR);
196
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
197
0
    }
198
0
  }
199
0
}
200
201
/*-
202
 * _gnutls_cipher_get_iv:
203
 * @handle: is a #gnutls_cipher_hd_t type
204
 * @iv: the IV to set
205
 * @ivlen: the length of the IV
206
 *
207
 * This function will retrieve the internally calculated IV value. It is
208
 * intended to be used  for modes like CFB. @iv must have @ivlen length
209
 * at least.
210
 *
211
 * This is solely for validation purposes of our crypto
212
 * implementation.  For other purposes, the IV can be typically
213
 * calculated from the initial IV value and the subsequent ciphertext
214
 * values.  As such, this function only works with the internally
215
 * registered ciphers.
216
 *
217
 * Returns: The length of IV or a negative error code on error.
218
 *
219
 * Since: 3.6.8
220
 -*/
221
int _gnutls_cipher_get_iv(gnutls_cipher_hd_t handle, void *iv, size_t ivlen)
222
0
{
223
0
  api_cipher_hd_st *h = handle;
224
225
0
  return _gnutls_cipher_getiv(&h->ctx_enc, iv, ivlen);
226
0
}
227
228
/*-
229
 * _gnutls_cipher_set_key:
230
 * @handle: is a #gnutls_cipher_hd_t type
231
 * @key: the key to set
232
 * @keylen: the length of the key
233
 *
234
 * This function will set the key used by the cipher
235
 *
236
 * This is solely for validation purposes of our crypto
237
 * implementation.  For other purposes, the key should be set at the time of
238
 * cipher setup.  As such, this function only works with the internally
239
 * registered ciphers.
240
 *
241
 * Returns: Zero or a negative error code on error.
242
 *
243
 * Since: 3.6.14
244
 -*/
245
int _gnutls_cipher_set_key(gnutls_cipher_hd_t handle, void *key, size_t keylen)
246
0
{
247
0
  api_cipher_hd_st *h = handle;
248
0
  int ret;
249
250
0
  ret = _gnutls_cipher_setkey(&h->ctx_enc, key, keylen);
251
252
0
  if (ret < 0) {
253
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
254
0
  }
255
0
  return ret;
256
0
}
257
258
/**
259
 * gnutls_cipher_encrypt:
260
 * @handle: is a #gnutls_cipher_hd_t type
261
 * @ptext: the data to encrypt
262
 * @ptext_len: the length of data to encrypt
263
 *
264
 * This function will encrypt the given data using the algorithm
265
 * specified by the context.
266
 *
267
 * Returns: Zero or a negative error code on error.
268
 *
269
 * Since: 2.10.0
270
 **/
271
int gnutls_cipher_encrypt(gnutls_cipher_hd_t handle, void *ptext,
272
        size_t ptext_len)
273
0
{
274
0
  api_cipher_hd_st *h = handle;
275
0
  int ret;
276
277
0
  ret = _gnutls_cipher_encrypt(&h->ctx_enc, ptext, ptext_len);
278
0
  if (ret < 0) {
279
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
280
0
  } else {
281
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
282
0
  }
283
0
  return ret;
284
0
}
285
286
/**
287
 * gnutls_cipher_decrypt:
288
 * @handle: is a #gnutls_cipher_hd_t type
289
 * @ctext: the data to decrypt
290
 * @ctext_len: the length of data to decrypt
291
 *
292
 * This function will decrypt the given data using the algorithm
293
 * specified by the context.
294
 *
295
 * Note that in AEAD ciphers, this will not check the tag. You will
296
 * need to compare the tag sent with the value returned from gnutls_cipher_tag().
297
 *
298
 * Returns: Zero or a negative error code on error.
299
 *
300
 * Since: 2.10.0
301
 **/
302
int gnutls_cipher_decrypt(gnutls_cipher_hd_t handle, void *ctext,
303
        size_t ctext_len)
304
13.1k
{
305
13.1k
  api_cipher_hd_st *h = handle;
306
13.1k
  int ret;
307
308
13.1k
  if (_gnutls_cipher_type(h->ctx_enc.e) != CIPHER_BLOCK) {
309
2.40k
    ret = _gnutls_cipher_decrypt(&h->ctx_enc, ctext, ctext_len);
310
10.7k
  } else {
311
10.7k
    ret = _gnutls_cipher_decrypt(&h->ctx_dec, ctext, ctext_len);
312
10.7k
  }
313
314
13.1k
  if (ret < 0) {
315
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
316
13.1k
  } else {
317
13.1k
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
318
13.1k
  }
319
13.1k
  return ret;
320
13.1k
}
321
322
/**
323
 * gnutls_cipher_encrypt2:
324
 * @handle: is a #gnutls_cipher_hd_t type
325
 * @ptext: the data to encrypt
326
 * @ptext_len: the length of data to encrypt
327
 * @ctext: the encrypted data
328
 * @ctext_len: the available length for encrypted data
329
 *
330
 * This function will encrypt the given data using the algorithm
331
 * specified by the context. For block ciphers the @ptext_len must be
332
 * a multiple of the block size. For the supported ciphers the encrypted
333
 * data length will equal the plaintext size.
334
 *
335
 * Returns: Zero or a negative error code on error.
336
 *
337
 * Since: 2.12.0
338
 **/
339
int gnutls_cipher_encrypt2(gnutls_cipher_hd_t handle, const void *ptext,
340
         size_t ptext_len, void *ctext, size_t ctext_len)
341
0
{
342
0
  api_cipher_hd_st *h = handle;
343
0
  int ret;
344
345
0
  ret = _gnutls_cipher_encrypt2(&h->ctx_enc, ptext, ptext_len, ctext,
346
0
              ctext_len);
347
0
  if (ret < 0) {
348
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
349
0
  } else {
350
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
351
0
  }
352
0
  return ret;
353
0
}
354
355
/**
356
 * gnutls_cipher_decrypt2:
357
 * @handle: is a #gnutls_cipher_hd_t type
358
 * @ctext: the data to decrypt
359
 * @ctext_len: the length of data to decrypt
360
 * @ptext: the decrypted data
361
 * @ptext_len: the available length for decrypted data
362
 *
363
 * This function will decrypt the given data using the algorithm
364
 * specified by the context. For block ciphers the @ctext_len must be
365
 * a multiple of the block size. For the supported ciphers the plaintext
366
 * data length will equal the ciphertext size.
367
 *
368
 * Note that in AEAD ciphers, this will not check the tag. You will
369
 * need to compare the tag sent with the value returned from gnutls_cipher_tag().
370
 *
371
 * Returns: Zero or a negative error code on error.
372
 *
373
 * Since: 2.12.0
374
 **/
375
int gnutls_cipher_decrypt2(gnutls_cipher_hd_t handle, const void *ctext,
376
         size_t ctext_len, void *ptext, size_t ptext_len)
377
0
{
378
0
  api_cipher_hd_st *h = handle;
379
0
  int ret;
380
381
0
  if (_gnutls_cipher_type(h->ctx_enc.e) != CIPHER_BLOCK) {
382
0
    ret = _gnutls_cipher_decrypt2(&h->ctx_enc, ctext, ctext_len,
383
0
                ptext, ptext_len);
384
0
  } else {
385
0
    ret = _gnutls_cipher_decrypt2(&h->ctx_dec, ctext, ctext_len,
386
0
                ptext, ptext_len);
387
0
  }
388
389
0
  if (ret < 0) {
390
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
391
0
  } else {
392
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
393
0
  }
394
0
  return ret;
395
0
}
396
397
/**
398
 * gnutls_cipher_encrypt3:
399
 * @handle: is a #gnutls_cipher_hd_t type
400
 * @ptext: the data to encrypt
401
 * @ptext_len: the length of data to encrypt
402
 * @ctext: the encrypted data
403
 * @ctext_len: the length of encrypted data (initially must hold the maximum available size)
404
 * @flags: flags for padding
405
 *
406
 * This function will encrypt the given data using the algorithm
407
 * specified by the context. For block ciphers, @ptext_len is
408
 * typically a multiple of the block size. If not, the caller can
409
 * instruct the function to pad the last block according to @flags.
410
 * Currently, the only available padding scheme is
411
 * %GNUTLS_CIPHER_PADDING_PKCS7.
412
 *
413
 * If @ctext is not %NULL, it must hold enough space to store
414
 * resulting cipher text. To check the required size, this function
415
 * can be called with @ctext set to %NULL. Then @ctext_len will be
416
 * updated without performing actual encryption.
417
 *
418
 * Returns: Zero or a negative error code on error.
419
 *
420
 * Since: 3.7.7
421
 **/
422
int gnutls_cipher_encrypt3(gnutls_cipher_hd_t handle, const void *ptext,
423
         size_t ptext_len, void *ctext, size_t *ctext_len,
424
         unsigned flags)
425
0
{
426
0
  api_cipher_hd_st *h = handle;
427
0
  const cipher_entry_st *e = h->ctx_enc.e;
428
0
  int block_size = _gnutls_cipher_get_block_size(e);
429
0
  int ret = 0;
430
431
0
  if (unlikely(ctext_len == NULL)) {
432
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
433
0
  }
434
435
0
  if (_gnutls_cipher_type(e) == CIPHER_BLOCK &&
436
0
      (flags & GNUTLS_CIPHER_PADDING_PKCS7)) {
437
0
    size_t n, r;
438
0
    uint8_t last_block[MAX_CIPHER_BLOCK_SIZE];
439
0
    const uint8_t *p = ptext;
440
0
    uint8_t *c = ctext;
441
442
0
    if (!INT_ADD_OK(ptext_len, block_size, &n)) {
443
0
      return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
444
0
    }
445
446
0
    n = (n / block_size) * block_size;
447
448
0
    if (!ctext) {
449
0
      *ctext_len = n;
450
0
      return 0;
451
0
    }
452
453
0
    if (*ctext_len < n) {
454
0
      return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
455
0
    }
456
457
    /* Encrypt up to the last complete block */
458
0
    r = ptext_len % block_size;
459
460
0
    ret = _gnutls_cipher_encrypt2(&h->ctx_enc, ptext, ptext_len - r,
461
0
                ctext, ptext_len - r);
462
0
    if (ret < 0) {
463
0
      goto error;
464
0
    }
465
466
    /* Encrypt the last block with padding */
467
0
    gnutls_memset(last_block, block_size - r, sizeof(last_block));
468
0
    if (r > 0) {
469
0
      memcpy(last_block, &p[ptext_len - r], r);
470
0
    }
471
0
    ret = _gnutls_cipher_encrypt2(&h->ctx_enc, last_block,
472
0
                block_size, &c[ptext_len - r],
473
0
                block_size);
474
0
    if (ret < 0) {
475
0
      goto error;
476
0
    }
477
0
    *ctext_len = n;
478
0
  } else {
479
0
    if (!ctext) {
480
0
      *ctext_len = ptext_len;
481
0
      return 0;
482
0
    }
483
484
0
    ret = _gnutls_cipher_encrypt2(&h->ctx_enc, ptext, ptext_len,
485
0
                ctext, *ctext_len);
486
0
    if (ret < 0) {
487
0
      goto error;
488
0
    }
489
0
    *ctext_len = ptext_len;
490
0
  }
491
492
0
error:
493
0
  if (ret < 0) {
494
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
495
0
  } else {
496
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
497
0
  }
498
0
  return ret;
499
0
}
500
501
unsigned int _gnutls_pkcs7_unpad(const uint8_t *block, unsigned int block_size);
502
503
/* If succeeds, returns the number of padding bytes to be removed;
504
 * zero otherwise.
505
 */
506
unsigned int _gnutls_pkcs7_unpad(const uint8_t *block, unsigned int block_size)
507
0
{
508
0
  uint8_t padding = block[block_size - 1];
509
0
  volatile unsigned int mask = ~0;
510
0
  volatile unsigned int count = 0;
511
512
  /* Count consecutive PADDING bytes from the end, in a
513
   * constant-time manner.
514
   */
515
0
  for (size_t i = block_size; i > 0; i--) {
516
0
    volatile unsigned int mask2;
517
518
0
    mask2 = -(unsigned int)(block[i - 1] == padding);
519
0
    mask2 &= -(unsigned int)(count < padding);
520
521
    /* MASK is initially ~0 and will be flipped to 0 upon first
522
     * non-padding bytes.
523
     */
524
0
    mask &= mask2;
525
0
    count += 1 & mask;
526
0
  }
527
528
  /* PADDING == 0 is effectively excluded here, given COUNT
529
   * will never be 0.
530
   */
531
0
  mask = -(unsigned int)(count <= block_size);
532
0
  mask &= -(unsigned int)(count == padding);
533
0
  return count & mask;
534
0
}
535
536
/**
537
 * gnutls_cipher_decrypt3:
538
 * @handle: is a #gnutls_cipher_hd_t type
539
 * @ctext: the data to decrypt
540
 * @ctext_len: the length of data to decrypt
541
 * @ptext: the decrypted data
542
 * @ptext_len: the available length for decrypted data
543
 * @flags: flags for padding
544
 *
545
 * This function will decrypt the given data using the algorithm
546
 * specified by the context. If @flags is specified, padding for the
547
 * decrypted data will be removed accordingly and @ptext_len will be
548
 * updated.
549
 *
550
 * Returns: Zero or a negative error code on error.
551
 *
552
 * Since: 3.7.7
553
 **/
554
int gnutls_cipher_decrypt3(gnutls_cipher_hd_t handle, const void *ctext,
555
         size_t ctext_len, void *ptext, size_t *ptext_len,
556
         unsigned flags)
557
0
{
558
0
  api_cipher_hd_st *h = handle;
559
0
  int ret;
560
561
0
  ret = gnutls_cipher_decrypt2(handle, ctext, ctext_len, ptext,
562
0
             *ptext_len);
563
0
  if (ret < 0) {
564
0
    return ret;
565
0
  }
566
567
0
  if (_gnutls_cipher_type(h->ctx_enc.e) == CIPHER_BLOCK &&
568
0
      (flags & GNUTLS_CIPHER_PADDING_PKCS7)) {
569
0
    uint8_t *p = ptext;
570
0
    size_t block_size = _gnutls_cipher_get_block_size(h->ctx_enc.e);
571
0
    uint8_t *block = &p[*ptext_len - block_size];
572
0
    unsigned int padding = _gnutls_pkcs7_unpad(block, block_size);
573
0
    volatile unsigned int mask;
574
575
0
    mask = -(unsigned int)(padding == 0);
576
0
    ret = GNUTLS_E_DECRYPTION_FAILED & mask;
577
0
    *ptext_len -= padding;
578
0
  }
579
580
0
  return ret;
581
0
}
582
583
/**
584
 * gnutls_cipher_deinit:
585
 * @handle: is a #gnutls_cipher_hd_t type
586
 *
587
 * This function will deinitialize all resources occupied by the given
588
 * encryption context.
589
 *
590
 * Since: 2.10.0
591
 **/
592
void gnutls_cipher_deinit(gnutls_cipher_hd_t handle)
593
13.1k
{
594
13.1k
  api_cipher_hd_st *h = handle;
595
596
13.1k
  _gnutls_cipher_deinit(&h->ctx_enc);
597
13.1k
  if (_gnutls_cipher_type(h->ctx_enc.e) == CIPHER_BLOCK)
598
10.7k
    _gnutls_cipher_deinit(&h->ctx_dec);
599
13.1k
  gnutls_free(handle);
600
13.1k
}
601
602
/* HMAC */
603
604
/**
605
 * gnutls_hmac_init:
606
 * @dig: is a #gnutls_hmac_hd_t type
607
 * @algorithm: the HMAC algorithm to use
608
 * @key: the key to be used for encryption
609
 * @keylen: the length of the key
610
 *
611
 * This function will initialize an context that can be used to
612
 * produce a Message Authentication Code (MAC) of data.  This will
613
 * effectively use the current crypto backend in use by gnutls or the
614
 * cryptographic accelerator in use.
615
 *
616
 * Note that despite the name of this function, it can be used
617
 * for other MAC algorithms than HMAC.
618
 *
619
 * Returns: Zero or a negative error code on error.
620
 *
621
 * Since: 2.10.0
622
 **/
623
int gnutls_hmac_init(gnutls_hmac_hd_t *dig, gnutls_mac_algorithm_t algorithm,
624
         const void *key, size_t keylen)
625
761
{
626
761
  int ret;
627
761
  bool not_approved = false;
628
629
  /* MD5 is only allowed internally for TLS */
630
761
  if (!is_mac_algo_allowed(algorithm)) {
631
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
632
0
    return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
633
761
  } else if (!is_mac_algo_approved_in_fips(algorithm)) {
634
448
    not_approved = true;
635
448
  }
636
637
  /* Key lengths of less than 112 bits are not approved */
638
761
  if (keylen < 14) {
639
0
    not_approved = true;
640
0
  }
641
642
761
  *dig = gnutls_malloc(sizeof(mac_hd_st));
643
761
  if (*dig == NULL) {
644
0
    gnutls_assert();
645
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
646
0
    return GNUTLS_E_MEMORY_ERROR;
647
0
  }
648
649
761
  ret = _gnutls_mac_init(((mac_hd_st *)*dig), mac_to_entry(algorithm),
650
761
             key, keylen);
651
761
  if (ret < 0) {
652
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
653
761
  } else if (not_approved) {
654
448
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
655
448
  } else {
656
313
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
657
313
  }
658
761
  return ret;
659
761
}
660
661
/**
662
 * gnutls_hmac_set_nonce:
663
 * @handle: is a #gnutls_hmac_hd_t type
664
 * @nonce: the data to set as nonce
665
 * @nonce_len: the length of data
666
 *
667
 * This function will set the nonce in the MAC algorithm.
668
 *
669
 * Since: 3.2.0
670
 **/
671
void gnutls_hmac_set_nonce(gnutls_hmac_hd_t handle, const void *nonce,
672
         size_t nonce_len)
673
0
{
674
0
  _gnutls_mac_set_nonce((mac_hd_st *)handle, nonce, nonce_len);
675
0
}
676
677
/**
678
 * gnutls_hmac:
679
 * @handle: is a #gnutls_hmac_hd_t type
680
 * @ptext: the data to hash
681
 * @ptext_len: the length of data to hash
682
 *
683
 * This function will hash the given data using the algorithm
684
 * specified by the context.
685
 *
686
 * Returns: Zero or a negative error code on error.
687
 *
688
 * Since: 2.10.0
689
 **/
690
int gnutls_hmac(gnutls_hmac_hd_t handle, const void *ptext, size_t ptext_len)
691
761
{
692
761
  int ret;
693
694
761
  ret = _gnutls_mac((mac_hd_st *)handle, ptext, ptext_len);
695
761
  if (ret < 0) {
696
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
697
761
  } else {
698
761
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
699
761
  }
700
761
  return ret;
701
761
}
702
703
/**
704
 * gnutls_hmac_output:
705
 * @handle: is a #gnutls_hmac_hd_t type
706
 * @digest: is the output value of the MAC
707
 *
708
 * This function will output the current MAC value
709
 * and reset the state of the MAC.
710
 *
711
 * Since: 2.10.0
712
 **/
713
void gnutls_hmac_output(gnutls_hmac_hd_t handle, void *digest)
714
0
{
715
0
  _gnutls_mac_output((mac_hd_st *)handle, digest);
716
0
}
717
718
/**
719
 * gnutls_hmac_deinit:
720
 * @handle: is a #gnutls_hmac_hd_t type
721
 * @digest: is the output value of the MAC
722
 *
723
 * This function will deinitialize all resources occupied by
724
 * the given hmac context.
725
 *
726
 * Since: 2.10.0
727
 **/
728
void gnutls_hmac_deinit(gnutls_hmac_hd_t handle, void *digest)
729
761
{
730
761
  _gnutls_mac_deinit((mac_hd_st *)handle, digest);
731
761
  gnutls_free(handle);
732
761
}
733
734
/**
735
 * gnutls_hmac_get_len:
736
 * @algorithm: the hmac algorithm to use
737
 *
738
 * This function will return the length of the output data
739
 * of the given hmac algorithm.
740
 *
741
 * Returns: The length or zero on error.
742
 *
743
 * Since: 2.10.0
744
 **/
745
unsigned gnutls_hmac_get_len(gnutls_mac_algorithm_t algorithm)
746
0
{
747
0
  return _gnutls_mac_get_algo_len(mac_to_entry(algorithm));
748
0
}
749
750
/**
751
 * gnutls_hmac_get_key_size:
752
 * @algorithm: the mac algorithm to use
753
 *
754
 * This function will return the size of the key to be used with this
755
 * algorithm. On the algorithms which may accept arbitrary key sizes,
756
 * the returned size is the MAC key size used in the TLS protocol.
757
 *
758
 * Returns: The key size or zero on error.
759
 *
760
 * Since: 3.6.12
761
 **/
762
unsigned gnutls_hmac_get_key_size(gnutls_mac_algorithm_t algorithm)
763
0
{
764
0
  return _gnutls_mac_get_key_size(mac_to_entry(algorithm));
765
0
}
766
767
/**
768
 * gnutls_hmac_fast:
769
 * @algorithm: the hash algorithm to use
770
 * @key: the key to use
771
 * @keylen: the length of the key
772
 * @ptext: the data to hash
773
 * @ptext_len: the length of data to hash
774
 * @digest: is the output value of the hash
775
 *
776
 * This convenience function will hash the given data and return output
777
 * on a single call. Note, this call will not work for MAC algorithms
778
 * that require nonce (like UMAC or GMAC).
779
 *
780
 * Returns: Zero or a negative error code on error.
781
 *
782
 * Since: 2.10.0
783
 **/
784
int gnutls_hmac_fast(gnutls_mac_algorithm_t algorithm, const void *key,
785
         size_t keylen, const void *ptext, size_t ptext_len,
786
         void *digest)
787
83.8k
{
788
83.8k
  int ret;
789
83.8k
  bool not_approved = false;
790
791
83.8k
  if (!is_mac_algo_allowed(algorithm)) {
792
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
793
0
    return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
794
83.8k
  } else if (!is_mac_algo_approved_in_fips(algorithm)) {
795
0
    not_approved = true;
796
0
  }
797
798
  /* Key lengths of less than 112 bits are not approved */
799
83.8k
  if (keylen < 14) {
800
20.1k
    not_approved = true;
801
20.1k
  }
802
803
83.8k
  ret = _gnutls_mac_fast(algorithm, key, keylen, ptext, ptext_len,
804
83.8k
             digest);
805
83.8k
  if (ret < 0) {
806
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
807
83.8k
  } else if (not_approved) {
808
20.1k
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
809
63.7k
  } else {
810
63.7k
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
811
63.7k
  }
812
83.8k
  return ret;
813
83.8k
}
814
815
/**
816
 * gnutls_hmac_copy:
817
 * @handle: is a #gnutls_hmac_hd_t type
818
 *
819
 * This function will create a copy of MAC context, containing all its current
820
 * state. Copying contexts for MACs registered using
821
 * gnutls_crypto_register_mac() is not supported and will always result in an
822
 * error. In addition to that, some of the MAC implementations do not support
823
 * this operation. Applications should check the return value and provide a
824
 * proper fallback.
825
 *
826
 * Returns: new MAC context or NULL in case of an error.
827
 *
828
 * Since: 3.6.9
829
 */
830
gnutls_hmac_hd_t gnutls_hmac_copy(gnutls_hmac_hd_t handle)
831
0
{
832
0
  gnutls_hmac_hd_t dig;
833
834
0
  dig = gnutls_malloc(sizeof(mac_hd_st));
835
0
  if (dig == NULL) {
836
0
    gnutls_assert();
837
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
838
0
    return NULL;
839
0
  }
840
841
0
  if (_gnutls_mac_copy((const mac_hd_st *)handle, (mac_hd_st *)dig) !=
842
0
      GNUTLS_E_SUCCESS) {
843
0
    gnutls_assert();
844
0
    gnutls_free(dig);
845
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
846
0
    return NULL;
847
0
  }
848
849
0
  return dig;
850
0
}
851
852
/* HASH */
853
854
/**
855
 * gnutls_hash_init:
856
 * @dig: is a #gnutls_hash_hd_t type
857
 * @algorithm: the hash algorithm to use
858
 *
859
 * This function will initialize an context that can be used to
860
 * produce a Message Digest of data.  This will effectively use the
861
 * current crypto backend in use by gnutls or the cryptographic
862
 * accelerator in use.
863
 *
864
 * Returns: Zero or a negative error code on error.
865
 *
866
 * Since: 2.10.0
867
 **/
868
int gnutls_hash_init(gnutls_hash_hd_t *dig, gnutls_digest_algorithm_t algorithm)
869
2.64M
{
870
2.64M
  int ret;
871
2.64M
  bool not_approved = false;
872
873
2.64M
  if (!is_mac_algo_allowed(DIG_TO_MAC(algorithm))) {
874
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
875
0
    return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
876
2.64M
  } else if (!is_mac_algo_approved_in_fips(DIG_TO_MAC(algorithm))) {
877
2.58M
    not_approved = true;
878
2.58M
  }
879
880
2.64M
  *dig = gnutls_malloc(sizeof(digest_hd_st));
881
2.64M
  if (*dig == NULL) {
882
0
    gnutls_assert();
883
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
884
0
    return GNUTLS_E_MEMORY_ERROR;
885
0
  }
886
887
2.64M
  ret = _gnutls_hash_init(((digest_hd_st *)*dig),
888
2.64M
        hash_to_entry(algorithm));
889
2.64M
  if (ret < 0) {
890
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
891
2.64M
  } else if (not_approved) {
892
2.58M
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
893
2.58M
  } else {
894
58.8k
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
895
58.8k
  }
896
2.64M
  return ret;
897
2.64M
}
898
899
/**
900
 * gnutls_hash:
901
 * @handle: is a #gnutls_hash_hd_t type
902
 * @ptext: the data to hash
903
 * @ptext_len: the length of data to hash
904
 *
905
 * This function will hash the given data using the algorithm
906
 * specified by the context.
907
 *
908
 * Returns: Zero or a negative error code on error.
909
 *
910
 * Since: 2.10.0
911
 **/
912
int gnutls_hash(gnutls_hash_hd_t handle, const void *ptext, size_t ptext_len)
913
2.64M
{
914
2.64M
  int ret;
915
916
2.64M
  ret = _gnutls_hash((digest_hd_st *)handle, ptext, ptext_len);
917
2.64M
  if (ret < 0) {
918
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
919
0
  }
920
2.64M
  return ret;
921
2.64M
}
922
923
/**
924
 * gnutls_hash_output:
925
 * @handle: is a #gnutls_hash_hd_t type
926
 * @digest: is the output value of the hash
927
 *
928
 * This function will output the current hash value and reset the
929
 * state of the hash. If @digest is %NULL, it only resets the state of
930
 * the hash.
931
 *
932
 * Since: 2.10.0
933
 **/
934
void gnutls_hash_output(gnutls_hash_hd_t handle, void *digest)
935
0
{
936
0
  _gnutls_hash_output((digest_hd_st *)handle, digest);
937
0
}
938
939
/**
940
 * gnutls_hash_deinit:
941
 * @handle: is a #gnutls_hash_hd_t type
942
 * @digest: is the output value of the hash
943
 *
944
 * This function will deinitialize all resources occupied by
945
 * the given hash context.
946
 *
947
 * Since: 2.10.0
948
 **/
949
void gnutls_hash_deinit(gnutls_hash_hd_t handle, void *digest)
950
2.64M
{
951
2.64M
  _gnutls_hash_deinit((digest_hd_st *)handle, digest);
952
2.64M
  gnutls_free(handle);
953
2.64M
}
954
955
/**
956
 * gnutls_hash_get_len:
957
 * @algorithm: the hash algorithm to use
958
 *
959
 * This function will return the length of the output data
960
 * of the given hash algorithm.
961
 *
962
 * Returns: The length or zero on error.
963
 *
964
 * Since: 2.10.0
965
 **/
966
unsigned gnutls_hash_get_len(gnutls_digest_algorithm_t algorithm)
967
1.27k
{
968
1.27k
  return _gnutls_hash_get_algo_len(hash_to_entry(algorithm));
969
1.27k
}
970
971
/**
972
 * gnutls_hash_fast:
973
 * @algorithm: the hash algorithm to use
974
 * @ptext: the data to hash
975
 * @ptext_len: the length of data to hash
976
 * @digest: is the output value of the hash
977
 *
978
 * This convenience function will hash the given data and return output
979
 * on a single call.
980
 *
981
 * Returns: Zero or a negative error code on error.
982
 *
983
 * Since: 2.10.0
984
 **/
985
int gnutls_hash_fast(gnutls_digest_algorithm_t algorithm, const void *ptext,
986
         size_t ptext_len, void *digest)
987
121k
{
988
121k
  int ret;
989
121k
  bool not_approved = false;
990
991
121k
  if (!is_mac_algo_allowed(DIG_TO_MAC(algorithm))) {
992
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
993
0
    return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
994
121k
  } else if (!is_mac_algo_approved_in_fips(DIG_TO_MAC(algorithm))) {
995
52
    not_approved = true;
996
52
  }
997
998
121k
  ret = _gnutls_hash_fast(algorithm, ptext, ptext_len, digest);
999
121k
  if (ret < 0) {
1000
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1001
121k
  } else if (not_approved) {
1002
52
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
1003
121k
  } else {
1004
121k
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
1005
121k
  }
1006
1007
121k
  return ret;
1008
121k
}
1009
1010
/**
1011
 * gnutls_hash_copy:
1012
 * @handle: is a #gnutls_hash_hd_t type
1013
 *
1014
 * This function will create a copy of Message Digest context, containing all
1015
 * its current state. Copying contexts for Message Digests registered using
1016
 * gnutls_crypto_register_digest() is not supported and will always result in
1017
 * an error. In addition to that, some of the Message Digest implementations do
1018
 * not support this operation. Applications should check the return value and
1019
 * provide a proper fallback.
1020
 *
1021
 * Returns: new Message Digest context or NULL in case of an error.
1022
 *
1023
 * Since: 3.6.9
1024
 */
1025
gnutls_hash_hd_t gnutls_hash_copy(gnutls_hash_hd_t handle)
1026
0
{
1027
0
  gnutls_hash_hd_t dig;
1028
1029
0
  dig = gnutls_malloc(sizeof(digest_hd_st));
1030
0
  if (dig == NULL) {
1031
0
    gnutls_assert();
1032
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1033
0
    return NULL;
1034
0
  }
1035
1036
0
  if (_gnutls_hash_copy((const digest_hd_st *)handle,
1037
0
            (digest_hd_st *)dig) != GNUTLS_E_SUCCESS) {
1038
0
    gnutls_assert();
1039
0
    gnutls_free(dig);
1040
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1041
0
    return NULL;
1042
0
  }
1043
1044
0
  return dig;
1045
0
}
1046
1047
/**
1048
 * gnutls_hash_squeeze:
1049
 * @handle: a #gnutls_hash_hd_t
1050
 * @output: destination to store the output; must be equal to or larger than @length
1051
 * @length: length of @output
1052
 *
1053
 * This function will extract digest output of @length bytes. The @handle must
1054
 * be initialized with gnutls_hash_init() as an extended output function (XOF),
1055
 * such as %GNUTLS_DIG_SHAKE_128 or %GNUTLS_DIG_SHAKE_256.
1056
 *
1057
 * This function can be called multiple times. To reset the state of @handle,
1058
 * call gnutls_hash_deinit() with %NULL as the digest argument.
1059
 *
1060
 * Returns: %GNUTLS_E_SUCCESS (0) on success; negative error code otherwise.
1061
 *
1062
 * Since: 3.8.6
1063
 */
1064
int gnutls_hash_squeeze(gnutls_hash_hd_t handle, void *output, size_t length)
1065
0
{
1066
0
  return _gnutls_hash_squeeze((digest_hd_st *)handle, output, length);
1067
0
}
1068
1069
/**
1070
 * gnutls_key_generate:
1071
 * @key: is a pointer to a #gnutls_datum_t which will contain a newly
1072
 * created key
1073
 * @key_size: the number of bytes of the key
1074
 *
1075
 * Generates a random key of @key_size bytes.
1076
 *
1077
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
1078
 * error code.
1079
 *
1080
 * Since: 3.0
1081
 **/
1082
int gnutls_key_generate(gnutls_datum_t *key, unsigned int key_size)
1083
0
{
1084
0
  int ret;
1085
0
  bool not_approved = false;
1086
1087
0
  FAIL_IF_LIB_ERROR;
1088
1089
#ifdef ENABLE_FIPS140
1090
  /* The FIPS140 approved RNGs are not allowed to be used
1091
   * to extract key sizes longer than their original seed.
1092
   */
1093
  if (_gnutls_fips_mode_enabled() != 0 && key_size > FIPS140_RND_KEY_SIZE)
1094
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1095
#endif
1096
1097
0
  key->size = key_size;
1098
0
  key->data = gnutls_malloc(key->size);
1099
0
  if (!key->data) {
1100
0
    gnutls_assert();
1101
0
    ret = GNUTLS_E_MEMORY_ERROR;
1102
0
    goto error;
1103
0
  }
1104
1105
  /* Key lengths of less than 112 bits are not approved */
1106
0
  if (key_size < 14) {
1107
0
    not_approved = true;
1108
0
  }
1109
1110
0
  ret = gnutls_rnd(GNUTLS_RND_RANDOM, key->data, key->size);
1111
0
  if (ret < 0) {
1112
0
    gnutls_assert();
1113
0
    _gnutls_free_datum(key);
1114
0
    goto error;
1115
0
  }
1116
1117
0
error:
1118
0
  if (ret < 0) {
1119
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1120
0
  } else if (not_approved) {
1121
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
1122
0
  } else {
1123
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
1124
0
  }
1125
0
  return ret;
1126
0
}
1127
1128
/* AEAD API */
1129
1130
/**
1131
 * gnutls_aead_cipher_init:
1132
 * @handle: is a #gnutls_aead_cipher_hd_t type.
1133
 * @cipher: the authenticated-encryption algorithm to use
1134
 * @key: The key to be used for encryption
1135
 *
1136
 * This function will initialize an context that can be used for
1137
 * encryption/decryption of data. This will effectively use the
1138
 * current crypto backend in use by gnutls or the cryptographic
1139
 * accelerator in use.
1140
 *
1141
 * Returns: Zero or a negative error code on error.
1142
 *
1143
 * Since: 3.4.0
1144
 **/
1145
int gnutls_aead_cipher_init(gnutls_aead_cipher_hd_t *handle,
1146
          gnutls_cipher_algorithm_t cipher,
1147
          const gnutls_datum_t *key)
1148
0
{
1149
0
  api_aead_cipher_hd_st *h;
1150
0
  const cipher_entry_st *e;
1151
0
  int ret;
1152
0
  bool not_approved = false;
1153
1154
0
  if (!is_cipher_algo_allowed(cipher)) {
1155
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1156
0
    return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
1157
0
  } else if (!is_cipher_algo_approved_in_fips(cipher)) {
1158
0
    not_approved = true;
1159
0
  }
1160
1161
0
  e = cipher_to_entry(cipher);
1162
0
  if (e == NULL || e->type != CIPHER_AEAD) {
1163
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1164
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1165
0
  }
1166
1167
0
  h = gnutls_calloc(1, sizeof(api_aead_cipher_hd_st));
1168
0
  if (h == NULL) {
1169
0
    gnutls_assert();
1170
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1171
0
    return GNUTLS_E_MEMORY_ERROR;
1172
0
  }
1173
1174
0
  ret = _gnutls_aead_cipher_init(h, cipher, key);
1175
0
  if (ret < 0) {
1176
0
    gnutls_free(h);
1177
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1178
0
    return ret;
1179
0
  }
1180
1181
0
  *handle = h;
1182
1183
0
  if (not_approved) {
1184
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
1185
0
  } else {
1186
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
1187
0
  }
1188
1189
0
  return ret;
1190
0
}
1191
1192
/**
1193
 * gnutls_aead_cipher_set_key:
1194
 * @handle: is a #gnutls_aead_cipher_hd_t type.
1195
 * @key: The key to be used for encryption
1196
 *
1197
 * This function will set a new key without re-initializing the
1198
 * context.
1199
 *
1200
 * Returns: Zero or a negative error code on error.
1201
 *
1202
 * Since: 3.7.5
1203
 **/
1204
int gnutls_aead_cipher_set_key(gnutls_aead_cipher_hd_t handle,
1205
             const gnutls_datum_t *key)
1206
0
{
1207
0
  const cipher_entry_st *e;
1208
0
  int ret;
1209
1210
0
  e = cipher_to_entry(handle->ctx_enc.e->id);
1211
0
  if (e == NULL || e->type != CIPHER_AEAD) {
1212
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1213
0
  }
1214
1215
0
  ret = handle->ctx_enc.setkey(handle->ctx_enc.handle, key->data,
1216
0
             key->size);
1217
0
  if (ret < 0) {
1218
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1219
0
  }
1220
1221
0
  return ret;
1222
0
}
1223
1224
/**
1225
 * gnutls_aead_cipher_decrypt:
1226
 * @handle: is a #gnutls_aead_cipher_hd_t type.
1227
 * @nonce: the nonce to set
1228
 * @nonce_len: The length of the nonce
1229
 * @auth: additional data to be authenticated
1230
 * @auth_len: The length of the data
1231
 * @tag_size: The size of the tag to use (use zero for the default)
1232
 * @ctext: the data to decrypt (including the authentication tag)
1233
 * @ctext_len: the length of data to decrypt (includes tag size)
1234
 * @ptext: the decrypted data
1235
 * @ptext_len: the length of decrypted data (initially must hold the maximum available size)
1236
 *
1237
 * This function will decrypt the given data using the algorithm
1238
 * specified by the context. This function must be provided the complete
1239
 * data to be decrypted, including the authentication tag. On several
1240
 * AEAD ciphers, the authentication tag is appended to the ciphertext,
1241
 * though this is not a general rule. This function will fail if
1242
 * the tag verification fails.
1243
 *
1244
 * Returns: Zero or a negative error code on verification failure or other error.
1245
 *
1246
 * Since: 3.4.0
1247
 **/
1248
int gnutls_aead_cipher_decrypt(gnutls_aead_cipher_hd_t handle,
1249
             const void *nonce, size_t nonce_len,
1250
             const void *auth, size_t auth_len,
1251
             size_t tag_size, const void *ctext,
1252
             size_t ctext_len, void *ptext, size_t *ptext_len)
1253
19.9k
{
1254
19.9k
  int ret;
1255
19.9k
  api_aead_cipher_hd_st *h = handle;
1256
1257
19.9k
  if (tag_size == 0)
1258
0
    tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e);
1259
19.9k
  else if (tag_size >
1260
19.9k
     (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e)) {
1261
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1262
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1263
0
  }
1264
1265
19.9k
  if (unlikely(ctext_len < tag_size)) {
1266
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1267
0
    return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
1268
0
  }
1269
1270
19.9k
  ret = _gnutls_aead_cipher_decrypt(&h->ctx_enc, nonce, nonce_len, auth,
1271
19.9k
            auth_len, tag_size, ctext, ctext_len,
1272
19.9k
            ptext, *ptext_len);
1273
19.9k
  if (unlikely(ret < 0)) {
1274
19.9k
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1275
19.9k
    return gnutls_assert_val(ret);
1276
19.9k
  } else {
1277
1
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
1278
1
  }
1279
1280
  /* That assumes that AEAD ciphers are stream */
1281
1
  *ptext_len = ctext_len - tag_size;
1282
1283
1
  return 0;
1284
19.9k
}
1285
1286
/**
1287
 * gnutls_aead_cipher_encrypt:
1288
 * @handle: is a #gnutls_aead_cipher_hd_t type.
1289
 * @nonce: the nonce to set
1290
 * @nonce_len: The length of the nonce
1291
 * @auth: additional data to be authenticated
1292
 * @auth_len: The length of the data
1293
 * @tag_size: The size of the tag to use (use zero for the default)
1294
 * @ptext: the data to encrypt
1295
 * @ptext_len: The length of data to encrypt
1296
 * @ctext: the encrypted data including authentication tag
1297
 * @ctext_len: the length of encrypted data (initially must hold the maximum available size, including space for tag)
1298
 *
1299
 * This function will encrypt the given data using the algorithm
1300
 * specified by the context. The output data will contain the
1301
 * authentication tag.
1302
 *
1303
 * Returns: Zero or a negative error code on error.
1304
 *
1305
 * Since: 3.4.0
1306
 **/
1307
int gnutls_aead_cipher_encrypt(gnutls_aead_cipher_hd_t handle,
1308
             const void *nonce, size_t nonce_len,
1309
             const void *auth, size_t auth_len,
1310
             size_t tag_size, const void *ptext,
1311
             size_t ptext_len, void *ctext, size_t *ctext_len)
1312
1.02k
{
1313
1.02k
  api_aead_cipher_hd_st *h = handle;
1314
1.02k
  int ret;
1315
1316
1.02k
  if (tag_size == 0)
1317
0
    tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e);
1318
1.02k
  else if (tag_size >
1319
1.02k
     (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e)) {
1320
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1321
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1322
0
  }
1323
1324
1.02k
  if (unlikely(*ctext_len < ptext_len + tag_size)) {
1325
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1326
0
    return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
1327
0
  }
1328
1329
1.02k
  ret = _gnutls_aead_cipher_encrypt(&h->ctx_enc, nonce, nonce_len, auth,
1330
1.02k
            auth_len, tag_size, ptext, ptext_len,
1331
1.02k
            ctext, *ctext_len);
1332
1.02k
  if (unlikely(ret < 0)) {
1333
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1334
0
    return gnutls_assert_val(ret);
1335
1.02k
  } else {
1336
1.02k
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
1337
1.02k
  }
1338
1339
  /* That assumes that AEAD ciphers are stream */
1340
1.02k
  *ctext_len = ptext_len + tag_size;
1341
1342
1.02k
  return 0;
1343
1.02k
}
1344
1345
struct iov_store_st {
1346
  void *data;
1347
  size_t length;
1348
  size_t capacity;
1349
};
1350
1351
static void iov_store_free(struct iov_store_st *s)
1352
2.05k
{
1353
2.05k
  gnutls_free(s->data);
1354
2.05k
}
1355
1356
static int iov_store_grow(struct iov_store_st *s, size_t length)
1357
0
{
1358
0
  void *new_data;
1359
0
  size_t new_capacity = s->capacity;
1360
1361
0
  if (INT_ADD_OVERFLOW(new_capacity, length)) {
1362
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1363
0
  }
1364
0
  new_capacity += length;
1365
0
  new_data = gnutls_realloc(s->data, new_capacity);
1366
0
  if (!new_data) {
1367
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
1368
0
  }
1369
0
  s->data = new_data;
1370
0
  s->capacity = new_capacity;
1371
0
  return 0;
1372
0
}
1373
1374
static int append_from_iov(struct iov_store_st *dst, const giovec_t *iov,
1375
         int iovcnt)
1376
2.05k
{
1377
2.05k
  if (iovcnt > 0) {
1378
2.05k
    int i;
1379
2.05k
    uint8_t *p;
1380
2.05k
    void *new_data;
1381
2.05k
    size_t new_capacity = dst->capacity;
1382
1383
5.13k
    for (i = 0; i < iovcnt; i++) {
1384
3.07k
      if (INT_ADD_OVERFLOW(new_capacity, iov[i].iov_len)) {
1385
0
        return gnutls_assert_val(
1386
0
          GNUTLS_E_INVALID_REQUEST);
1387
0
      }
1388
3.07k
      new_capacity += iov[i].iov_len;
1389
3.07k
    }
1390
2.05k
    new_data = gnutls_realloc(dst->data, new_capacity);
1391
2.05k
    if (!new_data) {
1392
0
      return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
1393
0
    }
1394
2.05k
    dst->data = new_data;
1395
2.05k
    dst->capacity = new_capacity;
1396
1397
2.05k
    p = (uint8_t *)dst->data + dst->length;
1398
5.13k
    for (i = 0; i < iovcnt; i++) {
1399
3.07k
      if (iov[i].iov_len > 0) {
1400
3.07k
        memcpy(p, iov[i].iov_base, iov[i].iov_len);
1401
3.07k
      }
1402
3.07k
      p += iov[i].iov_len;
1403
3.07k
      dst->length += iov[i].iov_len;
1404
3.07k
    }
1405
2.05k
  }
1406
2.05k
  return 0;
1407
2.05k
}
1408
1409
static int copy_to_iov(const uint8_t *data, size_t size, const giovec_t *iov,
1410
           int iovcnt)
1411
0
{
1412
0
  size_t offset = 0;
1413
0
  int i;
1414
1415
0
  for (i = 0; i < iovcnt && size > 0; i++) {
1416
0
    size_t to_copy = MIN(size, iov[i].iov_len);
1417
0
    memcpy(iov[i].iov_base, (uint8_t *)data + offset, to_copy);
1418
0
    offset += to_copy;
1419
0
    size -= to_copy;
1420
0
  }
1421
0
  if (size > 0)
1422
0
    return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
1423
0
  return 0;
1424
0
}
1425
1426
2.05k
#define IOV_STORE_INIT { NULL, 0, 0 }
1427
1428
static int aead_cipher_encryptv_fallback(gnutls_aead_cipher_hd_t handle,
1429
           const void *nonce, size_t nonce_len,
1430
           const giovec_t *auth_iov,
1431
           int auth_iovcnt, size_t tag_size,
1432
           const giovec_t *iov, int iovcnt,
1433
           void *ctext, size_t *ctext_len)
1434
1.02k
{
1435
1.02k
  struct iov_store_st auth = IOV_STORE_INIT;
1436
1.02k
  struct iov_store_st ptext = IOV_STORE_INIT;
1437
1.02k
  int ret;
1438
1439
1.02k
  if (tag_size == 0)
1440
0
    tag_size = _gnutls_cipher_get_tag_size(handle->ctx_enc.e);
1441
1.02k
  else if (tag_size >
1442
1.02k
     (unsigned)_gnutls_cipher_get_tag_size(handle->ctx_enc.e)) {
1443
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1444
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1445
0
  }
1446
1447
1.02k
  ret = append_from_iov(&auth, auth_iov, auth_iovcnt);
1448
1.02k
  if (ret < 0) {
1449
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1450
0
    return gnutls_assert_val(ret);
1451
0
  }
1452
1453
1.02k
  ret = append_from_iov(&ptext, iov, iovcnt);
1454
1.02k
  if (ret < 0) {
1455
0
    iov_store_free(&auth);
1456
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1457
0
    return gnutls_assert_val(ret);
1458
0
  }
1459
1460
1.02k
  ret = gnutls_aead_cipher_encrypt(handle, nonce, nonce_len, auth.data,
1461
1.02k
           auth.length, tag_size, ptext.data,
1462
1.02k
           ptext.length, ctext, ctext_len);
1463
1.02k
  iov_store_free(&auth);
1464
1.02k
  iov_store_free(&ptext);
1465
1466
  /* FIPS operation state is set by gnutls_aead_cipher_encrypt */
1467
1.02k
  return ret;
1468
1.02k
}
1469
1470
static int aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle,
1471
        const void *nonce, size_t nonce_len,
1472
        const giovec_t *auth_iov, int auth_iovcnt,
1473
        size_t tag_size, const giovec_t *iov,
1474
        int iovcnt, void *ctext, size_t *ctext_len)
1475
2.65k
{
1476
2.65k
  int ret;
1477
2.65k
  uint8_t *dst;
1478
2.65k
  size_t dst_size, total = 0;
1479
2.65k
  uint8_t *p;
1480
2.65k
  size_t len;
1481
2.65k
  size_t blocksize = handle->ctx_enc.e->blocksize;
1482
2.65k
  struct iov_iter_st iter;
1483
1484
2.65k
  if (tag_size == 0)
1485
0
    tag_size = _gnutls_cipher_get_tag_size(handle->ctx_enc.e);
1486
2.65k
  else if (tag_size >
1487
2.65k
     (unsigned)_gnutls_cipher_get_tag_size(handle->ctx_enc.e)) {
1488
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1489
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1490
0
  }
1491
1492
2.65k
  ret = _gnutls_cipher_setiv(&handle->ctx_enc, nonce, nonce_len);
1493
2.65k
  if (unlikely(ret < 0)) {
1494
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1495
0
    return gnutls_assert_val(ret);
1496
0
  }
1497
1498
2.65k
  ret = _gnutls_iov_iter_init(&iter, auth_iov, auth_iovcnt, blocksize);
1499
2.65k
  if (unlikely(ret < 0)) {
1500
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1501
0
    return gnutls_assert_val(ret);
1502
0
  }
1503
5.30k
  while (1) {
1504
5.30k
    ret = _gnutls_iov_iter_next(&iter, &p);
1505
5.30k
    if (unlikely(ret < 0)) {
1506
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1507
0
      return gnutls_assert_val(ret);
1508
0
    }
1509
5.30k
    if (ret == 0)
1510
2.65k
      break;
1511
2.65k
    ret = _gnutls_cipher_auth(&handle->ctx_enc, p, ret);
1512
2.65k
    if (unlikely(ret < 0)) {
1513
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1514
0
      return gnutls_assert_val(ret);
1515
0
    }
1516
2.65k
  }
1517
1518
2.65k
  dst = ctext;
1519
2.65k
  dst_size = *ctext_len;
1520
1521
2.65k
  ret = _gnutls_iov_iter_init(&iter, iov, iovcnt, blocksize);
1522
2.65k
  if (unlikely(ret < 0)) {
1523
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1524
0
    return gnutls_assert_val(ret);
1525
0
  }
1526
7.18k
  while (1) {
1527
7.18k
    ret = _gnutls_iov_iter_next(&iter, &p);
1528
7.18k
    if (unlikely(ret < 0)) {
1529
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1530
0
      return gnutls_assert_val(ret);
1531
0
    }
1532
7.18k
    if (ret == 0)
1533
2.65k
      break;
1534
4.53k
    len = ret;
1535
4.53k
    ret = _gnutls_cipher_encrypt2(&handle->ctx_enc, p, len, dst,
1536
4.53k
                dst_size);
1537
4.53k
    if (unlikely(ret < 0)) {
1538
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1539
0
      return gnutls_assert_val(ret);
1540
0
    }
1541
1542
4.53k
    DECR_LEN(dst_size, len);
1543
4.53k
    dst += len;
1544
4.53k
    total += len;
1545
4.53k
  }
1546
1547
2.65k
  if (dst_size < tag_size) {
1548
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1549
0
    return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
1550
0
  }
1551
1552
2.65k
  _gnutls_cipher_tag(&handle->ctx_enc, dst, tag_size);
1553
1554
2.65k
  total += tag_size;
1555
2.65k
  *ctext_len = total;
1556
1557
2.65k
  _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
1558
2.65k
  return 0;
1559
2.65k
}
1560
1561
/**
1562
 * gnutls_aead_cipher_encryptv:
1563
 * @handle: is a #gnutls_aead_cipher_hd_t type.
1564
 * @nonce: the nonce to set
1565
 * @nonce_len: The length of the nonce
1566
 * @auth_iov: additional data to be authenticated
1567
 * @auth_iovcnt: The number of buffers in @auth_iov
1568
 * @tag_size: The size of the tag to use (use zero for the default)
1569
 * @iov: the data to be encrypted
1570
 * @iovcnt: The number of buffers in @iov
1571
 * @ctext: the encrypted data including authentication tag
1572
 * @ctext_len: the length of encrypted data (initially must hold the maximum available size, including space for tag)
1573
 *
1574
 * This function will encrypt the provided data buffers using the algorithm
1575
 * specified by the context. The output data will contain the
1576
 * authentication tag.
1577
 *
1578
 * Returns: Zero or a negative error code on error.
1579
 *
1580
 * Since: 3.6.3
1581
 **/
1582
int gnutls_aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle,
1583
        const void *nonce, size_t nonce_len,
1584
        const giovec_t *auth_iov, int auth_iovcnt,
1585
        size_t tag_size, const giovec_t *iov,
1586
        int iovcnt, void *ctext, size_t *ctext_len)
1587
3.67k
{
1588
  /* Limitation: this function provides an optimization under the internally registered
1589
   * AEAD ciphers. When an AEAD cipher is used registered with gnutls_crypto_register_aead_cipher(),
1590
   * then this becomes a convenience function as it missed the lower-level primitives
1591
   * necessary for piecemeal encryption. */
1592
3.67k
  if ((handle->ctx_enc.e->flags & GNUTLS_CIPHER_FLAG_ONLY_AEAD) ||
1593
2.65k
      handle->ctx_enc.encrypt == NULL) {
1594
1.02k
    return aead_cipher_encryptv_fallback(handle, nonce, nonce_len,
1595
1.02k
                 auth_iov, auth_iovcnt,
1596
1.02k
                 tag_size, iov, iovcnt,
1597
1.02k
                 ctext, ctext_len);
1598
2.65k
  } else {
1599
2.65k
    return aead_cipher_encryptv(handle, nonce, nonce_len, auth_iov,
1600
2.65k
              auth_iovcnt, tag_size, iov, iovcnt,
1601
2.65k
              ctext, ctext_len);
1602
2.65k
  }
1603
3.67k
}
1604
1605
static int aead_cipher_encryptv2_fallback(gnutls_aead_cipher_hd_t handle,
1606
            const void *nonce, size_t nonce_len,
1607
            const giovec_t *auth_iov,
1608
            int auth_iovcnt, const giovec_t *iov,
1609
            int iovcnt, void *tag,
1610
            size_t *tag_size)
1611
0
{
1612
0
  struct iov_store_st auth = IOV_STORE_INIT;
1613
0
  struct iov_store_st ptext = IOV_STORE_INIT;
1614
0
  uint8_t *ptext_data;
1615
0
  size_t ptext_size;
1616
0
  uint8_t *ctext_data;
1617
0
  size_t ctext_size;
1618
0
  uint8_t *_tag;
1619
0
  size_t _tag_size;
1620
0
  int ret;
1621
1622
0
  if (tag_size == NULL || *tag_size == 0)
1623
0
    _tag_size = _gnutls_cipher_get_tag_size(handle->ctx_enc.e);
1624
0
  else
1625
0
    _tag_size = *tag_size;
1626
1627
0
  if (_tag_size >
1628
0
      (unsigned)_gnutls_cipher_get_tag_size(handle->ctx_enc.e)) {
1629
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1630
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1631
0
  }
1632
1633
0
  ret = append_from_iov(&auth, auth_iov, auth_iovcnt);
1634
0
  if (ret < 0) {
1635
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1636
0
    return gnutls_assert_val(ret);
1637
0
  }
1638
1639
0
  if (handle->ctx_enc.e->flags & GNUTLS_CIPHER_FLAG_TAG_PREFIXED) {
1640
    /* prepend space for tag */
1641
0
    ret = iov_store_grow(&ptext, _tag_size);
1642
0
    if (ret < 0) {
1643
0
      gnutls_assert();
1644
0
      goto error;
1645
0
    }
1646
0
    ptext.length = _tag_size;
1647
1648
0
    ret = append_from_iov(&ptext, iov, iovcnt);
1649
0
    if (ret < 0) {
1650
0
      gnutls_assert();
1651
0
      goto error;
1652
0
    }
1653
1654
    /* We must set ptext_data after the above
1655
     * grow/append operations, otherwise it will point to an invalid pointer after realloc.
1656
     */
1657
0
    ptext_data = (uint8_t *)ptext.data + _tag_size;
1658
0
    ptext_size = ptext.length - _tag_size;
1659
0
  } else {
1660
0
    ret = append_from_iov(&ptext, iov, iovcnt);
1661
0
    if (ret < 0) {
1662
0
      gnutls_assert();
1663
0
      goto error;
1664
0
    }
1665
1666
    /* append space for tag */
1667
0
    ret = iov_store_grow(&ptext, _tag_size);
1668
0
    if (ret < 0) {
1669
0
      gnutls_assert();
1670
0
      goto error;
1671
0
    }
1672
1673
    /* We must set ptext_data after the above
1674
     * grow/append operations, otherwise it will point to an invalid pointer after realloc.
1675
     */
1676
0
    ptext_data = ptext.data;
1677
0
    ptext_size = ptext.length;
1678
0
  }
1679
1680
0
  ctext_size = ptext.capacity;
1681
0
  ret = gnutls_aead_cipher_encrypt(handle, nonce, nonce_len, auth.data,
1682
0
           auth.length, _tag_size, ptext_data,
1683
0
           ptext_size, ptext.data, &ctext_size);
1684
0
  if (ret < 0) {
1685
0
    gnutls_assert();
1686
0
    goto error;
1687
0
  }
1688
1689
0
  if (handle->ctx_enc.e->flags & GNUTLS_CIPHER_FLAG_TAG_PREFIXED) {
1690
0
    ctext_data = (uint8_t *)ptext.data + _tag_size;
1691
0
    _tag = ptext.data;
1692
0
  } else {
1693
0
    ctext_data = ptext.data;
1694
0
    _tag = (uint8_t *)ptext.data + ptext_size;
1695
0
  }
1696
1697
0
  ret = copy_to_iov(ctext_data, ptext_size, iov, iovcnt);
1698
0
  if (ret < 0) {
1699
0
    gnutls_assert();
1700
0
    goto error;
1701
0
  }
1702
1703
0
  if (tag != NULL) {
1704
0
    memcpy(tag, _tag, _tag_size);
1705
0
  }
1706
0
  if (tag_size != NULL) {
1707
0
    *tag_size = _tag_size;
1708
0
  }
1709
1710
0
error:
1711
0
  iov_store_free(&auth);
1712
0
  iov_store_free(&ptext);
1713
1714
0
  if (ret < 0) {
1715
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1716
0
  }
1717
  /* FIPS operation state is set by gnutls_aead_cipher_encrypt */
1718
0
  return ret;
1719
0
}
1720
1721
static int aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle,
1722
         const void *nonce, size_t nonce_len,
1723
         const giovec_t *auth_iov, int auth_iovcnt,
1724
         const giovec_t *iov, int iovcnt, void *tag,
1725
         size_t *tag_size)
1726
0
{
1727
0
  api_aead_cipher_hd_st *h = handle;
1728
0
  int ret;
1729
0
  uint8_t *p;
1730
0
  size_t len;
1731
0
  size_t blocksize = handle->ctx_enc.e->blocksize;
1732
0
  struct iov_iter_st iter;
1733
0
  size_t _tag_size;
1734
1735
0
  if (tag_size == NULL || *tag_size == 0)
1736
0
    _tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e);
1737
0
  else
1738
0
    _tag_size = *tag_size;
1739
1740
0
  if (_tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e)) {
1741
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1742
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1743
0
  }
1744
1745
0
  ret = _gnutls_cipher_setiv(&handle->ctx_enc, nonce, nonce_len);
1746
0
  if (unlikely(ret < 0)) {
1747
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1748
0
    return gnutls_assert_val(ret);
1749
0
  }
1750
1751
0
  ret = _gnutls_iov_iter_init(&iter, auth_iov, auth_iovcnt, blocksize);
1752
0
  if (unlikely(ret < 0)) {
1753
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1754
0
    return gnutls_assert_val(ret);
1755
0
  }
1756
0
  while (1) {
1757
0
    ret = _gnutls_iov_iter_next(&iter, &p);
1758
0
    if (unlikely(ret < 0)) {
1759
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1760
0
      return gnutls_assert_val(ret);
1761
0
    }
1762
0
    if (ret == 0)
1763
0
      break;
1764
0
    ret = _gnutls_cipher_auth(&handle->ctx_enc, p, ret);
1765
0
    if (unlikely(ret < 0)) {
1766
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1767
0
      return gnutls_assert_val(ret);
1768
0
    }
1769
0
  }
1770
1771
0
  ret = _gnutls_iov_iter_init(&iter, iov, iovcnt, blocksize);
1772
0
  if (unlikely(ret < 0))
1773
0
    return gnutls_assert_val(ret);
1774
0
  while (1) {
1775
0
    ret = _gnutls_iov_iter_next(&iter, &p);
1776
0
    if (unlikely(ret < 0)) {
1777
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1778
0
      return gnutls_assert_val(ret);
1779
0
    }
1780
0
    if (ret == 0)
1781
0
      break;
1782
1783
0
    len = ret;
1784
0
    ret = _gnutls_cipher_encrypt2(&handle->ctx_enc, p, len, p, len);
1785
0
    if (unlikely(ret < 0)) {
1786
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1787
0
      return gnutls_assert_val(ret);
1788
0
    }
1789
1790
0
    ret = _gnutls_iov_iter_sync(&iter, p, len);
1791
0
    if (unlikely(ret < 0)) {
1792
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1793
0
      return gnutls_assert_val(ret);
1794
0
    }
1795
0
  }
1796
1797
0
  if (tag != NULL)
1798
0
    _gnutls_cipher_tag(&handle->ctx_enc, tag, _tag_size);
1799
0
  if (tag_size != NULL)
1800
0
    *tag_size = _tag_size;
1801
1802
0
  _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
1803
0
  return 0;
1804
0
}
1805
1806
/**
1807
 * gnutls_aead_cipher_encryptv2:
1808
 * @handle: is a #gnutls_aead_cipher_hd_t type.
1809
 * @nonce: the nonce to set
1810
 * @nonce_len: The length of the nonce
1811
 * @auth_iov: additional data to be authenticated
1812
 * @auth_iovcnt: The number of buffers in @auth_iov
1813
 * @iov: the data to be encrypted
1814
 * @iovcnt: The number of buffers in @iov
1815
 * @tag: The authentication tag
1816
 * @tag_size: The size of the tag to use (use zero for the default)
1817
 *
1818
 * This is similar to gnutls_aead_cipher_encrypt(), but it performs
1819
 * in-place encryption on the provided data buffers.
1820
 *
1821
 * Returns: Zero or a negative error code on error.
1822
 *
1823
 * Since: 3.6.10
1824
 **/
1825
int gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle,
1826
         const void *nonce, size_t nonce_len,
1827
         const giovec_t *auth_iov, int auth_iovcnt,
1828
         const giovec_t *iov, int iovcnt, void *tag,
1829
         size_t *tag_size)
1830
0
{
1831
  /* Limitation: this function provides an optimization under the internally registered
1832
   * AEAD ciphers. When an AEAD cipher is used registered with gnutls_crypto_register_aead_cipher(),
1833
   * then this becomes a convenience function as it missed the lower-level primitives
1834
   * necessary for piecemeal encryption. */
1835
0
  if ((handle->ctx_enc.e->flags & GNUTLS_CIPHER_FLAG_ONLY_AEAD) ||
1836
0
      handle->ctx_enc.encrypt == NULL) {
1837
0
    return aead_cipher_encryptv2_fallback(handle, nonce, nonce_len,
1838
0
                  auth_iov, auth_iovcnt,
1839
0
                  iov, iovcnt, tag,
1840
0
                  tag_size);
1841
0
  } else {
1842
0
    return aead_cipher_encryptv2(handle, nonce, nonce_len, auth_iov,
1843
0
               auth_iovcnt, iov, iovcnt, tag,
1844
0
               tag_size);
1845
0
  }
1846
0
}
1847
1848
static int aead_cipher_decryptv2_fallback(gnutls_aead_cipher_hd_t handle,
1849
            const void *nonce, size_t nonce_len,
1850
            const giovec_t *auth_iov,
1851
            int auth_iovcnt, const giovec_t *iov,
1852
            int iovcnt, void *tag,
1853
            size_t tag_size)
1854
0
{
1855
0
  struct iov_store_st auth = IOV_STORE_INIT;
1856
0
  struct iov_store_st ctext = IOV_STORE_INIT;
1857
0
  uint8_t *ctext_data;
1858
0
  size_t ptext_size;
1859
0
  int ret;
1860
1861
0
  if (tag_size == 0)
1862
0
    tag_size = _gnutls_cipher_get_tag_size(handle->ctx_enc.e);
1863
0
  else if (tag_size >
1864
0
     (unsigned)_gnutls_cipher_get_tag_size(handle->ctx_enc.e)) {
1865
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1866
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1867
0
  }
1868
1869
0
  ret = append_from_iov(&auth, auth_iov, auth_iovcnt);
1870
0
  if (ret < 0) {
1871
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1872
0
    return gnutls_assert_val(ret);
1873
0
  }
1874
1875
0
  if (handle->ctx_enc.e->flags & GNUTLS_CIPHER_FLAG_TAG_PREFIXED) {
1876
    /* prepend tag */
1877
0
    ret = iov_store_grow(&ctext, tag_size);
1878
0
    if (ret < 0) {
1879
0
      gnutls_assert();
1880
0
      goto error;
1881
0
    }
1882
0
    memcpy(ctext.data, tag, tag_size);
1883
0
    ctext.length += tag_size;
1884
1885
0
    ret = append_from_iov(&ctext, iov, iovcnt);
1886
0
    if (ret < 0) {
1887
0
      gnutls_assert();
1888
0
      goto error;
1889
0
    }
1890
1891
    /* We must set ctext_data after the above
1892
     * grow/append operations, otherwise it will point to an invalid pointer after realloc.
1893
     */
1894
0
    ctext_data = (uint8_t *)ctext.data + tag_size;
1895
0
  } else {
1896
0
    ret = append_from_iov(&ctext, iov, iovcnt);
1897
0
    if (ret < 0) {
1898
0
      gnutls_assert();
1899
0
      goto error;
1900
0
    }
1901
1902
    /* append tag */
1903
0
    ret = iov_store_grow(&ctext, tag_size);
1904
0
    if (ret < 0) {
1905
0
      gnutls_assert();
1906
0
      goto error;
1907
0
    }
1908
0
    memcpy((uint8_t *)ctext.data + ctext.length, tag, tag_size);
1909
0
    ctext.length += tag_size;
1910
1911
    /* We must set ctext_data after the above
1912
     * grow/append operations, otherwise it will point to an invalid pointer after realloc.
1913
     */
1914
0
    ctext_data = ctext.data;
1915
0
  }
1916
1917
0
  ptext_size = ctext.capacity;
1918
0
  ret = gnutls_aead_cipher_decrypt(handle, nonce, nonce_len, auth.data,
1919
0
           auth.length, tag_size, ctext.data,
1920
0
           ctext.length, ctext_data, &ptext_size);
1921
0
  if (ret < 0) {
1922
0
    gnutls_assert();
1923
0
    goto error;
1924
0
  }
1925
1926
0
  ret = copy_to_iov(ctext.data, ptext_size, iov, iovcnt);
1927
0
  if (ret < 0) {
1928
0
    gnutls_assert();
1929
0
    goto error;
1930
0
  }
1931
1932
0
error:
1933
0
  iov_store_free(&auth);
1934
0
  iov_store_free(&ctext);
1935
1936
0
  if (ret < 0) {
1937
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1938
0
  }
1939
  /* FIPS operation state is set by gnutls_aead_cipher_decrypt */
1940
0
  return ret;
1941
0
}
1942
1943
static int aead_cipher_decryptv2(gnutls_aead_cipher_hd_t handle,
1944
         const void *nonce, size_t nonce_len,
1945
         const giovec_t *auth_iov, int auth_iovcnt,
1946
         const giovec_t *iov, int iovcnt, void *tag,
1947
         size_t tag_size)
1948
0
{
1949
0
  int ret;
1950
0
  uint8_t *p;
1951
0
  size_t len;
1952
0
  ssize_t blocksize = handle->ctx_enc.e->blocksize;
1953
0
  struct iov_iter_st iter;
1954
0
  uint8_t _tag[MAX_HASH_SIZE];
1955
1956
0
  if (tag_size == 0)
1957
0
    tag_size = _gnutls_cipher_get_tag_size(handle->ctx_enc.e);
1958
0
  else if (tag_size >
1959
0
     (unsigned)_gnutls_cipher_get_tag_size(handle->ctx_enc.e)) {
1960
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1961
0
    return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1962
0
  }
1963
1964
0
  ret = _gnutls_cipher_setiv(&handle->ctx_enc, nonce, nonce_len);
1965
0
  if (unlikely(ret < 0)) {
1966
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1967
0
    return gnutls_assert_val(ret);
1968
0
  }
1969
1970
0
  ret = _gnutls_iov_iter_init(&iter, auth_iov, auth_iovcnt, blocksize);
1971
0
  if (unlikely(ret < 0)) {
1972
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1973
0
    return gnutls_assert_val(ret);
1974
0
  }
1975
0
  while (1) {
1976
0
    ret = _gnutls_iov_iter_next(&iter, &p);
1977
0
    if (unlikely(ret < 0)) {
1978
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1979
0
      return gnutls_assert_val(ret);
1980
0
    }
1981
0
    if (ret == 0)
1982
0
      break;
1983
0
    ret = _gnutls_cipher_auth(&handle->ctx_enc, p, ret);
1984
0
    if (unlikely(ret < 0)) {
1985
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1986
0
      return gnutls_assert_val(ret);
1987
0
    }
1988
0
  }
1989
1990
0
  ret = _gnutls_iov_iter_init(&iter, iov, iovcnt, blocksize);
1991
0
  if (unlikely(ret < 0)) {
1992
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1993
0
    return gnutls_assert_val(ret);
1994
0
  }
1995
0
  while (1) {
1996
0
    ret = _gnutls_iov_iter_next(&iter, &p);
1997
0
    if (unlikely(ret < 0)) {
1998
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
1999
0
      return gnutls_assert_val(ret);
2000
0
    }
2001
0
    if (ret == 0)
2002
0
      break;
2003
2004
0
    len = ret;
2005
0
    ret = _gnutls_cipher_decrypt2(&handle->ctx_enc, p, len, p, len);
2006
0
    if (unlikely(ret < 0)) {
2007
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
2008
0
      return gnutls_assert_val(ret);
2009
0
    }
2010
2011
0
    ret = _gnutls_iov_iter_sync(&iter, p, len);
2012
0
    if (unlikely(ret < 0)) {
2013
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
2014
0
      return gnutls_assert_val(ret);
2015
0
    }
2016
0
  }
2017
2018
0
  if (tag != NULL) {
2019
0
    _gnutls_cipher_tag(&handle->ctx_enc, _tag, tag_size);
2020
0
    if (gnutls_memcmp(_tag, tag, tag_size) != 0) {
2021
0
      _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
2022
0
      return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
2023
0
    }
2024
0
  }
2025
2026
0
  _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
2027
0
  return 0;
2028
0
}
2029
2030
/**
2031
 * gnutls_aead_cipher_decryptv2:
2032
 * @handle: is a #gnutls_aead_cipher_hd_t type.
2033
 * @nonce: the nonce to set
2034
 * @nonce_len: The length of the nonce
2035
 * @auth_iov: additional data to be authenticated
2036
 * @auth_iovcnt: The number of buffers in @auth_iov
2037
 * @iov: the data to decrypt
2038
 * @iovcnt: The number of buffers in @iov
2039
 * @tag: The authentication tag
2040
 * @tag_size: The size of the tag to use (use zero for the default)
2041
 *
2042
 * This is similar to gnutls_aead_cipher_decrypt(), but it performs
2043
 * in-place encryption on the provided data buffers.
2044
 *
2045
 * Returns: Zero or a negative error code on error.
2046
 *
2047
 * Since: 3.6.10
2048
 **/
2049
int gnutls_aead_cipher_decryptv2(gnutls_aead_cipher_hd_t handle,
2050
         const void *nonce, size_t nonce_len,
2051
         const giovec_t *auth_iov, int auth_iovcnt,
2052
         const giovec_t *iov, int iovcnt, void *tag,
2053
         size_t tag_size)
2054
0
{
2055
  /* Limitation: this function provides an optimization under the internally registered
2056
   * AEAD ciphers. When an AEAD cipher is used registered with gnutls_crypto_register_aead_cipher(),
2057
   * then this becomes a convenience function as it missed the lower-level primitives
2058
   * necessary for piecemeal encryption. */
2059
0
  if ((handle->ctx_enc.e->flags & GNUTLS_CIPHER_FLAG_ONLY_AEAD) ||
2060
0
      handle->ctx_enc.encrypt == NULL) {
2061
0
    return aead_cipher_decryptv2_fallback(handle, nonce, nonce_len,
2062
0
                  auth_iov, auth_iovcnt,
2063
0
                  iov, iovcnt, tag,
2064
0
                  tag_size);
2065
0
  } else {
2066
0
    return aead_cipher_decryptv2(handle, nonce, nonce_len, auth_iov,
2067
0
               auth_iovcnt, iov, iovcnt, tag,
2068
0
               tag_size);
2069
0
  }
2070
0
}
2071
2072
/**
2073
 * gnutls_aead_cipher_deinit:
2074
 * @handle: is a #gnutls_aead_cipher_hd_t type.
2075
 *
2076
 * This function will deinitialize all resources occupied by the given
2077
 * authenticated-encryption context.
2078
 *
2079
 * Since: 3.4.0
2080
 **/
2081
void gnutls_aead_cipher_deinit(gnutls_aead_cipher_hd_t handle)
2082
0
{
2083
0
  _gnutls_aead_cipher_deinit(handle);
2084
0
  gnutls_free(handle);
2085
0
}
2086
2087
/* Same as @gnutls_hkdf_extract but without changing FIPS context */
2088
int _gnutls_hkdf_extract(gnutls_mac_algorithm_t mac, const gnutls_datum_t *key,
2089
       const gnutls_datum_t *salt, void *output)
2090
7.84k
{
2091
  /* MD5 is only allowed internally for TLS */
2092
7.84k
  if (!is_mac_algo_allowed(mac)) {
2093
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
2094
0
    return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
2095
0
  }
2096
2097
  /* We don't check whether MAC is approved, because HKDF is
2098
   * only approved in TLS, which is handled separately. */
2099
2100
7.84k
  return _gnutls_kdf_backend()->hkdf_extract(mac, key->data, key->size,
2101
7.84k
               salt ? salt->data : NULL,
2102
7.84k
               salt ? salt->size : 0,
2103
7.84k
               output);
2104
7.84k
}
2105
2106
/**
2107
 * gnutls_hkdf_extract:
2108
 * @mac: the mac algorithm used internally
2109
 * @key: the initial keying material
2110
 * @salt: the optional salt
2111
 * @output: the output value of the extract operation
2112
 *
2113
 * This function will derive a fixed-size key using the HKDF-Extract
2114
 * function as defined in RFC 5869.
2115
 *
2116
 * Returns: Zero or a negative error code on error.
2117
 *
2118
 * Since: 3.6.13
2119
 */
2120
int gnutls_hkdf_extract(gnutls_mac_algorithm_t mac, const gnutls_datum_t *key,
2121
      const gnutls_datum_t *salt, void *output)
2122
0
{
2123
0
  int ret;
2124
2125
0
  ret = _gnutls_hkdf_extract(mac, key, salt, output);
2126
0
  if (ret < 0)
2127
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
2128
0
  else
2129
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
2130
2131
0
  return ret;
2132
0
}
2133
2134
/* Same as @gnutls_hkdf_expand but without changing FIPS context */
2135
int _gnutls_hkdf_expand(gnutls_mac_algorithm_t mac, const gnutls_datum_t *key,
2136
      const gnutls_datum_t *info, void *output, size_t length)
2137
141k
{
2138
  /* MD5 is only allowed internally for TLS */
2139
141k
  if (!is_mac_algo_allowed(mac)) {
2140
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
2141
0
    return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
2142
0
  }
2143
2144
  /* We don't check whether MAC is approved, because HKDF is
2145
   * only approved in TLS, which is handled separately. */
2146
2147
141k
  return _gnutls_kdf_backend()->hkdf_expand(mac, key->data, key->size,
2148
141k
              info->data, info->size,
2149
141k
              output, length);
2150
141k
}
2151
2152
/**
2153
 * gnutls_hkdf_expand:
2154
 * @mac: the mac algorithm used internally
2155
 * @key: the pseudorandom key created with HKDF-Extract
2156
 * @info: the optional informational data
2157
 * @output: the output value of the expand operation
2158
 * @length: the desired length of the output key
2159
 *
2160
 * This function will derive a variable length keying material from
2161
 * the pseudorandom key using the HKDF-Expand function as defined in
2162
 * RFC 5869.
2163
 *
2164
 * Returns: Zero or a negative error code on error.
2165
 *
2166
 * Since: 3.6.13
2167
 */
2168
int gnutls_hkdf_expand(gnutls_mac_algorithm_t mac, const gnutls_datum_t *key,
2169
           const gnutls_datum_t *info, void *output, size_t length)
2170
0
{
2171
0
  int ret;
2172
2173
0
  ret = _gnutls_hkdf_expand(mac, key, info, output, length);
2174
0
  if (ret < 0)
2175
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
2176
0
  else
2177
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
2178
2179
0
  return ret;
2180
0
}
2181
2182
/**
2183
 * gnutls_pbkdf2:
2184
 * @mac: the mac algorithm used internally
2185
 * @key: the initial keying material
2186
 * @salt: the salt
2187
 * @iter_count: the iteration count
2188
 * @output: the output value
2189
 * @length: the desired length of the output key
2190
 *
2191
 * This function will derive a variable length keying material from
2192
 * a password according to PKCS #5 PBKDF2.
2193
 *
2194
 * Returns: Zero or a negative error code on error.
2195
 *
2196
 * Since: 3.6.13
2197
 */
2198
int gnutls_pbkdf2(gnutls_mac_algorithm_t mac, const gnutls_datum_t *key,
2199
      const gnutls_datum_t *salt, unsigned iter_count, void *output,
2200
      size_t length)
2201
7.42k
{
2202
7.42k
  int ret;
2203
7.42k
  bool not_approved = false;
2204
2205
  /* MD5 is only allowed internally for TLS */
2206
7.42k
  if (!is_mac_algo_allowed(mac)) {
2207
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
2208
0
    return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
2209
7.42k
  } else if (!is_mac_algo_hmac_approved_in_fips(mac)) {
2210
    /* ACVP only allows HMAC used with PBKDF2:
2211
     * https://pages.nist.gov/ACVP/draft-celi-acvp-pbkdf.html
2212
     */
2213
1.62k
    not_approved = true;
2214
1.62k
  }
2215
2216
  /* Key lengths and output sizes of less than 112 bits are not approved */
2217
7.42k
  if (key->size < 14 || length < 14) {
2218
7.42k
    not_approved = true;
2219
7.42k
  }
2220
2221
  /* Minimum salt length of 128 bits (SP 800-132 5.1) */
2222
7.42k
  if (salt->size < 16) {
2223
1.42k
    not_approved = true;
2224
1.42k
  }
2225
2226
  /* Minimum iterations bound (SP 800-132 5.2) */
2227
7.42k
  if (iter_count < 1000) {
2228
5.96k
    not_approved = true;
2229
5.96k
  }
2230
2231
7.42k
  ret = _gnutls_kdf_backend()->pbkdf2(mac, key->data, key->size,
2232
7.42k
              salt->data, salt->size, iter_count,
2233
7.42k
              output, length);
2234
7.42k
  if (ret < 0) {
2235
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
2236
7.42k
  } else if (not_approved) {
2237
7.42k
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
2238
7.42k
  } else {
2239
0
    _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
2240
0
  }
2241
7.42k
  return ret;
2242
7.42k
}