xref: /openbmc/linux/security/keys/dh.c (revision 85d7311f1908b9ca20c10c2c23f5dbb93875f0c6)
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