Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/security/keys/dh.c
26378 views
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
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
88
static void kdf_dealloc(struct crypto_shash *hash)
89
{
90
if (hash)
91
crypto_free_shash(hash);
92
}
93
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
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
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
315