18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Scatterlist Cryptographic API. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 68c2ecf20Sopenharmony_ci * Copyright (c) 2002 David S. Miller (davem@redhat.com) 78c2ecf20Sopenharmony_ci * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no> 108c2ecf20Sopenharmony_ci * and Nettle, by Niels Möller. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/err.h> 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/kmod.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/param.h> 198c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <linux/string.h> 228c2ecf20Sopenharmony_ci#include <linux/completion.h> 238c2ecf20Sopenharmony_ci#include "internal.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciLIST_HEAD(crypto_alg_list); 268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_alg_list); 278c2ecf20Sopenharmony_ciDECLARE_RWSEM(crypto_alg_sem); 288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_alg_sem); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciBLOCKING_NOTIFIER_HEAD(crypto_chain); 318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_chain); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistruct crypto_alg *crypto_mod_get(struct crypto_alg *alg) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_mod_get); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_civoid crypto_mod_put(struct crypto_alg *alg) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct module *module = alg->cra_module; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci crypto_alg_put(alg); 468c2ecf20Sopenharmony_ci module_put(module); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_mod_put); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic inline int crypto_is_test_larval(struct crypto_larval *larval) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci return larval->alg.cra_driver_name[0]; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, 568c2ecf20Sopenharmony_ci u32 mask) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct crypto_alg *q, *alg = NULL; 598c2ecf20Sopenharmony_ci int best = -2; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci list_for_each_entry(q, &crypto_alg_list, cra_list) { 628c2ecf20Sopenharmony_ci int exact, fuzzy; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (crypto_is_moribund(q)) 658c2ecf20Sopenharmony_ci continue; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if ((q->cra_flags ^ type) & mask) 688c2ecf20Sopenharmony_ci continue; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (crypto_is_larval(q) && 718c2ecf20Sopenharmony_ci !crypto_is_test_larval((struct crypto_larval *)q) && 728c2ecf20Sopenharmony_ci ((struct crypto_larval *)q)->mask != mask) 738c2ecf20Sopenharmony_ci continue; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci exact = !strcmp(q->cra_driver_name, name); 768c2ecf20Sopenharmony_ci fuzzy = !strcmp(q->cra_name, name); 778c2ecf20Sopenharmony_ci if (!exact && !(fuzzy && q->cra_priority > best)) 788c2ecf20Sopenharmony_ci continue; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (unlikely(!crypto_mod_get(q))) 818c2ecf20Sopenharmony_ci continue; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci best = q->cra_priority; 848c2ecf20Sopenharmony_ci if (alg) 858c2ecf20Sopenharmony_ci crypto_mod_put(alg); 868c2ecf20Sopenharmony_ci alg = q; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (exact) 898c2ecf20Sopenharmony_ci break; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return alg; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic void crypto_larval_destroy(struct crypto_alg *alg) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct crypto_larval *larval = (void *)alg; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci BUG_ON(!crypto_is_larval(alg)); 1008c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(larval->adult)) 1018c2ecf20Sopenharmony_ci crypto_mod_put(larval->adult); 1028c2ecf20Sopenharmony_ci kfree(larval); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistruct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct crypto_larval *larval; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci larval = kzalloc(sizeof(*larval), GFP_KERNEL); 1108c2ecf20Sopenharmony_ci if (!larval) 1118c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci larval->mask = mask; 1148c2ecf20Sopenharmony_ci larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type; 1158c2ecf20Sopenharmony_ci larval->alg.cra_priority = -1; 1168c2ecf20Sopenharmony_ci larval->alg.cra_destroy = crypto_larval_destroy; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME); 1198c2ecf20Sopenharmony_ci init_completion(&larval->completion); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return larval; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_larval_alloc); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic struct crypto_alg *crypto_larval_add(const char *name, u32 type, 1268c2ecf20Sopenharmony_ci u32 mask) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct crypto_alg *alg; 1298c2ecf20Sopenharmony_ci struct crypto_larval *larval; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci larval = crypto_larval_alloc(name, type, mask); 1328c2ecf20Sopenharmony_ci if (IS_ERR(larval)) 1338c2ecf20Sopenharmony_ci return ERR_CAST(larval); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci refcount_set(&larval->alg.cra_refcnt, 2); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci down_write(&crypto_alg_sem); 1388c2ecf20Sopenharmony_ci alg = __crypto_alg_lookup(name, type, mask); 1398c2ecf20Sopenharmony_ci if (!alg) { 1408c2ecf20Sopenharmony_ci alg = &larval->alg; 1418c2ecf20Sopenharmony_ci list_add(&alg->cra_list, &crypto_alg_list); 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci up_write(&crypto_alg_sem); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (alg != &larval->alg) { 1468c2ecf20Sopenharmony_ci kfree(larval); 1478c2ecf20Sopenharmony_ci if (crypto_is_larval(alg)) 1488c2ecf20Sopenharmony_ci alg = crypto_larval_wait(alg); 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return alg; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_civoid crypto_larval_kill(struct crypto_alg *alg) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci struct crypto_larval *larval = (void *)alg; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci down_write(&crypto_alg_sem); 1598c2ecf20Sopenharmony_ci list_del(&alg->cra_list); 1608c2ecf20Sopenharmony_ci up_write(&crypto_alg_sem); 1618c2ecf20Sopenharmony_ci complete_all(&larval->completion); 1628c2ecf20Sopenharmony_ci crypto_alg_put(alg); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_larval_kill); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct crypto_larval *larval = (void *)alg; 1698c2ecf20Sopenharmony_ci long timeout; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci timeout = wait_for_completion_killable_timeout( 1728c2ecf20Sopenharmony_ci &larval->completion, 60 * HZ); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci alg = larval->adult; 1758c2ecf20Sopenharmony_ci if (timeout < 0) 1768c2ecf20Sopenharmony_ci alg = ERR_PTR(-EINTR); 1778c2ecf20Sopenharmony_ci else if (!timeout) 1788c2ecf20Sopenharmony_ci alg = ERR_PTR(-ETIMEDOUT); 1798c2ecf20Sopenharmony_ci else if (!alg) 1808c2ecf20Sopenharmony_ci alg = ERR_PTR(-ENOENT); 1818c2ecf20Sopenharmony_ci else if (IS_ERR(alg)) 1828c2ecf20Sopenharmony_ci ; 1838c2ecf20Sopenharmony_ci else if (crypto_is_test_larval(larval) && 1848c2ecf20Sopenharmony_ci !(alg->cra_flags & CRYPTO_ALG_TESTED)) 1858c2ecf20Sopenharmony_ci alg = ERR_PTR(-EAGAIN); 1868c2ecf20Sopenharmony_ci else if (!crypto_mod_get(alg)) 1878c2ecf20Sopenharmony_ci alg = ERR_PTR(-EAGAIN); 1888c2ecf20Sopenharmony_ci crypto_mod_put(&larval->alg); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return alg; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, 1948c2ecf20Sopenharmony_ci u32 mask) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct crypto_alg *alg; 1978c2ecf20Sopenharmony_ci u32 test = 0; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (!((type | mask) & CRYPTO_ALG_TESTED)) 2008c2ecf20Sopenharmony_ci test |= CRYPTO_ALG_TESTED; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci down_read(&crypto_alg_sem); 2038c2ecf20Sopenharmony_ci alg = __crypto_alg_lookup(name, type | test, mask | test); 2048c2ecf20Sopenharmony_ci if (!alg && test) { 2058c2ecf20Sopenharmony_ci alg = __crypto_alg_lookup(name, type, mask); 2068c2ecf20Sopenharmony_ci if (alg && !crypto_is_larval(alg)) { 2078c2ecf20Sopenharmony_ci /* Test failed */ 2088c2ecf20Sopenharmony_ci crypto_mod_put(alg); 2098c2ecf20Sopenharmony_ci alg = ERR_PTR(-ELIBBAD); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci up_read(&crypto_alg_sem); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci return alg; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, 2188c2ecf20Sopenharmony_ci u32 mask) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct crypto_alg *alg; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (!name) 2238c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci type &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD); 2268c2ecf20Sopenharmony_ci mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci alg = crypto_alg_lookup(name, type, mask); 2298c2ecf20Sopenharmony_ci if (!alg && !(mask & CRYPTO_NOLOAD)) { 2308c2ecf20Sopenharmony_ci request_module("crypto-%s", name); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask & 2338c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK)) 2348c2ecf20Sopenharmony_ci request_module("crypto-%s-all", name); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci alg = crypto_alg_lookup(name, type, mask); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(alg) && crypto_is_larval(alg)) 2408c2ecf20Sopenharmony_ci alg = crypto_larval_wait(alg); 2418c2ecf20Sopenharmony_ci else if (!alg) 2428c2ecf20Sopenharmony_ci alg = crypto_larval_add(name, type, mask); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return alg; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ciint crypto_probing_notify(unsigned long val, void *v) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci int ok; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci ok = blocking_notifier_call_chain(&crypto_chain, val, v); 2528c2ecf20Sopenharmony_ci if (ok == NOTIFY_DONE) { 2538c2ecf20Sopenharmony_ci request_module("cryptomgr"); 2548c2ecf20Sopenharmony_ci ok = blocking_notifier_call_chain(&crypto_chain, val, v); 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return ok; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_probing_notify); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistruct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct crypto_alg *alg; 2648c2ecf20Sopenharmony_ci struct crypto_alg *larval; 2658c2ecf20Sopenharmony_ci int ok; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* 2688c2ecf20Sopenharmony_ci * If the internal flag is set for a cipher, require a caller to 2698c2ecf20Sopenharmony_ci * to invoke the cipher with the internal flag to use that cipher. 2708c2ecf20Sopenharmony_ci * Also, if a caller wants to allocate a cipher that may or may 2718c2ecf20Sopenharmony_ci * not be an internal cipher, use type | CRYPTO_ALG_INTERNAL and 2728c2ecf20Sopenharmony_ci * !(mask & CRYPTO_ALG_INTERNAL). 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ci if (!((type | mask) & CRYPTO_ALG_INTERNAL)) 2758c2ecf20Sopenharmony_ci mask |= CRYPTO_ALG_INTERNAL; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci larval = crypto_larval_lookup(name, type, mask); 2788c2ecf20Sopenharmony_ci if (IS_ERR(larval) || !crypto_is_larval(larval)) 2798c2ecf20Sopenharmony_ci return larval; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci ok = crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (ok == NOTIFY_STOP) 2848c2ecf20Sopenharmony_ci alg = crypto_larval_wait(larval); 2858c2ecf20Sopenharmony_ci else { 2868c2ecf20Sopenharmony_ci crypto_mod_put(larval); 2878c2ecf20Sopenharmony_ci alg = ERR_PTR(-ENOENT); 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci crypto_larval_kill(larval); 2908c2ecf20Sopenharmony_ci return alg; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_alg_mod_lookup); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci const struct crypto_type *type_obj = tfm->__crt_alg->cra_type; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (type_obj) 2998c2ecf20Sopenharmony_ci return type_obj->init(tfm, type, mask); 3008c2ecf20Sopenharmony_ci return 0; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic void crypto_exit_ops(struct crypto_tfm *tfm) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci const struct crypto_type *type = tfm->__crt_alg->cra_type; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (type && tfm->exit) 3088c2ecf20Sopenharmony_ci tfm->exit(tfm); 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci const struct crypto_type *type_obj = alg->cra_type; 3148c2ecf20Sopenharmony_ci unsigned int len; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1); 3178c2ecf20Sopenharmony_ci if (type_obj) 3188c2ecf20Sopenharmony_ci return len + type_obj->ctxsize(alg, type, mask); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { 3218c2ecf20Sopenharmony_ci default: 3228c2ecf20Sopenharmony_ci BUG(); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci case CRYPTO_ALG_TYPE_CIPHER: 3258c2ecf20Sopenharmony_ci len += crypto_cipher_ctxsize(alg); 3268c2ecf20Sopenharmony_ci break; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci case CRYPTO_ALG_TYPE_COMPRESS: 3298c2ecf20Sopenharmony_ci len += crypto_compress_ctxsize(alg); 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci return len; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_civoid crypto_shoot_alg(struct crypto_alg *alg) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci down_write(&crypto_alg_sem); 3398c2ecf20Sopenharmony_ci alg->cra_flags |= CRYPTO_ALG_DYING; 3408c2ecf20Sopenharmony_ci up_write(&crypto_alg_sem); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_shoot_alg); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistruct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, 3458c2ecf20Sopenharmony_ci u32 mask) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct crypto_tfm *tfm = NULL; 3488c2ecf20Sopenharmony_ci unsigned int tfm_size; 3498c2ecf20Sopenharmony_ci int err = -ENOMEM; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, type, mask); 3528c2ecf20Sopenharmony_ci tfm = kzalloc(tfm_size, GFP_KERNEL); 3538c2ecf20Sopenharmony_ci if (tfm == NULL) 3548c2ecf20Sopenharmony_ci goto out_err; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci tfm->__crt_alg = alg; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci err = crypto_init_ops(tfm, type, mask); 3598c2ecf20Sopenharmony_ci if (err) 3608c2ecf20Sopenharmony_ci goto out_free_tfm; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm))) 3638c2ecf20Sopenharmony_ci goto cra_init_failed; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci goto out; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cicra_init_failed: 3688c2ecf20Sopenharmony_ci crypto_exit_ops(tfm); 3698c2ecf20Sopenharmony_ciout_free_tfm: 3708c2ecf20Sopenharmony_ci if (err == -EAGAIN) 3718c2ecf20Sopenharmony_ci crypto_shoot_alg(alg); 3728c2ecf20Sopenharmony_ci kfree(tfm); 3738c2ecf20Sopenharmony_ciout_err: 3748c2ecf20Sopenharmony_ci tfm = ERR_PTR(err); 3758c2ecf20Sopenharmony_ciout: 3768c2ecf20Sopenharmony_ci return tfm; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__crypto_alloc_tfm); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/* 3818c2ecf20Sopenharmony_ci * crypto_alloc_base - Locate algorithm and allocate transform 3828c2ecf20Sopenharmony_ci * @alg_name: Name of algorithm 3838c2ecf20Sopenharmony_ci * @type: Type of algorithm 3848c2ecf20Sopenharmony_ci * @mask: Mask for type comparison 3858c2ecf20Sopenharmony_ci * 3868c2ecf20Sopenharmony_ci * This function should not be used by new algorithm types. 3878c2ecf20Sopenharmony_ci * Please use crypto_alloc_tfm instead. 3888c2ecf20Sopenharmony_ci * 3898c2ecf20Sopenharmony_ci * crypto_alloc_base() will first attempt to locate an already loaded 3908c2ecf20Sopenharmony_ci * algorithm. If that fails and the kernel supports dynamically loadable 3918c2ecf20Sopenharmony_ci * modules, it will then attempt to load a module of the same name or 3928c2ecf20Sopenharmony_ci * alias. If that fails it will send a query to any loaded crypto manager 3938c2ecf20Sopenharmony_ci * to construct an algorithm on the fly. A refcount is grabbed on the 3948c2ecf20Sopenharmony_ci * algorithm which is then associated with the new transform. 3958c2ecf20Sopenharmony_ci * 3968c2ecf20Sopenharmony_ci * The returned transform is of a non-determinate type. Most people 3978c2ecf20Sopenharmony_ci * should use one of the more specific allocation functions such as 3988c2ecf20Sopenharmony_ci * crypto_alloc_skcipher(). 3998c2ecf20Sopenharmony_ci * 4008c2ecf20Sopenharmony_ci * In case of error the return value is an error pointer. 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_cistruct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci struct crypto_tfm *tfm; 4058c2ecf20Sopenharmony_ci int err; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci for (;;) { 4088c2ecf20Sopenharmony_ci struct crypto_alg *alg; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci alg = crypto_alg_mod_lookup(alg_name, type, mask); 4118c2ecf20Sopenharmony_ci if (IS_ERR(alg)) { 4128c2ecf20Sopenharmony_ci err = PTR_ERR(alg); 4138c2ecf20Sopenharmony_ci goto err; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci tfm = __crypto_alloc_tfm(alg, type, mask); 4178c2ecf20Sopenharmony_ci if (!IS_ERR(tfm)) 4188c2ecf20Sopenharmony_ci return tfm; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci crypto_mod_put(alg); 4218c2ecf20Sopenharmony_ci err = PTR_ERR(tfm); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cierr: 4248c2ecf20Sopenharmony_ci if (err != -EAGAIN) 4258c2ecf20Sopenharmony_ci break; 4268c2ecf20Sopenharmony_ci if (fatal_signal_pending(current)) { 4278c2ecf20Sopenharmony_ci err = -EINTR; 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return ERR_PTR(err); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_alloc_base); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_civoid *crypto_create_tfm_node(struct crypto_alg *alg, 4378c2ecf20Sopenharmony_ci const struct crypto_type *frontend, 4388c2ecf20Sopenharmony_ci int node) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci char *mem; 4418c2ecf20Sopenharmony_ci struct crypto_tfm *tfm = NULL; 4428c2ecf20Sopenharmony_ci unsigned int tfmsize; 4438c2ecf20Sopenharmony_ci unsigned int total; 4448c2ecf20Sopenharmony_ci int err = -ENOMEM; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci tfmsize = frontend->tfmsize; 4478c2ecf20Sopenharmony_ci total = tfmsize + sizeof(*tfm) + frontend->extsize(alg); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci mem = kzalloc_node(total, GFP_KERNEL, node); 4508c2ecf20Sopenharmony_ci if (mem == NULL) 4518c2ecf20Sopenharmony_ci goto out_err; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci tfm = (struct crypto_tfm *)(mem + tfmsize); 4548c2ecf20Sopenharmony_ci tfm->__crt_alg = alg; 4558c2ecf20Sopenharmony_ci tfm->node = node; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci err = frontend->init_tfm(tfm); 4588c2ecf20Sopenharmony_ci if (err) 4598c2ecf20Sopenharmony_ci goto out_free_tfm; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm))) 4628c2ecf20Sopenharmony_ci goto cra_init_failed; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci goto out; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cicra_init_failed: 4678c2ecf20Sopenharmony_ci crypto_exit_ops(tfm); 4688c2ecf20Sopenharmony_ciout_free_tfm: 4698c2ecf20Sopenharmony_ci if (err == -EAGAIN) 4708c2ecf20Sopenharmony_ci crypto_shoot_alg(alg); 4718c2ecf20Sopenharmony_ci kfree(mem); 4728c2ecf20Sopenharmony_ciout_err: 4738c2ecf20Sopenharmony_ci mem = ERR_PTR(err); 4748c2ecf20Sopenharmony_ciout: 4758c2ecf20Sopenharmony_ci return mem; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_create_tfm_node); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistruct crypto_alg *crypto_find_alg(const char *alg_name, 4808c2ecf20Sopenharmony_ci const struct crypto_type *frontend, 4818c2ecf20Sopenharmony_ci u32 type, u32 mask) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci if (frontend) { 4848c2ecf20Sopenharmony_ci type &= frontend->maskclear; 4858c2ecf20Sopenharmony_ci mask &= frontend->maskclear; 4868c2ecf20Sopenharmony_ci type |= frontend->type; 4878c2ecf20Sopenharmony_ci mask |= frontend->maskset; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci return crypto_alg_mod_lookup(alg_name, type, mask); 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_find_alg); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci/* 4958c2ecf20Sopenharmony_ci * crypto_alloc_tfm_node - Locate algorithm and allocate transform 4968c2ecf20Sopenharmony_ci * @alg_name: Name of algorithm 4978c2ecf20Sopenharmony_ci * @frontend: Frontend algorithm type 4988c2ecf20Sopenharmony_ci * @type: Type of algorithm 4998c2ecf20Sopenharmony_ci * @mask: Mask for type comparison 5008c2ecf20Sopenharmony_ci * @node: NUMA node in which users desire to put requests, if node is 5018c2ecf20Sopenharmony_ci * NUMA_NO_NODE, it means users have no special requirement. 5028c2ecf20Sopenharmony_ci * 5038c2ecf20Sopenharmony_ci * crypto_alloc_tfm() will first attempt to locate an already loaded 5048c2ecf20Sopenharmony_ci * algorithm. If that fails and the kernel supports dynamically loadable 5058c2ecf20Sopenharmony_ci * modules, it will then attempt to load a module of the same name or 5068c2ecf20Sopenharmony_ci * alias. If that fails it will send a query to any loaded crypto manager 5078c2ecf20Sopenharmony_ci * to construct an algorithm on the fly. A refcount is grabbed on the 5088c2ecf20Sopenharmony_ci * algorithm which is then associated with the new transform. 5098c2ecf20Sopenharmony_ci * 5108c2ecf20Sopenharmony_ci * The returned transform is of a non-determinate type. Most people 5118c2ecf20Sopenharmony_ci * should use one of the more specific allocation functions such as 5128c2ecf20Sopenharmony_ci * crypto_alloc_skcipher(). 5138c2ecf20Sopenharmony_ci * 5148c2ecf20Sopenharmony_ci * In case of error the return value is an error pointer. 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_civoid *crypto_alloc_tfm_node(const char *alg_name, 5188c2ecf20Sopenharmony_ci const struct crypto_type *frontend, u32 type, u32 mask, 5198c2ecf20Sopenharmony_ci int node) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci void *tfm; 5228c2ecf20Sopenharmony_ci int err; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci for (;;) { 5258c2ecf20Sopenharmony_ci struct crypto_alg *alg; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci alg = crypto_find_alg(alg_name, frontend, type, mask); 5288c2ecf20Sopenharmony_ci if (IS_ERR(alg)) { 5298c2ecf20Sopenharmony_ci err = PTR_ERR(alg); 5308c2ecf20Sopenharmony_ci goto err; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci tfm = crypto_create_tfm_node(alg, frontend, node); 5348c2ecf20Sopenharmony_ci if (!IS_ERR(tfm)) 5358c2ecf20Sopenharmony_ci return tfm; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci crypto_mod_put(alg); 5388c2ecf20Sopenharmony_ci err = PTR_ERR(tfm); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cierr: 5418c2ecf20Sopenharmony_ci if (err != -EAGAIN) 5428c2ecf20Sopenharmony_ci break; 5438c2ecf20Sopenharmony_ci if (fatal_signal_pending(current)) { 5448c2ecf20Sopenharmony_ci err = -EINTR; 5458c2ecf20Sopenharmony_ci break; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return ERR_PTR(err); 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_alloc_tfm_node); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci/* 5548c2ecf20Sopenharmony_ci * crypto_destroy_tfm - Free crypto transform 5558c2ecf20Sopenharmony_ci * @mem: Start of tfm slab 5568c2ecf20Sopenharmony_ci * @tfm: Transform to free 5578c2ecf20Sopenharmony_ci * 5588c2ecf20Sopenharmony_ci * This function frees up the transform and any associated resources, 5598c2ecf20Sopenharmony_ci * then drops the refcount on the associated algorithm. 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_civoid crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct crypto_alg *alg; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(mem)) 5668c2ecf20Sopenharmony_ci return; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci alg = tfm->__crt_alg; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (!tfm->exit && alg->cra_exit) 5718c2ecf20Sopenharmony_ci alg->cra_exit(tfm); 5728c2ecf20Sopenharmony_ci crypto_exit_ops(tfm); 5738c2ecf20Sopenharmony_ci crypto_mod_put(alg); 5748c2ecf20Sopenharmony_ci kfree_sensitive(mem); 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_destroy_tfm); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ciint crypto_has_alg(const char *name, u32 type, u32 mask) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci int ret = 0; 5818c2ecf20Sopenharmony_ci struct crypto_alg *alg = crypto_alg_mod_lookup(name, type, mask); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (!IS_ERR(alg)) { 5848c2ecf20Sopenharmony_ci crypto_mod_put(alg); 5858c2ecf20Sopenharmony_ci ret = 1; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci return ret; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_has_alg); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_civoid crypto_req_done(struct crypto_async_request *req, int err) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci struct crypto_wait *wait = req->data; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (err == -EINPROGRESS) 5978c2ecf20Sopenharmony_ci return; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci wait->err = err; 6008c2ecf20Sopenharmony_ci complete(&wait->completion); 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_req_done); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cryptographic core API"); 6058c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 606