File gnutls_ECDSA_signing.patch of Package gnutls.26407
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) {