1ddbb4114SMat Martineau /* Crypto operations using stored keys 2ddbb4114SMat Martineau * 3ddbb4114SMat Martineau * Copyright (c) 2016, Intel Corporation 4ddbb4114SMat Martineau * 5ddbb4114SMat Martineau * This program is free software; you can redistribute it and/or 6ddbb4114SMat Martineau * modify it under the terms of the GNU General Public License 7ddbb4114SMat Martineau * as published by the Free Software Foundation; either version 8ddbb4114SMat Martineau * 2 of the License, or (at your option) any later version. 9ddbb4114SMat Martineau */ 10ddbb4114SMat Martineau 11ddbb4114SMat Martineau #include <linux/slab.h> 12ddbb4114SMat Martineau #include <linux/uaccess.h> 137cbe0932SMat Martineau #include <linux/scatterlist.h> 14f1c316a3SStephan Mueller #include <linux/crypto.h> 15f1c316a3SStephan Mueller #include <crypto/hash.h> 167cbe0932SMat Martineau #include <crypto/kpp.h> 177cbe0932SMat Martineau #include <crypto/dh.h> 18ddbb4114SMat Martineau #include <keys/user-type.h> 19ddbb4114SMat Martineau #include "internal.h" 20ddbb4114SMat Martineau 217cbe0932SMat Martineau static ssize_t dh_data_from_key(key_serial_t keyid, void **data) 22ddbb4114SMat Martineau { 23ddbb4114SMat Martineau struct key *key; 24ddbb4114SMat Martineau key_ref_t key_ref; 25ddbb4114SMat Martineau long status; 26ddbb4114SMat Martineau ssize_t ret; 27ddbb4114SMat Martineau 28ddbb4114SMat Martineau key_ref = lookup_user_key(keyid, 0, KEY_NEED_READ); 29ddbb4114SMat Martineau if (IS_ERR(key_ref)) { 30ddbb4114SMat Martineau ret = -ENOKEY; 31ddbb4114SMat Martineau goto error; 32ddbb4114SMat Martineau } 33ddbb4114SMat Martineau 34ddbb4114SMat Martineau key = key_ref_to_ptr(key_ref); 35ddbb4114SMat Martineau 36ddbb4114SMat Martineau ret = -EOPNOTSUPP; 37ddbb4114SMat Martineau if (key->type == &key_type_user) { 38ddbb4114SMat Martineau down_read(&key->sem); 39ddbb4114SMat Martineau status = key_validate(key); 40ddbb4114SMat Martineau if (status == 0) { 41ddbb4114SMat Martineau const struct user_key_payload *payload; 427cbe0932SMat Martineau uint8_t *duplicate; 43ddbb4114SMat Martineau 440837e49aSDavid Howells payload = user_key_payload_locked(key); 45ddbb4114SMat Martineau 467cbe0932SMat Martineau duplicate = kmemdup(payload->data, payload->datalen, 477cbe0932SMat Martineau GFP_KERNEL); 487cbe0932SMat Martineau if (duplicate) { 497cbe0932SMat Martineau *data = duplicate; 50ddbb4114SMat Martineau ret = payload->datalen; 51ddbb4114SMat Martineau } else { 527cbe0932SMat Martineau ret = -ENOMEM; 53ddbb4114SMat Martineau } 54ddbb4114SMat Martineau } 55ddbb4114SMat Martineau up_read(&key->sem); 56ddbb4114SMat Martineau } 57ddbb4114SMat Martineau 58ddbb4114SMat Martineau key_put(key); 59ddbb4114SMat Martineau error: 60ddbb4114SMat Martineau return ret; 61ddbb4114SMat Martineau } 62ddbb4114SMat Martineau 637cbe0932SMat Martineau static void dh_free_data(struct dh *dh) 647cbe0932SMat Martineau { 657cbe0932SMat Martineau kzfree(dh->key); 667cbe0932SMat Martineau kzfree(dh->p); 677cbe0932SMat Martineau kzfree(dh->g); 687cbe0932SMat Martineau } 697cbe0932SMat Martineau 707cbe0932SMat Martineau struct dh_completion { 717cbe0932SMat Martineau struct completion completion; 727cbe0932SMat Martineau int err; 737cbe0932SMat Martineau }; 747cbe0932SMat Martineau 757cbe0932SMat Martineau static void dh_crypto_done(struct crypto_async_request *req, int err) 767cbe0932SMat Martineau { 777cbe0932SMat Martineau struct dh_completion *compl = req->data; 787cbe0932SMat Martineau 797cbe0932SMat Martineau if (err == -EINPROGRESS) 807cbe0932SMat Martineau return; 817cbe0932SMat Martineau 827cbe0932SMat Martineau compl->err = err; 837cbe0932SMat Martineau complete(&compl->completion); 847cbe0932SMat Martineau } 857cbe0932SMat Martineau 86f1c316a3SStephan Mueller struct kdf_sdesc { 87f1c316a3SStephan Mueller struct shash_desc shash; 88f1c316a3SStephan Mueller char ctx[]; 89f1c316a3SStephan Mueller }; 90f1c316a3SStephan Mueller 91f1c316a3SStephan Mueller static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname) 92f1c316a3SStephan Mueller { 93f1c316a3SStephan Mueller struct crypto_shash *tfm; 94f1c316a3SStephan Mueller struct kdf_sdesc *sdesc; 95f1c316a3SStephan Mueller int size; 96bbe24045SEric Biggers int err; 97f1c316a3SStephan Mueller 98f1c316a3SStephan Mueller /* allocate synchronous hash */ 99f1c316a3SStephan Mueller tfm = crypto_alloc_shash(hashname, 0, 0); 100f1c316a3SStephan Mueller if (IS_ERR(tfm)) { 101f1c316a3SStephan Mueller pr_info("could not allocate digest TFM handle %s\n", hashname); 102f1c316a3SStephan Mueller return PTR_ERR(tfm); 103f1c316a3SStephan Mueller } 104f1c316a3SStephan Mueller 105bbe24045SEric Biggers err = -EINVAL; 106bbe24045SEric Biggers if (crypto_shash_digestsize(tfm) == 0) 107bbe24045SEric Biggers goto out_free_tfm; 108bbe24045SEric Biggers 109bbe24045SEric Biggers err = -ENOMEM; 110f1c316a3SStephan Mueller size = sizeof(struct shash_desc) + crypto_shash_descsize(tfm); 111f1c316a3SStephan Mueller sdesc = kmalloc(size, GFP_KERNEL); 112f1c316a3SStephan Mueller if (!sdesc) 113bbe24045SEric Biggers goto out_free_tfm; 114f1c316a3SStephan Mueller sdesc->shash.tfm = tfm; 115f1c316a3SStephan Mueller sdesc->shash.flags = 0x0; 116f1c316a3SStephan Mueller 117f1c316a3SStephan Mueller *sdesc_ret = sdesc; 118f1c316a3SStephan Mueller 119f1c316a3SStephan Mueller return 0; 120bbe24045SEric Biggers 121bbe24045SEric Biggers out_free_tfm: 122bbe24045SEric Biggers crypto_free_shash(tfm); 123bbe24045SEric Biggers return err; 124f1c316a3SStephan Mueller } 125f1c316a3SStephan Mueller 126f1c316a3SStephan Mueller static void kdf_dealloc(struct kdf_sdesc *sdesc) 127f1c316a3SStephan Mueller { 128f1c316a3SStephan Mueller if (!sdesc) 129f1c316a3SStephan Mueller return; 130f1c316a3SStephan Mueller 131f1c316a3SStephan Mueller if (sdesc->shash.tfm) 132f1c316a3SStephan Mueller crypto_free_shash(sdesc->shash.tfm); 133f1c316a3SStephan Mueller 134f1c316a3SStephan Mueller kzfree(sdesc); 135f1c316a3SStephan Mueller } 136f1c316a3SStephan Mueller 137f1c316a3SStephan Mueller /* 138f1c316a3SStephan Mueller * Implementation of the KDF in counter mode according to SP800-108 section 5.1 139f1c316a3SStephan Mueller * as well as SP800-56A section 5.8.1 (Single-step KDF). 140f1c316a3SStephan Mueller * 141f1c316a3SStephan Mueller * SP800-56A: 142f1c316a3SStephan Mueller * The src pointer is defined as Z || other info where Z is the shared secret 143f1c316a3SStephan Mueller * from DH and other info is an arbitrary string (see SP800-56A section 144f1c316a3SStephan Mueller * 5.8.1.2). 145f1c316a3SStephan Mueller */ 146f1c316a3SStephan Mueller static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen, 1477cbe0932SMat Martineau u8 *dst, unsigned int dlen, unsigned int zlen) 148f1c316a3SStephan Mueller { 149f1c316a3SStephan Mueller struct shash_desc *desc = &sdesc->shash; 150f1c316a3SStephan Mueller unsigned int h = crypto_shash_digestsize(desc->tfm); 151f1c316a3SStephan Mueller int err = 0; 152f1c316a3SStephan Mueller u8 *dst_orig = dst; 1530ddd9f1aSEric Biggers __be32 counter = cpu_to_be32(1); 154f1c316a3SStephan Mueller 155f1c316a3SStephan Mueller while (dlen) { 156f1c316a3SStephan Mueller err = crypto_shash_init(desc); 157f1c316a3SStephan Mueller if (err) 158f1c316a3SStephan Mueller goto err; 159f1c316a3SStephan Mueller 1600ddd9f1aSEric Biggers err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32)); 161f1c316a3SStephan Mueller if (err) 162f1c316a3SStephan Mueller goto err; 163f1c316a3SStephan Mueller 1647cbe0932SMat Martineau if (zlen && h) { 165890e2abeSTycho Andersen u8 tmpbuffer[32]; 166890e2abeSTycho Andersen size_t chunk = min_t(size_t, zlen, sizeof(tmpbuffer)); 1677cbe0932SMat Martineau memset(tmpbuffer, 0, chunk); 1687cbe0932SMat Martineau 1697cbe0932SMat Martineau do { 1707cbe0932SMat Martineau err = crypto_shash_update(desc, tmpbuffer, 1717cbe0932SMat Martineau chunk); 1727cbe0932SMat Martineau if (err) 1737cbe0932SMat Martineau goto err; 1747cbe0932SMat Martineau 1757cbe0932SMat Martineau zlen -= chunk; 176890e2abeSTycho Andersen chunk = min_t(size_t, zlen, sizeof(tmpbuffer)); 1777cbe0932SMat Martineau } while (zlen); 1787cbe0932SMat Martineau } 1797cbe0932SMat Martineau 180f1c316a3SStephan Mueller if (src && slen) { 181f1c316a3SStephan Mueller err = crypto_shash_update(desc, src, slen); 182f1c316a3SStephan Mueller if (err) 183f1c316a3SStephan Mueller goto err; 184f1c316a3SStephan Mueller } 185f1c316a3SStephan Mueller 186f1c316a3SStephan Mueller err = crypto_shash_final(desc, dst); 187f1c316a3SStephan Mueller if (err) 188f1c316a3SStephan Mueller goto err; 189f1c316a3SStephan Mueller 190f1c316a3SStephan Mueller dlen -= h; 191f1c316a3SStephan Mueller dst += h; 1920ddd9f1aSEric Biggers counter = cpu_to_be32(be32_to_cpu(counter) + 1); 193f1c316a3SStephan Mueller } 194f1c316a3SStephan Mueller 195f1c316a3SStephan Mueller return 0; 196f1c316a3SStephan Mueller 197f1c316a3SStephan Mueller err: 198f1c316a3SStephan Mueller memzero_explicit(dst_orig, dlen); 199f1c316a3SStephan Mueller return err; 200f1c316a3SStephan Mueller } 201f1c316a3SStephan Mueller 202f1c316a3SStephan Mueller static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc, 2034693fc73SStephan Mueller char __user *buffer, size_t buflen, 2047cbe0932SMat Martineau uint8_t *kbuf, size_t kbuflen, size_t lzero) 205f1c316a3SStephan Mueller { 206f1c316a3SStephan Mueller uint8_t *outbuf = NULL; 207f1c316a3SStephan Mueller int ret; 208383203efSTycho Andersen size_t outbuf_len = round_up(buflen, 209383203efSTycho Andersen crypto_shash_digestsize(sdesc->shash.tfm)); 210f1c316a3SStephan Mueller 211383203efSTycho Andersen outbuf = kmalloc(outbuf_len, GFP_KERNEL); 212f1c316a3SStephan Mueller if (!outbuf) { 213f1c316a3SStephan Mueller ret = -ENOMEM; 214f1c316a3SStephan Mueller goto err; 215f1c316a3SStephan Mueller } 216f1c316a3SStephan Mueller 217383203efSTycho Andersen ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, outbuf_len, lzero); 218f1c316a3SStephan Mueller if (ret) 219f1c316a3SStephan Mueller goto err; 220f1c316a3SStephan Mueller 221f1c316a3SStephan Mueller ret = buflen; 222f1c316a3SStephan Mueller if (copy_to_user(buffer, outbuf, buflen) != 0) 223f1c316a3SStephan Mueller ret = -EFAULT; 224f1c316a3SStephan Mueller 225f1c316a3SStephan Mueller err: 226f1c316a3SStephan Mueller kzfree(outbuf); 227f1c316a3SStephan Mueller return ret; 228f1c316a3SStephan Mueller } 229f1c316a3SStephan Mueller 230f1c316a3SStephan Mueller long __keyctl_dh_compute(struct keyctl_dh_params __user *params, 231f1c316a3SStephan Mueller char __user *buffer, size_t buflen, 232f1c316a3SStephan Mueller struct keyctl_kdf_params *kdfcopy) 233ddbb4114SMat Martineau { 234ddbb4114SMat Martineau long ret; 2357cbe0932SMat Martineau ssize_t dlen; 2367cbe0932SMat Martineau int secretlen; 2377cbe0932SMat Martineau int outlen; 238ddbb4114SMat Martineau struct keyctl_dh_params pcopy; 2397cbe0932SMat Martineau struct dh dh_inputs; 2407cbe0932SMat Martineau struct scatterlist outsg; 2417cbe0932SMat Martineau struct dh_completion compl; 2427cbe0932SMat Martineau struct crypto_kpp *tfm; 2437cbe0932SMat Martineau struct kpp_request *req; 2447cbe0932SMat Martineau uint8_t *secret; 2457cbe0932SMat Martineau uint8_t *outbuf; 246f1c316a3SStephan Mueller struct kdf_sdesc *sdesc = NULL; 247ddbb4114SMat Martineau 248ddbb4114SMat Martineau if (!params || (!buffer && buflen)) { 249ddbb4114SMat Martineau ret = -EINVAL; 2507cbe0932SMat Martineau goto out1; 251ddbb4114SMat Martineau } 252ddbb4114SMat Martineau if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) { 253ddbb4114SMat Martineau ret = -EFAULT; 2547cbe0932SMat Martineau goto out1; 255ddbb4114SMat Martineau } 256ddbb4114SMat Martineau 257f1c316a3SStephan Mueller if (kdfcopy) { 258f1c316a3SStephan Mueller char *hashname; 259f1c316a3SStephan Mueller 2604f9dabfaSEric Biggers if (memchr_inv(kdfcopy->__spare, 0, sizeof(kdfcopy->__spare))) { 2614f9dabfaSEric Biggers ret = -EINVAL; 2624f9dabfaSEric Biggers goto out1; 2634f9dabfaSEric Biggers } 2644f9dabfaSEric Biggers 265f1c316a3SStephan Mueller if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN || 266f1c316a3SStephan Mueller kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) { 267f1c316a3SStephan Mueller ret = -EMSGSIZE; 2687cbe0932SMat Martineau goto out1; 2694693fc73SStephan Mueller } 2704693fc73SStephan Mueller 271f1c316a3SStephan Mueller /* get KDF name string */ 272f1c316a3SStephan Mueller hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME); 273f1c316a3SStephan Mueller if (IS_ERR(hashname)) { 274f1c316a3SStephan Mueller ret = PTR_ERR(hashname); 2757cbe0932SMat Martineau goto out1; 276f1c316a3SStephan Mueller } 277f1c316a3SStephan Mueller 278f1c316a3SStephan Mueller /* allocate KDF from the kernel crypto API */ 279f1c316a3SStephan Mueller ret = kdf_alloc(&sdesc, hashname); 280f1c316a3SStephan Mueller kfree(hashname); 281f1c316a3SStephan Mueller if (ret) 2827cbe0932SMat Martineau goto out1; 283f1c316a3SStephan Mueller } 284f1c316a3SStephan Mueller 2857cbe0932SMat Martineau memset(&dh_inputs, 0, sizeof(dh_inputs)); 2867cbe0932SMat Martineau 2877cbe0932SMat Martineau dlen = dh_data_from_key(pcopy.prime, &dh_inputs.p); 2887cbe0932SMat Martineau if (dlen < 0) { 2897cbe0932SMat Martineau ret = dlen; 2907cbe0932SMat Martineau goto out1; 2917cbe0932SMat Martineau } 2927cbe0932SMat Martineau dh_inputs.p_size = dlen; 2937cbe0932SMat Martineau 2947cbe0932SMat Martineau dlen = dh_data_from_key(pcopy.base, &dh_inputs.g); 2957cbe0932SMat Martineau if (dlen < 0) { 2967cbe0932SMat Martineau ret = dlen; 2977cbe0932SMat Martineau goto out2; 2987cbe0932SMat Martineau } 2997cbe0932SMat Martineau dh_inputs.g_size = dlen; 3007cbe0932SMat Martineau 3017cbe0932SMat Martineau dlen = dh_data_from_key(pcopy.private, &dh_inputs.key); 3027cbe0932SMat Martineau if (dlen < 0) { 3037cbe0932SMat Martineau ret = dlen; 3047cbe0932SMat Martineau goto out2; 3057cbe0932SMat Martineau } 3067cbe0932SMat Martineau dh_inputs.key_size = dlen; 3077cbe0932SMat Martineau 3087cbe0932SMat Martineau secretlen = crypto_dh_key_len(&dh_inputs); 3097cbe0932SMat Martineau secret = kmalloc(secretlen, GFP_KERNEL); 3107cbe0932SMat Martineau if (!secret) { 3117cbe0932SMat Martineau ret = -ENOMEM; 3127cbe0932SMat Martineau goto out2; 3137cbe0932SMat Martineau } 3147cbe0932SMat Martineau ret = crypto_dh_encode_key(secret, secretlen, &dh_inputs); 3157cbe0932SMat Martineau if (ret) 3167cbe0932SMat Martineau goto out3; 3177cbe0932SMat Martineau 318*85d7311fSEric Biggers tfm = crypto_alloc_kpp("dh", 0, 0); 3197cbe0932SMat Martineau if (IS_ERR(tfm)) { 3207cbe0932SMat Martineau ret = PTR_ERR(tfm); 3217cbe0932SMat Martineau goto out3; 3227cbe0932SMat Martineau } 3237cbe0932SMat Martineau 3247cbe0932SMat Martineau ret = crypto_kpp_set_secret(tfm, secret, secretlen); 3257cbe0932SMat Martineau if (ret) 3267cbe0932SMat Martineau goto out4; 3277cbe0932SMat Martineau 3287cbe0932SMat Martineau outlen = crypto_kpp_maxsize(tfm); 3297cbe0932SMat Martineau 3307cbe0932SMat Martineau if (!kdfcopy) { 3317cbe0932SMat Martineau /* 3327cbe0932SMat Martineau * When not using a KDF, buflen 0 is used to read the 3337cbe0932SMat Martineau * required buffer length 3347cbe0932SMat Martineau */ 3357cbe0932SMat Martineau if (buflen == 0) { 3367cbe0932SMat Martineau ret = outlen; 3377cbe0932SMat Martineau goto out4; 3387cbe0932SMat Martineau } else if (outlen > buflen) { 3397cbe0932SMat Martineau ret = -EOVERFLOW; 3407cbe0932SMat Martineau goto out4; 3417cbe0932SMat Martineau } 3427cbe0932SMat Martineau } 3437cbe0932SMat Martineau 3447cbe0932SMat Martineau outbuf = kzalloc(kdfcopy ? (outlen + kdfcopy->otherinfolen) : outlen, 3457cbe0932SMat Martineau GFP_KERNEL); 3467cbe0932SMat Martineau if (!outbuf) { 3477cbe0932SMat Martineau ret = -ENOMEM; 3487cbe0932SMat Martineau goto out4; 3497cbe0932SMat Martineau } 3507cbe0932SMat Martineau 3517cbe0932SMat Martineau sg_init_one(&outsg, outbuf, outlen); 3527cbe0932SMat Martineau 3537cbe0932SMat Martineau req = kpp_request_alloc(tfm, GFP_KERNEL); 3547cbe0932SMat Martineau if (!req) { 3557cbe0932SMat Martineau ret = -ENOMEM; 3567cbe0932SMat Martineau goto out5; 3577cbe0932SMat Martineau } 3587cbe0932SMat Martineau 3597cbe0932SMat Martineau kpp_request_set_input(req, NULL, 0); 3607cbe0932SMat Martineau kpp_request_set_output(req, &outsg, outlen); 3617cbe0932SMat Martineau init_completion(&compl.completion); 3627cbe0932SMat Martineau kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | 3637cbe0932SMat Martineau CRYPTO_TFM_REQ_MAY_SLEEP, 3647cbe0932SMat Martineau dh_crypto_done, &compl); 3657cbe0932SMat Martineau 366f1c316a3SStephan Mueller /* 3677cbe0932SMat Martineau * For DH, generate_public_key and generate_shared_secret are 3687cbe0932SMat Martineau * the same calculation 369f1c316a3SStephan Mueller */ 3707cbe0932SMat Martineau ret = crypto_kpp_generate_public_key(req); 3717cbe0932SMat Martineau if (ret == -EINPROGRESS) { 3727cbe0932SMat Martineau wait_for_completion(&compl.completion); 3737cbe0932SMat Martineau ret = compl.err; 3747cbe0932SMat Martineau if (ret) 3757cbe0932SMat Martineau goto out6; 376ddbb4114SMat Martineau } 377ddbb4114SMat Martineau 3787cbe0932SMat Martineau if (kdfcopy) { 379f1c316a3SStephan Mueller /* 380f1c316a3SStephan Mueller * Concatenate SP800-56A otherinfo past DH shared secret -- the 381f1c316a3SStephan Mueller * input to the KDF is (DH shared secret || otherinfo) 382f1c316a3SStephan Mueller */ 3837cbe0932SMat Martineau if (copy_from_user(outbuf + req->dst_len, kdfcopy->otherinfo, 384f1c316a3SStephan Mueller kdfcopy->otherinfolen) != 0) { 385f1c316a3SStephan Mueller ret = -EFAULT; 3867cbe0932SMat Martineau goto out6; 387f1c316a3SStephan Mueller } 388f1c316a3SStephan Mueller 3897cbe0932SMat Martineau ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, outbuf, 3907cbe0932SMat Martineau req->dst_len + kdfcopy->otherinfolen, 3917cbe0932SMat Martineau outlen - req->dst_len); 3927cbe0932SMat Martineau } else if (copy_to_user(buffer, outbuf, req->dst_len) == 0) { 3937cbe0932SMat Martineau ret = req->dst_len; 394f1c316a3SStephan Mueller } else { 395ddbb4114SMat Martineau ret = -EFAULT; 396f1c316a3SStephan Mueller } 397ddbb4114SMat Martineau 3987cbe0932SMat Martineau out6: 3997cbe0932SMat Martineau kpp_request_free(req); 4007cbe0932SMat Martineau out5: 4017cbe0932SMat Martineau kzfree(outbuf); 4027cbe0932SMat Martineau out4: 4037cbe0932SMat Martineau crypto_free_kpp(tfm); 4047cbe0932SMat Martineau out3: 4057cbe0932SMat Martineau kzfree(secret); 4067cbe0932SMat Martineau out2: 4077cbe0932SMat Martineau dh_free_data(&dh_inputs); 4087cbe0932SMat Martineau out1: 409f1c316a3SStephan Mueller kdf_dealloc(sdesc); 410ddbb4114SMat Martineau return ret; 411ddbb4114SMat Martineau } 412f1c316a3SStephan Mueller 413f1c316a3SStephan Mueller long keyctl_dh_compute(struct keyctl_dh_params __user *params, 414f1c316a3SStephan Mueller char __user *buffer, size_t buflen, 415f1c316a3SStephan Mueller struct keyctl_kdf_params __user *kdf) 416f1c316a3SStephan Mueller { 417f1c316a3SStephan Mueller struct keyctl_kdf_params kdfcopy; 418f1c316a3SStephan Mueller 419f1c316a3SStephan Mueller if (!kdf) 420f1c316a3SStephan Mueller return __keyctl_dh_compute(params, buffer, buflen, NULL); 421f1c316a3SStephan Mueller 422f1c316a3SStephan Mueller if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0) 423f1c316a3SStephan Mueller return -EFAULT; 424f1c316a3SStephan Mueller 425f1c316a3SStephan Mueller return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy); 426f1c316a3SStephan Mueller } 427