Commit | Line | Data |
---|---|---|
964f3b3b DH |
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> | |
46c6f177 | 14 | #include <keys/asymmetric-parser.h> |
964f3b3b DH |
15 | #include <linux/seq_file.h> |
16 | #include <linux/module.h> | |
17 | #include <linux/slab.h> | |
7901c1a8 | 18 | #include <linux/ctype.h> |
964f3b3b DH |
19 | #include "asymmetric_keys.h" |
20 | ||
21 | MODULE_LICENSE("GPL"); | |
22 | ||
46c6f177 DH |
23 | static LIST_HEAD(asymmetric_key_parsers); |
24 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | |
25 | ||
7901c1a8 DH |
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 | ||
f1b731db DK |
68 | /** |
69 | * asymmetric_key_id_partial - Return true if two asymmetric keys IDs | |
70 | * partially match | |
71 | * @kid_1, @kid_2: The key IDs to compare | |
72 | */ | |
73 | bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1, | |
74 | const struct asymmetric_key_id *kid2) | |
75 | { | |
76 | if (!kid1 || !kid2) | |
77 | return false; | |
78 | if (kid1->len < kid2->len) | |
79 | return false; | |
80 | return memcmp(kid1->data + (kid1->len - kid2->len), | |
81 | kid2->data, kid2->len) == 0; | |
82 | } | |
83 | EXPORT_SYMBOL_GPL(asymmetric_key_id_partial); | |
84 | ||
7901c1a8 DH |
85 | /** |
86 | * asymmetric_match_key_ids - Search asymmetric key IDs | |
87 | * @kids: The list of key IDs to check | |
88 | * @match_id: The key ID we're looking for | |
f1b731db | 89 | * @match: The match function to use |
7901c1a8 | 90 | */ |
f1b731db DK |
91 | static bool asymmetric_match_key_ids( |
92 | const struct asymmetric_key_ids *kids, | |
93 | const struct asymmetric_key_id *match_id, | |
94 | bool (*match)(const struct asymmetric_key_id *kid1, | |
95 | const struct asymmetric_key_id *kid2)) | |
7901c1a8 | 96 | { |
f1b731db DK |
97 | int i; |
98 | ||
7901c1a8 DH |
99 | if (!kids || !match_id) |
100 | return false; | |
f1b731db DK |
101 | for (i = 0; i < ARRAY_SIZE(kids->id); i++) |
102 | if (match(kids->id[i], match_id)) | |
103 | return true; | |
7901c1a8 DH |
104 | return false; |
105 | } | |
7901c1a8 DH |
106 | |
107 | /** | |
108 | * asymmetric_key_hex_to_key_id - Convert a hex string into a key ID. | |
109 | * @id: The ID as a hex string. | |
110 | */ | |
111 | struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id) | |
112 | { | |
113 | struct asymmetric_key_id *match_id; | |
d1ac5540 DH |
114 | size_t hexlen; |
115 | int ret; | |
7901c1a8 DH |
116 | |
117 | if (!*id) | |
118 | return ERR_PTR(-EINVAL); | |
d1ac5540 | 119 | hexlen = strlen(id); |
7901c1a8 DH |
120 | if (hexlen & 1) |
121 | return ERR_PTR(-EINVAL); | |
122 | ||
123 | match_id = kmalloc(sizeof(struct asymmetric_key_id) + hexlen / 2, | |
124 | GFP_KERNEL); | |
125 | if (!match_id) | |
126 | return ERR_PTR(-ENOMEM); | |
127 | match_id->len = hexlen / 2; | |
d1ac5540 DH |
128 | ret = hex2bin(match_id->data, id, hexlen / 2); |
129 | if (ret < 0) { | |
130 | kfree(match_id); | |
131 | return ERR_PTR(-EINVAL); | |
132 | } | |
7901c1a8 DH |
133 | return match_id; |
134 | } | |
135 | ||
b3426827 | 136 | /* |
f1b731db | 137 | * Match asymmetric keys by an exact match on an ID. |
964f3b3b | 138 | */ |
0c903ab6 DH |
139 | static bool asymmetric_key_cmp(const struct key *key, |
140 | const struct key_match_data *match_data) | |
964f3b3b | 141 | { |
46963b77 DH |
142 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); |
143 | const struct asymmetric_key_id *match_id = match_data->preparsed; | |
964f3b3b | 144 | |
f1b731db DK |
145 | return asymmetric_match_key_ids(kids, match_id, |
146 | asymmetric_key_id_same); | |
147 | } | |
148 | ||
149 | /* | |
150 | * Match asymmetric keys by a partial match on an IDs. | |
151 | */ | |
152 | static bool asymmetric_key_cmp_partial(const struct key *key, | |
153 | const struct key_match_data *match_data) | |
154 | { | |
155 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); | |
156 | const struct asymmetric_key_id *match_id = match_data->preparsed; | |
157 | ||
158 | return asymmetric_match_key_ids(kids, match_id, | |
159 | asymmetric_key_id_partial); | |
964f3b3b DH |
160 | } |
161 | ||
46291959 DH |
162 | /* |
163 | * Preparse the match criterion. If we don't set lookup_type and cmp, | |
164 | * the default will be an exact match on the key description. | |
165 | * | |
166 | * There are some specifiers for matching key IDs rather than by the key | |
167 | * description: | |
168 | * | |
f1b731db DK |
169 | * "id:<id>" - find a key by partial match on any available ID |
170 | * "ex:<id>" - find a key by exact match on any available ID | |
46291959 DH |
171 | * |
172 | * These have to be searched by iteration rather than by direct lookup because | |
173 | * the key is hashed according to its description. | |
174 | */ | |
175 | static int asymmetric_key_match_preparse(struct key_match_data *match_data) | |
176 | { | |
46963b77 DH |
177 | struct asymmetric_key_id *match_id; |
178 | const char *spec = match_data->raw_data; | |
179 | const char *id; | |
f1b731db DK |
180 | bool (*cmp)(const struct key *, const struct key_match_data *) = |
181 | asymmetric_key_cmp; | |
46963b77 DH |
182 | |
183 | if (!spec || !*spec) | |
184 | return -EINVAL; | |
185 | if (spec[0] == 'i' && | |
186 | spec[1] == 'd' && | |
187 | spec[2] == ':') { | |
188 | id = spec + 3; | |
f1b731db DK |
189 | cmp = asymmetric_key_cmp_partial; |
190 | } else if (spec[0] == 'e' && | |
191 | spec[1] == 'x' && | |
192 | spec[2] == ':') { | |
193 | id = spec + 3; | |
46963b77 DH |
194 | } else { |
195 | goto default_match; | |
196 | } | |
197 | ||
198 | match_id = asymmetric_key_hex_to_key_id(id); | |
40b50e80 DK |
199 | if (IS_ERR(match_id)) |
200 | return PTR_ERR(match_id); | |
46963b77 DH |
201 | |
202 | match_data->preparsed = match_id; | |
f1b731db | 203 | match_data->cmp = cmp; |
46963b77 DH |
204 | match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE; |
205 | return 0; | |
206 | ||
207 | default_match: | |
46291959 DH |
208 | return 0; |
209 | } | |
210 | ||
211 | /* | |
212 | * Free the preparsed the match criterion. | |
213 | */ | |
214 | static void asymmetric_key_match_free(struct key_match_data *match_data) | |
215 | { | |
46963b77 | 216 | kfree(match_data->preparsed); |
46291959 DH |
217 | } |
218 | ||
964f3b3b DH |
219 | /* |
220 | * Describe the asymmetric key | |
221 | */ | |
222 | static void asymmetric_key_describe(const struct key *key, struct seq_file *m) | |
223 | { | |
224 | const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); | |
46963b77 DH |
225 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); |
226 | const struct asymmetric_key_id *kid; | |
227 | const unsigned char *p; | |
228 | int n; | |
964f3b3b DH |
229 | |
230 | seq_puts(m, key->description); | |
231 | ||
232 | if (subtype) { | |
233 | seq_puts(m, ": "); | |
234 | subtype->describe(key, m); | |
235 | ||
d4016589 DK |
236 | if (kids && kids->id[1]) { |
237 | kid = kids->id[1]; | |
964f3b3b | 238 | seq_putc(m, ' '); |
46963b77 DH |
239 | n = kid->len; |
240 | p = kid->data; | |
d4016589 DK |
241 | if (n > 4) { |
242 | p += n - 4; | |
243 | n = 4; | |
46963b77 DH |
244 | } |
245 | seq_printf(m, "%*phN", n, p); | |
964f3b3b DH |
246 | } |
247 | ||
248 | seq_puts(m, " ["); | |
249 | /* put something here to indicate the key's capabilities */ | |
250 | seq_putc(m, ']'); | |
251 | } | |
252 | } | |
253 | ||
46c6f177 DH |
254 | /* |
255 | * Preparse a asymmetric payload to get format the contents appropriately for the | |
256 | * internal payload to cut down on the number of scans of the data performed. | |
257 | * | |
258 | * We also generate a proposed description from the contents of the key that | |
259 | * can be used to name the key if the user doesn't want to provide one. | |
260 | */ | |
261 | static int asymmetric_key_preparse(struct key_preparsed_payload *prep) | |
262 | { | |
263 | struct asymmetric_key_parser *parser; | |
264 | int ret; | |
265 | ||
266 | pr_devel("==>%s()\n", __func__); | |
267 | ||
268 | if (prep->datalen == 0) | |
269 | return -EINVAL; | |
270 | ||
271 | down_read(&asymmetric_key_parsers_sem); | |
272 | ||
273 | ret = -EBADMSG; | |
274 | list_for_each_entry(parser, &asymmetric_key_parsers, link) { | |
275 | pr_debug("Trying parser '%s'\n", parser->name); | |
276 | ||
277 | ret = parser->parse(prep); | |
278 | if (ret != -EBADMSG) { | |
279 | pr_debug("Parser recognised the format (ret %d)\n", | |
280 | ret); | |
281 | break; | |
282 | } | |
283 | } | |
284 | ||
285 | up_read(&asymmetric_key_parsers_sem); | |
286 | pr_devel("<==%s() = %d\n", __func__, ret); | |
287 | return ret; | |
288 | } | |
289 | ||
290 | /* | |
291 | * Clean up the preparse data | |
292 | */ | |
293 | static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) | |
294 | { | |
295 | struct asymmetric_key_subtype *subtype = prep->type_data[0]; | |
46963b77 | 296 | struct asymmetric_key_ids *kids = prep->type_data[1]; |
f1b731db | 297 | int i; |
46c6f177 DH |
298 | |
299 | pr_devel("==>%s()\n", __func__); | |
300 | ||
301 | if (subtype) { | |
fc7c70e0 | 302 | subtype->destroy(prep->payload[0]); |
46c6f177 DH |
303 | module_put(subtype->owner); |
304 | } | |
46963b77 | 305 | if (kids) { |
f1b731db DK |
306 | for (i = 0; i < ARRAY_SIZE(kids->id); i++) |
307 | kfree(kids->id[i]); | |
46963b77 DH |
308 | kfree(kids); |
309 | } | |
46c6f177 DH |
310 | kfree(prep->description); |
311 | } | |
312 | ||
964f3b3b DH |
313 | /* |
314 | * dispose of the data dangling from the corpse of a asymmetric key | |
315 | */ | |
316 | static void asymmetric_key_destroy(struct key *key) | |
317 | { | |
318 | struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); | |
46963b77 DH |
319 | struct asymmetric_key_ids *kids = key->type_data.p[1]; |
320 | ||
964f3b3b DH |
321 | if (subtype) { |
322 | subtype->destroy(key->payload.data); | |
323 | module_put(subtype->owner); | |
324 | key->type_data.p[0] = NULL; | |
325 | } | |
46963b77 DH |
326 | |
327 | if (kids) { | |
328 | kfree(kids->id[0]); | |
329 | kfree(kids->id[1]); | |
330 | kfree(kids); | |
331 | key->type_data.p[1] = NULL; | |
332 | } | |
964f3b3b DH |
333 | } |
334 | ||
335 | struct key_type key_type_asymmetric = { | |
336 | .name = "asymmetric", | |
46c6f177 DH |
337 | .preparse = asymmetric_key_preparse, |
338 | .free_preparse = asymmetric_key_free_preparse, | |
6a09d17b | 339 | .instantiate = generic_key_instantiate, |
46291959 | 340 | .match_preparse = asymmetric_key_match_preparse, |
46291959 | 341 | .match_free = asymmetric_key_match_free, |
964f3b3b DH |
342 | .destroy = asymmetric_key_destroy, |
343 | .describe = asymmetric_key_describe, | |
344 | }; | |
345 | EXPORT_SYMBOL_GPL(key_type_asymmetric); | |
346 | ||
46c6f177 DH |
347 | /** |
348 | * register_asymmetric_key_parser - Register a asymmetric key blob parser | |
349 | * @parser: The parser to register | |
350 | */ | |
351 | int register_asymmetric_key_parser(struct asymmetric_key_parser *parser) | |
352 | { | |
353 | struct asymmetric_key_parser *cursor; | |
354 | int ret; | |
355 | ||
356 | down_write(&asymmetric_key_parsers_sem); | |
357 | ||
358 | list_for_each_entry(cursor, &asymmetric_key_parsers, link) { | |
359 | if (strcmp(cursor->name, parser->name) == 0) { | |
360 | pr_err("Asymmetric key parser '%s' already registered\n", | |
361 | parser->name); | |
362 | ret = -EEXIST; | |
363 | goto out; | |
364 | } | |
365 | } | |
366 | ||
367 | list_add_tail(&parser->link, &asymmetric_key_parsers); | |
368 | ||
369 | pr_notice("Asymmetric key parser '%s' registered\n", parser->name); | |
370 | ret = 0; | |
371 | ||
372 | out: | |
373 | up_write(&asymmetric_key_parsers_sem); | |
374 | return ret; | |
375 | } | |
376 | EXPORT_SYMBOL_GPL(register_asymmetric_key_parser); | |
377 | ||
378 | /** | |
379 | * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser | |
380 | * @parser: The parser to unregister | |
381 | */ | |
382 | void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser) | |
383 | { | |
384 | down_write(&asymmetric_key_parsers_sem); | |
385 | list_del(&parser->link); | |
386 | up_write(&asymmetric_key_parsers_sem); | |
387 | ||
388 | pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name); | |
389 | } | |
390 | EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser); | |
391 | ||
964f3b3b DH |
392 | /* |
393 | * Module stuff | |
394 | */ | |
395 | static int __init asymmetric_key_init(void) | |
396 | { | |
397 | return register_key_type(&key_type_asymmetric); | |
398 | } | |
399 | ||
400 | static void __exit asymmetric_key_cleanup(void) | |
401 | { | |
402 | unregister_key_type(&key_type_asymmetric); | |
403 | } | |
404 | ||
405 | module_init(asymmetric_key_init); | |
406 | module_exit(asymmetric_key_cleanup); |