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;
 }
openSUSE Build Service is sponsored by