Skip to content

Commit d6097b8

Browse files
nicstangeherbertx
authored andcommitted
crypto: api - allow algs only in specific constructions in FIPS mode
Currently we do not distinguish between algorithms that fail on the self-test vs. those which are disabled in FIPS mode (not allowed). Both are marked as having failed the self-test. Recently the need arose to allow the usage of certain algorithms only as arguments to specific template instantiations in FIPS mode. For example, standalone "dh" must be blocked, but e.g. "ffdhe2048(dh)" is allowed. Other potential use cases include "cbcmac(aes)", which must only be used with ccm(), or "ghash", which must be used only for gcm(). This patch allows this scenario by adding a new flag FIPS_INTERNAL to indicate those algorithms that are not FIPS-allowed. They can then be used as template arguments only, i.e. when looked up via crypto_grab_spawn() to be more specific. The FIPS_INTERNAL bit gets propagated upwards recursively into the surrounding template instances, until the construction eventually matches an explicit testmgr entry with ->fips_allowed being set, if any. The behaviour to skip !->fips_allowed self-test executions in FIPS mode will be retained. Note that this effectively means that FIPS_INTERNAL algorithms are handled very similarly to the INTERNAL ones in this regard. It is expected that the FIPS_INTERNAL algorithms will receive sufficient testing when the larger constructions they're a part of, if any, get exercised by testmgr. Note that as a side-effect of this patch algorithms which are not FIPS-allowed will now return ENOENT instead of ELIBBAD. Hopefully this is not an issue as some people were relying on this already. Link: https://lore.kernel.org/r/[email protected] Originally-by: Herbert Xu <[email protected]> Signed-off-by: Nicolai Stange <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent c8e8236 commit d6097b8

File tree

5 files changed

+63
-10
lines changed

5 files changed

+63
-10
lines changed

crypto/algapi.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,16 @@ void crypto_alg_tested(const char *name, int err)
328328
found:
329329
q->cra_flags |= CRYPTO_ALG_DEAD;
330330
alg = test->adult;
331-
if (err || list_empty(&alg->cra_list))
331+
332+
if (list_empty(&alg->cra_list))
333+
goto complete;
334+
335+
if (err == -ECANCELED)
336+
alg->cra_flags |= CRYPTO_ALG_FIPS_INTERNAL;
337+
else if (err)
332338
goto complete;
339+
else
340+
alg->cra_flags &= ~CRYPTO_ALG_FIPS_INTERNAL;
333341

334342
alg->cra_flags |= CRYPTO_ALG_TESTED;
335343

@@ -610,6 +618,7 @@ int crypto_register_instance(struct crypto_template *tmpl,
610618
{
611619
struct crypto_larval *larval;
612620
struct crypto_spawn *spawn;
621+
u32 fips_internal = 0;
613622
int err;
614623

615624
err = crypto_check_alg(&inst->alg);
@@ -632,11 +641,15 @@ int crypto_register_instance(struct crypto_template *tmpl,
632641
spawn->inst = inst;
633642
spawn->registered = true;
634643

644+
fips_internal |= spawn->alg->cra_flags;
645+
635646
crypto_mod_put(spawn->alg);
636647

637648
spawn = next;
638649
}
639650

651+
inst->alg.cra_flags |= (fips_internal & CRYPTO_ALG_FIPS_INTERNAL);
652+
640653
larval = __crypto_register_alg(&inst->alg);
641654
if (IS_ERR(larval))
642655
goto unlock;
@@ -689,7 +702,8 @@ int crypto_grab_spawn(struct crypto_spawn *spawn, struct crypto_instance *inst,
689702
if (IS_ERR(name))
690703
return PTR_ERR(name);
691704

692-
alg = crypto_find_alg(name, spawn->frontend, type, mask);
705+
alg = crypto_find_alg(name, spawn->frontend,
706+
type | CRYPTO_ALG_FIPS_INTERNAL, mask);
693707
if (IS_ERR(alg))
694708
return PTR_ERR(alg);
695709

crypto/api.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
223223
else if (crypto_is_test_larval(larval) &&
224224
!(alg->cra_flags & CRYPTO_ALG_TESTED))
225225
alg = ERR_PTR(-EAGAIN);
226+
else if (alg->cra_flags & CRYPTO_ALG_FIPS_INTERNAL)
227+
alg = ERR_PTR(-EAGAIN);
226228
else if (!crypto_mod_get(alg))
227229
alg = ERR_PTR(-EAGAIN);
228230
crypto_mod_put(&larval->alg);
@@ -233,15 +235,28 @@ static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
233235
static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type,
234236
u32 mask)
235237
{
238+
const u32 fips = CRYPTO_ALG_FIPS_INTERNAL;
236239
struct crypto_alg *alg;
237240
u32 test = 0;
238241

239242
if (!((type | mask) & CRYPTO_ALG_TESTED))
240243
test |= CRYPTO_ALG_TESTED;
241244

242245
down_read(&crypto_alg_sem);
243-
alg = __crypto_alg_lookup(name, type | test, mask | test);
244-
if (!alg && test) {
246+
alg = __crypto_alg_lookup(name, (type | test) & ~fips,
247+
(mask | test) & ~fips);
248+
if (alg) {
249+
if (((type | mask) ^ fips) & fips)
250+
mask |= fips;
251+
mask &= fips;
252+
253+
if (!crypto_is_larval(alg) &&
254+
((type ^ alg->cra_flags) & mask)) {
255+
/* Algorithm is disallowed in FIPS mode. */
256+
crypto_mod_put(alg);
257+
alg = ERR_PTR(-ENOENT);
258+
}
259+
} else if (test) {
245260
alg = __crypto_alg_lookup(name, type, mask);
246261
if (alg && !crypto_is_larval(alg)) {
247262
/* Test failed */

crypto/tcrypt.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,8 +1473,8 @@ static inline int tcrypt_test(const char *alg)
14731473
pr_debug("testing %s\n", alg);
14741474

14751475
ret = alg_test(alg, alg, 0, 0);
1476-
/* non-fips algs return -EINVAL in fips mode */
1477-
if (fips_enabled && ret == -EINVAL)
1476+
/* non-fips algs return -EINVAL or -ECANCELED in fips mode */
1477+
if (fips_enabled && (ret == -EINVAL || ret == -ECANCELED))
14781478
ret = 0;
14791479
return ret;
14801480
}

crypto/testmgr.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5650,6 +5650,13 @@ static int alg_find_test(const char *alg)
56505650
return -1;
56515651
}
56525652

5653+
static int alg_fips_disabled(const char *driver, const char *alg)
5654+
{
5655+
pr_info("alg: %s (%s) is disabled due to FIPS\n", alg, driver);
5656+
5657+
return -ECANCELED;
5658+
}
5659+
56535660
int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
56545661
{
56555662
int i;
@@ -5686,9 +5693,13 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
56865693
if (i < 0 && j < 0)
56875694
goto notest;
56885695

5689-
if (fips_enabled && ((i >= 0 && !alg_test_descs[i].fips_allowed) ||
5690-
(j >= 0 && !alg_test_descs[j].fips_allowed)))
5691-
goto non_fips_alg;
5696+
if (fips_enabled) {
5697+
if (j >= 0 && !alg_test_descs[j].fips_allowed)
5698+
return -EINVAL;
5699+
5700+
if (i >= 0 && !alg_test_descs[i].fips_allowed)
5701+
goto non_fips_alg;
5702+
}
56925703

56935704
rc = 0;
56945705
if (i >= 0)
@@ -5718,9 +5729,13 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
57185729

57195730
notest:
57205731
printk(KERN_INFO "alg: No test for %s (%s)\n", alg, driver);
5732+
5733+
if (type & CRYPTO_ALG_FIPS_INTERNAL)
5734+
return alg_fips_disabled(driver, alg);
5735+
57215736
return 0;
57225737
non_fips_alg:
5723-
return -EINVAL;
5738+
return alg_fips_disabled(driver, alg);
57245739
}
57255740

57265741
#endif /* CONFIG_CRYPTO_MANAGER_DISABLE_TESTS */

include/linux/crypto.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,15 @@
132132
*/
133133
#define CRYPTO_ALG_ALLOCATES_MEMORY 0x00010000
134134

135+
/*
136+
* Mark an algorithm as a service implementation only usable by a
137+
* template and never by a normal user of the kernel crypto API.
138+
* This is intended to be used by algorithms that are themselves
139+
* not FIPS-approved but may instead be used to implement parts of
140+
* a FIPS-approved algorithm (e.g., dh vs. ffdhe2048(dh)).
141+
*/
142+
#define CRYPTO_ALG_FIPS_INTERNAL 0x00020000
143+
135144
/*
136145
* Transform masks and values (for crt_flags).
137146
*/

0 commit comments

Comments
 (0)