Add a FIPS cryptographic algorithm self-test for AES-CMAC to fulfill the self-test requirement when this code is built into a FIPS 140 cryptographic module. This provides parity with the traditional crypto API, which uses crypto/testmgr.c to meet the FIPS self-test requirement. Signed-off-by: Eric Biggers --- lib/crypto/aes.c | 35 ++++++++++++++++++++++++++--- lib/crypto/fips.h | 5 +++++ scripts/crypto/gen-fips-testvecs.py | 10 +++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/lib/crypto/aes.c b/lib/crypto/aes.c index 39deae6105c0..ca733f15b2a8 100644 --- a/lib/crypto/aes.c +++ b/lib/crypto/aes.c @@ -10,10 +10,11 @@ #include #include #include #include #include +#include "fips.h" static const u8 ____cacheline_aligned aes_sbox[] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, @@ -706,25 +707,53 @@ void aes_cbcmac_final(struct aes_cbcmac_ctx *ctx, u8 out[AES_BLOCK_SIZE]) else memcpy(out, ctx->h, AES_BLOCK_SIZE); memzero_explicit(ctx, sizeof(*ctx)); } EXPORT_SYMBOL_NS_GPL(aes_cbcmac_final, "CRYPTO_INTERNAL"); -#endif /* CONFIG_CRYPTO_LIB_AES_CBC_MACS */ -#ifdef aes_mod_init_arch +/* + * FIPS cryptographic algorithm self-test for AES-CMAC. As per the FIPS 140-3 + * Implementation Guidance, a cryptographic algorithm self-test for at least one + * of AES-GCM, AES-CCM, AES-CMAC, or AES-GMAC is required if any of those modes + * is implemented. This fulfills that requirement via AES-CMAC. + * + * This is just for FIPS. The full tests are in the KUnit test suite. + */ +static void __init aes_cmac_fips_test(void) +{ + struct aes_cmac_key key; + u8 mac[AES_BLOCK_SIZE]; + + if (aes_cmac_preparekey(&key, fips_test_key, sizeof(fips_test_key)) != + 0) + panic("aes: CMAC FIPS self-test failed (preparekey)\n"); + aes_cmac(&key, fips_test_data, sizeof(fips_test_data), mac); + if (memcmp(fips_test_aes_cmac_value, mac, sizeof(mac)) != 0) + panic("aes: CMAC FIPS self-test failed (wrong MAC)\n"); + memzero_explicit(&key, sizeof(key)); +} +#else /* CONFIG_CRYPTO_LIB_AES_CBC_MACS */ +static inline void aes_cmac_fips_test(void) +{ +} +#endif /* !CONFIG_CRYPTO_LIB_AES_CBC_MACS */ + static int __init aes_mod_init(void) { +#ifdef aes_mod_init_arch aes_mod_init_arch(); +#endif + if (fips_enabled) + aes_cmac_fips_test(); return 0; } subsys_initcall(aes_mod_init); static void __exit aes_mod_exit(void) { } module_exit(aes_mod_exit); -#endif MODULE_DESCRIPTION("AES block cipher"); MODULE_AUTHOR("Ard Biesheuvel "); MODULE_AUTHOR("Eric Biggers "); MODULE_LICENSE("GPL v2"); diff --git a/lib/crypto/fips.h b/lib/crypto/fips.h index 023410c2e0db..9fc49747db64 100644 --- a/lib/crypto/fips.h +++ b/lib/crypto/fips.h @@ -41,5 +41,10 @@ static const u8 fips_test_sha3_256_value[] __initconst __maybe_unused = { 0x77, 0xc4, 0x8b, 0x69, 0x70, 0x5f, 0x0a, 0xb1, 0xb1, 0xa5, 0x82, 0x0a, 0x22, 0x2b, 0x49, 0x31, 0xba, 0x9b, 0xb6, 0xaa, 0x32, 0xa7, 0x97, 0x00, 0x98, 0xdb, 0xff, 0xe7, 0xc6, 0xde, 0xb5, 0x82, }; + +static const u8 fips_test_aes_cmac_value[] __initconst __maybe_unused = { + 0xc5, 0x88, 0x28, 0x55, 0xd7, 0x2c, 0x00, 0xb6, + 0x6a, 0xa7, 0xfc, 0x82, 0x90, 0x81, 0xcf, 0x18, +}; diff --git a/scripts/crypto/gen-fips-testvecs.py b/scripts/crypto/gen-fips-testvecs.py index db873f88619a..9f18bcb97412 100755 --- a/scripts/crypto/gen-fips-testvecs.py +++ b/scripts/crypto/gen-fips-testvecs.py @@ -1,12 +1,16 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: GPL-2.0-or-later # # Script that generates lib/crypto/fips.h # +# Requires that python-cryptography be installed. +# # Copyright 2025 Google LLC +import cryptography.hazmat.primitives.ciphers +import cryptography.hazmat.primitives.cmac import hashlib import hmac fips_test_data = b"fips test data\0\0" fips_test_key = b"fips test key\0\0\0" @@ -32,5 +36,11 @@ for alg in 'sha1', 'sha256', 'sha512': ctx.update(fips_test_data) print_static_u8_array_definition(f'fips_test_hmac_{alg}_value', ctx.digest()) print_static_u8_array_definition(f'fips_test_sha3_256_value', hashlib.sha3_256(fips_test_data).digest()) + +aes = cryptography.hazmat.primitives.ciphers.algorithms.AES(fips_test_key) +aes_cmac = cryptography.hazmat.primitives.cmac.CMAC(aes) +aes_cmac.update(fips_test_data) +print_static_u8_array_definition('fips_test_aes_cmac_value', + aes_cmac.finalize()) -- 2.53.0