xref: /openbmc/linux/security/keys/dh.c (revision 47010c04)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Crypto operations using stored keys
3  *
4  * Copyright (c) 2016, Intel Corporation
5  */
6 
7 #include <linux/slab.h>
8 #include <linux/uaccess.h>
9 #include <linux/scatterlist.h>
10 #include <linux/crypto.h>
11 #include <crypto/hash.h>
12 #include <crypto/kpp.h>
13 #include <crypto/dh.h>
14 #include <crypto/kdf_sp800108.h>
15 #include <keys/user-type.h>
16 #include "internal.h"
17 
18 static ssize_t dh_data_from_key(key_serial_t keyid, const void **data)
19 {
20 	struct key *key;
21 	key_ref_t key_ref;
22 	long status;
23 	ssize_t ret;
24 
25 	key_ref = lookup_user_key(keyid, 0, KEY_NEED_READ);
26 	if (IS_ERR(key_ref)) {
27 		ret = -ENOKEY;
28 		goto error;
29 	}
30 
31 	key = key_ref_to_ptr(key_ref);
32 
33 	ret = -EOPNOTSUPP;
34 	if (key->type == &key_type_user) {
35 		down_read(&key->sem);
36 		status = key_validate(key);
37 		if (status == 0) {
38 			const struct user_key_payload *payload;
39 			uint8_t *duplicate;
40 
41 			payload = user_key_payload_locked(key);
42 
43 			duplicate = kmemdup(payload->data, payload->datalen,
44 					    GFP_KERNEL);
45 			if (duplicate) {
46 				*data = duplicate;
47 				ret = payload->datalen;
48 			} else {
49 				ret = -ENOMEM;
50 			}
51 		}
52 		up_read(&key->sem);
53 	}
54 
55 	key_put(key);
56 error:
57 	return ret;
58 }
59 
60 static void dh_free_data(struct dh *dh)
61 {
62 	kfree_sensitive(dh->key);
63 	kfree_sensitive(dh->p);
64 	kfree_sensitive(dh->g);
65 }
66 
67 struct dh_completion {
68 	struct completion completion;
69 	int err;
70 };
71 
72 static void dh_crypto_done(struct crypto_async_request *req, int err)
73 {
74 	struct dh_completion *compl = req->data;
75 
76 	if (err == -EINPROGRESS)
77 		return;
78 
79 	compl->err = err;
80 	complete(&compl->completion);
81 }
82 
83 static int kdf_alloc(struct crypto_shash **hash, char *hashname)
84 {
85 	struct crypto_shash *tfm;
86 
87 	/* allocate synchronous hash */
88 	tfm = crypto_alloc_shash(hashname, 0, 0);
89 	if (IS_ERR(tfm)) {
90 		pr_info("could not allocate digest TFM handle %s\n", hashname);
91 		return PTR_ERR(tfm);
92 	}
93 
94 	if (crypto_shash_digestsize(tfm) == 0) {
95 		crypto_free_shash(tfm);
96 		return -EINVAL;
97 	}
98 
99 	*hash = tfm;
100 
101 	return 0;
102 }
103 
104 static void kdf_dealloc(struct crypto_shash *hash)
105 {
106 	if (hash)
107 		crypto_free_shash(hash);
108 }
109 
110 static int keyctl_dh_compute_kdf(struct crypto_shash *hash,
111 				 char __user *buffer, size_t buflen,
112 				 uint8_t *kbuf, size_t kbuflen)
113 {
114 	struct kvec kbuf_iov = { .iov_base = kbuf, .iov_len = kbuflen };
115 	uint8_t *outbuf = NULL;
116 	int ret;
117 	size_t outbuf_len = roundup(buflen, crypto_shash_digestsize(hash));
118 
119 	outbuf = kmalloc(outbuf_len, GFP_KERNEL);
120 	if (!outbuf) {
121 		ret = -ENOMEM;
122 		goto err;
123 	}
124 
125 	ret = crypto_kdf108_ctr_generate(hash, &kbuf_iov, 1, outbuf, outbuf_len);
126 	if (ret)
127 		goto err;
128 
129 	ret = buflen;
130 	if (copy_to_user(buffer, outbuf, buflen) != 0)
131 		ret = -EFAULT;
132 
133 err:
134 	kfree_sensitive(outbuf);
135 	return ret;
136 }
137 
138 long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
139 			 char __user *buffer, size_t buflen,
140 			 struct keyctl_kdf_params *kdfcopy)
141 {
142 	long ret;
143 	ssize_t dlen;
144 	int secretlen;
145 	int outlen;
146 	struct keyctl_dh_params pcopy;
147 	struct dh dh_inputs;
148 	struct scatterlist outsg;
149 	struct dh_completion compl;
150 	struct crypto_kpp *tfm;
151 	struct kpp_request *req;
152 	uint8_t *secret;
153 	uint8_t *outbuf;
154 	struct crypto_shash *hash = NULL;
155 
156 	if (!params || (!buffer && buflen)) {
157 		ret = -EINVAL;
158 		goto out1;
159 	}
160 	if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) {
161 		ret = -EFAULT;
162 		goto out1;
163 	}
164 
165 	if (kdfcopy) {
166 		char *hashname;
167 
168 		if (memchr_inv(kdfcopy->__spare, 0, sizeof(kdfcopy->__spare))) {
169 			ret = -EINVAL;
170 			goto out1;
171 		}
172 
173 		if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN ||
174 		    kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) {
175 			ret = -EMSGSIZE;
176 			goto out1;
177 		}
178 
179 		/* get KDF name string */
180 		hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME);
181 		if (IS_ERR(hashname)) {
182 			ret = PTR_ERR(hashname);
183 			goto out1;
184 		}
185 
186 		/* allocate KDF from the kernel crypto API */
187 		ret = kdf_alloc(&hash, hashname);
188 		kfree(hashname);
189 		if (ret)
190 			goto out1;
191 	}
192 
193 	memset(&dh_inputs, 0, sizeof(dh_inputs));
194 
195 	dlen = dh_data_from_key(pcopy.prime, &dh_inputs.p);
196 	if (dlen < 0) {
197 		ret = dlen;
198 		goto out1;
199 	}
200 	dh_inputs.p_size = dlen;
201 
202 	dlen = dh_data_from_key(pcopy.base, &dh_inputs.g);
203 	if (dlen < 0) {
204 		ret = dlen;
205 		goto out2;
206 	}
207 	dh_inputs.g_size = dlen;
208 
209 	dlen = dh_data_from_key(pcopy.private, &dh_inputs.key);
210 	if (dlen < 0) {
211 		ret = dlen;
212 		goto out2;
213 	}
214 	dh_inputs.key_size = dlen;
215 
216 	secretlen = crypto_dh_key_len(&dh_inputs);
217 	secret = kmalloc(secretlen, GFP_KERNEL);
218 	if (!secret) {
219 		ret = -ENOMEM;
220 		goto out2;
221 	}
222 	ret = crypto_dh_encode_key(secret, secretlen, &dh_inputs);
223 	if (ret)
224 		goto out3;
225 
226 	tfm = crypto_alloc_kpp("dh", 0, 0);
227 	if (IS_ERR(tfm)) {
228 		ret = PTR_ERR(tfm);
229 		goto out3;
230 	}
231 
232 	ret = crypto_kpp_set_secret(tfm, secret, secretlen);
233 	if (ret)
234 		goto out4;
235 
236 	outlen = crypto_kpp_maxsize(tfm);
237 
238 	if (!kdfcopy) {
239 		/*
240 		 * When not using a KDF, buflen 0 is used to read the
241 		 * required buffer length
242 		 */
243 		if (buflen == 0) {
244 			ret = outlen;
245 			goto out4;
246 		} else if (outlen > buflen) {
247 			ret = -EOVERFLOW;
248 			goto out4;
249 		}
250 	}
251 
252 	outbuf = kzalloc(kdfcopy ? (outlen + kdfcopy->otherinfolen) : outlen,
253 			 GFP_KERNEL);
254 	if (!outbuf) {
255 		ret = -ENOMEM;
256 		goto out4;
257 	}
258 
259 	sg_init_one(&outsg, outbuf, outlen);
260 
261 	req = kpp_request_alloc(tfm, GFP_KERNEL);
262 	if (!req) {
263 		ret = -ENOMEM;
264 		goto out5;
265 	}
266 
267 	kpp_request_set_input(req, NULL, 0);
268 	kpp_request_set_output(req, &outsg, outlen);
269 	init_completion(&compl.completion);
270 	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
271 				 CRYPTO_TFM_REQ_MAY_SLEEP,
272 				 dh_crypto_done, &compl);
273 
274 	/*
275 	 * For DH, generate_public_key and generate_shared_secret are
276 	 * the same calculation
277 	 */
278 	ret = crypto_kpp_generate_public_key(req);
279 	if (ret == -EINPROGRESS) {
280 		wait_for_completion(&compl.completion);
281 		ret = compl.err;
282 		if (ret)
283 			goto out6;
284 	}
285 
286 	if (kdfcopy) {
287 		/*
288 		 * Concatenate SP800-56A otherinfo past DH shared secret -- the
289 		 * input to the KDF is (DH shared secret || otherinfo)
290 		 */
291 		if (copy_from_user(outbuf + req->dst_len, kdfcopy->otherinfo,
292 				   kdfcopy->otherinfolen) != 0) {
293 			ret = -EFAULT;
294 			goto out6;
295 		}
296 
297 		ret = keyctl_dh_compute_kdf(hash, buffer, buflen, outbuf,
298 					    req->dst_len + kdfcopy->otherinfolen);
299 	} else if (copy_to_user(buffer, outbuf, req->dst_len) == 0) {
300 		ret = req->dst_len;
301 	} else {
302 		ret = -EFAULT;
303 	}
304 
305 out6:
306 	kpp_request_free(req);
307 out5:
308 	kfree_sensitive(outbuf);
309 out4:
310 	crypto_free_kpp(tfm);
311 out3:
312 	kfree_sensitive(secret);
313 out2:
314 	dh_free_data(&dh_inputs);
315 out1:
316 	kdf_dealloc(hash);
317 	return ret;
318 }
319 
320 long keyctl_dh_compute(struct keyctl_dh_params __user *params,
321 		       char __user *buffer, size_t buflen,
322 		       struct keyctl_kdf_params __user *kdf)
323 {
324 	struct keyctl_kdf_params kdfcopy;
325 
326 	if (!kdf)
327 		return __keyctl_dh_compute(params, buffer, buflen, NULL);
328 
329 	if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0)
330 		return -EFAULT;
331 
332 	return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
333 }
334