lib/crypto: Add FIPS self-tests for SHA-1 and SHA-2
Subsystems (2)
Eric Biggers
maintainerPATCH v2 1/1 lib/crypto: Add FIPS self-tests for SHA-1 and SHA-2
Add FIPS cryptographic algorithm self-tests for all SHA-1 and SHA-2 algorithms. Following the "Implementation Guidance for FIPS 140-3" document, to achieve this it's sufficient to just test a single test vector for each of HMAC-SHA1, HMAC-SHA256, and HMAC-SHA512.
Just run these tests in the initcalls, following the example of e.g. crypto/kdf_sp800108.c. Note that this should meet the FIPS self-test requirement even in the built-in case, given that the initcalls run before userspace, storage, network, etc. are accessible.
This does not fix a regression, seeing as lib/ has had SHA-1 support since 2005 and SHA-256 support since 2018. Neither ever had FIPS self-tests. Moreover, fips=1 support has always been an unfinished feature upstream. However, with lib/ now being used more widely, it's now seeing more scrutiny and people seem to want these now.
---
Changed in v2:
- Call them "cryptographic algorithm self-tests" instead of "pre-operational self-tests".
- Add more details to commit message.
- Fix purgatory build error by omitting the tests from there.
lib/crypto/fips.h | 38 +++++++++++++++++++++++++++++ lib/crypto/sha1.c | 19 ++++++++++++++- lib/crypto/sha256.c | 26 +++++++++++++++++--- lib/crypto/sha512.c | 19 ++++++++++++++- scripts/crypto/gen-fips-testvecs.py | 32 ++++++++++++++++++++++++ 5 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 lib/crypto/fips.h create mode 100755 scripts/crypto/gen-fips-testvecs.py
lib/crypto/fips.h new file +38 -0
@@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* This file was generated by: gen-fips-testvecs.py */ + +#include <linux/fips.h> + +static const u8 fips_test_data[]__initconst __maybe_unused = { +0x66 ,0x69 ,0x70 ,0x73 ,0x20 ,0x74 ,0x65 ,0x73 , +0x74 ,0x20 ,0x64 ,0x61 ,0x74 ,0x61 ,0x00 ,0x00 , +}; + +static const u8 fips_test_key[]__initconst __maybe_unused = { +0x66 ,0x69 ,0x70 ,0x73 ,0x20 ,0x74 ,0x65 ,0x73 , +0x74 ,0x20 ,0x6b ,0x65 ,0x79 ,0x00 ,0x00 ,0x00 , +}; + +static const u8 fips_test_hmac_sha1_value[]__initconst __maybe_unused = { +0x29 ,0xa9 ,0x88 ,0xb8 ,0x5c ,0xb4 ,0xaf ,0x4b , +0x97 ,0x2a ,0xee ,0x87 ,0x5b ,0x0a ,0x02 ,0x55 , +0x99 ,0xbf ,0x86 ,0x78 , +}; + +static const u8 fips_test_hmac_sha256_value[]__initconst __maybe_unused = { +0x59 ,0x25 ,0x85 ,0xcc ,0x40 ,0xe9 ,0x64 ,0x2f , +0xe9 ,0xbf ,0x82 ,0xb7 ,0xd3 ,0x15 ,0x3d ,0x43 , +0x22 ,0x0b ,0x4c ,0x00 ,0x90 ,0x14 ,0x25 ,0xcf , +0x9e ,0x13 ,0x2b ,0xc2 ,0x30 ,0xe6 ,0xe8 ,0x93 , +}; + +static const u8 fips_test_hmac_sha512_value[]__initconst __maybe_unused = { +0x6b ,0xea ,0x5d ,0x27 ,0x49 ,0x5b ,0x3f ,0xea , +0xde ,0x2d ,0xfa ,0x32 ,0x75 ,0xdb ,0x77 ,0xc8 , +0x26 ,0xe9 ,0x4e ,0x95 ,0x4d ,0xad ,0x88 ,0x02 , +0x87 ,0xf9 ,0x52 ,0x0a ,0xd1 ,0x92 ,0x80 ,0x1d , +0x92 ,0x7e ,0x3c ,0xbd ,0xb1 ,0x3c ,0x49 ,0x98 , +0x44 ,0x9c ,0x8f ,0xee ,0x3f ,0x02 ,0x71 ,0x51 , +0x57 ,0x0b ,0x15 ,0x38 ,0x95 ,0xd8 ,0xa3 ,0x81 , +0xba ,0xb3 ,0x15 ,0x37 ,0x5c ,0x6d ,0x57 ,0x2b , +};
lib/crypto/sha1.c +18 -1
@@ -10,10 +10,11 @@#include <linux/kernel.h> #include <linux/module.h> #include <linux/string.h> #include <linux/unaligned.h> #include <linux/wordpart.h> +#include "fips.h" static const struct sha1_block_state sha1_iv = { .h = {SHA1_H0 ,SHA1_H1 ,SHA1_H2 ,SHA1_H3 ,SHA1_H4 }, };
@@ -328,14 +329,30 @@ void hmac_sha1_usingrawkey(const u8 *raw_key, size_t raw_key_len,hmac_sha1_update (&ctx, data, data_len);hmac_sha1_final (&ctx, out); }EXPORT_SYMBOL_GPL (hmac_sha1_usingrawkey); -#ifdef sha1_mod_init_arch +#if defined(sha1_mod_init_arch) || defined(CONFIG_CRYPTO_FIPS )static int __init sha1_mod_init (void ) { +#ifdef sha1_mod_init_archsha1_mod_init_arch (); +#endif +if (fips_enabled) { +/* +* FIPS cryptographic algorithm self-test. As per the FIPS +* Implementation Guidance, testing HMAC-SHA1 satisfies the test +* requirement for SHA-1 too. +*/ +u8 mac[SHA1_DIGEST_SIZE ]; + +hmac_sha1_usingrawkey (fips_test_key,sizeof (fips_test_key), + fips_test_data,sizeof (fips_test_data), + mac); +if (memcmp (fips_test_hmac_sha1_value, mac,sizeof (mac)) !=0 ) +panic ("sha1: FIPS self-test failed\n" ); + }return 0 ; }subsys_initcall (sha1_mod_init); static void __exit sha1_mod_exit(void)
lib/crypto/sha256.c +22 -4
@@ -15,10 +15,11 @@#include <linux/kernel.h> #include <linux/module.h> #include <linux/string.h> #include <linux/unaligned.h> #include <linux/wordpart.h> +#include "fips.h" static const struct sha256_block_state sha224_iv = { .h = {SHA224_H0 ,SHA224_H1 ,SHA224_H2 ,SHA224_H3 ,SHA224_H4 ,SHA224_H5 ,SHA224_H6 ,SHA224_H7 ,
@@ -267,12 +268,12 @@ void sha256(const u8 *data, size_t len, u8 out[SHA256_DIGEST_SIZE])sha256_final (&ctx, out); }EXPORT_SYMBOL (sha256);/* -* Pre-boot environment (as indicated by __DISABLE_EXPORTS being defined) -* doesn't need either HMAC support or interleaved hashing support +* Pre-boot environments (as indicated by __DISABLE_EXPORTS being defined) just +* need the generic SHA-256 code. Omit all other features from them. */ #ifndef __DISABLE_EXPORTS#ifndef sha256_finup_2x_arch static bool sha256_finup_2x_arch(const struct __sha256_ctx *ctx,
@@ -475,23 +476,40 @@ void hmac_sha256_usingrawkey(const u8 *raw_key, size_t raw_key_len,hmac_sha256_init_usingrawkey (&ctx, raw_key, raw_key_len);hmac_sha256_update (&ctx, data, data_len);hmac_sha256_final (&ctx, out); }EXPORT_SYMBOL_GPL (hmac_sha256_usingrawkey); -#endif /* !__DISABLE_EXPORTS */ -#ifdef sha256_mod_init_arch +#if defined(sha256_mod_init_arch) || defined(CONFIG_CRYPTO_FIPS )static int __init sha256_mod_init (void ) { +#ifdef sha256_mod_init_archsha256_mod_init_arch (); +#endif +if (fips_enabled) { +/* +* FIPS cryptographic algorithm self-test. As per the FIPS +* Implementation Guidance, testing HMAC-SHA256 satisfies the +* test requirement for SHA-224, SHA-256, and HMAC-SHA224 too. +*/ +u8 mac[SHA256_DIGEST_SIZE ]; + +hmac_sha256_usingrawkey (fips_test_key,sizeof (fips_test_key), + fips_test_data,sizeof (fips_test_data), + mac); +if (memcmp (fips_test_hmac_sha256_value, mac,sizeof (mac)) !=0 ) +panic ("sha256: FIPS self-test failed\n" ); + }return 0 ; }subsys_initcall (sha256_mod_init); static void __exit sha256_mod_exit(void) { }module_exit (sha256_mod_exit);#endif +#endif /* !__DISABLE_EXPORTS */ +MODULE_DESCRIPTION ("SHA-224, SHA-256, HMAC-SHA224, and HMAC-SHA256 library functions" );MODULE_LICENSE ("GPL" );
lib/crypto/sha512.c +18 -1
@@ -15,10 +15,11 @@#include <linux/module.h> #include <linux/overflow.h> #include <linux/string.h> #include <linux/unaligned.h> #include <linux/wordpart.h> +#include "fips.h" static const struct sha512_block_state sha384_iv = { .h = {SHA384_H0 ,SHA384_H1 ,SHA384_H2 ,SHA384_H3 ,SHA384_H4 ,SHA384_H5 ,SHA384_H6 ,SHA384_H7 ,
@@ -403,14 +404,30 @@ void hmac_sha512_usingrawkey(const u8 *raw_key, size_t raw_key_len,hmac_sha512_update (&ctx, data, data_len);hmac_sha512_final (&ctx, out); }EXPORT_SYMBOL_GPL (hmac_sha512_usingrawkey); -#ifdef sha512_mod_init_arch +#if defined(sha512_mod_init_arch) || defined(CONFIG_CRYPTO_FIPS )static int __init sha512_mod_init (void ) { +#ifdef sha512_mod_init_archsha512_mod_init_arch (); +#endif +if (fips_enabled) { +/* +* FIPS cryptographic algorithm self-test. As per the FIPS +* Implementation Guidance, testing HMAC-SHA512 satisfies the +* test requirement for SHA-384, SHA-512, and HMAC-SHA384 too. +*/ +u8 mac[SHA512_DIGEST_SIZE ]; + +hmac_sha512_usingrawkey (fips_test_key,sizeof (fips_test_key), + fips_test_data,sizeof (fips_test_data), + mac); +if (memcmp (fips_test_hmac_sha512_value, mac,sizeof (mac)) !=0 ) +panic ("sha512: FIPS self-test failed\n" ); + }return 0 ; }subsys_initcall (sha512_mod_init); static void __exit sha512_mod_exit(void)
scripts/crypto/gen-fips-testvecs.py new file +32 -0
@@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Script that generates lib/crypto/fips.h +# +# Copyright 2025 Google LLC + +import hmac + +fips_test_data = b"fips test data\0\0" +fips_test_key = b"fips test key\0\0\0" + +def print_static_u8_array_definition(name, value): + print('') + print(f'static const u8 {name}[] __initconst __maybe_unused = {{') + for i in range(0, len(value), 8): + line = '\t' + ''.join(f'0x{b:02x}, ' for b in value[i:i+8]) + print(f'{line.rstrip()}') + print('};') + +print('/* SPDX-License-Identifier: GPL-2.0-or-later */') +print(f'/* This file was generated by: gen-fips-testvecs.py */') +print() +print('#include <linux/fips.h>') + +print_static_u8_array_definition("fips_test_data", fips_test_data) +print_static_u8_array_definition("fips_test_key", fips_test_key) + +for alg in 'sha1', 'sha256', 'sha512': + ctx = hmac.new(fips_test_key, digestmod=alg) + ctx.update(fips_test_data) + print_static_u8_array_definition(f'fips_test_hmac_{alg}_value', ctx.digest())
base-commit: 8bd9238e511d02831022ff0270865c54ccc482d6
Signature · 1 line
2.51.0
Quoted 11 lines · Eric Biggers
Add FIPS cryptographic algorithm self-tests for all SHA-1 and SHA-2 algorithms. Following the "Implementation Guidance for FIPS 140-3" document, to achieve this it's sufficient to just test a single test vector for each of HMAC-SHA1, HMAC-SHA256, and HMAC-SHA512.
Just run these tests in the initcalls, following the example of e.g.
crypto/kdf_sp800108.c. Note that this should meet the FIPS self-test requirement even in the built-in case, given that the initcalls run before userspace, storage, network, etc. are accessible.
Quoted 8 lines
This does not fix a regression, seeing as
lib/has had SHA-1 support since 2005 and SHA-256 support since 2018. Neither ever had FIPS self-tests. Moreover, fips=1 support has always been an unfinished feature upstream. However, withlib/now being used more widely, it's now seeing more scrutiny and people seem to want these now.
Quoted 10 lines · Eric Biggers
Add FIPS cryptographic algorithm self-tests for all SHA-1 and SHA-2 algorithms. Following the "Implementation Guidance for FIPS 140-3" document, to achieve this it's sufficient to just test a single test vector for each of HMAC-SHA1, HMAC-SHA256, and HMAC-SHA512.
Just run these tests in the initcalls, following the example of e.g.
crypto/kdf_sp800108.c. Note that this should meet the FIPS self-test requirement even in the built-in case, given that the initcalls run before userspace, storage, network, etc. are accessible.
Quoted 8 lines
This does not fix a regression, seeing as
lib/has had SHA-1 support since 2005 and SHA-256 support since 2018. Neither ever had FIPS self-tests. Moreover, fips=1 support has always been an unfinished feature upstream. However, withlib/now being used more widely, it's now seeing more scrutiny and people seem to want these now.
Applied to https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/log/?h=libcrypto-next
- Eric