Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:15-SP4
gnutls
gnutls-Add-missing-FIPS-service-indicator-trans...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File gnutls-Add-missing-FIPS-service-indicator-transitions.patch of Package gnutls
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
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor