Coverage Report

Created: 2024-06-20 06:28

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