• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Asymmetric public-key cryptography key type
3  *
4  * See Documentation/crypto/asymmetric-keys.txt
5  *
6  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
7  * Written by David Howells (dhowells@redhat.com)
8  */
9 #ifndef __UBOOT__
10 #include <keys/asymmetric-subtype.h>
11 #include <keys/asymmetric-parser.h>
12 #endif
13 #include <crypto/public_key.h>
14 #ifdef __UBOOT__
15 #include <linux/compat.h>
16 #include <linux/ctype.h>
17 #include <linux/string.h>
18 #else
19 #include <linux/seq_file.h>
20 #include <linux/module.h>
21 #include <linux/slab.h>
22 #include <linux/ctype.h>
23 #endif
24 #ifdef __UBOOT__
25 #include <keys/asymmetric-type.h>
26 #else
27 #include <keys/system_keyring.h>
28 #include <keys/user-type.h>
29 #include "asymmetric_keys.h"
30 #endif
31 
32 MODULE_LICENSE("GPL");
33 
34 #ifndef __UBOOT__
35 const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = {
36 	[VERIFYING_MODULE_SIGNATURE]		= "mod sig",
37 	[VERIFYING_FIRMWARE_SIGNATURE]		= "firmware sig",
38 	[VERIFYING_KEXEC_PE_SIGNATURE]		= "kexec PE sig",
39 	[VERIFYING_KEY_SIGNATURE]		= "key sig",
40 	[VERIFYING_KEY_SELF_SIGNATURE]		= "key self sig",
41 	[VERIFYING_UNSPECIFIED_SIGNATURE]	= "unspec sig",
42 };
43 EXPORT_SYMBOL_GPL(key_being_used_for);
44 
45 static LIST_HEAD(asymmetric_key_parsers);
46 static DECLARE_RWSEM(asymmetric_key_parsers_sem);
47 
48 /**
49  * find_asymmetric_key - Find a key by ID.
50  * @keyring: The keys to search.
51  * @id_0: The first ID to look for or NULL.
52  * @id_1: The second ID to look for or NULL.
53  * @partial: Use partial match if true, exact if false.
54  *
55  * Find a key in the given keyring by identifier.  The preferred identifier is
56  * the id_0 and the fallback identifier is the id_1.  If both are given, the
57  * lookup is by the former, but the latter must also match.
58  */
find_asymmetric_key(struct key * keyring,const struct asymmetric_key_id * id_0,const struct asymmetric_key_id * id_1,bool partial)59 struct key *find_asymmetric_key(struct key *keyring,
60 				const struct asymmetric_key_id *id_0,
61 				const struct asymmetric_key_id *id_1,
62 				bool partial)
63 {
64 	struct key *key;
65 	key_ref_t ref;
66 	const char *lookup;
67 	char *req, *p;
68 	int len;
69 
70 	BUG_ON(!id_0 && !id_1);
71 
72 	if (id_0) {
73 		lookup = id_0->data;
74 		len = id_0->len;
75 	} else {
76 		lookup = id_1->data;
77 		len = id_1->len;
78 	}
79 
80 	/* Construct an identifier "id:<keyid>". */
81 	p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
82 	if (!req)
83 		return ERR_PTR(-ENOMEM);
84 
85 	if (partial) {
86 		*p++ = 'i';
87 		*p++ = 'd';
88 	} else {
89 		*p++ = 'e';
90 		*p++ = 'x';
91 	}
92 	*p++ = ':';
93 	p = bin2hex(p, lookup, len);
94 	*p = 0;
95 
96 	pr_debug("Look up: \"%s\"\n", req);
97 
98 	ref = keyring_search(make_key_ref(keyring, 1),
99 			     &key_type_asymmetric, req, true);
100 	if (IS_ERR(ref))
101 		pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
102 	kfree(req);
103 
104 	if (IS_ERR(ref)) {
105 		switch (PTR_ERR(ref)) {
106 			/* Hide some search errors */
107 		case -EACCES:
108 		case -ENOTDIR:
109 		case -EAGAIN:
110 			return ERR_PTR(-ENOKEY);
111 		default:
112 			return ERR_CAST(ref);
113 		}
114 	}
115 
116 	key = key_ref_to_ptr(ref);
117 	if (id_0 && id_1) {
118 		const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
119 
120 		if (!kids->id[1]) {
121 			pr_debug("First ID matches, but second is missing\n");
122 			goto reject;
123 		}
124 		if (!asymmetric_key_id_same(id_1, kids->id[1])) {
125 			pr_debug("First ID matches, but second does not\n");
126 			goto reject;
127 		}
128 	}
129 
130 	pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
131 	return key;
132 
133 reject:
134 	key_put(key);
135 	return ERR_PTR(-EKEYREJECTED);
136 }
137 EXPORT_SYMBOL_GPL(find_asymmetric_key);
138 #endif /* !__UBOOT__ */
139 
140 /**
141  * asymmetric_key_generate_id: Construct an asymmetric key ID
142  * @val_1: First binary blob
143  * @len_1: Length of first binary blob
144  * @val_2: Second binary blob
145  * @len_2: Length of second binary blob
146  *
147  * Construct an asymmetric key ID from a pair of binary blobs.
148  */
asymmetric_key_generate_id(const void * val_1,size_t len_1,const void * val_2,size_t len_2)149 struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
150 						     size_t len_1,
151 						     const void *val_2,
152 						     size_t len_2)
153 {
154 	struct asymmetric_key_id *kid;
155 
156 	kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2,
157 		      GFP_KERNEL);
158 	if (!kid)
159 		return ERR_PTR(-ENOMEM);
160 	kid->len = len_1 + len_2;
161 	memcpy(kid->data, val_1, len_1);
162 	memcpy(kid->data + len_1, val_2, len_2);
163 	return kid;
164 }
165 EXPORT_SYMBOL_GPL(asymmetric_key_generate_id);
166 
167 /**
168  * asymmetric_key_id_same - Return true if two asymmetric keys IDs are the same.
169  * @kid_1, @kid_2: The key IDs to compare
170  */
asymmetric_key_id_same(const struct asymmetric_key_id * kid1,const struct asymmetric_key_id * kid2)171 bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
172 			    const struct asymmetric_key_id *kid2)
173 {
174 	if (!kid1 || !kid2)
175 		return false;
176 	if (kid1->len != kid2->len)
177 		return false;
178 	return memcmp(kid1->data, kid2->data, kid1->len) == 0;
179 }
180 EXPORT_SYMBOL_GPL(asymmetric_key_id_same);
181 
182 /**
183  * asymmetric_key_id_partial - Return true if two asymmetric keys IDs
184  * partially match
185  * @kid_1, @kid_2: The key IDs to compare
186  */
asymmetric_key_id_partial(const struct asymmetric_key_id * kid1,const struct asymmetric_key_id * kid2)187 bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
188 			       const struct asymmetric_key_id *kid2)
189 {
190 	if (!kid1 || !kid2)
191 		return false;
192 	if (kid1->len < kid2->len)
193 		return false;
194 	return memcmp(kid1->data + (kid1->len - kid2->len),
195 		      kid2->data, kid2->len) == 0;
196 }
197 EXPORT_SYMBOL_GPL(asymmetric_key_id_partial);
198 
199 #ifndef __UBOOT__
200 /**
201  * asymmetric_match_key_ids - Search asymmetric key IDs
202  * @kids: The list of key IDs to check
203  * @match_id: The key ID we're looking for
204  * @match: The match function to use
205  */
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))206 static bool asymmetric_match_key_ids(
207 	const struct asymmetric_key_ids *kids,
208 	const struct asymmetric_key_id *match_id,
209 	bool (*match)(const struct asymmetric_key_id *kid1,
210 		      const struct asymmetric_key_id *kid2))
211 {
212 	int i;
213 
214 	if (!kids || !match_id)
215 		return false;
216 	for (i = 0; i < ARRAY_SIZE(kids->id); i++)
217 		if (match(kids->id[i], match_id))
218 			return true;
219 	return false;
220 }
221 
222 /* helper function can be called directly with pre-allocated memory */
__asymmetric_key_hex_to_key_id(const char * id,struct asymmetric_key_id * match_id,size_t hexlen)223 inline int __asymmetric_key_hex_to_key_id(const char *id,
224 				   struct asymmetric_key_id *match_id,
225 				   size_t hexlen)
226 {
227 	match_id->len = hexlen;
228 	return hex2bin(match_id->data, id, hexlen);
229 }
230 
231 /**
232  * asymmetric_key_hex_to_key_id - Convert a hex string into a key ID.
233  * @id: The ID as a hex string.
234  */
asymmetric_key_hex_to_key_id(const char * id)235 struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id)
236 {
237 	struct asymmetric_key_id *match_id;
238 	size_t asciihexlen;
239 	int ret;
240 
241 	if (!*id)
242 		return ERR_PTR(-EINVAL);
243 	asciihexlen = strlen(id);
244 	if (asciihexlen & 1)
245 		return ERR_PTR(-EINVAL);
246 
247 	match_id = kmalloc(sizeof(struct asymmetric_key_id) + asciihexlen / 2,
248 			   GFP_KERNEL);
249 	if (!match_id)
250 		return ERR_PTR(-ENOMEM);
251 	ret = __asymmetric_key_hex_to_key_id(id, match_id, asciihexlen / 2);
252 	if (ret < 0) {
253 		kfree(match_id);
254 		return ERR_PTR(-EINVAL);
255 	}
256 	return match_id;
257 }
258 
259 /*
260  * Match asymmetric keys by an exact match on an ID.
261  */
asymmetric_key_cmp(const struct key * key,const struct key_match_data * match_data)262 static bool asymmetric_key_cmp(const struct key *key,
263 			       const struct key_match_data *match_data)
264 {
265 	const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
266 	const struct asymmetric_key_id *match_id = match_data->preparsed;
267 
268 	return asymmetric_match_key_ids(kids, match_id,
269 					asymmetric_key_id_same);
270 }
271 
272 /*
273  * Match asymmetric keys by a partial match on an IDs.
274  */
asymmetric_key_cmp_partial(const struct key * key,const struct key_match_data * match_data)275 static bool asymmetric_key_cmp_partial(const struct key *key,
276 				       const struct key_match_data *match_data)
277 {
278 	const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
279 	const struct asymmetric_key_id *match_id = match_data->preparsed;
280 
281 	return asymmetric_match_key_ids(kids, match_id,
282 					asymmetric_key_id_partial);
283 }
284 
285 /*
286  * Preparse the match criterion.  If we don't set lookup_type and cmp,
287  * the default will be an exact match on the key description.
288  *
289  * There are some specifiers for matching key IDs rather than by the key
290  * description:
291  *
292  *	"id:<id>" - find a key by partial match on any available ID
293  *	"ex:<id>" - find a key by exact match on any available ID
294  *
295  * These have to be searched by iteration rather than by direct lookup because
296  * the key is hashed according to its description.
297  */
asymmetric_key_match_preparse(struct key_match_data * match_data)298 static int asymmetric_key_match_preparse(struct key_match_data *match_data)
299 {
300 	struct asymmetric_key_id *match_id;
301 	const char *spec = match_data->raw_data;
302 	const char *id;
303 	bool (*cmp)(const struct key *, const struct key_match_data *) =
304 		asymmetric_key_cmp;
305 
306 	if (!spec || !*spec)
307 		return -EINVAL;
308 	if (spec[0] == 'i' &&
309 	    spec[1] == 'd' &&
310 	    spec[2] == ':') {
311 		id = spec + 3;
312 		cmp = asymmetric_key_cmp_partial;
313 	} else if (spec[0] == 'e' &&
314 		   spec[1] == 'x' &&
315 		   spec[2] == ':') {
316 		id = spec + 3;
317 	} else {
318 		goto default_match;
319 	}
320 
321 	match_id = asymmetric_key_hex_to_key_id(id);
322 	if (IS_ERR(match_id))
323 		return PTR_ERR(match_id);
324 
325 	match_data->preparsed = match_id;
326 	match_data->cmp = cmp;
327 	match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
328 	return 0;
329 
330 default_match:
331 	return 0;
332 }
333 
334 /*
335  * Free the preparsed the match criterion.
336  */
asymmetric_key_match_free(struct key_match_data * match_data)337 static void asymmetric_key_match_free(struct key_match_data *match_data)
338 {
339 	kfree(match_data->preparsed);
340 }
341 
342 /*
343  * Describe the asymmetric key
344  */
asymmetric_key_describe(const struct key * key,struct seq_file * m)345 static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
346 {
347 	const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
348 	const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
349 	const struct asymmetric_key_id *kid;
350 	const unsigned char *p;
351 	int n;
352 
353 	seq_puts(m, key->description);
354 
355 	if (subtype) {
356 		seq_puts(m, ": ");
357 		subtype->describe(key, m);
358 
359 		if (kids && kids->id[1]) {
360 			kid = kids->id[1];
361 			seq_putc(m, ' ');
362 			n = kid->len;
363 			p = kid->data;
364 			if (n > 4) {
365 				p += n - 4;
366 				n = 4;
367 			}
368 			seq_printf(m, "%*phN", n, p);
369 		}
370 
371 		seq_puts(m, " [");
372 		/* put something here to indicate the key's capabilities */
373 		seq_putc(m, ']');
374 	}
375 }
376 
377 /*
378  * Preparse a asymmetric payload to get format the contents appropriately for the
379  * internal payload to cut down on the number of scans of the data performed.
380  *
381  * We also generate a proposed description from the contents of the key that
382  * can be used to name the key if the user doesn't want to provide one.
383  */
asymmetric_key_preparse(struct key_preparsed_payload * prep)384 static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
385 {
386 	struct asymmetric_key_parser *parser;
387 	int ret;
388 
389 	pr_devel("==>%s()\n", __func__);
390 
391 	if (prep->datalen == 0)
392 		return -EINVAL;
393 
394 	down_read(&asymmetric_key_parsers_sem);
395 
396 	ret = -EBADMSG;
397 	list_for_each_entry(parser, &asymmetric_key_parsers, link) {
398 		pr_debug("Trying parser '%s'\n", parser->name);
399 
400 		ret = parser->parse(prep);
401 		if (ret != -EBADMSG) {
402 			pr_debug("Parser recognised the format (ret %d)\n",
403 				 ret);
404 			break;
405 		}
406 	}
407 
408 	up_read(&asymmetric_key_parsers_sem);
409 	pr_devel("<==%s() = %d\n", __func__, ret);
410 	return ret;
411 }
412 
413 /*
414  * Clean up the key ID list
415  */
asymmetric_key_free_kids(struct asymmetric_key_ids * kids)416 static void asymmetric_key_free_kids(struct asymmetric_key_ids *kids)
417 {
418 	int i;
419 
420 	if (kids) {
421 		for (i = 0; i < ARRAY_SIZE(kids->id); i++)
422 			kfree(kids->id[i]);
423 		kfree(kids);
424 	}
425 }
426 
427 /*
428  * Clean up the preparse data
429  */
asymmetric_key_free_preparse(struct key_preparsed_payload * prep)430 static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
431 {
432 	struct asymmetric_key_subtype *subtype = prep->payload.data[asym_subtype];
433 	struct asymmetric_key_ids *kids = prep->payload.data[asym_key_ids];
434 
435 	pr_devel("==>%s()\n", __func__);
436 
437 	if (subtype) {
438 		subtype->destroy(prep->payload.data[asym_crypto],
439 				 prep->payload.data[asym_auth]);
440 		module_put(subtype->owner);
441 	}
442 	asymmetric_key_free_kids(kids);
443 	kfree(prep->description);
444 }
445 
446 /*
447  * dispose of the data dangling from the corpse of a asymmetric key
448  */
asymmetric_key_destroy(struct key * key)449 static void asymmetric_key_destroy(struct key *key)
450 {
451 	struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
452 	struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids];
453 	void *data = key->payload.data[asym_crypto];
454 	void *auth = key->payload.data[asym_auth];
455 
456 	key->payload.data[asym_crypto] = NULL;
457 	key->payload.data[asym_subtype] = NULL;
458 	key->payload.data[asym_key_ids] = NULL;
459 	key->payload.data[asym_auth] = NULL;
460 
461 	if (subtype) {
462 		subtype->destroy(data, auth);
463 		module_put(subtype->owner);
464 	}
465 
466 	asymmetric_key_free_kids(kids);
467 }
468 
asymmetric_restriction_alloc(key_restrict_link_func_t check,struct key * key)469 static struct key_restriction *asymmetric_restriction_alloc(
470 	key_restrict_link_func_t check,
471 	struct key *key)
472 {
473 	struct key_restriction *keyres =
474 		kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
475 
476 	if (!keyres)
477 		return ERR_PTR(-ENOMEM);
478 
479 	keyres->check = check;
480 	keyres->key = key;
481 	keyres->keytype = &key_type_asymmetric;
482 
483 	return keyres;
484 }
485 
486 /*
487  * look up keyring restrict functions for asymmetric keys
488  */
asymmetric_lookup_restriction(const char * restriction)489 static struct key_restriction *asymmetric_lookup_restriction(
490 	const char *restriction)
491 {
492 	char *restrict_method;
493 	char *parse_buf;
494 	char *next;
495 	struct key_restriction *ret = ERR_PTR(-EINVAL);
496 
497 	if (strcmp("builtin_trusted", restriction) == 0)
498 		return asymmetric_restriction_alloc(
499 			restrict_link_by_builtin_trusted, NULL);
500 
501 	if (strcmp("builtin_and_secondary_trusted", restriction) == 0)
502 		return asymmetric_restriction_alloc(
503 			restrict_link_by_builtin_and_secondary_trusted, NULL);
504 
505 	parse_buf = kstrndup(restriction, PAGE_SIZE, GFP_KERNEL);
506 	if (!parse_buf)
507 		return ERR_PTR(-ENOMEM);
508 
509 	next = parse_buf;
510 	restrict_method = strsep(&next, ":");
511 
512 	if ((strcmp(restrict_method, "key_or_keyring") == 0) && next) {
513 		char *key_text;
514 		key_serial_t serial;
515 		struct key *key;
516 		key_restrict_link_func_t link_fn =
517 			restrict_link_by_key_or_keyring;
518 		bool allow_null_key = false;
519 
520 		key_text = strsep(&next, ":");
521 
522 		if (next) {
523 			if (strcmp(next, "chain") != 0)
524 				goto out;
525 
526 			link_fn = restrict_link_by_key_or_keyring_chain;
527 			allow_null_key = true;
528 		}
529 
530 		if (kstrtos32(key_text, 0, &serial) < 0)
531 			goto out;
532 
533 		if ((serial == 0) && allow_null_key) {
534 			key = NULL;
535 		} else {
536 			key = key_lookup(serial);
537 			if (IS_ERR(key)) {
538 				ret = ERR_CAST(key);
539 				goto out;
540 			}
541 		}
542 
543 		ret = asymmetric_restriction_alloc(link_fn, key);
544 		if (IS_ERR(ret))
545 			key_put(key);
546 	}
547 
548 out:
549 	kfree(parse_buf);
550 	return ret;
551 }
552 
asymmetric_key_eds_op(struct kernel_pkey_params * params,const void * in,void * out)553 int asymmetric_key_eds_op(struct kernel_pkey_params *params,
554 			  const void *in, void *out)
555 {
556 	const struct asymmetric_key_subtype *subtype;
557 	struct key *key = params->key;
558 	int ret;
559 
560 	pr_devel("==>%s()\n", __func__);
561 
562 	if (key->type != &key_type_asymmetric)
563 		return -EINVAL;
564 	subtype = asymmetric_key_subtype(key);
565 	if (!subtype ||
566 	    !key->payload.data[0])
567 		return -EINVAL;
568 	if (!subtype->eds_op)
569 		return -ENOTSUPP;
570 
571 	ret = subtype->eds_op(params, in, out);
572 
573 	pr_devel("<==%s() = %d\n", __func__, ret);
574 	return ret;
575 }
576 
asymmetric_key_verify_signature(struct kernel_pkey_params * params,const void * in,const void * in2)577 static int asymmetric_key_verify_signature(struct kernel_pkey_params *params,
578 					   const void *in, const void *in2)
579 {
580 	struct public_key_signature sig = {
581 		.s_size		= params->in2_len,
582 		.digest_size	= params->in_len,
583 		.encoding	= params->encoding,
584 		.hash_algo	= params->hash_algo,
585 		.digest		= (void *)in,
586 		.s		= (void *)in2,
587 	};
588 
589 	return verify_signature(params->key, &sig);
590 }
591 
592 struct key_type key_type_asymmetric = {
593 	.name			= "asymmetric",
594 	.preparse		= asymmetric_key_preparse,
595 	.free_preparse		= asymmetric_key_free_preparse,
596 	.instantiate		= generic_key_instantiate,
597 	.match_preparse		= asymmetric_key_match_preparse,
598 	.match_free		= asymmetric_key_match_free,
599 	.destroy		= asymmetric_key_destroy,
600 	.describe		= asymmetric_key_describe,
601 	.lookup_restriction	= asymmetric_lookup_restriction,
602 	.asym_query		= query_asymmetric_key,
603 	.asym_eds_op		= asymmetric_key_eds_op,
604 	.asym_verify_signature	= asymmetric_key_verify_signature,
605 };
606 EXPORT_SYMBOL_GPL(key_type_asymmetric);
607 
608 /**
609  * register_asymmetric_key_parser - Register a asymmetric key blob parser
610  * @parser: The parser to register
611  */
register_asymmetric_key_parser(struct asymmetric_key_parser * parser)612 int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
613 {
614 	struct asymmetric_key_parser *cursor;
615 	int ret;
616 
617 	down_write(&asymmetric_key_parsers_sem);
618 
619 	list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
620 		if (strcmp(cursor->name, parser->name) == 0) {
621 			pr_err("Asymmetric key parser '%s' already registered\n",
622 			       parser->name);
623 			ret = -EEXIST;
624 			goto out;
625 		}
626 	}
627 
628 	list_add_tail(&parser->link, &asymmetric_key_parsers);
629 
630 	pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
631 	ret = 0;
632 
633 out:
634 	up_write(&asymmetric_key_parsers_sem);
635 	return ret;
636 }
637 EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
638 
639 /**
640  * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
641  * @parser: The parser to unregister
642  */
unregister_asymmetric_key_parser(struct asymmetric_key_parser * parser)643 void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
644 {
645 	down_write(&asymmetric_key_parsers_sem);
646 	list_del(&parser->link);
647 	up_write(&asymmetric_key_parsers_sem);
648 
649 	pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
650 }
651 EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
652 
653 /*
654  * Module stuff
655  */
asymmetric_key_init(void)656 static int __init asymmetric_key_init(void)
657 {
658 	return register_key_type(&key_type_asymmetric);
659 }
660 
asymmetric_key_cleanup(void)661 static void __exit asymmetric_key_cleanup(void)
662 {
663 	unregister_key_type(&key_type_asymmetric);
664 }
665 
666 module_init(asymmetric_key_init);
667 module_exit(asymmetric_key_cleanup);
668 #endif /* !__UBOOT__ */
669