18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Crypto operations using stored keys 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2016, Intel Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 98c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 108c2ecf20Sopenharmony_ci#include <linux/crypto.h> 118c2ecf20Sopenharmony_ci#include <crypto/hash.h> 128c2ecf20Sopenharmony_ci#include <crypto/kpp.h> 138c2ecf20Sopenharmony_ci#include <crypto/dh.h> 148c2ecf20Sopenharmony_ci#include <keys/user-type.h> 158c2ecf20Sopenharmony_ci#include "internal.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic ssize_t dh_data_from_key(key_serial_t keyid, void **data) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci struct key *key; 208c2ecf20Sopenharmony_ci key_ref_t key_ref; 218c2ecf20Sopenharmony_ci long status; 228c2ecf20Sopenharmony_ci ssize_t ret; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci key_ref = lookup_user_key(keyid, 0, KEY_NEED_READ); 258c2ecf20Sopenharmony_ci if (IS_ERR(key_ref)) { 268c2ecf20Sopenharmony_ci ret = -ENOKEY; 278c2ecf20Sopenharmony_ci goto error; 288c2ecf20Sopenharmony_ci } 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci key = key_ref_to_ptr(key_ref); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 338c2ecf20Sopenharmony_ci if (key->type == &key_type_user) { 348c2ecf20Sopenharmony_ci down_read(&key->sem); 358c2ecf20Sopenharmony_ci status = key_validate(key); 368c2ecf20Sopenharmony_ci if (status == 0) { 378c2ecf20Sopenharmony_ci const struct user_key_payload *payload; 388c2ecf20Sopenharmony_ci uint8_t *duplicate; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci payload = user_key_payload_locked(key); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci duplicate = kmemdup(payload->data, payload->datalen, 438c2ecf20Sopenharmony_ci GFP_KERNEL); 448c2ecf20Sopenharmony_ci if (duplicate) { 458c2ecf20Sopenharmony_ci *data = duplicate; 468c2ecf20Sopenharmony_ci ret = payload->datalen; 478c2ecf20Sopenharmony_ci } else { 488c2ecf20Sopenharmony_ci ret = -ENOMEM; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci up_read(&key->sem); 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci key_put(key); 558c2ecf20Sopenharmony_cierror: 568c2ecf20Sopenharmony_ci return ret; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic void dh_free_data(struct dh *dh) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci kfree_sensitive(dh->key); 628c2ecf20Sopenharmony_ci kfree_sensitive(dh->p); 638c2ecf20Sopenharmony_ci kfree_sensitive(dh->g); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistruct dh_completion { 678c2ecf20Sopenharmony_ci struct completion completion; 688c2ecf20Sopenharmony_ci int err; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void dh_crypto_done(struct crypto_async_request *req, int err) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct dh_completion *compl = req->data; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (err == -EINPROGRESS) 768c2ecf20Sopenharmony_ci return; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci compl->err = err; 798c2ecf20Sopenharmony_ci complete(&compl->completion); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistruct kdf_sdesc { 838c2ecf20Sopenharmony_ci struct shash_desc shash; 848c2ecf20Sopenharmony_ci char ctx[]; 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct crypto_shash *tfm; 908c2ecf20Sopenharmony_ci struct kdf_sdesc *sdesc; 918c2ecf20Sopenharmony_ci int size; 928c2ecf20Sopenharmony_ci int err; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* allocate synchronous hash */ 958c2ecf20Sopenharmony_ci tfm = crypto_alloc_shash(hashname, 0, 0); 968c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) { 978c2ecf20Sopenharmony_ci pr_info("could not allocate digest TFM handle %s\n", hashname); 988c2ecf20Sopenharmony_ci return PTR_ERR(tfm); 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci err = -EINVAL; 1028c2ecf20Sopenharmony_ci if (crypto_shash_digestsize(tfm) == 0) 1038c2ecf20Sopenharmony_ci goto out_free_tfm; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci err = -ENOMEM; 1068c2ecf20Sopenharmony_ci size = sizeof(struct shash_desc) + crypto_shash_descsize(tfm); 1078c2ecf20Sopenharmony_ci sdesc = kmalloc(size, GFP_KERNEL); 1088c2ecf20Sopenharmony_ci if (!sdesc) 1098c2ecf20Sopenharmony_ci goto out_free_tfm; 1108c2ecf20Sopenharmony_ci sdesc->shash.tfm = tfm; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci *sdesc_ret = sdesc; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ciout_free_tfm: 1178c2ecf20Sopenharmony_ci crypto_free_shash(tfm); 1188c2ecf20Sopenharmony_ci return err; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic void kdf_dealloc(struct kdf_sdesc *sdesc) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci if (!sdesc) 1248c2ecf20Sopenharmony_ci return; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (sdesc->shash.tfm) 1278c2ecf20Sopenharmony_ci crypto_free_shash(sdesc->shash.tfm); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci kfree_sensitive(sdesc); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* 1338c2ecf20Sopenharmony_ci * Implementation of the KDF in counter mode according to SP800-108 section 5.1 1348c2ecf20Sopenharmony_ci * as well as SP800-56A section 5.8.1 (Single-step KDF). 1358c2ecf20Sopenharmony_ci * 1368c2ecf20Sopenharmony_ci * SP800-56A: 1378c2ecf20Sopenharmony_ci * The src pointer is defined as Z || other info where Z is the shared secret 1388c2ecf20Sopenharmony_ci * from DH and other info is an arbitrary string (see SP800-56A section 1398c2ecf20Sopenharmony_ci * 5.8.1.2). 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * 'dlen' must be a multiple of the digest size. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistatic int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen, 1448c2ecf20Sopenharmony_ci u8 *dst, unsigned int dlen, unsigned int zlen) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct shash_desc *desc = &sdesc->shash; 1478c2ecf20Sopenharmony_ci unsigned int h = crypto_shash_digestsize(desc->tfm); 1488c2ecf20Sopenharmony_ci int err = 0; 1498c2ecf20Sopenharmony_ci u8 *dst_orig = dst; 1508c2ecf20Sopenharmony_ci __be32 counter = cpu_to_be32(1); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci while (dlen) { 1538c2ecf20Sopenharmony_ci err = crypto_shash_init(desc); 1548c2ecf20Sopenharmony_ci if (err) 1558c2ecf20Sopenharmony_ci goto err; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32)); 1588c2ecf20Sopenharmony_ci if (err) 1598c2ecf20Sopenharmony_ci goto err; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (zlen && h) { 1628c2ecf20Sopenharmony_ci u8 tmpbuffer[32]; 1638c2ecf20Sopenharmony_ci size_t chunk = min_t(size_t, zlen, sizeof(tmpbuffer)); 1648c2ecf20Sopenharmony_ci memset(tmpbuffer, 0, chunk); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci do { 1678c2ecf20Sopenharmony_ci err = crypto_shash_update(desc, tmpbuffer, 1688c2ecf20Sopenharmony_ci chunk); 1698c2ecf20Sopenharmony_ci if (err) 1708c2ecf20Sopenharmony_ci goto err; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci zlen -= chunk; 1738c2ecf20Sopenharmony_ci chunk = min_t(size_t, zlen, sizeof(tmpbuffer)); 1748c2ecf20Sopenharmony_ci } while (zlen); 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (src && slen) { 1788c2ecf20Sopenharmony_ci err = crypto_shash_update(desc, src, slen); 1798c2ecf20Sopenharmony_ci if (err) 1808c2ecf20Sopenharmony_ci goto err; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci err = crypto_shash_final(desc, dst); 1848c2ecf20Sopenharmony_ci if (err) 1858c2ecf20Sopenharmony_ci goto err; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci dlen -= h; 1888c2ecf20Sopenharmony_ci dst += h; 1898c2ecf20Sopenharmony_ci counter = cpu_to_be32(be32_to_cpu(counter) + 1); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cierr: 1958c2ecf20Sopenharmony_ci memzero_explicit(dst_orig, dlen); 1968c2ecf20Sopenharmony_ci return err; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc, 2008c2ecf20Sopenharmony_ci char __user *buffer, size_t buflen, 2018c2ecf20Sopenharmony_ci uint8_t *kbuf, size_t kbuflen, size_t lzero) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci uint8_t *outbuf = NULL; 2048c2ecf20Sopenharmony_ci int ret; 2058c2ecf20Sopenharmony_ci size_t outbuf_len = roundup(buflen, 2068c2ecf20Sopenharmony_ci crypto_shash_digestsize(sdesc->shash.tfm)); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci outbuf = kmalloc(outbuf_len, GFP_KERNEL); 2098c2ecf20Sopenharmony_ci if (!outbuf) { 2108c2ecf20Sopenharmony_ci ret = -ENOMEM; 2118c2ecf20Sopenharmony_ci goto err; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, outbuf_len, lzero); 2158c2ecf20Sopenharmony_ci if (ret) 2168c2ecf20Sopenharmony_ci goto err; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci ret = buflen; 2198c2ecf20Sopenharmony_ci if (copy_to_user(buffer, outbuf, buflen) != 0) 2208c2ecf20Sopenharmony_ci ret = -EFAULT; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cierr: 2238c2ecf20Sopenharmony_ci kfree_sensitive(outbuf); 2248c2ecf20Sopenharmony_ci return ret; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cilong __keyctl_dh_compute(struct keyctl_dh_params __user *params, 2288c2ecf20Sopenharmony_ci char __user *buffer, size_t buflen, 2298c2ecf20Sopenharmony_ci struct keyctl_kdf_params *kdfcopy) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci long ret; 2328c2ecf20Sopenharmony_ci ssize_t dlen; 2338c2ecf20Sopenharmony_ci int secretlen; 2348c2ecf20Sopenharmony_ci int outlen; 2358c2ecf20Sopenharmony_ci struct keyctl_dh_params pcopy; 2368c2ecf20Sopenharmony_ci struct dh dh_inputs; 2378c2ecf20Sopenharmony_ci struct scatterlist outsg; 2388c2ecf20Sopenharmony_ci struct dh_completion compl; 2398c2ecf20Sopenharmony_ci struct crypto_kpp *tfm; 2408c2ecf20Sopenharmony_ci struct kpp_request *req; 2418c2ecf20Sopenharmony_ci uint8_t *secret; 2428c2ecf20Sopenharmony_ci uint8_t *outbuf; 2438c2ecf20Sopenharmony_ci struct kdf_sdesc *sdesc = NULL; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (!params || (!buffer && buflen)) { 2468c2ecf20Sopenharmony_ci ret = -EINVAL; 2478c2ecf20Sopenharmony_ci goto out1; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) { 2508c2ecf20Sopenharmony_ci ret = -EFAULT; 2518c2ecf20Sopenharmony_ci goto out1; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (kdfcopy) { 2558c2ecf20Sopenharmony_ci char *hashname; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (memchr_inv(kdfcopy->__spare, 0, sizeof(kdfcopy->__spare))) { 2588c2ecf20Sopenharmony_ci ret = -EINVAL; 2598c2ecf20Sopenharmony_ci goto out1; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN || 2638c2ecf20Sopenharmony_ci kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) { 2648c2ecf20Sopenharmony_ci ret = -EMSGSIZE; 2658c2ecf20Sopenharmony_ci goto out1; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* get KDF name string */ 2698c2ecf20Sopenharmony_ci hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME); 2708c2ecf20Sopenharmony_ci if (IS_ERR(hashname)) { 2718c2ecf20Sopenharmony_ci ret = PTR_ERR(hashname); 2728c2ecf20Sopenharmony_ci goto out1; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* allocate KDF from the kernel crypto API */ 2768c2ecf20Sopenharmony_ci ret = kdf_alloc(&sdesc, hashname); 2778c2ecf20Sopenharmony_ci kfree(hashname); 2788c2ecf20Sopenharmony_ci if (ret) 2798c2ecf20Sopenharmony_ci goto out1; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci memset(&dh_inputs, 0, sizeof(dh_inputs)); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci dlen = dh_data_from_key(pcopy.prime, &dh_inputs.p); 2858c2ecf20Sopenharmony_ci if (dlen < 0) { 2868c2ecf20Sopenharmony_ci ret = dlen; 2878c2ecf20Sopenharmony_ci goto out1; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci dh_inputs.p_size = dlen; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci dlen = dh_data_from_key(pcopy.base, &dh_inputs.g); 2928c2ecf20Sopenharmony_ci if (dlen < 0) { 2938c2ecf20Sopenharmony_ci ret = dlen; 2948c2ecf20Sopenharmony_ci goto out2; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci dh_inputs.g_size = dlen; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci dlen = dh_data_from_key(pcopy.private, &dh_inputs.key); 2998c2ecf20Sopenharmony_ci if (dlen < 0) { 3008c2ecf20Sopenharmony_ci ret = dlen; 3018c2ecf20Sopenharmony_ci goto out2; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci dh_inputs.key_size = dlen; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci secretlen = crypto_dh_key_len(&dh_inputs); 3068c2ecf20Sopenharmony_ci secret = kmalloc(secretlen, GFP_KERNEL); 3078c2ecf20Sopenharmony_ci if (!secret) { 3088c2ecf20Sopenharmony_ci ret = -ENOMEM; 3098c2ecf20Sopenharmony_ci goto out2; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci ret = crypto_dh_encode_key(secret, secretlen, &dh_inputs); 3128c2ecf20Sopenharmony_ci if (ret) 3138c2ecf20Sopenharmony_ci goto out3; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci tfm = crypto_alloc_kpp("dh", 0, 0); 3168c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) { 3178c2ecf20Sopenharmony_ci ret = PTR_ERR(tfm); 3188c2ecf20Sopenharmony_ci goto out3; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci ret = crypto_kpp_set_secret(tfm, secret, secretlen); 3228c2ecf20Sopenharmony_ci if (ret) 3238c2ecf20Sopenharmony_ci goto out4; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci outlen = crypto_kpp_maxsize(tfm); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (!kdfcopy) { 3288c2ecf20Sopenharmony_ci /* 3298c2ecf20Sopenharmony_ci * When not using a KDF, buflen 0 is used to read the 3308c2ecf20Sopenharmony_ci * required buffer length 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ci if (buflen == 0) { 3338c2ecf20Sopenharmony_ci ret = outlen; 3348c2ecf20Sopenharmony_ci goto out4; 3358c2ecf20Sopenharmony_ci } else if (outlen > buflen) { 3368c2ecf20Sopenharmony_ci ret = -EOVERFLOW; 3378c2ecf20Sopenharmony_ci goto out4; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci outbuf = kzalloc(kdfcopy ? (outlen + kdfcopy->otherinfolen) : outlen, 3428c2ecf20Sopenharmony_ci GFP_KERNEL); 3438c2ecf20Sopenharmony_ci if (!outbuf) { 3448c2ecf20Sopenharmony_ci ret = -ENOMEM; 3458c2ecf20Sopenharmony_ci goto out4; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci sg_init_one(&outsg, outbuf, outlen); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci req = kpp_request_alloc(tfm, GFP_KERNEL); 3518c2ecf20Sopenharmony_ci if (!req) { 3528c2ecf20Sopenharmony_ci ret = -ENOMEM; 3538c2ecf20Sopenharmony_ci goto out5; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci kpp_request_set_input(req, NULL, 0); 3578c2ecf20Sopenharmony_ci kpp_request_set_output(req, &outsg, outlen); 3588c2ecf20Sopenharmony_ci init_completion(&compl.completion); 3598c2ecf20Sopenharmony_ci kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | 3608c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MAY_SLEEP, 3618c2ecf20Sopenharmony_ci dh_crypto_done, &compl); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* 3648c2ecf20Sopenharmony_ci * For DH, generate_public_key and generate_shared_secret are 3658c2ecf20Sopenharmony_ci * the same calculation 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_ci ret = crypto_kpp_generate_public_key(req); 3688c2ecf20Sopenharmony_ci if (ret == -EINPROGRESS) { 3698c2ecf20Sopenharmony_ci wait_for_completion(&compl.completion); 3708c2ecf20Sopenharmony_ci ret = compl.err; 3718c2ecf20Sopenharmony_ci if (ret) 3728c2ecf20Sopenharmony_ci goto out6; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (kdfcopy) { 3768c2ecf20Sopenharmony_ci /* 3778c2ecf20Sopenharmony_ci * Concatenate SP800-56A otherinfo past DH shared secret -- the 3788c2ecf20Sopenharmony_ci * input to the KDF is (DH shared secret || otherinfo) 3798c2ecf20Sopenharmony_ci */ 3808c2ecf20Sopenharmony_ci if (copy_from_user(outbuf + req->dst_len, kdfcopy->otherinfo, 3818c2ecf20Sopenharmony_ci kdfcopy->otherinfolen) != 0) { 3828c2ecf20Sopenharmony_ci ret = -EFAULT; 3838c2ecf20Sopenharmony_ci goto out6; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, outbuf, 3878c2ecf20Sopenharmony_ci req->dst_len + kdfcopy->otherinfolen, 3888c2ecf20Sopenharmony_ci outlen - req->dst_len); 3898c2ecf20Sopenharmony_ci } else if (copy_to_user(buffer, outbuf, req->dst_len) == 0) { 3908c2ecf20Sopenharmony_ci ret = req->dst_len; 3918c2ecf20Sopenharmony_ci } else { 3928c2ecf20Sopenharmony_ci ret = -EFAULT; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ciout6: 3968c2ecf20Sopenharmony_ci kpp_request_free(req); 3978c2ecf20Sopenharmony_ciout5: 3988c2ecf20Sopenharmony_ci kfree_sensitive(outbuf); 3998c2ecf20Sopenharmony_ciout4: 4008c2ecf20Sopenharmony_ci crypto_free_kpp(tfm); 4018c2ecf20Sopenharmony_ciout3: 4028c2ecf20Sopenharmony_ci kfree_sensitive(secret); 4038c2ecf20Sopenharmony_ciout2: 4048c2ecf20Sopenharmony_ci dh_free_data(&dh_inputs); 4058c2ecf20Sopenharmony_ciout1: 4068c2ecf20Sopenharmony_ci kdf_dealloc(sdesc); 4078c2ecf20Sopenharmony_ci return ret; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cilong keyctl_dh_compute(struct keyctl_dh_params __user *params, 4118c2ecf20Sopenharmony_ci char __user *buffer, size_t buflen, 4128c2ecf20Sopenharmony_ci struct keyctl_kdf_params __user *kdf) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct keyctl_kdf_params kdfcopy; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (!kdf) 4178c2ecf20Sopenharmony_ci return __keyctl_dh_compute(params, buffer, buflen, NULL); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0) 4208c2ecf20Sopenharmony_ci return -EFAULT; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy); 4238c2ecf20Sopenharmony_ci} 424