KEYS: Asymmetric key pluggable data parsers
[linux-3.10.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 keys on (part of) their name
27  * We have some shorthand methods for matching keys.  We allow:
28  *
29  *      "<desc>"        - request a key by description
30  *      "id:<id>"       - request a key matching the ID
31  *      "<subtype>:<id>" - request a key of a subtype
32  */
33 static int asymmetric_key_match(const struct key *key, const void *description)
34 {
35         const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
36         const char *spec = description;
37         const char *id, *kid;
38         ptrdiff_t speclen;
39         size_t idlen, kidlen;
40
41         if (!subtype || !spec || !*spec)
42                 return 0;
43
44         /* See if the full key description matches as is */
45         if (key->description && strcmp(key->description, description) == 0)
46                 return 1;
47
48         /* All tests from here on break the criterion description into a
49          * specifier, a colon and then an identifier.
50          */
51         id = strchr(spec, ':');
52         if (!id)
53                 return 0;
54
55         speclen = id - spec;
56         id++;
57
58         /* Anything after here requires a partial match on the ID string */
59         kid = asymmetric_key_id(key);
60         if (!kid)
61                 return 0;
62
63         idlen = strlen(id);
64         kidlen = strlen(kid);
65         if (idlen > kidlen)
66                 return 0;
67
68         kid += kidlen - idlen;
69         if (strcasecmp(id, kid) != 0)
70                 return 0;
71
72         if (speclen == 2 &&
73             memcmp(spec, "id", 2) == 0)
74                 return 1;
75
76         if (speclen == subtype->name_len &&
77             memcmp(spec, subtype->name, speclen) == 0)
78                 return 1;
79
80         return 0;
81 }
82
83 /*
84  * Describe the asymmetric key
85  */
86 static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
87 {
88         const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
89         const char *kid = asymmetric_key_id(key);
90         size_t n;
91
92         seq_puts(m, key->description);
93
94         if (subtype) {
95                 seq_puts(m, ": ");
96                 subtype->describe(key, m);
97
98                 if (kid) {
99                         seq_putc(m, ' ');
100                         n = strlen(kid);
101                         if (n <= 8)
102                                 seq_puts(m, kid);
103                         else
104                                 seq_puts(m, kid + n - 8);
105                 }
106
107                 seq_puts(m, " [");
108                 /* put something here to indicate the key's capabilities */
109                 seq_putc(m, ']');
110         }
111 }
112
113 /*
114  * Preparse a asymmetric payload to get format the contents appropriately for the
115  * internal payload to cut down on the number of scans of the data performed.
116  *
117  * We also generate a proposed description from the contents of the key that
118  * can be used to name the key if the user doesn't want to provide one.
119  */
120 static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
121 {
122         struct asymmetric_key_parser *parser;
123         int ret;
124
125         pr_devel("==>%s()\n", __func__);
126
127         if (prep->datalen == 0)
128                 return -EINVAL;
129
130         down_read(&asymmetric_key_parsers_sem);
131
132         ret = -EBADMSG;
133         list_for_each_entry(parser, &asymmetric_key_parsers, link) {
134                 pr_debug("Trying parser '%s'\n", parser->name);
135
136                 ret = parser->parse(prep);
137                 if (ret != -EBADMSG) {
138                         pr_debug("Parser recognised the format (ret %d)\n",
139                                  ret);
140                         break;
141                 }
142         }
143
144         up_read(&asymmetric_key_parsers_sem);
145         pr_devel("<==%s() = %d\n", __func__, ret);
146         return ret;
147 }
148
149 /*
150  * Clean up the preparse data
151  */
152 static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
153 {
154         struct asymmetric_key_subtype *subtype = prep->type_data[0];
155
156         pr_devel("==>%s()\n", __func__);
157
158         if (subtype) {
159                 subtype->destroy(prep->payload);
160                 module_put(subtype->owner);
161         }
162         kfree(prep->type_data[1]);
163         kfree(prep->description);
164 }
165
166 /*
167  * Instantiate a asymmetric_key defined key.  The key was preparsed, so we just
168  * have to transfer the data here.
169  */
170 static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
171 {
172         int ret;
173
174         pr_devel("==>%s()\n", __func__);
175
176         ret = key_payload_reserve(key, prep->quotalen);
177         if (ret == 0) {
178                 key->type_data.p[0] = prep->type_data[0];
179                 key->type_data.p[1] = prep->type_data[1];
180                 key->payload.data = prep->payload;
181                 prep->type_data[0] = NULL;
182                 prep->type_data[1] = NULL;
183                 prep->payload = NULL;
184         }
185         pr_devel("<==%s() = %d\n", __func__, ret);
186         return ret;
187 }
188
189 /*
190  * dispose of the data dangling from the corpse of a asymmetric key
191  */
192 static void asymmetric_key_destroy(struct key *key)
193 {
194         struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
195         if (subtype) {
196                 subtype->destroy(key->payload.data);
197                 module_put(subtype->owner);
198                 key->type_data.p[0] = NULL;
199         }
200         kfree(key->type_data.p[1]);
201         key->type_data.p[1] = NULL;
202 }
203
204 struct key_type key_type_asymmetric = {
205         .name           = "asymmetric",
206         .preparse       = asymmetric_key_preparse,
207         .free_preparse  = asymmetric_key_free_preparse,
208         .instantiate    = asymmetric_key_instantiate,
209         .match          = asymmetric_key_match,
210         .destroy        = asymmetric_key_destroy,
211         .describe       = asymmetric_key_describe,
212 };
213 EXPORT_SYMBOL_GPL(key_type_asymmetric);
214
215 /**
216  * register_asymmetric_key_parser - Register a asymmetric key blob parser
217  * @parser: The parser to register
218  */
219 int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
220 {
221         struct asymmetric_key_parser *cursor;
222         int ret;
223
224         down_write(&asymmetric_key_parsers_sem);
225
226         list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
227                 if (strcmp(cursor->name, parser->name) == 0) {
228                         pr_err("Asymmetric key parser '%s' already registered\n",
229                                parser->name);
230                         ret = -EEXIST;
231                         goto out;
232                 }
233         }
234
235         list_add_tail(&parser->link, &asymmetric_key_parsers);
236
237         pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
238         ret = 0;
239
240 out:
241         up_write(&asymmetric_key_parsers_sem);
242         return ret;
243 }
244 EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
245
246 /**
247  * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
248  * @parser: The parser to unregister
249  */
250 void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
251 {
252         down_write(&asymmetric_key_parsers_sem);
253         list_del(&parser->link);
254         up_write(&asymmetric_key_parsers_sem);
255
256         pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
257 }
258 EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
259
260 /*
261  * Module stuff
262  */
263 static int __init asymmetric_key_init(void)
264 {
265         return register_key_type(&key_type_asymmetric);
266 }
267
268 static void __exit asymmetric_key_cleanup(void)
269 {
270         unregister_key_type(&key_type_asymmetric);
271 }
272
273 module_init(asymmetric_key_init);
274 module_exit(asymmetric_key_cleanup);