File gnutls-FIPS-force-self-test.patch of Package gnutls.28150
Index: gnutls-3.7.3/doc/Makefile.am
===================================================================
--- gnutls-3.7.3.orig/doc/Makefile.am 2022-07-08 13:35:05.577272530 +0200
+++ gnutls-3.7.3/doc/Makefile.am 2022-07-08 14:46:23.460305049 +0200
@@ -1070,6 +1070,8 @@
FUNCS += functions/gnutls_fips140_pop_context.short
FUNCS += functions/gnutls_fips140_push_context
FUNCS += functions/gnutls_fips140_push_context.short
+FUNCS += functions/gnutls_fips140_run_self_tests
+FUNCS += functions/gnutls_fips140_run_self_tests.short
FUNCS += functions/gnutls_fips140_set_mode
FUNCS += functions/gnutls_fips140_set_mode.short
FUNCS += functions/gnutls_get_library_config
Index: gnutls-3.7.3/doc/manpages/Makefile.am
===================================================================
--- gnutls-3.7.3.orig/doc/manpages/Makefile.am 2022-07-08 13:35:05.577272530 +0200
+++ gnutls-3.7.3/doc/manpages/Makefile.am 2022-07-08 14:46:23.460305049 +0200
@@ -375,6 +375,7 @@
APIMANS += gnutls_fips140_mode_enabled.3
APIMANS += gnutls_fips140_pop_context.3
APIMANS += gnutls_fips140_push_context.3
+APIMANS += gnutls_fips140_run_self_tests.3
APIMANS += gnutls_fips140_set_mode.3
APIMANS += gnutls_get_library_config.3
APIMANS += gnutls_get_system_config_file.3
Index: gnutls-3.7.3/lib/fips.c
===================================================================
--- gnutls-3.7.3.orig/lib/fips.c 2022-07-08 14:46:23.404304679 +0200
+++ gnutls-3.7.3/lib/fips.c 2022-07-08 14:46:56.952527793 +0200
@@ -278,8 +278,6 @@
{
int ret;
- _gnutls_switch_lib_state(LIB_STATE_SELFTEST);
-
/* Tests the FIPS algorithms used by nettle internally.
* In our case we test AES-CBC since nettle's AES is used by
* the DRBG-AES.
@@ -288,118 +286,94 @@
/* ciphers - one test per cipher */
ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_128_CBC);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
return 0;
-
-error:
- _gnutls_switch_lib_state(LIB_STATE_ERROR);
- _gnutls_audit_log(NULL, "FIPS140-2 self testing part1 failed\n");
-
- return GNUTLS_E_SELF_TEST_ERROR;
}
int _gnutls_fips_perform_self_checks2(void)
{
int ret;
- _gnutls_switch_lib_state(LIB_STATE_SELFTEST);
-
/* Tests the FIPS algorithms */
/* ciphers - one test per cipher */
ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_3DES_CBC);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_CBC);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_GCM);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_XTS);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_CFB8);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
/* Digest tests */
ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHA3_224);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHA3_256);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHA3_384);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHA3_512);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
/* MAC (includes message digest test) */
ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA1);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA224);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA256);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA384);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA512);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = gnutls_mac_self_test(0, GNUTLS_MAC_AES_CMAC_256);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
/* KDF */
@@ -414,107 +388,88 @@
ret = _gnutls_prf_raw(GNUTLS_MAC_SHA256, secret.size, secret.data,
label.size, (char*)label.data, seed.size, seed.data, expected.size, derived);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = memcmp(derived, expected.data, expected.size);
if (ret != 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
/* PK */
ret = gnutls_pk_self_test(0, GNUTLS_PK_RSA);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
- ret = gnutls_pk_self_test(0, GNUTLS_PK_DSA);
+ // Removed from self-test since this would cause lib to be put
+ // into FIPS error state.
+ /*ret = gnutls_pk_self_test(0, GNUTLS_PK_DSA);
if (ret < 0) {
- gnutls_assert();
- goto error;
- }
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }*/
ret = gnutls_pk_self_test(0, GNUTLS_PK_EC);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = gnutls_pk_self_test(0, GNUTLS_PK_DH);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
/* HKDF */
ret = gnutls_hkdf_self_test(0, GNUTLS_MAC_SHA256);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
/* PBKDF2 */
ret = gnutls_pbkdf2_self_test(0, GNUTLS_MAC_SHA256);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
/* TLS-PRF */
ret = gnutls_tlsprf_self_test(0, GNUTLS_MAC_SHA256);
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
if (_gnutls_rnd_ops.self_test == NULL) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
/* this does not require rng initialization */
ret = _gnutls_rnd_ops.self_test();
if (ret < 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
if (_skip_integrity_checks == 0) {
ret = check_binary_integrity(GNUTLS_LIBRARY_NAME, "gnutls_global_init");
if (ret == 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = check_binary_integrity(NETTLE_LIBRARY_NAME, "nettle_aes_set_encrypt_key");
if (ret == 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = check_binary_integrity(HOGWEED_LIBRARY_NAME, "nettle_mpz_sizeinbase_256_u");
if (ret == 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
ret = check_binary_integrity(GMP_LIBRARY_NAME, "__gmpz_init");
if (ret == 0) {
- gnutls_assert();
- goto error;
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
}
}
return 0;
-
-error:
- _gnutls_switch_lib_state(LIB_STATE_ERROR);
- _gnutls_audit_log(NULL, "FIPS140-2 self testing part 2 failed\n");
-
- return GNUTLS_E_SELF_TEST_ERROR;
}
#endif
@@ -793,3 +748,67 @@
(void)state;
#endif
}
+
+/**
+ * gnutls_fips140_run_self_tests:
+ *
+ * Manually perform the second round of the FIPS140 self-tests,
+ * including:
+ *
+ * - Known answer tests (KAT) for the selected set of symmetric
+ * cipher, MAC, public key, KDF, and DRBG
+ * - Library integrity checks
+ *
+ * Upon failure with FIPS140 mode enabled, it makes the library
+ * unusable. This function is not thread-safe.
+ *
+ * Returns: 0 upon success, a negative error code otherwise
+ *
+ * Since: 3.7.3
+ */
+int
+gnutls_fips140_run_self_tests(void)
+{
+#ifdef ENABLE_FIPS140
+ int ret;
+ unsigned prev_lib_state;
+ gnutls_fips140_context_t fips_context = NULL;
+
+ /* Save the FIPS context, because self tests change it */
+ if (gnutls_fips140_mode_enabled() != GNUTLS_FIPS140_DISABLED) {
+ if (gnutls_fips140_context_init(&fips_context) < 0 ||
+ gnutls_fips140_push_context(fips_context) < 0) {
+ gnutls_fips140_context_deinit(fips_context);
+ fips_context = NULL;
+ }
+ }
+
+ /* Temporarily switch to LIB_STATE_SELFTEST as some of the
+ * algorithms are implemented using special constructs in
+ * self-tests (such as deterministic variants) */
+ prev_lib_state = _gnutls_get_lib_state();
+ _gnutls_switch_lib_state(LIB_STATE_SELFTEST);
+
+ ret = _gnutls_fips_perform_self_checks2();
+ if (gnutls_fips140_mode_enabled() != GNUTLS_FIPS140_DISABLED &&
+ ret < 0) {
+ _gnutls_switch_lib_state(LIB_STATE_ERROR);
+ _gnutls_audit_log(NULL, "FIPS140-2 self testing part 2 failed\n");
+ } else {
+ /* Restore the previous library state */
+ _gnutls_switch_lib_state(prev_lib_state);
+ }
+
+ /* Restore the previous FIPS context */
+ if (gnutls_fips140_mode_enabled() != GNUTLS_FIPS140_DISABLED && fips_context) {
+ if (gnutls_fips140_pop_context() < 0) {
+ _gnutls_switch_lib_state(LIB_STATE_ERROR);
+ _gnutls_audit_log(NULL, "FIPS140-2 context restoration failed\n");
+ }
+ gnutls_fips140_context_deinit(fips_context);
+ }
+ return ret;
+#else
+ return 0;
+#endif
+}
Index: gnutls-3.7.3/lib/global.c
===================================================================
--- gnutls-3.7.3.orig/lib/global.c 2022-07-08 13:35:05.577272530 +0200
+++ gnutls-3.7.3/lib/global.c 2022-07-08 14:46:23.460305049 +0200
@@ -336,9 +336,12 @@
/* first round of self checks, these are done on the
* nettle algorithms which are used internally */
+ _gnutls_switch_lib_state(LIB_STATE_SELFTEST);
ret = _gnutls_fips_perform_self_checks1();
- if (res != 2) {
- if (ret < 0) {
+ if (ret < 0) {
+ _gnutls_switch_lib_state(LIB_STATE_ERROR);
+ _gnutls_audit_log(NULL, "FIPS140-2 self testing part1 failed\n");
+ if (res != 2) {
gnutls_assert();
goto out;
}
@@ -355,9 +358,12 @@
* (e.g., AESNI overridden AES). They are after _gnutls_register_accel_crypto()
* intentionally */
if (res != 0) {
+ _gnutls_switch_lib_state(LIB_STATE_SELFTEST);
ret = _gnutls_fips_perform_self_checks2();
- if (res != 2) {
- if (ret < 0) {
+ if (ret < 0) {
+ _gnutls_switch_lib_state(LIB_STATE_ERROR);
+ _gnutls_audit_log(NULL, "FIPS140-2 self testing part 2 failed\n");
+ if (res != 2) {
gnutls_assert();
goto out;
}
Index: gnutls-3.7.3/lib/includes/gnutls/gnutls.h.in
===================================================================
--- gnutls-3.7.3.orig/lib/includes/gnutls/gnutls.h.in 2022-07-08 13:35:05.577272530 +0200
+++ gnutls-3.7.3/lib/includes/gnutls/gnutls.h.in 2022-07-08 14:46:23.460305049 +0200
@@ -3394,6 +3394,8 @@
int gnutls_fips140_push_context(gnutls_fips140_context_t context);
int gnutls_fips140_pop_context(void);
+int gnutls_fips140_run_self_tests(void);
+
/* Gnutls error codes. The mapping to a TLS alert is also shown in
* comments.
*/
Index: gnutls-3.7.3/lib/libgnutls.map
===================================================================
--- gnutls-3.7.3.orig/lib/libgnutls.map 2022-07-08 13:35:05.577272530 +0200
+++ gnutls-3.7.3/lib/libgnutls.map 2022-07-08 14:46:23.460305049 +0200
@@ -1376,10 +1376,19 @@
gnutls_fips140_push_context;
gnutls_fips140_pop_context;
gnutls_get_library_config;
+ gnutls_fips140_run_self_tests;
local:
*;
} GNUTLS_3_7_2;
+GNUTLS_3_7_7
+{
+ global:
+ gnutls_fips140_run_self_tests;
+ local:
+ *;
+} GNUTLS_3_7_3;
+
GNUTLS_FIPS140_3_4 {
global:
gnutls_cipher_self_test;
Index: gnutls-3.7.3/tests/fips-test.c
===================================================================
--- gnutls-3.7.3.orig/tests/fips-test.c 2022-07-08 14:46:23.456305023 +0200
+++ gnutls-3.7.3/tests/fips-test.c 2022-07-08 14:46:23.460305049 +0200
@@ -459,7 +459,8 @@
/* Verify a signature created with SHA-1; approved */
FIPS_PUSH_CONTEXT();
- ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0, &data,
+ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA1,
+ GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1, &data,
&rsa2342_sha1_sig);
if (ret < 0) {
fail("gnutls_pubkey_verify_data2 failed\n");
@@ -493,6 +494,15 @@
}
FIPS_POP_CONTEXT(APPROVED);
+ /* run self-tests manually */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_rnd(GNUTLS_RND_RANDOM, key16, sizeof(key16));
+ ret = gnutls_fips140_run_self_tests();
+ if (ret < 0) {
+ fail("gnutls_fips140_run_self_tests failed\n");
+ }
+ FIPS_POP_CONTEXT(APPROVED);
+
/* Test when FIPS140 is set to error state */
_gnutls_lib_simulate_error();
@@ -535,6 +545,7 @@
}
gnutls_fips140_context_deinit(fips_context);
+
gnutls_global_deinit();
return;
}