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> | |
18 | #include "asymmetric_keys.h" | |
19 | ||
20 | MODULE_LICENSE("GPL"); | |
21 | ||
46c6f177 DH |
22 | static LIST_HEAD(asymmetric_key_parsers); |
23 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | |
24 | ||
964f3b3b DH |
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 | ||
46c6f177 DH |
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 | ||
964f3b3b DH |
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 | { | |
46c6f177 DH |
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; | |
964f3b3b DH |
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", | |
46c6f177 DH |
206 | .preparse = asymmetric_key_preparse, |
207 | .free_preparse = asymmetric_key_free_preparse, | |
964f3b3b DH |
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 | ||
46c6f177 DH |
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 | ||
964f3b3b DH |
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); |