]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Add missing FIPS service indicator transitions
authorZoltan Fridrich <zfridric@redhat.com>
Tue, 5 Apr 2022 14:28:41 +0000 (16:28 +0200)
committerZoltan Fridrich <zfridric@redhat.com>
Mon, 11 Apr 2022 07:24:18 +0000 (09:24 +0200)
Signed-off-by: Zoltan Fridrich <zfridric@redhat.com>
lib/ext/session_ticket.c
lib/nettle/rnd-fips.c
lib/nettle/rnd.c
lib/x509/privkey_pkcs8_pbes1.c
tests/fips-test.c

index 5877f8fa124d664b5a84e313eac9d18d5a1ef51e..cecb370cd41c25e549e8918a7963f3d49764b20e 100644 (file)
@@ -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);
index ccb92d25a29bcaa74fb69c13be3c6436439e7662..35ad618d6487c3c6143b47df76803fea44dbe848 100644 (file)
@@ -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;
 }
 
index 0512af1cd1570c9a0b0359f40872c9574ba2553d..cddf1f72ffe92fda04444d30b8b8fc96c5ec9095 100644 (file)
@@ -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;
index 70217dac474946c3d995ecbe98e2fbec35ca71ab..c296807974245daa787487915bccc91472806d18 100644 (file)
@@ -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) {
index d72b5d2bce687250fb2cf68c0588b6fe624200ce..32b224260a362aa56a8e4402be7523318e8d264a 100644 (file)
@@ -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();