KEYS: Remove key_type::match in favour of overriding default by match_preparse
[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_cmp(const struct key *key,
63                               const struct key_match_data *match_data)
64 {
65         const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
66         const char *description = match_data->raw_data;
67         const char *spec = description;
68         const char *id;
69         ptrdiff_t speclen;
70
71         if (!subtype || !spec || !*spec)
72                 return 0;
73
74         /* See if the full key description matches as is */
75         if (key->description && strcmp(key->description, description) == 0)
76                 return 1;
77
78         /* All tests from here on break the criterion description into a
79          * specifier, a colon and then an identifier.
80          */
81         id = strchr(spec, ':');
82         if (!id)
83                 return 0;
84
85         speclen = id - spec;
86         id++;
87
88         if (speclen == 2 && memcmp(spec, "id", 2) == 0)
89                 return asymmetric_keyid_match(asymmetric_key_id(key), id);
90
91         if (speclen == subtype->name_len &&
92             memcmp(spec, subtype->name, speclen) == 0)
93                 return 1;
94
95         return 0;
96 }
97
98 /*
99  * Preparse the match criterion.  If we don't set lookup_type and cmp,
100  * the default will be an exact match on the key description.
101  *
102  * There are some specifiers for matching key IDs rather than by the key
103  * description:
104  *
105  *      "id:<id>" - request a key by any available ID
106  *
107  * These have to be searched by iteration rather than by direct lookup because
108  * the key is hashed according to its description.
109  */
110 static int asymmetric_key_match_preparse(struct key_match_data *match_data)
111 {
112         match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
113         match_data->cmp = asymmetric_key_cmp;
114         return 0;
115 }
116
117 /*
118  * Free the preparsed the match criterion.
119  */
120 static void asymmetric_key_match_free(struct key_match_data *match_data)
121 {
122 }
123
124 /*
125  * Describe the asymmetric key
126  */
127 static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
128 {
129         const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
130         const char *kid = asymmetric_key_id(key);
131         size_t n;
132
133         seq_puts(m, key->description);
134
135         if (subtype) {
136                 seq_puts(m, ": ");
137                 subtype->describe(key, m);
138
139                 if (kid) {
140                         seq_putc(m, ' ');
141                         n = strlen(kid);
142                         if (n <= 8)
143                                 seq_puts(m, kid);
144                         else
145                                 seq_puts(m, kid + n - 8);
146                 }
147
148                 seq_puts(m, " [");
149                 /* put something here to indicate the key's capabilities */
150                 seq_putc(m, ']');
151         }
152 }
153
154 /*
155  * Preparse a asymmetric payload to get format the contents appropriately for the
156  * internal payload to cut down on the number of scans of the data performed.
157  *
158  * We also generate a proposed description from the contents of the key that
159  * can be used to name the key if the user doesn't want to provide one.
160  */
161 static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
162 {
163         struct asymmetric_key_parser *parser;
164         int ret;
165
166         pr_devel("==>%s()\n", __func__);
167
168         if (prep->datalen == 0)
169                 return -EINVAL;
170
171         down_read(&asymmetric_key_parsers_sem);
172
173         ret = -EBADMSG;
174         list_for_each_entry(parser, &asymmetric_key_parsers, link) {
175                 pr_debug("Trying parser '%s'\n", parser->name);
176
177                 ret = parser->parse(prep);
178                 if (ret != -EBADMSG) {
179                         pr_debug("Parser recognised the format (ret %d)\n",
180                                  ret);
181                         break;
182                 }
183         }
184
185         up_read(&asymmetric_key_parsers_sem);
186         pr_devel("<==%s() = %d\n", __func__, ret);
187         return ret;
188 }
189
190 /*
191  * Clean up the preparse data
192  */
193 static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
194 {
195         struct asymmetric_key_subtype *subtype = prep->type_data[0];
196
197         pr_devel("==>%s()\n", __func__);
198
199         if (subtype) {
200                 subtype->destroy(prep->payload[0]);
201                 module_put(subtype->owner);
202         }
203         kfree(prep->type_data[1]);
204         kfree(prep->description);
205 }
206
207 /*
208  * dispose of the data dangling from the corpse of a asymmetric key
209  */
210 static void asymmetric_key_destroy(struct key *key)
211 {
212         struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
213         if (subtype) {
214                 subtype->destroy(key->payload.data);
215                 module_put(subtype->owner);
216                 key->type_data.p[0] = NULL;
217         }
218         kfree(key->type_data.p[1]);
219         key->type_data.p[1] = NULL;
220 }
221
222 struct key_type key_type_asymmetric = {
223         .name           = "asymmetric",
224         .preparse       = asymmetric_key_preparse,
225         .free_preparse  = asymmetric_key_free_preparse,
226         .instantiate    = generic_key_instantiate,
227         .match_preparse = asymmetric_key_match_preparse,
228         .match_free     = asymmetric_key_match_free,
229         .destroy        = asymmetric_key_destroy,
230         .describe       = asymmetric_key_describe,
231 };
232 EXPORT_SYMBOL_GPL(key_type_asymmetric);
233
234 /**
235  * register_asymmetric_key_parser - Register a asymmetric key blob parser
236  * @parser: The parser to register
237  */
238 int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
239 {
240         struct asymmetric_key_parser *cursor;
241         int ret;
242
243         down_write(&asymmetric_key_parsers_sem);
244
245         list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
246                 if (strcmp(cursor->name, parser->name) == 0) {
247                         pr_err("Asymmetric key parser '%s' already registered\n",
248                                parser->name);
249                         ret = -EEXIST;
250                         goto out;
251                 }
252         }
253
254         list_add_tail(&parser->link, &asymmetric_key_parsers);
255
256         pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
257         ret = 0;
258
259 out:
260         up_write(&asymmetric_key_parsers_sem);
261         return ret;
262 }
263 EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
264
265 /**
266  * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
267  * @parser: The parser to unregister
268  */
269 void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
270 {
271         down_write(&asymmetric_key_parsers_sem);
272         list_del(&parser->link);
273         up_write(&asymmetric_key_parsers_sem);
274
275         pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
276 }
277 EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
278
279 /*
280  * Module stuff
281  */
282 static int __init asymmetric_key_init(void)
283 {
284         return register_key_type(&key_type_asymmetric);
285 }
286
287 static void __exit asymmetric_key_cleanup(void)
288 {
289         unregister_key_type(&key_type_asymmetric);
290 }
291
292 module_init(asymmetric_key_init);
293 module_exit(asymmetric_key_cleanup);