Commit 53fecfc80b for openssl.org
commit 53fecfc80bfe8fbef5923f4e84255f07695eb92f
Author: Simo Sorce <simo@redhat.com>
Date: Tue Dec 9 14:29:43 2025 -0500
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 <simo@redhat.com>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(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 befc9ad3c4..1e799d4c67 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<OSSL_SELF_TEST_TYPE_KAT_INTEGRITY>)
+=item "KAT_Mac" (B<OSSL_SELF_TEST_TYPE_KAT_MAC>)
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<OSSL_SELF_TEST_TYPE_KAT_INTEGRITY> ("KAT_Integrity") was used for this.
=item "KAT_Cipher" (B<OSSL_SELF_TEST_TYPE_KAT_CIPHER>)
diff --git a/include/internal/fips.h b/include/internal/fips.h
index 67b5f7d151..c62865ebd9 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 c5e4be955e..f879370ae1 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 e9f88140a6..84e65bcf4a 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 44c47e669b..2083ce5226 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 c829e3d5af..73b3ebec29 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 1750c99609..59e0346162 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;