Merge tag 'amd-drm-next-5.18-2022-03-25' of https://gitlab.freedesktop.org/agd5f...
[linux-2.6-microblaze.git] / security / keys / dh.c
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 }