blob: eb8cd46961a5aa5a6a7470c6d17008d1745bbdf6 [file] [log] [blame]
David Howells964f3b32012-09-13 15:17:21 +01001/* 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>
David Howells46c6f172012-09-13 15:17:32 +010014#include <keys/asymmetric-parser.h>
David Howells964f3b32012-09-13 15:17:21 +010015#include <linux/seq_file.h>
16#include <linux/module.h>
17#include <linux/slab.h>
18#include "asymmetric_keys.h"
19
20MODULE_LICENSE("GPL");
21
David Howells46c6f172012-09-13 15:17:32 +010022static LIST_HEAD(asymmetric_key_parsers);
23static DECLARE_RWSEM(asymmetric_key_parsers_sem);
24
David Howells964f3b32012-09-13 15:17:21 +010025/*
Dmitry Kasatkinb3426822014-06-17 11:56:57 +030026 * Match asymmetric key id with partial match
27 * @id: key id to match in a form "id:<id>"
28 */
29int asymmetric_keyid_match(const char *kid, const char *id)
30{
31 size_t idlen, kidlen;
32
33 if (!kid || !id)
34 return 0;
35
36 /* make it possible to use id as in the request: "id:<id>" */
37 if (strncmp(id, "id:", 3) == 0)
38 id += 3;
39
40 /* Anything after here requires a partial match on the ID string */
41 idlen = strlen(id);
42 kidlen = strlen(kid);
43 if (idlen > kidlen)
44 return 0;
45
46 kid += kidlen - idlen;
47 if (strcasecmp(id, kid) != 0)
48 return 0;
49
50 return 1;
51}
Dmitry Kasatkinffb70f62014-06-17 11:56:58 +030052EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
Dmitry Kasatkinb3426822014-06-17 11:56:57 +030053
54/*
David Howells964f3b32012-09-13 15:17:21 +010055 * Match asymmetric keys on (part of) their name
56 * We have some shorthand methods for matching keys. We allow:
57 *
58 * "<desc>" - request a key by description
59 * "id:<id>" - request a key matching the ID
60 * "<subtype>:<id>" - request a key of a subtype
61 */
62static int asymmetric_key_match(const struct key *key, const void *description)
63{
64 const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
65 const char *spec = description;
Dmitry Kasatkinb3426822014-06-17 11:56:57 +030066 const char *id;
David Howells964f3b32012-09-13 15:17:21 +010067 ptrdiff_t speclen;
David Howells964f3b32012-09-13 15:17:21 +010068
69 if (!subtype || !spec || !*spec)
70 return 0;
71
72 /* See if the full key description matches as is */
73 if (key->description && strcmp(key->description, description) == 0)
74 return 1;
75
76 /* All tests from here on break the criterion description into a
77 * specifier, a colon and then an identifier.
78 */
79 id = strchr(spec, ':');
80 if (!id)
81 return 0;
82
83 speclen = id - spec;
84 id++;
85
Dmitry Kasatkinb3426822014-06-17 11:56:57 +030086 if (speclen == 2 && memcmp(spec, "id", 2) == 0)
87 return asymmetric_keyid_match(asymmetric_key_id(key), id);
David Howells964f3b32012-09-13 15:17:21 +010088
89 if (speclen == subtype->name_len &&
90 memcmp(spec, subtype->name, speclen) == 0)
91 return 1;
92
93 return 0;
94}
95
96/*
97 * Describe the asymmetric key
98 */
99static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
100{
101 const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
102 const char *kid = asymmetric_key_id(key);
103 size_t n;
104
105 seq_puts(m, key->description);
106
107 if (subtype) {
108 seq_puts(m, ": ");
109 subtype->describe(key, m);
110
111 if (kid) {
112 seq_putc(m, ' ');
113 n = strlen(kid);
114 if (n <= 8)
115 seq_puts(m, kid);
116 else
117 seq_puts(m, kid + n - 8);
118 }
119
120 seq_puts(m, " [");
121 /* put something here to indicate the key's capabilities */
122 seq_putc(m, ']');
123 }
124}
125
126/*
David Howells46c6f172012-09-13 15:17:32 +0100127 * Preparse a asymmetric payload to get format the contents appropriately for the
128 * internal payload to cut down on the number of scans of the data performed.
129 *
130 * We also generate a proposed description from the contents of the key that
131 * can be used to name the key if the user doesn't want to provide one.
132 */
133static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
134{
135 struct asymmetric_key_parser *parser;
136 int ret;
137
138 pr_devel("==>%s()\n", __func__);
139
140 if (prep->datalen == 0)
141 return -EINVAL;
142
143 down_read(&asymmetric_key_parsers_sem);
144
145 ret = -EBADMSG;
146 list_for_each_entry(parser, &asymmetric_key_parsers, link) {
147 pr_debug("Trying parser '%s'\n", parser->name);
148
149 ret = parser->parse(prep);
150 if (ret != -EBADMSG) {
151 pr_debug("Parser recognised the format (ret %d)\n",
152 ret);
153 break;
154 }
155 }
156
157 up_read(&asymmetric_key_parsers_sem);
158 pr_devel("<==%s() = %d\n", __func__, ret);
159 return ret;
160}
161
162/*
163 * Clean up the preparse data
164 */
165static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
166{
167 struct asymmetric_key_subtype *subtype = prep->type_data[0];
168
169 pr_devel("==>%s()\n", __func__);
170
171 if (subtype) {
David Howellsfc7c70e2014-07-18 18:56:34 +0100172 subtype->destroy(prep->payload[0]);
David Howells46c6f172012-09-13 15:17:32 +0100173 module_put(subtype->owner);
174 }
175 kfree(prep->type_data[1]);
176 kfree(prep->description);
177}
178
179/*
David Howells964f3b32012-09-13 15:17:21 +0100180 * dispose of the data dangling from the corpse of a asymmetric key
181 */
182static void asymmetric_key_destroy(struct key *key)
183{
184 struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
185 if (subtype) {
186 subtype->destroy(key->payload.data);
187 module_put(subtype->owner);
188 key->type_data.p[0] = NULL;
189 }
190 kfree(key->type_data.p[1]);
191 key->type_data.p[1] = NULL;
192}
193
194struct key_type key_type_asymmetric = {
195 .name = "asymmetric",
David Howells46c6f172012-09-13 15:17:32 +0100196 .preparse = asymmetric_key_preparse,
197 .free_preparse = asymmetric_key_free_preparse,
David Howells6a09d172014-07-18 18:56:34 +0100198 .instantiate = generic_key_instantiate,
David Howells964f3b32012-09-13 15:17:21 +0100199 .match = asymmetric_key_match,
200 .destroy = asymmetric_key_destroy,
201 .describe = asymmetric_key_describe,
David Howellscd0421d2013-09-04 19:28:03 +0100202 .def_lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE,
David Howells964f3b32012-09-13 15:17:21 +0100203};
204EXPORT_SYMBOL_GPL(key_type_asymmetric);
205
David Howells46c6f172012-09-13 15:17:32 +0100206/**
207 * register_asymmetric_key_parser - Register a asymmetric key blob parser
208 * @parser: The parser to register
209 */
210int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
211{
212 struct asymmetric_key_parser *cursor;
213 int ret;
214
215 down_write(&asymmetric_key_parsers_sem);
216
217 list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
218 if (strcmp(cursor->name, parser->name) == 0) {
219 pr_err("Asymmetric key parser '%s' already registered\n",
220 parser->name);
221 ret = -EEXIST;
222 goto out;
223 }
224 }
225
226 list_add_tail(&parser->link, &asymmetric_key_parsers);
227
228 pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
229 ret = 0;
230
231out:
232 up_write(&asymmetric_key_parsers_sem);
233 return ret;
234}
235EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
236
237/**
238 * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
239 * @parser: The parser to unregister
240 */
241void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
242{
243 down_write(&asymmetric_key_parsers_sem);
244 list_del(&parser->link);
245 up_write(&asymmetric_key_parsers_sem);
246
247 pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
248}
249EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
250
David Howells964f3b32012-09-13 15:17:21 +0100251/*
252 * Module stuff
253 */
254static int __init asymmetric_key_init(void)
255{
256 return register_key_type(&key_type_asymmetric);
257}
258
259static void __exit asymmetric_key_cleanup(void)
260{
261 unregister_key_type(&key_type_asymmetric);
262}
263
264module_init(asymmetric_key_init);
265module_exit(asymmetric_key_cleanup);