diff --git a/crypto/fips140-selftests.c b/crypto/fips140-selftests.c index 3ebf5a914cf0..6679e675fe03 100644 --- a/crypto/fips140-selftests.c +++ b/crypto/fips140-selftests.c @@ -14,10 +14,6 @@ * is somewhat helpful. Basically, all implementations of all FIPS approved * algorithms (including modes of operation) must be tested. However: * - * - If an implementation won't be used, it doesn't have to be tested. So - * when multiple implementations of the same algorithm are registered with - * the crypto API, we only have to test the default (highest-priority) one. - * * - There are provisions for skipping tests that are already sufficiently * covered by other tests. E.g., HMAC-SHA256 may cover SHA-256. * @@ -28,12 +24,15 @@ * * - Only one key size per algorithm needs to be tested. * + * There is some ambiguity about whether all implementations of each algorithm + * must be tested, or whether it is sufficient to test just the highest priority + * implementation. To be safe we test all implementations, except ones that can + * be excluded by one of the rules above. + * * See fips140_selftests[] for the list of tests we've selected. Currently, all * our test vectors except the DRBG ones were generated by the script * tools/crypto/gen_fips140_testvecs.py, using the known-good implementations in - * the Python packages hashlib, pycryptodome, and cryptography. The DRBG test - * vectors were manually extracted from - * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/drbg/drbgtestvectors.zip. + * the Python packages hashlib, pycryptodome, and cryptography. * * Note that we don't reuse the upstream crypto API's self-tests * (crypto/testmgr.{c,h}), for several reasons: @@ -54,22 +53,12 @@ #include #include #include -#include #include #include #include #include "fips140-module.h" -/* Test vector for a block cipher algorithm */ -struct blockcipher_testvec { - const u8 *key; - size_t key_size; - const u8 *plaintext; - const u8 *ciphertext; - size_t block_size; -}; - /* Test vector for an AEAD algorithm */ struct aead_testvec { const u8 *key; @@ -121,15 +110,27 @@ struct drbg_testvec { size_t out_size; }; -/* - * A struct which specifies an algorithm name (using crypto API syntax), a test - * function for that algorithm, and a test vector used by that test function. - */ struct fips_test { + /* The name of the algorithm, in crypto API syntax */ const char *alg; - int __must_check (*func)(const struct fips_test *test); + + /* + * The optional list of implementations to test. @func will be called + * once per implementation, or once with @alg if this list is empty. + * The implementation names must be given in crypto API syntax, or in + * the case of a library implementation should have "-lib" appended. + */ + const char *impls[8]; + + /* + * The test function. It should execute a known-answer test on an + * algorithm implementation, using the below test vector. + */ + int __must_check (*func)(const struct fips_test *test, + const char *impl); + + /* The test vector, with a format specific to the type of algorithm */ union { - struct blockcipher_testvec blockcipher; struct aead_testvec aead; struct skcipher_testvec skcipher; struct hash_testvec hash; @@ -141,17 +142,16 @@ struct fips_test { #define MAX_IV_SIZE 16 static int __init __must_check -fips_check_result(const struct fips_test *test, u8 *result, - const u8 *expected_result, size_t result_size, - const char *operation) +fips_check_result(u8 *result, const u8 *expected_result, size_t result_size, + const char *impl, const char *operation) { #ifdef CONFIG_CRYPTO_FIPS140_MOD_ERROR_INJECTION /* Inject a failure (via corrupting the result) if requested. */ - if (fips140_broken_alg && strcmp(test->alg, fips140_broken_alg) == 0) + if (fips140_broken_alg && strcmp(impl, fips140_broken_alg) == 0) result[0] ^= 0xff; #endif if (memcmp(result, expected_result, result_size) != 0) { - pr_err("wrong result from %s %s\n", test->alg, operation); + pr_err("wrong result from %s %s\n", impl, operation); return -EBADMSG; } return 0; @@ -176,96 +176,65 @@ fips_validate_alg(const struct crypto_alg *alg) return 0; } -/* Test a block cipher using the crypto_cipher API. */ static int __init __must_check -fips_test_blockcipher(const struct fips_test *test) +fips_handle_alloc_tfm_error(const char *impl, int err) { - const struct blockcipher_testvec *vec = &test->blockcipher; - struct crypto_cipher *tfm; - u8 block[MAX_CIPHER_BLOCKSIZE]; - int err; + if (err == -ENOENT) { + /* + * The requested implementation of the algorithm wasn't found. + * This is expected if the CPU lacks a feature the + * implementation needs, such as the ARMv8 Crypto Extensions. + * + * When this happens, the implementation isn't available for + * use, so we can't test it, nor do we need to. So we just skip + * the test. + */ - if (WARN_ON(vec->block_size > MAX_CIPHER_BLOCKSIZE)) - return -EINVAL; + /* + * "ghash-neon" is a bit unusual in that it is only registered + * if the CPU does *not* have a feature. Skip it silently in + * order to avoid a confusing log message. + */ + if (!strcmp(impl, "gcm_base(ctr(aes-generic),ghash-neon)")) + return 0; - tfm = crypto_alloc_cipher(test->alg, 0, 0); - if (IS_ERR(tfm)) { - err = PTR_ERR(tfm); - pr_err("failed to allocate %s tfm: %d\n", test->alg, err); - return err; + pr_info("%s is unavailable (no CPU support?), skipping testing it\n", + impl); + return 0; } - err = fips_validate_alg(tfm->base.__crt_alg); - if (err) - goto out; - if (crypto_cipher_blocksize(tfm) != vec->block_size) { - pr_err("%s has wrong block size\n", test->alg); - err = -EINVAL; - goto out; - } - - err = crypto_cipher_setkey(tfm, vec->key, vec->key_size); - if (err) { - pr_err("failed to set %s key: %d\n", test->alg, err); - goto out; - } - - /* Encrypt the plaintext, then verify the resulting ciphertext. */ - memcpy(block, vec->plaintext, vec->block_size); - crypto_cipher_encrypt_one(tfm, block, block); - err = fips_check_result(test, block, vec->ciphertext, vec->block_size, - "encryption"); - if (err) - goto out; - - /* Decrypt the ciphertext, then verify the resulting plaintext. */ - crypto_cipher_decrypt_one(tfm, block, block); - err = fips_check_result(test, block, vec->plaintext, vec->block_size, - "decryption"); -out: - crypto_free_cipher(tfm); + pr_err("failed to allocate %s tfm: %d\n", impl, err); return err; } -/* - * Test for plain AES (no mode of operation). We test this separately from the - * AES modes because the implementation of AES which is used by the "aes" - * crypto_cipher isn't necessarily the same as that used by the AES modes such - * as "ecb(aes)". Similarly, the aes_{encrypt,decrypt}() library functions may - * use a different implementation as well, so we test them separately too. - */ static int __init __must_check -fips_test_aes(const struct fips_test *test) +fips_test_aes_library(const struct fips_test *test, const char *impl) { - const struct blockcipher_testvec *vec = &test->blockcipher; + const struct skcipher_testvec *vec = &test->skcipher; struct crypto_aes_ctx ctx; u8 block[AES_BLOCK_SIZE]; int err; - if (WARN_ON(vec->block_size != AES_BLOCK_SIZE)) + if (WARN_ON(vec->message_size != AES_BLOCK_SIZE)) return -EINVAL; - err = fips_test_blockcipher(test); - if (err) - return err; - err = aes_expandkey(&ctx, vec->key, vec->key_size); if (err) { pr_err("aes_expandkey() failed: %d\n", err); return err; } aes_encrypt(&ctx, block, vec->plaintext); - err = fips_check_result(test, block, vec->ciphertext, AES_BLOCK_SIZE, - "encryption (library API)"); + err = fips_check_result(block, vec->ciphertext, AES_BLOCK_SIZE, + impl, "encryption"); if (err) return err; aes_decrypt(&ctx, block, block); - return fips_check_result(test, block, vec->plaintext, AES_BLOCK_SIZE, - "decryption (library API)"); + return fips_check_result(block, vec->plaintext, AES_BLOCK_SIZE, + impl, "decryption"); } /* Test a length-preserving symmetric cipher using the crypto_skcipher API. */ static int __init __must_check -fips_test_skcipher(const struct fips_test *test) +fips_test_skcipher(const struct fips_test *test, const char *impl) { const struct skcipher_testvec *vec = &test->skcipher; struct crypto_skcipher *tfm; @@ -277,18 +246,17 @@ fips_test_skcipher(const struct fips_test *test) if (WARN_ON(vec->iv_size > MAX_IV_SIZE)) return -EINVAL; + if (WARN_ON(vec->message_size <= 0)) + return -EINVAL; - tfm = crypto_alloc_skcipher(test->alg, 0, 0); - if (IS_ERR(tfm)) { - err = PTR_ERR(tfm); - pr_err("failed to allocate %s tfm: %d\n", test->alg, err); - return err; - } + tfm = crypto_alloc_skcipher(impl, 0, 0); + if (IS_ERR(tfm)) + return fips_handle_alloc_tfm_error(impl, PTR_ERR(tfm)); err = fips_validate_alg(&crypto_skcipher_alg(tfm)->base); if (err) goto out; if (crypto_skcipher_ivsize(tfm) != vec->iv_size) { - pr_err("%s has wrong IV size\n", test->alg); + pr_err("%s has wrong IV size\n", impl); err = -EINVAL; goto out; } @@ -307,7 +275,7 @@ fips_test_skcipher(const struct fips_test *test) err = crypto_skcipher_setkey(tfm, vec->key, vec->key_size); if (err) { - pr_err("failed to set %s key: %d\n", test->alg, err); + pr_err("failed to set %s key: %d\n", impl, err); goto out; } @@ -315,11 +283,11 @@ fips_test_skcipher(const struct fips_test *test) memcpy(iv, vec->iv, vec->iv_size); err = crypto_skcipher_encrypt(req); if (err) { - pr_err("%s encryption failed: %d\n", test->alg, err); + pr_err("%s encryption failed: %d\n", impl, err); goto out; } - err = fips_check_result(test, message, vec->ciphertext, - vec->message_size, "encryption"); + err = fips_check_result(message, vec->ciphertext, vec->message_size, + impl, "encryption"); if (err) goto out; @@ -327,11 +295,11 @@ fips_test_skcipher(const struct fips_test *test) memcpy(iv, vec->iv, vec->iv_size); err = crypto_skcipher_decrypt(req); if (err) { - pr_err("%s decryption failed: %d\n", test->alg, err); + pr_err("%s decryption failed: %d\n", impl, err); goto out; } - err = fips_check_result(test, message, vec->plaintext, - vec->message_size, "decryption"); + err = fips_check_result(message, vec->plaintext, vec->message_size, + impl, "decryption"); out: kfree(message); skcipher_request_free(req); @@ -341,7 +309,7 @@ out: /* Test an AEAD using the crypto_aead API. */ static int __init __must_check -fips_test_aead(const struct fips_test *test) +fips_test_aead(const struct fips_test *test, const char *impl) { const struct aead_testvec *vec = &test->aead; const int tag_size = vec->ciphertext_size - vec->plaintext_size; @@ -359,17 +327,14 @@ fips_test_aead(const struct fips_test *test) if (WARN_ON(vec->ciphertext_size <= vec->plaintext_size)) return -EINVAL; - tfm = crypto_alloc_aead(test->alg, 0, 0); - if (IS_ERR(tfm)) { - err = PTR_ERR(tfm); - pr_err("failed to allocate %s tfm: %d\n", test->alg, err); - return err; - } + tfm = crypto_alloc_aead(impl, 0, 0); + if (IS_ERR(tfm)) + return fips_handle_alloc_tfm_error(impl, PTR_ERR(tfm)); err = fips_validate_alg(&crypto_aead_alg(tfm)->base); if (err) goto out; if (crypto_aead_ivsize(tfm) != vec->iv_size) { - pr_err("%s has wrong IV size\n", test->alg); + pr_err("%s has wrong IV size\n", impl); err = -EINVAL; goto out; } @@ -393,14 +358,14 @@ fips_test_aead(const struct fips_test *test) err = crypto_aead_setkey(tfm, vec->key, vec->key_size); if (err) { - pr_err("failed to set %s key: %d\n", test->alg, err); + pr_err("failed to set %s key: %d\n", impl, err); goto out; } err = crypto_aead_setauthsize(tfm, tag_size); if (err) { pr_err("failed to set %s authentication tag size: %d\n", - test->alg, err); + impl, err); goto out; } @@ -412,11 +377,11 @@ fips_test_aead(const struct fips_test *test) aead_request_set_crypt(req, sg, sg, vec->plaintext_size, iv); err = crypto_aead_encrypt(req); if (err) { - pr_err("%s encryption failed: %d\n", test->alg, err); + pr_err("%s encryption failed: %d\n", impl, err); goto out; } - err = fips_check_result(test, message, vec->ciphertext, - vec->ciphertext_size, "encryption"); + err = fips_check_result(message, vec->ciphertext, vec->ciphertext_size, + impl, "encryption"); if (err) goto out; @@ -428,11 +393,11 @@ fips_test_aead(const struct fips_test *test) aead_request_set_crypt(req, sg, sg, vec->ciphertext_size, iv); err = crypto_aead_decrypt(req); if (err) { - pr_err("%s decryption failed: %d\n", test->alg, err); + pr_err("%s decryption failed: %d\n", impl, err); goto out; } - err = fips_check_result(test, message, vec->plaintext, - vec->plaintext_size, "decryption"); + err = fips_check_result(message, vec->plaintext, vec->plaintext_size, + impl, "decryption"); out: kfree(message); kfree(assoc); @@ -449,7 +414,7 @@ out: * be no hash algorithms that can be accessed only through crypto_ahash. */ static int __init __must_check -fips_test_hash(const struct fips_test *test) +fips_test_hash(const struct fips_test *test, const char *impl) { const struct hash_testvec *vec = &test->hash; struct crypto_shash *tfm; @@ -459,17 +424,14 @@ fips_test_hash(const struct fips_test *test) if (WARN_ON(vec->digest_size > HASH_MAX_DIGESTSIZE)) return -EINVAL; - tfm = crypto_alloc_shash(test->alg, 0, 0); - if (IS_ERR(tfm)) { - err = PTR_ERR(tfm); - pr_err("failed to allocate %s tfm: %d\n", test->alg, err); - return err; - } + tfm = crypto_alloc_shash(impl, 0, 0); + if (IS_ERR(tfm)) + return fips_handle_alloc_tfm_error(impl, PTR_ERR(tfm)); err = fips_validate_alg(&crypto_shash_alg(tfm)->base); if (err) goto out; if (crypto_shash_digestsize(tfm) != vec->digest_size) { - pr_err("%s has wrong digest size\n", test->alg); + pr_err("%s has wrong digest size\n", impl); err = -EINVAL; goto out; } @@ -477,7 +439,7 @@ fips_test_hash(const struct fips_test *test) if (vec->key) { err = crypto_shash_setkey(tfm, vec->key, vec->key_size); if (err) { - pr_err("failed to set %s key: %d\n", test->alg, err); + pr_err("failed to set %s key: %d\n", impl, err); goto out; } } @@ -485,22 +447,18 @@ fips_test_hash(const struct fips_test *test) err = crypto_shash_tfm_digest(tfm, vec->message, vec->message_size, digest); if (err) { - pr_err("%s digest computation failed: %d\n", test->alg, err); + pr_err("%s digest computation failed: %d\n", impl, err); goto out; } - err = fips_check_result(test, digest, vec->digest, vec->digest_size, - "digest"); + err = fips_check_result(digest, vec->digest, vec->digest_size, + impl, "digest"); out: crypto_free_shash(tfm); return err; } -/* - * Test the sha256() library function, as it may not be covered by the "sha256" - * crypto_shash, and thus may not be covered by the "hmac(sha256)" test we do. - */ static int __init __must_check -fips_test_sha256_library(const struct fips_test *test) +fips_test_sha256_library(const struct fips_test *test, const char *impl) { const struct hash_testvec *vec = &test->hash; u8 digest[SHA256_DIGEST_SIZE]; @@ -509,13 +467,13 @@ fips_test_sha256_library(const struct fips_test *test) return -EINVAL; sha256(vec->message, vec->message_size, digest); - return fips_check_result(test, digest, vec->digest, vec->digest_size, - "digest (library API)"); + return fips_check_result(digest, vec->digest, vec->digest_size, + impl, "digest"); } /* Test a DRBG using the crypto_rng API. */ static int __init __must_check -fips_test_drbg(const struct fips_test *test) +fips_test_drbg(const struct fips_test *test, const char *impl) { const struct drbg_testvec *vec = &test->drbg; struct crypto_rng *rng; @@ -524,12 +482,9 @@ fips_test_drbg(const struct fips_test *test) struct drbg_string addtl, pers, testentropy; int err; - rng = crypto_alloc_rng(test->alg, 0, 0); - if (IS_ERR(rng)) { - err = PTR_ERR(rng); - pr_err("failed to allocate %s tfm: %d\n", test->alg, err); - return PTR_ERR(rng); - } + rng = crypto_alloc_rng(impl, 0, 0); + if (IS_ERR(rng)) + return fips_handle_alloc_tfm_error(impl, PTR_ERR(rng)); err = fips_validate_alg(&crypto_rng_alg(rng)->base); if (err) goto out; @@ -549,7 +504,7 @@ fips_test_drbg(const struct fips_test *test) drbg_string_fill(&pers, vec->pers, vec->pers_size); err = crypto_drbg_reset_test(rng, &pers, &test_data); if (err) { - pr_err("failed to reset %s\n", test->alg); + pr_err("failed to reset %s\n", impl); goto out; } @@ -570,7 +525,7 @@ fips_test_drbg(const struct fips_test *test) } if (err) { pr_err("failed to get bytes from %s (try 1): %d\n", - test->alg, err); + impl, err); goto out; } @@ -590,13 +545,13 @@ fips_test_drbg(const struct fips_test *test) } if (err) { pr_err("failed to get bytes from %s (try 2): %d\n", - test->alg, err); + impl, err); goto out; } /* Check that the DRBG generated the expected output. */ - err = fips_check_result(test, output, vec->output, vec->out_size, - "get_bytes"); + err = fips_check_result(output, vec->output, vec->out_size, + impl, "get_bytes"); out: kfree(output); crypto_free_rng(rng); @@ -606,33 +561,134 @@ out: /* Include the test vectors generated by the Python script. */ #include "fips140-generated-testvecs.h" -/* List of all self-tests. Keep this in sync with fips140_algorithms[]. */ +/* + * List of all self-tests. Keep this in sync with fips140_algorithms[]. + * + * When possible, we have followed the FIPS 140-2 Implementation Guidance (IG) + * document when creating this list of tests. The result is intended to be a + * list of tests that is near-minimal (and thus minimizes runtime overhead) + * while complying with all requirements. For additional details, see the + * comment at the beginning of this file. + */ static const struct fips_test fips140_selftests[] __initconst = { /* - * Tests for AES and AES modes. + * Test for the AES library API. * - * The full list of AES algorithms we potentially need to test are AES - * by itself, AES-CBC, AES-CTR, AES-ECB, AES-GCM, and AES-XTS. We can - * follow the FIPS 140-2 Implementation Guidance (IG) document to try to - * reduce this list, but we run into the issue that the architecture- - * specific implementations of these algorithms in Linux often don't - * share the "same" underlying AES implementation. E.g., the ARMv8 CE - * optimized implementations issue ARMv8 CE instructions directly rather - * than going through a separate AES implementation. In this case, - * separate tests are needed according to section 9.2 of the IG. + * Since the AES library API may use its own AES implementation and the + * module provides no support for composing it with a mode of operation + * (it's just plain AES), we must test it directly. + * + * In contrast, we don't need to directly test the "aes" ciphers that + * are accessible through the crypto_cipher API (e.g. "aes-ce"), as they + * are covered indirectly by AES-GCM and AES-ECB tests. */ { .alg = "aes", - .func = fips_test_aes, - .blockcipher = { + .impls = {"aes-lib"}, + .func = fips_test_aes_library, + .skcipher = { .key = fips_aes_key, .key_size = sizeof(fips_aes_key), .plaintext = fips_message, .ciphertext = fips_aes_ecb_ciphertext, - .block_size = 16, + .message_size = 16, } - }, { + }, + /* + * Tests for AES-GCM, a.k.a. "gcm(aes)" in crypto API syntax. + * + * The IG requires that each underlying AES implementation be tested in + * an authenticated mode, if implemented. We therefore must test the + * "gcm" template composed with each "aes" implementation. + * + * We also must test all standalone implementations of "gcm(aes)" such + * as "gcm-aes-ce", as they don't reuse another full AES implementation + * and thus can't be covered by another test. + */ + { + .alg = "gcm(aes)", + .impls = { + /* "gcm" template with all "aes" implementations */ + "gcm_base(ctr(aes-generic),ghash-generic)", + "gcm_base(ctr(aes-arm64),ghash-generic)", + "gcm_base(ctr(aes-ce),ghash-generic)", + /* + * "gcm" template with alternate "ghash" implementation. + * The IG doesn't consider multiple GHASH + * implementations, but we include this to be safe. + */ + "gcm_base(ctr(aes-generic),ghash-neon)", + /* All standalone implementations of "gcm(aes)" */ + "gcm-aes-ce", + }, + .func = fips_test_aead, + .aead = { + .key = fips_aes_key, + .key_size = sizeof(fips_aes_key), + .iv = fips_aes_iv, + /* The GCM implementations assume an IV size of 12. */ + .iv_size = 12, + .assoc = fips_aes_gcm_assoc, + .assoc_size = sizeof(fips_aes_gcm_assoc), + .plaintext = fips_message, + .plaintext_size = sizeof(fips_message), + .ciphertext = fips_aes_gcm_ciphertext, + .ciphertext_size = sizeof(fips_aes_gcm_ciphertext), + } + }, + /* + * Tests for AES-ECB, a.k.a. "ecb(aes)" in crypto API syntax. + * + * The IG requires that each underlying AES implementation be tested in + * a mode that exercises the encryption direction of AES and in a mode + * that exercises the decryption direction of AES. GCM only covers the + * encryption direction, so we add ECB to test decryption. We therefore + * test the "ecb" template composed with each "aes" implementation. + * + * We also must test all standalone implementations of "ecb(aes)" such + * as "ecb-aes-ce", as they don't reuse another full AES implementation + * and thus can't be covered by another test. + */ + { + .alg = "ecb(aes)", + .impls = { + /* "ecb" template with all "aes" implementations */ + "ecb(aes-generic)", + "ecb(aes-arm64)", + "ecb(aes-ce)", + /* All standalone implementations of "ecb(aes)" */ + "ecb-aes-neon", + "ecb-aes-neonbs", + "ecb-aes-ce", + }, + .func = fips_test_skcipher, + .skcipher = { + .key = fips_aes_key, + .key_size = sizeof(fips_aes_key), + .plaintext = fips_message, + .ciphertext = fips_aes_ecb_ciphertext, + .message_size = sizeof(fips_message) + } + }, + /* + * Tests for AES-CBC, AES-CTR, and AES-XTS. + * + * According to the IG, unauthenticated AES modes don't need to have + * their own test as long as both directions of the underlying AES + * implementation are already tested via other modes. + * + * However we must still test standalone implementations of these modes, + * as they don't reuse another full AES implementation and thus can't be + * covered by another test. + */ + { .alg = "cbc(aes)", + .impls = { + /* All standalone implementations of "cbc(aes)" */ + "cbc-aes-neon", + "cbc-aes-neonbs", + "cbc-aes-ce", + }, .func = fips_test_skcipher, .skcipher = { .key = fips_aes_key, @@ -645,6 +701,12 @@ static const struct fips_test fips140_selftests[] __initconst = { } }, { .alg = "ctr(aes)", + .impls = { + /* All standalone implementations of "ctr(aes)" */ + "ctr-aes-neon", + "ctr-aes-neonbs", + "ctr-aes-ce", + }, .func = fips_test_skcipher, .skcipher = { .key = fips_aes_key, @@ -655,34 +717,14 @@ static const struct fips_test fips140_selftests[] __initconst = { .ciphertext = fips_aes_ctr_ciphertext, .message_size = sizeof(fips_message), } - }, { - .alg = "ecb(aes)", - .func = fips_test_skcipher, - .skcipher = { - .key = fips_aes_key, - .key_size = sizeof(fips_aes_key), - .plaintext = fips_message, - .ciphertext = fips_aes_ecb_ciphertext, - .message_size = sizeof(fips_message) - } - }, { - .alg = "gcm(aes)", - .func = fips_test_aead, - .aead = { - .key = fips_aes_key, - .key_size = sizeof(fips_aes_key), - .iv = fips_aes_iv, - /* The GCM implementation assumes an IV size of 12. */ - .iv_size = 12, - .assoc = fips_aes_gcm_assoc, - .assoc_size = sizeof(fips_aes_gcm_assoc), - .plaintext = fips_message, - .plaintext_size = sizeof(fips_message), - .ciphertext = fips_aes_gcm_ciphertext, - .ciphertext_size = sizeof(fips_aes_gcm_ciphertext), - } }, { .alg = "xts(aes)", + .impls = { + /* All standalone implementations of "xts(aes)" */ + "xts-aes-neon", + "xts-aes-neonbs", + "xts-aes-ce", + }, .func = fips_test_skcipher, .skcipher = { .key = fips_aes_xts_key, @@ -693,27 +735,16 @@ static const struct fips_test fips140_selftests[] __initconst = { .ciphertext = fips_aes_xts_ciphertext, .message_size = sizeof(fips_message), } - /* - * Tests for SHA-1, SHA-256, HMAC-SHA256, and SHA-512. - * - * The selection of these specific tests follows the guidance from - * section 9 of the FIPS 140-2 Implementation Guidance (IG) document to - * achieve a minimal list of tests, rather than testing all of - * SHA-{1,224,256,384,512} and HMAC-SHA{1,224,256,384,512}. As per the - * IG, testing SHA-224 is only required if SHA-256 isn't implemented, - * and testing SHA-384 is only required if SHA-512 isn't implemented. - * Also, HMAC only has to be tested with one underlying SHA, and the - * HMAC test also fulfills the test for its underlying SHA. That would - * result in a test list of e.g. SHA-1, HMAC-SHA256, and SHA-512. - * - * However we also need to take into account cases where implementations - * aren't shared in the "natural" way assumed by the IG. Currently the - * only known exception w.r.t. SHA-* and HMAC-* is the sha256() library - * function which may not be covered by the test of the "hmac(sha256)" - * crypto_shash. So, we test sha256() separately. - */ - }, { + }, + + /* Tests for SHA-1 */ + { .alg = "sha1", + .impls = { + /* All implementations of "sha1" */ + "sha1-generic", + "sha1-ce" + }, .func = fips_test_hash, .hash = { .message = fips_message, @@ -721,8 +752,35 @@ static const struct fips_test fips140_selftests[] __initconst = { .digest = fips_sha1_digest, .digest_size = sizeof(fips_sha1_digest) } - }, { + }, + /* + * Tests for all SHA-256 implementations other than the sha256() library + * function. As per the IG, these tests also fulfill the tests for the + * corresponding SHA-224 implementations. + */ + { .alg = "sha256", + .impls = { + /* All implementations of "sha256" */ + "sha256-generic", + "sha256-arm64", + "sha256-ce", + }, + .func = fips_test_hash, + .hash = { + .message = fips_message, + .message_size = sizeof(fips_message), + .digest = fips_sha256_digest, + .digest_size = sizeof(fips_sha256_digest) + } + }, + /* + * Test for the sha256() library function. This must be tested + * separately because it may use its own SHA-256 implementation. + */ + { + .alg = "sha256", + .impls = {"sha256-lib"}, .func = fips_test_sha256_library, .hash = { .message = fips_message, @@ -730,7 +788,36 @@ static const struct fips_test fips140_selftests[] __initconst = { .digest = fips_sha256_digest, .digest_size = sizeof(fips_sha256_digest) } - }, { + }, + /* + * Tests for all SHA-512 implementations. As per the IG, these tests + * also fulfill the tests for the corresponding SHA-384 implementations. + */ + { + .alg = "sha512", + .impls = { + /* All implementations of "sha512" */ + "sha512-generic", + "sha512-arm64", + "sha512-ce", + }, + .func = fips_test_hash, + .hash = { + .message = fips_message, + .message_size = sizeof(fips_message), + .digest = fips_sha512_digest, + .digest_size = sizeof(fips_sha512_digest) + } + }, + /* + * Test for HMAC. As per the IG, only one HMAC test is required, + * provided that the same HMAC code is shared by all HMAC-SHA*. This is + * true in our case. We choose HMAC-SHA256 for the test. + * + * Note that as per the IG, this can fulfill the test for the underlying + * SHA. However, we don't currently rely on this. + */ + { .alg = "hmac(sha256)", .func = fips_test_hash, .hash = { @@ -741,28 +828,37 @@ static const struct fips_test fips140_selftests[] __initconst = { .digest = fips_hmac_sha256_digest, .digest_size = sizeof(fips_hmac_sha256_digest) } - }, { - .alg = "sha512", - .func = fips_test_hash, - .hash = { - .message = fips_message, - .message_size = sizeof(fips_message), - .digest = fips_sha512_digest, - .digest_size = sizeof(fips_sha512_digest) - } + }, /* - * Tests for DRBG algorithms. + * Known-answer tests for the SP800-90A DRBG algorithms. * - * Only the default variant (the one that users get when they request - * "stdrng") is required to be tested, as we don't consider the other - * variants to be used / usable in the FIPS security policy. This is - * similar to how e.g. we don't test both "xts(aes-generic)" and - * "xts-aes-ce" but rather just "xts(aes)". + * These test vectors were manually extracted from + * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/drbg/drbgtestvectors.zip. * - * Currently the default one is "drbg_nopr_hmac_sha256"; however, just - * in case we also test the prediction-resistant enabled variant too. + * The selection of these tests follows the FIPS 140-2 IG as well as + * Section 11 of SP800-90A: + * + * - We must test all DRBG types (HMAC, Hash, and CTR) that the module + * implements. However, currently the module only implements + * HMAC_DRBG (since CONFIG_CRYPTO_DRBG_CTR and CONFIG_CRYPTO_DRBG_HASH + * aren't enabled). Therefore, we only need to test HMAC_DRBG. + * + * - We only need to test one HMAC variant. + * + * - We must test all DRBG operations: Instantiate(), Reseed(), and + * Generate(). However, a single test sequence with a single output + * comparison may cover all three operations, and this is what we do. + * Note that Reseed() happens implicitly via the use of the additional + * input and also via the use of prediction resistance when enabled. + * + * - The personalization string, additional input, and prediction + * resistance support must be tested. Therefore we have chosen test + * vectors that have a nonempty personalization string and nonempty + * additional input, and we test the prediction-resistant variant. + * Just in case, we also test the non-prediction-resistant variant; + * however, it's unclear whether it's required. */ - }, { + { .alg = "drbg_nopr_hmac_sha256", .func = fips_test_drbg, .drbg = { @@ -845,19 +941,44 @@ static const struct fips_test fips140_selftests[] __initconst = { } }; +static int __init __must_check +fips_run_test(const struct fips_test *test) +{ + int i; + int err; + + /* + * If no implementations were specified, then just test the default one. + * Otherwise, test the specified list of implementations. + */ + + if (test->impls[0] == NULL) { + err = test->func(test, test->alg); + if (err) + pr_emerg("self-tests failed for algorithm %s: %d\n", + test->alg, err); + return err; + } + + for (i = 0; i < ARRAY_SIZE(test->impls) && test->impls[i] != NULL; + i++) { + err = test->func(test, test->impls[i]); + if (err) { + pr_emerg("self-tests failed for algorithm %s, implementation %s: %d\n", + test->alg, test->impls[i], err); + return err; + } + } + return 0; +} + bool __init fips140_run_selftests(void) { int i; pr_info("running self-tests\n"); for (i = 0; i < ARRAY_SIZE(fips140_selftests); i++) { - const struct fips_test *test = &fips140_selftests[i]; - int err; - - err = test->func(test); - if (err) { - pr_emerg("self-tests failed for algorithm %s: %d\n", - test->alg, err); + if (fips_run_test(&fips140_selftests[i]) != 0) { /* The caller is responsible for calling panic(). */ return false; }