xref: /openbmc/linux/security/keys/dh.c (revision 5419f2b2)
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 
dh_data_from_key(key_serial_t keyid,const void ** data)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 
dh_free_data(struct dh * dh)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 
kdf_alloc(struct crypto_shash ** hash,char * hashname)67 static int kdf_alloc(struct crypto_shash **hash, char *hashname)
68 {
69 	struct crypto_shash *tfm;
70 
71 	/* allocate synchronous hash */
72 	tfm = crypto_alloc_shash(hashname, 0, 0);
73 	if (IS_ERR(tfm)) {
74 		pr_info("could not allocate digest TFM handle %s\n", hashname);
75 		return PTR_ERR(tfm);
76 	}
77 
78 	if (crypto_shash_digestsize(tfm) == 0) {
79 		crypto_free_shash(tfm);
80 		return -EINVAL;
81 	}
82 
83 	*hash = tfm;
84 
85 	return 0;
86 }
87 
kdf_dealloc(struct crypto_shash * hash)88 static void kdf_dealloc(struct crypto_shash *hash)
89 {
90 	if (hash)
91 		crypto_free_shash(hash);
92 }
93 
keyctl_dh_compute_kdf(struct crypto_shash * hash,char __user * buffer,size_t buflen,uint8_t * kbuf,size_t kbuflen)94 static int keyctl_dh_compute_kdf(struct crypto_shash *hash,
95 				 char __user *buffer, size_t buflen,
96 				 uint8_t *kbuf, size_t kbuflen)
97 {
98 	struct kvec kbuf_iov = { .iov_base = kbuf, .iov_len = kbuflen };
99 	uint8_t *outbuf = NULL;
100 	int ret;
101 	size_t outbuf_len = roundup(buflen, crypto_shash_digestsize(hash));
102 
103 	outbuf = kmalloc(outbuf_len, GFP_KERNEL);
104 	if (!outbuf) {
105 		ret = -ENOMEM;
106 		goto err;
107 	}
108 
109 	ret = crypto_kdf108_ctr_generate(hash, &kbuf_iov, 1, outbuf, outbuf_len);
110 	if (ret)
111 		goto err;
112 
113 	ret = buflen;
114 	if (copy_to_user(buffer, outbuf, buflen) != 0)
115 		ret = -EFAULT;
116 
117 err:
118 	kfree_sensitive(outbuf);
119 	return ret;
120 }
121 
__keyctl_dh_compute(struct keyctl_dh_params __user * params,char __user * buffer,size_t buflen,struct keyctl_kdf_params * kdfcopy)122 long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
123 			 char __user *buffer, size_t buflen,
124 			 struct keyctl_kdf_params *kdfcopy)
125 {
126 	long ret;
127 	ssize_t dlen;
128 	int secretlen;
129 	int outlen;
130 	struct keyctl_dh_params pcopy;
131 	struct dh dh_inputs;
132 	struct scatterlist outsg;
133 	DECLARE_CRYPTO_WAIT(compl);
134 	struct crypto_kpp *tfm;
135 	struct kpp_request *req;
136 	uint8_t *secret;
137 	uint8_t *outbuf;
138 	struct crypto_shash *hash = NULL;
139 
140 	if (!params || (!buffer && buflen)) {
141 		ret = -EINVAL;
142 		goto out1;
143 	}
144 	if (copy_from_user(&pcopy, params, sizeof(pcopy)) != 0) {
145 		ret = -EFAULT;
146 		goto out1;
147 	}
148 
149 	if (kdfcopy) {
150 		char *hashname;
151 
152 		if (memchr_inv(kdfcopy->__spare, 0, sizeof(kdfcopy->__spare))) {
153 			ret = -EINVAL;
154 			goto out1;
155 		}
156 
157 		if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN ||
158 		    kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) {
159 			ret = -EMSGSIZE;
160 			goto out1;
161 		}
162 
163 		/* get KDF name string */
164 		hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME);
165 		if (IS_ERR(hashname)) {
166 			ret = PTR_ERR(hashname);
167 			goto out1;
168 		}
169 
170 		/* allocate KDF from the kernel crypto API */
171 		ret = kdf_alloc(&hash, hashname);
172 		kfree(hashname);
173 		if (ret)
174 			goto out1;
175 	}
176 
177 	memset(&dh_inputs, 0, sizeof(dh_inputs));
178 
179 	dlen = dh_data_from_key(pcopy.prime, &dh_inputs.p);
180 	if (dlen < 0) {
181 		ret = dlen;
182 		goto out1;
183 	}
184 	dh_inputs.p_size = dlen;
185 
186 	dlen = dh_data_from_key(pcopy.base, &dh_inputs.g);
187 	if (dlen < 0) {
188 		ret = dlen;
189 		goto out2;
190 	}
191 	dh_inputs.g_size = dlen;
192 
193 	dlen = dh_data_from_key(pcopy.private, &dh_inputs.key);
194 	if (dlen < 0) {
195 		ret = dlen;
196 		goto out2;
197 	}
198 	dh_inputs.key_size = dlen;
199 
200 	secretlen = crypto_dh_key_len(&dh_inputs);
201 	secret = kmalloc(secretlen, GFP_KERNEL);
202 	if (!secret) {
203 		ret = -ENOMEM;
204 		goto out2;
205 	}
206 	ret = crypto_dh_encode_key(secret, secretlen, &dh_inputs);
207 	if (ret)
208 		goto out3;
209 
210 	tfm = crypto_alloc_kpp("dh", 0, 0);
211 	if (IS_ERR(tfm)) {
212 		ret = PTR_ERR(tfm);
213 		goto out3;
214 	}
215 
216 	ret = crypto_kpp_set_secret(tfm, secret, secretlen);
217 	if (ret)
218 		goto out4;
219 
220 	outlen = crypto_kpp_maxsize(tfm);
221 
222 	if (!kdfcopy) {
223 		/*
224 		 * When not using a KDF, buflen 0 is used to read the
225 		 * required buffer length
226 		 */
227 		if (buflen == 0) {
228 			ret = outlen;
229 			goto out4;
230 		} else if (outlen > buflen) {
231 			ret = -EOVERFLOW;
232 			goto out4;
233 		}
234 	}
235 
236 	outbuf = kzalloc(kdfcopy ? (outlen + kdfcopy->otherinfolen) : outlen,
237 			 GFP_KERNEL);
238 	if (!outbuf) {
239 		ret = -ENOMEM;
240 		goto out4;
241 	}
242 
243 	sg_init_one(&outsg, outbuf, outlen);
244 
245 	req = kpp_request_alloc(tfm, GFP_KERNEL);
246 	if (!req) {
247 		ret = -ENOMEM;
248 		goto out5;
249 	}
250 
251 	kpp_request_set_input(req, NULL, 0);
252 	kpp_request_set_output(req, &outsg, outlen);
253 	kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
254 				 CRYPTO_TFM_REQ_MAY_SLEEP,
255 				 crypto_req_done, &compl);
256 
257 	/*
258 	 * For DH, generate_public_key and generate_shared_secret are
259 	 * the same calculation
260 	 */
261 	ret = crypto_kpp_generate_public_key(req);
262 	ret = crypto_wait_req(ret, &compl);
263 	if (ret)
264 		goto out6;
265 
266 	if (kdfcopy) {
267 		/*
268 		 * Concatenate SP800-56A otherinfo past DH shared secret -- the
269 		 * input to the KDF is (DH shared secret || otherinfo)
270 		 */
271 		if (copy_from_user(outbuf + req->dst_len, kdfcopy->otherinfo,
272 				   kdfcopy->otherinfolen) != 0) {
273 			ret = -EFAULT;
274 			goto out6;
275 		}
276 
277 		ret = keyctl_dh_compute_kdf(hash, buffer, buflen, outbuf,
278 					    req->dst_len + kdfcopy->otherinfolen);
279 	} else if (copy_to_user(buffer, outbuf, req->dst_len) == 0) {
280 		ret = req->dst_len;
281 	} else {
282 		ret = -EFAULT;
283 	}
284 
285 out6:
286 	kpp_request_free(req);
287 out5:
288 	kfree_sensitive(outbuf);
289 out4:
290 	crypto_free_kpp(tfm);
291 out3:
292 	kfree_sensitive(secret);
293 out2:
294 	dh_free_data(&dh_inputs);
295 out1:
296 	kdf_dealloc(hash);
297 	return ret;
298 }
299 
keyctl_dh_compute(struct keyctl_dh_params __user * params,char __user * buffer,size_t buflen,struct keyctl_kdf_params __user * kdf)300 long keyctl_dh_compute(struct keyctl_dh_params __user *params,
301 		       char __user *buffer, size_t buflen,
302 		       struct keyctl_kdf_params __user *kdf)
303 {
304 	struct keyctl_kdf_params kdfcopy;
305 
306 	if (!kdf)
307 		return __keyctl_dh_compute(params, buffer, buflen, NULL);
308 
309 	if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0)
310 		return -EFAULT;
311 
312 	return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
313 }
314