12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2cce9e06dSHerbert Xu /*
3cce9e06dSHerbert Xu * Cryptographic API for algorithms (i.e., low-level API).
4cce9e06dSHerbert Xu *
5cce9e06dSHerbert Xu * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
6cce9e06dSHerbert Xu */
7cce9e06dSHerbert Xu
813c935bbSSalvatore Mesoraca #include <crypto/algapi.h>
98fc5f2adSHerbert Xu #include <crypto/internal/simd.h>
106bfd4809SHerbert Xu #include <linux/err.h>
11cce9e06dSHerbert Xu #include <linux/errno.h>
123133d76fSHerbert Xu #include <linux/fips.h>
13cce9e06dSHerbert Xu #include <linux/init.h>
14cce9e06dSHerbert Xu #include <linux/kernel.h>
154cc7720cSHerbert Xu #include <linux/list.h>
16cce9e06dSHerbert Xu #include <linux/module.h>
177fed0bf2SHerbert Xu #include <linux/rtnetlink.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
19cce9e06dSHerbert Xu #include <linux/string.h>
209ae4577bSHerbert Xu #include <linux/workqueue.h>
21cce9e06dSHerbert Xu
22cce9e06dSHerbert Xu #include "internal.h"
23cce9e06dSHerbert Xu
244cc7720cSHerbert Xu static LIST_HEAD(crypto_template_list);
254cc7720cSHerbert Xu
268fc5f2adSHerbert Xu #ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS
278fc5f2adSHerbert Xu DEFINE_PER_CPU(bool, crypto_simd_disabled_for_test);
288fc5f2adSHerbert Xu EXPORT_PER_CPU_SYMBOL_GPL(crypto_simd_disabled_for_test);
298fc5f2adSHerbert Xu #endif
308fc5f2adSHerbert Xu
crypto_check_module_sig(struct module * mod)31002c77a4SJarod Wilson static inline void crypto_check_module_sig(struct module *mod)
32002c77a4SJarod Wilson {
3359afdc7bSHerbert Xu if (fips_enabled && mod && !module_sig_ok(mod))
34002c77a4SJarod Wilson panic("Module %s signature verification failed in FIPS mode\n",
35bd4a7c69SHerbert Xu module_name(mod));
36002c77a4SJarod Wilson }
37002c77a4SJarod Wilson
crypto_check_alg(struct crypto_alg * alg)384cc7720cSHerbert Xu static int crypto_check_alg(struct crypto_alg *alg)
39cce9e06dSHerbert Xu {
40002c77a4SJarod Wilson crypto_check_module_sig(alg->cra_module);
41002c77a4SJarod Wilson
42177f87d0SEric Biggers if (!alg->cra_name[0] || !alg->cra_driver_name[0])
43177f87d0SEric Biggers return -EINVAL;
44177f87d0SEric Biggers
45cce9e06dSHerbert Xu if (alg->cra_alignmask & (alg->cra_alignmask + 1))
46cce9e06dSHerbert Xu return -EINVAL;
47cce9e06dSHerbert Xu
48a9f7f88aSKees Cook /* General maximums for all algs. */
49a9f7f88aSKees Cook if (alg->cra_alignmask > MAX_ALGAPI_ALIGNMASK)
50cce9e06dSHerbert Xu return -EINVAL;
51cce9e06dSHerbert Xu
52a9f7f88aSKees Cook if (alg->cra_blocksize > MAX_ALGAPI_BLOCKSIZE)
53a9f7f88aSKees Cook return -EINVAL;
54a9f7f88aSKees Cook
55a9f7f88aSKees Cook /* Lower maximums for specific alg types. */
5613c935bbSSalvatore Mesoraca if (!alg->cra_type && (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
5713c935bbSSalvatore Mesoraca CRYPTO_ALG_TYPE_CIPHER) {
5813c935bbSSalvatore Mesoraca if (alg->cra_alignmask > MAX_CIPHER_ALIGNMASK)
5913c935bbSSalvatore Mesoraca return -EINVAL;
6013c935bbSSalvatore Mesoraca
6113c935bbSSalvatore Mesoraca if (alg->cra_blocksize > MAX_CIPHER_BLOCKSIZE)
6213c935bbSSalvatore Mesoraca return -EINVAL;
6313c935bbSSalvatore Mesoraca }
6413c935bbSSalvatore Mesoraca
65cce9e06dSHerbert Xu if (alg->cra_priority < 0)
66cce9e06dSHerbert Xu return -EINVAL;
67cce9e06dSHerbert Xu
68ce8614a3SEric Biggers refcount_set(&alg->cra_refcnt, 1);
69e9b8e5beSHerbert Xu
70177f87d0SEric Biggers return 0;
714cc7720cSHerbert Xu }
72cce9e06dSHerbert Xu
crypto_free_instance(struct crypto_instance * inst)73319382a6SHerbert Xu static void crypto_free_instance(struct crypto_instance *inst)
74319382a6SHerbert Xu {
75319382a6SHerbert Xu inst->alg.cra_type->free(inst);
76319382a6SHerbert Xu }
77319382a6SHerbert Xu
crypto_destroy_instance_workfn(struct work_struct * w)789ae4577bSHerbert Xu static void crypto_destroy_instance_workfn(struct work_struct *w)
796bfd4809SHerbert Xu {
809ae4577bSHerbert Xu struct crypto_instance *inst = container_of(w, struct crypto_instance,
819ae4577bSHerbert Xu free_work);
826bfd4809SHerbert Xu struct crypto_template *tmpl = inst->tmpl;
836bfd4809SHerbert Xu
84319382a6SHerbert Xu crypto_free_instance(inst);
856bfd4809SHerbert Xu crypto_tmpl_put(tmpl);
866bfd4809SHerbert Xu }
876bfd4809SHerbert Xu
crypto_destroy_instance(struct crypto_alg * alg)889ae4577bSHerbert Xu static void crypto_destroy_instance(struct crypto_alg *alg)
899ae4577bSHerbert Xu {
909ae4577bSHerbert Xu struct crypto_instance *inst = container_of(alg,
919ae4577bSHerbert Xu struct crypto_instance,
929ae4577bSHerbert Xu alg);
939ae4577bSHerbert Xu
949ae4577bSHerbert Xu INIT_WORK(&inst->free_work, crypto_destroy_instance_workfn);
959ae4577bSHerbert Xu schedule_work(&inst->free_work);
969ae4577bSHerbert Xu }
979ae4577bSHerbert Xu
9802244ba4SHerbert Xu /*
9902244ba4SHerbert Xu * This function adds a spawn to the list secondary_spawns which
10002244ba4SHerbert Xu * will be used at the end of crypto_remove_spawns to unregister
10102244ba4SHerbert Xu * instances, unless the spawn happens to be one that is depended
10202244ba4SHerbert Xu * on by the new algorithm (nalg in crypto_remove_spawns).
10302244ba4SHerbert Xu *
10402244ba4SHerbert Xu * This function is also responsible for resurrecting any algorithms
10502244ba4SHerbert Xu * in the dependency chain of nalg by unsetting n->dead.
10602244ba4SHerbert Xu */
crypto_more_spawns(struct crypto_alg * alg,struct list_head * stack,struct list_head * top,struct list_head * secondary_spawns)1072bf29016SHerbert Xu static struct list_head *crypto_more_spawns(struct crypto_alg *alg,
1082bf29016SHerbert Xu struct list_head *stack,
1092bf29016SHerbert Xu struct list_head *top,
110a73e6996SHerbert Xu struct list_head *secondary_spawns)
1116bfd4809SHerbert Xu {
1122bf29016SHerbert Xu struct crypto_spawn *spawn, *n;
1132bf29016SHerbert Xu
114304e4818SGeliang Tang spawn = list_first_entry_or_null(stack, struct crypto_spawn, list);
115304e4818SGeliang Tang if (!spawn)
1162bf29016SHerbert Xu return NULL;
1172bf29016SHerbert Xu
1184f87ee11SHerbert Xu n = list_prev_entry(spawn, list);
1192bf29016SHerbert Xu list_move(&spawn->list, secondary_spawns);
1202bf29016SHerbert Xu
1214f87ee11SHerbert Xu if (list_is_last(&n->list, stack))
1224f87ee11SHerbert Xu return top;
1234f87ee11SHerbert Xu
1244f87ee11SHerbert Xu n = list_next_entry(n, list);
1254f87ee11SHerbert Xu if (!spawn->dead)
1264f87ee11SHerbert Xu n->dead = false;
1274f87ee11SHerbert Xu
1284f87ee11SHerbert Xu return &n->inst->alg.cra_users;
1292bf29016SHerbert Xu }
1302bf29016SHerbert Xu
crypto_remove_instance(struct crypto_instance * inst,struct list_head * list)1311f723710SHerbert Xu static void crypto_remove_instance(struct crypto_instance *inst,
1322bf29016SHerbert Xu struct list_head *list)
1332bf29016SHerbert Xu {
1346bfd4809SHerbert Xu struct crypto_template *tmpl = inst->tmpl;
1356bfd4809SHerbert Xu
1366bfd4809SHerbert Xu if (crypto_is_dead(&inst->alg))
137a73e6996SHerbert Xu return;
1386bfd4809SHerbert Xu
1396bfd4809SHerbert Xu inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
14038cb2419SHerbert Xu
1416bfd4809SHerbert Xu if (!tmpl || !crypto_tmpl_get(tmpl))
142a73e6996SHerbert Xu return;
1436bfd4809SHerbert Xu
1446bfd4809SHerbert Xu list_move(&inst->alg.cra_list, list);
1456bfd4809SHerbert Xu hlist_del(&inst->list);
1466bfd4809SHerbert Xu inst->alg.cra_destroy = crypto_destroy_instance;
1476bfd4809SHerbert Xu
1482bf29016SHerbert Xu BUG_ON(!list_empty(&inst->alg.cra_users));
1496bfd4809SHerbert Xu }
150a73e6996SHerbert Xu
15102244ba4SHerbert Xu /*
15202244ba4SHerbert Xu * Given an algorithm alg, remove all algorithms that depend on it
15302244ba4SHerbert Xu * through spawns. If nalg is not null, then exempt any algorithms
15402244ba4SHerbert Xu * that is depended on by nalg. This is useful when nalg itself
15502244ba4SHerbert Xu * depends on alg.
15602244ba4SHerbert Xu */
crypto_remove_spawns(struct crypto_alg * alg,struct list_head * list,struct crypto_alg * nalg)15789b596baSSteffen Klassert void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
1582bf29016SHerbert Xu struct crypto_alg *nalg)
159a73e6996SHerbert Xu {
1602bf29016SHerbert Xu u32 new_type = (nalg ?: alg)->cra_flags;
161a73e6996SHerbert Xu struct crypto_spawn *spawn, *n;
162a73e6996SHerbert Xu LIST_HEAD(secondary_spawns);
1632bf29016SHerbert Xu struct list_head *spawns;
1642bf29016SHerbert Xu LIST_HEAD(stack);
1652bf29016SHerbert Xu LIST_HEAD(top);
166a73e6996SHerbert Xu
1672bf29016SHerbert Xu spawns = &alg->cra_users;
168a73e6996SHerbert Xu list_for_each_entry_safe(spawn, n, spawns, list) {
169a73e6996SHerbert Xu if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
170a73e6996SHerbert Xu continue;
171a73e6996SHerbert Xu
1722bf29016SHerbert Xu list_move(&spawn->list, &top);
173a73e6996SHerbert Xu }
174a73e6996SHerbert Xu
17502244ba4SHerbert Xu /*
17602244ba4SHerbert Xu * Perform a depth-first walk starting from alg through
17702244ba4SHerbert Xu * the cra_users tree. The list stack records the path
17802244ba4SHerbert Xu * from alg to the current spawn.
17902244ba4SHerbert Xu */
1802bf29016SHerbert Xu spawns = ⊤
1812bf29016SHerbert Xu do {
1822bf29016SHerbert Xu while (!list_empty(spawns)) {
1832bf29016SHerbert Xu struct crypto_instance *inst;
1842bf29016SHerbert Xu
1852bf29016SHerbert Xu spawn = list_first_entry(spawns, struct crypto_spawn,
1862bf29016SHerbert Xu list);
1872bf29016SHerbert Xu inst = spawn->inst;
1882bf29016SHerbert Xu
1892bf29016SHerbert Xu list_move(&spawn->list, &stack);
1905f567fffSHerbert Xu spawn->dead = !spawn->registered || &inst->alg != nalg;
1915f567fffSHerbert Xu
1925f567fffSHerbert Xu if (!spawn->registered)
1935f567fffSHerbert Xu break;
1945f567fffSHerbert Xu
1955f567fffSHerbert Xu BUG_ON(&inst->alg == alg);
1962bf29016SHerbert Xu
1972bf29016SHerbert Xu if (&inst->alg == nalg)
1982bf29016SHerbert Xu break;
1992bf29016SHerbert Xu
2002bf29016SHerbert Xu spawns = &inst->alg.cra_users;
2019a006742SEric Biggers
2029a006742SEric Biggers /*
2035f567fffSHerbert Xu * Even if spawn->registered is true, the
2045f567fffSHerbert Xu * instance itself may still be unregistered.
2055f567fffSHerbert Xu * This is because it may have failed during
2065f567fffSHerbert Xu * registration. Therefore we still need to
2075f567fffSHerbert Xu * make the following test.
2085f567fffSHerbert Xu *
2099a006742SEric Biggers * We may encounter an unregistered instance here, since
2109a006742SEric Biggers * an instance's spawns are set up prior to the instance
2119a006742SEric Biggers * being registered. An unregistered instance will have
2129a006742SEric Biggers * NULL ->cra_users.next, since ->cra_users isn't
2139a006742SEric Biggers * properly initialized until registration. But an
2149a006742SEric Biggers * unregistered instance cannot have any users, so treat
2159a006742SEric Biggers * it the same as ->cra_users being empty.
2169a006742SEric Biggers */
2179a006742SEric Biggers if (spawns->next == NULL)
2189a006742SEric Biggers break;
2192bf29016SHerbert Xu }
2202bf29016SHerbert Xu } while ((spawns = crypto_more_spawns(alg, &stack, &top,
2212bf29016SHerbert Xu &secondary_spawns)));
2222bf29016SHerbert Xu
22302244ba4SHerbert Xu /*
22402244ba4SHerbert Xu * Remove all instances that are marked as dead. Also
22502244ba4SHerbert Xu * complete the resurrection of the others by moving them
22602244ba4SHerbert Xu * back to the cra_users list.
22702244ba4SHerbert Xu */
2282bf29016SHerbert Xu list_for_each_entry_safe(spawn, n, &secondary_spawns, list) {
2294f87ee11SHerbert Xu if (!spawn->dead)
2302bf29016SHerbert Xu list_move(&spawn->list, &spawn->alg->cra_users);
2315f567fffSHerbert Xu else if (spawn->registered)
2321f723710SHerbert Xu crypto_remove_instance(spawn->inst, list);
2336bfd4809SHerbert Xu }
2346bfd4809SHerbert Xu }
23589b596baSSteffen Klassert EXPORT_SYMBOL_GPL(crypto_remove_spawns);
2366bfd4809SHerbert Xu
crypto_alg_finish_registration(struct crypto_alg * alg,bool fulfill_requests,struct list_head * algs_to_put)237a7008584SEric Biggers static void crypto_alg_finish_registration(struct crypto_alg *alg,
238a7008584SEric Biggers bool fulfill_requests,
239a7008584SEric Biggers struct list_head *algs_to_put)
240a7008584SEric Biggers {
241a7008584SEric Biggers struct crypto_alg *q;
242a7008584SEric Biggers
243a7008584SEric Biggers list_for_each_entry(q, &crypto_alg_list, cra_list) {
244a7008584SEric Biggers if (q == alg)
245a7008584SEric Biggers continue;
246a7008584SEric Biggers
247a7008584SEric Biggers if (crypto_is_moribund(q))
248a7008584SEric Biggers continue;
249a7008584SEric Biggers
250a7008584SEric Biggers if (crypto_is_larval(q)) {
251a7008584SEric Biggers struct crypto_larval *larval = (void *)q;
252a7008584SEric Biggers
253a7008584SEric Biggers /*
254a7008584SEric Biggers * Check to see if either our generic name or
255a7008584SEric Biggers * specific name can satisfy the name requested
256a7008584SEric Biggers * by the larval entry q.
257a7008584SEric Biggers */
258a7008584SEric Biggers if (strcmp(alg->cra_name, q->cra_name) &&
259a7008584SEric Biggers strcmp(alg->cra_driver_name, q->cra_name))
260a7008584SEric Biggers continue;
261a7008584SEric Biggers
262a7008584SEric Biggers if (larval->adult)
263a7008584SEric Biggers continue;
264a7008584SEric Biggers if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
265a7008584SEric Biggers continue;
266a7008584SEric Biggers
267a7008584SEric Biggers if (fulfill_requests && crypto_mod_get(alg))
268a7008584SEric Biggers larval->adult = alg;
269a7008584SEric Biggers else
270a7008584SEric Biggers larval->adult = ERR_PTR(-EAGAIN);
271a7008584SEric Biggers
272a7008584SEric Biggers continue;
273a7008584SEric Biggers }
274a7008584SEric Biggers
275a7008584SEric Biggers if (strcmp(alg->cra_name, q->cra_name))
276a7008584SEric Biggers continue;
277a7008584SEric Biggers
278a7008584SEric Biggers if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
279a7008584SEric Biggers q->cra_priority > alg->cra_priority)
280a7008584SEric Biggers continue;
281a7008584SEric Biggers
282a7008584SEric Biggers crypto_remove_spawns(q, algs_to_put, alg);
283a7008584SEric Biggers }
284a7008584SEric Biggers
285a7008584SEric Biggers crypto_notify(CRYPTO_MSG_ALG_LOADED, alg);
286a7008584SEric Biggers }
287a7008584SEric Biggers
crypto_alloc_test_larval(struct crypto_alg * alg)288cad439fcSHerbert Xu static struct crypto_larval *crypto_alloc_test_larval(struct crypto_alg *alg)
289cad439fcSHerbert Xu {
290cad439fcSHerbert Xu struct crypto_larval *larval;
291cad439fcSHerbert Xu
292a7008584SEric Biggers if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER) ||
2939cadd73aSEric Biggers IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) ||
2949cadd73aSEric Biggers (alg->cra_flags & CRYPTO_ALG_INTERNAL))
295a7008584SEric Biggers return NULL; /* No self-test needed */
296cad439fcSHerbert Xu
297cad439fcSHerbert Xu larval = crypto_larval_alloc(alg->cra_name,
298cad439fcSHerbert Xu alg->cra_flags | CRYPTO_ALG_TESTED, 0);
299cad439fcSHerbert Xu if (IS_ERR(larval))
300cad439fcSHerbert Xu return larval;
301cad439fcSHerbert Xu
302cad439fcSHerbert Xu larval->adult = crypto_mod_get(alg);
303cad439fcSHerbert Xu if (!larval->adult) {
304cad439fcSHerbert Xu kfree(larval);
305cad439fcSHerbert Xu return ERR_PTR(-ENOENT);
306cad439fcSHerbert Xu }
307cad439fcSHerbert Xu
308cad439fcSHerbert Xu refcount_set(&larval->alg.cra_refcnt, 1);
309cad439fcSHerbert Xu memcpy(larval->alg.cra_driver_name, alg->cra_driver_name,
310cad439fcSHerbert Xu CRYPTO_MAX_ALG_NAME);
311cad439fcSHerbert Xu larval->alg.cra_priority = alg->cra_priority;
312cad439fcSHerbert Xu
313cad439fcSHerbert Xu return larval;
314cad439fcSHerbert Xu }
315cad439fcSHerbert Xu
316a7008584SEric Biggers static struct crypto_larval *
__crypto_register_alg(struct crypto_alg * alg,struct list_head * algs_to_put)317a7008584SEric Biggers __crypto_register_alg(struct crypto_alg *alg, struct list_head *algs_to_put)
3184cc7720cSHerbert Xu {
3194cc7720cSHerbert Xu struct crypto_alg *q;
32073d3864aSHerbert Xu struct crypto_larval *larval;
3216bfd4809SHerbert Xu int ret = -EAGAIN;
3226bfd4809SHerbert Xu
3236bfd4809SHerbert Xu if (crypto_is_dead(alg))
32473d3864aSHerbert Xu goto err;
3256bfd4809SHerbert Xu
3266bfd4809SHerbert Xu INIT_LIST_HEAD(&alg->cra_users);
3276bfd4809SHerbert Xu
3286bfd4809SHerbert Xu ret = -EEXIST;
329cce9e06dSHerbert Xu
330cce9e06dSHerbert Xu list_for_each_entry(q, &crypto_alg_list, cra_list) {
3314cc7720cSHerbert Xu if (q == alg)
33273d3864aSHerbert Xu goto err;
33373d3864aSHerbert Xu
334b8e15992SHerbert Xu if (crypto_is_moribund(q))
335b8e15992SHerbert Xu continue;
336b8e15992SHerbert Xu
33773d3864aSHerbert Xu if (crypto_is_larval(q)) {
33873d3864aSHerbert Xu if (!strcmp(alg->cra_driver_name, q->cra_driver_name))
33973d3864aSHerbert Xu goto err;
34073d3864aSHerbert Xu continue;
34173d3864aSHerbert Xu }
34273d3864aSHerbert Xu
34373d3864aSHerbert Xu if (!strcmp(q->cra_driver_name, alg->cra_name) ||
344b1a67a0dSHerbert Xu !strcmp(q->cra_driver_name, alg->cra_driver_name) ||
34573d3864aSHerbert Xu !strcmp(q->cra_name, alg->cra_driver_name))
34673d3864aSHerbert Xu goto err;
34773d3864aSHerbert Xu }
34873d3864aSHerbert Xu
349cad439fcSHerbert Xu larval = crypto_alloc_test_larval(alg);
35073d3864aSHerbert Xu if (IS_ERR(larval))
351cce9e06dSHerbert Xu goto out;
3526bfd4809SHerbert Xu
35373d3864aSHerbert Xu list_add(&alg->cra_list, &crypto_alg_list);
354cad439fcSHerbert Xu
355a7008584SEric Biggers if (larval) {
356a7008584SEric Biggers /* No cheating! */
357a7008584SEric Biggers alg->cra_flags &= ~CRYPTO_ALG_TESTED;
358a7008584SEric Biggers
359a7008584SEric Biggers list_add(&larval->alg.cra_list, &crypto_alg_list);
360a7008584SEric Biggers } else {
361a7008584SEric Biggers alg->cra_flags |= CRYPTO_ALG_TESTED;
362a7008584SEric Biggers crypto_alg_finish_registration(alg, true, algs_to_put);
363a7008584SEric Biggers }
364a7008584SEric Biggers
36573d3864aSHerbert Xu out:
36673d3864aSHerbert Xu return larval;
36773d3864aSHerbert Xu
36873d3864aSHerbert Xu err:
36973d3864aSHerbert Xu larval = ERR_PTR(ret);
37073d3864aSHerbert Xu goto out;
37173d3864aSHerbert Xu }
37273d3864aSHerbert Xu
crypto_alg_tested(const char * name,int err)37373d3864aSHerbert Xu void crypto_alg_tested(const char *name, int err)
37473d3864aSHerbert Xu {
37573d3864aSHerbert Xu struct crypto_larval *test;
37673d3864aSHerbert Xu struct crypto_alg *alg;
37773d3864aSHerbert Xu struct crypto_alg *q;
37873d3864aSHerbert Xu LIST_HEAD(list);
3792bbb3375SHerbert Xu bool best;
38073d3864aSHerbert Xu
38173d3864aSHerbert Xu down_write(&crypto_alg_sem);
38273d3864aSHerbert Xu list_for_each_entry(q, &crypto_alg_list, cra_list) {
383b8e15992SHerbert Xu if (crypto_is_moribund(q) || !crypto_is_larval(q))
38473d3864aSHerbert Xu continue;
38573d3864aSHerbert Xu
38673d3864aSHerbert Xu test = (struct crypto_larval *)q;
38773d3864aSHerbert Xu
38873d3864aSHerbert Xu if (!strcmp(q->cra_driver_name, name))
38973d3864aSHerbert Xu goto found;
39073d3864aSHerbert Xu }
39173d3864aSHerbert Xu
392c7235857SKarim Eshapa pr_err("alg: Unexpected test result for %s: %d\n", name, err);
39373d3864aSHerbert Xu goto unlock;
39473d3864aSHerbert Xu
39573d3864aSHerbert Xu found:
396b8e15992SHerbert Xu q->cra_flags |= CRYPTO_ALG_DEAD;
39773d3864aSHerbert Xu alg = test->adult;
398d6097b8dSNicolai Stange
399*83394e7dSHerbert Xu if (crypto_is_dead(alg))
40073d3864aSHerbert Xu goto complete;
40173d3864aSHerbert Xu
402d6097b8dSNicolai Stange if (err == -ECANCELED)
403d6097b8dSNicolai Stange alg->cra_flags |= CRYPTO_ALG_FIPS_INTERNAL;
404d6097b8dSNicolai Stange else if (err)
405d6097b8dSNicolai Stange goto complete;
406d6097b8dSNicolai Stange else
407d6097b8dSNicolai Stange alg->cra_flags &= ~CRYPTO_ALG_FIPS_INTERNAL;
408d6097b8dSNicolai Stange
40973d3864aSHerbert Xu alg->cra_flags |= CRYPTO_ALG_TESTED;
41073d3864aSHerbert Xu
411a7008584SEric Biggers /*
412a7008584SEric Biggers * If a higher-priority implementation of the same algorithm is
413a7008584SEric Biggers * currently being tested, then don't fulfill request larvals.
414a7008584SEric Biggers */
4152bbb3375SHerbert Xu best = true;
4162bbb3375SHerbert Xu list_for_each_entry(q, &crypto_alg_list, cra_list) {
4172bbb3375SHerbert Xu if (crypto_is_moribund(q) || !crypto_is_larval(q))
4182bbb3375SHerbert Xu continue;
4192bbb3375SHerbert Xu
4202bbb3375SHerbert Xu if (strcmp(alg->cra_name, q->cra_name))
4212bbb3375SHerbert Xu continue;
4222bbb3375SHerbert Xu
4232bbb3375SHerbert Xu if (q->cra_priority > alg->cra_priority) {
4242bbb3375SHerbert Xu best = false;
4252bbb3375SHerbert Xu break;
4262bbb3375SHerbert Xu }
4272bbb3375SHerbert Xu }
4282bbb3375SHerbert Xu
429a7008584SEric Biggers crypto_alg_finish_registration(alg, best, &list);
430cce9e06dSHerbert Xu
43173d3864aSHerbert Xu complete:
43273d3864aSHerbert Xu complete_all(&test->completion);
4332825982dSHerbert Xu
43473d3864aSHerbert Xu unlock:
43573d3864aSHerbert Xu up_write(&crypto_alg_sem);
4362825982dSHerbert Xu
43773d3864aSHerbert Xu crypto_remove_final(&list);
438cce9e06dSHerbert Xu }
43973d3864aSHerbert Xu EXPORT_SYMBOL_GPL(crypto_alg_tested);
4404cc7720cSHerbert Xu
crypto_remove_final(struct list_head * list)44122e5b20bSSteffen Klassert void crypto_remove_final(struct list_head *list)
4426bfd4809SHerbert Xu {
4436bfd4809SHerbert Xu struct crypto_alg *alg;
4446bfd4809SHerbert Xu struct crypto_alg *n;
4456bfd4809SHerbert Xu
4466bfd4809SHerbert Xu list_for_each_entry_safe(alg, n, list, cra_list) {
4476bfd4809SHerbert Xu list_del_init(&alg->cra_list);
4486bfd4809SHerbert Xu crypto_alg_put(alg);
4496bfd4809SHerbert Xu }
4506bfd4809SHerbert Xu }
45122e5b20bSSteffen Klassert EXPORT_SYMBOL_GPL(crypto_remove_final);
4526bfd4809SHerbert Xu
crypto_register_alg(struct crypto_alg * alg)4534cc7720cSHerbert Xu int crypto_register_alg(struct crypto_alg *alg)
4544cc7720cSHerbert Xu {
45573d3864aSHerbert Xu struct crypto_larval *larval;
456a7008584SEric Biggers LIST_HEAD(algs_to_put);
457a7008584SEric Biggers bool test_started = false;
4584cc7720cSHerbert Xu int err;
4594cc7720cSHerbert Xu
460d6040764SSalvatore Benedetto alg->cra_flags &= ~CRYPTO_ALG_DEAD;
4614cc7720cSHerbert Xu err = crypto_check_alg(alg);
4624cc7720cSHerbert Xu if (err)
4634cc7720cSHerbert Xu return err;
4644cc7720cSHerbert Xu
4654cc7720cSHerbert Xu down_write(&crypto_alg_sem);
466a7008584SEric Biggers larval = __crypto_register_alg(alg, &algs_to_put);
467a7008584SEric Biggers if (!IS_ERR_OR_NULL(larval)) {
46806bd9c96SEric Biggers test_started = crypto_boot_test_finished();
469adad556eSHerbert Xu larval->test_started = test_started;
470a7008584SEric Biggers }
4714cc7720cSHerbert Xu up_write(&crypto_alg_sem);
4724cc7720cSHerbert Xu
473a7008584SEric Biggers if (IS_ERR(larval))
47473d3864aSHerbert Xu return PTR_ERR(larval);
475adad556eSHerbert Xu if (test_started)
47673d3864aSHerbert Xu crypto_wait_for_test(larval);
477a7008584SEric Biggers crypto_remove_final(&algs_to_put);
47873d3864aSHerbert Xu return 0;
4794cc7720cSHerbert Xu }
480cce9e06dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_alg);
481cce9e06dSHerbert Xu
crypto_remove_alg(struct crypto_alg * alg,struct list_head * list)4826bfd4809SHerbert Xu static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
4836bfd4809SHerbert Xu {
4846bfd4809SHerbert Xu if (unlikely(list_empty(&alg->cra_list)))
4856bfd4809SHerbert Xu return -ENOENT;
4866bfd4809SHerbert Xu
4876bfd4809SHerbert Xu alg->cra_flags |= CRYPTO_ALG_DEAD;
4886bfd4809SHerbert Xu
4896bfd4809SHerbert Xu list_del_init(&alg->cra_list);
4902bf29016SHerbert Xu crypto_remove_spawns(alg, list, NULL);
4916bfd4809SHerbert Xu
4926bfd4809SHerbert Xu return 0;
4936bfd4809SHerbert Xu }
4946bfd4809SHerbert Xu
crypto_unregister_alg(struct crypto_alg * alg)495c6d633a9SEric Biggers void crypto_unregister_alg(struct crypto_alg *alg)
496cce9e06dSHerbert Xu {
4976bfd4809SHerbert Xu int ret;
4986bfd4809SHerbert Xu LIST_HEAD(list);
499cce9e06dSHerbert Xu
500cce9e06dSHerbert Xu down_write(&crypto_alg_sem);
5016bfd4809SHerbert Xu ret = crypto_remove_alg(alg, &list);
502cce9e06dSHerbert Xu up_write(&crypto_alg_sem);
503cce9e06dSHerbert Xu
504c6d633a9SEric Biggers if (WARN(ret, "Algorithm %s is not registered", alg->cra_driver_name))
505c6d633a9SEric Biggers return;
506cce9e06dSHerbert Xu
507a543ada7SToke Høiland-Jørgensen if (WARN_ON(refcount_read(&alg->cra_refcnt) != 1))
508a543ada7SToke Høiland-Jørgensen return;
509a543ada7SToke Høiland-Jørgensen
510cce9e06dSHerbert Xu if (alg->cra_destroy)
511cce9e06dSHerbert Xu alg->cra_destroy(alg);
512cce9e06dSHerbert Xu
5136bfd4809SHerbert Xu crypto_remove_final(&list);
514cce9e06dSHerbert Xu }
515cce9e06dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_alg);
516cce9e06dSHerbert Xu
crypto_register_algs(struct crypto_alg * algs,int count)5174b004346SMark Brown int crypto_register_algs(struct crypto_alg *algs, int count)
5184b004346SMark Brown {
5194b004346SMark Brown int i, ret;
5204b004346SMark Brown
5214b004346SMark Brown for (i = 0; i < count; i++) {
5224b004346SMark Brown ret = crypto_register_alg(&algs[i]);
5234b004346SMark Brown if (ret)
5244b004346SMark Brown goto err;
5254b004346SMark Brown }
5264b004346SMark Brown
5274b004346SMark Brown return 0;
5284b004346SMark Brown
5294b004346SMark Brown err:
5304b004346SMark Brown for (--i; i >= 0; --i)
5314b004346SMark Brown crypto_unregister_alg(&algs[i]);
5324b004346SMark Brown
5334b004346SMark Brown return ret;
5344b004346SMark Brown }
5354b004346SMark Brown EXPORT_SYMBOL_GPL(crypto_register_algs);
5364b004346SMark Brown
crypto_unregister_algs(struct crypto_alg * algs,int count)537c6d633a9SEric Biggers void crypto_unregister_algs(struct crypto_alg *algs, int count)
5384b004346SMark Brown {
539c6d633a9SEric Biggers int i;
5404b004346SMark Brown
541c6d633a9SEric Biggers for (i = 0; i < count; i++)
542c6d633a9SEric Biggers crypto_unregister_alg(&algs[i]);
5434b004346SMark Brown }
5444b004346SMark Brown EXPORT_SYMBOL_GPL(crypto_unregister_algs);
5454b004346SMark Brown
crypto_register_template(struct crypto_template * tmpl)5464cc7720cSHerbert Xu int crypto_register_template(struct crypto_template *tmpl)
5474cc7720cSHerbert Xu {
5484cc7720cSHerbert Xu struct crypto_template *q;
5494cc7720cSHerbert Xu int err = -EEXIST;
5504cc7720cSHerbert Xu
5514cc7720cSHerbert Xu down_write(&crypto_alg_sem);
5524cc7720cSHerbert Xu
553002c77a4SJarod Wilson crypto_check_module_sig(tmpl->module);
554002c77a4SJarod Wilson
5554cc7720cSHerbert Xu list_for_each_entry(q, &crypto_template_list, list) {
5564cc7720cSHerbert Xu if (q == tmpl)
5574cc7720cSHerbert Xu goto out;
5584cc7720cSHerbert Xu }
5594cc7720cSHerbert Xu
5604cc7720cSHerbert Xu list_add(&tmpl->list, &crypto_template_list);
5614cc7720cSHerbert Xu err = 0;
5624cc7720cSHerbert Xu out:
5634cc7720cSHerbert Xu up_write(&crypto_alg_sem);
5644cc7720cSHerbert Xu return err;
5654cc7720cSHerbert Xu }
5664cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_template);
5674cc7720cSHerbert Xu
crypto_register_templates(struct crypto_template * tmpls,int count)5689572442dSXiongfeng Wang int crypto_register_templates(struct crypto_template *tmpls, int count)
5699572442dSXiongfeng Wang {
5709572442dSXiongfeng Wang int i, err;
5719572442dSXiongfeng Wang
5729572442dSXiongfeng Wang for (i = 0; i < count; i++) {
5739572442dSXiongfeng Wang err = crypto_register_template(&tmpls[i]);
5749572442dSXiongfeng Wang if (err)
5759572442dSXiongfeng Wang goto out;
5769572442dSXiongfeng Wang }
5779572442dSXiongfeng Wang return 0;
5789572442dSXiongfeng Wang
5799572442dSXiongfeng Wang out:
5809572442dSXiongfeng Wang for (--i; i >= 0; --i)
5819572442dSXiongfeng Wang crypto_unregister_template(&tmpls[i]);
5829572442dSXiongfeng Wang return err;
5839572442dSXiongfeng Wang }
5849572442dSXiongfeng Wang EXPORT_SYMBOL_GPL(crypto_register_templates);
5859572442dSXiongfeng Wang
crypto_unregister_template(struct crypto_template * tmpl)5864cc7720cSHerbert Xu void crypto_unregister_template(struct crypto_template *tmpl)
5874cc7720cSHerbert Xu {
5884cc7720cSHerbert Xu struct crypto_instance *inst;
589b67bfe0dSSasha Levin struct hlist_node *n;
5904cc7720cSHerbert Xu struct hlist_head *list;
5916bfd4809SHerbert Xu LIST_HEAD(users);
5924cc7720cSHerbert Xu
5934cc7720cSHerbert Xu down_write(&crypto_alg_sem);
5944cc7720cSHerbert Xu
5954cc7720cSHerbert Xu BUG_ON(list_empty(&tmpl->list));
5964cc7720cSHerbert Xu list_del_init(&tmpl->list);
5974cc7720cSHerbert Xu
5984cc7720cSHerbert Xu list = &tmpl->instances;
599b67bfe0dSSasha Levin hlist_for_each_entry(inst, list, list) {
6006bfd4809SHerbert Xu int err = crypto_remove_alg(&inst->alg, &users);
6010efcb8d5SJoshua I. James
6026bfd4809SHerbert Xu BUG_ON(err);
6034cc7720cSHerbert Xu }
6044cc7720cSHerbert Xu
6054cc7720cSHerbert Xu up_write(&crypto_alg_sem);
6064cc7720cSHerbert Xu
607b67bfe0dSSasha Levin hlist_for_each_entry_safe(inst, n, list, list) {
608ce8614a3SEric Biggers BUG_ON(refcount_read(&inst->alg.cra_refcnt) != 1);
609319382a6SHerbert Xu crypto_free_instance(inst);
6104cc7720cSHerbert Xu }
6116bfd4809SHerbert Xu crypto_remove_final(&users);
6124cc7720cSHerbert Xu }
6134cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_template);
6144cc7720cSHerbert Xu
crypto_unregister_templates(struct crypto_template * tmpls,int count)6159572442dSXiongfeng Wang void crypto_unregister_templates(struct crypto_template *tmpls, int count)
6169572442dSXiongfeng Wang {
6179572442dSXiongfeng Wang int i;
6189572442dSXiongfeng Wang
6199572442dSXiongfeng Wang for (i = count - 1; i >= 0; --i)
6209572442dSXiongfeng Wang crypto_unregister_template(&tmpls[i]);
6219572442dSXiongfeng Wang }
6229572442dSXiongfeng Wang EXPORT_SYMBOL_GPL(crypto_unregister_templates);
6239572442dSXiongfeng Wang
__crypto_lookup_template(const char * name)6244cc7720cSHerbert Xu static struct crypto_template *__crypto_lookup_template(const char *name)
6254cc7720cSHerbert Xu {
6264cc7720cSHerbert Xu struct crypto_template *q, *tmpl = NULL;
6274cc7720cSHerbert Xu
6284cc7720cSHerbert Xu down_read(&crypto_alg_sem);
6294cc7720cSHerbert Xu list_for_each_entry(q, &crypto_template_list, list) {
6304cc7720cSHerbert Xu if (strcmp(q->name, name))
6314cc7720cSHerbert Xu continue;
6324cc7720cSHerbert Xu if (unlikely(!crypto_tmpl_get(q)))
6334cc7720cSHerbert Xu continue;
6344cc7720cSHerbert Xu
6354cc7720cSHerbert Xu tmpl = q;
6364cc7720cSHerbert Xu break;
6374cc7720cSHerbert Xu }
6384cc7720cSHerbert Xu up_read(&crypto_alg_sem);
6394cc7720cSHerbert Xu
6404cc7720cSHerbert Xu return tmpl;
6414cc7720cSHerbert Xu }
6424cc7720cSHerbert Xu
crypto_lookup_template(const char * name)6434cc7720cSHerbert Xu struct crypto_template *crypto_lookup_template(const char *name)
6444cc7720cSHerbert Xu {
6454943ba16SKees Cook return try_then_request_module(__crypto_lookup_template(name),
6464943ba16SKees Cook "crypto-%s", name);
6474cc7720cSHerbert Xu }
6484cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_lookup_template);
6494cc7720cSHerbert Xu
crypto_register_instance(struct crypto_template * tmpl,struct crypto_instance * inst)6504cc7720cSHerbert Xu int crypto_register_instance(struct crypto_template *tmpl,
6514cc7720cSHerbert Xu struct crypto_instance *inst)
6524cc7720cSHerbert Xu {
65373d3864aSHerbert Xu struct crypto_larval *larval;
6545f567fffSHerbert Xu struct crypto_spawn *spawn;
655d6097b8dSNicolai Stange u32 fips_internal = 0;
656a7008584SEric Biggers LIST_HEAD(algs_to_put);
65773d3864aSHerbert Xu int err;
6584cc7720cSHerbert Xu
6594cc7720cSHerbert Xu err = crypto_check_alg(&inst->alg);
6604cc7720cSHerbert Xu if (err)
6619c521a20SStephan Mueller return err;
6629c521a20SStephan Mueller
6634cc7720cSHerbert Xu inst->alg.cra_module = tmpl->module;
66464a947b1SSteffen Klassert inst->alg.cra_flags |= CRYPTO_ALG_INSTANCE;
6654cc7720cSHerbert Xu
6664cc7720cSHerbert Xu down_write(&crypto_alg_sem);
6674cc7720cSHerbert Xu
6685f567fffSHerbert Xu larval = ERR_PTR(-EAGAIN);
6695f567fffSHerbert Xu for (spawn = inst->spawns; spawn;) {
6705f567fffSHerbert Xu struct crypto_spawn *next;
6715f567fffSHerbert Xu
6725f567fffSHerbert Xu if (spawn->dead)
6735f567fffSHerbert Xu goto unlock;
6745f567fffSHerbert Xu
6755f567fffSHerbert Xu next = spawn->next;
6765f567fffSHerbert Xu spawn->inst = inst;
6775f567fffSHerbert Xu spawn->registered = true;
6785f567fffSHerbert Xu
679d6097b8dSNicolai Stange fips_internal |= spawn->alg->cra_flags;
680d6097b8dSNicolai Stange
6815f567fffSHerbert Xu crypto_mod_put(spawn->alg);
6825f567fffSHerbert Xu
6835f567fffSHerbert Xu spawn = next;
6845f567fffSHerbert Xu }
6855f567fffSHerbert Xu
686d6097b8dSNicolai Stange inst->alg.cra_flags |= (fips_internal & CRYPTO_ALG_FIPS_INTERNAL);
687d6097b8dSNicolai Stange
688a7008584SEric Biggers larval = __crypto_register_alg(&inst->alg, &algs_to_put);
68973d3864aSHerbert Xu if (IS_ERR(larval))
6904cc7720cSHerbert Xu goto unlock;
691cad439fcSHerbert Xu else if (larval)
692adad556eSHerbert Xu larval->test_started = true;
693adad556eSHerbert Xu
6944cc7720cSHerbert Xu hlist_add_head(&inst->list, &tmpl->instances);
6954cc7720cSHerbert Xu inst->tmpl = tmpl;
6964cc7720cSHerbert Xu
6974cc7720cSHerbert Xu unlock:
6984cc7720cSHerbert Xu up_write(&crypto_alg_sem);
6994cc7720cSHerbert Xu
700a7008584SEric Biggers if (IS_ERR(larval))
701a7008584SEric Biggers return PTR_ERR(larval);
702a7008584SEric Biggers if (larval)
70373d3864aSHerbert Xu crypto_wait_for_test(larval);
704a7008584SEric Biggers crypto_remove_final(&algs_to_put);
705a7008584SEric Biggers return 0;
7064cc7720cSHerbert Xu }
7074cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_instance);
7084cc7720cSHerbert Xu
crypto_unregister_instance(struct crypto_instance * inst)709c6d633a9SEric Biggers void crypto_unregister_instance(struct crypto_instance *inst)
710ce3fd840SSteffen Klassert {
7111f723710SHerbert Xu LIST_HEAD(list);
712ce3fd840SSteffen Klassert
713ce3fd840SSteffen Klassert down_write(&crypto_alg_sem);
714ce3fd840SSteffen Klassert
71587b16756SHerbert Xu crypto_remove_spawns(&inst->alg, &list, NULL);
7161f723710SHerbert Xu crypto_remove_instance(inst, &list);
717ce3fd840SSteffen Klassert
718ce3fd840SSteffen Klassert up_write(&crypto_alg_sem);
719ce3fd840SSteffen Klassert
7201f723710SHerbert Xu crypto_remove_final(&list);
721ce3fd840SSteffen Klassert }
722ce3fd840SSteffen Klassert EXPORT_SYMBOL_GPL(crypto_unregister_instance);
723ce3fd840SSteffen Klassert
crypto_grab_spawn(struct crypto_spawn * spawn,struct crypto_instance * inst,const char * name,u32 type,u32 mask)724de95c957SEric Biggers int crypto_grab_spawn(struct crypto_spawn *spawn, struct crypto_instance *inst,
725de95c957SEric Biggers const char *name, u32 type, u32 mask)
726d6ef2f19SHerbert Xu {
727d6ef2f19SHerbert Xu struct crypto_alg *alg;
728aed11cf5SEric Biggers int err = -EAGAIN;
729aed11cf5SEric Biggers
730aed11cf5SEric Biggers if (WARN_ON_ONCE(inst == NULL))
731aed11cf5SEric Biggers return -EINVAL;
732d6ef2f19SHerbert Xu
733ca94e937SEric Biggers /* Allow the result of crypto_attr_alg_name() to be passed directly */
734ca94e937SEric Biggers if (IS_ERR(name))
735ca94e937SEric Biggers return PTR_ERR(name);
736ca94e937SEric Biggers
737d6097b8dSNicolai Stange alg = crypto_find_alg(name, spawn->frontend,
738d6097b8dSNicolai Stange type | CRYPTO_ALG_FIPS_INTERNAL, mask);
739d6ef2f19SHerbert Xu if (IS_ERR(alg))
740d6ef2f19SHerbert Xu return PTR_ERR(alg);
741d6ef2f19SHerbert Xu
742aed11cf5SEric Biggers down_write(&crypto_alg_sem);
743aed11cf5SEric Biggers if (!crypto_is_moribund(alg)) {
744aed11cf5SEric Biggers list_add(&spawn->list, &alg->cra_users);
745aed11cf5SEric Biggers spawn->alg = alg;
746aed11cf5SEric Biggers spawn->mask = mask;
747aed11cf5SEric Biggers spawn->next = inst->spawns;
748aed11cf5SEric Biggers inst->spawns = spawn;
7497bcb2c99SEric Biggers inst->alg.cra_flags |=
7507bcb2c99SEric Biggers (alg->cra_flags & CRYPTO_ALG_INHERITED_FLAGS);
751aed11cf5SEric Biggers err = 0;
752aed11cf5SEric Biggers }
753aed11cf5SEric Biggers up_write(&crypto_alg_sem);
7545f567fffSHerbert Xu if (err)
755d6ef2f19SHerbert Xu crypto_mod_put(alg);
756d6ef2f19SHerbert Xu return err;
757d6ef2f19SHerbert Xu }
758d6ef2f19SHerbert Xu EXPORT_SYMBOL_GPL(crypto_grab_spawn);
759d6ef2f19SHerbert Xu
crypto_drop_spawn(struct crypto_spawn * spawn)7606bfd4809SHerbert Xu void crypto_drop_spawn(struct crypto_spawn *spawn)
7616bfd4809SHerbert Xu {
762ff670627SEric Biggers if (!spawn->alg) /* not yet initialized? */
763ff670627SEric Biggers return;
764ff670627SEric Biggers
7656bfd4809SHerbert Xu down_write(&crypto_alg_sem);
7664f87ee11SHerbert Xu if (!spawn->dead)
7676bfd4809SHerbert Xu list_del(&spawn->list);
7686bfd4809SHerbert Xu up_write(&crypto_alg_sem);
7695f567fffSHerbert Xu
770aed11cf5SEric Biggers if (!spawn->registered)
7715f567fffSHerbert Xu crypto_mod_put(spawn->alg);
7726bfd4809SHerbert Xu }
7736bfd4809SHerbert Xu EXPORT_SYMBOL_GPL(crypto_drop_spawn);
7746bfd4809SHerbert Xu
crypto_spawn_alg(struct crypto_spawn * spawn)77597eedce1SHerbert Xu static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn)
7766bfd4809SHerbert Xu {
7776603523bSHerbert Xu struct crypto_alg *alg = ERR_PTR(-EAGAIN);
7786603523bSHerbert Xu struct crypto_alg *target;
7796603523bSHerbert Xu bool shoot = false;
7806bfd4809SHerbert Xu
7816bfd4809SHerbert Xu down_read(&crypto_alg_sem);
7826603523bSHerbert Xu if (!spawn->dead) {
7836bfd4809SHerbert Xu alg = spawn->alg;
7846603523bSHerbert Xu if (!crypto_mod_get(alg)) {
7856603523bSHerbert Xu target = crypto_alg_get(alg);
7866603523bSHerbert Xu shoot = true;
7876603523bSHerbert Xu alg = ERR_PTR(-EAGAIN);
7886603523bSHerbert Xu }
78973669cc5SHerbert Xu }
7906bfd4809SHerbert Xu up_read(&crypto_alg_sem);
7916bfd4809SHerbert Xu
7926603523bSHerbert Xu if (shoot) {
7936603523bSHerbert Xu crypto_shoot_alg(target);
7946603523bSHerbert Xu crypto_alg_put(target);
7956603523bSHerbert Xu }
7966603523bSHerbert Xu
7976603523bSHerbert Xu return alg;
79897eedce1SHerbert Xu }
79997eedce1SHerbert Xu
crypto_spawn_tfm(struct crypto_spawn * spawn,u32 type,u32 mask)80097eedce1SHerbert Xu struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
80197eedce1SHerbert Xu u32 mask)
80297eedce1SHerbert Xu {
80397eedce1SHerbert Xu struct crypto_alg *alg;
80497eedce1SHerbert Xu struct crypto_tfm *tfm;
80597eedce1SHerbert Xu
80697eedce1SHerbert Xu alg = crypto_spawn_alg(spawn);
80797eedce1SHerbert Xu if (IS_ERR(alg))
80897eedce1SHerbert Xu return ERR_CAST(alg);
80997eedce1SHerbert Xu
8102e306ee0SHerbert Xu tfm = ERR_PTR(-EINVAL);
8112e306ee0SHerbert Xu if (unlikely((alg->cra_flags ^ type) & mask))
8122e306ee0SHerbert Xu goto out_put_alg;
8132e306ee0SHerbert Xu
81427d2a330SHerbert Xu tfm = __crypto_alloc_tfm(alg, type, mask);
8156bfd4809SHerbert Xu if (IS_ERR(tfm))
8162e306ee0SHerbert Xu goto out_put_alg;
8176bfd4809SHerbert Xu
8186bfd4809SHerbert Xu return tfm;
8192e306ee0SHerbert Xu
8202e306ee0SHerbert Xu out_put_alg:
8212e306ee0SHerbert Xu crypto_mod_put(alg);
8222e306ee0SHerbert Xu return tfm;
8236bfd4809SHerbert Xu }
8246bfd4809SHerbert Xu EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
8256bfd4809SHerbert Xu
crypto_spawn_tfm2(struct crypto_spawn * spawn)82697eedce1SHerbert Xu void *crypto_spawn_tfm2(struct crypto_spawn *spawn)
82797eedce1SHerbert Xu {
82897eedce1SHerbert Xu struct crypto_alg *alg;
82997eedce1SHerbert Xu struct crypto_tfm *tfm;
83097eedce1SHerbert Xu
83197eedce1SHerbert Xu alg = crypto_spawn_alg(spawn);
83297eedce1SHerbert Xu if (IS_ERR(alg))
83397eedce1SHerbert Xu return ERR_CAST(alg);
83497eedce1SHerbert Xu
83597eedce1SHerbert Xu tfm = crypto_create_tfm(alg, spawn->frontend);
83697eedce1SHerbert Xu if (IS_ERR(tfm))
83797eedce1SHerbert Xu goto out_put_alg;
83897eedce1SHerbert Xu
83997eedce1SHerbert Xu return tfm;
84097eedce1SHerbert Xu
84197eedce1SHerbert Xu out_put_alg:
84297eedce1SHerbert Xu crypto_mod_put(alg);
84397eedce1SHerbert Xu return tfm;
84497eedce1SHerbert Xu }
84597eedce1SHerbert Xu EXPORT_SYMBOL_GPL(crypto_spawn_tfm2);
84697eedce1SHerbert Xu
crypto_register_notifier(struct notifier_block * nb)8472825982dSHerbert Xu int crypto_register_notifier(struct notifier_block *nb)
8482825982dSHerbert Xu {
8492825982dSHerbert Xu return blocking_notifier_chain_register(&crypto_chain, nb);
8502825982dSHerbert Xu }
8512825982dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_notifier);
8522825982dSHerbert Xu
crypto_unregister_notifier(struct notifier_block * nb)8532825982dSHerbert Xu int crypto_unregister_notifier(struct notifier_block *nb)
8542825982dSHerbert Xu {
8552825982dSHerbert Xu return blocking_notifier_chain_unregister(&crypto_chain, nb);
8562825982dSHerbert Xu }
8572825982dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
8582825982dSHerbert Xu
crypto_get_attr_type(struct rtattr ** tb)859ebc610e5SHerbert Xu struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb)
8607fed0bf2SHerbert Xu {
86139e1ee01SHerbert Xu struct rtattr *rta = tb[0];
862ebc610e5SHerbert Xu struct crypto_attr_type *algt;
863ebc610e5SHerbert Xu
864ebc610e5SHerbert Xu if (!rta)
865ebc610e5SHerbert Xu return ERR_PTR(-ENOENT);
866ebc610e5SHerbert Xu if (RTA_PAYLOAD(rta) < sizeof(*algt))
867ebc610e5SHerbert Xu return ERR_PTR(-EINVAL);
86839e1ee01SHerbert Xu if (rta->rta_type != CRYPTOA_TYPE)
86939e1ee01SHerbert Xu return ERR_PTR(-EINVAL);
870ebc610e5SHerbert Xu
871ebc610e5SHerbert Xu algt = RTA_DATA(rta);
872ebc610e5SHerbert Xu
873ebc610e5SHerbert Xu return algt;
874ebc610e5SHerbert Xu }
875ebc610e5SHerbert Xu EXPORT_SYMBOL_GPL(crypto_get_attr_type);
876ebc610e5SHerbert Xu
8777bcb2c99SEric Biggers /**
8787bcb2c99SEric Biggers * crypto_check_attr_type() - check algorithm type and compute inherited mask
8797bcb2c99SEric Biggers * @tb: the template parameters
8807bcb2c99SEric Biggers * @type: the algorithm type the template would be instantiated as
8817bcb2c99SEric Biggers * @mask_ret: (output) the mask that should be passed to crypto_grab_*()
8827bcb2c99SEric Biggers * to restrict the flags of any inner algorithms
8837bcb2c99SEric Biggers *
8847bcb2c99SEric Biggers * Validate that the algorithm type the user requested is compatible with the
8857bcb2c99SEric Biggers * one the template would actually be instantiated as. E.g., if the user is
8867bcb2c99SEric Biggers * doing crypto_alloc_shash("cbc(aes)", ...), this would return an error because
8877bcb2c99SEric Biggers * the "cbc" template creates an "skcipher" algorithm, not an "shash" algorithm.
8887bcb2c99SEric Biggers *
8897bcb2c99SEric Biggers * Also compute the mask to use to restrict the flags of any inner algorithms.
8907bcb2c99SEric Biggers *
8917bcb2c99SEric Biggers * Return: 0 on success; -errno on failure
8927bcb2c99SEric Biggers */
crypto_check_attr_type(struct rtattr ** tb,u32 type,u32 * mask_ret)8937bcb2c99SEric Biggers int crypto_check_attr_type(struct rtattr **tb, u32 type, u32 *mask_ret)
894ebc610e5SHerbert Xu {
895ebc610e5SHerbert Xu struct crypto_attr_type *algt;
896ebc610e5SHerbert Xu
897ebc610e5SHerbert Xu algt = crypto_get_attr_type(tb);
898ebc610e5SHerbert Xu if (IS_ERR(algt))
899ebc610e5SHerbert Xu return PTR_ERR(algt);
900ebc610e5SHerbert Xu
901ebc610e5SHerbert Xu if ((algt->type ^ type) & algt->mask)
902ebc610e5SHerbert Xu return -EINVAL;
903ebc610e5SHerbert Xu
9047bcb2c99SEric Biggers *mask_ret = crypto_algt_inherited_mask(algt);
905ebc610e5SHerbert Xu return 0;
906ebc610e5SHerbert Xu }
907ebc610e5SHerbert Xu EXPORT_SYMBOL_GPL(crypto_check_attr_type);
908ebc610e5SHerbert Xu
crypto_attr_alg_name(struct rtattr * rta)90968b6c7d6SHerbert Xu const char *crypto_attr_alg_name(struct rtattr *rta)
910ebc610e5SHerbert Xu {
9117fed0bf2SHerbert Xu struct crypto_attr_alg *alga;
9127fed0bf2SHerbert Xu
913ebc610e5SHerbert Xu if (!rta)
914ebc610e5SHerbert Xu return ERR_PTR(-ENOENT);
915ebc610e5SHerbert Xu if (RTA_PAYLOAD(rta) < sizeof(*alga))
9167fed0bf2SHerbert Xu return ERR_PTR(-EINVAL);
91739e1ee01SHerbert Xu if (rta->rta_type != CRYPTOA_ALG)
91839e1ee01SHerbert Xu return ERR_PTR(-EINVAL);
9197fed0bf2SHerbert Xu
9207fed0bf2SHerbert Xu alga = RTA_DATA(rta);
9217fed0bf2SHerbert Xu alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;
9227fed0bf2SHerbert Xu
92368b6c7d6SHerbert Xu return alga->name;
92468b6c7d6SHerbert Xu }
92568b6c7d6SHerbert Xu EXPORT_SYMBOL_GPL(crypto_attr_alg_name);
92668b6c7d6SHerbert Xu
crypto_inst_setname(struct crypto_instance * inst,const char * name,struct crypto_alg * alg)92732f27c74SHerbert Xu int crypto_inst_setname(struct crypto_instance *inst, const char *name,
92832f27c74SHerbert Xu struct crypto_alg *alg)
92932f27c74SHerbert Xu {
93032f27c74SHerbert Xu if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", name,
93132f27c74SHerbert Xu alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
93232f27c74SHerbert Xu return -ENAMETOOLONG;
93332f27c74SHerbert Xu
93432f27c74SHerbert Xu if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
93532f27c74SHerbert Xu name, alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
93632f27c74SHerbert Xu return -ENAMETOOLONG;
93732f27c74SHerbert Xu
93832f27c74SHerbert Xu return 0;
93932f27c74SHerbert Xu }
94032f27c74SHerbert Xu EXPORT_SYMBOL_GPL(crypto_inst_setname);
94132f27c74SHerbert Xu
crypto_init_queue(struct crypto_queue * queue,unsigned int max_qlen)942b5b7f088SHerbert Xu void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen)
943b5b7f088SHerbert Xu {
944b5b7f088SHerbert Xu INIT_LIST_HEAD(&queue->list);
945b5b7f088SHerbert Xu queue->backlog = &queue->list;
946b5b7f088SHerbert Xu queue->qlen = 0;
947b5b7f088SHerbert Xu queue->max_qlen = max_qlen;
948b5b7f088SHerbert Xu }
949b5b7f088SHerbert Xu EXPORT_SYMBOL_GPL(crypto_init_queue);
950b5b7f088SHerbert Xu
crypto_enqueue_request(struct crypto_queue * queue,struct crypto_async_request * request)951b5b7f088SHerbert Xu int crypto_enqueue_request(struct crypto_queue *queue,
952b5b7f088SHerbert Xu struct crypto_async_request *request)
953b5b7f088SHerbert Xu {
954b5b7f088SHerbert Xu int err = -EINPROGRESS;
955b5b7f088SHerbert Xu
956b5b7f088SHerbert Xu if (unlikely(queue->qlen >= queue->max_qlen)) {
9576b80ea38SGilad Ben-Yossef if (!(request->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
9586b80ea38SGilad Ben-Yossef err = -ENOSPC;
959b5b7f088SHerbert Xu goto out;
9606b80ea38SGilad Ben-Yossef }
9616b80ea38SGilad Ben-Yossef err = -EBUSY;
962b5b7f088SHerbert Xu if (queue->backlog == &queue->list)
963b5b7f088SHerbert Xu queue->backlog = &request->list;
964b5b7f088SHerbert Xu }
965b5b7f088SHerbert Xu
966b5b7f088SHerbert Xu queue->qlen++;
967b5b7f088SHerbert Xu list_add_tail(&request->list, &queue->list);
968b5b7f088SHerbert Xu
969b5b7f088SHerbert Xu out:
970b5b7f088SHerbert Xu return err;
971b5b7f088SHerbert Xu }
972b5b7f088SHerbert Xu EXPORT_SYMBOL_GPL(crypto_enqueue_request);
973b5b7f088SHerbert Xu
crypto_enqueue_request_head(struct crypto_queue * queue,struct crypto_async_request * request)974ec6e2bf3SIuliana Prodan void crypto_enqueue_request_head(struct crypto_queue *queue,
975ec6e2bf3SIuliana Prodan struct crypto_async_request *request)
976ec6e2bf3SIuliana Prodan {
9774140aafcSOlivier Bacon if (unlikely(queue->qlen >= queue->max_qlen))
9784140aafcSOlivier Bacon queue->backlog = queue->backlog->prev;
9794140aafcSOlivier Bacon
980ec6e2bf3SIuliana Prodan queue->qlen++;
981ec6e2bf3SIuliana Prodan list_add(&request->list, &queue->list);
982ec6e2bf3SIuliana Prodan }
983ec6e2bf3SIuliana Prodan EXPORT_SYMBOL_GPL(crypto_enqueue_request_head);
984ec6e2bf3SIuliana Prodan
crypto_dequeue_request(struct crypto_queue * queue)98531d228ccSHerbert Xu struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue)
986b5b7f088SHerbert Xu {
987b5b7f088SHerbert Xu struct list_head *request;
988b5b7f088SHerbert Xu
989b5b7f088SHerbert Xu if (unlikely(!queue->qlen))
990b5b7f088SHerbert Xu return NULL;
991b5b7f088SHerbert Xu
992b5b7f088SHerbert Xu queue->qlen--;
993b5b7f088SHerbert Xu
994b5b7f088SHerbert Xu if (queue->backlog != &queue->list)
995b5b7f088SHerbert Xu queue->backlog = queue->backlog->next;
996b5b7f088SHerbert Xu
997b5b7f088SHerbert Xu request = queue->list.next;
998b5b7f088SHerbert Xu list_del(request);
999b5b7f088SHerbert Xu
100031d228ccSHerbert Xu return list_entry(request, struct crypto_async_request, list);
1001b5b7f088SHerbert Xu }
1002b5b7f088SHerbert Xu EXPORT_SYMBOL_GPL(crypto_dequeue_request);
1003b5b7f088SHerbert Xu
crypto_inc_byte(u8 * a,unsigned int size)10047613636dSHerbert Xu static inline void crypto_inc_byte(u8 *a, unsigned int size)
10057613636dSHerbert Xu {
10067613636dSHerbert Xu u8 *b = (a + size);
10077613636dSHerbert Xu u8 c;
10087613636dSHerbert Xu
10097613636dSHerbert Xu for (; size; size--) {
10107613636dSHerbert Xu c = *--b + 1;
10117613636dSHerbert Xu *b = c;
10127613636dSHerbert Xu if (c)
10137613636dSHerbert Xu break;
10147613636dSHerbert Xu }
10157613636dSHerbert Xu }
10167613636dSHerbert Xu
crypto_inc(u8 * a,unsigned int size)10177613636dSHerbert Xu void crypto_inc(u8 *a, unsigned int size)
10187613636dSHerbert Xu {
10197613636dSHerbert Xu __be32 *b = (__be32 *)(a + size);
10207613636dSHerbert Xu u32 c;
10217613636dSHerbert Xu
1022db91af0fSArd Biesheuvel if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ||
102327c539aeSArd Biesheuvel IS_ALIGNED((unsigned long)b, __alignof__(*b)))
10247613636dSHerbert Xu for (; size >= 4; size -= 4) {
10257613636dSHerbert Xu c = be32_to_cpu(*--b) + 1;
10267613636dSHerbert Xu *b = cpu_to_be32(c);
102727c539aeSArd Biesheuvel if (likely(c))
10287613636dSHerbert Xu return;
10297613636dSHerbert Xu }
10307613636dSHerbert Xu
10317613636dSHerbert Xu crypto_inc_byte(a, size);
10327613636dSHerbert Xu }
10337613636dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_inc);
10347613636dSHerbert Xu
crypto_alg_extsize(struct crypto_alg * alg)103538d21433SHerbert Xu unsigned int crypto_alg_extsize(struct crypto_alg *alg)
103638d21433SHerbert Xu {
1037c2110f28SHerbert Xu return alg->cra_ctxsize +
1038c2110f28SHerbert Xu (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1));
103938d21433SHerbert Xu }
104038d21433SHerbert Xu EXPORT_SYMBOL_GPL(crypto_alg_extsize);
104138d21433SHerbert Xu
crypto_type_has_alg(const char * name,const struct crypto_type * frontend,u32 type,u32 mask)1042f2aefdabSHerbert Xu int crypto_type_has_alg(const char *name, const struct crypto_type *frontend,
1043f2aefdabSHerbert Xu u32 type, u32 mask)
1044f2aefdabSHerbert Xu {
1045f2aefdabSHerbert Xu int ret = 0;
1046f2aefdabSHerbert Xu struct crypto_alg *alg = crypto_find_alg(name, frontend, type, mask);
1047f2aefdabSHerbert Xu
1048f2aefdabSHerbert Xu if (!IS_ERR(alg)) {
1049f2aefdabSHerbert Xu crypto_mod_put(alg);
1050f2aefdabSHerbert Xu ret = 1;
1051f2aefdabSHerbert Xu }
1052f2aefdabSHerbert Xu
1053f2aefdabSHerbert Xu return ret;
1054f2aefdabSHerbert Xu }
1055f2aefdabSHerbert Xu EXPORT_SYMBOL_GPL(crypto_type_has_alg);
1056f2aefdabSHerbert Xu
crypto_start_tests(void)1057adad556eSHerbert Xu static void __init crypto_start_tests(void)
1058adad556eSHerbert Xu {
105906bd9c96SEric Biggers if (IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS))
106006bd9c96SEric Biggers return;
106106bd9c96SEric Biggers
1062adad556eSHerbert Xu for (;;) {
1063adad556eSHerbert Xu struct crypto_larval *larval = NULL;
1064adad556eSHerbert Xu struct crypto_alg *q;
1065adad556eSHerbert Xu
1066adad556eSHerbert Xu down_write(&crypto_alg_sem);
1067adad556eSHerbert Xu
1068adad556eSHerbert Xu list_for_each_entry(q, &crypto_alg_list, cra_list) {
1069adad556eSHerbert Xu struct crypto_larval *l;
1070adad556eSHerbert Xu
1071adad556eSHerbert Xu if (!crypto_is_larval(q))
1072adad556eSHerbert Xu continue;
1073adad556eSHerbert Xu
1074adad556eSHerbert Xu l = (void *)q;
1075adad556eSHerbert Xu
1076adad556eSHerbert Xu if (!crypto_is_test_larval(l))
1077adad556eSHerbert Xu continue;
1078adad556eSHerbert Xu
1079adad556eSHerbert Xu if (l->test_started)
1080adad556eSHerbert Xu continue;
1081adad556eSHerbert Xu
1082adad556eSHerbert Xu l->test_started = true;
1083adad556eSHerbert Xu larval = l;
1084adad556eSHerbert Xu break;
1085adad556eSHerbert Xu }
1086adad556eSHerbert Xu
1087adad556eSHerbert Xu up_write(&crypto_alg_sem);
1088adad556eSHerbert Xu
1089adad556eSHerbert Xu if (!larval)
1090adad556eSHerbert Xu break;
1091adad556eSHerbert Xu
1092adad556eSHerbert Xu crypto_wait_for_test(larval);
1093adad556eSHerbert Xu }
1094adad556eSHerbert Xu
109506bd9c96SEric Biggers set_crypto_boot_test_finished();
1096adad556eSHerbert Xu }
1097adad556eSHerbert Xu
crypto_algapi_init(void)1098cce9e06dSHerbert Xu static int __init crypto_algapi_init(void)
1099cce9e06dSHerbert Xu {
1100cce9e06dSHerbert Xu crypto_init_proc();
1101adad556eSHerbert Xu crypto_start_tests();
1102cce9e06dSHerbert Xu return 0;
1103cce9e06dSHerbert Xu }
1104cce9e06dSHerbert Xu
crypto_algapi_exit(void)1105cce9e06dSHerbert Xu static void __exit crypto_algapi_exit(void)
1106cce9e06dSHerbert Xu {
1107cce9e06dSHerbert Xu crypto_exit_proc();
1108cce9e06dSHerbert Xu }
1109cce9e06dSHerbert Xu
1110adad556eSHerbert Xu /*
1111adad556eSHerbert Xu * We run this at late_initcall so that all the built-in algorithms
1112adad556eSHerbert Xu * have had a chance to register themselves first.
1113adad556eSHerbert Xu */
1114adad556eSHerbert Xu late_initcall(crypto_algapi_init);
1115cce9e06dSHerbert Xu module_exit(crypto_algapi_exit);
1116cce9e06dSHerbert Xu
1117cce9e06dSHerbert Xu MODULE_LICENSE("GPL");
1118cce9e06dSHerbert Xu MODULE_DESCRIPTION("Cryptographic algorithms API");
1119c6ce9c58SHerbert Xu MODULE_SOFTDEP("pre: cryptomgr");
1120