]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - crypto/asymmetric_keys/asymmetric_type.c
Merge tag 'nfs-for-3.17-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[mirror_ubuntu-zesty-kernel.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 "asymmetric_keys.h"
19
20 MODULE_LICENSE("GPL");
21
22 static LIST_HEAD(asymmetric_key_parsers);
23 static DECLARE_RWSEM(asymmetric_key_parsers_sem);
24
25 /*
26 * Match asymmetric key id with partial match
27 * @id: key id to match in a form "id:<id>"
28 */
29 int 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 }
52 EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
53
54 /*
55 * 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 */
62 static 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;
66 const char *id;
67 ptrdiff_t speclen;
68
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
86 if (speclen == 2 && memcmp(spec, "id", 2) == 0)
87 return asymmetric_keyid_match(asymmetric_key_id(key), id);
88
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 */
99 static 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 /*
127 * 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 */
133 static 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 */
165 static 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) {
172 subtype->destroy(prep->payload[0]);
173 module_put(subtype->owner);
174 }
175 kfree(prep->type_data[1]);
176 kfree(prep->description);
177 }
178
179 /*
180 * dispose of the data dangling from the corpse of a asymmetric key
181 */
182 static 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
194 struct key_type key_type_asymmetric = {
195 .name = "asymmetric",
196 .preparse = asymmetric_key_preparse,
197 .free_preparse = asymmetric_key_free_preparse,
198 .instantiate = generic_key_instantiate,
199 .match = asymmetric_key_match,
200 .destroy = asymmetric_key_destroy,
201 .describe = asymmetric_key_describe,
202 .def_lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE,
203 };
204 EXPORT_SYMBOL_GPL(key_type_asymmetric);
205
206 /**
207 * register_asymmetric_key_parser - Register a asymmetric key blob parser
208 * @parser: The parser to register
209 */
210 int 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
231 out:
232 up_write(&asymmetric_key_parsers_sem);
233 return ret;
234 }
235 EXPORT_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 */
241 void 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 }
249 EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
250
251 /*
252 * Module stuff
253 */
254 static int __init asymmetric_key_init(void)
255 {
256 return register_key_type(&key_type_asymmetric);
257 }
258
259 static void __exit asymmetric_key_cleanup(void)
260 {
261 unregister_key_type(&key_type_asymmetric);
262 }
263
264 module_init(asymmetric_key_init);
265 module_exit(asymmetric_key_cleanup);