xref: /linux-6.15/crypto/api.c (revision fce8b8d5)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Scatterlist Cryptographic API.
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (c) 2002 James Morris <[email protected]>
61da177e4SLinus Torvalds  * Copyright (c) 2002 David S. Miller ([email protected])
75cb1454bSHerbert Xu  * Copyright (c) 2005 Herbert Xu <[email protected]>
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  * Portions derived from Cryptoapi, by Alexander Kjeldaas <[email protected]>
10991d1740SJohn Anthony Kazos Jr  * and Nettle, by Niels Möller.
111da177e4SLinus Torvalds  */
12a61cc448SJesper Juhl 
136bfd4809SHerbert Xu #include <linux/err.h>
141da177e4SLinus Torvalds #include <linux/errno.h>
15adad556eSHerbert Xu #include <linux/jump_label.h>
165cb1454bSHerbert Xu #include <linux/kernel.h>
17176c3652SAdrian Bunk #include <linux/kmod.h>
182b8c19dbSHerbert Xu #include <linux/module.h>
192825982dSHerbert Xu #include <linux/param.h>
20174cd4b1SIngo Molnar #include <linux/sched/signal.h>
211da177e4SLinus Torvalds #include <linux/slab.h>
225cb1454bSHerbert Xu #include <linux/string.h>
23ada69a16SGilad Ben-Yossef #include <linux/completion.h>
241da177e4SLinus Torvalds #include "internal.h"
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds LIST_HEAD(crypto_alg_list);
27cce9e06dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_alg_list);
281da177e4SLinus Torvalds DECLARE_RWSEM(crypto_alg_sem);
29cce9e06dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_alg_sem);
301da177e4SLinus Torvalds 
312825982dSHerbert Xu BLOCKING_NOTIFIER_HEAD(crypto_chain);
322825982dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_chain);
332825982dSHerbert Xu 
34f9110822SHerbert Xu #if IS_BUILTIN(CONFIG_CRYPTO_ALGAPI) && \
35f9110822SHerbert Xu     !IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS)
3606bd9c96SEric Biggers DEFINE_STATIC_KEY_FALSE(__crypto_boot_test_finished);
3706bd9c96SEric Biggers #endif
38adad556eSHerbert Xu 
397505436eSHerbert Xu static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg,
407505436eSHerbert Xu 					     u32 type, u32 mask);
4196ad5955SHerbert Xu static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type,
4296ad5955SHerbert Xu 					    u32 mask);
4377dbd7a9SHerbert Xu 
crypto_mod_get(struct crypto_alg * alg)442825982dSHerbert Xu struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
456521f302SHerbert Xu {
466521f302SHerbert Xu 	return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL;
476521f302SHerbert Xu }
482825982dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_mod_get);
496521f302SHerbert Xu 
crypto_mod_put(struct crypto_alg * alg)502825982dSHerbert Xu void crypto_mod_put(struct crypto_alg *alg)
516521f302SHerbert Xu {
52da7cd59aSHerbert Xu 	struct module *module = alg->cra_module;
53da7cd59aSHerbert Xu 
546521f302SHerbert Xu 	crypto_alg_put(alg);
55da7cd59aSHerbert Xu 	module_put(module);
561da177e4SLinus Torvalds }
572825982dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_mod_put);
581da177e4SLinus Torvalds 
__crypto_alg_lookup(const char * name,u32 type,u32 mask)59c51b6c81SHerbert Xu static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type,
60c51b6c81SHerbert Xu 					      u32 mask)
611da177e4SLinus Torvalds {
621da177e4SLinus Torvalds 	struct crypto_alg *q, *alg = NULL;
632825982dSHerbert Xu 	int best = -2;
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
665cb1454bSHerbert Xu 		int exact, fuzzy;
675cb1454bSHerbert Xu 
686bfd4809SHerbert Xu 		if (crypto_is_moribund(q))
696bfd4809SHerbert Xu 			continue;
706bfd4809SHerbert Xu 
71492e2b63SHerbert Xu 		if ((q->cra_flags ^ type) & mask)
72492e2b63SHerbert Xu 			continue;
73492e2b63SHerbert Xu 
745cb1454bSHerbert Xu 		exact = !strcmp(q->cra_driver_name, name);
755cb1454bSHerbert Xu 		fuzzy = !strcmp(q->cra_name, name);
765cb1454bSHerbert Xu 		if (!exact && !(fuzzy && q->cra_priority > best))
775cb1454bSHerbert Xu 			continue;
785cb1454bSHerbert Xu 
7972fa4919SHerbert Xu 		if (unlikely(!crypto_mod_get(q)))
805cb1454bSHerbert Xu 			continue;
815cb1454bSHerbert Xu 
825cb1454bSHerbert Xu 		best = q->cra_priority;
835cb1454bSHerbert Xu 		if (alg)
8472fa4919SHerbert Xu 			crypto_mod_put(alg);
851da177e4SLinus Torvalds 		alg = q;
865cb1454bSHerbert Xu 
875cb1454bSHerbert Xu 		if (exact)
881da177e4SLinus Torvalds 			break;
891da177e4SLinus Torvalds 	}
901da177e4SLinus Torvalds 
912825982dSHerbert Xu 	return alg;
922825982dSHerbert Xu }
932825982dSHerbert Xu 
crypto_larval_destroy(struct crypto_alg * alg)942825982dSHerbert Xu static void crypto_larval_destroy(struct crypto_alg *alg)
952825982dSHerbert Xu {
962825982dSHerbert Xu 	struct crypto_larval *larval = (void *)alg;
972825982dSHerbert Xu 
982825982dSHerbert Xu 	BUG_ON(!crypto_is_larval(alg));
992bbb3375SHerbert Xu 	if (!IS_ERR_OR_NULL(larval->adult))
1002825982dSHerbert Xu 		crypto_mod_put(larval->adult);
1012825982dSHerbert Xu 	kfree(larval);
1022825982dSHerbert Xu }
1032825982dSHerbert Xu 
crypto_larval_alloc(const char * name,u32 type,u32 mask)10473d3864aSHerbert Xu struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask)
1052825982dSHerbert Xu {
1062825982dSHerbert Xu 	struct crypto_larval *larval;
1072825982dSHerbert Xu 
1082825982dSHerbert Xu 	larval = kzalloc(sizeof(*larval), GFP_KERNEL);
1092825982dSHerbert Xu 	if (!larval)
1106bfd4809SHerbert Xu 		return ERR_PTR(-ENOMEM);
1112825982dSHerbert Xu 
112e7a4142bSHerbert Xu 	type &= ~CRYPTO_ALG_TYPE_MASK | (mask ?: CRYPTO_ALG_TYPE_MASK);
113e7a4142bSHerbert Xu 
114492e2b63SHerbert Xu 	larval->mask = mask;
115492e2b63SHerbert Xu 	larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type;
1162825982dSHerbert Xu 	larval->alg.cra_priority = -1;
1172825982dSHerbert Xu 	larval->alg.cra_destroy = crypto_larval_destroy;
1182825982dSHerbert Xu 
119dd4f8ee7SWolfram Sang 	strscpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME);
1202825982dSHerbert Xu 	init_completion(&larval->completion);
1212825982dSHerbert Xu 
12273d3864aSHerbert Xu 	return larval;
12373d3864aSHerbert Xu }
12473d3864aSHerbert Xu EXPORT_SYMBOL_GPL(crypto_larval_alloc);
12573d3864aSHerbert Xu 
crypto_larval_add(const char * name,u32 type,u32 mask)12673d3864aSHerbert Xu static struct crypto_alg *crypto_larval_add(const char *name, u32 type,
12773d3864aSHerbert Xu 					    u32 mask)
12873d3864aSHerbert Xu {
12973d3864aSHerbert Xu 	struct crypto_alg *alg;
13073d3864aSHerbert Xu 	struct crypto_larval *larval;
13173d3864aSHerbert Xu 
13273d3864aSHerbert Xu 	larval = crypto_larval_alloc(name, type, mask);
13373d3864aSHerbert Xu 	if (IS_ERR(larval))
13473d3864aSHerbert Xu 		return ERR_CAST(larval);
13573d3864aSHerbert Xu 
136ce8614a3SEric Biggers 	refcount_set(&larval->alg.cra_refcnt, 2);
13773d3864aSHerbert Xu 
1382825982dSHerbert Xu 	down_write(&crypto_alg_sem);
139492e2b63SHerbert Xu 	alg = __crypto_alg_lookup(name, type, mask);
1402825982dSHerbert Xu 	if (!alg) {
1412825982dSHerbert Xu 		alg = &larval->alg;
1422825982dSHerbert Xu 		list_add(&alg->cra_list, &crypto_alg_list);
1432825982dSHerbert Xu 	}
1442825982dSHerbert Xu 	up_write(&crypto_alg_sem);
1452825982dSHerbert Xu 
14677dbd7a9SHerbert Xu 	if (alg != &larval->alg) {
1472825982dSHerbert Xu 		kfree(larval);
14877dbd7a9SHerbert Xu 		if (crypto_is_larval(alg))
1497505436eSHerbert Xu 			alg = crypto_larval_wait(alg, type, mask);
15077dbd7a9SHerbert Xu 	}
1512825982dSHerbert Xu 
1522825982dSHerbert Xu 	return alg;
1532825982dSHerbert Xu }
1542825982dSHerbert Xu 
crypto_larval_kill(struct crypto_larval * larval)15537da5d0fSHerbert Xu static void crypto_larval_kill(struct crypto_larval *larval)
1562825982dSHerbert Xu {
15737da5d0fSHerbert Xu 	bool unlinked;
1582825982dSHerbert Xu 
1592825982dSHerbert Xu 	down_write(&crypto_alg_sem);
16037da5d0fSHerbert Xu 	unlinked = list_empty(&larval->alg.cra_list);
16137da5d0fSHerbert Xu 	if (!unlinked)
16237da5d0fSHerbert Xu 		list_del_init(&larval->alg.cra_list);
1632825982dSHerbert Xu 	up_write(&crypto_alg_sem);
1642825982dSHerbert Xu 
16537da5d0fSHerbert Xu 	if (unlinked)
16637da5d0fSHerbert Xu 		return;
16737da5d0fSHerbert Xu 
16837da5d0fSHerbert Xu 	complete_all(&larval->completion);
16937da5d0fSHerbert Xu 	crypto_alg_put(&larval->alg);
17037da5d0fSHerbert Xu }
17137da5d0fSHerbert Xu 
crypto_schedule_test(struct crypto_larval * larval)17237da5d0fSHerbert Xu void crypto_schedule_test(struct crypto_larval *larval)
173adad556eSHerbert Xu {
174adad556eSHerbert Xu 	int err;
175adad556eSHerbert Xu 
176adad556eSHerbert Xu 	err = crypto_probing_notify(CRYPTO_MSG_ALG_REGISTER, larval->adult);
17737da5d0fSHerbert Xu 	WARN_ON_ONCE(err != NOTIFY_STOP);
178adad556eSHerbert Xu }
17937da5d0fSHerbert Xu EXPORT_SYMBOL_GPL(crypto_schedule_test);
180adad556eSHerbert Xu 
crypto_start_test(struct crypto_larval * larval)181adad556eSHerbert Xu static void crypto_start_test(struct crypto_larval *larval)
182adad556eSHerbert Xu {
183adad556eSHerbert Xu 	if (!crypto_is_test_larval(larval))
184adad556eSHerbert Xu 		return;
185adad556eSHerbert Xu 
186adad556eSHerbert Xu 	if (larval->test_started)
187adad556eSHerbert Xu 		return;
188adad556eSHerbert Xu 
189adad556eSHerbert Xu 	down_write(&crypto_alg_sem);
190adad556eSHerbert Xu 	if (larval->test_started) {
191adad556eSHerbert Xu 		up_write(&crypto_alg_sem);
192adad556eSHerbert Xu 		return;
193adad556eSHerbert Xu 	}
194adad556eSHerbert Xu 
195adad556eSHerbert Xu 	larval->test_started = true;
196adad556eSHerbert Xu 	up_write(&crypto_alg_sem);
197adad556eSHerbert Xu 
19837da5d0fSHerbert Xu 	crypto_schedule_test(larval);
199adad556eSHerbert Xu }
200adad556eSHerbert Xu 
crypto_larval_wait(struct crypto_alg * alg,u32 type,u32 mask)2017505436eSHerbert Xu static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg,
2027505436eSHerbert Xu 					     u32 type, u32 mask)
2032825982dSHerbert Xu {
20496ad5955SHerbert Xu 	struct crypto_larval *larval;
20598f9e447SWolfram Sang 	long time_left;
2062825982dSHerbert Xu 
20796ad5955SHerbert Xu again:
20896ad5955SHerbert Xu 	larval = container_of(alg, struct crypto_larval, alg);
20996ad5955SHerbert Xu 
21006bd9c96SEric Biggers 	if (!crypto_boot_test_finished())
211adad556eSHerbert Xu 		crypto_start_test(larval);
212adad556eSHerbert Xu 
21398f9e447SWolfram Sang 	time_left = wait_for_completion_killable_timeout(
21473d3864aSHerbert Xu 		&larval->completion, 60 * HZ);
21573d3864aSHerbert Xu 
2162825982dSHerbert Xu 	alg = larval->adult;
21798f9e447SWolfram Sang 	if (time_left < 0)
21873d3864aSHerbert Xu 		alg = ERR_PTR(-EINTR);
21937da5d0fSHerbert Xu 	else if (!time_left) {
22037da5d0fSHerbert Xu 		if (crypto_is_test_larval(larval))
22137da5d0fSHerbert Xu 			crypto_larval_kill(larval);
22273d3864aSHerbert Xu 		alg = ERR_PTR(-ETIMEDOUT);
22337da5d0fSHerbert Xu 	} else if (!alg) {
22496ad5955SHerbert Xu 		alg = &larval->alg;
22596ad5955SHerbert Xu 		alg = crypto_alg_lookup(alg->cra_name, type, mask) ?:
226e7a4142bSHerbert Xu 		      ERR_PTR(-EAGAIN);
22796ad5955SHerbert Xu 	} else if (IS_ERR(alg))
2282bbb3375SHerbert Xu 		;
22973d3864aSHerbert Xu 	else if (crypto_is_test_larval(larval) &&
23073d3864aSHerbert Xu 		 !(alg->cra_flags & CRYPTO_ALG_TESTED))
23173d3864aSHerbert Xu 		alg = ERR_PTR(-EAGAIN);
232d6097b8dSNicolai Stange 	else if (alg->cra_flags & CRYPTO_ALG_FIPS_INTERNAL)
233d6097b8dSNicolai Stange 		alg = ERR_PTR(-EAGAIN);
23473d3864aSHerbert Xu 	else if (!crypto_mod_get(alg))
23573d3864aSHerbert Xu 		alg = ERR_PTR(-EAGAIN);
2362825982dSHerbert Xu 	crypto_mod_put(&larval->alg);
2372825982dSHerbert Xu 
23896ad5955SHerbert Xu 	if (!IS_ERR(alg) && crypto_is_larval(alg))
23996ad5955SHerbert Xu 		goto again;
24096ad5955SHerbert Xu 
2412825982dSHerbert Xu 	return alg;
2422825982dSHerbert Xu }
2432825982dSHerbert Xu 
crypto_alg_lookup(const char * name,u32 type,u32 mask)2443ca1e994SHerbert Xu static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type,
2453ca1e994SHerbert Xu 					    u32 mask)
2462825982dSHerbert Xu {
247d6097b8dSNicolai Stange 	const u32 fips = CRYPTO_ALG_FIPS_INTERNAL;
2482825982dSHerbert Xu 	struct crypto_alg *alg;
249eb02c38fSHerbert Xu 	u32 test = 0;
250eb02c38fSHerbert Xu 
251eb02c38fSHerbert Xu 	if (!((type | mask) & CRYPTO_ALG_TESTED))
252eb02c38fSHerbert Xu 		test |= CRYPTO_ALG_TESTED;
2532825982dSHerbert Xu 
2542825982dSHerbert Xu 	down_read(&crypto_alg_sem);
255d6097b8dSNicolai Stange 	alg = __crypto_alg_lookup(name, (type | test) & ~fips,
256d6097b8dSNicolai Stange 				  (mask | test) & ~fips);
257d6097b8dSNicolai Stange 	if (alg) {
258d6097b8dSNicolai Stange 		if (((type | mask) ^ fips) & fips)
259d6097b8dSNicolai Stange 			mask |= fips;
260d6097b8dSNicolai Stange 		mask &= fips;
261d6097b8dSNicolai Stange 
262d6097b8dSNicolai Stange 		if (!crypto_is_larval(alg) &&
263d6097b8dSNicolai Stange 		    ((type ^ alg->cra_flags) & mask)) {
264d6097b8dSNicolai Stange 			/* Algorithm is disallowed in FIPS mode. */
265d6097b8dSNicolai Stange 			crypto_mod_put(alg);
266d6097b8dSNicolai Stange 			alg = ERR_PTR(-ENOENT);
267d6097b8dSNicolai Stange 		}
268d6097b8dSNicolai Stange 	} else if (test) {
269b346e492SEric Biggers 		alg = __crypto_alg_lookup(name, type, mask);
270b346e492SEric Biggers 		if (alg && !crypto_is_larval(alg)) {
271b346e492SEric Biggers 			/* Test failed */
272b346e492SEric Biggers 			crypto_mod_put(alg);
273b346e492SEric Biggers 			alg = ERR_PTR(-ELIBBAD);
274b346e492SEric Biggers 		}
275b346e492SEric Biggers 	}
2761da177e4SLinus Torvalds 	up_read(&crypto_alg_sem);
2772825982dSHerbert Xu 
2781da177e4SLinus Torvalds 	return alg;
2791da177e4SLinus Torvalds }
2801da177e4SLinus Torvalds 
crypto_larval_lookup(const char * name,u32 type,u32 mask)281cadc9ab5SEric Biggers static struct crypto_alg *crypto_larval_lookup(const char *name, u32 type,
282cadc9ab5SEric Biggers 					       u32 mask)
283176c3652SAdrian Bunk {
2842825982dSHerbert Xu 	struct crypto_alg *alg;
2852825982dSHerbert Xu 
2866bfd4809SHerbert Xu 	if (!name)
2876bfd4809SHerbert Xu 		return ERR_PTR(-ENOENT);
2886bfd4809SHerbert Xu 
289430b441cSHerbert Xu 	type &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);
2906bfd4809SHerbert Xu 	mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);
291492e2b63SHerbert Xu 
292a760a665SHerbert Xu 	alg = crypto_alg_lookup(name, type, mask);
293e2861fa7SMatthew Garrett 	if (!alg && !(mask & CRYPTO_NOLOAD)) {
2945d26a105SKees Cook 		request_module("crypto-%s", name);
295a760a665SHerbert Xu 
29637fc334cSHerbert Xu 		if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask &
297aa07a699SAlex Riesen 		      CRYPTO_ALG_NEED_FALLBACK))
2985d26a105SKees Cook 			request_module("crypto-%s-all", name);
299a760a665SHerbert Xu 
300a760a665SHerbert Xu 		alg = crypto_alg_lookup(name, type, mask);
301a760a665SHerbert Xu 	}
302a760a665SHerbert Xu 
303eb02c38fSHerbert Xu 	if (!IS_ERR_OR_NULL(alg) && crypto_is_larval(alg))
3047505436eSHerbert Xu 		alg = crypto_larval_wait(alg, type, mask);
305e7a4142bSHerbert Xu 	else if (alg)
306e7a4142bSHerbert Xu 		;
307e7a4142bSHerbert Xu 	else if (!(mask & CRYPTO_ALG_TESTED))
308eb02c38fSHerbert Xu 		alg = crypto_larval_add(name, type, mask);
309e7a4142bSHerbert Xu 	else
310e7a4142bSHerbert Xu 		alg = ERR_PTR(-ENOENT);
3112825982dSHerbert Xu 
312eb02c38fSHerbert Xu 	return alg;
313b9c55aa4SHerbert Xu }
314b9c55aa4SHerbert Xu 
crypto_probing_notify(unsigned long val,void * v)31573d3864aSHerbert Xu int crypto_probing_notify(unsigned long val, void *v)
31673d3864aSHerbert Xu {
31773d3864aSHerbert Xu 	int ok;
31873d3864aSHerbert Xu 
31973d3864aSHerbert Xu 	ok = blocking_notifier_call_chain(&crypto_chain, val, v);
32073d3864aSHerbert Xu 	if (ok == NOTIFY_DONE) {
32173d3864aSHerbert Xu 		request_module("cryptomgr");
32273d3864aSHerbert Xu 		ok = blocking_notifier_call_chain(&crypto_chain, val, v);
32373d3864aSHerbert Xu 	}
32473d3864aSHerbert Xu 
32573d3864aSHerbert Xu 	return ok;
32673d3864aSHerbert Xu }
32773d3864aSHerbert Xu EXPORT_SYMBOL_GPL(crypto_probing_notify);
32873d3864aSHerbert Xu 
crypto_alg_mod_lookup(const char * name,u32 type,u32 mask)329b9c55aa4SHerbert Xu struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
330b9c55aa4SHerbert Xu {
331b9c55aa4SHerbert Xu 	struct crypto_alg *alg;
332b9c55aa4SHerbert Xu 	struct crypto_alg *larval;
333b9c55aa4SHerbert Xu 	int ok;
334b9c55aa4SHerbert Xu 
33506ca7f68SStephan Mueller 	/*
33606ca7f68SStephan Mueller 	 * If the internal flag is set for a cipher, require a caller to
337bc9d6dacSJason Wang 	 * invoke the cipher with the internal flag to use that cipher.
33806ca7f68SStephan Mueller 	 * Also, if a caller wants to allocate a cipher that may or may
33906ca7f68SStephan Mueller 	 * not be an internal cipher, use type | CRYPTO_ALG_INTERNAL and
34006ca7f68SStephan Mueller 	 * !(mask & CRYPTO_ALG_INTERNAL).
34106ca7f68SStephan Mueller 	 */
34206ca7f68SStephan Mueller 	if (!((type | mask) & CRYPTO_ALG_INTERNAL))
34306ca7f68SStephan Mueller 		mask |= CRYPTO_ALG_INTERNAL;
34406ca7f68SStephan Mueller 
345b9c55aa4SHerbert Xu 	larval = crypto_larval_lookup(name, type, mask);
3466bfd4809SHerbert Xu 	if (IS_ERR(larval) || !crypto_is_larval(larval))
3472825982dSHerbert Xu 		return larval;
3482825982dSHerbert Xu 
34973d3864aSHerbert Xu 	ok = crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval);
3502b8c19dbSHerbert Xu 
3512b8c19dbSHerbert Xu 	if (ok == NOTIFY_STOP)
3527505436eSHerbert Xu 		alg = crypto_larval_wait(larval, type, mask);
3532825982dSHerbert Xu 	else {
3542825982dSHerbert Xu 		crypto_mod_put(larval);
3556bfd4809SHerbert Xu 		alg = ERR_PTR(-ENOENT);
3562825982dSHerbert Xu 	}
35737da5d0fSHerbert Xu 	crypto_larval_kill(container_of(larval, struct crypto_larval, alg));
3582825982dSHerbert Xu 	return alg;
359176c3652SAdrian Bunk }
360492e2b63SHerbert Xu EXPORT_SYMBOL_GPL(crypto_alg_mod_lookup);
361176c3652SAdrian Bunk 
crypto_exit_ops(struct crypto_tfm * tfm)3621da177e4SLinus Torvalds static void crypto_exit_ops(struct crypto_tfm *tfm)
3631da177e4SLinus Torvalds {
364e853c3cfSHerbert Xu 	const struct crypto_type *type = tfm->__crt_alg->cra_type;
365e853c3cfSHerbert Xu 
3669c8ae17bSEric Biggers 	if (type && tfm->exit)
3674a779486SHerbert Xu 		tfm->exit(tfm);
3681da177e4SLinus Torvalds }
3691da177e4SLinus Torvalds 
crypto_ctxsize(struct crypto_alg * alg,u32 type,u32 mask)37027d2a330SHerbert Xu static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask)
371fbdae9f3SHerbert Xu {
37227d2a330SHerbert Xu 	const struct crypto_type *type_obj = alg->cra_type;
373fbdae9f3SHerbert Xu 	unsigned int len;
374fbdae9f3SHerbert Xu 
375e853c3cfSHerbert Xu 	len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1);
37627d2a330SHerbert Xu 	if (type_obj)
37727d2a330SHerbert Xu 		return len + type_obj->ctxsize(alg, type, mask);
378e853c3cfSHerbert Xu 
379fbdae9f3SHerbert Xu 	switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
380fbdae9f3SHerbert Xu 	default:
381fbdae9f3SHerbert Xu 		BUG();
382fbdae9f3SHerbert Xu 
383fbdae9f3SHerbert Xu 	case CRYPTO_ALG_TYPE_CIPHER:
384f1ddcaf3SHerbert Xu 		len += crypto_cipher_ctxsize(alg);
385fbdae9f3SHerbert Xu 		break;
386fbdae9f3SHerbert Xu 	}
387fbdae9f3SHerbert Xu 
388e853c3cfSHerbert Xu 	return len;
389fbdae9f3SHerbert Xu }
390fbdae9f3SHerbert Xu 
crypto_shoot_alg(struct crypto_alg * alg)3916603523bSHerbert Xu void crypto_shoot_alg(struct crypto_alg *alg)
3926bfd4809SHerbert Xu {
3936bfd4809SHerbert Xu 	down_write(&crypto_alg_sem);
3946bfd4809SHerbert Xu 	alg->cra_flags |= CRYPTO_ALG_DYING;
3956bfd4809SHerbert Xu 	up_write(&crypto_alg_sem);
3966bfd4809SHerbert Xu }
3976603523bSHerbert Xu EXPORT_SYMBOL_GPL(crypto_shoot_alg);
3986bfd4809SHerbert Xu 
__crypto_alloc_tfmgfp(struct crypto_alg * alg,u32 type,u32 mask,gfp_t gfp)399fa3b3565SHerbert Xu struct crypto_tfm *__crypto_alloc_tfmgfp(struct crypto_alg *alg, u32 type,
400fa3b3565SHerbert Xu 					 u32 mask, gfp_t gfp)
4011da177e4SLinus Torvalds {
40217f7b983SLi zeming 	struct crypto_tfm *tfm;
403fbdae9f3SHerbert Xu 	unsigned int tfm_size;
4046bfd4809SHerbert Xu 	int err = -ENOMEM;
4051da177e4SLinus Torvalds 
40627d2a330SHerbert Xu 	tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, type, mask);
407fa3b3565SHerbert Xu 	tfm = kzalloc(tfm_size, gfp);
4081da177e4SLinus Torvalds 	if (tfm == NULL)
4099765d262SAkinobu Mita 		goto out_err;
4101da177e4SLinus Torvalds 
4111da177e4SLinus Torvalds 	tfm->__crt_alg = alg;
412ae131f49SHerbert Xu 	refcount_set(&tfm->refcnt, 1);
4131da177e4SLinus Torvalds 
4144a779486SHerbert Xu 	if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm)))
415c7fc0599SHerbert Xu 		goto cra_init_failed;
4161da177e4SLinus Torvalds 
4171da177e4SLinus Torvalds 	goto out;
4181da177e4SLinus Torvalds 
419c7fc0599SHerbert Xu cra_init_failed:
420c7fc0599SHerbert Xu 	crypto_exit_ops(tfm);
4214a779486SHerbert Xu 	if (err == -EAGAIN)
4224a779486SHerbert Xu 		crypto_shoot_alg(alg);
4231da177e4SLinus Torvalds 	kfree(tfm);
4249765d262SAkinobu Mita out_err:
4256bfd4809SHerbert Xu 	tfm = ERR_PTR(err);
4261da177e4SLinus Torvalds out:
4271da177e4SLinus Torvalds 	return tfm;
4281da177e4SLinus Torvalds }
429fa3b3565SHerbert Xu EXPORT_SYMBOL_GPL(__crypto_alloc_tfmgfp);
430fa3b3565SHerbert Xu 
__crypto_alloc_tfm(struct crypto_alg * alg,u32 type,u32 mask)431fa3b3565SHerbert Xu struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
432fa3b3565SHerbert Xu 				      u32 mask)
433fa3b3565SHerbert Xu {
434fa3b3565SHerbert Xu 	return __crypto_alloc_tfmgfp(alg, type, mask, GFP_KERNEL);
435fa3b3565SHerbert Xu }
4366bfd4809SHerbert Xu EXPORT_SYMBOL_GPL(__crypto_alloc_tfm);
4376bfd4809SHerbert Xu 
4386d7d684dSHerbert Xu /*
4396d7d684dSHerbert Xu  *	crypto_alloc_base - Locate algorithm and allocate transform
4406d7d684dSHerbert Xu  *	@alg_name: Name of algorithm
4416d7d684dSHerbert Xu  *	@type: Type of algorithm
4426d7d684dSHerbert Xu  *	@mask: Mask for type comparison
4436d7d684dSHerbert Xu  *
4447b0bac64SHerbert Xu  *	This function should not be used by new algorithm types.
445fd1a1900SCristian Stoica  *	Please use crypto_alloc_tfm instead.
4467b0bac64SHerbert Xu  *
4476d7d684dSHerbert Xu  *	crypto_alloc_base() will first attempt to locate an already loaded
4486d7d684dSHerbert Xu  *	algorithm.  If that fails and the kernel supports dynamically loadable
4496d7d684dSHerbert Xu  *	modules, it will then attempt to load a module of the same name or
4506d7d684dSHerbert Xu  *	alias.  If that fails it will send a query to any loaded crypto manager
4516d7d684dSHerbert Xu  *	to construct an algorithm on the fly.  A refcount is grabbed on the
4526d7d684dSHerbert Xu  *	algorithm which is then associated with the new transform.
4536d7d684dSHerbert Xu  *
4546d7d684dSHerbert Xu  *	The returned transform is of a non-determinate type.  Most people
4556d7d684dSHerbert Xu  *	should use one of the more specific allocation functions such as
456c65058b7SEric Biggers  *	crypto_alloc_skcipher().
4576d7d684dSHerbert Xu  *
4586d7d684dSHerbert Xu  *	In case of error the return value is an error pointer.
4596d7d684dSHerbert Xu  */
crypto_alloc_base(const char * alg_name,u32 type,u32 mask)4606d7d684dSHerbert Xu struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask)
4616d7d684dSHerbert Xu {
4626d7d684dSHerbert Xu 	struct crypto_tfm *tfm;
4636d7d684dSHerbert Xu 	int err;
4646d7d684dSHerbert Xu 
4656d7d684dSHerbert Xu 	for (;;) {
4666d7d684dSHerbert Xu 		struct crypto_alg *alg;
4676d7d684dSHerbert Xu 
4686d7d684dSHerbert Xu 		alg = crypto_alg_mod_lookup(alg_name, type, mask);
4699765d262SAkinobu Mita 		if (IS_ERR(alg)) {
4706d7d684dSHerbert Xu 			err = PTR_ERR(alg);
4716d7d684dSHerbert Xu 			goto err;
4729765d262SAkinobu Mita 		}
4736d7d684dSHerbert Xu 
47427d2a330SHerbert Xu 		tfm = __crypto_alloc_tfm(alg, type, mask);
4756d7d684dSHerbert Xu 		if (!IS_ERR(tfm))
4769765d262SAkinobu Mita 			return tfm;
4776d7d684dSHerbert Xu 
4786d7d684dSHerbert Xu 		crypto_mod_put(alg);
4796d7d684dSHerbert Xu 		err = PTR_ERR(tfm);
4806d7d684dSHerbert Xu 
4816d7d684dSHerbert Xu err:
4826d7d684dSHerbert Xu 		if (err != -EAGAIN)
4836d7d684dSHerbert Xu 			break;
4843fc89adbSHerbert Xu 		if (fatal_signal_pending(current)) {
4856d7d684dSHerbert Xu 			err = -EINTR;
4866d7d684dSHerbert Xu 			break;
4876d7d684dSHerbert Xu 		}
4889765d262SAkinobu Mita 	}
4896d7d684dSHerbert Xu 
4909765d262SAkinobu Mita 	return ERR_PTR(err);
4916d7d684dSHerbert Xu }
4926d7d684dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_alloc_base);
4936d7d684dSHerbert Xu 
crypto_alloc_tfmmem(struct crypto_alg * alg,const struct crypto_type * frontend,int node,gfp_t gfp)4943c3a24cbSHerbert Xu static void *crypto_alloc_tfmmem(struct crypto_alg *alg,
4953c3a24cbSHerbert Xu 				 const struct crypto_type *frontend, int node,
4963c3a24cbSHerbert Xu 				 gfp_t gfp)
4977b0bac64SHerbert Xu {
4983c3a24cbSHerbert Xu 	struct crypto_tfm *tfm;
4997b0bac64SHerbert Xu 	unsigned int tfmsize;
5007b0bac64SHerbert Xu 	unsigned int total;
5013c3a24cbSHerbert Xu 	char *mem;
5027b0bac64SHerbert Xu 
5037b0bac64SHerbert Xu 	tfmsize = frontend->tfmsize;
5042ca33da1SHerbert Xu 	total = tfmsize + sizeof(*tfm) + frontend->extsize(alg);
5057b0bac64SHerbert Xu 
5063c3a24cbSHerbert Xu 	mem = kzalloc_node(total, gfp, node);
5077b0bac64SHerbert Xu 	if (mem == NULL)
5083c3a24cbSHerbert Xu 		return ERR_PTR(-ENOMEM);
5097b0bac64SHerbert Xu 
5107b0bac64SHerbert Xu 	tfm = (struct crypto_tfm *)(mem + tfmsize);
5117b0bac64SHerbert Xu 	tfm->__crt_alg = alg;
5127bc13b5bSBarry Song 	tfm->node = node;
513ae131f49SHerbert Xu 	refcount_set(&tfm->refcnt, 1);
5147b0bac64SHerbert Xu 
5153c3a24cbSHerbert Xu 	return mem;
5163c3a24cbSHerbert Xu }
5173c3a24cbSHerbert Xu 
crypto_create_tfm_node(struct crypto_alg * alg,const struct crypto_type * frontend,int node)5183c3a24cbSHerbert Xu void *crypto_create_tfm_node(struct crypto_alg *alg,
5193c3a24cbSHerbert Xu 			     const struct crypto_type *frontend,
5203c3a24cbSHerbert Xu 			     int node)
5213c3a24cbSHerbert Xu {
5223c3a24cbSHerbert Xu 	struct crypto_tfm *tfm;
5233c3a24cbSHerbert Xu 	char *mem;
5243c3a24cbSHerbert Xu 	int err;
5253c3a24cbSHerbert Xu 
5263c3a24cbSHerbert Xu 	mem = crypto_alloc_tfmmem(alg, frontend, node, GFP_KERNEL);
5273c3a24cbSHerbert Xu 	if (IS_ERR(mem))
5283c3a24cbSHerbert Xu 		goto out;
5293c3a24cbSHerbert Xu 
5303c3a24cbSHerbert Xu 	tfm = (struct crypto_tfm *)(mem + frontend->tfmsize);
5313c3a24cbSHerbert Xu 
5322ca33da1SHerbert Xu 	err = frontend->init_tfm(tfm);
5337b0bac64SHerbert Xu 	if (err)
5347b0bac64SHerbert Xu 		goto out_free_tfm;
5357b0bac64SHerbert Xu 
5367b0bac64SHerbert Xu 	if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm)))
5377b0bac64SHerbert Xu 		goto cra_init_failed;
5387b0bac64SHerbert Xu 
5397b0bac64SHerbert Xu 	goto out;
5407b0bac64SHerbert Xu 
5417b0bac64SHerbert Xu cra_init_failed:
5427b0bac64SHerbert Xu 	crypto_exit_ops(tfm);
5437b0bac64SHerbert Xu out_free_tfm:
5447b0bac64SHerbert Xu 	if (err == -EAGAIN)
5457b0bac64SHerbert Xu 		crypto_shoot_alg(alg);
5467b0bac64SHerbert Xu 	kfree(mem);
5473f683d61SHerbert Xu 	mem = ERR_PTR(err);
5487b0bac64SHerbert Xu out:
5493f683d61SHerbert Xu 	return mem;
5507b0bac64SHerbert Xu }
5517bc13b5bSBarry Song EXPORT_SYMBOL_GPL(crypto_create_tfm_node);
5527b0bac64SHerbert Xu 
crypto_clone_tfm(const struct crypto_type * frontend,struct crypto_tfm * otfm)5533c3a24cbSHerbert Xu void *crypto_clone_tfm(const struct crypto_type *frontend,
5543c3a24cbSHerbert Xu 		       struct crypto_tfm *otfm)
5553c3a24cbSHerbert Xu {
5563c3a24cbSHerbert Xu 	struct crypto_alg *alg = otfm->__crt_alg;
5573c3a24cbSHerbert Xu 	struct crypto_tfm *tfm;
5583c3a24cbSHerbert Xu 	char *mem;
5593c3a24cbSHerbert Xu 
5603c3a24cbSHerbert Xu 	mem = ERR_PTR(-ESTALE);
5613c3a24cbSHerbert Xu 	if (unlikely(!crypto_mod_get(alg)))
5623c3a24cbSHerbert Xu 		goto out;
5633c3a24cbSHerbert Xu 
5643c3a24cbSHerbert Xu 	mem = crypto_alloc_tfmmem(alg, frontend, otfm->node, GFP_ATOMIC);
5653c3a24cbSHerbert Xu 	if (IS_ERR(mem)) {
5663c3a24cbSHerbert Xu 		crypto_mod_put(alg);
5673c3a24cbSHerbert Xu 		goto out;
5683c3a24cbSHerbert Xu 	}
5693c3a24cbSHerbert Xu 
5703c3a24cbSHerbert Xu 	tfm = (struct crypto_tfm *)(mem + frontend->tfmsize);
5713c3a24cbSHerbert Xu 	tfm->crt_flags = otfm->crt_flags;
5723c3a24cbSHerbert Xu 	tfm->exit = otfm->exit;
5733c3a24cbSHerbert Xu 
5743c3a24cbSHerbert Xu out:
5753c3a24cbSHerbert Xu 	return mem;
5763c3a24cbSHerbert Xu }
5773c3a24cbSHerbert Xu EXPORT_SYMBOL_GPL(crypto_clone_tfm);
5783c3a24cbSHerbert Xu 
crypto_find_alg(const char * alg_name,const struct crypto_type * frontend,u32 type,u32 mask)579d06854f0SHerbert Xu struct crypto_alg *crypto_find_alg(const char *alg_name,
580d06854f0SHerbert Xu 				   const struct crypto_type *frontend,
581d06854f0SHerbert Xu 				   u32 type, u32 mask)
582d06854f0SHerbert Xu {
583d06854f0SHerbert Xu 	if (frontend) {
584d06854f0SHerbert Xu 		type &= frontend->maskclear;
585d06854f0SHerbert Xu 		mask &= frontend->maskclear;
586d06854f0SHerbert Xu 		type |= frontend->type;
587d06854f0SHerbert Xu 		mask |= frontend->maskset;
588d06854f0SHerbert Xu 	}
589d06854f0SHerbert Xu 
5904989d4f0SHerbert Xu 	return crypto_alg_mod_lookup(alg_name, type, mask);
591d06854f0SHerbert Xu }
592d06854f0SHerbert Xu EXPORT_SYMBOL_GPL(crypto_find_alg);
593d06854f0SHerbert Xu 
5947b0bac64SHerbert Xu /*
5957bc13b5bSBarry Song  *	crypto_alloc_tfm_node - Locate algorithm and allocate transform
5967b0bac64SHerbert Xu  *	@alg_name: Name of algorithm
5977b0bac64SHerbert Xu  *	@frontend: Frontend algorithm type
5987b0bac64SHerbert Xu  *	@type: Type of algorithm
5997b0bac64SHerbert Xu  *	@mask: Mask for type comparison
6007bc13b5bSBarry Song  *	@node: NUMA node in which users desire to put requests, if node is
6017bc13b5bSBarry Song  *		NUMA_NO_NODE, it means users have no special requirement.
6027b0bac64SHerbert Xu  *
6037b0bac64SHerbert Xu  *	crypto_alloc_tfm() will first attempt to locate an already loaded
6047b0bac64SHerbert Xu  *	algorithm.  If that fails and the kernel supports dynamically loadable
6057b0bac64SHerbert Xu  *	modules, it will then attempt to load a module of the same name or
6067b0bac64SHerbert Xu  *	alias.  If that fails it will send a query to any loaded crypto manager
6077b0bac64SHerbert Xu  *	to construct an algorithm on the fly.  A refcount is grabbed on the
6087b0bac64SHerbert Xu  *	algorithm which is then associated with the new transform.
6097b0bac64SHerbert Xu  *
6107b0bac64SHerbert Xu  *	The returned transform is of a non-determinate type.  Most people
6117b0bac64SHerbert Xu  *	should use one of the more specific allocation functions such as
6120a940d4eSEric Biggers  *	crypto_alloc_skcipher().
6137b0bac64SHerbert Xu  *
6147b0bac64SHerbert Xu  *	In case of error the return value is an error pointer.
6157b0bac64SHerbert Xu  */
6167bc13b5bSBarry Song 
crypto_alloc_tfm_node(const char * alg_name,const struct crypto_type * frontend,u32 type,u32 mask,int node)6177bc13b5bSBarry Song void *crypto_alloc_tfm_node(const char *alg_name,
6187bc13b5bSBarry Song 		       const struct crypto_type *frontend, u32 type, u32 mask,
6197bc13b5bSBarry Song 		       int node)
6207b0bac64SHerbert Xu {
6213f683d61SHerbert Xu 	void *tfm;
6227b0bac64SHerbert Xu 	int err;
6237b0bac64SHerbert Xu 
6247b0bac64SHerbert Xu 	for (;;) {
6257b0bac64SHerbert Xu 		struct crypto_alg *alg;
6267b0bac64SHerbert Xu 
627d06854f0SHerbert Xu 		alg = crypto_find_alg(alg_name, frontend, type, mask);
6287b0bac64SHerbert Xu 		if (IS_ERR(alg)) {
6297b0bac64SHerbert Xu 			err = PTR_ERR(alg);
6307b0bac64SHerbert Xu 			goto err;
6317b0bac64SHerbert Xu 		}
6327b0bac64SHerbert Xu 
6337bc13b5bSBarry Song 		tfm = crypto_create_tfm_node(alg, frontend, node);
6347b0bac64SHerbert Xu 		if (!IS_ERR(tfm))
6357b0bac64SHerbert Xu 			return tfm;
6367b0bac64SHerbert Xu 
6377b0bac64SHerbert Xu 		crypto_mod_put(alg);
6387b0bac64SHerbert Xu 		err = PTR_ERR(tfm);
6397b0bac64SHerbert Xu 
6407b0bac64SHerbert Xu err:
6417b0bac64SHerbert Xu 		if (err != -EAGAIN)
6427b0bac64SHerbert Xu 			break;
6433fc89adbSHerbert Xu 		if (fatal_signal_pending(current)) {
6447b0bac64SHerbert Xu 			err = -EINTR;
6457b0bac64SHerbert Xu 			break;
6467b0bac64SHerbert Xu 		}
6477b0bac64SHerbert Xu 	}
6487b0bac64SHerbert Xu 
6497b0bac64SHerbert Xu 	return ERR_PTR(err);
6507b0bac64SHerbert Xu }
6517bc13b5bSBarry Song EXPORT_SYMBOL_GPL(crypto_alloc_tfm_node);
6527b0bac64SHerbert Xu 
6536d7d684dSHerbert Xu /*
6547b2cd92aSHerbert Xu  *	crypto_destroy_tfm - Free crypto transform
6557b2cd92aSHerbert Xu  *	@mem: Start of tfm slab
6566d7d684dSHerbert Xu  *	@tfm: Transform to free
6576d7d684dSHerbert Xu  *
6587b2cd92aSHerbert Xu  *	This function frees up the transform and any associated resources,
6596d7d684dSHerbert Xu  *	then drops the refcount on the associated algorithm.
6606d7d684dSHerbert Xu  */
crypto_destroy_tfm(void * mem,struct crypto_tfm * tfm)6617b2cd92aSHerbert Xu void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm)
6621da177e4SLinus Torvalds {
663a61cc448SJesper Juhl 	struct crypto_alg *alg;
664a61cc448SJesper Juhl 
66583681f2bSArd Biesheuvel 	if (IS_ERR_OR_NULL(mem))
666a61cc448SJesper Juhl 		return;
667a61cc448SJesper Juhl 
668ae131f49SHerbert Xu 	if (!refcount_dec_and_test(&tfm->refcnt))
669ae131f49SHerbert Xu 		return;
670a61cc448SJesper Juhl 	alg = tfm->__crt_alg;
6711da177e4SLinus Torvalds 
6724a779486SHerbert Xu 	if (!tfm->exit && alg->cra_exit)
673c7fc0599SHerbert Xu 		alg->cra_exit(tfm);
6741da177e4SLinus Torvalds 	crypto_exit_ops(tfm);
67572fa4919SHerbert Xu 	crypto_mod_put(alg);
676453431a5SWaiman Long 	kfree_sensitive(mem);
6771da177e4SLinus Torvalds }
6787b2cd92aSHerbert Xu EXPORT_SYMBOL_GPL(crypto_destroy_tfm);
679fce32d70SHerbert Xu 
crypto_has_alg(const char * name,u32 type,u32 mask)680fce32d70SHerbert Xu int crypto_has_alg(const char *name, u32 type, u32 mask)
681fce32d70SHerbert Xu {
682fce32d70SHerbert Xu 	int ret = 0;
683fce32d70SHerbert Xu 	struct crypto_alg *alg = crypto_alg_mod_lookup(name, type, mask);
684fce32d70SHerbert Xu 
685fce32d70SHerbert Xu 	if (!IS_ERR(alg)) {
686fce32d70SHerbert Xu 		crypto_mod_put(alg);
687fce32d70SHerbert Xu 		ret = 1;
688fce32d70SHerbert Xu 	}
689fce32d70SHerbert Xu 
690fce32d70SHerbert Xu 	return ret;
691fce32d70SHerbert Xu }
692fce32d70SHerbert Xu EXPORT_SYMBOL_GPL(crypto_has_alg);
693c3715cb9SSebastian Siewior 
crypto_req_done(void * data,int err)694255e48ebSHerbert Xu void crypto_req_done(void *data, int err)
695ada69a16SGilad Ben-Yossef {
696255e48ebSHerbert Xu 	struct crypto_wait *wait = data;
697ada69a16SGilad Ben-Yossef 
698ada69a16SGilad Ben-Yossef 	if (err == -EINPROGRESS)
699ada69a16SGilad Ben-Yossef 		return;
700ada69a16SGilad Ben-Yossef 
701ada69a16SGilad Ben-Yossef 	wait->err = err;
702ada69a16SGilad Ben-Yossef 	complete(&wait->completion);
703ada69a16SGilad Ben-Yossef }
704ada69a16SGilad Ben-Yossef EXPORT_SYMBOL_GPL(crypto_req_done);
705ada69a16SGilad Ben-Yossef 
crypto_destroy_alg(struct crypto_alg * alg)706*3d6979bfSHerbert Xu void crypto_destroy_alg(struct crypto_alg *alg)
707*3d6979bfSHerbert Xu {
708*3d6979bfSHerbert Xu 	if (alg->cra_type && alg->cra_type->destroy)
709*3d6979bfSHerbert Xu 		alg->cra_type->destroy(alg);
710*3d6979bfSHerbert Xu 
711*3d6979bfSHerbert Xu 	if (alg->cra_destroy)
712*3d6979bfSHerbert Xu 		alg->cra_destroy(alg);
713*3d6979bfSHerbert Xu }
714*3d6979bfSHerbert Xu EXPORT_SYMBOL_GPL(crypto_destroy_alg);
715*3d6979bfSHerbert Xu 
716c3715cb9SSebastian Siewior MODULE_DESCRIPTION("Cryptographic core API");
717c3715cb9SSebastian Siewior MODULE_LICENSE("GPL");
718