KEYS: Overhaul key identification when searching for asymmetric keys
[firefly-linux-kernel-4.4.55.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 <linux/ctype.h>
19 #include "asymmetric_keys.h"
20
21 MODULE_LICENSE("GPL");
22
23 static LIST_HEAD(asymmetric_key_parsers);
24 static DECLARE_RWSEM(asymmetric_key_parsers_sem);
25
26 /**
27  * asymmetric_key_generate_id: Construct an asymmetric key ID
28  * @val_1: First binary blob
29  * @len_1: Length of first binary blob
30  * @val_2: Second binary blob
31  * @len_2: Length of second binary blob
32  *
33  * Construct an asymmetric key ID from a pair of binary blobs.
34  */
35 struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
36                                                      size_t len_1,
37                                                      const void *val_2,
38                                                      size_t len_2)
39 {
40         struct asymmetric_key_id *kid;
41
42         kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2,
43                       GFP_KERNEL);
44         if (!kid)
45                 return ERR_PTR(-ENOMEM);
46         kid->len = len_1 + len_2;
47         memcpy(kid->data, val_1, len_1);
48         memcpy(kid->data + len_1, val_2, len_2);
49         return kid;
50 }
51 EXPORT_SYMBOL_GPL(asymmetric_key_generate_id);
52
53 /**
54  * asymmetric_key_id_same - Return true if two asymmetric keys IDs are the same.
55  * @kid_1, @kid_2: The key IDs to compare
56  */
57 bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
58                             const struct asymmetric_key_id *kid2)
59 {
60         if (!kid1 || !kid2)
61                 return false;
62         if (kid1->len != kid2->len)
63                 return false;
64         return memcmp(kid1->data, kid2->data, kid1->len) == 0;
65 }
66 EXPORT_SYMBOL_GPL(asymmetric_key_id_same);
67
68 /**
69  * asymmetric_match_key_ids - Search asymmetric key IDs
70  * @kids: The list of key IDs to check
71  * @match_id: The key ID we're looking for
72  */
73 bool asymmetric_match_key_ids(const struct asymmetric_key_ids *kids,
74                               const struct asymmetric_key_id *match_id)
75 {
76         if (!kids || !match_id)
77                 return false;
78         if (asymmetric_key_id_same(kids->id[0], match_id))
79                 return true;
80         if (asymmetric_key_id_same(kids->id[1], match_id))
81                 return true;
82         return false;
83 }
84 EXPORT_SYMBOL_GPL(asymmetric_match_key_ids);
85
86 /**
87  * asymmetric_key_hex_to_key_id - Convert a hex string into a key ID.
88  * @id: The ID as a hex string.
89  */
90 struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id)
91 {
92         struct asymmetric_key_id *match_id;
93         const char *p;
94         ptrdiff_t hexlen;
95
96         if (!*id)
97                 return ERR_PTR(-EINVAL);
98         for (p = id; *p; p++)
99                 if (!isxdigit(*p))
100                         return ERR_PTR(-EINVAL);
101         hexlen = p - id;
102         if (hexlen & 1)
103                 return ERR_PTR(-EINVAL);
104
105         match_id = kmalloc(sizeof(struct asymmetric_key_id) + hexlen / 2,
106                            GFP_KERNEL);
107         if (!match_id)
108                 return ERR_PTR(-ENOMEM);
109         match_id->len = hexlen / 2;
110         (void)hex2bin(match_id->data, id, hexlen / 2);
111         return match_id;
112 }
113
114 /*
115  * Match asymmetric keys by ID.
116  */
117 static bool asymmetric_key_cmp(const struct key *key,
118                                const struct key_match_data *match_data)
119 {
120         const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
121         const struct asymmetric_key_id *match_id = match_data->preparsed;
122
123         return asymmetric_match_key_ids(kids, match_id);
124 }
125
126 /*
127  * Preparse the match criterion.  If we don't set lookup_type and cmp,
128  * the default will be an exact match on the key description.
129  *
130  * There are some specifiers for matching key IDs rather than by the key
131  * description:
132  *
133  *      "id:<id>" - request a key by any available ID
134  *
135  * These have to be searched by iteration rather than by direct lookup because
136  * the key is hashed according to its description.
137  */
138 static int asymmetric_key_match_preparse(struct key_match_data *match_data)
139 {
140         struct asymmetric_key_id *match_id;
141         const char *spec = match_data->raw_data;
142         const char *id;
143
144         if (!spec || !*spec)
145                 return -EINVAL;
146         if (spec[0] == 'i' &&
147             spec[1] == 'd' &&
148             spec[2] == ':') {
149                 id = spec + 3;
150         } else {
151                 goto default_match;
152         }
153
154         match_id = asymmetric_key_hex_to_key_id(id);
155         if (!match_id)
156                 return -ENOMEM;
157
158         match_data->preparsed = match_id;
159         match_data->cmp = asymmetric_key_cmp;
160         match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
161         return 0;
162
163 default_match:
164         return 0;
165 }
166
167 /*
168  * Free the preparsed the match criterion.
169  */
170 static void asymmetric_key_match_free(struct key_match_data *match_data)
171 {
172         kfree(match_data->preparsed);
173 }
174
175 /*
176  * Describe the asymmetric key
177  */
178 static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
179 {
180         const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
181         const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
182         const struct asymmetric_key_id *kid;
183         const unsigned char *p;
184         int n;
185
186         seq_puts(m, key->description);
187
188         if (subtype) {
189                 seq_puts(m, ": ");
190                 subtype->describe(key, m);
191
192                 if (kids && kids->id[0]) {
193                         kid = kids->id[0];
194                         seq_putc(m, ' ');
195                         n = kid->len;
196                         p = kid->data;
197                         if (n > 8) {
198                                 p += n - 8;
199                                 n = 8;
200                         }
201                         seq_printf(m, "%*phN", n, p);
202                 }
203
204                 seq_puts(m, " [");
205                 /* put something here to indicate the key's capabilities */
206                 seq_putc(m, ']');
207         }
208 }
209
210 /*
211  * Preparse a asymmetric payload to get format the contents appropriately for the
212  * internal payload to cut down on the number of scans of the data performed.
213  *
214  * We also generate a proposed description from the contents of the key that
215  * can be used to name the key if the user doesn't want to provide one.
216  */
217 static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
218 {
219         struct asymmetric_key_parser *parser;
220         int ret;
221
222         pr_devel("==>%s()\n", __func__);
223
224         if (prep->datalen == 0)
225                 return -EINVAL;
226
227         down_read(&asymmetric_key_parsers_sem);
228
229         ret = -EBADMSG;
230         list_for_each_entry(parser, &asymmetric_key_parsers, link) {
231                 pr_debug("Trying parser '%s'\n", parser->name);
232
233                 ret = parser->parse(prep);
234                 if (ret != -EBADMSG) {
235                         pr_debug("Parser recognised the format (ret %d)\n",
236                                  ret);
237                         break;
238                 }
239         }
240
241         up_read(&asymmetric_key_parsers_sem);
242         pr_devel("<==%s() = %d\n", __func__, ret);
243         return ret;
244 }
245
246 /*
247  * Clean up the preparse data
248  */
249 static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
250 {
251         struct asymmetric_key_subtype *subtype = prep->type_data[0];
252         struct asymmetric_key_ids *kids = prep->type_data[1];
253
254         pr_devel("==>%s()\n", __func__);
255
256         if (subtype) {
257                 subtype->destroy(prep->payload[0]);
258                 module_put(subtype->owner);
259         }
260         if (kids) {
261                 kfree(kids->id[0]);
262                 kfree(kids->id[1]);
263                 kfree(kids);
264         }
265         kfree(prep->description);
266 }
267
268 /*
269  * dispose of the data dangling from the corpse of a asymmetric key
270  */
271 static void asymmetric_key_destroy(struct key *key)
272 {
273         struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
274         struct asymmetric_key_ids *kids = key->type_data.p[1];
275
276         if (subtype) {
277                 subtype->destroy(key->payload.data);
278                 module_put(subtype->owner);
279                 key->type_data.p[0] = NULL;
280         }
281
282         if (kids) {
283                 kfree(kids->id[0]);
284                 kfree(kids->id[1]);
285                 kfree(kids);
286                 key->type_data.p[1] = NULL;
287         }
288 }
289
290 struct key_type key_type_asymmetric = {
291         .name           = "asymmetric",
292         .preparse       = asymmetric_key_preparse,
293         .free_preparse  = asymmetric_key_free_preparse,
294         .instantiate    = generic_key_instantiate,
295         .match_preparse = asymmetric_key_match_preparse,
296         .match_free     = asymmetric_key_match_free,
297         .destroy        = asymmetric_key_destroy,
298         .describe       = asymmetric_key_describe,
299 };
300 EXPORT_SYMBOL_GPL(key_type_asymmetric);
301
302 /**
303  * register_asymmetric_key_parser - Register a asymmetric key blob parser
304  * @parser: The parser to register
305  */
306 int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
307 {
308         struct asymmetric_key_parser *cursor;
309         int ret;
310
311         down_write(&asymmetric_key_parsers_sem);
312
313         list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
314                 if (strcmp(cursor->name, parser->name) == 0) {
315                         pr_err("Asymmetric key parser '%s' already registered\n",
316                                parser->name);
317                         ret = -EEXIST;
318                         goto out;
319                 }
320         }
321
322         list_add_tail(&parser->link, &asymmetric_key_parsers);
323
324         pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
325         ret = 0;
326
327 out:
328         up_write(&asymmetric_key_parsers_sem);
329         return ret;
330 }
331 EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
332
333 /**
334  * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
335  * @parser: The parser to unregister
336  */
337 void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
338 {
339         down_write(&asymmetric_key_parsers_sem);
340         list_del(&parser->link);
341         up_write(&asymmetric_key_parsers_sem);
342
343         pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
344 }
345 EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
346
347 /*
348  * Module stuff
349  */
350 static int __init asymmetric_key_init(void)
351 {
352         return register_key_type(&key_type_asymmetric);
353 }
354
355 static void __exit asymmetric_key_cleanup(void)
356 {
357         unregister_key_type(&key_type_asymmetric);
358 }
359
360 module_init(asymmetric_key_init);
361 module_exit(asymmetric_key_cleanup);