From: Simo Sorce Date: Tue, 9 Dec 2025 19:29:43 +0000 (-0500) Subject: Refactor FIPS integrity check to use KAT framework X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=53fecfc80bfe8fbef5923f4e84255f07695eb92f;p=thirdparty%2Fopenssl.git Refactor FIPS integrity check to use KAT framework The FIPS module integrity check (HMAC-SHA256) is refactored to use the generic Known Answer Test (KAT) framework instead of a standalone function. - Remove `integrity_self_test` and use `ST_ID_MAC_HMAC` with `SELF_TEST_kats_single`. - Add `self_test_mac` to `self_test_kats.c` to support MAC tests. - Move HMAC test data to `self_test_data.c`. - Rename the self-test type from "KAT_Integrity" to "KAT_Mac". - Ensure on-demand tests reset state so they can be repeated. Signed-off-by: Simo Sorce Reviewed-by: Dmitry Belyavskiy (Merged from https://github.com/openssl/openssl/pull/29222) --- diff --git a/doc/man7/OSSL_PROVIDER-FIPS.pod b/doc/man7/OSSL_PROVIDER-FIPS.pod index befc9ad3c49..1e799d4c67c 100644 --- a/doc/man7/OSSL_PROVIDER-FIPS.pod +++ b/doc/man7/OSSL_PROVIDER-FIPS.pod @@ -327,10 +327,11 @@ Uses HMAC SHA256 on the module file to validate that the module has not been modified. The integrity value is compared to a value written to a configuration file during installation. -=item "KAT_Integrity" (B) +=item "KAT_Mac" (B) Used during the Module Integrity test to perform a known answer test on -HMAC SHA256 prior to using it. +HMAC SHA256 prior to using it. In pre-4.0 versions +B ("KAT_Integrity") was used for this. =item "KAT_Cipher" (B) diff --git a/include/internal/fips.h b/include/internal/fips.h index 67b5f7d151f..c62865ebd9b 100644 --- a/include/internal/fips.h +++ b/include/internal/fips.h @@ -108,6 +108,7 @@ typedef enum { ST_ID_ASYM_CIPHER_RSA_ENC, ST_ID_ASYM_CIPHER_RSA_DEC, ST_ID_ASYM_CIPHER_RSA_DEC_CRT, + ST_ID_MAC_HMAC, ST_ID_MAX } self_test_id_t; diff --git a/include/openssl/self_test.h b/include/openssl/self_test.h index c5e4be955e7..f879370ae12 100644 --- a/include/openssl/self_test.h +++ b/include/openssl/self_test.h @@ -38,6 +38,7 @@ extern "C" { #define OSSL_SELF_TEST_TYPE_KAT_ASYM_KEYGEN "KAT_AsymmetricKeyGeneration" #define OSSL_SELF_TEST_TYPE_KAT_KEM "KAT_KEM" #define OSSL_SELF_TEST_TYPE_KAT_DIGEST "KAT_Digest" +#define OSSL_SELF_TEST_TYPE_KAT_MAC "KAT_Mac" #define OSSL_SELF_TEST_TYPE_KAT_SIGNATURE "KAT_Signature" #define OSSL_SELF_TEST_TYPE_PCT_SIGNATURE "PCT_Signature" #define OSSL_SELF_TEST_TYPE_KAT_KDF "KAT_KDF" diff --git a/providers/fips/self_test.c b/providers/fips/self_test.c index e9f88140a64..84e65bcf4aa 100644 --- a/providers/fips/self_test.c +++ b/providers/fips/self_test.c @@ -181,64 +181,6 @@ DEP_FINI_ATTRIBUTE void cleanup(void) #endif #if !defined(OPENSSL_NO_FIPS_POST) -/* - * We need an explicit HMAC-SHA-256 KAT even though it is also - * checked as part of the KDF KATs. Refer IG 10.3. - */ -static const unsigned char hmac_kat_pt[] = { - 0xdd, 0x0c, 0x30, 0x33, 0x35, 0xf9, 0xe4, 0x2e, - 0xc2, 0xef, 0xcc, 0xbf, 0x07, 0x95, 0xee, 0xa2 -}; -static const unsigned char hmac_kat_key[] = { - 0xf4, 0x55, 0x66, 0x50, 0xac, 0x31, 0xd3, 0x54, - 0x61, 0x61, 0x0b, 0xac, 0x4e, 0xd8, 0x1b, 0x1a, - 0x18, 0x1b, 0x2d, 0x8a, 0x43, 0xea, 0x28, 0x54, - 0xcb, 0xae, 0x22, 0xca, 0x74, 0x56, 0x08, 0x13 -}; -static const unsigned char hmac_kat_digest[] = { - 0xf5, 0xf5, 0xe5, 0xf2, 0x66, 0x49, 0xe2, 0x40, - 0xfc, 0x9e, 0x85, 0x7f, 0x2b, 0x9a, 0xbe, 0x28, - 0x20, 0x12, 0x00, 0x92, 0x82, 0x21, 0x3e, 0x51, - 0x44, 0x5d, 0xe3, 0x31, 0x04, 0x01, 0x72, 0x6b -}; - -static int integrity_self_test(OSSL_SELF_TEST *ev, OSSL_LIB_CTX *libctx) -{ - int ok = 0; - unsigned char out[EVP_MAX_MD_SIZE]; - size_t out_len = 0; - - OSSL_PARAM params[2]; - EVP_MAC *mac = EVP_MAC_fetch(libctx, MAC_NAME, NULL); - EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(mac); - - OSSL_SELF_TEST_onbegin(ev, OSSL_SELF_TEST_TYPE_KAT_INTEGRITY, - OSSL_SELF_TEST_DESC_INTEGRITY_HMAC); - - params[0] = OSSL_PARAM_construct_utf8_string("digest", DIGEST_NAME, 0); - params[1] = OSSL_PARAM_construct_end(); - - if (ctx == NULL - || mac == NULL - || !EVP_MAC_init(ctx, hmac_kat_key, sizeof(hmac_kat_key), params) - || !EVP_MAC_update(ctx, hmac_kat_pt, sizeof(hmac_kat_pt)) - || !EVP_MAC_final(ctx, out, &out_len, MAX_MD_SIZE)) - goto err; - - /* Optional corruption */ - OSSL_SELF_TEST_oncorrupt_byte(ev, out); - - if (out_len != sizeof(hmac_kat_digest) - || memcmp(out, hmac_kat_digest, out_len) != 0) - goto err; - ok = 1; -err: - OSSL_SELF_TEST_onend(ev, ok); - EVP_MAC_free(mac); - EVP_MAC_CTX_free(ctx); - return ok; -} - /* * Calculate the HMAC SHA256 of data read using a BIO and read_cb, and verify * the result matches the expected value. @@ -257,7 +199,7 @@ static int verify_integrity(OSSL_CORE_BIO *bio, OSSL_FUNC_BIO_read_ex_fn read_ex EVP_MAC_CTX *ctx = NULL; OSSL_PARAM params[2], *p = params; - if (!integrity_self_test(ev, libctx)) + if (!SELF_TEST_kats_single(ev, libctx, ST_ID_MAC_HMAC)) goto err; OSSL_SELF_TEST_onbegin(ev, event_type, OSSL_SELF_TEST_DESC_INTEGRITY_HMAC); @@ -383,6 +325,11 @@ int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test) goto end; } + if (on_demand_test) + /* ensure all states are cleared so all tests are repeated */ + for (int i = 0; i < ST_ID_MAX; i++) + st_all_tests[i].state = SELF_TEST_STATE_INIT; + if (!SELF_TEST_kats(ev, st->libctx, on_demand_test)) { ERR_raise(ERR_LIB_PROV, PROV_R_SELF_TEST_KAT_FAILURE); goto end; diff --git a/providers/fips/self_test.h b/providers/fips/self_test.h index 44c47e669b0..2083ce5226c 100644 --- a/providers/fips/self_test.h +++ b/providers/fips/self_test.h @@ -49,7 +49,7 @@ enum st_test_category { SELF_TEST_KAT_ASYM_KEYGEN, SELF_TEST_KAT_KEM, SELF_TEST_KAT_ASYM_CIPHER, - SELF_TEST_KAT_MAC, /* currently unused */ + SELF_TEST_KAT_MAC, }; enum st_test_state { @@ -145,6 +145,10 @@ typedef struct st_kat_drbg_st { ST_BUFFER entropyaddin2; } ST_KAT_DRBG; +typedef struct st_kat_mac_st { + const ST_KAT_PARAM *params; +} ST_KAT_MAC; + typedef struct self_test_st { const char *algorithm; const char *desc; @@ -162,6 +166,7 @@ typedef struct self_test_st { ST_KAT_KDF kdf; ST_KAT_KAS kas; ST_KAT_DRBG drbg; + ST_KAT_MAC mac; } u; const self_test_id_t *depends_on; } ST_DEFINITION; diff --git a/providers/fips/self_test_data.c b/providers/fips/self_test_data.c index c829e3d5afb..73b3ebec293 100644 --- a/providers/fips/self_test_data.c +++ b/providers/fips/self_test_data.c @@ -3298,6 +3298,33 @@ static const ST_KAT_PARAM ml_kem_key[] = { }; #endif /* OPENSSL_NO_ML_KEM */ +/* + * We need an explicit HMAC-SHA-256 KAT even though it is also + * checked as part of the KDF KATs. Refer IG 10.3. + */ +static const char hmac_kat_digest[] = "SHA256"; +static const unsigned char hmac_kat_pt[] = { + 0xdd, 0x0c, 0x30, 0x33, 0x35, 0xf9, 0xe4, 0x2e, + 0xc2, 0xef, 0xcc, 0xbf, 0x07, 0x95, 0xee, 0xa2 +}; +static const unsigned char hmac_kat_key[] = { + 0xf4, 0x55, 0x66, 0x50, 0xac, 0x31, 0xd3, 0x54, + 0x61, 0x61, 0x0b, 0xac, 0x4e, 0xd8, 0x1b, 0x1a, + 0x18, 0x1b, 0x2d, 0x8a, 0x43, 0xea, 0x28, 0x54, + 0xcb, 0xae, 0x22, 0xca, 0x74, 0x56, 0x08, 0x13 +}; +static const unsigned char hmac_kat_expected[] = { + 0xf5, 0xf5, 0xe5, 0xf2, 0x66, 0x49, 0xe2, 0x40, + 0xfc, 0x9e, 0x85, 0x7f, 0x2b, 0x9a, 0xbe, 0x28, + 0x20, 0x12, 0x00, 0x92, 0x82, 0x21, 0x3e, 0x51, + 0x44, 0x5d, 0xe3, 0x31, 0x04, 0x01, 0x72, 0x6b +}; +static const ST_KAT_PARAM hmac_kat_params[] = { + ST_KAT_PARAM_UTF8STRING(OSSL_KDF_PARAM_DIGEST, hmac_kat_digest), + ST_KAT_PARAM_OCTET(OSSL_MAC_PARAM_KEY, hmac_kat_key), + ST_KAT_PARAM_END() +}; + ST_DEFINITION st_all_tests[ST_ID_MAX] = { { "SHA1", @@ -3921,4 +3948,16 @@ ST_DEFINITION st_all_tests[ST_ID_MAX] = { }, .depends_on = rsaenc_depends_on, }, + { + "HMAC", + OSSL_SELF_TEST_DESC_INTEGRITY_HMAC, + SELF_TEST_KAT_MAC, + SELF_TEST_DEFERRED, + SELF_TEST_STATE_INIT, + ITM_BUF(hmac_kat_pt), + ITM_BUF(hmac_kat_expected), + .u.mac = { + hmac_kat_params, + }, + }, }; diff --git a/providers/fips/self_test_kats.c b/providers/fips/self_test_kats.c index 1750c99609d..59e03461629 100644 --- a/providers/fips/self_test_kats.c +++ b/providers/fips/self_test_kats.c @@ -899,6 +899,55 @@ err: return ret; } +/* Test MAC algorithms */ +static int self_test_mac(const ST_DEFINITION *t, OSSL_SELF_TEST *st, + OSSL_LIB_CTX *libctx) +{ + int ret = 0; + unsigned char out[EVP_MAX_MD_SIZE]; + size_t out_len = 0; + EVP_MAC *mac = NULL; + EVP_MAC_CTX *ctx = NULL; + OSSL_PARAM *params = NULL; + + /* Currently used for integrity */ + OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_KAT_MAC, t->desc); + + mac = EVP_MAC_fetch(libctx, t->algorithm, ""); + if (mac == NULL) + goto err; + + ctx = EVP_MAC_CTX_new(mac); + if (ctx == NULL) + goto err; + + params = kat_params_to_ossl_params(libctx, t->u.mac.params, NULL); + if (params == NULL) + goto err; + + if (t->expected.len > sizeof(out)) + goto err; + + if (!EVP_MAC_init(ctx, NULL, 0, params) + || !EVP_MAC_update(ctx, t->pt.buf, t->pt.len) + || !EVP_MAC_final(ctx, out, &out_len, EVP_MAX_MD_SIZE)) + goto err; + + OSSL_SELF_TEST_oncorrupt_byte(st, out); + + if ((out_len != t->expected.len) + || memcmp(out, t->expected.buf, t->expected.len) != 0) + goto err; + + ret = 1; +err: + EVP_MAC_free(mac); + EVP_MAC_CTX_free(ctx); + OSSL_PARAM_free(params); + OSSL_SELF_TEST_onend(st, ret); + return ret; +} + /* * Swap the library context DRBG for KAT testing * @@ -1065,7 +1114,7 @@ int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx, int do_deferred) for (i = 0; i < ST_ID_MAX; i++) { int res; - if (!do_deferred && (st_all_tests[i].deferred == SELF_TEST_DEFERRED)) + if (!do_deferred && (st_all_tests[i].deferred == SELF_TEST_DEFERRED) && (st_all_tests[i].state != SELF_TEST_STATE_PASSED)) continue; switch (st_all_tests[i].category) { @@ -1096,6 +1145,9 @@ int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx, int do_deferred) case SELF_TEST_KAT_ASYM_CIPHER: res = self_test_asym_cipher(&st_all_tests[i], st, libctx); break; + case SELF_TEST_KAT_MAC: + res = self_test_mac(&st_all_tests[i], st, libctx); + break; default: res = 0; break; @@ -1169,6 +1221,9 @@ int SELF_TEST_kats_single(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx, int id) case SELF_TEST_KAT_ASYM_CIPHER: ret = self_test_asym_cipher(&st_all_tests[id], st, libctx); break; + case SELF_TEST_KAT_MAC: + ret = self_test_mac(&st_all_tests[id], st, libctx); + break; default: ret = 0; break;