xref: /openbmc/linux/security/keys/dh.c (revision 7cbe0932c2f2014d6e24e716e79ea3910b468950)
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>
13*7cbe0932SMat Martineau #include <linux/scatterlist.h>
14f1c316a3SStephan Mueller #include <linux/crypto.h>
15f1c316a3SStephan Mueller #include <crypto/hash.h>
16*7cbe0932SMat Martineau #include <crypto/kpp.h>
17*7cbe0932SMat Martineau #include <crypto/dh.h>
18ddbb4114SMat Martineau #include <keys/user-type.h>
19ddbb4114SMat Martineau #include "internal.h"
20ddbb4114SMat Martineau 
21*7cbe0932SMat 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;
42*7cbe0932SMat Martineau 			uint8_t *duplicate;
43ddbb4114SMat Martineau 
440837e49aSDavid Howells 			payload = user_key_payload_locked(key);
45ddbb4114SMat Martineau 
46*7cbe0932SMat Martineau 			duplicate = kmemdup(payload->data, payload->datalen,
47*7cbe0932SMat Martineau 					    GFP_KERNEL);
48*7cbe0932SMat Martineau 			if (duplicate) {
49*7cbe0932SMat Martineau 				*data = duplicate;
50ddbb4114SMat Martineau 				ret = payload->datalen;
51ddbb4114SMat Martineau 			} else {
52*7cbe0932SMat 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 
63*7cbe0932SMat Martineau static void dh_free_data(struct dh *dh)
64*7cbe0932SMat Martineau {
65*7cbe0932SMat Martineau 	kzfree(dh->key);
66*7cbe0932SMat Martineau 	kzfree(dh->p);
67*7cbe0932SMat Martineau 	kzfree(dh->g);
68*7cbe0932SMat Martineau }
69*7cbe0932SMat Martineau 
70*7cbe0932SMat Martineau struct dh_completion {
71*7cbe0932SMat Martineau 	struct completion completion;
72*7cbe0932SMat Martineau 	int err;
73*7cbe0932SMat Martineau };
74*7cbe0932SMat Martineau 
75*7cbe0932SMat Martineau static void dh_crypto_done(struct crypto_async_request *req, int err)
76*7cbe0932SMat Martineau {
77*7cbe0932SMat Martineau 	struct dh_completion *compl = req->data;
78*7cbe0932SMat Martineau 
79*7cbe0932SMat Martineau 	if (err == -EINPROGRESS)
80*7cbe0932SMat Martineau 		return;
81*7cbe0932SMat Martineau 
82*7cbe0932SMat Martineau 	compl->err = err;
83*7cbe0932SMat Martineau 	complete(&compl->completion);
84*7cbe0932SMat Martineau }
85*7cbe0932SMat 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,
147*7cbe0932SMat 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 
164*7cbe0932SMat Martineau 		if (zlen && h) {
165*7cbe0932SMat Martineau 			u8 tmpbuffer[h];
166*7cbe0932SMat Martineau 			size_t chunk = min_t(size_t, zlen, h);
167*7cbe0932SMat Martineau 			memset(tmpbuffer, 0, chunk);
168*7cbe0932SMat Martineau 
169*7cbe0932SMat Martineau 			do {
170*7cbe0932SMat Martineau 				err = crypto_shash_update(desc, tmpbuffer,
171*7cbe0932SMat Martineau 							  chunk);
172*7cbe0932SMat Martineau 				if (err)
173*7cbe0932SMat Martineau 					goto err;
174*7cbe0932SMat Martineau 
175*7cbe0932SMat Martineau 				zlen -= chunk;
176*7cbe0932SMat Martineau 				chunk = min_t(size_t, zlen, h);
177*7cbe0932SMat Martineau 			} while (zlen);
178*7cbe0932SMat Martineau 		}
179*7cbe0932SMat 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 		if (dlen < h) {
187f1c316a3SStephan Mueller 			u8 tmpbuffer[h];
188f1c316a3SStephan Mueller 
189f1c316a3SStephan Mueller 			err = crypto_shash_final(desc, tmpbuffer);
190f1c316a3SStephan Mueller 			if (err)
191f1c316a3SStephan Mueller 				goto err;
192f1c316a3SStephan Mueller 			memcpy(dst, tmpbuffer, dlen);
193f1c316a3SStephan Mueller 			memzero_explicit(tmpbuffer, h);
194f1c316a3SStephan Mueller 			return 0;
195f1c316a3SStephan Mueller 		} else {
196f1c316a3SStephan Mueller 			err = crypto_shash_final(desc, dst);
197f1c316a3SStephan Mueller 			if (err)
198f1c316a3SStephan Mueller 				goto err;
199f1c316a3SStephan Mueller 
200f1c316a3SStephan Mueller 			dlen -= h;
201f1c316a3SStephan Mueller 			dst += h;
2020ddd9f1aSEric Biggers 			counter = cpu_to_be32(be32_to_cpu(counter) + 1);
203f1c316a3SStephan Mueller 		}
204f1c316a3SStephan Mueller 	}
205f1c316a3SStephan Mueller 
206f1c316a3SStephan Mueller 	return 0;
207f1c316a3SStephan Mueller 
208f1c316a3SStephan Mueller err:
209f1c316a3SStephan Mueller 	memzero_explicit(dst_orig, dlen);
210f1c316a3SStephan Mueller 	return err;
211f1c316a3SStephan Mueller }
212f1c316a3SStephan Mueller 
213f1c316a3SStephan Mueller static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc,
2144693fc73SStephan Mueller 				 char __user *buffer, size_t buflen,
215*7cbe0932SMat Martineau 				 uint8_t *kbuf, size_t kbuflen, size_t lzero)
216f1c316a3SStephan Mueller {
217f1c316a3SStephan Mueller 	uint8_t *outbuf = NULL;
218f1c316a3SStephan Mueller 	int ret;
219f1c316a3SStephan Mueller 
220f1c316a3SStephan Mueller 	outbuf = kmalloc(buflen, GFP_KERNEL);
221f1c316a3SStephan Mueller 	if (!outbuf) {
222f1c316a3SStephan Mueller 		ret = -ENOMEM;
223f1c316a3SStephan Mueller 		goto err;
224f1c316a3SStephan Mueller 	}
225f1c316a3SStephan Mueller 
226*7cbe0932SMat Martineau 	ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, buflen, lzero);
227f1c316a3SStephan Mueller 	if (ret)
228f1c316a3SStephan Mueller 		goto err;
229f1c316a3SStephan Mueller 
230f1c316a3SStephan Mueller 	ret = buflen;
231f1c316a3SStephan Mueller 	if (copy_to_user(buffer, outbuf, buflen) != 0)
232f1c316a3SStephan Mueller 		ret = -EFAULT;
233f1c316a3SStephan Mueller 
234f1c316a3SStephan Mueller err:
235f1c316a3SStephan Mueller 	kzfree(outbuf);
236f1c316a3SStephan Mueller 	return ret;
237f1c316a3SStephan Mueller }
238f1c316a3SStephan Mueller 
239f1c316a3SStephan Mueller long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
240f1c316a3SStephan Mueller 			 char __user *buffer, size_t buflen,
241f1c316a3SStephan Mueller 			 struct keyctl_kdf_params *kdfcopy)
242ddbb4114SMat Martineau {
243ddbb4114SMat Martineau 	long ret;
244*7cbe0932SMat Martineau 	ssize_t dlen;
245*7cbe0932SMat Martineau 	int secretlen;
246*7cbe0932SMat Martineau 	int outlen;
247ddbb4114SMat Martineau 	struct keyctl_dh_params pcopy;
248*7cbe0932SMat Martineau 	struct dh dh_inputs;
249*7cbe0932SMat Martineau 	struct scatterlist outsg;
250*7cbe0932SMat Martineau 	struct dh_completion compl;
251*7cbe0932SMat Martineau 	struct crypto_kpp *tfm;
252*7cbe0932SMat Martineau 	struct kpp_request *req;
253*7cbe0932SMat Martineau 	uint8_t *secret;
254*7cbe0932SMat Martineau 	uint8_t *outbuf;
255f1c316a3SStephan Mueller 	struct kdf_sdesc *sdesc = NULL;
256ddbb4114SMat Martineau 
257ddbb4114SMat Martineau 	if (!params || (!buffer && buflen)) {
258ddbb4114SMat Martineau 		ret = -EINVAL;
259*7cbe0932SMat Martineau 		goto out1;
260ddbb4114SMat Martineau 	}
261ddbb4114SMat Martineau 	if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) {
262ddbb4114SMat Martineau 		ret = -EFAULT;
263*7cbe0932SMat Martineau 		goto out1;
264ddbb4114SMat Martineau 	}
265ddbb4114SMat Martineau 
266f1c316a3SStephan Mueller 	if (kdfcopy) {
267f1c316a3SStephan Mueller 		char *hashname;
268f1c316a3SStephan Mueller 
269f1c316a3SStephan Mueller 		if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN ||
270f1c316a3SStephan Mueller 		    kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) {
271f1c316a3SStephan Mueller 			ret = -EMSGSIZE;
272*7cbe0932SMat Martineau 			goto out1;
2734693fc73SStephan Mueller 		}
2744693fc73SStephan Mueller 
275f1c316a3SStephan Mueller 		/* get KDF name string */
276f1c316a3SStephan Mueller 		hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME);
277f1c316a3SStephan Mueller 		if (IS_ERR(hashname)) {
278f1c316a3SStephan Mueller 			ret = PTR_ERR(hashname);
279*7cbe0932SMat Martineau 			goto out1;
280f1c316a3SStephan Mueller 		}
281f1c316a3SStephan Mueller 
282f1c316a3SStephan Mueller 		/* allocate KDF from the kernel crypto API */
283f1c316a3SStephan Mueller 		ret = kdf_alloc(&sdesc, hashname);
284f1c316a3SStephan Mueller 		kfree(hashname);
285f1c316a3SStephan Mueller 		if (ret)
286*7cbe0932SMat Martineau 			goto out1;
287f1c316a3SStephan Mueller 	}
288f1c316a3SStephan Mueller 
289*7cbe0932SMat Martineau 	memset(&dh_inputs, 0, sizeof(dh_inputs));
290*7cbe0932SMat Martineau 
291*7cbe0932SMat Martineau 	dlen = dh_data_from_key(pcopy.prime, &dh_inputs.p);
292*7cbe0932SMat Martineau 	if (dlen < 0) {
293*7cbe0932SMat Martineau 		ret = dlen;
294*7cbe0932SMat Martineau 		goto out1;
295*7cbe0932SMat Martineau 	}
296*7cbe0932SMat Martineau 	dh_inputs.p_size = dlen;
297*7cbe0932SMat Martineau 
298*7cbe0932SMat Martineau 	dlen = dh_data_from_key(pcopy.base, &dh_inputs.g);
299*7cbe0932SMat Martineau 	if (dlen < 0) {
300*7cbe0932SMat Martineau 		ret = dlen;
301*7cbe0932SMat Martineau 		goto out2;
302*7cbe0932SMat Martineau 	}
303*7cbe0932SMat Martineau 	dh_inputs.g_size = dlen;
304*7cbe0932SMat Martineau 
305*7cbe0932SMat Martineau 	dlen = dh_data_from_key(pcopy.private, &dh_inputs.key);
306*7cbe0932SMat Martineau 	if (dlen < 0) {
307*7cbe0932SMat Martineau 		ret = dlen;
308*7cbe0932SMat Martineau 		goto out2;
309*7cbe0932SMat Martineau 	}
310*7cbe0932SMat Martineau 	dh_inputs.key_size = dlen;
311*7cbe0932SMat Martineau 
312*7cbe0932SMat Martineau 	secretlen = crypto_dh_key_len(&dh_inputs);
313*7cbe0932SMat Martineau 	secret = kmalloc(secretlen, GFP_KERNEL);
314*7cbe0932SMat Martineau 	if (!secret) {
315*7cbe0932SMat Martineau 		ret = -ENOMEM;
316*7cbe0932SMat Martineau 		goto out2;
317*7cbe0932SMat Martineau 	}
318*7cbe0932SMat Martineau 	ret = crypto_dh_encode_key(secret, secretlen, &dh_inputs);
319*7cbe0932SMat Martineau 	if (ret)
320*7cbe0932SMat Martineau 		goto out3;
321*7cbe0932SMat Martineau 
322*7cbe0932SMat Martineau 	tfm = crypto_alloc_kpp("dh", CRYPTO_ALG_TYPE_KPP, 0);
323*7cbe0932SMat Martineau 	if (IS_ERR(tfm)) {
324*7cbe0932SMat Martineau 		ret = PTR_ERR(tfm);
325*7cbe0932SMat Martineau 		goto out3;
326*7cbe0932SMat Martineau 	}
327*7cbe0932SMat Martineau 
328*7cbe0932SMat Martineau 	ret = crypto_kpp_set_secret(tfm, secret, secretlen);
329*7cbe0932SMat Martineau 	if (ret)
330*7cbe0932SMat Martineau 		goto out4;
331*7cbe0932SMat Martineau 
332*7cbe0932SMat Martineau 	outlen = crypto_kpp_maxsize(tfm);
333*7cbe0932SMat Martineau 
334*7cbe0932SMat Martineau 	if (!kdfcopy) {
335*7cbe0932SMat Martineau 		/*
336*7cbe0932SMat Martineau 		 * When not using a KDF, buflen 0 is used to read the
337*7cbe0932SMat Martineau 		 * required buffer length
338*7cbe0932SMat Martineau 		 */
339*7cbe0932SMat Martineau 		if (buflen == 0) {
340*7cbe0932SMat Martineau 			ret = outlen;
341*7cbe0932SMat Martineau 			goto out4;
342*7cbe0932SMat Martineau 		} else if (outlen > buflen) {
343*7cbe0932SMat Martineau 			ret = -EOVERFLOW;
344*7cbe0932SMat Martineau 			goto out4;
345*7cbe0932SMat Martineau 		}
346*7cbe0932SMat Martineau 	}
347*7cbe0932SMat Martineau 
348*7cbe0932SMat Martineau 	outbuf = kzalloc(kdfcopy ? (outlen + kdfcopy->otherinfolen) : outlen,
349*7cbe0932SMat Martineau 			 GFP_KERNEL);
350*7cbe0932SMat Martineau 	if (!outbuf) {
351*7cbe0932SMat Martineau 		ret = -ENOMEM;
352*7cbe0932SMat Martineau 		goto out4;
353*7cbe0932SMat Martineau 	}
354*7cbe0932SMat Martineau 
355*7cbe0932SMat Martineau 	sg_init_one(&outsg, outbuf, outlen);
356*7cbe0932SMat Martineau 
357*7cbe0932SMat Martineau 	req = kpp_request_alloc(tfm, GFP_KERNEL);
358*7cbe0932SMat Martineau 	if (!req) {
359*7cbe0932SMat Martineau 		ret = -ENOMEM;
360*7cbe0932SMat Martineau 		goto out5;
361*7cbe0932SMat Martineau 	}
362*7cbe0932SMat Martineau 
363*7cbe0932SMat Martineau 	kpp_request_set_input(req, NULL, 0);
364*7cbe0932SMat Martineau 	kpp_request_set_output(req, &outsg, outlen);
365*7cbe0932SMat Martineau 	init_completion(&compl.completion);
366*7cbe0932SMat Martineau 	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
367*7cbe0932SMat Martineau 				 CRYPTO_TFM_REQ_MAY_SLEEP,
368*7cbe0932SMat Martineau 				 dh_crypto_done, &compl);
369*7cbe0932SMat Martineau 
370f1c316a3SStephan Mueller 	/*
371*7cbe0932SMat Martineau 	 * For DH, generate_public_key and generate_shared_secret are
372*7cbe0932SMat Martineau 	 * the same calculation
373f1c316a3SStephan Mueller 	 */
374*7cbe0932SMat Martineau 	ret = crypto_kpp_generate_public_key(req);
375*7cbe0932SMat Martineau 	if (ret == -EINPROGRESS) {
376*7cbe0932SMat Martineau 		wait_for_completion(&compl.completion);
377*7cbe0932SMat Martineau 		ret = compl.err;
378*7cbe0932SMat Martineau 		if (ret)
379*7cbe0932SMat Martineau 			goto out6;
380ddbb4114SMat Martineau 	}
381ddbb4114SMat Martineau 
382*7cbe0932SMat Martineau 	if (kdfcopy) {
383f1c316a3SStephan Mueller 		/*
384f1c316a3SStephan Mueller 		 * Concatenate SP800-56A otherinfo past DH shared secret -- the
385f1c316a3SStephan Mueller 		 * input to the KDF is (DH shared secret || otherinfo)
386f1c316a3SStephan Mueller 		 */
387*7cbe0932SMat Martineau 		if (copy_from_user(outbuf + req->dst_len, kdfcopy->otherinfo,
388f1c316a3SStephan Mueller 				   kdfcopy->otherinfolen) != 0) {
389f1c316a3SStephan Mueller 			ret = -EFAULT;
390*7cbe0932SMat Martineau 			goto out6;
391f1c316a3SStephan Mueller 		}
392f1c316a3SStephan Mueller 
393*7cbe0932SMat Martineau 		ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, outbuf,
394*7cbe0932SMat Martineau 					    req->dst_len + kdfcopy->otherinfolen,
395*7cbe0932SMat Martineau 					    outlen - req->dst_len);
396*7cbe0932SMat Martineau 	} else if (copy_to_user(buffer, outbuf, req->dst_len) == 0) {
397*7cbe0932SMat Martineau 		ret = req->dst_len;
398f1c316a3SStephan Mueller 	} else {
399ddbb4114SMat Martineau 		ret = -EFAULT;
400f1c316a3SStephan Mueller 	}
401ddbb4114SMat Martineau 
402*7cbe0932SMat Martineau out6:
403*7cbe0932SMat Martineau 	kpp_request_free(req);
404*7cbe0932SMat Martineau out5:
405*7cbe0932SMat Martineau 	kzfree(outbuf);
406*7cbe0932SMat Martineau out4:
407*7cbe0932SMat Martineau 	crypto_free_kpp(tfm);
408*7cbe0932SMat Martineau out3:
409*7cbe0932SMat Martineau 	kzfree(secret);
410*7cbe0932SMat Martineau out2:
411*7cbe0932SMat Martineau 	dh_free_data(&dh_inputs);
412*7cbe0932SMat Martineau out1:
413f1c316a3SStephan Mueller 	kdf_dealloc(sdesc);
414ddbb4114SMat Martineau 	return ret;
415ddbb4114SMat Martineau }
416f1c316a3SStephan Mueller 
417f1c316a3SStephan Mueller long keyctl_dh_compute(struct keyctl_dh_params __user *params,
418f1c316a3SStephan Mueller 		       char __user *buffer, size_t buflen,
419f1c316a3SStephan Mueller 		       struct keyctl_kdf_params __user *kdf)
420f1c316a3SStephan Mueller {
421f1c316a3SStephan Mueller 	struct keyctl_kdf_params kdfcopy;
422f1c316a3SStephan Mueller 
423f1c316a3SStephan Mueller 	if (!kdf)
424f1c316a3SStephan Mueller 		return __keyctl_dh_compute(params, buffer, buflen, NULL);
425f1c316a3SStephan Mueller 
426f1c316a3SStephan Mueller 	if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0)
427f1c316a3SStephan Mueller 		return -EFAULT;
428f1c316a3SStephan Mueller 
429f1c316a3SStephan Mueller 	return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
430f1c316a3SStephan Mueller }
431