1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* Public-key operation keyctls |
3 | * |
4 | * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. |
5 | * Written by David Howells (dhowells@redhat.com) |
6 | */ |
7 | |
8 | #include <linux/slab.h> |
9 | #include <linux/err.h> |
10 | #include <linux/key.h> |
11 | #include <linux/keyctl.h> |
12 | #include <linux/parser.h> |
13 | #include <linux/uaccess.h> |
14 | #include <keys/user-type.h> |
15 | #include "internal.h" |
16 | |
17 | static void keyctl_pkey_params_free(struct kernel_pkey_params *params) |
18 | { |
19 | kfree(objp: params->info); |
20 | key_put(key: params->key); |
21 | } |
22 | |
23 | enum { |
24 | Opt_err, |
25 | Opt_enc, /* "enc=<encoding>" eg. "enc=oaep" */ |
26 | Opt_hash, /* "hash=<digest-name>" eg. "hash=sha1" */ |
27 | }; |
28 | |
29 | static const match_table_t param_keys = { |
30 | { Opt_enc, "enc=%s" }, |
31 | { Opt_hash, "hash=%s" }, |
32 | { Opt_err, NULL } |
33 | }; |
34 | |
35 | /* |
36 | * Parse the information string which consists of key=val pairs. |
37 | */ |
38 | static int keyctl_pkey_params_parse(struct kernel_pkey_params *params) |
39 | { |
40 | unsigned long token_mask = 0; |
41 | substring_t args[MAX_OPT_ARGS]; |
42 | char *c = params->info, *p, *q; |
43 | int token; |
44 | |
45 | while ((p = strsep(&c, " \t" ))) { |
46 | if (*p == '\0' || *p == ' ' || *p == '\t') |
47 | continue; |
48 | token = match_token(p, table: param_keys, args); |
49 | if (token == Opt_err) |
50 | return -EINVAL; |
51 | if (__test_and_set_bit(token, &token_mask)) |
52 | return -EINVAL; |
53 | q = args[0].from; |
54 | if (!q[0]) |
55 | return -EINVAL; |
56 | |
57 | switch (token) { |
58 | case Opt_enc: |
59 | params->encoding = q; |
60 | break; |
61 | |
62 | case Opt_hash: |
63 | params->hash_algo = q; |
64 | break; |
65 | |
66 | default: |
67 | return -EINVAL; |
68 | } |
69 | } |
70 | |
71 | return 0; |
72 | } |
73 | |
74 | /* |
75 | * Interpret parameters. Callers must always call the free function |
76 | * on params, even if an error is returned. |
77 | */ |
78 | static int keyctl_pkey_params_get(key_serial_t id, |
79 | const char __user *_info, |
80 | struct kernel_pkey_params *params) |
81 | { |
82 | key_ref_t key_ref; |
83 | void *p; |
84 | int ret; |
85 | |
86 | memset(params, 0, sizeof(*params)); |
87 | params->encoding = "raw" ; |
88 | |
89 | p = strndup_user(_info, PAGE_SIZE); |
90 | if (IS_ERR(ptr: p)) |
91 | return PTR_ERR(ptr: p); |
92 | params->info = p; |
93 | |
94 | ret = keyctl_pkey_params_parse(params); |
95 | if (ret < 0) |
96 | return ret; |
97 | |
98 | key_ref = lookup_user_key(id, flags: 0, need_perm: KEY_NEED_SEARCH); |
99 | if (IS_ERR(ptr: key_ref)) |
100 | return PTR_ERR(ptr: key_ref); |
101 | params->key = key_ref_to_ptr(key_ref); |
102 | |
103 | if (!params->key->type->asym_query) |
104 | return -EOPNOTSUPP; |
105 | |
106 | return 0; |
107 | } |
108 | |
109 | /* |
110 | * Get parameters from userspace. Callers must always call the free function |
111 | * on params, even if an error is returned. |
112 | */ |
113 | static int keyctl_pkey_params_get_2(const struct keyctl_pkey_params __user *_params, |
114 | const char __user *_info, |
115 | int op, |
116 | struct kernel_pkey_params *params) |
117 | { |
118 | struct keyctl_pkey_params uparams; |
119 | struct kernel_pkey_query info; |
120 | int ret; |
121 | |
122 | memset(params, 0, sizeof(*params)); |
123 | params->encoding = "raw" ; |
124 | |
125 | if (copy_from_user(to: &uparams, from: _params, n: sizeof(uparams)) != 0) |
126 | return -EFAULT; |
127 | |
128 | ret = keyctl_pkey_params_get(id: uparams.key_id, _info, params); |
129 | if (ret < 0) |
130 | return ret; |
131 | |
132 | ret = params->key->type->asym_query(params, &info); |
133 | if (ret < 0) |
134 | return ret; |
135 | |
136 | switch (op) { |
137 | case KEYCTL_PKEY_ENCRYPT: |
138 | if (uparams.in_len > info.max_dec_size || |
139 | uparams.out_len > info.max_enc_size) |
140 | return -EINVAL; |
141 | break; |
142 | case KEYCTL_PKEY_DECRYPT: |
143 | if (uparams.in_len > info.max_enc_size || |
144 | uparams.out_len > info.max_dec_size) |
145 | return -EINVAL; |
146 | break; |
147 | case KEYCTL_PKEY_SIGN: |
148 | if (uparams.in_len > info.max_data_size || |
149 | uparams.out_len > info.max_sig_size) |
150 | return -EINVAL; |
151 | break; |
152 | case KEYCTL_PKEY_VERIFY: |
153 | if (uparams.in_len > info.max_data_size || |
154 | uparams.in2_len > info.max_sig_size) |
155 | return -EINVAL; |
156 | break; |
157 | default: |
158 | BUG(); |
159 | } |
160 | |
161 | params->in_len = uparams.in_len; |
162 | params->out_len = uparams.out_len; /* Note: same as in2_len */ |
163 | return 0; |
164 | } |
165 | |
166 | /* |
167 | * Query information about an asymmetric key. |
168 | */ |
169 | long keyctl_pkey_query(key_serial_t id, |
170 | const char __user *_info, |
171 | struct keyctl_pkey_query __user *_res) |
172 | { |
173 | struct kernel_pkey_params params; |
174 | struct kernel_pkey_query res; |
175 | long ret; |
176 | |
177 | ret = keyctl_pkey_params_get(id, _info, params: ¶ms); |
178 | if (ret < 0) |
179 | goto error; |
180 | |
181 | ret = params.key->type->asym_query(¶ms, &res); |
182 | if (ret < 0) |
183 | goto error; |
184 | |
185 | ret = -EFAULT; |
186 | if (copy_to_user(to: _res, from: &res, n: sizeof(res)) == 0 && |
187 | clear_user(to: _res->__spare, n: sizeof(_res->__spare)) == 0) |
188 | ret = 0; |
189 | |
190 | error: |
191 | keyctl_pkey_params_free(params: ¶ms); |
192 | return ret; |
193 | } |
194 | |
195 | /* |
196 | * Encrypt/decrypt/sign |
197 | * |
198 | * Encrypt data, decrypt data or sign data using a public key. |
199 | * |
200 | * _info is a string of supplementary information in key=val format. For |
201 | * instance, it might contain: |
202 | * |
203 | * "enc=pkcs1 hash=sha256" |
204 | * |
205 | * where enc= specifies the encoding and hash= selects the OID to go in that |
206 | * particular encoding if required. If enc= isn't supplied, it's assumed that |
207 | * the caller is supplying raw values. |
208 | * |
209 | * If successful, the amount of data written into the output buffer is |
210 | * returned. |
211 | */ |
212 | long keyctl_pkey_e_d_s(int op, |
213 | const struct keyctl_pkey_params __user *_params, |
214 | const char __user *_info, |
215 | const void __user *_in, |
216 | void __user *_out) |
217 | { |
218 | struct kernel_pkey_params params; |
219 | void *in, *out; |
220 | long ret; |
221 | |
222 | ret = keyctl_pkey_params_get_2(_params, _info, op, params: ¶ms); |
223 | if (ret < 0) |
224 | goto error_params; |
225 | |
226 | ret = -EOPNOTSUPP; |
227 | if (!params.key->type->asym_eds_op) |
228 | goto error_params; |
229 | |
230 | switch (op) { |
231 | case KEYCTL_PKEY_ENCRYPT: |
232 | params.op = kernel_pkey_encrypt; |
233 | break; |
234 | case KEYCTL_PKEY_DECRYPT: |
235 | params.op = kernel_pkey_decrypt; |
236 | break; |
237 | case KEYCTL_PKEY_SIGN: |
238 | params.op = kernel_pkey_sign; |
239 | break; |
240 | default: |
241 | BUG(); |
242 | } |
243 | |
244 | in = memdup_user(_in, params.in_len); |
245 | if (IS_ERR(ptr: in)) { |
246 | ret = PTR_ERR(ptr: in); |
247 | goto error_params; |
248 | } |
249 | |
250 | ret = -ENOMEM; |
251 | out = kmalloc(size: params.out_len, GFP_KERNEL); |
252 | if (!out) |
253 | goto error_in; |
254 | |
255 | ret = params.key->type->asym_eds_op(¶ms, in, out); |
256 | if (ret < 0) |
257 | goto error_out; |
258 | |
259 | if (copy_to_user(to: _out, from: out, n: ret) != 0) |
260 | ret = -EFAULT; |
261 | |
262 | error_out: |
263 | kfree(objp: out); |
264 | error_in: |
265 | kfree(objp: in); |
266 | error_params: |
267 | keyctl_pkey_params_free(params: ¶ms); |
268 | return ret; |
269 | } |
270 | |
271 | /* |
272 | * Verify a signature. |
273 | * |
274 | * Verify a public key signature using the given key, or if not given, search |
275 | * for a matching key. |
276 | * |
277 | * _info is a string of supplementary information in key=val format. For |
278 | * instance, it might contain: |
279 | * |
280 | * "enc=pkcs1 hash=sha256" |
281 | * |
282 | * where enc= specifies the signature blob encoding and hash= selects the OID |
283 | * to go in that particular encoding. If enc= isn't supplied, it's assumed |
284 | * that the caller is supplying raw values. |
285 | * |
286 | * If successful, 0 is returned. |
287 | */ |
288 | long keyctl_pkey_verify(const struct keyctl_pkey_params __user *_params, |
289 | const char __user *_info, |
290 | const void __user *_in, |
291 | const void __user *_in2) |
292 | { |
293 | struct kernel_pkey_params params; |
294 | void *in, *in2; |
295 | long ret; |
296 | |
297 | ret = keyctl_pkey_params_get_2(_params, _info, KEYCTL_PKEY_VERIFY, |
298 | params: ¶ms); |
299 | if (ret < 0) |
300 | goto error_params; |
301 | |
302 | ret = -EOPNOTSUPP; |
303 | if (!params.key->type->asym_verify_signature) |
304 | goto error_params; |
305 | |
306 | in = memdup_user(_in, params.in_len); |
307 | if (IS_ERR(ptr: in)) { |
308 | ret = PTR_ERR(ptr: in); |
309 | goto error_params; |
310 | } |
311 | |
312 | in2 = memdup_user(_in2, params.in2_len); |
313 | if (IS_ERR(ptr: in2)) { |
314 | ret = PTR_ERR(ptr: in2); |
315 | goto error_in; |
316 | } |
317 | |
318 | params.op = kernel_pkey_verify; |
319 | ret = params.key->type->asym_verify_signature(¶ms, in, in2); |
320 | |
321 | kfree(objp: in2); |
322 | error_in: |
323 | kfree(objp: in); |
324 | error_params: |
325 | keyctl_pkey_params_free(params: ¶ms); |
326 | return ret; |
327 | } |
328 | |