Blame view

crypto/asymmetric_keys/asymmetric_type.c 16 KB
b4d0d230c   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
964f3b3bf   David Howells   KEYS: Implement a...
2
3
  /* Asymmetric public-key cryptography key type
   *
0efaaa865   Mauro Carvalho Chehab   docs: crypto: con...
4
   * See Documentation/crypto/asymmetric-keys.rst
964f3b3bf   David Howells   KEYS: Implement a...
5
6
7
   *
   * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells (dhowells@redhat.com)
964f3b3bf   David Howells   KEYS: Implement a...
8
9
   */
  #include <keys/asymmetric-subtype.h>
46c6f1776   David Howells   KEYS: Asymmetric ...
10
  #include <keys/asymmetric-parser.h>
99db44350   David Howells   PKCS#7: Appropria...
11
  #include <crypto/public_key.h>
964f3b3bf   David Howells   KEYS: Implement a...
12
13
14
  #include <linux/seq_file.h>
  #include <linux/module.h>
  #include <linux/slab.h>
7901c1a8e   David Howells   KEYS: Implement b...
15
  #include <linux/ctype.h>
97d3aa0f3   Mat Martineau   KEYS: Add a looku...
16
  #include <keys/system_keyring.h>
5a3077183   David Howells   KEYS: Provide mis...
17
  #include <keys/user-type.h>
964f3b3bf   David Howells   KEYS: Implement a...
18
19
20
  #include "asymmetric_keys.h"
  
  MODULE_LICENSE("GPL");
99db44350   David Howells   PKCS#7: Appropria...
21
22
23
24
25
26
27
28
29
  const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = {
  	[VERIFYING_MODULE_SIGNATURE]		= "mod sig",
  	[VERIFYING_FIRMWARE_SIGNATURE]		= "firmware sig",
  	[VERIFYING_KEXEC_PE_SIGNATURE]		= "kexec PE sig",
  	[VERIFYING_KEY_SIGNATURE]		= "key sig",
  	[VERIFYING_KEY_SELF_SIGNATURE]		= "key self sig",
  	[VERIFYING_UNSPECIFIED_SIGNATURE]	= "unspec sig",
  };
  EXPORT_SYMBOL_GPL(key_being_used_for);
46c6f1776   David Howells   KEYS: Asymmetric ...
30
31
  static LIST_HEAD(asymmetric_key_parsers);
  static DECLARE_RWSEM(asymmetric_key_parsers_sem);
7901c1a8e   David Howells   KEYS: Implement b...
32
  /**
9eb029893   David Howells   KEYS: Generalise ...
33
   * find_asymmetric_key - Find a key by ID.
983023f28   David Howells   KEYS: Move x509_r...
34
   * @keyring: The keys to search.
9eb029893   David Howells   KEYS: Generalise ...
35
36
   * @id_0: The first ID to look for or NULL.
   * @id_1: The second ID to look for or NULL.
983023f28   David Howells   KEYS: Move x509_r...
37
38
39
   * @partial: Use partial match if true, exact if false.
   *
   * Find a key in the given keyring by identifier.  The preferred identifier is
9eb029893   David Howells   KEYS: Generalise ...
40
41
   * the id_0 and the fallback identifier is the id_1.  If both are given, the
   * lookup is by the former, but the latter must also match.
983023f28   David Howells   KEYS: Move x509_r...
42
   */
9eb029893   David Howells   KEYS: Generalise ...
43
44
45
46
  struct key *find_asymmetric_key(struct key *keyring,
  				const struct asymmetric_key_id *id_0,
  				const struct asymmetric_key_id *id_1,
  				bool partial)
983023f28   David Howells   KEYS: Move x509_r...
47
48
49
50
51
52
  {
  	struct key *key;
  	key_ref_t ref;
  	const char *lookup;
  	char *req, *p;
  	int len;
b3811d36a   Chun-Yi Lee   KEYS: checking th...
53
  	BUG_ON(!id_0 && !id_1);
9eb029893   David Howells   KEYS: Generalise ...
54
55
56
  	if (id_0) {
  		lookup = id_0->data;
  		len = id_0->len;
983023f28   David Howells   KEYS: Move x509_r...
57
  	} else {
9eb029893   David Howells   KEYS: Generalise ...
58
59
  		lookup = id_1->data;
  		len = id_1->len;
983023f28   David Howells   KEYS: Move x509_r...
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  	}
  
  	/* Construct an identifier "id:<keyid>". */
  	p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
  	if (!req)
  		return ERR_PTR(-ENOMEM);
  
  	if (partial) {
  		*p++ = 'i';
  		*p++ = 'd';
  	} else {
  		*p++ = 'e';
  		*p++ = 'x';
  	}
  	*p++ = ':';
  	p = bin2hex(p, lookup, len);
  	*p = 0;
  
  	pr_debug("Look up: \"%s\"
  ", req);
  
  	ref = keyring_search(make_key_ref(keyring, 1),
dcf49dbc8   David Howells   keys: Add a 'recu...
82
  			     &key_type_asymmetric, req, true);
983023f28   David Howells   KEYS: Move x509_r...
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  	if (IS_ERR(ref))
  		pr_debug("Request for key '%s' err %ld
  ", req, PTR_ERR(ref));
  	kfree(req);
  
  	if (IS_ERR(ref)) {
  		switch (PTR_ERR(ref)) {
  			/* Hide some search errors */
  		case -EACCES:
  		case -ENOTDIR:
  		case -EAGAIN:
  			return ERR_PTR(-ENOKEY);
  		default:
  			return ERR_CAST(ref);
  		}
  	}
  
  	key = key_ref_to_ptr(ref);
9eb029893   David Howells   KEYS: Generalise ...
101
  	if (id_0 && id_1) {
983023f28   David Howells   KEYS: Move x509_r...
102
  		const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
9eb029893   David Howells   KEYS: Generalise ...
103

6a6d2a77a   Chun-Yi Lee   KEYS: Fix the wro...
104
  		if (!kids->id[1]) {
9eb029893   David Howells   KEYS: Generalise ...
105
106
  			pr_debug("First ID matches, but second is missing
  ");
983023f28   David Howells   KEYS: Move x509_r...
107
108
  			goto reject;
  		}
9eb029893   David Howells   KEYS: Generalise ...
109
110
111
  		if (!asymmetric_key_id_same(id_1, kids->id[1])) {
  			pr_debug("First ID matches, but second does not
  ");
983023f28   David Howells   KEYS: Move x509_r...
112
113
114
115
116
117
118
119
120
121
122
123
  			goto reject;
  		}
  	}
  
  	pr_devel("<==%s() = 0 [%x]
  ", __func__, key_serial(key));
  	return key;
  
  reject:
  	key_put(key);
  	return ERR_PTR(-EKEYREJECTED);
  }
9eb029893   David Howells   KEYS: Generalise ...
124
  EXPORT_SYMBOL_GPL(find_asymmetric_key);
983023f28   David Howells   KEYS: Move x509_r...
125
126
  
  /**
7901c1a8e   David Howells   KEYS: Implement b...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
   * asymmetric_key_generate_id: Construct an asymmetric key ID
   * @val_1: First binary blob
   * @len_1: Length of first binary blob
   * @val_2: Second binary blob
   * @len_2: Length of second binary blob
   *
   * Construct an asymmetric key ID from a pair of binary blobs.
   */
  struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
  						     size_t len_1,
  						     const void *val_2,
  						     size_t len_2)
  {
  	struct asymmetric_key_id *kid;
  
  	kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2,
  		      GFP_KERNEL);
  	if (!kid)
  		return ERR_PTR(-ENOMEM);
  	kid->len = len_1 + len_2;
  	memcpy(kid->data, val_1, len_1);
  	memcpy(kid->data + len_1, val_2, len_2);
  	return kid;
  }
  EXPORT_SYMBOL_GPL(asymmetric_key_generate_id);
  
  /**
   * asymmetric_key_id_same - Return true if two asymmetric keys IDs are the same.
60f0f0b3c   Krzysztof Kozlowski   KEYS: asymmetric:...
155
156
   * @kid1: The key ID to compare
   * @kid2: The key ID to compare
7901c1a8e   David Howells   KEYS: Implement b...
157
158
159
160
161
162
163
164
165
166
167
168
169
   */
  bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
  			    const struct asymmetric_key_id *kid2)
  {
  	if (!kid1 || !kid2)
  		return false;
  	if (kid1->len != kid2->len)
  		return false;
  	return memcmp(kid1->data, kid2->data, kid1->len) == 0;
  }
  EXPORT_SYMBOL_GPL(asymmetric_key_id_same);
  
  /**
f1b731dbc   Dmitry Kasatkin   KEYS: Restore par...
170
171
   * asymmetric_key_id_partial - Return true if two asymmetric keys IDs
   * partially match
60f0f0b3c   Krzysztof Kozlowski   KEYS: asymmetric:...
172
173
   * @kid1: The key ID to compare
   * @kid2: The key ID to compare
f1b731dbc   Dmitry Kasatkin   KEYS: Restore par...
174
175
176
177
178
179
180
181
182
183
184
185
186
187
   */
  bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
  			       const struct asymmetric_key_id *kid2)
  {
  	if (!kid1 || !kid2)
  		return false;
  	if (kid1->len < kid2->len)
  		return false;
  	return memcmp(kid1->data + (kid1->len - kid2->len),
  		      kid2->data, kid2->len) == 0;
  }
  EXPORT_SYMBOL_GPL(asymmetric_key_id_partial);
  
  /**
7901c1a8e   David Howells   KEYS: Implement b...
188
189
190
   * asymmetric_match_key_ids - Search asymmetric key IDs
   * @kids: The list of key IDs to check
   * @match_id: The key ID we're looking for
f1b731dbc   Dmitry Kasatkin   KEYS: Restore par...
191
   * @match: The match function to use
7901c1a8e   David Howells   KEYS: Implement b...
192
   */
f1b731dbc   Dmitry Kasatkin   KEYS: Restore par...
193
194
195
196
197
  static bool asymmetric_match_key_ids(
  	const struct asymmetric_key_ids *kids,
  	const struct asymmetric_key_id *match_id,
  	bool (*match)(const struct asymmetric_key_id *kid1,
  		      const struct asymmetric_key_id *kid2))
7901c1a8e   David Howells   KEYS: Implement b...
198
  {
f1b731dbc   Dmitry Kasatkin   KEYS: Restore par...
199
  	int i;
7901c1a8e   David Howells   KEYS: Implement b...
200
201
  	if (!kids || !match_id)
  		return false;
f1b731dbc   Dmitry Kasatkin   KEYS: Restore par...
202
203
204
  	for (i = 0; i < ARRAY_SIZE(kids->id); i++)
  		if (match(kids->id[i], match_id))
  			return true;
7901c1a8e   David Howells   KEYS: Implement b...
205
206
  	return false;
  }
7901c1a8e   David Howells   KEYS: Implement b...
207

f2b3dee48   Mimi Zohar   KEYS: fix "ca_key...
208
209
210
211
212
213
214
215
  /* helper function can be called directly with pre-allocated memory */
  inline int __asymmetric_key_hex_to_key_id(const char *id,
  				   struct asymmetric_key_id *match_id,
  				   size_t hexlen)
  {
  	match_id->len = hexlen;
  	return hex2bin(match_id->data, id, hexlen);
  }
7901c1a8e   David Howells   KEYS: Implement b...
216
217
218
219
220
221
222
  /**
   * asymmetric_key_hex_to_key_id - Convert a hex string into a key ID.
   * @id: The ID as a hex string.
   */
  struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id)
  {
  	struct asymmetric_key_id *match_id;
f2b3dee48   Mimi Zohar   KEYS: fix "ca_key...
223
  	size_t asciihexlen;
d1ac55404   David Howells   KEYS: Check hex2b...
224
  	int ret;
7901c1a8e   David Howells   KEYS: Implement b...
225
226
227
  
  	if (!*id)
  		return ERR_PTR(-EINVAL);
f2b3dee48   Mimi Zohar   KEYS: fix "ca_key...
228
229
  	asciihexlen = strlen(id);
  	if (asciihexlen & 1)
7901c1a8e   David Howells   KEYS: Implement b...
230
  		return ERR_PTR(-EINVAL);
f2b3dee48   Mimi Zohar   KEYS: fix "ca_key...
231
  	match_id = kmalloc(sizeof(struct asymmetric_key_id) + asciihexlen / 2,
7901c1a8e   David Howells   KEYS: Implement b...
232
233
234
  			   GFP_KERNEL);
  	if (!match_id)
  		return ERR_PTR(-ENOMEM);
f2b3dee48   Mimi Zohar   KEYS: fix "ca_key...
235
  	ret = __asymmetric_key_hex_to_key_id(id, match_id, asciihexlen / 2);
d1ac55404   David Howells   KEYS: Check hex2b...
236
237
238
239
  	if (ret < 0) {
  		kfree(match_id);
  		return ERR_PTR(-EINVAL);
  	}
7901c1a8e   David Howells   KEYS: Implement b...
240
241
  	return match_id;
  }
964f3b3bf   David Howells   KEYS: Implement a...
242
  /*
f1b731dbc   Dmitry Kasatkin   KEYS: Restore par...
243
   * Match asymmetric keys by an exact match on an ID.
964f3b3bf   David Howells   KEYS: Implement a...
244
   */
0c903ab64   David Howells   KEYS: Make the ke...
245
246
  static bool asymmetric_key_cmp(const struct key *key,
  			       const struct key_match_data *match_data)
964f3b3bf   David Howells   KEYS: Implement a...
247
  {
46963b774   David Howells   KEYS: Overhaul ke...
248
249
  	const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
  	const struct asymmetric_key_id *match_id = match_data->preparsed;
964f3b3bf   David Howells   KEYS: Implement a...
250

f1b731dbc   Dmitry Kasatkin   KEYS: Restore par...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  	return asymmetric_match_key_ids(kids, match_id,
  					asymmetric_key_id_same);
  }
  
  /*
   * Match asymmetric keys by a partial match on an IDs.
   */
  static bool asymmetric_key_cmp_partial(const struct key *key,
  				       const struct key_match_data *match_data)
  {
  	const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
  	const struct asymmetric_key_id *match_id = match_data->preparsed;
  
  	return asymmetric_match_key_ids(kids, match_id,
  					asymmetric_key_id_partial);
964f3b3bf   David Howells   KEYS: Implement a...
266
267
268
  }
  
  /*
462919591   David Howells   KEYS: Preparse ma...
269
270
271
272
273
274
   * Preparse the match criterion.  If we don't set lookup_type and cmp,
   * the default will be an exact match on the key description.
   *
   * There are some specifiers for matching key IDs rather than by the key
   * description:
   *
f1b731dbc   Dmitry Kasatkin   KEYS: Restore par...
275
276
   *	"id:<id>" - find a key by partial match on any available ID
   *	"ex:<id>" - find a key by exact match on any available ID
462919591   David Howells   KEYS: Preparse ma...
277
278
279
280
281
282
   *
   * These have to be searched by iteration rather than by direct lookup because
   * the key is hashed according to its description.
   */
  static int asymmetric_key_match_preparse(struct key_match_data *match_data)
  {
46963b774   David Howells   KEYS: Overhaul ke...
283
284
285
  	struct asymmetric_key_id *match_id;
  	const char *spec = match_data->raw_data;
  	const char *id;
f1b731dbc   Dmitry Kasatkin   KEYS: Restore par...
286
287
  	bool (*cmp)(const struct key *, const struct key_match_data *) =
  		asymmetric_key_cmp;
46963b774   David Howells   KEYS: Overhaul ke...
288
289
290
291
292
293
294
  
  	if (!spec || !*spec)
  		return -EINVAL;
  	if (spec[0] == 'i' &&
  	    spec[1] == 'd' &&
  	    spec[2] == ':') {
  		id = spec + 3;
f1b731dbc   Dmitry Kasatkin   KEYS: Restore par...
295
296
297
298
299
  		cmp = asymmetric_key_cmp_partial;
  	} else if (spec[0] == 'e' &&
  		   spec[1] == 'x' &&
  		   spec[2] == ':') {
  		id = spec + 3;
46963b774   David Howells   KEYS: Overhaul ke...
300
301
302
303
304
  	} else {
  		goto default_match;
  	}
  
  	match_id = asymmetric_key_hex_to_key_id(id);
40b50e80c   Dmitry Kasatkin   KEYS: handle erro...
305
306
  	if (IS_ERR(match_id))
  		return PTR_ERR(match_id);
46963b774   David Howells   KEYS: Overhaul ke...
307
308
  
  	match_data->preparsed = match_id;
f1b731dbc   Dmitry Kasatkin   KEYS: Restore par...
309
  	match_data->cmp = cmp;
46963b774   David Howells   KEYS: Overhaul ke...
310
311
312
313
  	match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
  	return 0;
  
  default_match:
462919591   David Howells   KEYS: Preparse ma...
314
315
316
317
318
319
320
321
  	return 0;
  }
  
  /*
   * Free the preparsed the match criterion.
   */
  static void asymmetric_key_match_free(struct key_match_data *match_data)
  {
46963b774   David Howells   KEYS: Overhaul ke...
322
  	kfree(match_data->preparsed);
462919591   David Howells   KEYS: Preparse ma...
323
324
325
  }
  
  /*
964f3b3bf   David Howells   KEYS: Implement a...
326
327
328
329
330
   * Describe the asymmetric key
   */
  static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
  {
  	const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
46963b774   David Howells   KEYS: Overhaul ke...
331
332
333
334
  	const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
  	const struct asymmetric_key_id *kid;
  	const unsigned char *p;
  	int n;
964f3b3bf   David Howells   KEYS: Implement a...
335
336
337
338
339
340
  
  	seq_puts(m, key->description);
  
  	if (subtype) {
  		seq_puts(m, ": ");
  		subtype->describe(key, m);
d40165898   Dmitry Kasatkin   KEYS: output last...
341
342
  		if (kids && kids->id[1]) {
  			kid = kids->id[1];
964f3b3bf   David Howells   KEYS: Implement a...
343
  			seq_putc(m, ' ');
46963b774   David Howells   KEYS: Overhaul ke...
344
345
  			n = kid->len;
  			p = kid->data;
d40165898   Dmitry Kasatkin   KEYS: output last...
346
347
348
  			if (n > 4) {
  				p += n - 4;
  				n = 4;
46963b774   David Howells   KEYS: Overhaul ke...
349
350
  			}
  			seq_printf(m, "%*phN", n, p);
964f3b3bf   David Howells   KEYS: Implement a...
351
352
353
354
355
356
357
358
359
  		}
  
  		seq_puts(m, " [");
  		/* put something here to indicate the key's capabilities */
  		seq_putc(m, ']');
  	}
  }
  
  /*
46c6f1776   David Howells   KEYS: Asymmetric ...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
   * Preparse a asymmetric payload to get format the contents appropriately for the
   * internal payload to cut down on the number of scans of the data performed.
   *
   * We also generate a proposed description from the contents of the key that
   * can be used to name the key if the user doesn't want to provide one.
   */
  static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
  {
  	struct asymmetric_key_parser *parser;
  	int ret;
  
  	pr_devel("==>%s()
  ", __func__);
  
  	if (prep->datalen == 0)
  		return -EINVAL;
  
  	down_read(&asymmetric_key_parsers_sem);
  
  	ret = -EBADMSG;
  	list_for_each_entry(parser, &asymmetric_key_parsers, link) {
  		pr_debug("Trying parser '%s'
  ", parser->name);
  
  		ret = parser->parse(prep);
  		if (ret != -EBADMSG) {
  			pr_debug("Parser recognised the format (ret %d)
  ",
  				 ret);
  			break;
  		}
  	}
  
  	up_read(&asymmetric_key_parsers_sem);
  	pr_devel("<==%s() = %d
  ", __func__, ret);
  	return ret;
  }
  
  /*
146aa8b14   David Howells   KEYS: Merge the t...
400
401
402
403
404
405
406
407
408
409
410
411
412
413
   * Clean up the key ID list
   */
  static void asymmetric_key_free_kids(struct asymmetric_key_ids *kids)
  {
  	int i;
  
  	if (kids) {
  		for (i = 0; i < ARRAY_SIZE(kids->id); i++)
  			kfree(kids->id[i]);
  		kfree(kids);
  	}
  }
  
  /*
46c6f1776   David Howells   KEYS: Asymmetric ...
414
415
416
417
   * Clean up the preparse data
   */
  static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
  {
146aa8b14   David Howells   KEYS: Merge the t...
418
419
  	struct asymmetric_key_subtype *subtype = prep->payload.data[asym_subtype];
  	struct asymmetric_key_ids *kids = prep->payload.data[asym_key_ids];
46c6f1776   David Howells   KEYS: Asymmetric ...
420
421
422
423
424
  
  	pr_devel("==>%s()
  ", __func__);
  
  	if (subtype) {
3b7645631   David Howells   KEYS: Allow authe...
425
426
  		subtype->destroy(prep->payload.data[asym_crypto],
  				 prep->payload.data[asym_auth]);
46c6f1776   David Howells   KEYS: Asymmetric ...
427
428
  		module_put(subtype->owner);
  	}
146aa8b14   David Howells   KEYS: Merge the t...
429
  	asymmetric_key_free_kids(kids);
46c6f1776   David Howells   KEYS: Asymmetric ...
430
431
432
433
  	kfree(prep->description);
  }
  
  /*
964f3b3bf   David Howells   KEYS: Implement a...
434
435
436
437
438
   * dispose of the data dangling from the corpse of a asymmetric key
   */
  static void asymmetric_key_destroy(struct key *key)
  {
  	struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
146aa8b14   David Howells   KEYS: Merge the t...
439
440
  	struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids];
  	void *data = key->payload.data[asym_crypto];
3b7645631   David Howells   KEYS: Allow authe...
441
  	void *auth = key->payload.data[asym_auth];
146aa8b14   David Howells   KEYS: Merge the t...
442
443
444
445
  
  	key->payload.data[asym_crypto] = NULL;
  	key->payload.data[asym_subtype] = NULL;
  	key->payload.data[asym_key_ids] = NULL;
3b7645631   David Howells   KEYS: Allow authe...
446
  	key->payload.data[asym_auth] = NULL;
46963b774   David Howells   KEYS: Overhaul ke...
447

964f3b3bf   David Howells   KEYS: Implement a...
448
  	if (subtype) {
3b7645631   David Howells   KEYS: Allow authe...
449
  		subtype->destroy(data, auth);
964f3b3bf   David Howells   KEYS: Implement a...
450
  		module_put(subtype->owner);
964f3b3bf   David Howells   KEYS: Implement a...
451
  	}
46963b774   David Howells   KEYS: Overhaul ke...
452

146aa8b14   David Howells   KEYS: Merge the t...
453
  	asymmetric_key_free_kids(kids);
964f3b3bf   David Howells   KEYS: Implement a...
454
  }
97d3aa0f3   Mat Martineau   KEYS: Add a looku...
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  static struct key_restriction *asymmetric_restriction_alloc(
  	key_restrict_link_func_t check,
  	struct key *key)
  {
  	struct key_restriction *keyres =
  		kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
  
  	if (!keyres)
  		return ERR_PTR(-ENOMEM);
  
  	keyres->check = check;
  	keyres->key = key;
  	keyres->keytype = &key_type_asymmetric;
  
  	return keyres;
  }
  
  /*
   * look up keyring restrict functions for asymmetric keys
   */
  static struct key_restriction *asymmetric_lookup_restriction(
  	const char *restriction)
  {
7e3c4d220   Mat Martineau   KEYS: Restrict as...
478
479
480
481
  	char *restrict_method;
  	char *parse_buf;
  	char *next;
  	struct key_restriction *ret = ERR_PTR(-EINVAL);
97d3aa0f3   Mat Martineau   KEYS: Add a looku...
482
483
484
485
486
487
488
  	if (strcmp("builtin_trusted", restriction) == 0)
  		return asymmetric_restriction_alloc(
  			restrict_link_by_builtin_trusted, NULL);
  
  	if (strcmp("builtin_and_secondary_trusted", restriction) == 0)
  		return asymmetric_restriction_alloc(
  			restrict_link_by_builtin_and_secondary_trusted, NULL);
7e3c4d220   Mat Martineau   KEYS: Restrict as...
489
490
491
492
493
494
495
496
  	parse_buf = kstrndup(restriction, PAGE_SIZE, GFP_KERNEL);
  	if (!parse_buf)
  		return ERR_PTR(-ENOMEM);
  
  	next = parse_buf;
  	restrict_method = strsep(&next, ":");
  
  	if ((strcmp(restrict_method, "key_or_keyring") == 0) && next) {
8e323a02e   Mat Martineau   KEYS: Keyring asy...
497
  		char *key_text;
7e3c4d220   Mat Martineau   KEYS: Restrict as...
498
499
  		key_serial_t serial;
  		struct key *key;
8e323a02e   Mat Martineau   KEYS: Keyring asy...
500
501
502
  		key_restrict_link_func_t link_fn =
  			restrict_link_by_key_or_keyring;
  		bool allow_null_key = false;
7e3c4d220   Mat Martineau   KEYS: Restrict as...
503

8e323a02e   Mat Martineau   KEYS: Keyring asy...
504
505
506
507
508
509
510
511
512
  		key_text = strsep(&next, ":");
  
  		if (next) {
  			if (strcmp(next, "chain") != 0)
  				goto out;
  
  			link_fn = restrict_link_by_key_or_keyring_chain;
  			allow_null_key = true;
  		}
7e3c4d220   Mat Martineau   KEYS: Restrict as...
513

8e323a02e   Mat Martineau   KEYS: Keyring asy...
514
  		if (kstrtos32(key_text, 0, &serial) < 0)
7e3c4d220   Mat Martineau   KEYS: Restrict as...
515
  			goto out;
8e323a02e   Mat Martineau   KEYS: Keyring asy...
516
517
518
519
520
521
522
523
524
  
  		if ((serial == 0) && allow_null_key) {
  			key = NULL;
  		} else {
  			key = key_lookup(serial);
  			if (IS_ERR(key)) {
  				ret = ERR_CAST(key);
  				goto out;
  			}
7e3c4d220   Mat Martineau   KEYS: Restrict as...
525
  		}
8e323a02e   Mat Martineau   KEYS: Keyring asy...
526
  		ret = asymmetric_restriction_alloc(link_fn, key);
7e3c4d220   Mat Martineau   KEYS: Restrict as...
527
528
529
530
531
532
533
  		if (IS_ERR(ret))
  			key_put(key);
  	}
  
  out:
  	kfree(parse_buf);
  	return ret;
97d3aa0f3   Mat Martineau   KEYS: Add a looku...
534
  }
5a3077183   David Howells   KEYS: Provide mis...
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  int asymmetric_key_eds_op(struct kernel_pkey_params *params,
  			  const void *in, void *out)
  {
  	const struct asymmetric_key_subtype *subtype;
  	struct key *key = params->key;
  	int ret;
  
  	pr_devel("==>%s()
  ", __func__);
  
  	if (key->type != &key_type_asymmetric)
  		return -EINVAL;
  	subtype = asymmetric_key_subtype(key);
  	if (!subtype ||
  	    !key->payload.data[0])
  		return -EINVAL;
  	if (!subtype->eds_op)
  		return -ENOTSUPP;
  
  	ret = subtype->eds_op(params, in, out);
  
  	pr_devel("<==%s() = %d
  ", __func__, ret);
  	return ret;
  }
  
  static int asymmetric_key_verify_signature(struct kernel_pkey_params *params,
  					   const void *in, const void *in2)
  {
  	struct public_key_signature sig = {
  		.s_size		= params->in2_len,
  		.digest_size	= params->in_len,
  		.encoding	= params->encoding,
  		.hash_algo	= params->hash_algo,
  		.digest		= (void *)in,
  		.s		= (void *)in2,
  	};
  
  	return verify_signature(params->key, &sig);
  }
964f3b3bf   David Howells   KEYS: Implement a...
575
  struct key_type key_type_asymmetric = {
97d3aa0f3   Mat Martineau   KEYS: Add a looku...
576
577
578
579
580
581
582
583
584
  	.name			= "asymmetric",
  	.preparse		= asymmetric_key_preparse,
  	.free_preparse		= asymmetric_key_free_preparse,
  	.instantiate		= generic_key_instantiate,
  	.match_preparse		= asymmetric_key_match_preparse,
  	.match_free		= asymmetric_key_match_free,
  	.destroy		= asymmetric_key_destroy,
  	.describe		= asymmetric_key_describe,
  	.lookup_restriction	= asymmetric_lookup_restriction,
5a3077183   David Howells   KEYS: Provide mis...
585
586
587
  	.asym_query		= query_asymmetric_key,
  	.asym_eds_op		= asymmetric_key_eds_op,
  	.asym_verify_signature	= asymmetric_key_verify_signature,
964f3b3bf   David Howells   KEYS: Implement a...
588
589
  };
  EXPORT_SYMBOL_GPL(key_type_asymmetric);
46c6f1776   David Howells   KEYS: Asymmetric ...
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
  /**
   * register_asymmetric_key_parser - Register a asymmetric key blob parser
   * @parser: The parser to register
   */
  int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
  {
  	struct asymmetric_key_parser *cursor;
  	int ret;
  
  	down_write(&asymmetric_key_parsers_sem);
  
  	list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
  		if (strcmp(cursor->name, parser->name) == 0) {
  			pr_err("Asymmetric key parser '%s' already registered
  ",
  			       parser->name);
  			ret = -EEXIST;
  			goto out;
  		}
  	}
  
  	list_add_tail(&parser->link, &asymmetric_key_parsers);
  
  	pr_notice("Asymmetric key parser '%s' registered
  ", parser->name);
  	ret = 0;
  
  out:
  	up_write(&asymmetric_key_parsers_sem);
  	return ret;
  }
  EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
  
  /**
   * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
   * @parser: The parser to unregister
   */
  void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
  {
  	down_write(&asymmetric_key_parsers_sem);
  	list_del(&parser->link);
  	up_write(&asymmetric_key_parsers_sem);
  
  	pr_notice("Asymmetric key parser '%s' unregistered
  ", parser->name);
  }
  EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
964f3b3bf   David Howells   KEYS: Implement a...
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
  /*
   * Module stuff
   */
  static int __init asymmetric_key_init(void)
  {
  	return register_key_type(&key_type_asymmetric);
  }
  
  static void __exit asymmetric_key_cleanup(void)
  {
  	unregister_key_type(&key_type_asymmetric);
  }
  
  module_init(asymmetric_key_init);
  module_exit(asymmetric_key_cleanup);