File gnutls-Add-missing-FIPS-service-indicator-transitions.patch of Package gnutls.32149
From e6c7e55953abd52b731cf4581e0d89065eb1e20a Mon Sep 17 00:00:00 2001
From: Zoltan Fridrich <zfridric@redhat.com>
Date: Tue, 5 Apr 2022 16:28:41 +0200
Subject: [PATCH] Add missing FIPS service indicator transitions
Signed-off-by: Zoltan Fridrich <zfridric@redhat.com>
---
lib/ext/session_ticket.c | 5 +
lib/nettle/rnd-fips.c | 33 ++++--
lib/nettle/rnd.c | 11 +-
lib/x509/privkey_pkcs8_pbes1.c | 5 +-
tests/fips-test.c | 193 ++++++++++++++++++++++++++++-----
5 files changed, 209 insertions(+), 38 deletions(-)
diff --git a/lib/ext/session_ticket.c b/lib/ext/session_ticket.c
index 5877f8fa12..cecb370cd4 100644
--- a/lib/ext/session_ticket.c
+++ b/lib/ext/session_ticket.c
@@ -22,6 +22,7 @@
#include "gnutls_int.h"
#include "errors.h"
+#include <fips.h>
#include <datum.h>
#include <algorithms.h>
#include <handshake.h>
@@ -238,9 +239,11 @@ _gnutls_decrypt_session_ticket(gnutls_session_t session,
cipher_to_entry(TICKET_CIPHER),
&stek_cipher_key, &IV, 0);
if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
gnutls_assert();
goto cleanup;
}
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
ret = _gnutls_cipher_decrypt(&cipher_hd, ticket.encrypted_state,
ticket.encrypted_state_len);
@@ -315,9 +318,11 @@ _gnutls_encrypt_session_ticket(gnutls_session_t session,
cipher_to_entry(TICKET_CIPHER),
&stek_cipher_key, &IV, 1);
if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
gnutls_assert();
goto cleanup;
}
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
ret = _gnutls_cipher_encrypt(&cipher_hd, encrypted_state.data,
encrypted_state.size);
diff --git a/lib/nettle/rnd-fips.c b/lib/nettle/rnd-fips.c
index ccb92d25a2..35ad618d64 100644
--- a/lib/nettle/rnd-fips.c
+++ b/lib/nettle/rnd-fips.c
@@ -57,20 +57,27 @@ static int get_random(struct drbg_aes_ctx *ctx, struct fips_ctx *fctx,
if ( _gnutls_detect_fork(fctx->forkid) != 0) {
ret = _rngfips_ctx_reinit(fctx);
- if (ret < 0)
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
}
if (ctx->reseed_counter > DRBG_AES_RESEED_TIME) {
ret = drbg_reseed(fctx, ctx);
- if (ret < 0)
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
}
ret = drbg_aes_random(ctx, length, buffer);
- if (ret == 0)
+ if (ret == 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
+ }
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
return 0;
}
@@ -99,6 +106,7 @@ static int get_entropy(struct fips_ctx *fctx, uint8_t *buffer, size_t length)
sha256_digest(&ctx, sizeof(hash), hash);
if (memcmp(hash, fctx->entropy_hash, sizeof(hash)) == 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
_gnutls_switch_lib_state(LIB_STATE_ERROR);
return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
}
@@ -110,6 +118,7 @@ static int get_entropy(struct fips_ctx *fctx, uint8_t *buffer, size_t length)
}
zeroize_key(block, sizeof(block));
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
return 0;
}
@@ -121,15 +130,20 @@ static int drbg_init(struct fips_ctx *fctx, struct drbg_aes_ctx *ctx)
int ret;
ret = get_entropy(fctx, buffer, sizeof(buffer));
- if (ret < 0)
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
ret = drbg_aes_init(ctx, sizeof(buffer), buffer,
PSTRING_SIZE, (void*)PSTRING);
zeroize_key(buffer, sizeof(buffer));
- if (ret == 0)
+ if (ret == 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
+ }
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
return GNUTLS_E_SUCCESS;
}
@@ -140,14 +154,19 @@ static int drbg_reseed(struct fips_ctx *fctx, struct drbg_aes_ctx *ctx)
int ret;
ret = get_entropy(fctx, buffer, sizeof(buffer));
- if (ret < 0)
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
ret = drbg_aes_reseed(ctx, sizeof(buffer), buffer, 0, NULL);
zeroize_key(buffer, sizeof(buffer));
- if (ret == 0)
+ if (ret == 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
+ }
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
return GNUTLS_E_SUCCESS;
}
diff --git a/lib/nettle/rnd.c b/lib/nettle/rnd.c
index 0512af1cd1..cddf1f72ff 100644
--- a/lib/nettle/rnd.c
+++ b/lib/nettle/rnd.c
@@ -174,8 +174,10 @@ wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize)
prng_ctx = &ctx->normal;
else if (level == GNUTLS_RND_NONCE)
prng_ctx = &ctx->nonce;
- else
+ else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
+ }
/* Two reasons for this memset():
* 1. avoid getting filled with valgrind warnings
@@ -207,12 +209,14 @@ wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize)
if (ret < 0) {
gnutls_assert();
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
goto cleanup;
}
ret = single_prng_init(prng_ctx, new_key, sizeof(new_key), 0);
if (ret < 0) {
gnutls_assert();
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
goto cleanup;
}
@@ -227,17 +231,20 @@ wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize)
ret = wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, new_key, sizeof(new_key));
if (ret < 0) {
gnutls_assert();
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
goto cleanup;
}
ret = single_prng_init(prng_ctx, new_key, sizeof(new_key), 0);
if (ret < 0) {
gnutls_assert();
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
goto cleanup;
}
}
ret = 0;
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
cleanup:
return ret;
@@ -254,8 +261,6 @@ static void wrap_nettle_rnd_refresh(void *_ctx)
wrap_nettle_rnd(_ctx, GNUTLS_RND_NONCE, &tmp, 1);
wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, &tmp, 1);
-
- return;
}
int crypto_rnd_prio = INT_MAX;
diff --git a/lib/x509/privkey_pkcs8_pbes1.c b/lib/x509/privkey_pkcs8_pbes1.c
index 70217dac47..c296807974 100644
--- a/lib/x509/privkey_pkcs8_pbes1.c
+++ b/lib/x509/privkey_pkcs8_pbes1.c
@@ -161,8 +161,11 @@ _gnutls_decrypt_pbes1_des_md5_data(const char *password,
result =
_gnutls_cipher_init(&ch, cipher_to_entry(GNUTLS_CIPHER_DES_CBC),
&dkey, &d_iv, 0);
- if (result < 0)
+ if (result < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(result);
+ }
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
result = _gnutls_cipher_decrypt(&ch, encrypted_data->data, encrypted_data->size);
if (result < 0) {
diff --git a/tests/fips-test.c b/tests/fips-test.c
index d72b5d2bce..32b224260a 100644
--- a/tests/fips-test.c
+++ b/tests/fips-test.c
@@ -9,11 +9,30 @@
#include <gnutls/abstract.h>
#include <gnutls/x509.h>
-void _gnutls_lib_simulate_error(void);
-
/* This does check the FIPS140 support.
*/
+#define FIPS_PUSH_CONTEXT() do { \
+ ret = gnutls_fips140_push_context(fips_context); \
+ if (ret < 0) { \
+ fail("gnutls_fips140_push_context failed\n"); \
+ } \
+} while (0)
+
+#define FIPS_POP_CONTEXT(state) do { \
+ ret = gnutls_fips140_pop_context(); \
+ if (ret < 0) { \
+ fail("gnutls_fips140_context_pop failed\n"); \
+ } \
+ fips_state = gnutls_fips140_get_operation_state(fips_context); \
+ if (fips_state != GNUTLS_FIPS140_OP_ ## state) { \
+ fail("operation state is not " # state " (%d)\n", \
+ fips_state); \
+ } \
+} while (0)
+
+void _gnutls_lib_simulate_error(void);
+
static void tls_log_func(int level, const char *str)
{
fprintf(stderr, "<%d>| %s", level, str);
@@ -21,6 +40,10 @@ static void tls_log_func(int level, const char *str)
static uint8_t key16[16];
static uint8_t iv16[16];
+uint8_t key_data[64];
+uint8_t iv_data[16];
+gnutls_fips140_context_t fips_context;
+gnutls_fips140_operation_state_t fips_state;
static const gnutls_datum_t data = { .data = (unsigned char *)"foo", 3 };
static const uint8_t rsa2342_sha1_sig_data[] = {
@@ -109,6 +132,131 @@ rsa_import_keypair(gnutls_privkey_t *privkey, gnutls_pubkey_t *pubkey,
}
+static void
+test_aead_cipher_approved(gnutls_cipher_algorithm_t cipher,
+ unsigned key_size)
+{
+ int ret;
+ gnutls_aead_cipher_hd_t h;
+ gnutls_datum_t key = { key_data, key_size };
+ gnutls_memset(key_data, 0, key_size);
+
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_aead_cipher_init(&h, cipher, &key);
+ if (ret < 0) {
+ fail("gnutls_aead_cipher_init failed %s for %s\n",
+ gnutls_strerror(ret),
+ gnutls_cipher_get_name(cipher));
+ }
+ gnutls_aead_cipher_deinit(h);
+ FIPS_POP_CONTEXT(APPROVED);
+}
+
+static void
+test_cipher_approved(gnutls_cipher_algorithm_t cipher,
+ unsigned key_size, unsigned iv_size)
+{
+ int ret;
+ gnutls_cipher_hd_t h;
+ gnutls_datum_t key = { key_data, key_size };
+ gnutls_datum_t iv = { iv_data, iv_size };
+ gnutls_memset(key_data, 0, key_size);
+ gnutls_memset(iv_data, 0, iv_size);
+
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_cipher_init(&h, cipher, &key, &iv);
+ if (ret < 0) {
+ fail("gnutls_cipher_init failed for %s\n",
+ gnutls_cipher_get_name(cipher));
+ }
+ gnutls_cipher_deinit(h);
+ FIPS_POP_CONTEXT(APPROVED);
+}
+
+static void
+test_cipher_allowed(gnutls_cipher_algorithm_t cipher,
+ unsigned key_size, unsigned iv_size)
+{
+ int ret;
+ gnutls_cipher_hd_t h;
+ gnutls_datum_t key = { key_data, key_size };
+ gnutls_datum_t iv = { iv_data, iv_size };
+ gnutls_memset(key_data, 0, key_size);
+ gnutls_memset(iv_data, 0, iv_size);
+
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_cipher_init(&h, cipher, &key, &iv);
+ if (ret < 0) {
+ fail("gnutls_cipher_init failed for %s\n",
+ gnutls_cipher_get_name(cipher));
+ }
+ gnutls_cipher_deinit(h);
+ FIPS_POP_CONTEXT(NOT_APPROVED);
+}
+
+static void
+test_cipher_disallowed(gnutls_cipher_algorithm_t cipher,
+ unsigned key_size, unsigned iv_size)
+{
+ int ret;
+ gnutls_cipher_hd_t h;
+ gnutls_datum_t key = { key_data, key_size };
+ gnutls_datum_t iv = { iv_data, iv_size };
+ gnutls_memset(key_data, 0, key_size);
+ gnutls_memset(iv_data, 0, iv_size);
+
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_cipher_init(&h, cipher, &key, &iv);
+ if (ret != GNUTLS_E_UNWANTED_ALGORITHM) {
+ if (ret == 0)
+ gnutls_cipher_deinit(h);
+ fail("gnutls_cipher_init should have failed with"
+ "GNUTLS_E_UNWANTED_ALGORITHM for %s\n",
+ gnutls_cipher_get_name(cipher));
+ }
+ FIPS_POP_CONTEXT(ERROR);
+}
+
+static inline void
+test_ciphers(void)
+{
+ test_cipher_approved(GNUTLS_CIPHER_AES_128_CBC, 16, 16);
+ test_cipher_approved(GNUTLS_CIPHER_AES_192_CBC, 24, 16);
+ test_cipher_approved(GNUTLS_CIPHER_AES_256_CBC, 32, 16);
+ test_aead_cipher_approved(GNUTLS_CIPHER_AES_128_CCM, 16);
+ test_aead_cipher_approved(GNUTLS_CIPHER_AES_256_CCM, 32);
+ test_aead_cipher_approved(GNUTLS_CIPHER_AES_128_CCM_8, 16);
+ test_aead_cipher_approved(GNUTLS_CIPHER_AES_256_CCM_8, 32);
+ test_cipher_approved(GNUTLS_CIPHER_AES_128_CFB8, 16, 16);
+ test_cipher_approved(GNUTLS_CIPHER_AES_192_CFB8, 24, 16);
+ test_cipher_approved(GNUTLS_CIPHER_AES_256_CFB8, 32, 16);
+ test_cipher_allowed(GNUTLS_CIPHER_AES_128_GCM, 16, 12);
+ test_cipher_allowed(GNUTLS_CIPHER_AES_192_GCM, 24, 12);
+ test_cipher_allowed(GNUTLS_CIPHER_AES_256_GCM, 32, 12);
+ test_cipher_disallowed(GNUTLS_CIPHER_ARCFOUR_128, 16, 0);
+ test_cipher_disallowed(GNUTLS_CIPHER_ESTREAM_SALSA20_256, 32, 0);
+ test_cipher_disallowed(GNUTLS_CIPHER_SALSA20_256, 32, 8);
+ test_cipher_disallowed(GNUTLS_CIPHER_CHACHA20_32, 32, 16);
+ test_cipher_disallowed(GNUTLS_CIPHER_CHACHA20_64, 32, 16);
+ test_cipher_disallowed(GNUTLS_CIPHER_CAMELLIA_192_CBC, 24, 16);
+ test_cipher_disallowed(GNUTLS_CIPHER_CAMELLIA_128_CBC, 16, 16);
+ test_cipher_disallowed(GNUTLS_CIPHER_CHACHA20_POLY1305, 32, 12);
+ test_cipher_disallowed(GNUTLS_CIPHER_CAMELLIA_128_GCM, 16, 0);
+ test_cipher_disallowed(GNUTLS_CIPHER_CAMELLIA_256_GCM, 32, 12);
+ test_cipher_disallowed(GNUTLS_CIPHER_GOST28147_CPA_CFB, 32, 8);
+ test_cipher_disallowed(GNUTLS_CIPHER_GOST28147_CPB_CFB, 32, 8);
+ test_cipher_disallowed(GNUTLS_CIPHER_GOST28147_CPC_CFB, 32, 8);
+ test_cipher_disallowed(GNUTLS_CIPHER_AES_128_SIV, 32, 16);
+ test_cipher_disallowed(GNUTLS_CIPHER_AES_256_SIV, 64, 16);
+ test_cipher_disallowed(GNUTLS_CIPHER_GOST28147_TC26Z_CNT, 32, 8);
+ test_cipher_disallowed(GNUTLS_CIPHER_MAGMA_CTR_ACPKM, 32, 8);
+ test_cipher_disallowed(GNUTLS_CIPHER_KUZNYECHIK_CTR_ACPKM, 32, 16);
+ test_cipher_disallowed(GNUTLS_CIPHER_3DES_CBC, 24, 8);
+ test_cipher_disallowed(GNUTLS_CIPHER_DES_CBC, 8, 8);
+ test_cipher_disallowed(GNUTLS_CIPHER_ARCFOUR_40, 5, 0);
+ test_cipher_disallowed(GNUTLS_CIPHER_RC2_40_CBC, 5, 8);
+}
+
void doit(void)
{
int ret;
@@ -121,8 +269,6 @@ void doit(void)
gnutls_privkey_t privkey;
gnutls_datum_t key = { key16, sizeof(key16) };
gnutls_datum_t iv = { iv16, sizeof(iv16) };
- gnutls_fips140_context_t fips_context;
- gnutls_fips140_operation_state_t fips_state;
gnutls_datum_t signature;
unsigned int bits;
uint8_t hmac[64];
@@ -158,38 +304,23 @@ void doit(void)
fail("gnutls_fips140_pop_context succeeded while not pushed\n");
}
-#define FIPS_PUSH_CONTEXT() do { \
- ret = gnutls_fips140_push_context(fips_context); \
- if (ret < 0) { \
- fail("gnutls_fips140_push_context failed\n"); \
- } \
-} while (0)
-
-#define FIPS_POP_CONTEXT(state) do { \
- ret = gnutls_fips140_pop_context(); \
- if (ret < 0) { \
- fail("gnutls_fips140_context_pop failed\n"); \
- } \
- fips_state = gnutls_fips140_get_operation_state(fips_context); \
- if (fips_state != GNUTLS_FIPS140_OP_ ## state) { \
- fail("operation state is not " # state " (%d)\n", \
- fips_state); \
- } \
-} while (0)
-
/* Try crypto.h functionality */
- ret =
- gnutls_cipher_init(&ch, GNUTLS_CIPHER_AES_128_CBC, &key, &iv);
+ test_ciphers();
+
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_cipher_init(&ch, GNUTLS_CIPHER_AES_128_CBC, &key, &iv);
if (ret < 0) {
fail("gnutls_cipher_init failed\n");
}
gnutls_cipher_deinit(ch);
+ FIPS_POP_CONTEXT(APPROVED);
- ret =
- gnutls_cipher_init(&ch, GNUTLS_CIPHER_ARCFOUR_128, &key, &iv);
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_cipher_init(&ch, GNUTLS_CIPHER_ARCFOUR_128, &key, &iv);
if (ret != GNUTLS_E_UNWANTED_ALGORITHM) {
fail("gnutls_cipher_init succeeded for arcfour\n");
}
+ FIPS_POP_CONTEXT(ERROR);
ret = gnutls_hmac_init(&mh, GNUTLS_MAC_SHA1, key.data, key.size);
if (ret < 0) {
@@ -342,6 +473,14 @@ void doit(void)
gnutls_pubkey_deinit(pubkey);
gnutls_privkey_deinit(privkey);
+ /* Test RND functions */
+ FIPS_PUSH_CONTEXT();
+ ret = gnutls_rnd(GNUTLS_RND_RANDOM, key16, sizeof(key16));
+ if (ret < 0) {
+ fail("gnutls_rnd failed\n");
+ }
+ FIPS_POP_CONTEXT(APPROVED);
+
/* Test when FIPS140 is set to error state */
_gnutls_lib_simulate_error();
--
GitLab