Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 [1][2].

[1] https://lore.kernel.org/r/3226361.1758126043@warthog.procyon.org.uk/
[2] https://lore.kernel.org/r/f31dbb22-0add-481c-aee0-e337a7731f8e@oracle.com/

Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20251011001047.51886-1-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>

+128 -6
+38
lib/crypto/fips.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* This file was generated by: gen-fips-testvecs.py */ 3 + 4 + #include <linux/fips.h> 5 + 6 + static const u8 fips_test_data[] __initconst __maybe_unused = { 7 + 0x66, 0x69, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73, 8 + 0x74, 0x20, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 9 + }; 10 + 11 + static const u8 fips_test_key[] __initconst __maybe_unused = { 12 + 0x66, 0x69, 0x70, 0x73, 0x20, 0x74, 0x65, 0x73, 13 + 0x74, 0x20, 0x6b, 0x65, 0x79, 0x00, 0x00, 0x00, 14 + }; 15 + 16 + static const u8 fips_test_hmac_sha1_value[] __initconst __maybe_unused = { 17 + 0x29, 0xa9, 0x88, 0xb8, 0x5c, 0xb4, 0xaf, 0x4b, 18 + 0x97, 0x2a, 0xee, 0x87, 0x5b, 0x0a, 0x02, 0x55, 19 + 0x99, 0xbf, 0x86, 0x78, 20 + }; 21 + 22 + static const u8 fips_test_hmac_sha256_value[] __initconst __maybe_unused = { 23 + 0x59, 0x25, 0x85, 0xcc, 0x40, 0xe9, 0x64, 0x2f, 24 + 0xe9, 0xbf, 0x82, 0xb7, 0xd3, 0x15, 0x3d, 0x43, 25 + 0x22, 0x0b, 0x4c, 0x00, 0x90, 0x14, 0x25, 0xcf, 26 + 0x9e, 0x13, 0x2b, 0xc2, 0x30, 0xe6, 0xe8, 0x93, 27 + }; 28 + 29 + static const u8 fips_test_hmac_sha512_value[] __initconst __maybe_unused = { 30 + 0x6b, 0xea, 0x5d, 0x27, 0x49, 0x5b, 0x3f, 0xea, 31 + 0xde, 0x2d, 0xfa, 0x32, 0x75, 0xdb, 0x77, 0xc8, 32 + 0x26, 0xe9, 0x4e, 0x95, 0x4d, 0xad, 0x88, 0x02, 33 + 0x87, 0xf9, 0x52, 0x0a, 0xd1, 0x92, 0x80, 0x1d, 34 + 0x92, 0x7e, 0x3c, 0xbd, 0xb1, 0x3c, 0x49, 0x98, 35 + 0x44, 0x9c, 0x8f, 0xee, 0x3f, 0x02, 0x71, 0x51, 36 + 0x57, 0x0b, 0x15, 0x38, 0x95, 0xd8, 0xa3, 0x81, 37 + 0xba, 0xb3, 0x15, 0x37, 0x5c, 0x6d, 0x57, 0x2b, 38 + };
+18 -1
lib/crypto/sha1.c
··· 12 12 #include <linux/string.h> 13 13 #include <linux/unaligned.h> 14 14 #include <linux/wordpart.h> 15 + #include "fips.h" 15 16 16 17 static const struct sha1_block_state sha1_iv = { 17 18 .h = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, ··· 331 330 } 332 331 EXPORT_SYMBOL_GPL(hmac_sha1_usingrawkey); 333 332 334 - #ifdef sha1_mod_init_arch 333 + #if defined(sha1_mod_init_arch) || defined(CONFIG_CRYPTO_FIPS) 335 334 static int __init sha1_mod_init(void) 336 335 { 336 + #ifdef sha1_mod_init_arch 337 337 sha1_mod_init_arch(); 338 + #endif 339 + if (fips_enabled) { 340 + /* 341 + * FIPS cryptographic algorithm self-test. As per the FIPS 342 + * Implementation Guidance, testing HMAC-SHA1 satisfies the test 343 + * requirement for SHA-1 too. 344 + */ 345 + u8 mac[SHA1_DIGEST_SIZE]; 346 + 347 + hmac_sha1_usingrawkey(fips_test_key, sizeof(fips_test_key), 348 + fips_test_data, sizeof(fips_test_data), 349 + mac); 350 + if (memcmp(fips_test_hmac_sha1_value, mac, sizeof(mac)) != 0) 351 + panic("sha1: FIPS self-test failed\n"); 352 + } 338 353 return 0; 339 354 } 340 355 subsys_initcall(sha1_mod_init);
+22 -4
lib/crypto/sha256.c
··· 17 17 #include <linux/string.h> 18 18 #include <linux/unaligned.h> 19 19 #include <linux/wordpart.h> 20 + #include "fips.h" 20 21 21 22 static const struct sha256_block_state sha224_iv = { 22 23 .h = { ··· 270 269 EXPORT_SYMBOL(sha256); 271 270 272 271 /* 273 - * Pre-boot environment (as indicated by __DISABLE_EXPORTS being defined) 274 - * doesn't need either HMAC support or interleaved hashing support 272 + * Pre-boot environments (as indicated by __DISABLE_EXPORTS being defined) just 273 + * need the generic SHA-256 code. Omit all other features from them. 275 274 */ 276 275 #ifndef __DISABLE_EXPORTS 277 276 ··· 478 477 hmac_sha256_final(&ctx, out); 479 478 } 480 479 EXPORT_SYMBOL_GPL(hmac_sha256_usingrawkey); 481 - #endif /* !__DISABLE_EXPORTS */ 482 480 483 - #ifdef sha256_mod_init_arch 481 + #if defined(sha256_mod_init_arch) || defined(CONFIG_CRYPTO_FIPS) 484 482 static int __init sha256_mod_init(void) 485 483 { 484 + #ifdef sha256_mod_init_arch 486 485 sha256_mod_init_arch(); 486 + #endif 487 + if (fips_enabled) { 488 + /* 489 + * FIPS cryptographic algorithm self-test. As per the FIPS 490 + * Implementation Guidance, testing HMAC-SHA256 satisfies the 491 + * test requirement for SHA-224, SHA-256, and HMAC-SHA224 too. 492 + */ 493 + u8 mac[SHA256_DIGEST_SIZE]; 494 + 495 + hmac_sha256_usingrawkey(fips_test_key, sizeof(fips_test_key), 496 + fips_test_data, sizeof(fips_test_data), 497 + mac); 498 + if (memcmp(fips_test_hmac_sha256_value, mac, sizeof(mac)) != 0) 499 + panic("sha256: FIPS self-test failed\n"); 500 + } 487 501 return 0; 488 502 } 489 503 subsys_initcall(sha256_mod_init); ··· 508 492 } 509 493 module_exit(sha256_mod_exit); 510 494 #endif 495 + 496 + #endif /* !__DISABLE_EXPORTS */ 511 497 512 498 MODULE_DESCRIPTION("SHA-224, SHA-256, HMAC-SHA224, and HMAC-SHA256 library functions"); 513 499 MODULE_LICENSE("GPL");
+18 -1
lib/crypto/sha512.c
··· 17 17 #include <linux/string.h> 18 18 #include <linux/unaligned.h> 19 19 #include <linux/wordpart.h> 20 + #include "fips.h" 20 21 21 22 static const struct sha512_block_state sha384_iv = { 22 23 .h = { ··· 406 405 } 407 406 EXPORT_SYMBOL_GPL(hmac_sha512_usingrawkey); 408 407 409 - #ifdef sha512_mod_init_arch 408 + #if defined(sha512_mod_init_arch) || defined(CONFIG_CRYPTO_FIPS) 410 409 static int __init sha512_mod_init(void) 411 410 { 411 + #ifdef sha512_mod_init_arch 412 412 sha512_mod_init_arch(); 413 + #endif 414 + if (fips_enabled) { 415 + /* 416 + * FIPS cryptographic algorithm self-test. As per the FIPS 417 + * Implementation Guidance, testing HMAC-SHA512 satisfies the 418 + * test requirement for SHA-384, SHA-512, and HMAC-SHA384 too. 419 + */ 420 + u8 mac[SHA512_DIGEST_SIZE]; 421 + 422 + hmac_sha512_usingrawkey(fips_test_key, sizeof(fips_test_key), 423 + fips_test_data, sizeof(fips_test_data), 424 + mac); 425 + if (memcmp(fips_test_hmac_sha512_value, mac, sizeof(mac)) != 0) 426 + panic("sha512: FIPS self-test failed\n"); 427 + } 413 428 return 0; 414 429 } 415 430 subsys_initcall(sha512_mod_init);
+32
scripts/crypto/gen-fips-testvecs.py
··· 1 + #!/usr/bin/env python3 2 + # SPDX-License-Identifier: GPL-2.0-or-later 3 + # 4 + # Script that generates lib/crypto/fips.h 5 + # 6 + # Copyright 2025 Google LLC 7 + 8 + import hmac 9 + 10 + fips_test_data = b"fips test data\0\0" 11 + fips_test_key = b"fips test key\0\0\0" 12 + 13 + def print_static_u8_array_definition(name, value): 14 + print('') 15 + print(f'static const u8 {name}[] __initconst __maybe_unused = {{') 16 + for i in range(0, len(value), 8): 17 + line = '\t' + ''.join(f'0x{b:02x}, ' for b in value[i:i+8]) 18 + print(f'{line.rstrip()}') 19 + print('};') 20 + 21 + print('/* SPDX-License-Identifier: GPL-2.0-or-later */') 22 + print(f'/* This file was generated by: gen-fips-testvecs.py */') 23 + print() 24 + print('#include <linux/fips.h>') 25 + 26 + print_static_u8_array_definition("fips_test_data", fips_test_data) 27 + print_static_u8_array_definition("fips_test_key", fips_test_key) 28 + 29 + for alg in 'sha1', 'sha256', 'sha512': 30 + ctx = hmac.new(fips_test_key, digestmod=alg) 31 + ctx.update(fips_test_data) 32 + print_static_u8_array_definition(f'fips_test_hmac_{alg}_value', ctx.digest())