Use a new flag to record whether a particular algorithm is provided by a standalone FIPS 140 module. Note: This does not mean the algorithm is "FIPS approved" or even "FIPS allowed" -- it simply means the algorithm is implemented within the FIPS module. Signed-off-by: Vegard Nossum <vegard.nossum@xxxxxxxxxx> --- crypto/algapi.c | 30 ++++++++++++++++++++++++++++++ crypto/testmgr.c | 22 +++++++++++++++------- include/linux/crypto.h | 8 ++++++++ 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/crypto/algapi.c b/crypto/algapi.c index 54b8d4acd651..29076797a938 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -450,6 +450,9 @@ int crypto_register_alg(struct crypto_alg *alg) if (err) return err; + /* Blatant API misuse */ + BUG_ON(alg->cra_flags & CRYPTO_ALG_FIPS_PROVIDED); + if (alg->cra_flags & CRYPTO_ALG_DUP_FIRST && !WARN_ON_ONCE(alg->cra_destroy)) { unsigned int algsize = alg->cra_type->algsize; @@ -463,6 +466,13 @@ int crypto_register_alg(struct crypto_alg *alg) alg->cra_destroy = crypto_free_alg; } +#ifdef FIPS_MODULE + if (alg->cra_module == THIS_MODULE) { + alg->cra_flags |= CRYPTO_ALG_FIPS_PROVIDED; + alg->cra_priority |= 4096; + } +#endif + down_write(&crypto_alg_sem); larval = __crypto_register_alg(alg, &algs_to_put); if (!IS_ERR_OR_NULL(larval)) { @@ -666,6 +676,9 @@ int crypto_register_instance(struct crypto_template *tmpl, struct crypto_larval *larval; struct crypto_spawn *spawn; u32 fips_internal = 0; +#ifdef FIPS_MODULE + u32 fips_provided = ~0; +#endif LIST_HEAD(algs_to_put); int err; @@ -673,6 +686,9 @@ int crypto_register_instance(struct crypto_template *tmpl, if (err) return err; + /* Blatant API misuse */ + BUG_ON(inst->alg.cra_flags & CRYPTO_ALG_FIPS_PROVIDED); + inst->alg.cra_module = tmpl->module; inst->alg.cra_flags |= CRYPTO_ALG_INSTANCE; inst->alg.cra_destroy = crypto_destroy_instance; @@ -692,6 +708,13 @@ int crypto_register_instance(struct crypto_template *tmpl, fips_internal |= spawn->alg->cra_flags; +#ifdef FIPS_MODULE + if (spawn->alg->cra_module == THIS_MODULE) + fips_provided &= spawn->alg->cra_flags; + else + fips_provided = 0; +#endif + crypto_mod_put(spawn->alg); spawn = next; @@ -699,6 +722,13 @@ int crypto_register_instance(struct crypto_template *tmpl, inst->alg.cra_flags |= (fips_internal & CRYPTO_ALG_FIPS_INTERNAL); +#ifdef FIPS_MODULE + if (tmpl->module == THIS_MODULE && (fips_provided & CRYPTO_ALG_FIPS_PROVIDED)) { + inst->alg.cra_flags |= CRYPTO_ALG_FIPS_PROVIDED; + inst->alg.cra_priority |= 4096; + } +#endif + larval = __crypto_register_alg(&inst->alg, &algs_to_put); if (IS_ERR(larval)) goto unlock; diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 25aadf5b6690..1dfd37761a4f 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -5771,15 +5771,23 @@ static int alg_fips_disabled(const char *driver, const char *alg) return -ECANCELED; } -static int alg_test_fips_disabled(const struct alg_test_desc *desc) +static int alg_test_fips_disabled(const struct crypto_alg *alg, const struct alg_test_desc *desc) { if (!fips_enabled) return 0; /* - * Only allow FIPS-allowed algorithms to be tested. + * If the algorithm is completely provided by the FIPS module + * we still require it to be allowed accoding to our test table. */ - return !(desc->fips_allowed & FIPS_ALLOWED); + if (alg->cra_flags & CRYPTO_ALG_FIPS_PROVIDED) + return !(desc->fips_allowed & FIPS_ALLOWED); + + /* + * If the algorithm is not provided by the FIPS module, then + * it must be FIPS_NON_CRYPTOGRAPHIC. + */ + return !(desc->fips_allowed & FIPS_NON_CRYPTOGRAPHIC); } int alg_test(struct crypto_alg *alg, const char *driver, const char *name, u32 type, u32 mask) @@ -5806,7 +5814,7 @@ int alg_test(struct crypto_alg *alg, const char *driver, const char *name, u32 t if (i < 0) goto notest; - if (alg_test_fips_disabled(&alg_test_descs[i])) + if (alg_test_fips_disabled(alg, &alg_test_descs[i])) goto non_fips_alg; rc = alg_test_cipher(alg_test_descs + i, driver, type, mask); @@ -5819,9 +5827,9 @@ int alg_test(struct crypto_alg *alg, const char *driver, const char *name, u32 t goto notest; if (fips_enabled) { - if (j >= 0 && alg_test_fips_disabled(&alg_test_descs[j])) + if (j >= 0 && alg_test_fips_disabled(alg, &alg_test_descs[j])) return -EINVAL; - if (i >= 0 && alg_test_fips_disabled(&alg_test_descs[i])) + if (i >= 0 && alg_test_fips_disabled(alg, &alg_test_descs[i])) goto non_fips_alg; } @@ -5865,7 +5873,7 @@ int alg_test(struct crypto_alg *alg, const char *driver, const char *name, u32 t if (i < 0) goto notest2; - if (alg_test_fips_disabled(&alg_test_descs[i])) + if (alg_test_fips_disabled(alg, &alg_test_descs[i])) goto non_fips_alg; rc = alg_test_skcipher(alg_test_descs + i, driver, type, mask); diff --git a/include/linux/crypto.h b/include/linux/crypto.h index a2137e19be7d..737e53a642d4 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -139,6 +139,14 @@ /* Set if the algorithm cannot have a fallback (e.g., phmac). */ #define CRYPTO_ALG_NO_FALLBACK 0x00080000 +/* + * The algorithm is provided by the FIPS module. + * + * NOTE: an algorithm can be provided by the FIPS module and not be + * approved, depending on the exact parameters like key size, etc. + */ +#define CRYPTO_ALG_FIPS_PROVIDED 0x00100000 + /* The high bits 0xff000000 are reserved for type-specific flags. */ /* -- 2.39.3