android_kernel_xiaomi_sm8450/crypto/fips140-selftests.c
Eric Biggers 903e97a0ca ANDROID: fips140: refactor evaluation testing support
It turns out that we have to add more code to the module to support lab
evaluation testing, beyond the error injection support we currently
have.  Therefore, rename CONFIG_CRYPTO_FIPS140_MOD_ERROR_INJECTION to
CONFIG_CRYPTO_FIPS140_MOD_EVAL_TESTING, and move the relevant code into
a new file fips140-eval-testing.c which is conditionally compiled.

Also rename the "broken_alg" module parameter to "fail_selftest" so that
it is similar to "fail_integrity_check" which we'll be adding.

Bug: 188620248
Change-Id: I01bcbf7525690e277854ba4ed8dd89e7cd08d98e
Signed-off-by: Eric Biggers <ebiggers@google.com>
2021-11-23 18:02:24 +00:00

999 lines
30 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2021 Google LLC
*
* Authors: Elena Petrova <lenaptr@google.com>,
* Eric Biggers <ebiggers@google.com>
*
* Self-tests of fips140.ko cryptographic functionality. These are run at
* module load time to fulfill FIPS 140 and NIAP FPT_TST_EXT.1 requirements.
*
* The actual requirements for these self-tests are somewhat vague, but
* section 9 ("Self-Tests") of the FIPS 140-2 Implementation Guidance document
* (https://csrc.nist.gov/csrc/media/projects/cryptographic-module-validation-program/documents/fips140-2/fips1402ig.pdf)
* is somewhat helpful. Basically, all implementations of all FIPS approved
* algorithms (including modes of operation) must be tested. However:
*
* - There are provisions for skipping tests that are already sufficiently
* covered by other tests. E.g., HMAC-SHA256 may cover SHA-256.
*
* - Only one test vector is required per algorithm, and it can be generated
* by any known-good implementation or taken from any official document.
*
* - For ciphers, both encryption and decryption must be tested.
*
* - 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 AES-CBC-CTS and 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.
*
* Note that we don't reuse the upstream crypto API's self-tests
* (crypto/testmgr.{c,h}), for several reasons:
*
* - To meet FIPS requirements, the self-tests must be located within the FIPS
* module boundary (fips140.ko). But testmgr is integrated into the crypto
* API framework and can't be extracted into the module.
*
* - testmgr is much more heavyweight than required for FIPS and NIAP; it
* tests more algorithms and does more tests per algorithm, as it's meant to
* do proper testing and not just meet certification requirements. We need
* tests that can run with minimal overhead on every boot-up.
*
* - Despite being more heavyweight in general, testmgr doesn't test the
* SHA-256 and AES library APIs, despite that being needed here.
*/
#include <crypto/aead.h>
#include <crypto/aes.h>
#include <crypto/drbg.h>
#include <crypto/hash.h>
#include <crypto/rng.h>
#include <crypto/sha.h>
#include <crypto/skcipher.h>
#include "fips140-module.h"
/* Test vector for an AEAD algorithm */
struct aead_testvec {
const u8 *key;
size_t key_size;
const u8 *iv;
size_t iv_size;
const u8 *assoc;
size_t assoc_size;
const u8 *plaintext;
size_t plaintext_size;
const u8 *ciphertext;
size_t ciphertext_size;
};
/* Test vector for a length-preserving encryption algorithm */
struct skcipher_testvec {
const u8 *key;
size_t key_size;
const u8 *iv;
size_t iv_size;
const u8 *plaintext;
const u8 *ciphertext;
size_t message_size;
};
/* Test vector for a hash algorithm */
struct hash_testvec {
const u8 *key;
size_t key_size;
const u8 *message;
size_t message_size;
const u8 *digest;
size_t digest_size;
};
/* Test vector for a DRBG algorithm */
struct drbg_testvec {
const u8 *entropy;
size_t entropy_size;
const u8 *pers;
size_t pers_size;
const u8 *entpr_a;
const u8 *entpr_b;
size_t entpr_size;
const u8 *add_a;
const u8 *add_b;
size_t add_size;
const u8 *output;
size_t out_size;
};
struct fips_test {
/* The name of the algorithm, in crypto API syntax */
const char *alg;
/*
* 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 aead_testvec aead;
struct skcipher_testvec skcipher;
struct hash_testvec hash;
struct drbg_testvec drbg;
};
};
/* Maximum IV size (in bytes) among any algorithm tested here */
#define MAX_IV_SIZE 16
static int __init __must_check
fips_check_result(u8 *result, const u8 *expected_result, size_t result_size,
const char *impl, const char *operation)
{
fips140_inject_selftest_failure(impl, result);
if (memcmp(result, expected_result, result_size) != 0) {
pr_err("wrong result from %s %s\n", impl, operation);
return -EBADMSG;
}
return 0;
}
/*
* None of the algorithms should be ASYNC, as the FIPS module doesn't register
* any ASYNC algorithms. (The ASYNC flag is only declared by hardware
* algorithms, which would need their own FIPS certification.)
*
* Ideally we would verify alg->cra_module == THIS_MODULE here as well, but that
* doesn't work because the files are compiled as built-in code.
*/
static int __init __must_check
fips_validate_alg(const struct crypto_alg *alg)
{
if (alg->cra_flags & CRYPTO_ALG_ASYNC) {
pr_err("unexpectedly got async implementation of %s (%s)\n",
alg->cra_name, alg->cra_driver_name);
return -EINVAL;
}
return 0;
}
static int __init __must_check
fips_handle_alloc_tfm_error(const char *impl, 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.
*/
pr_info("%s is unavailable (no CPU support?), skipping testing it\n",
impl);
return 0;
}
pr_err("failed to allocate %s tfm: %d\n", impl, err);
return err;
}
static int __init __must_check
fips_test_aes_library(const struct fips_test *test, const char *impl)
{
const struct skcipher_testvec *vec = &test->skcipher;
struct crypto_aes_ctx ctx;
u8 block[AES_BLOCK_SIZE];
int err;
if (WARN_ON(vec->message_size != AES_BLOCK_SIZE))
return -EINVAL;
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(block, vec->ciphertext, AES_BLOCK_SIZE,
impl, "encryption");
if (err)
return err;
aes_decrypt(&ctx, block, block);
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, const char *impl)
{
const struct skcipher_testvec *vec = &test->skcipher;
struct crypto_skcipher *tfm;
struct skcipher_request *req = NULL;
u8 *message = NULL;
struct scatterlist sg;
u8 iv[MAX_IV_SIZE];
int err;
if (WARN_ON(vec->iv_size > MAX_IV_SIZE))
return -EINVAL;
if (WARN_ON(vec->message_size <= 0))
return -EINVAL;
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", impl);
err = -EINVAL;
goto out;
}
req = skcipher_request_alloc(tfm, GFP_KERNEL);
message = kmemdup(vec->plaintext, vec->message_size, GFP_KERNEL);
if (!req || !message) {
err = -ENOMEM;
goto out;
}
sg_init_one(&sg, message, vec->message_size);
skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
NULL, NULL);
skcipher_request_set_crypt(req, &sg, &sg, vec->message_size, iv);
err = crypto_skcipher_setkey(tfm, vec->key, vec->key_size);
if (err) {
pr_err("failed to set %s key: %d\n", impl, err);
goto out;
}
/* Encrypt the plaintext, then verify the resulting ciphertext. */
memcpy(iv, vec->iv, vec->iv_size);
err = crypto_skcipher_encrypt(req);
if (err) {
pr_err("%s encryption failed: %d\n", impl, err);
goto out;
}
err = fips_check_result(message, vec->ciphertext, vec->message_size,
impl, "encryption");
if (err)
goto out;
/* Decrypt the ciphertext, then verify the resulting plaintext. */
memcpy(iv, vec->iv, vec->iv_size);
err = crypto_skcipher_decrypt(req);
if (err) {
pr_err("%s decryption failed: %d\n", impl, err);
goto out;
}
err = fips_check_result(message, vec->plaintext, vec->message_size,
impl, "decryption");
out:
kfree(message);
skcipher_request_free(req);
crypto_free_skcipher(tfm);
return err;
}
/* Test an AEAD using the crypto_aead API. */
static int __init __must_check
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;
struct crypto_aead *tfm;
struct aead_request *req = NULL;
u8 *assoc = NULL;
u8 *message = NULL;
struct scatterlist sg[2];
int sg_idx = 0;
u8 iv[MAX_IV_SIZE];
int err;
if (WARN_ON(vec->iv_size > MAX_IV_SIZE))
return -EINVAL;
if (WARN_ON(vec->ciphertext_size <= vec->plaintext_size))
return -EINVAL;
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", impl);
err = -EINVAL;
goto out;
}
req = aead_request_alloc(tfm, GFP_KERNEL);
assoc = kmemdup(vec->assoc, vec->assoc_size, GFP_KERNEL);
message = kzalloc(vec->ciphertext_size, GFP_KERNEL);
if (!req || !assoc || !message) {
err = -ENOMEM;
goto out;
}
memcpy(message, vec->plaintext, vec->plaintext_size);
sg_init_table(sg, ARRAY_SIZE(sg));
if (vec->assoc_size)
sg_set_buf(&sg[sg_idx++], assoc, vec->assoc_size);
sg_set_buf(&sg[sg_idx++], message, vec->ciphertext_size);
aead_request_set_ad(req, vec->assoc_size);
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
err = crypto_aead_setkey(tfm, vec->key, vec->key_size);
if (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",
impl, err);
goto out;
}
/*
* Encrypt the plaintext, then verify the resulting ciphertext (which
* includes the authentication tag).
*/
memcpy(iv, vec->iv, vec->iv_size);
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", impl, err);
goto out;
}
err = fips_check_result(message, vec->ciphertext, vec->ciphertext_size,
impl, "encryption");
if (err)
goto out;
/*
* Decrypt the ciphertext (which includes the authentication tag), then
* verify the resulting plaintext.
*/
memcpy(iv, vec->iv, vec->iv_size);
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", impl, err);
goto out;
}
err = fips_check_result(message, vec->plaintext, vec->plaintext_size,
impl, "decryption");
out:
kfree(message);
kfree(assoc);
aead_request_free(req);
crypto_free_aead(tfm);
return err;
}
/*
* Test a hash algorithm using the crypto_shash API.
*
* Note that we don't need to test the crypto_ahash API too, since none of the
* hash algorithms in the FIPS module have the ASYNC flag, and thus there will
* 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, const char *impl)
{
const struct hash_testvec *vec = &test->hash;
struct crypto_shash *tfm;
u8 digest[HASH_MAX_DIGESTSIZE];
int err;
if (WARN_ON(vec->digest_size > HASH_MAX_DIGESTSIZE))
return -EINVAL;
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", impl);
err = -EINVAL;
goto out;
}
if (vec->key) {
err = crypto_shash_setkey(tfm, vec->key, vec->key_size);
if (err) {
pr_err("failed to set %s key: %d\n", impl, err);
goto out;
}
}
err = crypto_shash_tfm_digest(tfm, vec->message, vec->message_size,
digest);
if (err) {
pr_err("%s digest computation failed: %d\n", impl, err);
goto out;
}
err = fips_check_result(digest, vec->digest, vec->digest_size,
impl, "digest");
out:
crypto_free_shash(tfm);
return err;
}
static int __init __must_check
fips_test_sha256_library(const struct fips_test *test, const char *impl)
{
const struct hash_testvec *vec = &test->hash;
u8 digest[SHA256_DIGEST_SIZE];
if (WARN_ON(vec->digest_size != SHA256_DIGEST_SIZE))
return -EINVAL;
sha256(vec->message, vec->message_size, digest);
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, const char *impl)
{
const struct drbg_testvec *vec = &test->drbg;
struct crypto_rng *rng;
u8 *output = NULL;
struct drbg_test_data test_data;
struct drbg_string addtl, pers, testentropy;
int err;
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;
output = kzalloc(vec->out_size, GFP_KERNEL);
if (!output) {
err = -ENOMEM;
goto out;
}
/*
* Initialize the DRBG with the entropy and personalization string given
* in the test vector.
*/
test_data.testentropy = &testentropy;
drbg_string_fill(&testentropy, vec->entropy, vec->entropy_size);
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", impl);
goto out;
}
/*
* Generate some random bytes using the additional data string provided
* in the test vector. Also use the additional entropy if provided
* (relevant for the prediction-resistant DRBG variants only).
*/
drbg_string_fill(&addtl, vec->add_a, vec->add_size);
if (vec->entpr_size) {
drbg_string_fill(&testentropy, vec->entpr_a, vec->entpr_size);
err = crypto_drbg_get_bytes_addtl_test(rng, output,
vec->out_size, &addtl,
&test_data);
} else {
err = crypto_drbg_get_bytes_addtl(rng, output, vec->out_size,
&addtl);
}
if (err) {
pr_err("failed to get bytes from %s (try 1): %d\n",
impl, err);
goto out;
}
/*
* Do the same again, using a second additional data string, and (when
* applicable) a second additional entropy string.
*/
drbg_string_fill(&addtl, vec->add_b, vec->add_size);
if (test->drbg.entpr_size) {
drbg_string_fill(&testentropy, vec->entpr_b, vec->entpr_size);
err = crypto_drbg_get_bytes_addtl_test(rng, output,
vec->out_size, &addtl,
&test_data);
} else {
err = crypto_drbg_get_bytes_addtl(rng, output, vec->out_size,
&addtl);
}
if (err) {
pr_err("failed to get bytes from %s (try 2): %d\n",
impl, err);
goto out;
}
/* Check that the DRBG generated the expected output. */
err = fips_check_result(output, vec->output, vec->out_size,
impl, "get_bytes");
out:
kfree(output);
crypto_free_rng(rng);
return err;
}
/* 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[].
*
* 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 = {
/*
* Test for the AES library API.
*
* 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-CMAC and AES-ECB tests.
*/
{
.alg = "aes",
.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,
.message_size = 16,
}
},
/*
* Tests for AES-CMAC, a.k.a. "cmac(aes)" in crypto API syntax.
*
* The IG requires that each underlying AES implementation be tested in
* an authenticated mode, if implemented. Of such modes, this module
* implements AES-GCM and AES-CMAC. However, AES-GCM doesn't "count"
* because this module's implementations of AES-GCM won't actually be
* FIPS-approved, due to a quirk in the FIPS requirements.
*
* Therefore, for us this requirement applies to AES-CMAC, so we must
* test the "cmac" template composed with each "aes" implementation.
*
* Separately from the above, we also must test all standalone
* implementations of "cmac(aes)" such as "cmac-aes-ce", as they don't
* reuse another full AES implementation and thus can't be covered by
* another test.
*/
{
.alg = "cmac(aes)",
.impls = {
/* "cmac" template with all "aes" implementations */
"cmac(aes-generic)",
"cmac(aes-arm64)",
"cmac(aes-ce)",
/* All standalone implementations of "cmac(aes)" */
"cmac-aes-neon",
"cmac-aes-ce",
},
.func = fips_test_hash,
.hash = {
.key = fips_aes_key,
.key_size = sizeof(fips_aes_key),
.message = fips_message,
.message_size = sizeof(fips_message),
.digest = fips_aes_cmac_digest,
.digest_size = sizeof(fips_aes_cmac_digest),
}
},
/*
* 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. CMAC only covers the
* encryption direction, so we choose ECB to test decryption. Thus, we
* test the "ecb" template composed with each "aes" implementation.
*
* Separately from the above, 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-CBC-CTS, AES-CTR, AES-XTS, and AES-GCM.
*
* According to the IG, an AES mode of operation doesn't need to have
* its own test, provided that (a) both the encryption and decryption
* directions of the underlying AES implementation are already tested
* via other mode(s), and (b) in the case of an authenticated mode, at
* least one other authenticated mode is already tested. The tests of
* the "cmac" and "ecb" templates fulfill these conditions; therefore,
* we don't need to test any other AES mode templates.
*
* This does *not* apply to standalone implementations of these modes
* such as "cbc-aes-ce", as such implementations don't reuse another
* full AES implementation and thus can't be covered by another test.
* We must test all such standalone implementations.
*
* The AES-GCM test isn't actually required, as it's expected that this
* module's AES-GCM implementation won't actually be able to be
* FIPS-approved. This is unfortunate; it's caused by the FIPS
* requirements for GCM being incompatible with GCM implementations that
* don't generate their own IVs. We choose to still include the AES-GCM
* test to keep it on par with the other FIPS-approved algorithms, in
* case it turns out that AES-GCM can be approved after all.
*/
{
.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,
.key_size = sizeof(fips_aes_key),
.iv = fips_aes_iv,
.iv_size = sizeof(fips_aes_iv),
.plaintext = fips_message,
.ciphertext = fips_aes_cbc_ciphertext,
.message_size = sizeof(fips_message),
}
}, {
.alg = "cts(cbc(aes))",
.impls = {
/* All standalone implementations of "cts(cbc(aes))" */
"cts-cbc-aes-neon",
"cts-cbc-aes-ce",
},
.func = fips_test_skcipher,
/* Test vector taken from RFC 3962 */
.skcipher = {
.key = "\x63\x68\x69\x63\x6b\x65\x6e\x20"
"\x74\x65\x72\x69\x79\x61\x6b\x69",
.key_size = 16,
.iv = "\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00",
.iv_size = 16,
.plaintext = "\x49\x20\x77\x6f\x75\x6c\x64\x20"
"\x6c\x69\x6b\x65\x20\x74\x68\x65"
"\x20\x47\x65\x6e\x65\x72\x61\x6c"
"\x20\x47\x61\x75\x27\x73\x20",
.ciphertext = "\xfc\x00\x78\x3e\x0e\xfd\xb2\xc1"
"\xd4\x45\xd4\xc8\xef\xf7\xed\x22"
"\x97\x68\x72\x68\xd6\xec\xcc\xc0"
"\xc0\x7b\x25\xe2\x5e\xcf\xe5",
.message_size = 31,
}
}, {
.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,
.key_size = sizeof(fips_aes_key),
.iv = fips_aes_iv,
.iv_size = sizeof(fips_aes_iv),
.plaintext = fips_message,
.ciphertext = fips_aes_ctr_ciphertext,
.message_size = sizeof(fips_message),
}
}, {
.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,
.key_size = sizeof(fips_aes_xts_key),
.iv = fips_aes_iv,
.iv_size = sizeof(fips_aes_iv),
.plaintext = fips_message,
.ciphertext = fips_aes_xts_ciphertext,
.message_size = sizeof(fips_message),
}
}, {
.alg = "gcm(aes)",
.impls = {
/* 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 SHA-1 */
{
.alg = "sha1",
.impls = {
/* All implementations of "sha1" */
"sha1-generic",
"sha1-ce"
},
.func = fips_test_hash,
.hash = {
.message = fips_message,
.message_size = sizeof(fips_message),
.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,
.message_size = sizeof(fips_message),
.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 = {
.key = fips_hmac_key,
.key_size = sizeof(fips_hmac_key),
.message = fips_message,
.message_size = sizeof(fips_message),
.digest = fips_hmac_sha256_digest,
.digest_size = sizeof(fips_hmac_sha256_digest)
}
},
/*
* Known-answer tests for the SP800-90A DRBG algorithms.
*
* These test vectors were manually extracted from
* https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/drbg/drbgtestvectors.zip.
*
* 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.
* Testing the non-prediction-resistant variant is not required.
*/
{
.alg = "drbg_pr_hmac_sha256",
.func = fips_test_drbg,
.drbg = {
.entropy =
"\xc7\xcc\xbc\x67\x7e\x21\x66\x1e\x27\x2b\x63\xdd"
"\x3a\x78\xdc\xdf\x66\x6d\x3f\x24\xae\xcf\x37\x01"
"\xa9\x0d\x89\x8a\xa7\xdc\x81\x58\xae\xb2\x10\x15"
"\x7e\x18\x44\x6d\x13\xea\xdf\x37\x85\xfe\x81\xfb",
.entropy_size = 48,
.entpr_a =
"\x7b\xa1\x91\x5b\x3c\x04\xc4\x1b\x1d\x19\x2f\x1a"
"\x18\x81\x60\x3c\x6c\x62\x91\xb7\xe9\xf5\xcb\x96"
"\xbb\x81\x6a\xcc\xb5\xae\x55\xb6",
.entpr_b =
"\x99\x2c\xc7\x78\x7e\x3b\x88\x12\xef\xbe\xd3\xd2"
"\x7d\x2a\xa5\x86\xda\x8d\x58\x73\x4a\x0a\xb2\x2e"
"\xbb\x4c\x7e\xe3\x9a\xb6\x81\xc1",
.entpr_size = 32,
.output =
"\x95\x6f\x95\xfc\x3b\xb7\xfe\x3e\xd0\x4e\x1a\x14"
"\x6c\x34\x7f\x7b\x1d\x0d\x63\x5e\x48\x9c\x69\xe6"
"\x46\x07\xd2\x87\xf3\x86\x52\x3d\x98\x27\x5e\xd7"
"\x54\xe7\x75\x50\x4f\xfb\x4d\xfd\xac\x2f\x4b\x77"
"\xcf\x9e\x8e\xcc\x16\xa2\x24\xcd\x53\xde\x3e\xc5"
"\x55\x5d\xd5\x26\x3f\x89\xdf\xca\x8b\x4e\x1e\xb6"
"\x88\x78\x63\x5c\xa2\x63\x98\x4e\x6f\x25\x59\xb1"
"\x5f\x2b\x23\xb0\x4b\xa5\x18\x5d\xc2\x15\x74\x40"
"\x59\x4c\xb4\x1e\xcf\x9a\x36\xfd\x43\xe2\x03\xb8"
"\x59\x91\x30\x89\x2a\xc8\x5a\x43\x23\x7c\x73\x72"
"\xda\x3f\xad\x2b\xba\x00\x6b\xd1",
.out_size = 128,
.add_a =
"\x18\xe8\x17\xff\xef\x39\xc7\x41\x5c\x73\x03\x03"
"\xf6\x3d\xe8\x5f\xc8\xab\xe4\xab\x0f\xad\xe8\xd6"
"\x86\x88\x55\x28\xc1\x69\xdd\x76",
.add_b =
"\xac\x07\xfc\xbe\x87\x0e\xd3\xea\x1f\x7e\xb8\xe7"
"\x9d\xec\xe8\xe7\xbc\xf3\x18\x25\x77\x35\x4a\xaa"
"\x00\x99\x2a\xdd\x0a\x00\x50\x82",
.add_size = 32,
.pers =
"\xbc\x55\xab\x3c\xf6\x52\xb0\x11\x3d\x7b\x90\xb8"
"\x24\xc9\x26\x4e\x5a\x1e\x77\x0d\x3d\x58\x4a\xda"
"\xd1\x81\xe9\xf8\xeb\x30\x8f\x6f",
.pers_size = 32,
}
}
};
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++) {
if (fips_run_test(&fips140_selftests[i]) != 0) {
/* The caller is responsible for calling panic(). */
return false;
}
}
pr_info("all self-tests passed\n");
return true;
}