]>
Commit | Line | Data |
---|---|---|
b4d0d230 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
964f3b3b DH |
2 | /* Asymmetric public-key cryptography key type |
3 | * | |
0efaaa86 | 4 | * See Documentation/crypto/asymmetric-keys.rst |
964f3b3b DH |
5 | * |
6 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | |
7 | * Written by David Howells (dhowells@redhat.com) | |
964f3b3b DH |
8 | */ |
9 | #include <keys/asymmetric-subtype.h> | |
46c6f177 | 10 | #include <keys/asymmetric-parser.h> |
99db4435 | 11 | #include <crypto/public_key.h> |
964f3b3b DH |
12 | #include <linux/seq_file.h> |
13 | #include <linux/module.h> | |
14 | #include <linux/slab.h> | |
7901c1a8 | 15 | #include <linux/ctype.h> |
97d3aa0f | 16 | #include <keys/system_keyring.h> |
5a307718 | 17 | #include <keys/user-type.h> |
964f3b3b DH |
18 | #include "asymmetric_keys.h" |
19 | ||
20 | MODULE_LICENSE("GPL"); | |
21 | ||
99db4435 DH |
22 | const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = { |
23 | [VERIFYING_MODULE_SIGNATURE] = "mod sig", | |
24 | [VERIFYING_FIRMWARE_SIGNATURE] = "firmware sig", | |
25 | [VERIFYING_KEXEC_PE_SIGNATURE] = "kexec PE sig", | |
26 | [VERIFYING_KEY_SIGNATURE] = "key sig", | |
27 | [VERIFYING_KEY_SELF_SIGNATURE] = "key self sig", | |
28 | [VERIFYING_UNSPECIFIED_SIGNATURE] = "unspec sig", | |
29 | }; | |
30 | EXPORT_SYMBOL_GPL(key_being_used_for); | |
31 | ||
46c6f177 DH |
32 | static LIST_HEAD(asymmetric_key_parsers); |
33 | static DECLARE_RWSEM(asymmetric_key_parsers_sem); | |
34 | ||
983023f2 | 35 | /** |
9eb02989 | 36 | * find_asymmetric_key - Find a key by ID. |
983023f2 | 37 | * @keyring: The keys to search. |
9eb02989 DH |
38 | * @id_0: The first ID to look for or NULL. |
39 | * @id_1: The second ID to look for or NULL. | |
983023f2 DH |
40 | * @partial: Use partial match if true, exact if false. |
41 | * | |
42 | * Find a key in the given keyring by identifier. The preferred identifier is | |
9eb02989 DH |
43 | * the id_0 and the fallback identifier is the id_1. If both are given, the |
44 | * lookup is by the former, but the latter must also match. | |
983023f2 | 45 | */ |
9eb02989 DH |
46 | struct key *find_asymmetric_key(struct key *keyring, |
47 | const struct asymmetric_key_id *id_0, | |
48 | const struct asymmetric_key_id *id_1, | |
49 | bool partial) | |
983023f2 DH |
50 | { |
51 | struct key *key; | |
52 | key_ref_t ref; | |
53 | const char *lookup; | |
54 | char *req, *p; | |
55 | int len; | |
56 | ||
b3811d36 CYL |
57 | BUG_ON(!id_0 && !id_1); |
58 | ||
9eb02989 DH |
59 | if (id_0) { |
60 | lookup = id_0->data; | |
61 | len = id_0->len; | |
983023f2 | 62 | } else { |
9eb02989 DH |
63 | lookup = id_1->data; |
64 | len = id_1->len; | |
983023f2 DH |
65 | } |
66 | ||
67 | /* Construct an identifier "id:<keyid>". */ | |
68 | p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL); | |
69 | if (!req) | |
70 | return ERR_PTR(-ENOMEM); | |
71 | ||
72 | if (partial) { | |
73 | *p++ = 'i'; | |
74 | *p++ = 'd'; | |
75 | } else { | |
76 | *p++ = 'e'; | |
77 | *p++ = 'x'; | |
78 | } | |
79 | *p++ = ':'; | |
80 | p = bin2hex(p, lookup, len); | |
81 | *p = 0; | |
82 | ||
83 | pr_debug("Look up: \"%s\"\n", req); | |
84 | ||
85 | ref = keyring_search(make_key_ref(keyring, 1), | |
dcf49dbc | 86 | &key_type_asymmetric, req, true); |
983023f2 DH |
87 | if (IS_ERR(ref)) |
88 | pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref)); | |
89 | kfree(req); | |
90 | ||
91 | if (IS_ERR(ref)) { | |
92 | switch (PTR_ERR(ref)) { | |
93 | /* Hide some search errors */ | |
94 | case -EACCES: | |
95 | case -ENOTDIR: | |
96 | case -EAGAIN: | |
97 | return ERR_PTR(-ENOKEY); | |
98 | default: | |
99 | return ERR_CAST(ref); | |
100 | } | |
101 | } | |
102 | ||
103 | key = key_ref_to_ptr(ref); | |
9eb02989 | 104 | if (id_0 && id_1) { |
983023f2 | 105 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); |
9eb02989 | 106 | |
6a6d2a77 | 107 | if (!kids->id[1]) { |
9eb02989 | 108 | pr_debug("First ID matches, but second is missing\n"); |
983023f2 DH |
109 | goto reject; |
110 | } | |
9eb02989 DH |
111 | if (!asymmetric_key_id_same(id_1, kids->id[1])) { |
112 | pr_debug("First ID matches, but second does not\n"); | |
983023f2 DH |
113 | goto reject; |
114 | } | |
115 | } | |
116 | ||
117 | pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key)); | |
118 | return key; | |
119 | ||
120 | reject: | |
121 | key_put(key); | |
122 | return ERR_PTR(-EKEYREJECTED); | |
123 | } | |
9eb02989 | 124 | EXPORT_SYMBOL_GPL(find_asymmetric_key); |
983023f2 | 125 | |
7901c1a8 DH |
126 | /** |
127 | * asymmetric_key_generate_id: Construct an asymmetric key ID | |
128 | * @val_1: First binary blob | |
129 | * @len_1: Length of first binary blob | |
130 | * @val_2: Second binary blob | |
131 | * @len_2: Length of second binary blob | |
132 | * | |
133 | * Construct an asymmetric key ID from a pair of binary blobs. | |
134 | */ | |
135 | struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1, | |
136 | size_t len_1, | |
137 | const void *val_2, | |
138 | size_t len_2) | |
139 | { | |
140 | struct asymmetric_key_id *kid; | |
141 | ||
142 | kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2, | |
143 | GFP_KERNEL); | |
144 | if (!kid) | |
145 | return ERR_PTR(-ENOMEM); | |
146 | kid->len = len_1 + len_2; | |
147 | memcpy(kid->data, val_1, len_1); | |
148 | memcpy(kid->data + len_1, val_2, len_2); | |
149 | return kid; | |
150 | } | |
151 | EXPORT_SYMBOL_GPL(asymmetric_key_generate_id); | |
152 | ||
153 | /** | |
154 | * asymmetric_key_id_same - Return true if two asymmetric keys IDs are the same. | |
155 | * @kid_1, @kid_2: The key IDs to compare | |
156 | */ | |
157 | bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1, | |
158 | const struct asymmetric_key_id *kid2) | |
159 | { | |
160 | if (!kid1 || !kid2) | |
161 | return false; | |
162 | if (kid1->len != kid2->len) | |
163 | return false; | |
164 | return memcmp(kid1->data, kid2->data, kid1->len) == 0; | |
165 | } | |
166 | EXPORT_SYMBOL_GPL(asymmetric_key_id_same); | |
167 | ||
f1b731db DK |
168 | /** |
169 | * asymmetric_key_id_partial - Return true if two asymmetric keys IDs | |
170 | * partially match | |
171 | * @kid_1, @kid_2: The key IDs to compare | |
172 | */ | |
173 | bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1, | |
174 | const struct asymmetric_key_id *kid2) | |
175 | { | |
176 | if (!kid1 || !kid2) | |
177 | return false; | |
178 | if (kid1->len < kid2->len) | |
179 | return false; | |
180 | return memcmp(kid1->data + (kid1->len - kid2->len), | |
181 | kid2->data, kid2->len) == 0; | |
182 | } | |
183 | EXPORT_SYMBOL_GPL(asymmetric_key_id_partial); | |
184 | ||
7901c1a8 DH |
185 | /** |
186 | * asymmetric_match_key_ids - Search asymmetric key IDs | |
187 | * @kids: The list of key IDs to check | |
188 | * @match_id: The key ID we're looking for | |
f1b731db | 189 | * @match: The match function to use |
7901c1a8 | 190 | */ |
f1b731db DK |
191 | static bool asymmetric_match_key_ids( |
192 | const struct asymmetric_key_ids *kids, | |
193 | const struct asymmetric_key_id *match_id, | |
194 | bool (*match)(const struct asymmetric_key_id *kid1, | |
195 | const struct asymmetric_key_id *kid2)) | |
7901c1a8 | 196 | { |
f1b731db DK |
197 | int i; |
198 | ||
7901c1a8 DH |
199 | if (!kids || !match_id) |
200 | return false; | |
f1b731db DK |
201 | for (i = 0; i < ARRAY_SIZE(kids->id); i++) |
202 | if (match(kids->id[i], match_id)) | |
203 | return true; | |
7901c1a8 DH |
204 | return false; |
205 | } | |
7901c1a8 | 206 | |
f2b3dee4 MZ |
207 | /* helper function can be called directly with pre-allocated memory */ |
208 | inline int __asymmetric_key_hex_to_key_id(const char *id, | |
209 | struct asymmetric_key_id *match_id, | |
210 | size_t hexlen) | |
211 | { | |
212 | match_id->len = hexlen; | |
213 | return hex2bin(match_id->data, id, hexlen); | |
214 | } | |
215 | ||
7901c1a8 DH |
216 | /** |
217 | * asymmetric_key_hex_to_key_id - Convert a hex string into a key ID. | |
218 | * @id: The ID as a hex string. | |
219 | */ | |
220 | struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id) | |
221 | { | |
222 | struct asymmetric_key_id *match_id; | |
f2b3dee4 | 223 | size_t asciihexlen; |
d1ac5540 | 224 | int ret; |
7901c1a8 DH |
225 | |
226 | if (!*id) | |
227 | return ERR_PTR(-EINVAL); | |
f2b3dee4 MZ |
228 | asciihexlen = strlen(id); |
229 | if (asciihexlen & 1) | |
7901c1a8 DH |
230 | return ERR_PTR(-EINVAL); |
231 | ||
f2b3dee4 | 232 | match_id = kmalloc(sizeof(struct asymmetric_key_id) + asciihexlen / 2, |
7901c1a8 DH |
233 | GFP_KERNEL); |
234 | if (!match_id) | |
235 | return ERR_PTR(-ENOMEM); | |
f2b3dee4 | 236 | ret = __asymmetric_key_hex_to_key_id(id, match_id, asciihexlen / 2); |
d1ac5540 DH |
237 | if (ret < 0) { |
238 | kfree(match_id); | |
239 | return ERR_PTR(-EINVAL); | |
240 | } | |
7901c1a8 DH |
241 | return match_id; |
242 | } | |
243 | ||
b3426827 | 244 | /* |
f1b731db | 245 | * Match asymmetric keys by an exact match on an ID. |
964f3b3b | 246 | */ |
0c903ab6 DH |
247 | static bool asymmetric_key_cmp(const struct key *key, |
248 | const struct key_match_data *match_data) | |
964f3b3b | 249 | { |
46963b77 DH |
250 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); |
251 | const struct asymmetric_key_id *match_id = match_data->preparsed; | |
964f3b3b | 252 | |
f1b731db DK |
253 | return asymmetric_match_key_ids(kids, match_id, |
254 | asymmetric_key_id_same); | |
255 | } | |
256 | ||
257 | /* | |
258 | * Match asymmetric keys by a partial match on an IDs. | |
259 | */ | |
260 | static bool asymmetric_key_cmp_partial(const struct key *key, | |
261 | const struct key_match_data *match_data) | |
262 | { | |
263 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); | |
264 | const struct asymmetric_key_id *match_id = match_data->preparsed; | |
265 | ||
266 | return asymmetric_match_key_ids(kids, match_id, | |
267 | asymmetric_key_id_partial); | |
964f3b3b DH |
268 | } |
269 | ||
46291959 DH |
270 | /* |
271 | * Preparse the match criterion. If we don't set lookup_type and cmp, | |
272 | * the default will be an exact match on the key description. | |
273 | * | |
274 | * There are some specifiers for matching key IDs rather than by the key | |
275 | * description: | |
276 | * | |
f1b731db DK |
277 | * "id:<id>" - find a key by partial match on any available ID |
278 | * "ex:<id>" - find a key by exact match on any available ID | |
46291959 DH |
279 | * |
280 | * These have to be searched by iteration rather than by direct lookup because | |
281 | * the key is hashed according to its description. | |
282 | */ | |
283 | static int asymmetric_key_match_preparse(struct key_match_data *match_data) | |
284 | { | |
46963b77 DH |
285 | struct asymmetric_key_id *match_id; |
286 | const char *spec = match_data->raw_data; | |
287 | const char *id; | |
f1b731db DK |
288 | bool (*cmp)(const struct key *, const struct key_match_data *) = |
289 | asymmetric_key_cmp; | |
46963b77 DH |
290 | |
291 | if (!spec || !*spec) | |
292 | return -EINVAL; | |
293 | if (spec[0] == 'i' && | |
294 | spec[1] == 'd' && | |
295 | spec[2] == ':') { | |
296 | id = spec + 3; | |
f1b731db DK |
297 | cmp = asymmetric_key_cmp_partial; |
298 | } else if (spec[0] == 'e' && | |
299 | spec[1] == 'x' && | |
300 | spec[2] == ':') { | |
301 | id = spec + 3; | |
46963b77 DH |
302 | } else { |
303 | goto default_match; | |
304 | } | |
305 | ||
306 | match_id = asymmetric_key_hex_to_key_id(id); | |
40b50e80 DK |
307 | if (IS_ERR(match_id)) |
308 | return PTR_ERR(match_id); | |
46963b77 DH |
309 | |
310 | match_data->preparsed = match_id; | |
f1b731db | 311 | match_data->cmp = cmp; |
46963b77 DH |
312 | match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE; |
313 | return 0; | |
314 | ||
315 | default_match: | |
46291959 DH |
316 | return 0; |
317 | } | |
318 | ||
319 | /* | |
320 | * Free the preparsed the match criterion. | |
321 | */ | |
322 | static void asymmetric_key_match_free(struct key_match_data *match_data) | |
323 | { | |
46963b77 | 324 | kfree(match_data->preparsed); |
46291959 DH |
325 | } |
326 | ||
964f3b3b DH |
327 | /* |
328 | * Describe the asymmetric key | |
329 | */ | |
330 | static void asymmetric_key_describe(const struct key *key, struct seq_file *m) | |
331 | { | |
332 | const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); | |
46963b77 DH |
333 | const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); |
334 | const struct asymmetric_key_id *kid; | |
335 | const unsigned char *p; | |
336 | int n; | |
964f3b3b DH |
337 | |
338 | seq_puts(m, key->description); | |
339 | ||
340 | if (subtype) { | |
341 | seq_puts(m, ": "); | |
342 | subtype->describe(key, m); | |
343 | ||
d4016589 DK |
344 | if (kids && kids->id[1]) { |
345 | kid = kids->id[1]; | |
964f3b3b | 346 | seq_putc(m, ' '); |
46963b77 DH |
347 | n = kid->len; |
348 | p = kid->data; | |
d4016589 DK |
349 | if (n > 4) { |
350 | p += n - 4; | |
351 | n = 4; | |
46963b77 DH |
352 | } |
353 | seq_printf(m, "%*phN", n, p); | |
964f3b3b DH |
354 | } |
355 | ||
356 | seq_puts(m, " ["); | |
357 | /* put something here to indicate the key's capabilities */ | |
358 | seq_putc(m, ']'); | |
359 | } | |
360 | } | |
361 | ||
46c6f177 DH |
362 | /* |
363 | * Preparse a asymmetric payload to get format the contents appropriately for the | |
364 | * internal payload to cut down on the number of scans of the data performed. | |
365 | * | |
366 | * We also generate a proposed description from the contents of the key that | |
367 | * can be used to name the key if the user doesn't want to provide one. | |
368 | */ | |
369 | static int asymmetric_key_preparse(struct key_preparsed_payload *prep) | |
370 | { | |
371 | struct asymmetric_key_parser *parser; | |
372 | int ret; | |
373 | ||
374 | pr_devel("==>%s()\n", __func__); | |
375 | ||
376 | if (prep->datalen == 0) | |
377 | return -EINVAL; | |
378 | ||
379 | down_read(&asymmetric_key_parsers_sem); | |
380 | ||
381 | ret = -EBADMSG; | |
382 | list_for_each_entry(parser, &asymmetric_key_parsers, link) { | |
383 | pr_debug("Trying parser '%s'\n", parser->name); | |
384 | ||
385 | ret = parser->parse(prep); | |
386 | if (ret != -EBADMSG) { | |
387 | pr_debug("Parser recognised the format (ret %d)\n", | |
388 | ret); | |
389 | break; | |
390 | } | |
391 | } | |
392 | ||
393 | up_read(&asymmetric_key_parsers_sem); | |
394 | pr_devel("<==%s() = %d\n", __func__, ret); | |
395 | return ret; | |
396 | } | |
397 | ||
146aa8b1 DH |
398 | /* |
399 | * Clean up the key ID list | |
400 | */ | |
401 | static void asymmetric_key_free_kids(struct asymmetric_key_ids *kids) | |
402 | { | |
403 | int i; | |
404 | ||
405 | if (kids) { | |
406 | for (i = 0; i < ARRAY_SIZE(kids->id); i++) | |
407 | kfree(kids->id[i]); | |
408 | kfree(kids); | |
409 | } | |
410 | } | |
411 | ||
46c6f177 DH |
412 | /* |
413 | * Clean up the preparse data | |
414 | */ | |
415 | static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) | |
416 | { | |
146aa8b1 DH |
417 | struct asymmetric_key_subtype *subtype = prep->payload.data[asym_subtype]; |
418 | struct asymmetric_key_ids *kids = prep->payload.data[asym_key_ids]; | |
46c6f177 DH |
419 | |
420 | pr_devel("==>%s()\n", __func__); | |
421 | ||
422 | if (subtype) { | |
3b764563 DH |
423 | subtype->destroy(prep->payload.data[asym_crypto], |
424 | prep->payload.data[asym_auth]); | |
46c6f177 DH |
425 | module_put(subtype->owner); |
426 | } | |
146aa8b1 | 427 | asymmetric_key_free_kids(kids); |
46c6f177 DH |
428 | kfree(prep->description); |
429 | } | |
430 | ||
964f3b3b DH |
431 | /* |
432 | * dispose of the data dangling from the corpse of a asymmetric key | |
433 | */ | |
434 | static void asymmetric_key_destroy(struct key *key) | |
435 | { | |
436 | struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); | |
146aa8b1 DH |
437 | struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids]; |
438 | void *data = key->payload.data[asym_crypto]; | |
3b764563 | 439 | void *auth = key->payload.data[asym_auth]; |
146aa8b1 DH |
440 | |
441 | key->payload.data[asym_crypto] = NULL; | |
442 | key->payload.data[asym_subtype] = NULL; | |
443 | key->payload.data[asym_key_ids] = NULL; | |
3b764563 | 444 | key->payload.data[asym_auth] = NULL; |
46963b77 | 445 | |
964f3b3b | 446 | if (subtype) { |
3b764563 | 447 | subtype->destroy(data, auth); |
964f3b3b | 448 | module_put(subtype->owner); |
964f3b3b | 449 | } |
46963b77 | 450 | |
146aa8b1 | 451 | asymmetric_key_free_kids(kids); |
964f3b3b DH |
452 | } |
453 | ||
97d3aa0f MM |
454 | static struct key_restriction *asymmetric_restriction_alloc( |
455 | key_restrict_link_func_t check, | |
456 | struct key *key) | |
457 | { | |
458 | struct key_restriction *keyres = | |
459 | kzalloc(sizeof(struct key_restriction), GFP_KERNEL); | |
460 | ||
461 | if (!keyres) | |
462 | return ERR_PTR(-ENOMEM); | |
463 | ||
464 | keyres->check = check; | |
465 | keyres->key = key; | |
466 | keyres->keytype = &key_type_asymmetric; | |
467 | ||
468 | return keyres; | |
469 | } | |
470 | ||
471 | /* | |
472 | * look up keyring restrict functions for asymmetric keys | |
473 | */ | |
474 | static struct key_restriction *asymmetric_lookup_restriction( | |
475 | const char *restriction) | |
476 | { | |
7e3c4d22 MM |
477 | char *restrict_method; |
478 | char *parse_buf; | |
479 | char *next; | |
480 | struct key_restriction *ret = ERR_PTR(-EINVAL); | |
481 | ||
97d3aa0f MM |
482 | if (strcmp("builtin_trusted", restriction) == 0) |
483 | return asymmetric_restriction_alloc( | |
484 | restrict_link_by_builtin_trusted, NULL); | |
485 | ||
486 | if (strcmp("builtin_and_secondary_trusted", restriction) == 0) | |
487 | return asymmetric_restriction_alloc( | |
488 | restrict_link_by_builtin_and_secondary_trusted, NULL); | |
489 | ||
7e3c4d22 MM |
490 | parse_buf = kstrndup(restriction, PAGE_SIZE, GFP_KERNEL); |
491 | if (!parse_buf) | |
492 | return ERR_PTR(-ENOMEM); | |
493 | ||
494 | next = parse_buf; | |
495 | restrict_method = strsep(&next, ":"); | |
496 | ||
497 | if ((strcmp(restrict_method, "key_or_keyring") == 0) && next) { | |
8e323a02 | 498 | char *key_text; |
7e3c4d22 MM |
499 | key_serial_t serial; |
500 | struct key *key; | |
8e323a02 MM |
501 | key_restrict_link_func_t link_fn = |
502 | restrict_link_by_key_or_keyring; | |
503 | bool allow_null_key = false; | |
7e3c4d22 | 504 | |
8e323a02 MM |
505 | key_text = strsep(&next, ":"); |
506 | ||
507 | if (next) { | |
508 | if (strcmp(next, "chain") != 0) | |
509 | goto out; | |
510 | ||
511 | link_fn = restrict_link_by_key_or_keyring_chain; | |
512 | allow_null_key = true; | |
513 | } | |
7e3c4d22 | 514 | |
8e323a02 | 515 | if (kstrtos32(key_text, 0, &serial) < 0) |
7e3c4d22 | 516 | goto out; |
8e323a02 MM |
517 | |
518 | if ((serial == 0) && allow_null_key) { | |
519 | key = NULL; | |
520 | } else { | |
521 | key = key_lookup(serial); | |
522 | if (IS_ERR(key)) { | |
523 | ret = ERR_CAST(key); | |
524 | goto out; | |
525 | } | |
7e3c4d22 MM |
526 | } |
527 | ||
8e323a02 | 528 | ret = asymmetric_restriction_alloc(link_fn, key); |
7e3c4d22 MM |
529 | if (IS_ERR(ret)) |
530 | key_put(key); | |
531 | } | |
532 | ||
533 | out: | |
534 | kfree(parse_buf); | |
535 | return ret; | |
97d3aa0f MM |
536 | } |
537 | ||
5a307718 DH |
538 | int asymmetric_key_eds_op(struct kernel_pkey_params *params, |
539 | const void *in, void *out) | |
540 | { | |
541 | const struct asymmetric_key_subtype *subtype; | |
542 | struct key *key = params->key; | |
543 | int ret; | |
544 | ||
545 | pr_devel("==>%s()\n", __func__); | |
546 | ||
547 | if (key->type != &key_type_asymmetric) | |
548 | return -EINVAL; | |
549 | subtype = asymmetric_key_subtype(key); | |
550 | if (!subtype || | |
551 | !key->payload.data[0]) | |
552 | return -EINVAL; | |
553 | if (!subtype->eds_op) | |
554 | return -ENOTSUPP; | |
555 | ||
556 | ret = subtype->eds_op(params, in, out); | |
557 | ||
558 | pr_devel("<==%s() = %d\n", __func__, ret); | |
559 | return ret; | |
560 | } | |
561 | ||
562 | static int asymmetric_key_verify_signature(struct kernel_pkey_params *params, | |
563 | const void *in, const void *in2) | |
564 | { | |
565 | struct public_key_signature sig = { | |
566 | .s_size = params->in2_len, | |
567 | .digest_size = params->in_len, | |
568 | .encoding = params->encoding, | |
569 | .hash_algo = params->hash_algo, | |
570 | .digest = (void *)in, | |
571 | .s = (void *)in2, | |
572 | }; | |
573 | ||
574 | return verify_signature(params->key, &sig); | |
575 | } | |
576 | ||
964f3b3b | 577 | struct key_type key_type_asymmetric = { |
97d3aa0f MM |
578 | .name = "asymmetric", |
579 | .preparse = asymmetric_key_preparse, | |
580 | .free_preparse = asymmetric_key_free_preparse, | |
581 | .instantiate = generic_key_instantiate, | |
582 | .match_preparse = asymmetric_key_match_preparse, | |
583 | .match_free = asymmetric_key_match_free, | |
584 | .destroy = asymmetric_key_destroy, | |
585 | .describe = asymmetric_key_describe, | |
586 | .lookup_restriction = asymmetric_lookup_restriction, | |
5a307718 DH |
587 | .asym_query = query_asymmetric_key, |
588 | .asym_eds_op = asymmetric_key_eds_op, | |
589 | .asym_verify_signature = asymmetric_key_verify_signature, | |
964f3b3b DH |
590 | }; |
591 | EXPORT_SYMBOL_GPL(key_type_asymmetric); | |
592 | ||
46c6f177 DH |
593 | /** |
594 | * register_asymmetric_key_parser - Register a asymmetric key blob parser | |
595 | * @parser: The parser to register | |
596 | */ | |
597 | int register_asymmetric_key_parser(struct asymmetric_key_parser *parser) | |
598 | { | |
599 | struct asymmetric_key_parser *cursor; | |
600 | int ret; | |
601 | ||
602 | down_write(&asymmetric_key_parsers_sem); | |
603 | ||
604 | list_for_each_entry(cursor, &asymmetric_key_parsers, link) { | |
605 | if (strcmp(cursor->name, parser->name) == 0) { | |
606 | pr_err("Asymmetric key parser '%s' already registered\n", | |
607 | parser->name); | |
608 | ret = -EEXIST; | |
609 | goto out; | |
610 | } | |
611 | } | |
612 | ||
613 | list_add_tail(&parser->link, &asymmetric_key_parsers); | |
614 | ||
615 | pr_notice("Asymmetric key parser '%s' registered\n", parser->name); | |
616 | ret = 0; | |
617 | ||
618 | out: | |
619 | up_write(&asymmetric_key_parsers_sem); | |
620 | return ret; | |
621 | } | |
622 | EXPORT_SYMBOL_GPL(register_asymmetric_key_parser); | |
623 | ||
624 | /** | |
625 | * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser | |
626 | * @parser: The parser to unregister | |
627 | */ | |
628 | void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser) | |
629 | { | |
630 | down_write(&asymmetric_key_parsers_sem); | |
631 | list_del(&parser->link); | |
632 | up_write(&asymmetric_key_parsers_sem); | |
633 | ||
634 | pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name); | |
635 | } | |
636 | EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser); | |
637 | ||
964f3b3b DH |
638 | /* |
639 | * Module stuff | |
640 | */ | |
641 | static int __init asymmetric_key_init(void) | |
642 | { | |
643 | return register_key_type(&key_type_asymmetric); | |
644 | } | |
645 | ||
646 | static void __exit asymmetric_key_cleanup(void) | |
647 | { | |
648 | unregister_key_type(&key_type_asymmetric); | |
649 | } | |
650 | ||
651 | module_init(asymmetric_key_init); | |
652 | module_exit(asymmetric_key_cleanup); |