Fix FIPS140-3 service indicator transitions

- fips: mark PBKDF2 with short key and output sizes non-approved
- fips: only mark HMAC as approved in PBKDF2
- fips: mark gnutls_key_generate with short key sizes non-approved
- fips: fix checking on hash algorithm used in ECDSA
- fips: preserve operation context around FIPS selftests API

Resolves: #2128229
Signed-off-by: Daiki Ueno <dueno@redhat.com>
This commit is contained in:
Daiki Ueno 2022-09-27 12:20:18 +09:00
parent e392f357d1
commit ef1a5b9b4f
4 changed files with 945 additions and 1 deletions

View File

@ -0,0 +1,427 @@
From 171b934a8c054e98b110892cae4130e1db64e656 Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Thu, 29 Sep 2022 21:28:19 +0900
Subject: [PATCH] gnutls-3.7.6-fips-ecdsa-hash-check.patch
---
lib/crypto-backend.h | 12 ++--
lib/nettle/pk.c | 33 +++++-----
lib/privkey.c | 42 ++++++++----
lib/pubkey.c | 5 +-
tests/fips-test.c | 150 ++++++++++++++++++++++++++++++++++++++++++-
5 files changed, 205 insertions(+), 37 deletions(-)
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h
index f0f68c3..4dd1ae2 100644
--- a/lib/crypto-backend.h
+++ b/lib/crypto-backend.h
@@ -247,11 +247,13 @@ typedef enum {
GNUTLS_PK_FLAG_RSA_PSS_FIXED_SALT_LENGTH = 4
} gnutls_pk_flag_t;
-#define FIX_SIGN_PARAMS(params, flags, dig) do { \
- if ((flags) & GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE) { \
- (params).flags |= GNUTLS_PK_FLAG_REPRODUCIBLE; \
- (params).dsa_dig = (dig); \
- } \
+#define FIX_SIGN_PARAMS(params, flags, dig) do { \
+ if ((flags) & GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE) { \
+ (params).flags |= GNUTLS_PK_FLAG_REPRODUCIBLE; \
+ } \
+ if ((params).pk == GNUTLS_PK_DSA || (params).pk == GNUTLS_PK_ECDSA) { \
+ (params).dsa_dig = (dig); \
+ } \
} while (0)
void gnutls_pk_params_release(gnutls_pk_params_st * p);
diff --git a/lib/nettle/pk.c b/lib/nettle/pk.c
index f38016b..c098e2a 100644
--- a/lib/nettle/pk.c
+++ b/lib/nettle/pk.c
@@ -1104,8 +1104,16 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
me = _gnutls_dsa_q_to_hash(pk_params,
&hash_len);
+ if (hash_len > vdata->size) {
+ gnutls_assert();
+ _gnutls_debug_log
+ ("Security level of algorithm requires hash %s(%d) or better\n",
+ _gnutls_mac_get_name(me), hash_len);
+ hash_len = vdata->size;
+ }
+
/* Only SHA-2 is allowed in FIPS 140-3 */
- switch (me->id) {
+ switch (DIG_TO_MAC(sign_params->dsa_dig)) {
case GNUTLS_MAC_SHA256:
case GNUTLS_MAC_SHA384:
case GNUTLS_MAC_SHA512:
@@ -1115,14 +1123,6 @@ _wrap_nettle_pk_sign(gnutls_pk_algorithm_t algo,
not_approved = true;
}
- if (hash_len > vdata->size) {
- gnutls_assert();
- _gnutls_debug_log
- ("Security level of algorithm requires hash %s(%d) or better\n",
- _gnutls_mac_get_name(me), hash_len);
- hash_len = vdata->size;
- }
-
mpz_init(k);
if (_gnutls_get_lib_state() == LIB_STATE_SELFTEST ||
(sign_params->flags & GNUTLS_PK_FLAG_REPRODUCIBLE)) {
@@ -1545,7 +1545,6 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
struct dsa_signature sig;
int curve_id = pk_params->curve;
const struct ecc_curve *curve;
- const mac_entry_st *me;
curve = get_supported_nist_curve(curve_id);
if (curve == NULL) {
@@ -1571,11 +1570,14 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
memcpy(sig.r, tmp[0], SIZEOF_MPZT);
memcpy(sig.s, tmp[1], SIZEOF_MPZT);
- me = _gnutls_dsa_q_to_hash(pk_params, &hash_len);
+ (void)_gnutls_dsa_q_to_hash(pk_params, &hash_len);
+
+ if (hash_len > vdata->size)
+ hash_len = vdata->size;
/* SHA-1 is allowed for SigVer in FIPS 140-3 in legacy
* mode */
- switch (me->id) {
+ switch (DIG_TO_MAC(sign_params->dsa_dig)) {
case GNUTLS_MAC_SHA1:
case GNUTLS_MAC_SHA256:
case GNUTLS_MAC_SHA384:
@@ -1586,9 +1588,6 @@ _wrap_nettle_pk_verify(gnutls_pk_algorithm_t algo,
not_approved = true;
}
- if (hash_len > vdata->size)
- hash_len = vdata->size;
-
ret =
ecdsa_verify(&pub, hash_len, vdata->data,
&sig);
@@ -2390,8 +2389,10 @@ static int pct_test(gnutls_pk_algorithm_t algo, const gnutls_pk_params_st* param
if (algo == GNUTLS_PK_DSA || algo == GNUTLS_PK_EC) {
unsigned hash_len;
+ const mac_entry_st *me;
- _gnutls_dsa_q_to_hash(params, &hash_len);
+ me = _gnutls_dsa_q_to_hash(params, &hash_len);
+ spki.dsa_dig = MAC_TO_DIG(me->id);
gen_data = gnutls_malloc(hash_len);
gnutls_rnd(GNUTLS_RND_NONCE, gen_data, hash_len);
diff --git a/lib/privkey.c b/lib/privkey.c
index 0b77443..2069fc0 100644
--- a/lib/privkey.c
+++ b/lib/privkey.c
@@ -1251,27 +1251,36 @@ gnutls_privkey_sign_hash2(gnutls_privkey_t signer,
se = _gnutls_sign_to_entry(GNUTLS_SIGN_RSA_RAW);
} else {
se = _gnutls_sign_to_entry(algo);
- if (unlikely(se == NULL))
- return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
-
+ if (unlikely(se == NULL)) {
+ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ goto cleanup;
+ }
}
ret = _gnutls_privkey_get_spki_params(signer, &params);
if (ret < 0) {
gnutls_assert();
- return ret;
+ goto cleanup;
}
ret = _gnutls_privkey_update_spki_params(signer, se->pk, se->hash,
flags, &params);
if (ret < 0) {
gnutls_assert();
- return ret;
+ goto cleanup;
}
FIX_SIGN_PARAMS(params, flags, se->hash);
- return privkey_sign_prehashed(signer, se, hash_data, signature, &params);
+ ret = privkey_sign_prehashed(signer, se, hash_data, signature, &params);
+
+ cleanup:
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ }
+ return ret;
}
int
@@ -1366,14 +1375,14 @@ gnutls_privkey_sign_hash(gnutls_privkey_t signer,
ret = _gnutls_privkey_get_spki_params(signer, &params);
if (ret < 0) {
gnutls_assert();
- return ret;
+ goto cleanup;
}
ret = _gnutls_privkey_update_spki_params(signer, signer->pk_algorithm,
hash_algo, flags, &params);
if (ret < 0) {
gnutls_assert();
- return ret;
+ goto cleanup;
}
/* legacy callers of this API could use a hash algorithm of 0 (unknown)
@@ -1391,13 +1400,22 @@ gnutls_privkey_sign_hash(gnutls_privkey_t signer,
se = _gnutls_pk_to_sign_entry(params.pk, hash_algo);
}
- if (unlikely(se == NULL))
- return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ if (unlikely(se == NULL)) {
+ ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ goto cleanup;
+ }
FIX_SIGN_PARAMS(params, flags, hash_algo);
- return privkey_sign_prehashed(signer, se,
- hash_data, signature, &params);
+ ret = privkey_sign_prehashed(signer, se,
+ hash_data, signature, &params);
+ cleanup:
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ }
+ return ret;
}
static int
diff --git a/lib/pubkey.c b/lib/pubkey.c
index eba1f5b..35126f3 100644
--- a/lib/pubkey.c
+++ b/lib/pubkey.c
@@ -1985,7 +1985,7 @@ gnutls_pubkey_import_dsa_raw(gnutls_pubkey_t key,
* parameters (if any) with the signature algorithm */
static
int fixup_spki_params(const gnutls_pk_params_st *key_params, const gnutls_sign_entry_st *se,
- const mac_entry_st *me, gnutls_x509_spki_st *params)
+ const mac_entry_st *me, gnutls_x509_spki_st *params)
{
unsigned bits;
@@ -2018,6 +2018,9 @@ int fixup_spki_params(const gnutls_pk_params_st *key_params, const gnutls_sign_e
if (params->rsa_pss_dig != se->hash)
return gnutls_assert_val(GNUTLS_E_CONSTRAINT_ERROR);
+ } else if (params->pk == GNUTLS_PK_DSA ||
+ params->pk == GNUTLS_PK_ECDSA) {
+ params->dsa_dig = se->hash;
}
return 0;
diff --git a/tests/fips-test.c b/tests/fips-test.c
index 788f4ab..ec0f4b4 100644
--- a/tests/fips-test.c
+++ b/tests/fips-test.c
@@ -80,8 +80,22 @@ static const gnutls_datum_t rsa2342_sha1_sig = {
.size = sizeof(rsa2342_sha1_sig_data),
};
+static const uint8_t ecc256_sha1_sig_data[] = {
+ 0x30, 0x45, 0x02, 0x21, 0x00, 0x9a, 0x28, 0xc9, 0xbf, 0xc8, 0x70, 0x4f,
+ 0x27, 0x2d, 0xe1, 0x66, 0xc4, 0xa5, 0xc6, 0xf2, 0xdc, 0x33, 0xb9, 0x41,
+ 0xdf, 0x78, 0x98, 0x8a, 0x22, 0x4d, 0x29, 0x37, 0xa0, 0x0f, 0x6f, 0xd4,
+ 0xed, 0x02, 0x20, 0x0b, 0x15, 0xca, 0x30, 0x09, 0x2d, 0x55, 0x44, 0xb4,
+ 0x1d, 0x3f, 0x48, 0x7a, 0xc3, 0xd1, 0x2a, 0xc1, 0x0e, 0x47, 0xfa, 0xe6,
+ 0xe9, 0x0f, 0x03, 0xe2, 0x01, 0x4e, 0xe4, 0x73, 0x37, 0xa7, 0x90,
+};
+
+static const gnutls_datum_t ecc256_sha1_sig = {
+ .data = (unsigned char *)ecc256_sha1_sig_data,
+ .size = sizeof(ecc256_sha1_sig_data),
+};
+
static void
-rsa_import_keypair(gnutls_privkey_t *privkey, gnutls_pubkey_t *pubkey,
+import_keypair(gnutls_privkey_t *privkey, gnutls_pubkey_t *pubkey,
const char *filename)
{
const char *srcdir;
@@ -274,6 +288,8 @@ void doit(void)
gnutls_datum_t signature;
unsigned int bits;
uint8_t hmac[64];
+ uint8_t hash[64];
+ gnutls_datum_t hashed_data;
uint8_t pbkdf2[64];
gnutls_datum_t temp_key = { NULL, 0 };
@@ -473,7 +489,7 @@ void doit(void)
/* Import 2432-bit RSA key; not a security function */
FIPS_PUSH_CONTEXT();
- rsa_import_keypair(&privkey, &pubkey, "rsa-2432.pem");
+ import_keypair(&privkey, &pubkey, "rsa-2432.pem");
FIPS_POP_CONTEXT(INITIAL);
/* Create a signature with 2432-bit RSA and SHA256; approved */
@@ -519,7 +535,7 @@ void doit(void)
/* Import 512-bit RSA key; not a security function */
FIPS_PUSH_CONTEXT();
- rsa_import_keypair(&privkey, &pubkey, "rsa-512.pem");
+ import_keypair(&privkey, &pubkey, "rsa-512.pem");
FIPS_POP_CONTEXT(INITIAL);
/* Create a signature with 512-bit RSA and SHA256; not approved */
@@ -543,6 +559,134 @@ void doit(void)
gnutls_pubkey_deinit(pubkey);
gnutls_privkey_deinit(privkey);
+ /* Import ECDSA key; not a security function */
+ FIPS_PUSH_CONTEXT();
+ import_keypair(&privkey, &pubkey, "ecc256.pem");
+ FIPS_POP_CONTEXT(INITIAL);
+
+ /* Create a signature with ECDSA and SHA256; approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_data2(privkey, GNUTLS_SIGN_ECDSA_SHA256, 0,
+ &data, &signature);
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_data2 failed\n");
+ }
+ FIPS_POP_CONTEXT(APPROVED);
+
+ /* Verify a signature with ECDSA and SHA256; approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_ECDSA_SHA256, 0,
+ &data, &signature);
+ if (ret < 0) {
+ fail("gnutls_pubkey_verify_data2 failed\n");
+ }
+ FIPS_POP_CONTEXT(APPROVED);
+ gnutls_free(signature.data);
+
+ /* Create a signature with ECDSA and SHA256 (old API); approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA256, 0,
+ &data, &signature);
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_data failed\n");
+ }
+ FIPS_POP_CONTEXT(APPROVED);
+
+ /* Create a SHA256 hashed data for 2-pass signature API; not a
+ * crypto operation */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_hash_fast(GNUTLS_DIG_SHA256, data.data, data.size, hash);
+ if (ret < 0) {
+ fail("gnutls_hash_fast failed\n");
+ }
+ hashed_data.data = hash;
+ hashed_data.size = 32;
+ FIPS_POP_CONTEXT(INITIAL);
+
+ /* Create a signature with ECDSA and SHA256 (2-pass API); not-approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_hash2(privkey, GNUTLS_SIGN_ECDSA_SHA256, 0,
+ &hashed_data, &signature);
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_hash2 failed\n");
+ }
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+ gnutls_free(signature.data);
+
+ /* Create a signature with ECDSA and SHA256 (2-pass old API); not-approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_hash(privkey, GNUTLS_DIG_SHA256, 0,
+ &hashed_data, &signature);
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_hash failed\n");
+ }
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+ gnutls_free(signature.data);
+
+ /* Create a signature with ECDSA and SHA-1; not approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_data2(privkey, GNUTLS_SIGN_ECDSA_SHA1, 0,
+ &data, &signature);
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_data2 failed\n");
+ }
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+
+ /* Verify a signature created with ECDSA and SHA-1; approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_ECDSA_SHA1,
+ GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1, &data,
+ &ecc256_sha1_sig);
+ if (ret < 0) {
+ fail("gnutls_pubkey_verify_data2 failed\n");
+ }
+ FIPS_POP_CONTEXT(APPROVED);
+ gnutls_free(signature.data);
+
+ /* Create a signature with ECDSA and SHA-1 (old API); not approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0,
+ &data, &signature);
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_data failed\n");
+ }
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+ gnutls_free(signature.data);
+
+ /* Create a SHA1 hashed data for 2-pass signature API; not a
+ * crypto operation */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_hash_fast(GNUTLS_DIG_SHA1, data.data, data.size, hash);
+ if (ret < 0) {
+ fail("gnutls_hash_fast failed\n");
+ }
+ hashed_data.data = hash;
+ hashed_data.size = 20;
+ FIPS_POP_CONTEXT(INITIAL);
+
+ /* Create a signature with ECDSA and SHA1 (2-pass API); not-approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_hash2(privkey, GNUTLS_SIGN_ECDSA_SHA1, 0,
+ &hashed_data, &signature);
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_hash2 failed\n");
+ }
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+ gnutls_free(signature.data);
+
+ /* Create a signature with ECDSA and SHA1 (2-pass old API); not-approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_privkey_sign_hash(privkey, GNUTLS_DIG_SHA1, 0,
+ &hashed_data, &signature);
+ if (ret < 0) {
+ fail("gnutls_privkey_sign_hash failed\n");
+ }
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+ gnutls_free(signature.data);
+
+ gnutls_pubkey_deinit(pubkey);
+ gnutls_privkey_deinit(privkey);
+
/* Test RND functions */
FIPS_PUSH_CONTEXT();
ret = gnutls_rnd(GNUTLS_RND_RANDOM, key16, sizeof(key16));
--
2.37.3

View File

@ -440,3 +440,201 @@ index a6a283fa67..31a5e26111 100644
--
2.36.1
From 354027c0c09db60d3083fa48ae791046d336957b Mon Sep 17 00:00:00 2001
From: Alexander Sosedkin <asosedkin@redhat.com>
Date: Tue, 28 Jun 2022 17:22:36 +0200
Subject: [PATCH] tests/fips-test: minor extension
Signed-off-by: Alexander Sosedkin <asosedkin@redhat.com>
---
tests/fips-test.c | 36 +++++++++++++++++++++++++++---------
1 file changed, 27 insertions(+), 9 deletions(-)
diff --git a/tests/fips-test.c b/tests/fips-test.c
index 31a5e26111..f9bd34586a 100644
--- a/tests/fips-test.c
+++ b/tests/fips-test.c
@@ -427,34 +427,43 @@ void doit(void)
rsa_import_keypair(&privkey, &pubkey, "rsa-2432.pem");
FIPS_POP_CONTEXT(INITIAL);
- /* Create a signature with SHA256; approved */
+ /* Create a signature with 2432-bit RSA and SHA256; approved */
FIPS_PUSH_CONTEXT();
ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA256, 0,
&data, &signature);
if (ret < 0) {
fail("gnutls_privkey_sign_data failed\n");
}
- gnutls_free(signature.data);
FIPS_POP_CONTEXT(APPROVED);
- /* Create a signature with SHA-1; not approved */
+ /* Verify a signature with 2432-bit RSA and SHA256; approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA256, 0,
+ &data, &signature);
+ if (ret < 0) {
+ fail("gnutls_pubkey_verify_data2 failed\n");
+ }
+ FIPS_POP_CONTEXT(APPROVED);
+ gnutls_free(signature.data);
+
+ /* Create a signature with 2432-bit RSA and SHA-1; not approved */
FIPS_PUSH_CONTEXT();
ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA1, 0,
&data, &signature);
if (ret < 0) {
fail("gnutls_privkey_sign_data failed\n");
}
- gnutls_free(signature.data);
FIPS_POP_CONTEXT(NOT_APPROVED);
- /* Verify a signature created with SHA-1; approved */
+ /* Verify a signature created with 2432-bit RSA and SHA-1; approved */
FIPS_PUSH_CONTEXT();
- ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0, &data,
- &rsa2342_sha1_sig);
+ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0,
+ &data, &rsa2342_sha1_sig);
if (ret < 0) {
fail("gnutls_pubkey_verify_data2 failed\n");
}
FIPS_POP_CONTEXT(APPROVED);
+ gnutls_free(signature.data);
gnutls_pubkey_deinit(pubkey);
gnutls_privkey_deinit(privkey);
@@ -463,15 +472,24 @@ void doit(void)
rsa_import_keypair(&privkey, &pubkey, "rsa-512.pem");
FIPS_POP_CONTEXT(INITIAL);
- /* Create a signature; not approved */
+ /* Create a signature with 512-bit RSA and SHA256; not approved */
FIPS_PUSH_CONTEXT();
ret = gnutls_privkey_sign_data(privkey, GNUTLS_DIG_SHA256, 0,
&data, &signature);
if (ret < 0) {
fail("gnutls_privkey_sign_data failed\n");
}
- gnutls_free(signature.data);
FIPS_POP_CONTEXT(NOT_APPROVED);
+
+ /* Verify a signature with 512-bit RSA and SHA256; not approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA256, 0,
+ &data, &signature);
+ if (ret < 0) {
+ fail("gnutls_pubkey_verify_data2 failed\n");
+ }
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+ gnutls_free(signature.data);
gnutls_pubkey_deinit(pubkey);
gnutls_privkey_deinit(privkey);
--
2.37.3
From 5a745120148861d873f47c1428c8c6dcadcf109b Mon Sep 17 00:00:00 2001
From: Richard Costa <richard.costa@suse.com>
Date: Sat, 9 Jul 2022 00:50:21 +0000
Subject: [PATCH] Add self-test code inside a FIPS context
Self-test code exercise lots of different FIPS-related code with
side-effects. So, in order to prevent it from losing information when
executing inside another context, we create an appropriated one.
If the self-test fails, then the library is placed in error state, so it
doesn't matter for other contexts.
Signed-off-by: Richard Maciel Costa <richard.costa@suse.com>
---
lib/fips.c | 19 +++++++++++++++++++
tests/fips-test.c | 20 ++++++++++++--------
2 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/lib/fips.c b/lib/fips.c
index 31a52a990f..7d143e608e 100644
--- a/lib/fips.c
+++ b/lib/fips.c
@@ -902,6 +902,16 @@ 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
@@ -918,6 +928,15 @@ gnutls_fips140_run_self_tests(void)
/* 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;
diff --git a/tests/fips-test.c b/tests/fips-test.c
index f9bd34586a..475b739197 100644
--- a/tests/fips-test.c
+++ b/tests/fips-test.c
@@ -457,8 +457,9 @@ void doit(void)
/* Verify a signature created with 2432-bit RSA and SHA-1; approved */
FIPS_PUSH_CONTEXT();
- ret = gnutls_pubkey_verify_data2(pubkey, GNUTLS_SIGN_RSA_SHA1, 0,
- &data, &rsa2342_sha1_sig);
+ 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");
}
@@ -501,6 +502,15 @@ void doit(void)
}
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();
@@ -544,12 +554,6 @@ void doit(void)
gnutls_fips140_context_deinit(fips_context);
- /* run self-tests manually */
- ret = gnutls_fips140_run_self_tests();
- if (ret < 0) {
- fail("gnutls_fips140_run_self_tests failed\n");
- }
-
gnutls_global_deinit();
return;
}
--
2.37.3

View File

@ -0,0 +1,310 @@
From f8a8961cfa176fc74c153cb6e1e68aff5e2d42f2 Mon Sep 17 00:00:00 2001
From: rpm-build <rpm-build>
Date: Tue, 27 Sep 2022 10:52:19 +0900
Subject: [PATCH] gnutls-3.7.6-fips-symkey-limit.patch
---
lib/crypto-api.c | 26 ++++++++++++++++++++++---
tests/fips-test.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++
tests/kdf-api.c | 9 ++++++++-
3 files changed, 80 insertions(+), 4 deletions(-)
diff --git a/lib/crypto-api.c b/lib/crypto-api.c
index b3e1eec..35200fb 100644
--- a/lib/crypto-api.c
+++ b/lib/crypto-api.c
@@ -896,6 +896,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;
@@ -912,17 +913,31 @@ int gnutls_key_generate(gnutls_datum_t * key, unsigned int key_size)
key->data = gnutls_malloc(key->size);
if (!key->data) {
gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
+ ret = GNUTLS_E_MEMORY_ERROR;
+ goto error;
+ }
+
+ /* Key lengths of less than 112 bits are not approved */
+ if (key_size < 14) {
+ not_approved = true;
}
ret = gnutls_rnd(GNUTLS_RND_RANDOM, key->data, key->size);
if (ret < 0) {
gnutls_assert();
_gnutls_free_datum(key);
- return ret;
+ goto error;
}
- return 0;
+ error:
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else if (not_approved) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
+ return ret;
}
/* AEAD API */
@@ -2058,6 +2073,11 @@ gnutls_pbkdf2(gnutls_mac_algorithm_t mac,
not_approved = true;
}
+ /* Key lengths and output sizes of less than 112 bits are not approved */
+ if (key->size < 14 || length < 14) {
+ not_approved = true;
+ }
+
ret = _gnutls_kdf_ops.pbkdf2(mac, key->data, key->size,
salt->data, salt->size, iter_count,
output, length);
diff --git a/tests/fips-test.c b/tests/fips-test.c
index 31a5e26..27da414 100644
--- a/tests/fips-test.c
+++ b/tests/fips-test.c
@@ -274,6 +274,8 @@ void doit(void)
gnutls_datum_t signature;
unsigned int bits;
uint8_t hmac[64];
+ uint8_t pbkdf2[64];
+ gnutls_datum_t temp_key = { NULL, 0 };
fprintf(stderr,
"Please note that if in FIPS140 mode, you need to assure the library's integrity prior to running this test\n");
@@ -371,11 +373,58 @@ void doit(void)
}
FIPS_POP_CONTEXT(NOT_APPROVED);
+ /* PBKDF2 with key equal to or longer than 112 bits: approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_pbkdf2(GNUTLS_MAC_SHA256, &key, &iv, 100,
+ &pbkdf2, sizeof(pbkdf2));
+ if (ret < 0) {
+ fail("gnutls_pbkdf2 failed\n");
+ }
+ FIPS_POP_CONTEXT(APPROVED);
+
+ /* PBKDF2 with key shorter than 112 bits: not approved */
+ FIPS_PUSH_CONTEXT();
+ key.size = 13;
+ ret = gnutls_pbkdf2(GNUTLS_MAC_SHA256, &key, &iv, 100,
+ &pbkdf2, sizeof(pbkdf2));
+ if (ret < 0) {
+ fail("gnutls_pbkdf2 failed\n");
+ }
+ key.size = sizeof(key16);
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+
+ /* PBKDF2 with output shorter than 112 bits: not approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_pbkdf2(GNUTLS_MAC_SHA256, &key, &iv, 100,
+ &pbkdf2, 13);
+ if (ret < 0) {
+ fail("gnutls_pbkdf2 failed\n");
+ }
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+
ret = gnutls_rnd(GNUTLS_RND_NONCE, key16, sizeof(key16));
if (ret < 0) {
fail("gnutls_rnd failed\n");
}
+ /* Symmetric key generation equal to or longer than 112 bits: approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_key_generate(&temp_key, 14);
+ if (ret < 0) {
+ fail("gnutls_key_generate failed\n");
+ }
+ gnutls_free(temp_key.data);
+ FIPS_POP_CONTEXT(APPROVED);
+
+ /* Symmetric key generation shorter than 112 bits: not approved */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_key_generate(&temp_key, 13);
+ if (ret < 0) {
+ fail("gnutls_key_generate failed\n");
+ }
+ gnutls_free(temp_key.data);
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+
ret = gnutls_pubkey_init(&pubkey);
if (ret < 0) {
fail("gnutls_pubkey_init failed\n");
diff --git a/tests/kdf-api.c b/tests/kdf-api.c
index 25fbc6a..8a4677c 100644
--- a/tests/kdf-api.c
+++ b/tests/kdf-api.c
@@ -89,6 +89,7 @@ test_hkdf(gnutls_mac_algorithm_t mac,
FIPS_PUSH_CONTEXT();
assert(gnutls_hkdf_extract(mac, &ikm, &salt, buf) >= 0);
+ /* HKDF outside of TLS usage is not approved */
FIPS_POP_CONTEXT(NOT_APPROVED);
gnutls_free(ikm.data);
gnutls_free(salt.data);
@@ -110,6 +111,7 @@ test_hkdf(gnutls_mac_algorithm_t mac,
FIPS_PUSH_CONTEXT();
assert(gnutls_hkdf_expand(mac, &prk, &info, buf, length) >= 0);
+ /* HKDF outside of TLS usage is not approved */
FIPS_POP_CONTEXT(NOT_APPROVED);
gnutls_free(info.data);
@@ -151,7 +153,12 @@ test_pbkdf2(gnutls_mac_algorithm_t mac,
FIPS_PUSH_CONTEXT();
assert(gnutls_pbkdf2(mac, &ikm, &salt, iter_count, buf, length) >= 0);
- FIPS_POP_CONTEXT(APPROVED);
+ /* Key sizes and output sizes less than 112-bit are not approved. */
+ if (ikm.size < 14 || length < 14) {
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+ } else {
+ FIPS_POP_CONTEXT(APPROVED);
+ }
gnutls_free(ikm.data);
gnutls_free(salt.data);
--
2.37.3
From 86eded166f77612c70201c0d85d3abe711edd77d Mon Sep 17 00:00:00 2001
From: Daiki Ueno <ueno@gnu.org>
Date: Thu, 29 Sep 2022 21:19:26 +0900
Subject: [PATCH] fips: only mark HMAC as approved in PBKDF2
As ACVP only allows HMAC used with PBKDF2[1], this change marks other
hash algorithms not-approved.
1. https://pages.nist.gov/ACVP/draft-celi-acvp-pbkdf.html
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
lib/crypto-api.c | 5 ++++-
lib/fips.h | 16 +++++++++++++++-
tests/kdf-api.c | 30 +++++++++++++++++++++++++++++-
3 files changed, 48 insertions(+), 3 deletions(-)
diff --git a/lib/crypto-api.c b/lib/crypto-api.c
index d3e601ab3a..9f7e18db11 100644
--- a/lib/crypto-api.c
+++ b/lib/crypto-api.c
@@ -2229,7 +2229,10 @@ gnutls_pbkdf2(gnutls_mac_algorithm_t mac,
if (!is_mac_algo_allowed(mac)) {
_gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
- } else if (!is_mac_algo_approved_in_fips(mac)) {
+ } else if (!is_mac_algo_hmac_approved_in_fips(mac)) {
+ /* ACVP only allows HMAC used with PBKDF2:
+ * https://pages.nist.gov/ACVP/draft-celi-acvp-pbkdf.html
+ */
not_approved = true;
}
diff --git a/lib/fips.h b/lib/fips.h
index 3a74f254e7..bf61b36741 100644
--- a/lib/fips.h
+++ b/lib/fips.h
@@ -76,7 +76,7 @@ void _gnutls_lib_simulate_error(void);
void _gnutls_lib_force_operational(void);
inline static bool
-is_mac_algo_approved_in_fips(gnutls_mac_algorithm_t algo)
+is_mac_algo_hmac_approved_in_fips(gnutls_mac_algorithm_t algo)
{
switch (algo) {
case GNUTLS_MAC_SHA1:
@@ -88,6 +88,20 @@ is_mac_algo_approved_in_fips(gnutls_mac_algorithm_t algo)
case GNUTLS_MAC_SHA3_256:
case GNUTLS_MAC_SHA3_384:
case GNUTLS_MAC_SHA3_512:
+ return true;
+ default:
+ return false;
+ }
+}
+
+inline static bool
+is_mac_algo_approved_in_fips(gnutls_mac_algorithm_t algo)
+{
+ if (is_mac_algo_hmac_approved_in_fips(algo)) {
+ return true;
+ }
+
+ switch (algo) {
case GNUTLS_MAC_AES_CMAC_128:
case GNUTLS_MAC_AES_CMAC_256:
case GNUTLS_MAC_AES_GMAC_128:
diff --git a/tests/kdf-api.c b/tests/kdf-api.c
index 577cbf7a17..4feb22688b 100644
--- a/tests/kdf-api.c
+++ b/tests/kdf-api.c
@@ -26,6 +26,7 @@
#include <gnutls/crypto.h>
#include <assert.h>
+#include <stdbool.h>
#include <stdint.h>
#include "utils.h"
@@ -133,6 +134,25 @@ test_hkdf(gnutls_mac_algorithm_t mac,
gnutls_free(hex.data);
}
+inline static bool
+is_mac_algo_hmac_approved_in_fips(gnutls_mac_algorithm_t algo)
+{
+ switch (algo) {
+ case GNUTLS_MAC_SHA1:
+ case GNUTLS_MAC_SHA256:
+ case GNUTLS_MAC_SHA384:
+ case GNUTLS_MAC_SHA512:
+ case GNUTLS_MAC_SHA224:
+ case GNUTLS_MAC_SHA3_224:
+ case GNUTLS_MAC_SHA3_256:
+ case GNUTLS_MAC_SHA3_384:
+ case GNUTLS_MAC_SHA3_512:
+ return true;
+ default:
+ return false;
+ }
+}
+
static void
test_pbkdf2(gnutls_mac_algorithm_t mac,
const char *ikm_hex,
@@ -161,7 +181,8 @@ test_pbkdf2(gnutls_mac_algorithm_t mac,
FIPS_PUSH_CONTEXT();
assert(gnutls_pbkdf2(mac, &ikm, &salt, iter_count, buf, length) >= 0);
/* Key sizes and output sizes less than 112-bit are not approved. */
- if (ikm.size < 14 || length < 14) {
+ if (ikm.size < 14 || length < 14 ||
+ !is_mac_algo_hmac_approved_in_fips(mac)) {
FIPS_POP_CONTEXT(NOT_APPROVED);
} else {
FIPS_POP_CONTEXT(APPROVED);
@@ -208,5 +229,12 @@ doit(void)
20,
"4b007901b765489abead49d926f721d065a429c1");
+ test_pbkdf2(GNUTLS_MAC_AES_CMAC_128,
+ "70617373776f726470617373776f7264", /* "passwordpassword" */
+ "73616c74", /* "salt" */
+ 4096,
+ 20,
+ "c4c112c6e1e3b8757640603dec78825ff87605a7");
+
gnutls_fips140_context_deinit(fips_context);
}
--
2.37.3

View File

@ -13,7 +13,7 @@ print(string.sub(hash, 0, 16))
}
Version: 3.7.6
Release: 11%{?dist}
Release: 12%{?dist}
# not upstreamed
Patch: gnutls-3.6.7-no-now-guile.patch
Patch: gnutls-3.2.7-rpath.patch
@ -28,6 +28,8 @@ Patch: gnutls-3.7.6-aes-gcm-pt-limit.patch
Patch: gnutls-3.7.6-pkcs7-verify.patch
Patch: gnutls-3.7.6-fips-pkcs12-des-cbc.patch
Patch: gnutls-3.7.6-fips-rsa-key-sizes.patch
Patch: gnutls-3.7.6-fips-symkey-limit.patch
Patch: gnutls-3.7.6-fips-ecdsa-hash-check.patch
# not upstreamed
Patch: gnutls-3.7.3-disable-config-reload.patch
@ -395,6 +397,13 @@ make check %{?_smp_mflags} GNUTLS_SYSTEM_PRIORITY_FILE=/dev/null
%endif
%changelog
* Tue Sep 27 2022 Daiki Ueno <dueno@redhat.com> - 3.7.6-12
- fips: mark PBKDF2 with short key and output sizes non-approved
- fips: only mark HMAC as approved in PBKDF2
- fips: mark gnutls_key_generate with short key sizes non-approved
- fips: fix checking on hash algorithm used in ECDSA
- fips: preserve operation context around FIPS selftests API
* Fri Aug 26 2022 Daiki Ueno <dueno@redhat.com> - 3.7.6-11
- Supply --with{,out}-{zlib,brotli,zstd} explicitly