]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Refactor FIPS integrity check to use KAT framework
authorSimo Sorce <simo@redhat.com>
Tue, 9 Dec 2025 19:29:43 +0000 (14:29 -0500)
committerDmitry Belyavskiy <beldmit@gmail.com>
Fri, 13 Feb 2026 09:53:41 +0000 (10:53 +0100)
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)

doc/man7/OSSL_PROVIDER-FIPS.pod
include/internal/fips.h
include/openssl/self_test.h
providers/fips/self_test.c
providers/fips/self_test.h
providers/fips/self_test_data.c
providers/fips/self_test_kats.c

index befc9ad3c49d92bba3c483a6a4d1dd033cfdeb57..1e799d4c67cb12a661aeaef327b9d0e10116d0ca 100644 (file)
@@ -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>)
 
index 67b5f7d151fcf72e42670458c6175e71a993a81c..c62865ebd9b5c1014c43519c6ff3e9392ec27c63 100644 (file)
@@ -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;
 
index c5e4be955e79cca900aef5a5890729327cc9cad4..f879370ae122c9bd442670c73a547a08e75e6cff 100644 (file)
@@ -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"
index e9f88140a641ceab8bcb2f863aebf1cbb896afad..84e65bcf4aa9fc4f3e1dba2d829e105dc279015d 100644 (file)
@@ -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;
index 44c47e669b039f0b73c95977a84900999a2ddfde..2083ce5226c22b9a5afd2dc250d7e15f22383eb4 100644 (file)
@@ -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;
index c829e3d5afba032d7d59c4bf2deecbabb9262407..73b3ebec2931dda3515ae85f0870c4e947fdc61e 100644 (file)
@@ -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,
+        },
+    },
 };
index 1750c99609d5ae0fbbd4e0d0b7d3ac589eb5fb80..59e03461629b6cdb0b6de1e5935d1c9d9290c1a2 100644 (file)
@@ -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;