File gnutls_ECDSA_signing.patch of Package gnutls.27505

diff --git a/lib/crypto-api.c b/lib/crypto-api.c
index f55baf6..6e25402 100644
--- a/lib/crypto-api.c
+++ b/lib/crypto-api.c
@@ -895,6 +895,7 @@ gnutls_hash_hd_t gnutls_hash_copy(gnutls_hash_hd_t handle)
 int gnutls_key_generate(gnutls_datum_t * key, unsigned int key_size)
 {
 	int ret;
+	bool not_approved = false;
 
 	FAIL_IF_LIB_ERROR;
 
@@ -905,6 +906,10 @@ int gnutls_key_generate(gnutls_datum_t * key, unsigned int key_size)
 	if (_gnutls_fips_mode_enabled() != 0 &&
 	    key_size > FIPS140_RND_KEY_SIZE)
 		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+	if (key_size < 14) {
+		not_approved = true;
+	}
+
 #endif
 
 	key->size = key_size;
@@ -921,6 +926,15 @@ int gnutls_key_generate(gnutls_datum_t * key, unsigned int key_size)
 		return ret;
 	}
 
+#ifdef ENABLE_FIPS140
+	if (not_approved) {
+		_gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+	} else {
+		_gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+	}
+
+#endif
+
 	return 0;
 }
 
diff --git a/lib/fips.h b/lib/fips.h
index 49ad1d9..a08a10c 100644
--- a/lib/fips.h
+++ b/lib/fips.h
@@ -149,6 +149,30 @@ is_cipher_algo_allowed_in_fips(gnutls_cipher_algorithm_t algo)
 	}
 }
 
+inline static bool
+is_digest_algo_approved_for_sign_in_fips(gnutls_digest_algorithm_t algo)
+{
+	switch (algo) {
+	case GNUTLS_DIG_SHA224:
+	case GNUTLS_DIG_SHA256:
+	case GNUTLS_DIG_SHA384:
+	case GNUTLS_DIG_SHA512:
+	case GNUTLS_DIG_SHA3_224:
+	case GNUTLS_DIG_SHA3_256:
+	case GNUTLS_DIG_SHA3_384:
+	case GNUTLS_DIG_SHA3_512:
+		return true;
+	default:
+		return false;
+	}
+}
+
+inline static bool
+is_digest_algo_allowed_for_sign_in_fips(gnutls_digest_algorithm_t algo)
+{
+	return is_digest_algo_approved_for_sign_in_fips(algo);
+}
+
 #ifdef ENABLE_FIPS140
 /* This will test the condition when in FIPS140-2 mode
  * and return an error if necessary or ignore */
@@ -209,9 +233,33 @@ is_cipher_algo_allowed(gnutls_cipher_algorithm_t algo)
 
 	return true;
 }
+
+inline static bool
+is_digest_algo_allowed_for_sign(gnutls_digest_algorithm_t algo)
+{
+	gnutls_fips_mode_t mode = _gnutls_fips_mode_enabled();
+	if (_gnutls_get_lib_state() != LIB_STATE_SELFTEST &&
+	    !is_digest_algo_allowed_for_sign_in_fips(algo)) {
+		switch (mode) {
+		case GNUTLS_FIPS140_LOG:
+			_gnutls_audit_log(NULL, "fips140-2: allowing access to %s\n",
+					  gnutls_cipher_get_name(algo));
+			FALLTHROUGH;
+		case GNUTLS_FIPS140_DISABLED:
+		case GNUTLS_FIPS140_LAX:
+			return true;
+		default:
+			return false;
+		}
+	}
+
+	return true;
+}
+
 #else
 # define is_mac_algo_allowed(x) true
 # define is_cipher_algo_allowed(x) true
+# define is_digest_algo_allowed_for_sign(x) true
 # define FIPS_RULE(condition, ret_error, ...)
 #endif
 
diff --git a/lib/privkey.c b/lib/privkey.c
index 0b77443..81de778 100644
--- a/lib/privkey.c
+++ b/lib/privkey.c
@@ -1284,10 +1284,24 @@ privkey_sign_and_hash_data(gnutls_privkey_t signer,
 	int ret;
 	gnutls_datum_t digest;
 	const mac_entry_st *me;
+	bool not_approved = false;
 
 	if (unlikely(se == NULL))
 		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
 
+	if (se->pk == GNUTLS_PK_ECDSA && !is_digest_algo_allowed_for_sign(se->hash)) {
+		_gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+		return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
+	} else if (se->pk == GNUTLS_PK_ECDSA && !is_digest_algo_approved_for_sign_in_fips(se->hash)) {
+		not_approved = true;
+	}
+
+	if (not_approved) {
+		_gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+	} else {
+		_gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+	}
+
 	if (_gnutls_pk_is_not_prehashed(se->pk)) {
 		return privkey_sign_raw_data(signer, se, data, signature, params);
 	}
diff --git a/tests/fips-test.c b/tests/fips-test.c
index a6a283f..999f11a 100644
--- a/tests/fips-test.c
+++ b/tests/fips-test.c
@@ -38,6 +38,7 @@ static void tls_log_func(int level, const char *str)
 	fprintf(stderr, "<%d>| %s", level, str);
 }
 
+static uint8_t key13[13];
 static uint8_t key16[16];
 static uint8_t iv16[16];
 uint8_t key_data[64];
@@ -269,6 +270,7 @@ void doit(void)
 	gnutls_pubkey_t pubkey;
 	gnutls_x509_privkey_t xprivkey;
 	gnutls_privkey_t privkey;
+	gnutls_datum_t key_invalid = { key13, sizeof(key13) };
 	gnutls_datum_t key = { key16, sizeof(key16) };
 	gnutls_datum_t iv = { iv16, sizeof(iv16) };
 	gnutls_datum_t signature;
@@ -309,6 +311,14 @@ void doit(void)
 	/* Try crypto.h functionality */
 	test_ciphers();
 
+	/* Try creating key with less than 112 bits: not approved */
+	FIPS_PUSH_CONTEXT();
+	ret = gnutls_key_generate(&key_invalid, 13);
+	if (ret < 0) {
+		fail("gnutls_generate_key failed\n");
+	}
+	FIPS_POP_CONTEXT(NOT_APPROVED);
+
 	FIPS_PUSH_CONTEXT();
 	ret = gnutls_cipher_init(&ch, GNUTLS_CIPHER_AES_128_CBC, &key, &iv);
 	if (ret < 0) {
openSUSE Build Service is sponsored by