Coverage Report

Created: 2026-11-12 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/fips.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2013 Red Hat
3
 *
4
 * Author: Nikos Mavrogiannopoulos
5
 *
6
 * This file is part of GnuTLS.
7
 *
8
 * The GnuTLS is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * as published by the Free Software Foundation; either version 2.1 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
20
 *
21
 */
22
#include "gnutls_int.h"
23
#include <gnutls/gnutls.h>
24
#include <gnutls/crypto.h>
25
#include <unistd.h>
26
#include "dirname.h"
27
#include "errors.h"
28
#include "file.h"
29
#include "inih/ini.h"
30
#include "str.h"
31
#include "fips.h"
32
#include <gnutls/self-test.h>
33
#include <stdio.h>
34
#include "extras/hex.h"
35
#include "random.h"
36
37
#include "gthreads.h"
38
39
#ifdef HAVE_DL_ITERATE_PHDR
40
#include <link.h>
41
#endif
42
43
unsigned int _gnutls_lib_state = LIB_STATE_POWERON;
44
45
#ifdef ENABLE_FIPS140
46
47
#include <dlfcn.h>
48
49
#define FIPS_KERNEL_FILE "/proc/sys/crypto/fips_enabled"
50
#define FIPS_SYSTEM_FILE "/etc/system-fips"
51
52
/* We provide a per-thread FIPS-mode so that an application
53
 * can use gnutls_fips140_set_mode() to override a specific
54
 * operation on a thread */
55
static gnutls_fips_mode_t _global_fips_mode = -1;
56
static _Thread_local gnutls_fips_mode_t _tfips_mode = -1;
57
58
static _Thread_local gnutls_fips140_context_t _tfips_context = NULL;
59
60
static int _skip_integrity_checks = 0;
61
62
/* Returns:
63
 * a gnutls_fips_mode_t value
64
 */
65
unsigned _gnutls_fips_mode_enabled(void)
66
{
67
  unsigned f1p = 0, f2p;
68
  FILE *fd;
69
  const char *p;
70
  unsigned ret;
71
72
  /* We initialize this threads' mode, and
73
   * the global mode if not already initialized.
74
   * When the global mode is initialized, then
75
   * the thread mode is copied from it. As this
76
   * is called on library initialization, the
77
   * _global_fips_mode is always set during app run.
78
   */
79
  if (_tfips_mode != (gnutls_fips_mode_t)-1)
80
    return _tfips_mode;
81
82
  if (_global_fips_mode != (gnutls_fips_mode_t)-1) {
83
    return _global_fips_mode;
84
  }
85
86
  p = secure_getenv("GNUTLS_SKIP_FIPS_INTEGRITY_CHECKS");
87
  if (p && p[0] == '1') {
88
    _skip_integrity_checks = 1;
89
  }
90
91
  p = secure_getenv("GNUTLS_FORCE_FIPS_MODE");
92
  if (p) {
93
    if (p[0] == '1')
94
      ret = GNUTLS_FIPS140_STRICT;
95
    else if (p[0] == '2')
96
      ret = GNUTLS_FIPS140_SELFTESTS;
97
    else if (p[0] == '3')
98
      ret = GNUTLS_FIPS140_LAX;
99
    else if (p[0] == '4')
100
      ret = GNUTLS_FIPS140_LOG;
101
    else
102
      ret = GNUTLS_FIPS140_DISABLED;
103
104
    goto exit;
105
  }
106
107
  fd = fopen(FIPS_KERNEL_FILE, "re");
108
  if (fd != NULL) {
109
    f1p = fgetc(fd);
110
    fclose(fd);
111
112
    if (f1p == '1')
113
      f1p = 1;
114
    else
115
      f1p = 0;
116
  }
117
118
  if (f1p != 0) {
119
    _gnutls_debug_log("FIPS140-2 mode enabled\n");
120
    ret = GNUTLS_FIPS140_STRICT;
121
    goto exit;
122
  }
123
124
  f2p = !access(FIPS_SYSTEM_FILE, F_OK);
125
  if (f2p != 0) {
126
    /* a funny state where self tests are performed
127
     * and ignored */
128
    _gnutls_debug_log("FIPS140-2 ZOMBIE mode enabled\n");
129
    ret = GNUTLS_FIPS140_SELFTESTS;
130
    goto exit;
131
  }
132
133
  ret = GNUTLS_FIPS140_DISABLED;
134
  goto exit;
135
136
exit:
137
  _global_fips_mode = ret;
138
  return ret;
139
}
140
141
/* This _fips_mode == 2 is a strange mode where checks are being
142
 * performed, but its output is ignored. */
143
void _gnutls_fips_mode_reset_zombie(void)
144
{
145
  if (_global_fips_mode == GNUTLS_FIPS140_SELFTESTS) {
146
    _global_fips_mode = GNUTLS_FIPS140_DISABLED;
147
  }
148
}
149
150
/* These only works with the platform where SONAME is part of the ABI. */
151
#ifndef GNUTLS_LIBRARY_SONAME
152
#define GNUTLS_LIBRARY_SONAME "none"
153
#endif
154
155
#define HMAC_SIZE 32
156
#define HMAC_ALGO GNUTLS_MAC_SHA256
157
#define HMAC_FORMAT_VERSION 1
158
159
struct hmac_entry {
160
  char path[GNUTLS_PATH_MAX];
161
  uint8_t hmac[HMAC_SIZE];
162
};
163
164
struct hmac_file {
165
  int version;
166
  struct hmac_entry gnutls;
167
#ifdef NETTLE_LIBRARY_SONAME
168
  struct hmac_entry nettle;
169
#endif
170
#ifdef HOGWEED_LIBRARY_SONAME
171
  struct hmac_entry hogweed;
172
#endif
173
#ifdef GMP_LIBRARY_SONAME
174
  struct hmac_entry gmp;
175
#endif
176
};
177
178
struct lib_paths {
179
  char gnutls[GNUTLS_PATH_MAX];
180
#ifdef NETTLE_LIBRARY_SONAME
181
  char nettle[GNUTLS_PATH_MAX];
182
#endif
183
#ifdef HOGWEED_LIBRARY_SONAME
184
  char hogweed[GNUTLS_PATH_MAX];
185
#endif
186
#ifdef GMP_LIBRARY_SONAME
187
  char gmp[GNUTLS_PATH_MAX];
188
#endif
189
};
190
191
/*
192
 * get_hmac:
193
 * @dest: buffer for the hex value
194
 * @value: hmac value
195
 *
196
 * Parses hmac data and copies hex value into dest.
197
 * dest must point to at least HMAC_SIZE amount of memory
198
 *
199
 * Returns: 0 on success, a negative error code otherwise
200
 */
201
static int get_hmac(uint8_t *dest, const char *value)
202
{
203
  int ret;
204
  size_t hmac_size;
205
  gnutls_datum_t data;
206
207
  data.size = strlen(value);
208
  data.data = (unsigned char *)value;
209
210
  hmac_size = HMAC_SIZE;
211
  ret = gnutls_hex_decode(&data, dest, &hmac_size);
212
  if (ret < 0)
213
    return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
214
215
  if (hmac_size != HMAC_SIZE)
216
    return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
217
218
  return 0;
219
}
220
221
static int lib_handler(struct hmac_entry *entry, const char *section,
222
           const char *name, const char *value)
223
{
224
  if (streq(name, "path")) {
225
    snprintf(entry->path, GNUTLS_PATH_MAX, "%s", value);
226
  } else if (streq(name, "hmac")) {
227
    if (get_hmac(entry->hmac, value) < 0)
228
      return 0;
229
  } else {
230
    return 0;
231
  }
232
  return 1;
233
}
234
235
static int handler(void *user, const char *section, const char *name,
236
       const char *value)
237
{
238
  struct hmac_file *p = (struct hmac_file *)user;
239
240
  if (streq(section, "global")) {
241
    if (streq(name, "format-version")) {
242
      p->version = strtol(value, NULL, 10);
243
    } else {
244
      return 0;
245
    }
246
  } else if (streq(section, GNUTLS_LIBRARY_SONAME)) {
247
    return lib_handler(&p->gnutls, section, name, value);
248
#ifdef NETTLE_LIBRARY_SONAME
249
  } else if (streq(section, NETTLE_LIBRARY_SONAME)) {
250
    return lib_handler(&p->nettle, section, name, value);
251
#endif
252
#ifdef HOGWEED_LIBRARY_SONAME
253
  } else if (streq(section, HOGWEED_LIBRARY_SONAME)) {
254
    return lib_handler(&p->hogweed, section, name, value);
255
#endif
256
#ifdef GMP_LIBRARY_SONAME
257
  } else if (streq(section, GMP_LIBRARY_SONAME)) {
258
    return lib_handler(&p->gmp, section, name, value);
259
#endif
260
  } else {
261
    return 0;
262
  }
263
  return 1;
264
}
265
266
/*
267
 * get_hmac_path:
268
 * @mac_file: buffer where the hmac file path will be written to
269
 * @mac_file_size: size of the mac_file buffer
270
 * @gnutls_path: path to the gnutls library, used to deduce hmac file path
271
 * 
272
 * Deduces hmac file path from the gnutls library path.
273
 *
274
 * Returns: 0 on success, a negative error code otherwise
275
 */
276
static int get_hmac_path(char *mac_file, size_t mac_file_size,
277
       const char *gnutls_path)
278
{
279
  int ret;
280
  const char *p;
281
282
  p = strrchr(gnutls_path, '/');
283
284
  if (p == NULL)
285
    ret = snprintf(mac_file, mac_file_size, ".%s.hmac",
286
             gnutls_path);
287
  else
288
    ret = snprintf(mac_file, mac_file_size, "%.*s/.%s.hmac",
289
             (int)(p - gnutls_path), gnutls_path, p + 1);
290
291
  if ((size_t)ret >= mac_file_size)
292
    return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
293
294
  ret = _gnutls_file_exists(mac_file);
295
  if (ret == 0)
296
    return GNUTLS_E_SUCCESS;
297
298
  if (p == NULL)
299
    ret = snprintf(mac_file, mac_file_size, "fipscheck/.%s.hmac",
300
             gnutls_path);
301
  else
302
    ret = snprintf(mac_file, mac_file_size,
303
             "%.*s/fipscheck/.%s.hmac",
304
             (int)(p - gnutls_path), gnutls_path, p + 1);
305
306
  if ((size_t)ret >= mac_file_size)
307
    return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
308
309
  ret = _gnutls_file_exists(mac_file);
310
  if (ret == 0)
311
    return GNUTLS_E_SUCCESS;
312
313
  return GNUTLS_E_FILE_ERROR;
314
}
315
316
/*
317
 * load_hmac_file:
318
 * @hmac_file: hmac file structure
319
 * @hmac_path: path to the hmac file
320
 *
321
 * Loads the hmac file into the hmac file structure.
322
 *
323
 * Returns: 0 on success, a negative error code otherwise
324
 */
325
static int load_hmac_file(struct hmac_file *hmac_file, const char *hmac_path)
326
{
327
  int ret;
328
  FILE *stream;
329
330
  stream = fopen(hmac_path, "r");
331
  if (stream == NULL)
332
    return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
333
334
  gnutls_memset(hmac_file, 0, sizeof(*hmac_file));
335
  ret = ini_parse_file(stream, handler, hmac_file);
336
  fclose(stream);
337
  if (ret < 0)
338
    return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
339
340
  if (hmac_file->version != HMAC_FORMAT_VERSION)
341
    return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
342
343
  return 0;
344
}
345
346
/*
347
 * check_lib_hmac:
348
 * @entry: hmac file entry
349
 * @path: path to the library which hmac should be compared
350
 *
351
 * Verify that HMAC from hmac file entry matches HMAC of given library.
352
 *
353
 * Returns: 0 on successful HMAC verification, a negative error code otherwise
354
 */
355
static int check_lib_hmac(struct hmac_entry *entry, const char *path)
356
{
357
  int ret;
358
  unsigned prev;
359
  uint8_t hmac[HMAC_SIZE];
360
  gnutls_datum_t data;
361
362
  _gnutls_debug_log("Loading: %s\n", path);
363
  ret = gnutls_load_file(path, &data);
364
  if (ret < 0) {
365
    _gnutls_debug_log("Could not load %s: %s\n", path,
366
          gnutls_strerror(ret));
367
    return gnutls_assert_val(ret);
368
  }
369
370
  prev = _gnutls_get_lib_state();
371
  _gnutls_switch_lib_state(LIB_STATE_OPERATIONAL);
372
  ret = gnutls_hmac_fast(HMAC_ALGO, FIPS_KEY, sizeof(FIPS_KEY) - 1,
373
             data.data, data.size, hmac);
374
  _gnutls_switch_lib_state(prev);
375
376
  gnutls_free(data.data);
377
  if (ret < 0) {
378
    _gnutls_debug_log("Could not calculate HMAC for %s: %s\n", path,
379
          gnutls_strerror(ret));
380
    return gnutls_assert_val(ret);
381
  }
382
383
  if (gnutls_memcmp(entry->hmac, hmac, HMAC_SIZE)) {
384
    _gnutls_debug_log("Calculated MAC for %s does not match\n",
385
          path);
386
    gnutls_memset(hmac, 0, HMAC_SIZE);
387
    return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
388
  }
389
  _gnutls_debug_log("Successfully verified MAC for %s\n", path);
390
391
  gnutls_memset(hmac, 0, HMAC_SIZE);
392
  return 0;
393
}
394
395
#ifdef HAVE_DL_ITERATE_PHDR
396
397
static int callback(struct dl_phdr_info *info, size_t size, void *data)
398
{
399
  const char *path = info->dlpi_name;
400
  const char *soname = last_component(path);
401
  struct lib_paths *paths = (struct lib_paths *)data;
402
403
  if (streq(soname, GNUTLS_LIBRARY_SONAME))
404
    _gnutls_str_cpy(paths->gnutls, GNUTLS_PATH_MAX, path);
405
#ifdef NETTLE_LIBRARY_SONAME
406
  else if (streq(soname, NETTLE_LIBRARY_SONAME))
407
    _gnutls_str_cpy(paths->nettle, GNUTLS_PATH_MAX, path);
408
#endif
409
#ifdef HOGWEED_LIBRARY_SONAME
410
  else if (streq(soname, HOGWEED_LIBRARY_SONAME))
411
    _gnutls_str_cpy(paths->hogweed, GNUTLS_PATH_MAX, path);
412
#endif
413
#ifdef GMP_LIBRARY_SONAME
414
  else if (streq(soname, GMP_LIBRARY_SONAME))
415
    _gnutls_str_cpy(paths->gmp, GNUTLS_PATH_MAX, path);
416
#endif
417
  return 0;
418
}
419
420
static int load_lib_paths(struct lib_paths *paths)
421
{
422
  memset(paths, 0, sizeof(*paths));
423
  dl_iterate_phdr(callback, paths);
424
425
  if (paths->gnutls[0] == '\0') {
426
    _gnutls_debug_log("Gnutls library path was not found\n");
427
    return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
428
  }
429
#ifdef NETTLE_LIBRARY_SONAME
430
  if (paths->nettle[0] == '\0') {
431
    _gnutls_debug_log("Nettle library path was not found\n");
432
    return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
433
  }
434
#endif
435
#ifdef HOGWEED_LIBRARY_SONAME
436
  if (paths->hogweed[0] == '\0') {
437
    _gnutls_debug_log("Hogweed library path was not found\n");
438
    return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
439
  }
440
#endif
441
#ifdef GMP_LIBRARY_SONAME
442
  if (paths->gmp[0] == '\0') {
443
    _gnutls_debug_log("Gmp library path was not found\n");
444
    return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
445
  }
446
#endif
447
448
  return GNUTLS_E_SUCCESS;
449
}
450
451
#else
452
453
static int load_lib_paths(struct lib_paths *paths)
454
{
455
  (void)paths;
456
  _gnutls_debug_log("Function dl_iterate_phdr is missing\n");
457
  return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
458
}
459
460
#endif /* HAVE_DL_ITERATE_PHDR */
461
462
static int check_binary_integrity(void)
463
{
464
  int ret;
465
  struct lib_paths paths;
466
  struct hmac_file hmac;
467
  char hmac_path[GNUTLS_PATH_MAX];
468
469
  ret = load_lib_paths(&paths);
470
  if (ret < 0) {
471
    _gnutls_debug_log("Could not load library paths: %s\n",
472
          gnutls_strerror(ret));
473
    return ret;
474
  }
475
476
  ret = get_hmac_path(hmac_path, sizeof(hmac_path), paths.gnutls);
477
  if (ret < 0) {
478
    _gnutls_debug_log("Could not get hmac file path: %s\n",
479
          gnutls_strerror(ret));
480
    return ret;
481
  }
482
483
  ret = load_hmac_file(&hmac, hmac_path);
484
  if (ret < 0) {
485
    _gnutls_debug_log("Could not load hmac file: %s\n",
486
          gnutls_strerror(ret));
487
    return ret;
488
  }
489
490
  ret = check_lib_hmac(&hmac.gnutls, paths.gnutls);
491
  if (ret < 0)
492
    return ret;
493
#ifdef NETTLE_LIBRARY_SONAME
494
  ret = check_lib_hmac(&hmac.nettle, paths.nettle);
495
  if (ret < 0)
496
    return ret;
497
#endif
498
#ifdef HOGWEED_LIBRARY_SONAME
499
  ret = check_lib_hmac(&hmac.hogweed, paths.hogweed);
500
  if (ret < 0)
501
    return ret;
502
#endif
503
#ifdef GMP_LIBRARY_SONAME
504
  ret = check_lib_hmac(&hmac.gmp, paths.gmp);
505
  if (ret < 0)
506
    return ret;
507
#endif
508
509
  return 0;
510
}
511
512
int _gnutls_fips_perform_self_checks1(void)
513
{
514
  int ret;
515
516
  /* Tests the FIPS algorithms used by nettle internally.
517
   * In our case we test AES-CBC since nettle's AES is used by
518
   * the DRBG-AES.
519
   */
520
521
  /* ciphers - one test per cipher */
522
  ret = gnutls_cipher_self_test(GNUTLS_SELF_TEST_FLAG_NO_COMPAT,
523
              GNUTLS_CIPHER_AES_128_CBC);
524
  if (ret < 0) {
525
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
526
  }
527
528
  return 0;
529
}
530
531
int _gnutls_fips_perform_self_checks2(void)
532
{
533
  int ret;
534
535
  /* Tests the FIPS algorithms */
536
537
  /* ciphers - one test per cipher */
538
  ret = gnutls_cipher_self_test(GNUTLS_SELF_TEST_FLAG_NO_COMPAT,
539
              GNUTLS_CIPHER_AES_256_GCM);
540
  if (ret < 0) {
541
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
542
  }
543
544
  /* Digest tests */
545
  ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHA3_224);
546
  if (ret < 0) {
547
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
548
  }
549
550
  ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHA3_256);
551
  if (ret < 0) {
552
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
553
  }
554
555
  ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHA3_384);
556
  if (ret < 0) {
557
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
558
  }
559
560
  ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHA3_512);
561
  if (ret < 0) {
562
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
563
  }
564
565
  ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHAKE_128);
566
  if (ret < 0) {
567
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
568
  }
569
570
  ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHAKE_256);
571
  if (ret < 0) {
572
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
573
  }
574
575
  /* MAC (includes message digest test) */
576
  ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA1);
577
  if (ret < 0) {
578
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
579
  }
580
581
  ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA224);
582
  if (ret < 0) {
583
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
584
  }
585
586
  ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA256);
587
  if (ret < 0) {
588
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
589
  }
590
591
  ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA384);
592
  if (ret < 0) {
593
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
594
  }
595
596
  ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA512);
597
  if (ret < 0) {
598
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
599
  }
600
601
  ret = gnutls_mac_self_test(0, GNUTLS_MAC_AES_CMAC_256);
602
  if (ret < 0) {
603
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
604
  }
605
606
  /* PK */
607
  ret = gnutls_pk_self_test(0, GNUTLS_PK_RSA_PSS);
608
  if (ret < 0) {
609
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
610
  }
611
612
  ret = gnutls_pk_self_test(0, GNUTLS_PK_EC);
613
  if (ret < 0) {
614
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
615
  }
616
617
  ret = gnutls_pk_self_test(0, GNUTLS_PK_EDDSA_ED25519);
618
  if (ret < 0) {
619
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
620
  }
621
622
  ret = gnutls_pk_self_test(0, GNUTLS_PK_EDDSA_ED448);
623
  if (ret < 0) {
624
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
625
  }
626
627
  ret = gnutls_pk_self_test(0, GNUTLS_PK_DH);
628
  if (ret < 0) {
629
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
630
  }
631
632
  /* HKDF */
633
  ret = gnutls_hkdf_self_test(0, GNUTLS_MAC_SHA256);
634
  if (ret < 0) {
635
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
636
  }
637
638
  /* PBKDF2 */
639
  ret = gnutls_pbkdf2_self_test(0, GNUTLS_MAC_SHA256);
640
  if (ret < 0) {
641
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
642
  }
643
644
  /* TLS-PRF */
645
  ret = gnutls_tlsprf_self_test(0, GNUTLS_MAC_SHA256);
646
  if (ret < 0) {
647
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
648
  }
649
650
  if (_gnutls_rnd_ops.self_test == NULL) {
651
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
652
  }
653
654
  /* this does not require rng initialization */
655
  ret = _gnutls_rnd_ops.self_test();
656
  if (ret < 0) {
657
    return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
658
  }
659
660
  if (_skip_integrity_checks == 0) {
661
    ret = check_binary_integrity();
662
    if (ret < 0) {
663
      return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
664
    }
665
  }
666
667
  return 0;
668
}
669
#endif
670
671
/**
672
 * gnutls_fips140_mode_enabled:
673
 *
674
 * Checks whether this library is in FIPS140 mode. The returned
675
 * value corresponds to the library mode as set with
676
 * gnutls_fips140_set_mode().
677
 *
678
 * If gnutls_fips140_set_mode() was called with %GNUTLS_FIPS140_SET_MODE_THREAD
679
 * then this function will return the current thread's FIPS140 mode, otherwise
680
 * the global value is returned.
681
 *
682
 * Returns: return non-zero if true or zero if false.
683
 *
684
 * Since: 3.3.0
685
 **/
686
unsigned gnutls_fips140_mode_enabled(void)
687
0
{
688
#ifdef ENABLE_FIPS140
689
  unsigned ret = _gnutls_fips_mode_enabled();
690
691
  if (ret > GNUTLS_FIPS140_DISABLED) {
692
    /* If the previous run of selftests has failed, return as if
693
     * the FIPS mode is disabled. We could use HAVE_LIB_ERROR, if
694
     * we can assume that all the selftests run atomically from
695
     * the ELF constructor.
696
     */
697
    if (_gnutls_get_lib_state() == LIB_STATE_ERROR)
698
      return 0;
699
700
    return ret;
701
  }
702
#endif
703
0
  return 0;
704
0
}
705
706
/**
707
 * gnutls_fips140_set_mode:
708
 * @mode: the FIPS140-2 mode to switch to
709
 * @flags: should be zero or %GNUTLS_FIPS140_SET_MODE_THREAD
710
 *
711
 * That function is not thread-safe when changing the mode with no flags
712
 * (globally), and should be called prior to creating any threads. Its
713
 * behavior with no flags after threads are created is undefined.
714
 *
715
 * When the flag %GNUTLS_FIPS140_SET_MODE_THREAD is specified
716
 * then this call will change the FIPS140-2 mode for this particular
717
 * thread and not for the whole process. That way an application
718
 * can utilize this function to set and reset mode for specific
719
 * operations.
720
 *
721
 * This function never fails but will be a no-op if used when
722
 * the library is not in FIPS140-2 mode. When asked to switch to unknown
723
 * values for @mode or to %GNUTLS_FIPS140_SELFTESTS mode, the library
724
 * switches to %GNUTLS_FIPS140_STRICT mode.
725
 *
726
 * Since: 3.6.2
727
 **/
728
void gnutls_fips140_set_mode(gnutls_fips_mode_t mode, unsigned flags)
729
0
{
730
#ifdef ENABLE_FIPS140
731
  gnutls_fips_mode_t prev = _gnutls_fips_mode_enabled();
732
  if (prev == GNUTLS_FIPS140_DISABLED ||
733
      prev == GNUTLS_FIPS140_SELFTESTS) {
734
    /* we need to run self-tests first to be in FIPS140-2 mode */
735
    _gnutls_audit_log(
736
      NULL,
737
      "The library should be initialized in FIPS140-2 mode to do that operation\n");
738
    return;
739
  }
740
741
  switch (mode) {
742
  case GNUTLS_FIPS140_STRICT:
743
  case GNUTLS_FIPS140_LAX:
744
  case GNUTLS_FIPS140_LOG:
745
  case GNUTLS_FIPS140_DISABLED:
746
    break;
747
  case GNUTLS_FIPS140_SELFTESTS:
748
    _gnutls_audit_log(
749
      NULL,
750
      "Cannot switch library to FIPS140-2 self-tests mode; defaulting to strict\n");
751
    mode = GNUTLS_FIPS140_STRICT;
752
    break;
753
  default:
754
    _gnutls_audit_log(
755
      NULL,
756
      "Cannot switch library to mode %u; defaulting to strict\n",
757
      (unsigned)mode);
758
    mode = GNUTLS_FIPS140_STRICT;
759
    break;
760
  }
761
762
  if (flags & GNUTLS_FIPS140_SET_MODE_THREAD)
763
    _tfips_mode = mode;
764
  else {
765
    _global_fips_mode = mode;
766
    _tfips_mode = -1;
767
  }
768
#endif
769
0
}
770
771
void _gnutls_lib_simulate_error(void)
772
0
{
773
0
  _gnutls_switch_lib_state(LIB_STATE_ERROR);
774
0
}
775
776
void _gnutls_lib_force_operational(void)
777
0
{
778
0
  _gnutls_switch_lib_state(LIB_STATE_OPERATIONAL);
779
0
}
780
781
/**
782
 * gnutls_fips140_context_init:
783
 * @context: location to store @gnutls_fips140_context_t
784
 *
785
 * Create and initialize the FIPS context object.
786
 *
787
 * Returns: 0 upon success, a negative error code otherwise
788
 *
789
 * Since: 3.7.3
790
 */
791
int gnutls_fips140_context_init(gnutls_fips140_context_t *context)
792
0
{
793
0
  *context = gnutls_malloc(sizeof(struct gnutls_fips140_context_st));
794
0
  if (!*context) {
795
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
796
0
  }
797
0
  (*context)->state = GNUTLS_FIPS140_OP_INITIAL;
798
0
  return 0;
799
0
}
800
801
/**
802
 * gnutls_fips140_context_deinit:
803
 * @context: a #gnutls_fips140_context_t
804
 *
805
 * Uninitialize and release the FIPS context @context.
806
 *
807
 * Since: 3.7.3
808
 */
809
void gnutls_fips140_context_deinit(gnutls_fips140_context_t context)
810
0
{
811
0
  gnutls_free(context);
812
0
}
813
814
/**
815
 * gnutls_fips140_get_operation_state:
816
 * @context: a #gnutls_fips140_context_t
817
 *
818
 * Get the previous operation state of @context in terms of FIPS.
819
 *
820
 * Returns: a #gnutls_fips140_operation_state_t
821
 *
822
 * Since: 3.7.3
823
 */
824
gnutls_fips140_operation_state_t
825
gnutls_fips140_get_operation_state(gnutls_fips140_context_t context)
826
0
{
827
0
  return context->state;
828
0
}
829
830
/**
831
 * gnutls_fips140_push_context:
832
 * @context: a #gnutls_fips140_context_t
833
 *
834
 * Associate the FIPS @context to the current thread, diverting the
835
 * currently active context. If a cryptographic operation is ongoing
836
 * in the current thread, e.g., gnutls_aead_cipher_init() is called
837
 * but gnutls_aead_cipher_deinit() is not yet called, it returns an
838
 * error %GNUTLS_E_INVALID_REQUEST.
839
 *
840
 * The operation state of @context will be reset to
841
 * %GNUTLS_FIPS140_OP_INITIAL.
842
 *
843
 * This function is no-op if FIPS140 is not compiled in nor enabled
844
 * at run-time.
845
 *
846
 * Returns: 0 upon success, a negative error code otherwise
847
 *
848
 * Since: 3.7.3
849
 */
850
int gnutls_fips140_push_context(gnutls_fips140_context_t context)
851
0
{
852
#ifdef ENABLE_FIPS140
853
  if (_gnutls_fips_mode_enabled() != GNUTLS_FIPS140_DISABLED) {
854
    context->next = _tfips_context;
855
    _tfips_context = context;
856
857
    context->state = GNUTLS_FIPS140_OP_INITIAL;
858
  }
859
  return 0;
860
#else
861
0
  return GNUTLS_E_INVALID_REQUEST;
862
0
#endif
863
0
}
864
865
/**
866
 * gnutls_fips140_pop_context:
867
 *
868
 * Dissociate the FIPS context currently
869
 * active on the current thread, reverting to the previously active
870
 * context. If a cryptographic operation is ongoing in the current
871
 * thread, e.g., gnutls_aead_cipher_init() is called but
872
 * gnutls_aead_cipher_deinit() is not yet called, it returns an error
873
 * %GNUTLS_E_INVALID_REQUEST.
874
 *
875
 * This function is no-op if FIPS140 is not compiled in nor enabled
876
 * at run-time.
877
 *
878
 * Returns: 0 upon success, a negative error code otherwise
879
 *
880
 * Since: 3.7.3
881
 */
882
int gnutls_fips140_pop_context(void)
883
0
{
884
#ifdef ENABLE_FIPS140
885
  if (_gnutls_fips_mode_enabled() != GNUTLS_FIPS140_DISABLED) {
886
    if (!_tfips_context) {
887
      return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
888
    }
889
890
    _tfips_context = _tfips_context->next;
891
  }
892
  return 0;
893
#else
894
0
  return GNUTLS_E_INVALID_REQUEST;
895
0
#endif
896
0
}
897
898
#ifdef ENABLE_FIPS140
899
900
static inline const char *
901
operation_state_to_string(gnutls_fips140_operation_state_t state)
902
{
903
  switch (state) {
904
  case GNUTLS_FIPS140_OP_INITIAL:
905
    return "initial";
906
  case GNUTLS_FIPS140_OP_APPROVED:
907
    return "approved";
908
  case GNUTLS_FIPS140_OP_NOT_APPROVED:
909
    return "not-approved";
910
  case GNUTLS_FIPS140_OP_ERROR:
911
    return "error";
912
  default:
913
    /*NOTREACHED*/ assert(0);
914
    return NULL;
915
  }
916
}
917
918
void _gnutls_switch_fips_state(gnutls_fips140_operation_state_t state)
919
{
920
  gnutls_fips_mode_t mode = _gnutls_fips_mode_enabled();
921
  if (mode == GNUTLS_FIPS140_DISABLED) {
922
    return;
923
  }
924
925
  if (!_tfips_context) {
926
    _gnutls_debug_log("FIPS140-2 context is not set\n");
927
    return;
928
  }
929
930
  if (_tfips_context->state == state) {
931
    return;
932
  }
933
934
  switch (_tfips_context->state) {
935
  case GNUTLS_FIPS140_OP_INITIAL:
936
    /* initial can be transitioned to any state */
937
    if (mode != GNUTLS_FIPS140_LAX) {
938
      _gnutls_audit_log(
939
        NULL,
940
        "FIPS140-2 operation mode switched from initial to %s\n",
941
        operation_state_to_string(state));
942
    }
943
    _tfips_context->state = state;
944
    break;
945
  case GNUTLS_FIPS140_OP_APPROVED:
946
    /* approved can only be transitioned to not-approved */
947
    if (likely(state == GNUTLS_FIPS140_OP_NOT_APPROVED)) {
948
      if (mode != GNUTLS_FIPS140_LAX) {
949
        _gnutls_audit_log(
950
          NULL,
951
          "FIPS140-2 operation mode switched from approved to %s\n",
952
          operation_state_to_string(state));
953
      }
954
      _tfips_context->state = state;
955
      return;
956
    }
957
    FALLTHROUGH;
958
  default:
959
    /* other transitions are prohibited */
960
    if (mode != GNUTLS_FIPS140_LAX) {
961
      _gnutls_audit_log(
962
        NULL,
963
        "FIPS140-2 operation mode cannot be switched from %s to %s\n",
964
        operation_state_to_string(
965
          _tfips_context->state),
966
        operation_state_to_string(state));
967
    }
968
    break;
969
  }
970
}
971
972
#else
973
974
void _gnutls_switch_fips_state(gnutls_fips140_operation_state_t state)
975
0
{
976
0
  (void)state;
977
0
}
978
979
#endif
980
981
/**
982
 * gnutls_fips140_run_self_tests:
983
 *
984
 * Manually perform the second round of the FIPS140 self-tests,
985
 * including:
986
 *
987
 * - Known answer tests (KAT) for the selected set of symmetric
988
 *   cipher, MAC, public key, KDF, and DRBG
989
 * - Library integrity checks
990
 *
991
 * Upon failure with FIPS140 mode enabled, it makes the library
992
 * unusable.  This function is not thread-safe.
993
 *
994
 * Returns: 0 upon success, a negative error code otherwise
995
 *
996
 * Since: 3.7.7
997
 */
998
int gnutls_fips140_run_self_tests(void)
999
0
{
1000
#ifdef ENABLE_FIPS140
1001
  int ret;
1002
  unsigned prev_lib_state;
1003
  gnutls_fips140_context_t fips_context = NULL;
1004
1005
  /* Save the FIPS context, because self tests change it */
1006
  if (gnutls_fips140_mode_enabled() != GNUTLS_FIPS140_DISABLED) {
1007
    if (gnutls_fips140_context_init(&fips_context) < 0 ||
1008
        gnutls_fips140_push_context(fips_context) < 0) {
1009
      gnutls_fips140_context_deinit(fips_context);
1010
      fips_context = NULL;
1011
    }
1012
  }
1013
1014
  /* Temporarily switch to LIB_STATE_SELFTEST as some of the
1015
   * algorithms are implemented using special constructs in
1016
   * self-tests (such as deterministic variants) */
1017
  prev_lib_state = _gnutls_get_lib_state();
1018
  _gnutls_switch_lib_state(LIB_STATE_SELFTEST);
1019
1020
  ret = _gnutls_fips_perform_self_checks2();
1021
  if (gnutls_fips140_mode_enabled() != GNUTLS_FIPS140_DISABLED &&
1022
      ret < 0) {
1023
    _gnutls_switch_lib_state(LIB_STATE_ERROR);
1024
    _gnutls_audit_log(NULL,
1025
          "FIPS140-2 self testing part 2 failed\n");
1026
  } else {
1027
    /* Restore the previous library state */
1028
    _gnutls_switch_lib_state(prev_lib_state);
1029
  }
1030
1031
  /* Restore the previous FIPS context */
1032
  if (gnutls_fips140_mode_enabled() != GNUTLS_FIPS140_DISABLED &&
1033
      fips_context) {
1034
    if (gnutls_fips140_pop_context() < 0) {
1035
      _gnutls_switch_lib_state(LIB_STATE_ERROR);
1036
      _gnutls_audit_log(
1037
        NULL, "FIPS140-2 context restoration failed\n");
1038
    }
1039
    gnutls_fips140_context_deinit(fips_context);
1040
  }
1041
  return ret;
1042
#else
1043
0
  return 0;
1044
0
#endif
1045
0
}