ANDROID: fips140: add service indicators

To satisfy the FIPS 140-3 "service indicators" requirement, add a
function which checks whether the given algorithm is "approved" or not.

Note that this function is a bit different from the module's other APIs
in that it is an exported symbol rather than a registration-based API.
This avoids needing to make kernel/KMI changes, so I think we should do
it this way if possible, given that it's unlikely this function will be
used in practice outside of the lab test.  Built-in code can still call
this function via symbol_get() if it really wants to.

Bug: 188620248
Change-Id: I26c976258fa9446b34eb189bba7154142d85da16
Signed-off-by: Eric Biggers <ebiggers@google.com>
(cherry picked from commit fe4b8d3c687efcf27064e472730291edbd81dad6)
This commit is contained in:
Eric Biggers 2021-11-02 14:50:17 -07:00
parent b9066e59a5
commit 64d769e53f
2 changed files with 68 additions and 25 deletions

View File

@ -14,6 +14,8 @@
* don't need to meet these requirements. * don't need to meet these requirements.
*/ */
#undef __DISABLE_EXPORTS
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/module.h> #include <linux/module.h>
#include <crypto/aead.h> #include <crypto/aead.h>
@ -86,34 +88,37 @@ const u8 *__rodata_start = &__fips140_rodata_start;
* When adding a new algorithm here, make sure to consider whether it needs a * When adding a new algorithm here, make sure to consider whether it needs a
* self-test added to fips140_selftests[] as well. * self-test added to fips140_selftests[] as well.
*/ */
static const char * const fips140_algorithms[] __initconst = { static const struct {
"aes", const char *name;
bool approved;
} fips140_algs_to_replace[] = {
{"aes", true},
"cmac(aes)", {"cmac(aes)", true},
"ecb(aes)", {"ecb(aes)", true},
"cbc(aes)", {"cbc(aes)", true},
"cts(cbc(aes))", {"cts(cbc(aes))", true},
"ctr(aes)", {"ctr(aes)", true},
"xts(aes)", {"xts(aes)", true},
"gcm(aes)", {"gcm(aes)", false},
"hmac(sha1)", {"hmac(sha1)", true},
"hmac(sha224)", {"hmac(sha224)", true},
"hmac(sha256)", {"hmac(sha256)", true},
"hmac(sha384)", {"hmac(sha384)", true},
"hmac(sha512)", {"hmac(sha512)", true},
"sha1", {"sha1", true},
"sha224", {"sha224", true},
"sha256", {"sha256", true},
"sha384", {"sha384", true},
"sha512", {"sha512", true},
"stdrng", {"stdrng", true},
"jitterentropy_rng", {"jitterentropy_rng", false},
}; };
static bool __init is_fips140_algo(struct crypto_alg *alg) static bool __init fips140_should_unregister_alg(struct crypto_alg *alg)
{ {
int i; int i;
@ -124,12 +129,48 @@ static bool __init is_fips140_algo(struct crypto_alg *alg)
if (alg->cra_flags & CRYPTO_ALG_ASYNC) if (alg->cra_flags & CRYPTO_ALG_ASYNC)
return false; return false;
for (i = 0; i < ARRAY_SIZE(fips140_algorithms); i++) for (i = 0; i < ARRAY_SIZE(fips140_algs_to_replace); i++) {
if (!strcmp(alg->cra_name, fips140_algorithms[i])) if (!strcmp(alg->cra_name, fips140_algs_to_replace[i].name))
return true; return true;
}
return false; return false;
} }
/*
* FIPS 140-3 service indicators. FIPS 140-3 requires that all services
* "provide an indicator when the service utilises an approved cryptographic
* algorithm, security function or process in an approved manner". What this
* means is very debatable, even with the help of the FIPS 140-3 Implementation
* Guidance document. However, it was decided that a function that takes in an
* algorithm name and returns whether that algorithm is approved or not will
* meet this requirement. Note, this relies on some properties of the module:
*
* - The module doesn't distinguish between "services" and "algorithms"; its
* services are simply its algorithms.
*
* - The status of an approved algorithm is never non-approved, since (a) the
* module doesn't support operating in a non-approved mode, such as a mode
* where the self-tests are skipped; (b) there are no cases where the module
* supports non-approved settings for approved algorithms, e.g.
* non-approved key sizes; and (c) this function isn't available to be
* called until the module_init function has completed, so it's guaranteed
* that the self-tests and integrity check have already passed.
*
* - The module does support some non-approved algorithms, so a single static
* indicator ("return true;") would not be acceptable.
*/
bool fips140_is_approved_service(const char *name)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(fips140_algs_to_replace); i++) {
if (!strcmp(name, fips140_algs_to_replace[i].name))
return fips140_algs_to_replace[i].approved;
}
return false;
}
EXPORT_SYMBOL_GPL(fips140_is_approved_service);
static LIST_HEAD(existing_live_algos); static LIST_HEAD(existing_live_algos);
/* /*
@ -180,7 +221,7 @@ static void __init unregister_existing_fips140_algos(void)
* that new users won't use them. * that new users won't use them.
*/ */
list_for_each_entry_safe(alg, tmp, &crypto_alg_list, cra_list) { list_for_each_entry_safe(alg, tmp, &crypto_alg_list, cra_list) {
if (!is_fips140_algo(alg)) if (!fips140_should_unregister_alg(alg))
continue; continue;
if (refcount_read(&alg->cra_refcnt) == 1) { if (refcount_read(&alg->cra_refcnt) == 1) {
/* /*

View File

@ -21,4 +21,6 @@ extern struct task_struct *fips140_init_thread;
bool __init __must_check fips140_run_selftests(void); bool __init __must_check fips140_run_selftests(void);
bool fips140_is_approved_service(const char *name);
#endif /* _CRYPTO_FIPS140_MODULE_H */ #endif /* _CRYPTO_FIPS140_MODULE_H */