~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/crypto/asymmetric_keys/asymmetric_type.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /* Asymmetric public-key cryptography key type
  3  *
  4  * See Documentation/crypto/asymmetric-keys.rst
  5  *
  6  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
  7  * Written by David Howells (dhowells@redhat.com)
  8  */
  9 #include <keys/asymmetric-subtype.h>
 10 #include <keys/asymmetric-parser.h>
 11 #include <crypto/public_key.h>
 12 #include <linux/seq_file.h>
 13 #include <linux/module.h>
 14 #include <linux/slab.h>
 15 #include <linux/ctype.h>
 16 #include <keys/system_keyring.h>
 17 #include <keys/user-type.h>
 18 #include "asymmetric_keys.h"
 19 
 20 
 21 const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = {
 22         [VERIFYING_MODULE_SIGNATURE]            = "mod sig",
 23         [VERIFYING_FIRMWARE_SIGNATURE]          = "firmware sig",
 24         [VERIFYING_KEXEC_PE_SIGNATURE]          = "kexec PE sig",
 25         [VERIFYING_KEY_SIGNATURE]               = "key sig",
 26         [VERIFYING_KEY_SELF_SIGNATURE]          = "key self sig",
 27         [VERIFYING_UNSPECIFIED_SIGNATURE]       = "unspec sig",
 28 };
 29 EXPORT_SYMBOL_GPL(key_being_used_for);
 30 
 31 static LIST_HEAD(asymmetric_key_parsers);
 32 static DECLARE_RWSEM(asymmetric_key_parsers_sem);
 33 
 34 /**
 35  * find_asymmetric_key - Find a key by ID.
 36  * @keyring: The keys to search.
 37  * @id_0: The first ID to look for or NULL.
 38  * @id_1: The second ID to look for or NULL, matched together with @id_0
 39  * against @keyring keys' id[0] and id[1].
 40  * @id_2: The fallback ID to match against @keyring keys' id[2] if both of the
 41  * other IDs are NULL.
 42  * @partial: Use partial match for @id_0 and @id_1 if true, exact if false.
 43  *
 44  * Find a key in the given keyring by identifier.  The preferred identifier is
 45  * the id_0 and the fallback identifier is the id_1.  If both are given, the
 46  * former is matched (exactly or partially) against either of the sought key's
 47  * identifiers and the latter must match the found key's second identifier
 48  * exactly.  If both are missing, id_2 must match the sought key's third
 49  * identifier exactly.
 50  */
 51 struct key *find_asymmetric_key(struct key *keyring,
 52                                 const struct asymmetric_key_id *id_0,
 53                                 const struct asymmetric_key_id *id_1,
 54                                 const struct asymmetric_key_id *id_2,
 55                                 bool partial)
 56 {
 57         struct key *key;
 58         key_ref_t ref;
 59         const char *lookup;
 60         char *req, *p;
 61         int len;
 62 
 63         if (id_0) {
 64                 lookup = id_0->data;
 65                 len = id_0->len;
 66         } else if (id_1) {
 67                 lookup = id_1->data;
 68                 len = id_1->len;
 69         } else if (id_2) {
 70                 lookup = id_2->data;
 71                 len = id_2->len;
 72         } else {
 73                 WARN_ON(1);
 74                 return ERR_PTR(-EINVAL);
 75         }
 76 
 77         /* Construct an identifier "id:<keyid>". */
 78         p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
 79         if (!req)
 80                 return ERR_PTR(-ENOMEM);
 81 
 82         if (!id_0 && !id_1) {
 83                 *p++ = 'd';
 84                 *p++ = 'n';
 85         } else 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 
139 /**
140  * asymmetric_key_generate_id: Construct an asymmetric key ID
141  * @val_1: First binary blob
142  * @len_1: Length of first binary blob
143  * @val_2: Second binary blob
144  * @len_2: Length of second binary blob
145  *
146  * Construct an asymmetric key ID from a pair of binary blobs.
147  */
148 struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
149                                                      size_t len_1,
150                                                      const void *val_2,
151                                                      size_t len_2)
152 {
153         struct asymmetric_key_id *kid;
154 
155         kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2,
156                       GFP_KERNEL);
157         if (!kid)
158                 return ERR_PTR(-ENOMEM);
159         kid->len = len_1 + len_2;
160         memcpy(kid->data, val_1, len_1);
161         memcpy(kid->data + len_1, val_2, len_2);
162         return kid;
163 }
164 EXPORT_SYMBOL_GPL(asymmetric_key_generate_id);
165 
166 /**
167  * asymmetric_key_id_same - Return true if two asymmetric keys IDs are the same.
168  * @kid1: The key ID to compare
169  * @kid2: The key ID to compare
170  */
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  * @kid1: The key ID to compare
186  * @kid2: The key ID to compare
187  */
188 bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
189                                const struct asymmetric_key_id *kid2)
190 {
191         if (!kid1 || !kid2)
192                 return false;
193         if (kid1->len < kid2->len)
194                 return false;
195         return memcmp(kid1->data + (kid1->len - kid2->len),
196                       kid2->data, kid2->len) == 0;
197 }
198 EXPORT_SYMBOL_GPL(asymmetric_key_id_partial);
199 
200 /**
201  * asymmetric_match_key_ids - Search asymmetric key IDs 1 & 2
202  * @kids: The pair of key IDs to check
203  * @match_id: The key ID we're looking for
204  * @match: The match function to use
205  */
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 < 2; 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 */
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  */
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 one of the first two IDs.
261  */
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 one of the first two IDs.
274  */
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  * Match asymmetric keys by an exact match on the third IDs.
287  */
288 static bool asymmetric_key_cmp_name(const struct key *key,
289                                     const struct key_match_data *match_data)
290 {
291         const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
292         const struct asymmetric_key_id *match_id = match_data->preparsed;
293 
294         return kids && asymmetric_key_id_same(kids->id[2], match_id);
295 }
296 
297 /*
298  * Preparse the match criterion.  If we don't set lookup_type and cmp,
299  * the default will be an exact match on the key description.
300  *
301  * There are some specifiers for matching key IDs rather than by the key
302  * description:
303  *
304  *      "id:<id>" - find a key by partial match on one of the first two IDs
305  *      "ex:<id>" - find a key by exact match on one of the first two IDs
306  *      "dn:<id>" - find a key by exact match on the third ID
307  *
308  * These have to be searched by iteration rather than by direct lookup because
309  * the key is hashed according to its description.
310  */
311 static int asymmetric_key_match_preparse(struct key_match_data *match_data)
312 {
313         struct asymmetric_key_id *match_id;
314         const char *spec = match_data->raw_data;
315         const char *id;
316         bool (*cmp)(const struct key *, const struct key_match_data *) =
317                 asymmetric_key_cmp;
318 
319         if (!spec || !*spec)
320                 return -EINVAL;
321         if (spec[0] == 'i' &&
322             spec[1] == 'd' &&
323             spec[2] == ':') {
324                 id = spec + 3;
325                 cmp = asymmetric_key_cmp_partial;
326         } else if (spec[0] == 'e' &&
327                    spec[1] == 'x' &&
328                    spec[2] == ':') {
329                 id = spec + 3;
330         } else if (spec[0] == 'd' &&
331                    spec[1] == 'n' &&
332                    spec[2] == ':') {
333                 id = spec + 3;
334                 cmp = asymmetric_key_cmp_name;
335         } else {
336                 goto default_match;
337         }
338 
339         match_id = asymmetric_key_hex_to_key_id(id);
340         if (IS_ERR(match_id))
341                 return PTR_ERR(match_id);
342 
343         match_data->preparsed = match_id;
344         match_data->cmp = cmp;
345         match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
346         return 0;
347 
348 default_match:
349         return 0;
350 }
351 
352 /*
353  * Free the preparsed the match criterion.
354  */
355 static void asymmetric_key_match_free(struct key_match_data *match_data)
356 {
357         kfree(match_data->preparsed);
358 }
359 
360 /*
361  * Describe the asymmetric key
362  */
363 static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
364 {
365         const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
366         const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
367         const struct asymmetric_key_id *kid;
368         const unsigned char *p;
369         int n;
370 
371         seq_puts(m, key->description);
372 
373         if (subtype) {
374                 seq_puts(m, ": ");
375                 subtype->describe(key, m);
376 
377                 if (kids && kids->id[1]) {
378                         kid = kids->id[1];
379                         seq_putc(m, ' ');
380                         n = kid->len;
381                         p = kid->data;
382                         if (n > 4) {
383                                 p += n - 4;
384                                 n = 4;
385                         }
386                         seq_printf(m, "%*phN", n, p);
387                 }
388 
389                 seq_puts(m, " [");
390                 /* put something here to indicate the key's capabilities */
391                 seq_putc(m, ']');
392         }
393 }
394 
395 /*
396  * Preparse a asymmetric payload to get format the contents appropriately for the
397  * internal payload to cut down on the number of scans of the data performed.
398  *
399  * We also generate a proposed description from the contents of the key that
400  * can be used to name the key if the user doesn't want to provide one.
401  */
402 static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
403 {
404         struct asymmetric_key_parser *parser;
405         int ret;
406 
407         pr_devel("==>%s()\n", __func__);
408 
409         if (prep->datalen == 0)
410                 return -EINVAL;
411 
412         down_read(&asymmetric_key_parsers_sem);
413 
414         ret = -EBADMSG;
415         list_for_each_entry(parser, &asymmetric_key_parsers, link) {
416                 pr_debug("Trying parser '%s'\n", parser->name);
417 
418                 ret = parser->parse(prep);
419                 if (ret != -EBADMSG) {
420                         pr_debug("Parser recognised the format (ret %d)\n",
421                                  ret);
422                         break;
423                 }
424         }
425 
426         up_read(&asymmetric_key_parsers_sem);
427         pr_devel("<==%s() = %d\n", __func__, ret);
428         return ret;
429 }
430 
431 /*
432  * Clean up the key ID list
433  */
434 static void asymmetric_key_free_kids(struct asymmetric_key_ids *kids)
435 {
436         int i;
437 
438         if (kids) {
439                 for (i = 0; i < ARRAY_SIZE(kids->id); i++)
440                         kfree(kids->id[i]);
441                 kfree(kids);
442         }
443 }
444 
445 /*
446  * Clean up the preparse data
447  */
448 static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
449 {
450         struct asymmetric_key_subtype *subtype = prep->payload.data[asym_subtype];
451         struct asymmetric_key_ids *kids = prep->payload.data[asym_key_ids];
452 
453         pr_devel("==>%s()\n", __func__);
454 
455         if (subtype) {
456                 subtype->destroy(prep->payload.data[asym_crypto],
457                                  prep->payload.data[asym_auth]);
458                 module_put(subtype->owner);
459         }
460         asymmetric_key_free_kids(kids);
461         kfree(prep->description);
462 }
463 
464 /*
465  * dispose of the data dangling from the corpse of a asymmetric key
466  */
467 static void asymmetric_key_destroy(struct key *key)
468 {
469         struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
470         struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids];
471         void *data = key->payload.data[asym_crypto];
472         void *auth = key->payload.data[asym_auth];
473 
474         key->payload.data[asym_crypto] = NULL;
475         key->payload.data[asym_subtype] = NULL;
476         key->payload.data[asym_key_ids] = NULL;
477         key->payload.data[asym_auth] = NULL;
478 
479         if (subtype) {
480                 subtype->destroy(data, auth);
481                 module_put(subtype->owner);
482         }
483 
484         asymmetric_key_free_kids(kids);
485 }
486 
487 static struct key_restriction *asymmetric_restriction_alloc(
488         key_restrict_link_func_t check,
489         struct key *key)
490 {
491         struct key_restriction *keyres =
492                 kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
493 
494         if (!keyres)
495                 return ERR_PTR(-ENOMEM);
496 
497         keyres->check = check;
498         keyres->key = key;
499         keyres->keytype = &key_type_asymmetric;
500 
501         return keyres;
502 }
503 
504 /*
505  * look up keyring restrict functions for asymmetric keys
506  */
507 static struct key_restriction *asymmetric_lookup_restriction(
508         const char *restriction)
509 {
510         char *restrict_method;
511         char *parse_buf;
512         char *next;
513         struct key_restriction *ret = ERR_PTR(-EINVAL);
514 
515         if (strcmp("builtin_trusted", restriction) == 0)
516                 return asymmetric_restriction_alloc(
517                         restrict_link_by_builtin_trusted, NULL);
518 
519         if (strcmp("builtin_and_secondary_trusted", restriction) == 0)
520                 return asymmetric_restriction_alloc(
521                         restrict_link_by_builtin_and_secondary_trusted, NULL);
522 
523         parse_buf = kstrndup(restriction, PAGE_SIZE, GFP_KERNEL);
524         if (!parse_buf)
525                 return ERR_PTR(-ENOMEM);
526 
527         next = parse_buf;
528         restrict_method = strsep(&next, ":");
529 
530         if ((strcmp(restrict_method, "key_or_keyring") == 0) && next) {
531                 char *key_text;
532                 key_serial_t serial;
533                 struct key *key;
534                 key_restrict_link_func_t link_fn =
535                         restrict_link_by_key_or_keyring;
536                 bool allow_null_key = false;
537 
538                 key_text = strsep(&next, ":");
539 
540                 if (next) {
541                         if (strcmp(next, "chain") != 0)
542                                 goto out;
543 
544                         link_fn = restrict_link_by_key_or_keyring_chain;
545                         allow_null_key = true;
546                 }
547 
548                 if (kstrtos32(key_text, 0, &serial) < 0)
549                         goto out;
550 
551                 if ((serial == 0) && allow_null_key) {
552                         key = NULL;
553                 } else {
554                         key = key_lookup(serial);
555                         if (IS_ERR(key)) {
556                                 ret = ERR_CAST(key);
557                                 goto out;
558                         }
559                 }
560 
561                 ret = asymmetric_restriction_alloc(link_fn, key);
562                 if (IS_ERR(ret))
563                         key_put(key);
564         }
565 
566 out:
567         kfree(parse_buf);
568         return ret;
569 }
570 
571 int asymmetric_key_eds_op(struct kernel_pkey_params *params,
572                           const void *in, void *out)
573 {
574         const struct asymmetric_key_subtype *subtype;
575         struct key *key = params->key;
576         int ret;
577 
578         pr_devel("==>%s()\n", __func__);
579 
580         if (key->type != &key_type_asymmetric)
581                 return -EINVAL;
582         subtype = asymmetric_key_subtype(key);
583         if (!subtype ||
584             !key->payload.data[0])
585                 return -EINVAL;
586         if (!subtype->eds_op)
587                 return -ENOTSUPP;
588 
589         ret = subtype->eds_op(params, in, out);
590 
591         pr_devel("<==%s() = %d\n", __func__, ret);
592         return ret;
593 }
594 
595 static int asymmetric_key_verify_signature(struct kernel_pkey_params *params,
596                                            const void *in, const void *in2)
597 {
598         struct public_key_signature sig = {
599                 .s_size         = params->in2_len,
600                 .digest_size    = params->in_len,
601                 .encoding       = params->encoding,
602                 .hash_algo      = params->hash_algo,
603                 .digest         = (void *)in,
604                 .s              = (void *)in2,
605         };
606 
607         return verify_signature(params->key, &sig);
608 }
609 
610 struct key_type key_type_asymmetric = {
611         .name                   = "asymmetric",
612         .preparse               = asymmetric_key_preparse,
613         .free_preparse          = asymmetric_key_free_preparse,
614         .instantiate            = generic_key_instantiate,
615         .match_preparse         = asymmetric_key_match_preparse,
616         .match_free             = asymmetric_key_match_free,
617         .destroy                = asymmetric_key_destroy,
618         .describe               = asymmetric_key_describe,
619         .lookup_restriction     = asymmetric_lookup_restriction,
620         .asym_query             = query_asymmetric_key,
621         .asym_eds_op            = asymmetric_key_eds_op,
622         .asym_verify_signature  = asymmetric_key_verify_signature,
623 };
624 EXPORT_SYMBOL_GPL(key_type_asymmetric);
625 
626 /**
627  * register_asymmetric_key_parser - Register a asymmetric key blob parser
628  * @parser: The parser to register
629  */
630 int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
631 {
632         struct asymmetric_key_parser *cursor;
633         int ret;
634 
635         down_write(&asymmetric_key_parsers_sem);
636 
637         list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
638                 if (strcmp(cursor->name, parser->name) == 0) {
639                         pr_err("Asymmetric key parser '%s' already registered\n",
640                                parser->name);
641                         ret = -EEXIST;
642                         goto out;
643                 }
644         }
645 
646         list_add_tail(&parser->link, &asymmetric_key_parsers);
647 
648         pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
649         ret = 0;
650 
651 out:
652         up_write(&asymmetric_key_parsers_sem);
653         return ret;
654 }
655 EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
656 
657 /**
658  * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
659  * @parser: The parser to unregister
660  */
661 void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
662 {
663         down_write(&asymmetric_key_parsers_sem);
664         list_del(&parser->link);
665         up_write(&asymmetric_key_parsers_sem);
666 
667         pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
668 }
669 EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
670 
671 /*
672  * Module stuff
673  */
674 static int __init asymmetric_key_init(void)
675 {
676         return register_key_type(&key_type_asymmetric);
677 }
678 
679 static void __exit asymmetric_key_cleanup(void)
680 {
681         unregister_key_type(&key_type_asymmetric);
682 }
683 
684 module_init(asymmetric_key_init);
685 module_exit(asymmetric_key_cleanup);
686 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php