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 <[email protected]>
6cce9e06dSHerbert Xu */
7cce9e06dSHerbert Xu
813c935bbSSalvatore Mesoraca #include <crypto/algapi.h>
96bfd4809SHerbert Xu #include <linux/err.h>
10cce9e06dSHerbert Xu #include <linux/errno.h>
113133d76fSHerbert Xu #include <linux/fips.h>
12cce9e06dSHerbert Xu #include <linux/init.h>
13cce9e06dSHerbert Xu #include <linux/kernel.h>
144cc7720cSHerbert Xu #include <linux/list.h>
15cce9e06dSHerbert Xu #include <linux/module.h>
167fed0bf2SHerbert Xu #include <linux/rtnetlink.h>
175a0e3ad6STejun Heo #include <linux/slab.h>
18cce9e06dSHerbert Xu #include <linux/string.h>
199ae4577bSHerbert Xu #include <linux/workqueue.h>
20cce9e06dSHerbert Xu
21cce9e06dSHerbert Xu #include "internal.h"
22cce9e06dSHerbert Xu
234cc7720cSHerbert Xu static LIST_HEAD(crypto_template_list);
244cc7720cSHerbert Xu
crypto_check_module_sig(struct module * mod)25002c77a4SJarod Wilson static inline void crypto_check_module_sig(struct module *mod)
26002c77a4SJarod Wilson {
2759afdc7bSHerbert Xu if (fips_enabled && mod && !module_sig_ok(mod))
28002c77a4SJarod Wilson panic("Module %s signature verification failed in FIPS mode\n",
29bd4a7c69SHerbert Xu module_name(mod));
30002c77a4SJarod Wilson }
31002c77a4SJarod Wilson
crypto_check_alg(struct crypto_alg * alg)324cc7720cSHerbert Xu static int crypto_check_alg(struct crypto_alg *alg)
33cce9e06dSHerbert Xu {
34002c77a4SJarod Wilson crypto_check_module_sig(alg->cra_module);
35002c77a4SJarod Wilson
36177f87d0SEric Biggers if (!alg->cra_name[0] || !alg->cra_driver_name[0])
37177f87d0SEric Biggers return -EINVAL;
38177f87d0SEric Biggers
39cce9e06dSHerbert Xu if (alg->cra_alignmask & (alg->cra_alignmask + 1))
40cce9e06dSHerbert Xu return -EINVAL;
41cce9e06dSHerbert Xu
42a9f7f88aSKees Cook /* General maximums for all algs. */
43a9f7f88aSKees Cook if (alg->cra_alignmask > MAX_ALGAPI_ALIGNMASK)
44cce9e06dSHerbert Xu return -EINVAL;
45cce9e06dSHerbert Xu
46a9f7f88aSKees Cook if (alg->cra_blocksize > MAX_ALGAPI_BLOCKSIZE)
47a9f7f88aSKees Cook return -EINVAL;
48a9f7f88aSKees Cook
49a9f7f88aSKees Cook /* Lower maximums for specific alg types. */
5013c935bbSSalvatore Mesoraca if (!alg->cra_type && (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
5113c935bbSSalvatore Mesoraca CRYPTO_ALG_TYPE_CIPHER) {
5213c935bbSSalvatore Mesoraca if (alg->cra_alignmask > MAX_CIPHER_ALIGNMASK)
5313c935bbSSalvatore Mesoraca return -EINVAL;
5413c935bbSSalvatore Mesoraca
5513c935bbSSalvatore Mesoraca if (alg->cra_blocksize > MAX_CIPHER_BLOCKSIZE)
5613c935bbSSalvatore Mesoraca return -EINVAL;
5713c935bbSSalvatore Mesoraca }
5813c935bbSSalvatore Mesoraca
59cce9e06dSHerbert Xu if (alg->cra_priority < 0)
60cce9e06dSHerbert Xu return -EINVAL;
61cce9e06dSHerbert Xu
62ce8614a3SEric Biggers refcount_set(&alg->cra_refcnt, 1);
63e9b8e5beSHerbert Xu
64177f87d0SEric Biggers return 0;
654cc7720cSHerbert Xu }
66cce9e06dSHerbert Xu
crypto_free_instance(struct crypto_instance * inst)67319382a6SHerbert Xu static void crypto_free_instance(struct crypto_instance *inst)
68319382a6SHerbert Xu {
69319382a6SHerbert Xu inst->alg.cra_type->free(inst);
70319382a6SHerbert Xu }
71319382a6SHerbert Xu
crypto_destroy_instance_workfn(struct work_struct * w)729ae4577bSHerbert Xu static void crypto_destroy_instance_workfn(struct work_struct *w)
736bfd4809SHerbert Xu {
749ae4577bSHerbert Xu struct crypto_instance *inst = container_of(w, struct crypto_instance,
759ae4577bSHerbert Xu free_work);
766bfd4809SHerbert Xu struct crypto_template *tmpl = inst->tmpl;
776bfd4809SHerbert Xu
78319382a6SHerbert Xu crypto_free_instance(inst);
796bfd4809SHerbert Xu crypto_tmpl_put(tmpl);
806bfd4809SHerbert Xu }
816bfd4809SHerbert Xu
crypto_destroy_instance(struct crypto_alg * alg)829ae4577bSHerbert Xu static void crypto_destroy_instance(struct crypto_alg *alg)
839ae4577bSHerbert Xu {
849ae4577bSHerbert Xu struct crypto_instance *inst = container_of(alg,
859ae4577bSHerbert Xu struct crypto_instance,
869ae4577bSHerbert Xu alg);
879ae4577bSHerbert Xu
889ae4577bSHerbert Xu INIT_WORK(&inst->free_work, crypto_destroy_instance_workfn);
899ae4577bSHerbert Xu schedule_work(&inst->free_work);
909ae4577bSHerbert Xu }
919ae4577bSHerbert Xu
9202244ba4SHerbert Xu /*
9302244ba4SHerbert Xu * This function adds a spawn to the list secondary_spawns which
9402244ba4SHerbert Xu * will be used at the end of crypto_remove_spawns to unregister
9502244ba4SHerbert Xu * instances, unless the spawn happens to be one that is depended
9602244ba4SHerbert Xu * on by the new algorithm (nalg in crypto_remove_spawns).
9702244ba4SHerbert Xu *
9802244ba4SHerbert Xu * This function is also responsible for resurrecting any algorithms
9902244ba4SHerbert Xu * in the dependency chain of nalg by unsetting n->dead.
10002244ba4SHerbert Xu */
crypto_more_spawns(struct crypto_alg * alg,struct list_head * stack,struct list_head * top,struct list_head * secondary_spawns)1012bf29016SHerbert Xu static struct list_head *crypto_more_spawns(struct crypto_alg *alg,
1022bf29016SHerbert Xu struct list_head *stack,
1032bf29016SHerbert Xu struct list_head *top,
104a73e6996SHerbert Xu struct list_head *secondary_spawns)
1056bfd4809SHerbert Xu {
1062bf29016SHerbert Xu struct crypto_spawn *spawn, *n;
1072bf29016SHerbert Xu
108304e4818SGeliang Tang spawn = list_first_entry_or_null(stack, struct crypto_spawn, list);
109304e4818SGeliang Tang if (!spawn)
1102bf29016SHerbert Xu return NULL;
1112bf29016SHerbert Xu
1124f87ee11SHerbert Xu n = list_prev_entry(spawn, list);
1132bf29016SHerbert Xu list_move(&spawn->list, secondary_spawns);
1142bf29016SHerbert Xu
1154f87ee11SHerbert Xu if (list_is_last(&n->list, stack))
1164f87ee11SHerbert Xu return top;
1174f87ee11SHerbert Xu
1184f87ee11SHerbert Xu n = list_next_entry(n, list);
1194f87ee11SHerbert Xu if (!spawn->dead)
1204f87ee11SHerbert Xu n->dead = false;
1214f87ee11SHerbert Xu
1224f87ee11SHerbert Xu return &n->inst->alg.cra_users;
1232bf29016SHerbert Xu }
1242bf29016SHerbert Xu
crypto_remove_instance(struct crypto_instance * inst,struct list_head * list)1251f723710SHerbert Xu static void crypto_remove_instance(struct crypto_instance *inst,
1262bf29016SHerbert Xu struct list_head *list)
1272bf29016SHerbert Xu {
1286bfd4809SHerbert Xu struct crypto_template *tmpl = inst->tmpl;
1296bfd4809SHerbert Xu
1306bfd4809SHerbert Xu if (crypto_is_dead(&inst->alg))
131a73e6996SHerbert Xu return;
1326bfd4809SHerbert Xu
1336bfd4809SHerbert Xu inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
13438cb2419SHerbert Xu
1356bfd4809SHerbert Xu if (!tmpl || !crypto_tmpl_get(tmpl))
136a73e6996SHerbert Xu return;
1376bfd4809SHerbert Xu
1386bfd4809SHerbert Xu list_move(&inst->alg.cra_list, list);
1396bfd4809SHerbert Xu hlist_del(&inst->list);
1406bfd4809SHerbert Xu inst->alg.cra_destroy = crypto_destroy_instance;
1416bfd4809SHerbert Xu
1422bf29016SHerbert Xu BUG_ON(!list_empty(&inst->alg.cra_users));
1436bfd4809SHerbert Xu }
144a73e6996SHerbert Xu
14502244ba4SHerbert Xu /*
14602244ba4SHerbert Xu * Given an algorithm alg, remove all algorithms that depend on it
14702244ba4SHerbert Xu * through spawns. If nalg is not null, then exempt any algorithms
14802244ba4SHerbert Xu * that is depended on by nalg. This is useful when nalg itself
14902244ba4SHerbert Xu * depends on alg.
15002244ba4SHerbert Xu */
crypto_remove_spawns(struct crypto_alg * alg,struct list_head * list,struct crypto_alg * nalg)15189b596baSSteffen Klassert void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
1522bf29016SHerbert Xu struct crypto_alg *nalg)
153a73e6996SHerbert Xu {
1542bf29016SHerbert Xu u32 new_type = (nalg ?: alg)->cra_flags;
155a73e6996SHerbert Xu struct crypto_spawn *spawn, *n;
156a73e6996SHerbert Xu LIST_HEAD(secondary_spawns);
1572bf29016SHerbert Xu struct list_head *spawns;
1582bf29016SHerbert Xu LIST_HEAD(stack);
1592bf29016SHerbert Xu LIST_HEAD(top);
160a73e6996SHerbert Xu
1612bf29016SHerbert Xu spawns = &alg->cra_users;
162a73e6996SHerbert Xu list_for_each_entry_safe(spawn, n, spawns, list) {
163a73e6996SHerbert Xu if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
164a73e6996SHerbert Xu continue;
165a73e6996SHerbert Xu
1662bf29016SHerbert Xu list_move(&spawn->list, &top);
167a73e6996SHerbert Xu }
168a73e6996SHerbert Xu
16902244ba4SHerbert Xu /*
17002244ba4SHerbert Xu * Perform a depth-first walk starting from alg through
17102244ba4SHerbert Xu * the cra_users tree. The list stack records the path
17202244ba4SHerbert Xu * from alg to the current spawn.
17302244ba4SHerbert Xu */
1742bf29016SHerbert Xu spawns = ⊤
1752bf29016SHerbert Xu do {
1762bf29016SHerbert Xu while (!list_empty(spawns)) {
1772bf29016SHerbert Xu struct crypto_instance *inst;
1782bf29016SHerbert Xu
1792bf29016SHerbert Xu spawn = list_first_entry(spawns, struct crypto_spawn,
1802bf29016SHerbert Xu list);
1812bf29016SHerbert Xu inst = spawn->inst;
1822bf29016SHerbert Xu
1832bf29016SHerbert Xu list_move(&spawn->list, &stack);
1845f567fffSHerbert Xu spawn->dead = !spawn->registered || &inst->alg != nalg;
1855f567fffSHerbert Xu
1865f567fffSHerbert Xu if (!spawn->registered)
1875f567fffSHerbert Xu break;
1885f567fffSHerbert Xu
1895f567fffSHerbert Xu BUG_ON(&inst->alg == alg);
1902bf29016SHerbert Xu
1912bf29016SHerbert Xu if (&inst->alg == nalg)
1922bf29016SHerbert Xu break;
1932bf29016SHerbert Xu
1942bf29016SHerbert Xu spawns = &inst->alg.cra_users;
1959a006742SEric Biggers
1969a006742SEric Biggers /*
1975f567fffSHerbert Xu * Even if spawn->registered is true, the
1985f567fffSHerbert Xu * instance itself may still be unregistered.
1995f567fffSHerbert Xu * This is because it may have failed during
2005f567fffSHerbert Xu * registration. Therefore we still need to
2015f567fffSHerbert Xu * make the following test.
2025f567fffSHerbert Xu *
2039a006742SEric Biggers * We may encounter an unregistered instance here, since
2049a006742SEric Biggers * an instance's spawns are set up prior to the instance
2059a006742SEric Biggers * being registered. An unregistered instance will have
2069a006742SEric Biggers * NULL ->cra_users.next, since ->cra_users isn't
2079a006742SEric Biggers * properly initialized until registration. But an
2089a006742SEric Biggers * unregistered instance cannot have any users, so treat
2099a006742SEric Biggers * it the same as ->cra_users being empty.
2109a006742SEric Biggers */
2119a006742SEric Biggers if (spawns->next == NULL)
2129a006742SEric Biggers break;
2132bf29016SHerbert Xu }
2142bf29016SHerbert Xu } while ((spawns = crypto_more_spawns(alg, &stack, &top,
2152bf29016SHerbert Xu &secondary_spawns)));
2162bf29016SHerbert Xu
21702244ba4SHerbert Xu /*
21802244ba4SHerbert Xu * Remove all instances that are marked as dead. Also
21902244ba4SHerbert Xu * complete the resurrection of the others by moving them
22002244ba4SHerbert Xu * back to the cra_users list.
22102244ba4SHerbert Xu */
2222bf29016SHerbert Xu list_for_each_entry_safe(spawn, n, &secondary_spawns, list) {
2234f87ee11SHerbert Xu if (!spawn->dead)
2242bf29016SHerbert Xu list_move(&spawn->list, &spawn->alg->cra_users);
2255f567fffSHerbert Xu else if (spawn->registered)
2261f723710SHerbert Xu crypto_remove_instance(spawn->inst, list);
2276bfd4809SHerbert Xu }
2286bfd4809SHerbert Xu }
22989b596baSSteffen Klassert EXPORT_SYMBOL_GPL(crypto_remove_spawns);
2306bfd4809SHerbert Xu
crypto_alg_finish_registration(struct crypto_alg * alg,struct list_head * algs_to_put)231a7008584SEric Biggers static void crypto_alg_finish_registration(struct crypto_alg *alg,
232a7008584SEric Biggers struct list_head *algs_to_put)
233a7008584SEric Biggers {
234a7008584SEric Biggers struct crypto_alg *q;
235a7008584SEric Biggers
236a7008584SEric Biggers list_for_each_entry(q, &crypto_alg_list, cra_list) {
237a7008584SEric Biggers if (q == alg)
238a7008584SEric Biggers continue;
239a7008584SEric Biggers
240a7008584SEric Biggers if (crypto_is_moribund(q))
241a7008584SEric Biggers continue;
242a7008584SEric Biggers
24396ad5955SHerbert Xu if (crypto_is_larval(q))
244a7008584SEric Biggers continue;
245a7008584SEric Biggers
246a7008584SEric Biggers if (strcmp(alg->cra_name, q->cra_name))
247a7008584SEric Biggers continue;
248a7008584SEric Biggers
249a7008584SEric Biggers if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
250a7008584SEric Biggers q->cra_priority > alg->cra_priority)
251a7008584SEric Biggers continue;
252a7008584SEric Biggers
253a7008584SEric Biggers crypto_remove_spawns(q, algs_to_put, alg);
254a7008584SEric Biggers }
255a7008584SEric Biggers
256a7008584SEric Biggers crypto_notify(CRYPTO_MSG_ALG_LOADED, alg);
257a7008584SEric Biggers }
258a7008584SEric Biggers
crypto_alloc_test_larval(struct crypto_alg * alg)259cad439fcSHerbert Xu static struct crypto_larval *crypto_alloc_test_larval(struct crypto_alg *alg)
260cad439fcSHerbert Xu {
261cad439fcSHerbert Xu struct crypto_larval *larval;
262cad439fcSHerbert Xu
263a7008584SEric Biggers if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER) ||
2649cadd73aSEric Biggers IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) ||
2659cadd73aSEric Biggers (alg->cra_flags & CRYPTO_ALG_INTERNAL))
266a7008584SEric Biggers return NULL; /* No self-test needed */
267cad439fcSHerbert Xu
268cad439fcSHerbert Xu larval = crypto_larval_alloc(alg->cra_name,
269cad439fcSHerbert Xu alg->cra_flags | CRYPTO_ALG_TESTED, 0);
270cad439fcSHerbert Xu if (IS_ERR(larval))
271cad439fcSHerbert Xu return larval;
272cad439fcSHerbert Xu
273cad439fcSHerbert Xu larval->adult = crypto_mod_get(alg);
274cad439fcSHerbert Xu if (!larval->adult) {
275cad439fcSHerbert Xu kfree(larval);
276cad439fcSHerbert Xu return ERR_PTR(-ENOENT);
277cad439fcSHerbert Xu }
278cad439fcSHerbert Xu
279cad439fcSHerbert Xu refcount_set(&larval->alg.cra_refcnt, 1);
280cad439fcSHerbert Xu memcpy(larval->alg.cra_driver_name, alg->cra_driver_name,
281cad439fcSHerbert Xu CRYPTO_MAX_ALG_NAME);
282cad439fcSHerbert Xu larval->alg.cra_priority = alg->cra_priority;
283cad439fcSHerbert Xu
284cad439fcSHerbert Xu return larval;
285cad439fcSHerbert Xu }
286cad439fcSHerbert Xu
287a7008584SEric Biggers static struct crypto_larval *
__crypto_register_alg(struct crypto_alg * alg,struct list_head * algs_to_put)288a7008584SEric Biggers __crypto_register_alg(struct crypto_alg *alg, struct list_head *algs_to_put)
2894cc7720cSHerbert Xu {
2904cc7720cSHerbert Xu struct crypto_alg *q;
29173d3864aSHerbert Xu struct crypto_larval *larval;
2926bfd4809SHerbert Xu int ret = -EAGAIN;
2936bfd4809SHerbert Xu
2946bfd4809SHerbert Xu if (crypto_is_dead(alg))
29573d3864aSHerbert Xu goto err;
2966bfd4809SHerbert Xu
2976bfd4809SHerbert Xu INIT_LIST_HEAD(&alg->cra_users);
2986bfd4809SHerbert Xu
2996bfd4809SHerbert Xu ret = -EEXIST;
300cce9e06dSHerbert Xu
301cce9e06dSHerbert Xu list_for_each_entry(q, &crypto_alg_list, cra_list) {
3024cc7720cSHerbert Xu if (q == alg)
30373d3864aSHerbert Xu goto err;
30473d3864aSHerbert Xu
305b8e15992SHerbert Xu if (crypto_is_moribund(q))
306b8e15992SHerbert Xu continue;
307b8e15992SHerbert Xu
30873d3864aSHerbert Xu if (crypto_is_larval(q)) {
30973d3864aSHerbert Xu if (!strcmp(alg->cra_driver_name, q->cra_driver_name))
31073d3864aSHerbert Xu goto err;
31173d3864aSHerbert Xu continue;
31273d3864aSHerbert Xu }
31373d3864aSHerbert Xu
31473d3864aSHerbert Xu if (!strcmp(q->cra_driver_name, alg->cra_name) ||
31527016f75SHerbert Xu !strcmp(q->cra_driver_name, alg->cra_driver_name) ||
31673d3864aSHerbert Xu !strcmp(q->cra_name, alg->cra_driver_name))
31773d3864aSHerbert Xu goto err;
31873d3864aSHerbert Xu }
31973d3864aSHerbert Xu
320cad439fcSHerbert Xu larval = crypto_alloc_test_larval(alg);
32173d3864aSHerbert Xu if (IS_ERR(larval))
322cce9e06dSHerbert Xu goto out;
3236bfd4809SHerbert Xu
32473d3864aSHerbert Xu list_add(&alg->cra_list, &crypto_alg_list);
325cad439fcSHerbert Xu
326a7008584SEric Biggers if (larval) {
327a7008584SEric Biggers /* No cheating! */
328a7008584SEric Biggers alg->cra_flags &= ~CRYPTO_ALG_TESTED;
329a7008584SEric Biggers
330a7008584SEric Biggers list_add(&larval->alg.cra_list, &crypto_alg_list);
331a7008584SEric Biggers } else {
332a7008584SEric Biggers alg->cra_flags |= CRYPTO_ALG_TESTED;
33396ad5955SHerbert Xu crypto_alg_finish_registration(alg, algs_to_put);
334a7008584SEric Biggers }
335a7008584SEric Biggers
33673d3864aSHerbert Xu out:
33773d3864aSHerbert Xu return larval;
33873d3864aSHerbert Xu
33973d3864aSHerbert Xu err:
34073d3864aSHerbert Xu larval = ERR_PTR(ret);
34173d3864aSHerbert Xu goto out;
34273d3864aSHerbert Xu }
34373d3864aSHerbert Xu
crypto_alg_tested(const char * name,int err)34473d3864aSHerbert Xu void crypto_alg_tested(const char *name, int err)
34573d3864aSHerbert Xu {
34673d3864aSHerbert Xu struct crypto_larval *test;
34773d3864aSHerbert Xu struct crypto_alg *alg;
34873d3864aSHerbert Xu struct crypto_alg *q;
34973d3864aSHerbert Xu LIST_HEAD(list);
35073d3864aSHerbert Xu
35173d3864aSHerbert Xu down_write(&crypto_alg_sem);
35273d3864aSHerbert Xu list_for_each_entry(q, &crypto_alg_list, cra_list) {
353b8e15992SHerbert Xu if (crypto_is_moribund(q) || !crypto_is_larval(q))
35473d3864aSHerbert Xu continue;
35573d3864aSHerbert Xu
35673d3864aSHerbert Xu test = (struct crypto_larval *)q;
35773d3864aSHerbert Xu
35873d3864aSHerbert Xu if (!strcmp(q->cra_driver_name, name))
35973d3864aSHerbert Xu goto found;
36073d3864aSHerbert Xu }
36173d3864aSHerbert Xu
362c7235857SKarim Eshapa pr_err("alg: Unexpected test result for %s: %d\n", name, err);
36337da5d0fSHerbert Xu up_write(&crypto_alg_sem);
36437da5d0fSHerbert Xu return;
36573d3864aSHerbert Xu
36673d3864aSHerbert Xu found:
367b8e15992SHerbert Xu q->cra_flags |= CRYPTO_ALG_DEAD;
36873d3864aSHerbert Xu alg = test->adult;
369d6097b8dSNicolai Stange
370b81e286bSHerbert Xu if (crypto_is_dead(alg))
37173d3864aSHerbert Xu goto complete;
37273d3864aSHerbert Xu
373d6097b8dSNicolai Stange if (err == -ECANCELED)
374d6097b8dSNicolai Stange alg->cra_flags |= CRYPTO_ALG_FIPS_INTERNAL;
375d6097b8dSNicolai Stange else if (err)
376d6097b8dSNicolai Stange goto complete;
377d6097b8dSNicolai Stange else
378d6097b8dSNicolai Stange alg->cra_flags &= ~CRYPTO_ALG_FIPS_INTERNAL;
379d6097b8dSNicolai Stange
38073d3864aSHerbert Xu alg->cra_flags |= CRYPTO_ALG_TESTED;
38173d3864aSHerbert Xu
38296ad5955SHerbert Xu crypto_alg_finish_registration(alg, &list);
383cce9e06dSHerbert Xu
38473d3864aSHerbert Xu complete:
38537da5d0fSHerbert Xu list_del_init(&test->alg.cra_list);
38673d3864aSHerbert Xu complete_all(&test->completion);
3872825982dSHerbert Xu
38873d3864aSHerbert Xu up_write(&crypto_alg_sem);
3892825982dSHerbert Xu
39037da5d0fSHerbert Xu crypto_alg_put(&test->alg);
39173d3864aSHerbert Xu crypto_remove_final(&list);
392cce9e06dSHerbert Xu }
39373d3864aSHerbert Xu EXPORT_SYMBOL_GPL(crypto_alg_tested);
3944cc7720cSHerbert Xu
crypto_remove_final(struct list_head * list)39522e5b20bSSteffen Klassert void crypto_remove_final(struct list_head *list)
3966bfd4809SHerbert Xu {
3976bfd4809SHerbert Xu struct crypto_alg *alg;
3986bfd4809SHerbert Xu struct crypto_alg *n;
3996bfd4809SHerbert Xu
4006bfd4809SHerbert Xu list_for_each_entry_safe(alg, n, list, cra_list) {
4016bfd4809SHerbert Xu list_del_init(&alg->cra_list);
4026bfd4809SHerbert Xu crypto_alg_put(alg);
4036bfd4809SHerbert Xu }
4046bfd4809SHerbert Xu }
40522e5b20bSSteffen Klassert EXPORT_SYMBOL_GPL(crypto_remove_final);
4066bfd4809SHerbert Xu
crypto_register_alg(struct crypto_alg * alg)4074cc7720cSHerbert Xu int crypto_register_alg(struct crypto_alg *alg)
4084cc7720cSHerbert Xu {
40973d3864aSHerbert Xu struct crypto_larval *larval;
410b7685262SHerbert Xu bool test_started = false;
411a7008584SEric Biggers LIST_HEAD(algs_to_put);
4124cc7720cSHerbert Xu int err;
4134cc7720cSHerbert Xu
414d6040764SSalvatore Benedetto alg->cra_flags &= ~CRYPTO_ALG_DEAD;
4154cc7720cSHerbert Xu err = crypto_check_alg(alg);
4164cc7720cSHerbert Xu if (err)
4174cc7720cSHerbert Xu return err;
4184cc7720cSHerbert Xu
4194cc7720cSHerbert Xu down_write(&crypto_alg_sem);
420a7008584SEric Biggers larval = __crypto_register_alg(alg, &algs_to_put);
421a7008584SEric Biggers if (!IS_ERR_OR_NULL(larval)) {
422b7685262SHerbert Xu test_started = crypto_boot_test_finished();
423adad556eSHerbert Xu larval->test_started = test_started;
424a7008584SEric Biggers }
4254cc7720cSHerbert Xu up_write(&crypto_alg_sem);
4264cc7720cSHerbert Xu
427a7008584SEric Biggers if (IS_ERR(larval))
42873d3864aSHerbert Xu return PTR_ERR(larval);
429b7685262SHerbert Xu
430b7685262SHerbert Xu if (test_started)
431b7685262SHerbert Xu crypto_schedule_test(larval);
432b7685262SHerbert Xu else
433a7008584SEric Biggers crypto_remove_final(&algs_to_put);
434b7685262SHerbert Xu
43573d3864aSHerbert Xu return 0;
4364cc7720cSHerbert Xu }
437cce9e06dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_alg);
438cce9e06dSHerbert Xu
crypto_remove_alg(struct crypto_alg * alg,struct list_head * list)4396bfd4809SHerbert Xu static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
4406bfd4809SHerbert Xu {
4416bfd4809SHerbert Xu if (unlikely(list_empty(&alg->cra_list)))
4426bfd4809SHerbert Xu return -ENOENT;
4436bfd4809SHerbert Xu
4446bfd4809SHerbert Xu alg->cra_flags |= CRYPTO_ALG_DEAD;
4456bfd4809SHerbert Xu
4466bfd4809SHerbert Xu list_del_init(&alg->cra_list);
4472bf29016SHerbert Xu crypto_remove_spawns(alg, list, NULL);
4486bfd4809SHerbert Xu
4496bfd4809SHerbert Xu return 0;
4506bfd4809SHerbert Xu }
4516bfd4809SHerbert Xu
crypto_unregister_alg(struct crypto_alg * alg)452c6d633a9SEric Biggers void crypto_unregister_alg(struct crypto_alg *alg)
453cce9e06dSHerbert Xu {
4546bfd4809SHerbert Xu int ret;
4556bfd4809SHerbert Xu LIST_HEAD(list);
456cce9e06dSHerbert Xu
457cce9e06dSHerbert Xu down_write(&crypto_alg_sem);
4586bfd4809SHerbert Xu ret = crypto_remove_alg(alg, &list);
459cce9e06dSHerbert Xu up_write(&crypto_alg_sem);
460cce9e06dSHerbert Xu
461c6d633a9SEric Biggers if (WARN(ret, "Algorithm %s is not registered", alg->cra_driver_name))
462c6d633a9SEric Biggers return;
463cce9e06dSHerbert Xu
464a543ada7SToke Høiland-Jørgensen if (WARN_ON(refcount_read(&alg->cra_refcnt) != 1))
465a543ada7SToke Høiland-Jørgensen return;
466a543ada7SToke Høiland-Jørgensen
467*27b13425SHerbert Xu crypto_alg_put(alg);
468cce9e06dSHerbert Xu
4696bfd4809SHerbert Xu crypto_remove_final(&list);
470cce9e06dSHerbert Xu }
471cce9e06dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_alg);
472cce9e06dSHerbert Xu
crypto_register_algs(struct crypto_alg * algs,int count)4734b004346SMark Brown int crypto_register_algs(struct crypto_alg *algs, int count)
4744b004346SMark Brown {
4754b004346SMark Brown int i, ret;
4764b004346SMark Brown
4774b004346SMark Brown for (i = 0; i < count; i++) {
4784b004346SMark Brown ret = crypto_register_alg(&algs[i]);
4794b004346SMark Brown if (ret)
4804b004346SMark Brown goto err;
4814b004346SMark Brown }
4824b004346SMark Brown
4834b004346SMark Brown return 0;
4844b004346SMark Brown
4854b004346SMark Brown err:
4864b004346SMark Brown for (--i; i >= 0; --i)
4874b004346SMark Brown crypto_unregister_alg(&algs[i]);
4884b004346SMark Brown
4894b004346SMark Brown return ret;
4904b004346SMark Brown }
4914b004346SMark Brown EXPORT_SYMBOL_GPL(crypto_register_algs);
4924b004346SMark Brown
crypto_unregister_algs(struct crypto_alg * algs,int count)493c6d633a9SEric Biggers void crypto_unregister_algs(struct crypto_alg *algs, int count)
4944b004346SMark Brown {
495c6d633a9SEric Biggers int i;
4964b004346SMark Brown
497c6d633a9SEric Biggers for (i = 0; i < count; i++)
498c6d633a9SEric Biggers crypto_unregister_alg(&algs[i]);
4994b004346SMark Brown }
5004b004346SMark Brown EXPORT_SYMBOL_GPL(crypto_unregister_algs);
5014b004346SMark Brown
crypto_register_template(struct crypto_template * tmpl)5024cc7720cSHerbert Xu int crypto_register_template(struct crypto_template *tmpl)
5034cc7720cSHerbert Xu {
5044cc7720cSHerbert Xu struct crypto_template *q;
5054cc7720cSHerbert Xu int err = -EEXIST;
5064cc7720cSHerbert Xu
5074cc7720cSHerbert Xu down_write(&crypto_alg_sem);
5084cc7720cSHerbert Xu
509002c77a4SJarod Wilson crypto_check_module_sig(tmpl->module);
510002c77a4SJarod Wilson
5114cc7720cSHerbert Xu list_for_each_entry(q, &crypto_template_list, list) {
5124cc7720cSHerbert Xu if (q == tmpl)
5134cc7720cSHerbert Xu goto out;
5144cc7720cSHerbert Xu }
5154cc7720cSHerbert Xu
5164cc7720cSHerbert Xu list_add(&tmpl->list, &crypto_template_list);
5174cc7720cSHerbert Xu err = 0;
5184cc7720cSHerbert Xu out:
5194cc7720cSHerbert Xu up_write(&crypto_alg_sem);
5204cc7720cSHerbert Xu return err;
5214cc7720cSHerbert Xu }
5224cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_template);
5234cc7720cSHerbert Xu
crypto_register_templates(struct crypto_template * tmpls,int count)5249572442dSXiongfeng Wang int crypto_register_templates(struct crypto_template *tmpls, int count)
5259572442dSXiongfeng Wang {
5269572442dSXiongfeng Wang int i, err;
5279572442dSXiongfeng Wang
5289572442dSXiongfeng Wang for (i = 0; i < count; i++) {
5299572442dSXiongfeng Wang err = crypto_register_template(&tmpls[i]);
5309572442dSXiongfeng Wang if (err)
5319572442dSXiongfeng Wang goto out;
5329572442dSXiongfeng Wang }
5339572442dSXiongfeng Wang return 0;
5349572442dSXiongfeng Wang
5359572442dSXiongfeng Wang out:
5369572442dSXiongfeng Wang for (--i; i >= 0; --i)
5379572442dSXiongfeng Wang crypto_unregister_template(&tmpls[i]);
5389572442dSXiongfeng Wang return err;
5399572442dSXiongfeng Wang }
5409572442dSXiongfeng Wang EXPORT_SYMBOL_GPL(crypto_register_templates);
5419572442dSXiongfeng Wang
crypto_unregister_template(struct crypto_template * tmpl)5424cc7720cSHerbert Xu void crypto_unregister_template(struct crypto_template *tmpl)
5434cc7720cSHerbert Xu {
5444cc7720cSHerbert Xu struct crypto_instance *inst;
545b67bfe0dSSasha Levin struct hlist_node *n;
5464cc7720cSHerbert Xu struct hlist_head *list;
5476bfd4809SHerbert Xu LIST_HEAD(users);
5484cc7720cSHerbert Xu
5494cc7720cSHerbert Xu down_write(&crypto_alg_sem);
5504cc7720cSHerbert Xu
5514cc7720cSHerbert Xu BUG_ON(list_empty(&tmpl->list));
5524cc7720cSHerbert Xu list_del_init(&tmpl->list);
5534cc7720cSHerbert Xu
5544cc7720cSHerbert Xu list = &tmpl->instances;
555b67bfe0dSSasha Levin hlist_for_each_entry(inst, list, list) {
5566bfd4809SHerbert Xu int err = crypto_remove_alg(&inst->alg, &users);
5570efcb8d5SJoshua I. James
5586bfd4809SHerbert Xu BUG_ON(err);
5594cc7720cSHerbert Xu }
5604cc7720cSHerbert Xu
5614cc7720cSHerbert Xu up_write(&crypto_alg_sem);
5624cc7720cSHerbert Xu
563b67bfe0dSSasha Levin hlist_for_each_entry_safe(inst, n, list, list) {
564ce8614a3SEric Biggers BUG_ON(refcount_read(&inst->alg.cra_refcnt) != 1);
565319382a6SHerbert Xu crypto_free_instance(inst);
5664cc7720cSHerbert Xu }
5676bfd4809SHerbert Xu crypto_remove_final(&users);
5684cc7720cSHerbert Xu }
5694cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_template);
5704cc7720cSHerbert Xu
crypto_unregister_templates(struct crypto_template * tmpls,int count)5719572442dSXiongfeng Wang void crypto_unregister_templates(struct crypto_template *tmpls, int count)
5729572442dSXiongfeng Wang {
5739572442dSXiongfeng Wang int i;
5749572442dSXiongfeng Wang
5759572442dSXiongfeng Wang for (i = count - 1; i >= 0; --i)
5769572442dSXiongfeng Wang crypto_unregister_template(&tmpls[i]);
5779572442dSXiongfeng Wang }
5789572442dSXiongfeng Wang EXPORT_SYMBOL_GPL(crypto_unregister_templates);
5799572442dSXiongfeng Wang
__crypto_lookup_template(const char * name)5804cc7720cSHerbert Xu static struct crypto_template *__crypto_lookup_template(const char *name)
5814cc7720cSHerbert Xu {
5824cc7720cSHerbert Xu struct crypto_template *q, *tmpl = NULL;
5834cc7720cSHerbert Xu
5844cc7720cSHerbert Xu down_read(&crypto_alg_sem);
5854cc7720cSHerbert Xu list_for_each_entry(q, &crypto_template_list, list) {
5864cc7720cSHerbert Xu if (strcmp(q->name, name))
5874cc7720cSHerbert Xu continue;
5884cc7720cSHerbert Xu if (unlikely(!crypto_tmpl_get(q)))
5894cc7720cSHerbert Xu continue;
5904cc7720cSHerbert Xu
5914cc7720cSHerbert Xu tmpl = q;
5924cc7720cSHerbert Xu break;
5934cc7720cSHerbert Xu }
5944cc7720cSHerbert Xu up_read(&crypto_alg_sem);
5954cc7720cSHerbert Xu
5964cc7720cSHerbert Xu return tmpl;
5974cc7720cSHerbert Xu }
5984cc7720cSHerbert Xu
crypto_lookup_template(const char * name)5994cc7720cSHerbert Xu struct crypto_template *crypto_lookup_template(const char *name)
6004cc7720cSHerbert Xu {
6014943ba16SKees Cook return try_then_request_module(__crypto_lookup_template(name),
6024943ba16SKees Cook "crypto-%s", name);
6034cc7720cSHerbert Xu }
6044cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_lookup_template);
6054cc7720cSHerbert Xu
crypto_register_instance(struct crypto_template * tmpl,struct crypto_instance * inst)6064cc7720cSHerbert Xu int crypto_register_instance(struct crypto_template *tmpl,
6074cc7720cSHerbert Xu struct crypto_instance *inst)
6084cc7720cSHerbert Xu {
60973d3864aSHerbert Xu struct crypto_larval *larval;
6105f567fffSHerbert Xu struct crypto_spawn *spawn;
611d6097b8dSNicolai Stange u32 fips_internal = 0;
612a7008584SEric Biggers LIST_HEAD(algs_to_put);
61373d3864aSHerbert Xu int err;
6144cc7720cSHerbert Xu
6154cc7720cSHerbert Xu err = crypto_check_alg(&inst->alg);
6164cc7720cSHerbert Xu if (err)
6179c521a20SStephan Mueller return err;
6189c521a20SStephan Mueller
6194cc7720cSHerbert Xu inst->alg.cra_module = tmpl->module;
62064a947b1SSteffen Klassert inst->alg.cra_flags |= CRYPTO_ALG_INSTANCE;
6214cc7720cSHerbert Xu
6224cc7720cSHerbert Xu down_write(&crypto_alg_sem);
6234cc7720cSHerbert Xu
6245f567fffSHerbert Xu larval = ERR_PTR(-EAGAIN);
6255f567fffSHerbert Xu for (spawn = inst->spawns; spawn;) {
6265f567fffSHerbert Xu struct crypto_spawn *next;
6275f567fffSHerbert Xu
6285f567fffSHerbert Xu if (spawn->dead)
6295f567fffSHerbert Xu goto unlock;
6305f567fffSHerbert Xu
6315f567fffSHerbert Xu next = spawn->next;
6325f567fffSHerbert Xu spawn->inst = inst;
6335f567fffSHerbert Xu spawn->registered = true;
6345f567fffSHerbert Xu
635d6097b8dSNicolai Stange fips_internal |= spawn->alg->cra_flags;
636d6097b8dSNicolai Stange
6375f567fffSHerbert Xu crypto_mod_put(spawn->alg);
6385f567fffSHerbert Xu
6395f567fffSHerbert Xu spawn = next;
6405f567fffSHerbert Xu }
6415f567fffSHerbert Xu
642d6097b8dSNicolai Stange inst->alg.cra_flags |= (fips_internal & CRYPTO_ALG_FIPS_INTERNAL);
643d6097b8dSNicolai Stange
644a7008584SEric Biggers larval = __crypto_register_alg(&inst->alg, &algs_to_put);
64573d3864aSHerbert Xu if (IS_ERR(larval))
6464cc7720cSHerbert Xu goto unlock;
647b7685262SHerbert Xu else if (larval)
648adad556eSHerbert Xu larval->test_started = true;
649adad556eSHerbert Xu
6504cc7720cSHerbert Xu hlist_add_head(&inst->list, &tmpl->instances);
6514cc7720cSHerbert Xu inst->tmpl = tmpl;
6524cc7720cSHerbert Xu
6534cc7720cSHerbert Xu unlock:
6544cc7720cSHerbert Xu up_write(&crypto_alg_sem);
6554cc7720cSHerbert Xu
656a7008584SEric Biggers if (IS_ERR(larval))
657a7008584SEric Biggers return PTR_ERR(larval);
658b7685262SHerbert Xu
659b7685262SHerbert Xu if (larval)
660b7685262SHerbert Xu crypto_schedule_test(larval);
661b7685262SHerbert Xu else
662a7008584SEric Biggers crypto_remove_final(&algs_to_put);
663b7685262SHerbert Xu
664a7008584SEric Biggers return 0;
6654cc7720cSHerbert Xu }
6664cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_instance);
6674cc7720cSHerbert Xu
crypto_unregister_instance(struct crypto_instance * inst)668c6d633a9SEric Biggers void crypto_unregister_instance(struct crypto_instance *inst)
669ce3fd840SSteffen Klassert {
6701f723710SHerbert Xu LIST_HEAD(list);
671ce3fd840SSteffen Klassert
672ce3fd840SSteffen Klassert down_write(&crypto_alg_sem);
673ce3fd840SSteffen Klassert
67487b16756SHerbert Xu crypto_remove_spawns(&inst->alg, &list, NULL);
6751f723710SHerbert Xu crypto_remove_instance(inst, &list);
676ce3fd840SSteffen Klassert
677ce3fd840SSteffen Klassert up_write(&crypto_alg_sem);
678ce3fd840SSteffen Klassert
6791f723710SHerbert Xu crypto_remove_final(&list);
680ce3fd840SSteffen Klassert }
681ce3fd840SSteffen Klassert EXPORT_SYMBOL_GPL(crypto_unregister_instance);
682ce3fd840SSteffen Klassert
crypto_grab_spawn(struct crypto_spawn * spawn,struct crypto_instance * inst,const char * name,u32 type,u32 mask)683de95c957SEric Biggers int crypto_grab_spawn(struct crypto_spawn *spawn, struct crypto_instance *inst,
684de95c957SEric Biggers const char *name, u32 type, u32 mask)
685d6ef2f19SHerbert Xu {
686d6ef2f19SHerbert Xu struct crypto_alg *alg;
687aed11cf5SEric Biggers int err = -EAGAIN;
688aed11cf5SEric Biggers
689aed11cf5SEric Biggers if (WARN_ON_ONCE(inst == NULL))
690aed11cf5SEric Biggers return -EINVAL;
691d6ef2f19SHerbert Xu
692ca94e937SEric Biggers /* Allow the result of crypto_attr_alg_name() to be passed directly */
693ca94e937SEric Biggers if (IS_ERR(name))
694ca94e937SEric Biggers return PTR_ERR(name);
695ca94e937SEric Biggers
696d6097b8dSNicolai Stange alg = crypto_find_alg(name, spawn->frontend,
697d6097b8dSNicolai Stange type | CRYPTO_ALG_FIPS_INTERNAL, mask);
698d6ef2f19SHerbert Xu if (IS_ERR(alg))
699d6ef2f19SHerbert Xu return PTR_ERR(alg);
700d6ef2f19SHerbert Xu
701aed11cf5SEric Biggers down_write(&crypto_alg_sem);
702aed11cf5SEric Biggers if (!crypto_is_moribund(alg)) {
703aed11cf5SEric Biggers list_add(&spawn->list, &alg->cra_users);
704aed11cf5SEric Biggers spawn->alg = alg;
705aed11cf5SEric Biggers spawn->mask = mask;
706aed11cf5SEric Biggers spawn->next = inst->spawns;
707aed11cf5SEric Biggers inst->spawns = spawn;
7087bcb2c99SEric Biggers inst->alg.cra_flags |=
7097bcb2c99SEric Biggers (alg->cra_flags & CRYPTO_ALG_INHERITED_FLAGS);
710aed11cf5SEric Biggers err = 0;
711aed11cf5SEric Biggers }
712aed11cf5SEric Biggers up_write(&crypto_alg_sem);
7135f567fffSHerbert Xu if (err)
714d6ef2f19SHerbert Xu crypto_mod_put(alg);
715d6ef2f19SHerbert Xu return err;
716d6ef2f19SHerbert Xu }
717d6ef2f19SHerbert Xu EXPORT_SYMBOL_GPL(crypto_grab_spawn);
718d6ef2f19SHerbert Xu
crypto_drop_spawn(struct crypto_spawn * spawn)7196bfd4809SHerbert Xu void crypto_drop_spawn(struct crypto_spawn *spawn)
7206bfd4809SHerbert Xu {
721ff670627SEric Biggers if (!spawn->alg) /* not yet initialized? */
722ff670627SEric Biggers return;
723ff670627SEric Biggers
7246bfd4809SHerbert Xu down_write(&crypto_alg_sem);
7254f87ee11SHerbert Xu if (!spawn->dead)
7266bfd4809SHerbert Xu list_del(&spawn->list);
7276bfd4809SHerbert Xu up_write(&crypto_alg_sem);
7285f567fffSHerbert Xu
729aed11cf5SEric Biggers if (!spawn->registered)
7305f567fffSHerbert Xu crypto_mod_put(spawn->alg);
7316bfd4809SHerbert Xu }
7326bfd4809SHerbert Xu EXPORT_SYMBOL_GPL(crypto_drop_spawn);
7336bfd4809SHerbert Xu
crypto_spawn_alg(struct crypto_spawn * spawn)73497eedce1SHerbert Xu static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn)
7356bfd4809SHerbert Xu {
7366603523bSHerbert Xu struct crypto_alg *alg = ERR_PTR(-EAGAIN);
7376603523bSHerbert Xu struct crypto_alg *target;
7386603523bSHerbert Xu bool shoot = false;
7396bfd4809SHerbert Xu
7406bfd4809SHerbert Xu down_read(&crypto_alg_sem);
7416603523bSHerbert Xu if (!spawn->dead) {
7426bfd4809SHerbert Xu alg = spawn->alg;
7436603523bSHerbert Xu if (!crypto_mod_get(alg)) {
7446603523bSHerbert Xu target = crypto_alg_get(alg);
7456603523bSHerbert Xu shoot = true;
7466603523bSHerbert Xu alg = ERR_PTR(-EAGAIN);
7476603523bSHerbert Xu }
74873669cc5SHerbert Xu }
7496bfd4809SHerbert Xu up_read(&crypto_alg_sem);
7506bfd4809SHerbert Xu
7516603523bSHerbert Xu if (shoot) {
7526603523bSHerbert Xu crypto_shoot_alg(target);
7536603523bSHerbert Xu crypto_alg_put(target);
7546603523bSHerbert Xu }
7556603523bSHerbert Xu
7566603523bSHerbert Xu return alg;
75797eedce1SHerbert Xu }
75897eedce1SHerbert Xu
crypto_spawn_tfm(struct crypto_spawn * spawn,u32 type,u32 mask)75997eedce1SHerbert Xu struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
76097eedce1SHerbert Xu u32 mask)
76197eedce1SHerbert Xu {
76297eedce1SHerbert Xu struct crypto_alg *alg;
76397eedce1SHerbert Xu struct crypto_tfm *tfm;
76497eedce1SHerbert Xu
76597eedce1SHerbert Xu alg = crypto_spawn_alg(spawn);
76697eedce1SHerbert Xu if (IS_ERR(alg))
76797eedce1SHerbert Xu return ERR_CAST(alg);
76897eedce1SHerbert Xu
7692e306ee0SHerbert Xu tfm = ERR_PTR(-EINVAL);
7702e306ee0SHerbert Xu if (unlikely((alg->cra_flags ^ type) & mask))
7712e306ee0SHerbert Xu goto out_put_alg;
7722e306ee0SHerbert Xu
77327d2a330SHerbert Xu tfm = __crypto_alloc_tfm(alg, type, mask);
7746bfd4809SHerbert Xu if (IS_ERR(tfm))
7752e306ee0SHerbert Xu goto out_put_alg;
7766bfd4809SHerbert Xu
7776bfd4809SHerbert Xu return tfm;
7782e306ee0SHerbert Xu
7792e306ee0SHerbert Xu out_put_alg:
7802e306ee0SHerbert Xu crypto_mod_put(alg);
7812e306ee0SHerbert Xu return tfm;
7826bfd4809SHerbert Xu }
7836bfd4809SHerbert Xu EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
7846bfd4809SHerbert Xu
crypto_spawn_tfm2(struct crypto_spawn * spawn)78597eedce1SHerbert Xu void *crypto_spawn_tfm2(struct crypto_spawn *spawn)
78697eedce1SHerbert Xu {
78797eedce1SHerbert Xu struct crypto_alg *alg;
78897eedce1SHerbert Xu struct crypto_tfm *tfm;
78997eedce1SHerbert Xu
79097eedce1SHerbert Xu alg = crypto_spawn_alg(spawn);
79197eedce1SHerbert Xu if (IS_ERR(alg))
79297eedce1SHerbert Xu return ERR_CAST(alg);
79397eedce1SHerbert Xu
79497eedce1SHerbert Xu tfm = crypto_create_tfm(alg, spawn->frontend);
79597eedce1SHerbert Xu if (IS_ERR(tfm))
79697eedce1SHerbert Xu goto out_put_alg;
79797eedce1SHerbert Xu
79897eedce1SHerbert Xu return tfm;
79997eedce1SHerbert Xu
80097eedce1SHerbert Xu out_put_alg:
80197eedce1SHerbert Xu crypto_mod_put(alg);
80297eedce1SHerbert Xu return tfm;
80397eedce1SHerbert Xu }
80497eedce1SHerbert Xu EXPORT_SYMBOL_GPL(crypto_spawn_tfm2);
80597eedce1SHerbert Xu
crypto_register_notifier(struct notifier_block * nb)8062825982dSHerbert Xu int crypto_register_notifier(struct notifier_block *nb)
8072825982dSHerbert Xu {
8082825982dSHerbert Xu return blocking_notifier_chain_register(&crypto_chain, nb);
8092825982dSHerbert Xu }
8102825982dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_notifier);
8112825982dSHerbert Xu
crypto_unregister_notifier(struct notifier_block * nb)8122825982dSHerbert Xu int crypto_unregister_notifier(struct notifier_block *nb)
8132825982dSHerbert Xu {
8142825982dSHerbert Xu return blocking_notifier_chain_unregister(&crypto_chain, nb);
8152825982dSHerbert Xu }
8162825982dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
8172825982dSHerbert Xu
crypto_get_attr_type(struct rtattr ** tb)818ebc610e5SHerbert Xu struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb)
8197fed0bf2SHerbert Xu {
82039e1ee01SHerbert Xu struct rtattr *rta = tb[0];
821ebc610e5SHerbert Xu struct crypto_attr_type *algt;
822ebc610e5SHerbert Xu
823ebc610e5SHerbert Xu if (!rta)
824ebc610e5SHerbert Xu return ERR_PTR(-ENOENT);
825ebc610e5SHerbert Xu if (RTA_PAYLOAD(rta) < sizeof(*algt))
826ebc610e5SHerbert Xu return ERR_PTR(-EINVAL);
82739e1ee01SHerbert Xu if (rta->rta_type != CRYPTOA_TYPE)
82839e1ee01SHerbert Xu return ERR_PTR(-EINVAL);
829ebc610e5SHerbert Xu
830ebc610e5SHerbert Xu algt = RTA_DATA(rta);
831ebc610e5SHerbert Xu
832ebc610e5SHerbert Xu return algt;
833ebc610e5SHerbert Xu }
834ebc610e5SHerbert Xu EXPORT_SYMBOL_GPL(crypto_get_attr_type);
835ebc610e5SHerbert Xu
8367bcb2c99SEric Biggers /**
8377bcb2c99SEric Biggers * crypto_check_attr_type() - check algorithm type and compute inherited mask
8387bcb2c99SEric Biggers * @tb: the template parameters
8397bcb2c99SEric Biggers * @type: the algorithm type the template would be instantiated as
8407bcb2c99SEric Biggers * @mask_ret: (output) the mask that should be passed to crypto_grab_*()
8417bcb2c99SEric Biggers * to restrict the flags of any inner algorithms
8427bcb2c99SEric Biggers *
8437bcb2c99SEric Biggers * Validate that the algorithm type the user requested is compatible with the
8447bcb2c99SEric Biggers * one the template would actually be instantiated as. E.g., if the user is
8457bcb2c99SEric Biggers * doing crypto_alloc_shash("cbc(aes)", ...), this would return an error because
8467bcb2c99SEric Biggers * the "cbc" template creates an "skcipher" algorithm, not an "shash" algorithm.
8477bcb2c99SEric Biggers *
8487bcb2c99SEric Biggers * Also compute the mask to use to restrict the flags of any inner algorithms.
8497bcb2c99SEric Biggers *
8507bcb2c99SEric Biggers * Return: 0 on success; -errno on failure
8517bcb2c99SEric Biggers */
crypto_check_attr_type(struct rtattr ** tb,u32 type,u32 * mask_ret)8527bcb2c99SEric Biggers int crypto_check_attr_type(struct rtattr **tb, u32 type, u32 *mask_ret)
853ebc610e5SHerbert Xu {
854ebc610e5SHerbert Xu struct crypto_attr_type *algt;
855ebc610e5SHerbert Xu
856ebc610e5SHerbert Xu algt = crypto_get_attr_type(tb);
857ebc610e5SHerbert Xu if (IS_ERR(algt))
858ebc610e5SHerbert Xu return PTR_ERR(algt);
859ebc610e5SHerbert Xu
860ebc610e5SHerbert Xu if ((algt->type ^ type) & algt->mask)
861ebc610e5SHerbert Xu return -EINVAL;
862ebc610e5SHerbert Xu
8637bcb2c99SEric Biggers *mask_ret = crypto_algt_inherited_mask(algt);
864ebc610e5SHerbert Xu return 0;
865ebc610e5SHerbert Xu }
866ebc610e5SHerbert Xu EXPORT_SYMBOL_GPL(crypto_check_attr_type);
867ebc610e5SHerbert Xu
crypto_attr_alg_name(struct rtattr * rta)86868b6c7d6SHerbert Xu const char *crypto_attr_alg_name(struct rtattr *rta)
869ebc610e5SHerbert Xu {
8707fed0bf2SHerbert Xu struct crypto_attr_alg *alga;
8717fed0bf2SHerbert Xu
872ebc610e5SHerbert Xu if (!rta)
873ebc610e5SHerbert Xu return ERR_PTR(-ENOENT);
874ebc610e5SHerbert Xu if (RTA_PAYLOAD(rta) < sizeof(*alga))
8757fed0bf2SHerbert Xu return ERR_PTR(-EINVAL);
87639e1ee01SHerbert Xu if (rta->rta_type != CRYPTOA_ALG)
87739e1ee01SHerbert Xu return ERR_PTR(-EINVAL);
8787fed0bf2SHerbert Xu
8797fed0bf2SHerbert Xu alga = RTA_DATA(rta);
8807fed0bf2SHerbert Xu alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;
8817fed0bf2SHerbert Xu
88268b6c7d6SHerbert Xu return alga->name;
88368b6c7d6SHerbert Xu }
88468b6c7d6SHerbert Xu EXPORT_SYMBOL_GPL(crypto_attr_alg_name);
88568b6c7d6SHerbert Xu
crypto_inst_setname(struct crypto_instance * inst,const char * name,struct crypto_alg * alg)88632f27c74SHerbert Xu int crypto_inst_setname(struct crypto_instance *inst, const char *name,
88732f27c74SHerbert Xu struct crypto_alg *alg)
88832f27c74SHerbert Xu {
88932f27c74SHerbert Xu if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", name,
89032f27c74SHerbert Xu alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
89132f27c74SHerbert Xu return -ENAMETOOLONG;
89232f27c74SHerbert Xu
89332f27c74SHerbert Xu if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
89432f27c74SHerbert Xu name, alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
89532f27c74SHerbert Xu return -ENAMETOOLONG;
89632f27c74SHerbert Xu
89732f27c74SHerbert Xu return 0;
89832f27c74SHerbert Xu }
89932f27c74SHerbert Xu EXPORT_SYMBOL_GPL(crypto_inst_setname);
90032f27c74SHerbert Xu
crypto_init_queue(struct crypto_queue * queue,unsigned int max_qlen)901b5b7f088SHerbert Xu void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen)
902b5b7f088SHerbert Xu {
903b5b7f088SHerbert Xu INIT_LIST_HEAD(&queue->list);
904b5b7f088SHerbert Xu queue->backlog = &queue->list;
905b5b7f088SHerbert Xu queue->qlen = 0;
906b5b7f088SHerbert Xu queue->max_qlen = max_qlen;
907b5b7f088SHerbert Xu }
908b5b7f088SHerbert Xu EXPORT_SYMBOL_GPL(crypto_init_queue);
909b5b7f088SHerbert Xu
crypto_enqueue_request(struct crypto_queue * queue,struct crypto_async_request * request)910b5b7f088SHerbert Xu int crypto_enqueue_request(struct crypto_queue *queue,
911b5b7f088SHerbert Xu struct crypto_async_request *request)
912b5b7f088SHerbert Xu {
913b5b7f088SHerbert Xu int err = -EINPROGRESS;
914b5b7f088SHerbert Xu
915b5b7f088SHerbert Xu if (unlikely(queue->qlen >= queue->max_qlen)) {
9166b80ea38SGilad Ben-Yossef if (!(request->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
9176b80ea38SGilad Ben-Yossef err = -ENOSPC;
918b5b7f088SHerbert Xu goto out;
9196b80ea38SGilad Ben-Yossef }
9206b80ea38SGilad Ben-Yossef err = -EBUSY;
921b5b7f088SHerbert Xu if (queue->backlog == &queue->list)
922b5b7f088SHerbert Xu queue->backlog = &request->list;
923b5b7f088SHerbert Xu }
924b5b7f088SHerbert Xu
925b5b7f088SHerbert Xu queue->qlen++;
926b5b7f088SHerbert Xu list_add_tail(&request->list, &queue->list);
927b5b7f088SHerbert Xu
928b5b7f088SHerbert Xu out:
929b5b7f088SHerbert Xu return err;
930b5b7f088SHerbert Xu }
931b5b7f088SHerbert Xu EXPORT_SYMBOL_GPL(crypto_enqueue_request);
932b5b7f088SHerbert Xu
crypto_enqueue_request_head(struct crypto_queue * queue,struct crypto_async_request * request)933ec6e2bf3SIuliana Prodan void crypto_enqueue_request_head(struct crypto_queue *queue,
934ec6e2bf3SIuliana Prodan struct crypto_async_request *request)
935ec6e2bf3SIuliana Prodan {
9364140aafcSOlivier Bacon if (unlikely(queue->qlen >= queue->max_qlen))
9374140aafcSOlivier Bacon queue->backlog = queue->backlog->prev;
9384140aafcSOlivier Bacon
939ec6e2bf3SIuliana Prodan queue->qlen++;
940ec6e2bf3SIuliana Prodan list_add(&request->list, &queue->list);
941ec6e2bf3SIuliana Prodan }
942ec6e2bf3SIuliana Prodan EXPORT_SYMBOL_GPL(crypto_enqueue_request_head);
943ec6e2bf3SIuliana Prodan
crypto_dequeue_request(struct crypto_queue * queue)94431d228ccSHerbert Xu struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue)
945b5b7f088SHerbert Xu {
946b5b7f088SHerbert Xu struct list_head *request;
947b5b7f088SHerbert Xu
948b5b7f088SHerbert Xu if (unlikely(!queue->qlen))
949b5b7f088SHerbert Xu return NULL;
950b5b7f088SHerbert Xu
951b5b7f088SHerbert Xu queue->qlen--;
952b5b7f088SHerbert Xu
953b5b7f088SHerbert Xu if (queue->backlog != &queue->list)
954b5b7f088SHerbert Xu queue->backlog = queue->backlog->next;
955b5b7f088SHerbert Xu
956b5b7f088SHerbert Xu request = queue->list.next;
957f2ffe5a9SHerbert Xu list_del_init(request);
958b5b7f088SHerbert Xu
95931d228ccSHerbert Xu return list_entry(request, struct crypto_async_request, list);
960b5b7f088SHerbert Xu }
961b5b7f088SHerbert Xu EXPORT_SYMBOL_GPL(crypto_dequeue_request);
962b5b7f088SHerbert Xu
crypto_inc_byte(u8 * a,unsigned int size)9637613636dSHerbert Xu static inline void crypto_inc_byte(u8 *a, unsigned int size)
9647613636dSHerbert Xu {
9657613636dSHerbert Xu u8 *b = (a + size);
9667613636dSHerbert Xu u8 c;
9677613636dSHerbert Xu
9687613636dSHerbert Xu for (; size; size--) {
9697613636dSHerbert Xu c = *--b + 1;
9707613636dSHerbert Xu *b = c;
9717613636dSHerbert Xu if (c)
9727613636dSHerbert Xu break;
9737613636dSHerbert Xu }
9747613636dSHerbert Xu }
9757613636dSHerbert Xu
crypto_inc(u8 * a,unsigned int size)9767613636dSHerbert Xu void crypto_inc(u8 *a, unsigned int size)
9777613636dSHerbert Xu {
9787613636dSHerbert Xu __be32 *b = (__be32 *)(a + size);
9797613636dSHerbert Xu u32 c;
9807613636dSHerbert Xu
981db91af0fSArd Biesheuvel if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ||
98227c539aeSArd Biesheuvel IS_ALIGNED((unsigned long)b, __alignof__(*b)))
9837613636dSHerbert Xu for (; size >= 4; size -= 4) {
9847613636dSHerbert Xu c = be32_to_cpu(*--b) + 1;
9857613636dSHerbert Xu *b = cpu_to_be32(c);
98627c539aeSArd Biesheuvel if (likely(c))
9877613636dSHerbert Xu return;
9887613636dSHerbert Xu }
9897613636dSHerbert Xu
9907613636dSHerbert Xu crypto_inc_byte(a, size);
9917613636dSHerbert Xu }
9927613636dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_inc);
9937613636dSHerbert Xu
crypto_alg_extsize(struct crypto_alg * alg)99438d21433SHerbert Xu unsigned int crypto_alg_extsize(struct crypto_alg *alg)
99538d21433SHerbert Xu {
996c2110f28SHerbert Xu return alg->cra_ctxsize +
997c2110f28SHerbert Xu (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1));
99838d21433SHerbert Xu }
99938d21433SHerbert Xu EXPORT_SYMBOL_GPL(crypto_alg_extsize);
100038d21433SHerbert Xu
crypto_type_has_alg(const char * name,const struct crypto_type * frontend,u32 type,u32 mask)1001f2aefdabSHerbert Xu int crypto_type_has_alg(const char *name, const struct crypto_type *frontend,
1002f2aefdabSHerbert Xu u32 type, u32 mask)
1003f2aefdabSHerbert Xu {
1004f2aefdabSHerbert Xu int ret = 0;
1005f2aefdabSHerbert Xu struct crypto_alg *alg = crypto_find_alg(name, frontend, type, mask);
1006f2aefdabSHerbert Xu
1007f2aefdabSHerbert Xu if (!IS_ERR(alg)) {
1008f2aefdabSHerbert Xu crypto_mod_put(alg);
1009f2aefdabSHerbert Xu ret = 1;
1010f2aefdabSHerbert Xu }
1011f2aefdabSHerbert Xu
1012f2aefdabSHerbert Xu return ret;
1013f2aefdabSHerbert Xu }
1014f2aefdabSHerbert Xu EXPORT_SYMBOL_GPL(crypto_type_has_alg);
1015f2aefdabSHerbert Xu
crypto_start_tests(void)1016adad556eSHerbert Xu static void __init crypto_start_tests(void)
1017adad556eSHerbert Xu {
1018f9110822SHerbert Xu if (!IS_BUILTIN(CONFIG_CRYPTO_ALGAPI))
1019f9110822SHerbert Xu return;
1020f9110822SHerbert Xu
102106bd9c96SEric Biggers if (IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS))
102206bd9c96SEric Biggers return;
102306bd9c96SEric Biggers
10248dd458cbSHerbert Xu set_crypto_boot_test_finished();
10258dd458cbSHerbert Xu
1026adad556eSHerbert Xu for (;;) {
1027adad556eSHerbert Xu struct crypto_larval *larval = NULL;
1028adad556eSHerbert Xu struct crypto_alg *q;
1029adad556eSHerbert Xu
1030adad556eSHerbert Xu down_write(&crypto_alg_sem);
1031adad556eSHerbert Xu
1032adad556eSHerbert Xu list_for_each_entry(q, &crypto_alg_list, cra_list) {
1033adad556eSHerbert Xu struct crypto_larval *l;
1034adad556eSHerbert Xu
1035adad556eSHerbert Xu if (!crypto_is_larval(q))
1036adad556eSHerbert Xu continue;
1037adad556eSHerbert Xu
1038adad556eSHerbert Xu l = (void *)q;
1039adad556eSHerbert Xu
1040adad556eSHerbert Xu if (!crypto_is_test_larval(l))
1041adad556eSHerbert Xu continue;
1042adad556eSHerbert Xu
1043adad556eSHerbert Xu if (l->test_started)
1044adad556eSHerbert Xu continue;
1045adad556eSHerbert Xu
1046adad556eSHerbert Xu l->test_started = true;
1047adad556eSHerbert Xu larval = l;
1048adad556eSHerbert Xu break;
1049adad556eSHerbert Xu }
1050adad556eSHerbert Xu
1051adad556eSHerbert Xu up_write(&crypto_alg_sem);
1052adad556eSHerbert Xu
1053adad556eSHerbert Xu if (!larval)
1054adad556eSHerbert Xu break;
1055b7685262SHerbert Xu
1056b7685262SHerbert Xu crypto_schedule_test(larval);
1057adad556eSHerbert Xu }
1058adad556eSHerbert Xu }
1059adad556eSHerbert Xu
crypto_algapi_init(void)1060cce9e06dSHerbert Xu static int __init crypto_algapi_init(void)
1061cce9e06dSHerbert Xu {
1062cce9e06dSHerbert Xu crypto_init_proc();
1063adad556eSHerbert Xu crypto_start_tests();
1064cce9e06dSHerbert Xu return 0;
1065cce9e06dSHerbert Xu }
1066cce9e06dSHerbert Xu
crypto_algapi_exit(void)1067cce9e06dSHerbert Xu static void __exit crypto_algapi_exit(void)
1068cce9e06dSHerbert Xu {
1069cce9e06dSHerbert Xu crypto_exit_proc();
1070cce9e06dSHerbert Xu }
1071cce9e06dSHerbert Xu
1072adad556eSHerbert Xu /*
1073adad556eSHerbert Xu * We run this at late_initcall so that all the built-in algorithms
1074adad556eSHerbert Xu * have had a chance to register themselves first.
1075adad556eSHerbert Xu */
1076adad556eSHerbert Xu late_initcall(crypto_algapi_init);
1077cce9e06dSHerbert Xu module_exit(crypto_algapi_exit);
1078cce9e06dSHerbert Xu
1079cce9e06dSHerbert Xu MODULE_LICENSE("GPL");
1080cce9e06dSHerbert Xu MODULE_DESCRIPTION("Cryptographic algorithms API");
1081c6ce9c58SHerbert Xu MODULE_SOFTDEP("pre: cryptomgr");
1082