History

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.

Nicolai Stange committed 4 years ago

Commit d6097b81 parent c8e82365 files · +63 −10Browse files

Unified · Split

5 files
  1. crypto/algapi.c +16 −2
  2. crypto/api.c +17 −2
  3. crypto/tcrypt.c +2 −2
  4. crypto/testmgr.c +19 −4
  5. include/linux/crypto.h +9 −0
crypto/algapi.c+16−2
@@ -328,8 +328,16 @@ void crypto_alg_tested(const char *name, int err) · 327 unmodified lines
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, · 274 unmodified lines
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, · 16 unmodified lines
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, · 46 unmodified lines
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+17−2
@@ -223,6 +223,8 @@ static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) · 222 unmodified lines
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,6 +235,7 @@ static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) · 4 unmodified lines
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
@@ -240,8 +243,20 @@ static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, · 1 unmodified line
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+2−2
@@ -1473,8 +1473,8 @@ static inline int tcrypt_test(const char *alg) · 1472 unmodified lines
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+19−4
@@ -5650,6 +5650,13 @@ static int alg_find_test(const char *alg) · 5649 unmodified lines
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) · 30 unmodified lines
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 @@ test_done: · 23 unmodified lines
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+9−0
@@ -132,6 +132,15 @@ · 131 unmodified lines
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 */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t