Linux Audio

Check our new training course

Loading...
v5.9
  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
 17static void keyctl_pkey_params_free(struct kernel_pkey_params *params)
 18{
 19	kfree(params->info);
 20	key_put(params->key);
 21}
 22
 23enum {
 24	Opt_err,
 25	Opt_enc,		/* "enc=<encoding>" eg. "enc=oaep" */
 26	Opt_hash,		/* "hash=<digest-name>" eg. "hash=sha1" */
 27};
 28
 29static 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 */
 38static 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, 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 */
 78static 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(p))
 91		return PTR_ERR(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, 0, KEY_NEED_SEARCH);
 99	if (IS_ERR(key_ref))
100		return PTR_ERR(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 */
113static 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(&uparams, _params, sizeof(uparams)) != 0)
126		return -EFAULT;
127
128	ret = keyctl_pkey_params_get(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	case KEYCTL_PKEY_DECRYPT:
139		if (uparams.in_len  > info.max_enc_size ||
140		    uparams.out_len > info.max_dec_size)
141			return -EINVAL;
142		break;
143	case KEYCTL_PKEY_SIGN:
 
 
 
 
144	case KEYCTL_PKEY_VERIFY:
145		if (uparams.in_len  > info.max_sig_size ||
146		    uparams.out_len > info.max_data_size)
147			return -EINVAL;
148		break;
149	default:
150		BUG();
151	}
152
153	params->in_len  = uparams.in_len;
154	params->out_len = uparams.out_len;
155	return 0;
156}
157
158/*
159 * Query information about an asymmetric key.
160 */
161long keyctl_pkey_query(key_serial_t id,
162		       const char __user *_info,
163		       struct keyctl_pkey_query __user *_res)
164{
165	struct kernel_pkey_params params;
166	struct kernel_pkey_query res;
167	long ret;
168
169	memset(&params, 0, sizeof(params));
170
171	ret = keyctl_pkey_params_get(id, _info, &params);
172	if (ret < 0)
173		goto error;
174
175	ret = params.key->type->asym_query(&params, &res);
176	if (ret < 0)
177		goto error;
178
179	ret = -EFAULT;
180	if (copy_to_user(_res, &res, sizeof(res)) == 0 &&
181	    clear_user(_res->__spare, sizeof(_res->__spare)) == 0)
182		ret = 0;
183
184error:
185	keyctl_pkey_params_free(&params);
186	return ret;
187}
188
189/*
190 * Encrypt/decrypt/sign
191 *
192 * Encrypt data, decrypt data or sign data using a public key.
193 *
194 * _info is a string of supplementary information in key=val format.  For
195 * instance, it might contain:
196 *
197 *	"enc=pkcs1 hash=sha256"
198 *
199 * where enc= specifies the encoding and hash= selects the OID to go in that
200 * particular encoding if required.  If enc= isn't supplied, it's assumed that
201 * the caller is supplying raw values.
202 *
203 * If successful, the amount of data written into the output buffer is
204 * returned.
205 */
206long keyctl_pkey_e_d_s(int op,
207		       const struct keyctl_pkey_params __user *_params,
208		       const char __user *_info,
209		       const void __user *_in,
210		       void __user *_out)
211{
212	struct kernel_pkey_params params;
213	void *in, *out;
214	long ret;
215
216	ret = keyctl_pkey_params_get_2(_params, _info, op, &params);
217	if (ret < 0)
218		goto error_params;
219
220	ret = -EOPNOTSUPP;
221	if (!params.key->type->asym_eds_op)
222		goto error_params;
223
224	switch (op) {
225	case KEYCTL_PKEY_ENCRYPT:
226		params.op = kernel_pkey_encrypt;
227		break;
228	case KEYCTL_PKEY_DECRYPT:
229		params.op = kernel_pkey_decrypt;
230		break;
231	case KEYCTL_PKEY_SIGN:
232		params.op = kernel_pkey_sign;
233		break;
234	default:
235		BUG();
236	}
237
238	in = memdup_user(_in, params.in_len);
239	if (IS_ERR(in)) {
240		ret = PTR_ERR(in);
241		goto error_params;
242	}
243
244	ret = -ENOMEM;
245	out = kmalloc(params.out_len, GFP_KERNEL);
246	if (!out)
247		goto error_in;
248
249	ret = params.key->type->asym_eds_op(&params, in, out);
250	if (ret < 0)
251		goto error_out;
252
253	if (copy_to_user(_out, out, ret) != 0)
254		ret = -EFAULT;
255
256error_out:
257	kfree(out);
258error_in:
259	kfree(in);
260error_params:
261	keyctl_pkey_params_free(&params);
262	return ret;
263}
264
265/*
266 * Verify a signature.
267 *
268 * Verify a public key signature using the given key, or if not given, search
269 * for a matching key.
270 *
271 * _info is a string of supplementary information in key=val format.  For
272 * instance, it might contain:
273 *
274 *	"enc=pkcs1 hash=sha256"
275 *
276 * where enc= specifies the signature blob encoding and hash= selects the OID
277 * to go in that particular encoding.  If enc= isn't supplied, it's assumed
278 * that the caller is supplying raw values.
279 *
280 * If successful, 0 is returned.
281 */
282long keyctl_pkey_verify(const struct keyctl_pkey_params __user *_params,
283			const char __user *_info,
284			const void __user *_in,
285			const void __user *_in2)
286{
287	struct kernel_pkey_params params;
288	void *in, *in2;
289	long ret;
290
291	ret = keyctl_pkey_params_get_2(_params, _info, KEYCTL_PKEY_VERIFY,
292				       &params);
293	if (ret < 0)
294		goto error_params;
295
296	ret = -EOPNOTSUPP;
297	if (!params.key->type->asym_verify_signature)
298		goto error_params;
299
300	in = memdup_user(_in, params.in_len);
301	if (IS_ERR(in)) {
302		ret = PTR_ERR(in);
303		goto error_params;
304	}
305
306	in2 = memdup_user(_in2, params.in2_len);
307	if (IS_ERR(in2)) {
308		ret = PTR_ERR(in2);
309		goto error_in;
310	}
311
312	params.op = kernel_pkey_verify;
313	ret = params.key->type->asym_verify_signature(&params, in, in2);
314
315	kfree(in2);
316error_in:
317	kfree(in);
318error_params:
319	keyctl_pkey_params_free(&params);
320	return ret;
321}
v6.2
  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
 17static void keyctl_pkey_params_free(struct kernel_pkey_params *params)
 18{
 19	kfree(params->info);
 20	key_put(params->key);
 21}
 22
 23enum {
 24	Opt_err,
 25	Opt_enc,		/* "enc=<encoding>" eg. "enc=oaep" */
 26	Opt_hash,		/* "hash=<digest-name>" eg. "hash=sha1" */
 27};
 28
 29static 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 */
 38static 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, 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 */
 78static 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(p))
 91		return PTR_ERR(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, 0, KEY_NEED_SEARCH);
 99	if (IS_ERR(key_ref))
100		return PTR_ERR(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 */
113static 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(&uparams, _params, sizeof(uparams)) != 0)
126		return -EFAULT;
127
128	ret = keyctl_pkey_params_get(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 */
169long 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);
178	if (ret < 0)
179		goto error;
180
181	ret = params.key->type->asym_query(&params, &res);
182	if (ret < 0)
183		goto error;
184
185	ret = -EFAULT;
186	if (copy_to_user(_res, &res, sizeof(res)) == 0 &&
187	    clear_user(_res->__spare, sizeof(_res->__spare)) == 0)
188		ret = 0;
189
190error:
191	keyctl_pkey_params_free(&params);
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 */
212long 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);
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(in)) {
246		ret = PTR_ERR(in);
247		goto error_params;
248	}
249
250	ret = -ENOMEM;
251	out = kmalloc(params.out_len, GFP_KERNEL);
252	if (!out)
253		goto error_in;
254
255	ret = params.key->type->asym_eds_op(&params, in, out);
256	if (ret < 0)
257		goto error_out;
258
259	if (copy_to_user(_out, out, ret) != 0)
260		ret = -EFAULT;
261
262error_out:
263	kfree(out);
264error_in:
265	kfree(in);
266error_params:
267	keyctl_pkey_params_free(&params);
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 */
288long 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);
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(in)) {
308		ret = PTR_ERR(in);
309		goto error_params;
310	}
311
312	in2 = memdup_user(_in2, params.in2_len);
313	if (IS_ERR(in2)) {
314		ret = PTR_ERR(in2);
315		goto error_in;
316	}
317
318	params.op = kernel_pkey_verify;
319	ret = params.key->type->asym_verify_signature(&params, in, in2);
320
321	kfree(in2);
322error_in:
323	kfree(in);
324error_params:
325	keyctl_pkey_params_free(&params);
326	return ret;
327}