]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
FIPS: Add HMAC key size compliance check to the MAC legacy bridge.
authorslontis <shane.lontis@oracle.com>
Tue, 24 Feb 2026 03:29:26 +0000 (14:29 +1100)
committerNikola Pajkovsky <nikolap@openssl.org>
Tue, 28 Apr 2026 07:13:23 +0000 (07:13 +0000)
The hmac fips provider implementation used by the EVP_MAC API handles key
size checks, but it only does the test for the internal case.
Previously HMAC was implemented using EVP_DigestSign related functions,
and these are implemented using a mac_legacy_sig bridge, because of this
the MAC is external. For external cases the caller is responsible for
doing any key checks, so a FIPS indicator has been added.

Reported-by: https://github.com/taha2samy
Fixes: #30012
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
MergeDate: Tue Apr 28 07:13:24 2026
(Merged from https://github.com/openssl/openssl/pull/30150)

.gitignore
build.info
providers/implementations/signature/mac_legacy_sig.c
providers/implementations/signature/mac_legacy_sig.inc.in [new file with mode: 0644]
test/recipes/20-test_mac.t

index a7d7b19e30d216c883b0a68b85cf0453eeac7a4a..53e3e7ad4ae1b7ebe08260c109edb0fda41969a4 100644 (file)
@@ -139,6 +139,7 @@ providers/implementations/keymgmt/mlx_kmgmt.inc
 providers/implementations/keymgmt/slh_dsa_kmgmt.inc
 providers/implementations/keymgmt/template_kmgmt.inc
 providers/implementations/signature/eddsa_sig.inc
+providers/implementations/signature/mac_legacy_sig.inc
 providers/implementations/signature/ml_dsa_sig.inc
 providers/implementations/signature/rsa_sig.inc
 providers/implementations/signature/slh_dsa_sig.inc
index de909255e18d8593f3dd54d628299c6717b966b8..d7982a95536c391260e11ba0cb1e2c6f762a693f 100644 (file)
@@ -92,6 +92,7 @@ DEPEND[]=include/openssl/asn1.h \
          providers/implementations/signature/dsa_sig.inc \
          providers/implementations/signature/ecdsa_sig.inc \
          providers/implementations/signature/eddsa_sig.inc \
+         providers/implementations/signature/mac_legacy_sig.inc \
          providers/implementations/signature/ml_dsa_sig.inc \
          providers/implementations/signature/rsa_sig.inc \
          providers/implementations/signature/slh_dsa_sig.inc \
@@ -216,6 +217,7 @@ DEPEND[providers/implementations/asymciphers/rsa_enc.inc \
        providers/implementations/signature/dsa_sig.inc \
        providers/implementations/signature/ecdsa_sig.inc \
        providers/implementations/signature/eddsa_sig.inc \
+       providers/implementations/signature/mac_legacy_sig.inc \
        providers/implementations/signature/ml_dsa_sig.inc \
        providers/implementations/signature/rsa_sig.inc \
        providers/implementations/signature/slh_dsa_sig.inc \
@@ -356,6 +358,8 @@ GENERATE[providers/implementations/signature/ecdsa_sig.inc]=\
     providers/implementations/signature/ecdsa_sig.inc.in
 GENERATE[providers/implementations/signature/eddsa_sig.inc]=\
     providers/implementations/signature/eddsa_sig.inc.in
+GENERATE[providers/implementations/signature/mac_legacy_sig.inc]=\
+    providers/implementations/signature/mac_legacy_sig.inc.in
 GENERATE[providers/implementations/signature/ml_dsa_sig.inc]=\
     providers/implementations/signature/ml_dsa_sig.inc.in
 GENERATE[providers/implementations/signature/rsa_sig.inc]=\
index 2630715089ca84128e4c3ef38e831fc057317d8e..cf2eff267d64865d17ae113e15a39ad9b8f272f3 100644 (file)
@@ -7,6 +7,7 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <stdbool.h>
 #include <openssl/crypto.h>
 #include <openssl/evp.h>
 #include <openssl/core_dispatch.h>
 #include "prov/provider_ctx.h"
 #include "prov/macsignature.h"
 #include "prov/providercommon.h"
+#include "prov/securitycheck.h"
+#include "internal/fips.h"
+#include "internal/common.h"
+
+#ifndef FIPS_MODULE
+#define mac_legacy_get_ctx_params_decoder
+#define mac_legacy_set_ctx_params_decoder
+#endif
+#include "providers/implementations/signature/mac_legacy_sig.inc"
 
 static OSSL_FUNC_signature_newctx_fn mac_hmac_newctx;
 static OSSL_FUNC_signature_newctx_fn mac_siphash_newctx;
@@ -39,6 +49,10 @@ typedef struct {
     char *propq;
     MAC_KEY *key;
     EVP_MAC_CTX *macctx;
+#ifdef FIPS_MODULE
+    bool hmac_keysize_check;
+    OSSL_FIPS_IND_DECLARE
+#endif
 } PROV_MAC_CTX;
 
 static void *mac_newctx(void *provctx, const char *propq, const char *macname)
@@ -66,7 +80,11 @@ static void *mac_newctx(void *provctx, const char *propq, const char *macname)
         goto err;
 
     EVP_MAC_free(mac);
-
+#ifdef FIPS_MODULE
+    pmacctx->hmac_keysize_check = (strcmp(macname, "HMAC") == 0);
+    /* Set FIPS indicator to approved */
+    OSSL_FIPS_IND_INIT(pmacctx)
+#endif
     return pmacctx;
 
 err:
@@ -87,6 +105,27 @@ MAC_NEWCTX(siphash, "SIPHASH")
 MAC_NEWCTX(poly1305, "POLY1305")
 MAC_NEWCTX(cmac, "CMAC")
 
+#ifdef FIPS_MODULE
+/*
+ * The fips indicator check is done at this level because HMAC will be created
+ * as an 'internal' sub-algorithm which will not perform the tests in hmac_prov.c
+ */
+static int hmac_check_key(PROV_MAC_CTX *macctx, const unsigned char *key, size_t keylen)
+{
+    int approved = ossl_mac_check_key_size(keylen);
+
+    if (!approved) {
+        if (!OSSL_FIPS_IND_ON_UNAPPROVED(macctx, OSSL_FIPS_IND_SETTABLE0,
+                macctx->libctx, "HMAC", "keysize",
+                FIPS_CONFIG_HMAC_KEY_CHECK)) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+            return 0;
+        }
+    }
+    return 1;
+}
+#endif
+
 static int mac_digest_sign_init(void *vpmacctx, const char *mdname, void *vkey,
     const OSSL_PARAM params[])
 {
@@ -118,6 +157,11 @@ static int mac_digest_sign_init(void *vpmacctx, const char *mdname, void *vkey,
             pmacctx->key->properties, params))
         return 0;
 
+#ifdef FIPS_MODULE
+    if (pmacctx->hmac_keysize_check
+        && !hmac_check_key(pmacctx, pmacctx->key->priv_key, pmacctx->key->priv_key_len))
+        return 0;
+#endif
     if (!EVP_MAC_init(pmacctx->macctx, pmacctx->key->priv_key,
             pmacctx->key->priv_key_len, NULL))
         return 0;
@@ -197,6 +241,22 @@ static int mac_set_ctx_params(void *vpmacctx, const OSSL_PARAM params[])
 {
     PROV_MAC_CTX *ctx = (PROV_MAC_CTX *)vpmacctx;
 
+#ifdef FIPS_MODULE
+    if (ctx->hmac_keysize_check) {
+        struct mac_legacy_set_ctx_params_st p;
+
+        if (!mac_legacy_set_ctx_params_decoder(params, &p))
+            return 0;
+        if (!OSSL_FIPS_IND_SET_CTX_FROM_PARAM(ctx, OSSL_FIPS_IND_SETTABLE0, p.ind_k))
+            return 0;
+        if (p.key != NULL) {
+            if (p.key->data_type != OSSL_PARAM_OCTET_STRING)
+                return 0;
+            if (!hmac_check_key(ctx, p.key->data, p.key->data_size))
+                return 0;
+        }
+    }
+#endif
     return EVP_MAC_CTX_set_params(ctx->macctx, params);
 }
 
@@ -217,6 +277,33 @@ static const OSSL_PARAM *mac_settable_ctx_params(ossl_unused void *ctx,
     return params;
 }
 
+static const OSSL_PARAM *mac_gettable_ctx_params(ossl_unused void *vctx,
+    ossl_unused void *provctx)
+{
+    return mac_legacy_get_ctx_params_list;
+}
+
+static int mac_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+    PROV_MAC_CTX *ctx = vctx;
+
+    if (ctx == NULL)
+        return 0;
+
+#ifdef FIPS_MODULE
+    struct mac_legacy_get_ctx_params_st p;
+
+    if (!mac_legacy_get_ctx_params_decoder(params, &p))
+        return 0;
+    if (p.ind != NULL) {
+        int approved = OSSL_FIPS_IND_GET(ctx)->approved;
+        if (!OSSL_PARAM_set_int(p.ind, approved))
+            return 0;
+    }
+#endif
+    return 1;
+}
+
 #define MAC_SETTABLE_CTX_PARAMS(funcname, macname)                           \
     static const OSSL_PARAM *mac_##funcname##_settable_ctx_params(void *ctx, \
         void *provctx)                                                       \
@@ -244,6 +331,10 @@ MAC_SETTABLE_CTX_PARAMS(cmac, "CMAC")
             (void (*)(void))mac_set_ctx_params },                                \
         { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS,                               \
             (void (*)(void))mac_##funcname##_settable_ctx_params },              \
+        { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS,                                    \
+            (void (*)(void))mac_get_ctx_params },                                \
+        { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS,                               \
+            (void (*)(void))mac_gettable_ctx_params },                           \
         OSSL_DISPATCH_END                                                        \
     };
 
diff --git a/providers/implementations/signature/mac_legacy_sig.inc.in b/providers/implementations/signature/mac_legacy_sig.inc.in
new file mode 100644 (file)
index 0000000..36f98b2
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the \"License\").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+{-
+use OpenSSL::paramnames qw(produce_param_decoder);
+-}
+
+{- produce_param_decoder('mac_legacy_get_ctx_params',
+                         (['OSSL_ALG_PARAM_FIPS_APPROVED_INDICATOR', 'ind',    'int', 'fips'],
+                         )); -}
+
+{- produce_param_decoder('mac_legacy_set_ctx_params',
+                         (['OSSL_MAC_PARAM_KEY', 'key', 'octet_string'],
+                          ['OSSL_MAC_PARAM_FIPS_KEY_CHECK', 'ind_k',   'int', 'fips'],
+                         )); -}
index 35a4904188cc21113f9d46baeed71e83d2583fa4..84a88990491254cdb8077df6683106024766469e 100644 (file)
@@ -10,7 +10,7 @@
 use strict;
 use warnings;
 
-use OpenSSL::Test qw(:DEFAULT data_file);
+use OpenSSL::Test qw(:DEFAULT data_file srctop_file);
 use OpenSSL::Test::Utils;
 use Storable qw(dclone);
 
@@ -138,8 +138,9 @@ my @siphash_fail_tests = (
 
 push @mac_fail_tests, @siphash_fail_tests unless disabled("siphash");
 
-plan tests => (scalar @mac_tests * 2) + scalar @mac_fail_tests;
+plan tests => (scalar @mac_tests * 2) + (scalar @mac_fail_tests) + 2;
 
+my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0);
 my $test_count = 0;
 
 foreach (@mac_tests) {
@@ -174,6 +175,28 @@ foreach (@mac_fail_tests) {
     ok(compareline($_->{cmd}, $_->{type}, $_->{input}, $_->{expected}, $_->{err}), $_->{desc});
 }
 
+SKIP: {
+    skip "Skipping FIPS tests", 2
+        if $no_fips;
+
+    my $fipsconf = srctop_file("test", "fips-and-base.cnf");
+
+    # This is only valid after OpenSSL 4.1
+    run(test(["fips_version_test", "-config", $fipsconf, ">=4.1.0"]),
+             capture => 1, statusvar => \my $exit);
+    skip "FIPS provider version is too old for this test", 2
+        if !$exit;
+
+    $ENV{OPENSSL_CONF} = $fipsconf;
+    ok(!run(app(['openssl', 'dgst', '-provider', 'fips', '-sha256', '-hmac',
+                 '1234', srctop_file("test", "testec-p112r1.pem")])),
+        "Checking bad key size fails in FIPS provider");
+    ok(run(app(['openssl', 'dgst', '-provider', 'fips', '-sha256', '-hmac',
+                 '123456789ABCDE', srctop_file("test", "testec-p112r1.pem")])),
+        "Checking good key size passes in FIPS provider");
+    delete $ENV{OPENSSL_CONF};
+}
+
 # Create a temp input file and save the input data into it, and
 # then compare the stdout output matches the expected value.
 sub compareline {