xref: /openbmc/linux/security/keys/dh.c (revision f1c316a3ab9d24df6022682422fe897492f2c0c8)
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/mpi.h>
12ddbb4114SMat Martineau #include <linux/slab.h>
13ddbb4114SMat Martineau #include <linux/uaccess.h>
14*f1c316a3SStephan Mueller #include <linux/crypto.h>
15*f1c316a3SStephan Mueller #include <crypto/hash.h>
16ddbb4114SMat Martineau #include <keys/user-type.h>
17ddbb4114SMat Martineau #include "internal.h"
18ddbb4114SMat Martineau 
19ddbb4114SMat Martineau /*
20ddbb4114SMat Martineau  * Public key or shared secret generation function [RFC2631 sec 2.1.1]
21ddbb4114SMat Martineau  *
22ddbb4114SMat Martineau  * ya = g^xa mod p;
23ddbb4114SMat Martineau  * or
24ddbb4114SMat Martineau  * ZZ = yb^xa mod p;
25ddbb4114SMat Martineau  *
26ddbb4114SMat Martineau  * where xa is the local private key, ya is the local public key, g is
27ddbb4114SMat Martineau  * the generator, p is the prime, yb is the remote public key, and ZZ
28ddbb4114SMat Martineau  * is the shared secret.
29ddbb4114SMat Martineau  *
30ddbb4114SMat Martineau  * Both are the same calculation, so g or yb are the "base" and ya or
31ddbb4114SMat Martineau  * ZZ are the "result".
32ddbb4114SMat Martineau  */
33ddbb4114SMat Martineau static int do_dh(MPI result, MPI base, MPI xa, MPI p)
34ddbb4114SMat Martineau {
35ddbb4114SMat Martineau 	return mpi_powm(result, base, xa, p);
36ddbb4114SMat Martineau }
37ddbb4114SMat Martineau 
38ddbb4114SMat Martineau static ssize_t mpi_from_key(key_serial_t keyid, size_t maxlen, MPI *mpi)
39ddbb4114SMat Martineau {
40ddbb4114SMat Martineau 	struct key *key;
41ddbb4114SMat Martineau 	key_ref_t key_ref;
42ddbb4114SMat Martineau 	long status;
43ddbb4114SMat Martineau 	ssize_t ret;
44ddbb4114SMat Martineau 
45ddbb4114SMat Martineau 	key_ref = lookup_user_key(keyid, 0, KEY_NEED_READ);
46ddbb4114SMat Martineau 	if (IS_ERR(key_ref)) {
47ddbb4114SMat Martineau 		ret = -ENOKEY;
48ddbb4114SMat Martineau 		goto error;
49ddbb4114SMat Martineau 	}
50ddbb4114SMat Martineau 
51ddbb4114SMat Martineau 	key = key_ref_to_ptr(key_ref);
52ddbb4114SMat Martineau 
53ddbb4114SMat Martineau 	ret = -EOPNOTSUPP;
54ddbb4114SMat Martineau 	if (key->type == &key_type_user) {
55ddbb4114SMat Martineau 		down_read(&key->sem);
56ddbb4114SMat Martineau 		status = key_validate(key);
57ddbb4114SMat Martineau 		if (status == 0) {
58ddbb4114SMat Martineau 			const struct user_key_payload *payload;
59ddbb4114SMat Martineau 
600837e49aSDavid Howells 			payload = user_key_payload_locked(key);
61ddbb4114SMat Martineau 
62ddbb4114SMat Martineau 			if (maxlen == 0) {
63ddbb4114SMat Martineau 				*mpi = NULL;
64ddbb4114SMat Martineau 				ret = payload->datalen;
65ddbb4114SMat Martineau 			} else if (payload->datalen <= maxlen) {
66ddbb4114SMat Martineau 				*mpi = mpi_read_raw_data(payload->data,
67ddbb4114SMat Martineau 							 payload->datalen);
68ddbb4114SMat Martineau 				if (*mpi)
69ddbb4114SMat Martineau 					ret = payload->datalen;
70ddbb4114SMat Martineau 			} else {
71ddbb4114SMat Martineau 				ret = -EINVAL;
72ddbb4114SMat Martineau 			}
73ddbb4114SMat Martineau 		}
74ddbb4114SMat Martineau 		up_read(&key->sem);
75ddbb4114SMat Martineau 	}
76ddbb4114SMat Martineau 
77ddbb4114SMat Martineau 	key_put(key);
78ddbb4114SMat Martineau error:
79ddbb4114SMat Martineau 	return ret;
80ddbb4114SMat Martineau }
81ddbb4114SMat Martineau 
82*f1c316a3SStephan Mueller struct kdf_sdesc {
83*f1c316a3SStephan Mueller 	struct shash_desc shash;
84*f1c316a3SStephan Mueller 	char ctx[];
85*f1c316a3SStephan Mueller };
86*f1c316a3SStephan Mueller 
87*f1c316a3SStephan Mueller static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname)
88*f1c316a3SStephan Mueller {
89*f1c316a3SStephan Mueller 	struct crypto_shash *tfm;
90*f1c316a3SStephan Mueller 	struct kdf_sdesc *sdesc;
91*f1c316a3SStephan Mueller 	int size;
92*f1c316a3SStephan Mueller 
93*f1c316a3SStephan Mueller 	/* allocate synchronous hash */
94*f1c316a3SStephan Mueller 	tfm = crypto_alloc_shash(hashname, 0, 0);
95*f1c316a3SStephan Mueller 	if (IS_ERR(tfm)) {
96*f1c316a3SStephan Mueller 		pr_info("could not allocate digest TFM handle %s\n", hashname);
97*f1c316a3SStephan Mueller 		return PTR_ERR(tfm);
98*f1c316a3SStephan Mueller 	}
99*f1c316a3SStephan Mueller 
100*f1c316a3SStephan Mueller 	size = sizeof(struct shash_desc) + crypto_shash_descsize(tfm);
101*f1c316a3SStephan Mueller 	sdesc = kmalloc(size, GFP_KERNEL);
102*f1c316a3SStephan Mueller 	if (!sdesc)
103*f1c316a3SStephan Mueller 		return -ENOMEM;
104*f1c316a3SStephan Mueller 	sdesc->shash.tfm = tfm;
105*f1c316a3SStephan Mueller 	sdesc->shash.flags = 0x0;
106*f1c316a3SStephan Mueller 
107*f1c316a3SStephan Mueller 	*sdesc_ret = sdesc;
108*f1c316a3SStephan Mueller 
109*f1c316a3SStephan Mueller 	return 0;
110*f1c316a3SStephan Mueller }
111*f1c316a3SStephan Mueller 
112*f1c316a3SStephan Mueller static void kdf_dealloc(struct kdf_sdesc *sdesc)
113*f1c316a3SStephan Mueller {
114*f1c316a3SStephan Mueller 	if (!sdesc)
115*f1c316a3SStephan Mueller 		return;
116*f1c316a3SStephan Mueller 
117*f1c316a3SStephan Mueller 	if (sdesc->shash.tfm)
118*f1c316a3SStephan Mueller 		crypto_free_shash(sdesc->shash.tfm);
119*f1c316a3SStephan Mueller 
120*f1c316a3SStephan Mueller 	kzfree(sdesc);
121*f1c316a3SStephan Mueller }
122*f1c316a3SStephan Mueller 
123*f1c316a3SStephan Mueller /* convert 32 bit integer into its string representation */
124*f1c316a3SStephan Mueller static inline void crypto_kw_cpu_to_be32(u32 val, u8 *buf)
125*f1c316a3SStephan Mueller {
126*f1c316a3SStephan Mueller 	__be32 *a = (__be32 *)buf;
127*f1c316a3SStephan Mueller 
128*f1c316a3SStephan Mueller 	*a = cpu_to_be32(val);
129*f1c316a3SStephan Mueller }
130*f1c316a3SStephan Mueller 
131*f1c316a3SStephan Mueller /*
132*f1c316a3SStephan Mueller  * Implementation of the KDF in counter mode according to SP800-108 section 5.1
133*f1c316a3SStephan Mueller  * as well as SP800-56A section 5.8.1 (Single-step KDF).
134*f1c316a3SStephan Mueller  *
135*f1c316a3SStephan Mueller  * SP800-56A:
136*f1c316a3SStephan Mueller  * The src pointer is defined as Z || other info where Z is the shared secret
137*f1c316a3SStephan Mueller  * from DH and other info is an arbitrary string (see SP800-56A section
138*f1c316a3SStephan Mueller  * 5.8.1.2).
139*f1c316a3SStephan Mueller  */
140*f1c316a3SStephan Mueller static int kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen,
141*f1c316a3SStephan Mueller 		   u8 *dst, unsigned int dlen)
142*f1c316a3SStephan Mueller {
143*f1c316a3SStephan Mueller 	struct shash_desc *desc = &sdesc->shash;
144*f1c316a3SStephan Mueller 	unsigned int h = crypto_shash_digestsize(desc->tfm);
145*f1c316a3SStephan Mueller 	int err = 0;
146*f1c316a3SStephan Mueller 	u8 *dst_orig = dst;
147*f1c316a3SStephan Mueller 	u32 i = 1;
148*f1c316a3SStephan Mueller 	u8 iteration[sizeof(u32)];
149*f1c316a3SStephan Mueller 
150*f1c316a3SStephan Mueller 	while (dlen) {
151*f1c316a3SStephan Mueller 		err = crypto_shash_init(desc);
152*f1c316a3SStephan Mueller 		if (err)
153*f1c316a3SStephan Mueller 			goto err;
154*f1c316a3SStephan Mueller 
155*f1c316a3SStephan Mueller 		crypto_kw_cpu_to_be32(i, iteration);
156*f1c316a3SStephan Mueller 		err = crypto_shash_update(desc, iteration, sizeof(u32));
157*f1c316a3SStephan Mueller 		if (err)
158*f1c316a3SStephan Mueller 			goto err;
159*f1c316a3SStephan Mueller 
160*f1c316a3SStephan Mueller 		if (src && slen) {
161*f1c316a3SStephan Mueller 			err = crypto_shash_update(desc, src, slen);
162*f1c316a3SStephan Mueller 			if (err)
163*f1c316a3SStephan Mueller 				goto err;
164*f1c316a3SStephan Mueller 		}
165*f1c316a3SStephan Mueller 
166*f1c316a3SStephan Mueller 		if (dlen < h) {
167*f1c316a3SStephan Mueller 			u8 tmpbuffer[h];
168*f1c316a3SStephan Mueller 
169*f1c316a3SStephan Mueller 			err = crypto_shash_final(desc, tmpbuffer);
170*f1c316a3SStephan Mueller 			if (err)
171*f1c316a3SStephan Mueller 				goto err;
172*f1c316a3SStephan Mueller 			memcpy(dst, tmpbuffer, dlen);
173*f1c316a3SStephan Mueller 			memzero_explicit(tmpbuffer, h);
174*f1c316a3SStephan Mueller 			return 0;
175*f1c316a3SStephan Mueller 		} else {
176*f1c316a3SStephan Mueller 			err = crypto_shash_final(desc, dst);
177*f1c316a3SStephan Mueller 			if (err)
178*f1c316a3SStephan Mueller 				goto err;
179*f1c316a3SStephan Mueller 
180*f1c316a3SStephan Mueller 			dlen -= h;
181*f1c316a3SStephan Mueller 			dst += h;
182*f1c316a3SStephan Mueller 			i++;
183*f1c316a3SStephan Mueller 		}
184*f1c316a3SStephan Mueller 	}
185*f1c316a3SStephan Mueller 
186*f1c316a3SStephan Mueller 	return 0;
187*f1c316a3SStephan Mueller 
188*f1c316a3SStephan Mueller err:
189*f1c316a3SStephan Mueller 	memzero_explicit(dst_orig, dlen);
190*f1c316a3SStephan Mueller 	return err;
191*f1c316a3SStephan Mueller }
192*f1c316a3SStephan Mueller 
193*f1c316a3SStephan Mueller static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc,
1944693fc73SStephan Mueller 				 char __user *buffer, size_t buflen,
195*f1c316a3SStephan Mueller 				 uint8_t *kbuf, size_t kbuflen)
196*f1c316a3SStephan Mueller {
197*f1c316a3SStephan Mueller 	uint8_t *outbuf = NULL;
198*f1c316a3SStephan Mueller 	int ret;
199*f1c316a3SStephan Mueller 
200*f1c316a3SStephan Mueller 	outbuf = kmalloc(buflen, GFP_KERNEL);
201*f1c316a3SStephan Mueller 	if (!outbuf) {
202*f1c316a3SStephan Mueller 		ret = -ENOMEM;
203*f1c316a3SStephan Mueller 		goto err;
204*f1c316a3SStephan Mueller 	}
205*f1c316a3SStephan Mueller 
206*f1c316a3SStephan Mueller 	ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, buflen);
207*f1c316a3SStephan Mueller 	if (ret)
208*f1c316a3SStephan Mueller 		goto err;
209*f1c316a3SStephan Mueller 
210*f1c316a3SStephan Mueller 	ret = buflen;
211*f1c316a3SStephan Mueller 	if (copy_to_user(buffer, outbuf, buflen) != 0)
212*f1c316a3SStephan Mueller 		ret = -EFAULT;
213*f1c316a3SStephan Mueller 
214*f1c316a3SStephan Mueller err:
215*f1c316a3SStephan Mueller 	kzfree(outbuf);
216*f1c316a3SStephan Mueller 	return ret;
217*f1c316a3SStephan Mueller }
218*f1c316a3SStephan Mueller 
219*f1c316a3SStephan Mueller long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
220*f1c316a3SStephan Mueller 			 char __user *buffer, size_t buflen,
221*f1c316a3SStephan Mueller 			 struct keyctl_kdf_params *kdfcopy)
222ddbb4114SMat Martineau {
223ddbb4114SMat Martineau 	long ret;
224ddbb4114SMat Martineau 	MPI base, private, prime, result;
225ddbb4114SMat Martineau 	unsigned nbytes;
226ddbb4114SMat Martineau 	struct keyctl_dh_params pcopy;
227ddbb4114SMat Martineau 	uint8_t *kbuf;
228ddbb4114SMat Martineau 	ssize_t keylen;
229ddbb4114SMat Martineau 	size_t resultlen;
230*f1c316a3SStephan Mueller 	struct kdf_sdesc *sdesc = NULL;
231ddbb4114SMat Martineau 
232ddbb4114SMat Martineau 	if (!params || (!buffer && buflen)) {
233ddbb4114SMat Martineau 		ret = -EINVAL;
234ddbb4114SMat Martineau 		goto out;
235ddbb4114SMat Martineau 	}
236ddbb4114SMat Martineau 	if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) {
237ddbb4114SMat Martineau 		ret = -EFAULT;
238ddbb4114SMat Martineau 		goto out;
239ddbb4114SMat Martineau 	}
240ddbb4114SMat Martineau 
241*f1c316a3SStephan Mueller 	if (kdfcopy) {
242*f1c316a3SStephan Mueller 		char *hashname;
243*f1c316a3SStephan Mueller 
244*f1c316a3SStephan Mueller 		if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN ||
245*f1c316a3SStephan Mueller 		    kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) {
246*f1c316a3SStephan Mueller 			ret = -EMSGSIZE;
2474693fc73SStephan Mueller 			goto out;
2484693fc73SStephan Mueller 		}
2494693fc73SStephan Mueller 
250*f1c316a3SStephan Mueller 		/* get KDF name string */
251*f1c316a3SStephan Mueller 		hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME);
252*f1c316a3SStephan Mueller 		if (IS_ERR(hashname)) {
253*f1c316a3SStephan Mueller 			ret = PTR_ERR(hashname);
254*f1c316a3SStephan Mueller 			goto out;
255*f1c316a3SStephan Mueller 		}
256*f1c316a3SStephan Mueller 
257*f1c316a3SStephan Mueller 		/* allocate KDF from the kernel crypto API */
258*f1c316a3SStephan Mueller 		ret = kdf_alloc(&sdesc, hashname);
259*f1c316a3SStephan Mueller 		kfree(hashname);
260*f1c316a3SStephan Mueller 		if (ret)
261*f1c316a3SStephan Mueller 			goto out;
262*f1c316a3SStephan Mueller 	}
263*f1c316a3SStephan Mueller 
264*f1c316a3SStephan Mueller 	/*
265*f1c316a3SStephan Mueller 	 * If the caller requests postprocessing with a KDF, allow an
266*f1c316a3SStephan Mueller 	 * arbitrary output buffer size since the KDF ensures proper truncation.
267*f1c316a3SStephan Mueller 	 */
268*f1c316a3SStephan Mueller 	keylen = mpi_from_key(pcopy.prime, kdfcopy ? SIZE_MAX : buflen, &prime);
269ddbb4114SMat Martineau 	if (keylen < 0 || !prime) {
270ddbb4114SMat Martineau 		/* buflen == 0 may be used to query the required buffer size,
271ddbb4114SMat Martineau 		 * which is the prime key length.
272ddbb4114SMat Martineau 		 */
273ddbb4114SMat Martineau 		ret = keylen;
274ddbb4114SMat Martineau 		goto out;
275ddbb4114SMat Martineau 	}
276ddbb4114SMat Martineau 
277ddbb4114SMat Martineau 	/* The result is never longer than the prime */
278ddbb4114SMat Martineau 	resultlen = keylen;
279ddbb4114SMat Martineau 
280ddbb4114SMat Martineau 	keylen = mpi_from_key(pcopy.base, SIZE_MAX, &base);
281ddbb4114SMat Martineau 	if (keylen < 0 || !base) {
282ddbb4114SMat Martineau 		ret = keylen;
283ddbb4114SMat Martineau 		goto error1;
284ddbb4114SMat Martineau 	}
285ddbb4114SMat Martineau 
286ddbb4114SMat Martineau 	keylen = mpi_from_key(pcopy.private, SIZE_MAX, &private);
287ddbb4114SMat Martineau 	if (keylen < 0 || !private) {
288ddbb4114SMat Martineau 		ret = keylen;
289ddbb4114SMat Martineau 		goto error2;
290ddbb4114SMat Martineau 	}
291ddbb4114SMat Martineau 
292ddbb4114SMat Martineau 	result = mpi_alloc(0);
293ddbb4114SMat Martineau 	if (!result) {
294ddbb4114SMat Martineau 		ret = -ENOMEM;
295ddbb4114SMat Martineau 		goto error3;
296ddbb4114SMat Martineau 	}
297ddbb4114SMat Martineau 
298*f1c316a3SStephan Mueller 	/* allocate space for DH shared secret and SP800-56A otherinfo */
299*f1c316a3SStephan Mueller 	kbuf = kmalloc(kdfcopy ? (resultlen + kdfcopy->otherinfolen) : resultlen,
300*f1c316a3SStephan Mueller 		       GFP_KERNEL);
301ddbb4114SMat Martineau 	if (!kbuf) {
302ddbb4114SMat Martineau 		ret = -ENOMEM;
303ddbb4114SMat Martineau 		goto error4;
304ddbb4114SMat Martineau 	}
305ddbb4114SMat Martineau 
306*f1c316a3SStephan Mueller 	/*
307*f1c316a3SStephan Mueller 	 * Concatenate SP800-56A otherinfo past DH shared secret -- the
308*f1c316a3SStephan Mueller 	 * input to the KDF is (DH shared secret || otherinfo)
309*f1c316a3SStephan Mueller 	 */
310*f1c316a3SStephan Mueller 	if (kdfcopy && kdfcopy->otherinfo &&
311*f1c316a3SStephan Mueller 	    copy_from_user(kbuf + resultlen, kdfcopy->otherinfo,
312*f1c316a3SStephan Mueller 			   kdfcopy->otherinfolen) != 0) {
313*f1c316a3SStephan Mueller 		ret = -EFAULT;
314*f1c316a3SStephan Mueller 		goto error5;
315*f1c316a3SStephan Mueller 	}
316*f1c316a3SStephan Mueller 
317ddbb4114SMat Martineau 	ret = do_dh(result, base, private, prime);
318ddbb4114SMat Martineau 	if (ret)
319ddbb4114SMat Martineau 		goto error5;
320ddbb4114SMat Martineau 
321ddbb4114SMat Martineau 	ret = mpi_read_buffer(result, kbuf, resultlen, &nbytes, NULL);
322ddbb4114SMat Martineau 	if (ret != 0)
323ddbb4114SMat Martineau 		goto error5;
324ddbb4114SMat Martineau 
325*f1c316a3SStephan Mueller 	if (kdfcopy) {
326*f1c316a3SStephan Mueller 		ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, kbuf,
327*f1c316a3SStephan Mueller 					    resultlen + kdfcopy->otherinfolen);
328*f1c316a3SStephan Mueller 	} else {
329ddbb4114SMat Martineau 		ret = nbytes;
330ddbb4114SMat Martineau 		if (copy_to_user(buffer, kbuf, nbytes) != 0)
331ddbb4114SMat Martineau 			ret = -EFAULT;
332*f1c316a3SStephan Mueller 	}
333ddbb4114SMat Martineau 
334ddbb4114SMat Martineau error5:
335*f1c316a3SStephan Mueller 	kzfree(kbuf);
336ddbb4114SMat Martineau error4:
337ddbb4114SMat Martineau 	mpi_free(result);
338ddbb4114SMat Martineau error3:
339ddbb4114SMat Martineau 	mpi_free(private);
340ddbb4114SMat Martineau error2:
341ddbb4114SMat Martineau 	mpi_free(base);
342ddbb4114SMat Martineau error1:
343ddbb4114SMat Martineau 	mpi_free(prime);
344ddbb4114SMat Martineau out:
345*f1c316a3SStephan Mueller 	kdf_dealloc(sdesc);
346ddbb4114SMat Martineau 	return ret;
347ddbb4114SMat Martineau }
348*f1c316a3SStephan Mueller 
349*f1c316a3SStephan Mueller long keyctl_dh_compute(struct keyctl_dh_params __user *params,
350*f1c316a3SStephan Mueller 		       char __user *buffer, size_t buflen,
351*f1c316a3SStephan Mueller 		       struct keyctl_kdf_params __user *kdf)
352*f1c316a3SStephan Mueller {
353*f1c316a3SStephan Mueller 	struct keyctl_kdf_params kdfcopy;
354*f1c316a3SStephan Mueller 
355*f1c316a3SStephan Mueller 	if (!kdf)
356*f1c316a3SStephan Mueller 		return __keyctl_dh_compute(params, buffer, buflen, NULL);
357*f1c316a3SStephan Mueller 
358*f1c316a3SStephan Mueller 	if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0)
359*f1c316a3SStephan Mueller 		return -EFAULT;
360*f1c316a3SStephan Mueller 
361*f1c316a3SStephan Mueller 	return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
362*f1c316a3SStephan Mueller }
363