Merge tag 'dmaengine-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw...
[pandora-kernel.git] / crypto / asymmetric_keys / asymmetric_type.c
1 /* Asymmetric public-key cryptography key type
2  *
3  * See Documentation/security/asymmetric-keys.txt
4  *
5  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
6  * Written by David Howells (dhowells@redhat.com)
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public Licence
10  * as published by the Free Software Foundation; either version
11  * 2 of the Licence, or (at your option) any later version.
12  */
13 #include <keys/asymmetric-subtype.h>
14 #include <keys/asymmetric-parser.h>
15 #include <linux/seq_file.h>
16 #include <linux/module.h>
17 #include <linux/slab.h>
18 #include "asymmetric_keys.h"
19
20 MODULE_LICENSE("GPL");
21
22 static LIST_HEAD(asymmetric_key_parsers);
23 static DECLARE_RWSEM(asymmetric_key_parsers_sem);
24
25 /*
26  * Match asymmetric key id with partial match
27  * @id:         key id to match in a form "id:<id>"
28  */
29 int asymmetric_keyid_match(const char *kid, const char *id)
30 {
31         size_t idlen, kidlen;
32
33         if (!kid || !id)
34                 return 0;
35
36         /* make it possible to use id as in the request: "id:<id>" */
37         if (strncmp(id, "id:", 3) == 0)
38                 id += 3;
39
40         /* Anything after here requires a partial match on the ID string */
41         idlen = strlen(id);
42         kidlen = strlen(kid);
43         if (idlen > kidlen)
44                 return 0;
45
46         kid += kidlen - idlen;
47         if (strcasecmp(id, kid) != 0)
48                 return 0;
49
50         return 1;
51 }
52 EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
53
54 /*
55  * Match asymmetric keys on (part of) their name
56  * We have some shorthand methods for matching keys.  We allow:
57  *
58  *      "<desc>"        - request a key by description
59  *      "id:<id>"       - request a key matching the ID
60  *      "<subtype>:<id>" - request a key of a subtype
61  */
62 static int asymmetric_key_match(const struct key *key, const void *description)
63 {
64         const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
65         const char *spec = description;
66         const char *id;
67         ptrdiff_t speclen;
68
69         if (!subtype || !spec || !*spec)
70                 return 0;
71
72         /* See if the full key description matches as is */
73         if (key->description && strcmp(key->description, description) == 0)
74                 return 1;
75
76         /* All tests from here on break the criterion description into a
77          * specifier, a colon and then an identifier.
78          */
79         id = strchr(spec, ':');
80         if (!id)
81                 return 0;
82
83         speclen = id - spec;
84         id++;
85
86         if (speclen == 2 && memcmp(spec, "id", 2) == 0)
87                 return asymmetric_keyid_match(asymmetric_key_id(key), id);
88
89         if (speclen == subtype->name_len &&
90             memcmp(spec, subtype->name, speclen) == 0)
91                 return 1;
92
93         return 0;
94 }
95
96 /*
97  * Describe the asymmetric key
98  */
99 static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
100 {
101         const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
102         const char *kid = asymmetric_key_id(key);
103         size_t n;
104
105         seq_puts(m, key->description);
106
107         if (subtype) {
108                 seq_puts(m, ": ");
109                 subtype->describe(key, m);
110
111                 if (kid) {
112                         seq_putc(m, ' ');
113                         n = strlen(kid);
114                         if (n <= 8)
115                                 seq_puts(m, kid);
116                         else
117                                 seq_puts(m, kid + n - 8);
118                 }
119
120                 seq_puts(m, " [");
121                 /* put something here to indicate the key's capabilities */
122                 seq_putc(m, ']');
123         }
124 }
125
126 /*
127  * Preparse a asymmetric payload to get format the contents appropriately for the
128  * internal payload to cut down on the number of scans of the data performed.
129  *
130  * We also generate a proposed description from the contents of the key that
131  * can be used to name the key if the user doesn't want to provide one.
132  */
133 static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
134 {
135         struct asymmetric_key_parser *parser;
136         int ret;
137
138         pr_devel("==>%s()\n", __func__);
139
140         if (prep->datalen == 0)
141                 return -EINVAL;
142
143         down_read(&asymmetric_key_parsers_sem);
144
145         ret = -EBADMSG;
146         list_for_each_entry(parser, &asymmetric_key_parsers, link) {
147                 pr_debug("Trying parser '%s'\n", parser->name);
148
149                 ret = parser->parse(prep);
150                 if (ret != -EBADMSG) {
151                         pr_debug("Parser recognised the format (ret %d)\n",
152                                  ret);
153                         break;
154                 }
155         }
156
157         up_read(&asymmetric_key_parsers_sem);
158         pr_devel("<==%s() = %d\n", __func__, ret);
159         return ret;
160 }
161
162 /*
163  * Clean up the preparse data
164  */
165 static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
166 {
167         struct asymmetric_key_subtype *subtype = prep->type_data[0];
168
169         pr_devel("==>%s()\n", __func__);
170
171         if (subtype) {
172                 subtype->destroy(prep->payload[0]);
173                 module_put(subtype->owner);
174         }
175         kfree(prep->type_data[1]);
176         kfree(prep->description);
177 }
178
179 /*
180  * dispose of the data dangling from the corpse of a asymmetric key
181  */
182 static void asymmetric_key_destroy(struct key *key)
183 {
184         struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
185         if (subtype) {
186                 subtype->destroy(key->payload.data);
187                 module_put(subtype->owner);
188                 key->type_data.p[0] = NULL;
189         }
190         kfree(key->type_data.p[1]);
191         key->type_data.p[1] = NULL;
192 }
193
194 struct key_type key_type_asymmetric = {
195         .name           = "asymmetric",
196         .preparse       = asymmetric_key_preparse,
197         .free_preparse  = asymmetric_key_free_preparse,
198         .instantiate    = generic_key_instantiate,
199         .match          = asymmetric_key_match,
200         .destroy        = asymmetric_key_destroy,
201         .describe       = asymmetric_key_describe,
202         .def_lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE,
203 };
204 EXPORT_SYMBOL_GPL(key_type_asymmetric);
205
206 /**
207  * register_asymmetric_key_parser - Register a asymmetric key blob parser
208  * @parser: The parser to register
209  */
210 int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
211 {
212         struct asymmetric_key_parser *cursor;
213         int ret;
214
215         down_write(&asymmetric_key_parsers_sem);
216
217         list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
218                 if (strcmp(cursor->name, parser->name) == 0) {
219                         pr_err("Asymmetric key parser '%s' already registered\n",
220                                parser->name);
221                         ret = -EEXIST;
222                         goto out;
223                 }
224         }
225
226         list_add_tail(&parser->link, &asymmetric_key_parsers);
227
228         pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
229         ret = 0;
230
231 out:
232         up_write(&asymmetric_key_parsers_sem);
233         return ret;
234 }
235 EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
236
237 /**
238  * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
239  * @parser: The parser to unregister
240  */
241 void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
242 {
243         down_write(&asymmetric_key_parsers_sem);
244         list_del(&parser->link);
245         up_write(&asymmetric_key_parsers_sem);
246
247         pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
248 }
249 EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
250
251 /*
252  * Module stuff
253  */
254 static int __init asymmetric_key_init(void)
255 {
256         return register_key_type(&key_type_asymmetric);
257 }
258
259 static void __exit asymmetric_key_cleanup(void)
260 {
261         unregister_key_type(&key_type_asymmetric);
262 }
263
264 module_init(asymmetric_key_init);
265 module_exit(asymmetric_key_cleanup);