]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - crypto/asymmetric_keys/asymmetric_type.c
KEYS: Update the keyrings documentation for match changes
[mirror_ubuntu-artful-kernel.git] / crypto / asymmetric_keys / asymmetric_type.c
CommitLineData
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
20MODULE_LICENSE("GPL");
21
46c6f177
DH
22static LIST_HEAD(asymmetric_key_parsers);
23static DECLARE_RWSEM(asymmetric_key_parsers_sem);
24
b3426827
DK
25/*
26 * 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}
ffb70f61 52EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
b3426827 53
964f3b3b
DH
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 */
0c903ab6
DH
62static bool asymmetric_key_cmp(const struct key *key,
63 const struct key_match_data *match_data)
964f3b3b
DH
64{
65 const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
46291959 66 const char *description = match_data->raw_data;
964f3b3b 67 const char *spec = description;
b3426827 68 const char *id;
964f3b3b 69 ptrdiff_t speclen;
964f3b3b
DH
70
71 if (!subtype || !spec || !*spec)
72 return 0;
73
74 /* See if the full key description matches as is */
75 if (key->description && strcmp(key->description, description) == 0)
76 return 1;
77
78 /* All tests from here on break the criterion description into a
79 * specifier, a colon and then an identifier.
80 */
81 id = strchr(spec, ':');
82 if (!id)
83 return 0;
84
85 speclen = id - spec;
86 id++;
87
b3426827
DK
88 if (speclen == 2 && memcmp(spec, "id", 2) == 0)
89 return asymmetric_keyid_match(asymmetric_key_id(key), id);
964f3b3b
DH
90
91 if (speclen == subtype->name_len &&
92 memcmp(spec, subtype->name, speclen) == 0)
93 return 1;
94
95 return 0;
96}
97
46291959
DH
98/*
99 * Preparse the match criterion. If we don't set lookup_type and cmp,
100 * the default will be an exact match on the key description.
101 *
102 * There are some specifiers for matching key IDs rather than by the key
103 * description:
104 *
105 * "id:<id>" - request a key by any available ID
106 *
107 * These have to be searched by iteration rather than by direct lookup because
108 * the key is hashed according to its description.
109 */
110static int asymmetric_key_match_preparse(struct key_match_data *match_data)
111{
112 match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
c06cfb08 113 match_data->cmp = asymmetric_key_cmp;
46291959
DH
114 return 0;
115}
116
117/*
118 * Free the preparsed the match criterion.
119 */
120static void asymmetric_key_match_free(struct key_match_data *match_data)
121{
122}
123
964f3b3b
DH
124/*
125 * Describe the asymmetric key
126 */
127static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
128{
129 const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
130 const char *kid = asymmetric_key_id(key);
131 size_t n;
132
133 seq_puts(m, key->description);
134
135 if (subtype) {
136 seq_puts(m, ": ");
137 subtype->describe(key, m);
138
139 if (kid) {
140 seq_putc(m, ' ');
141 n = strlen(kid);
142 if (n <= 8)
143 seq_puts(m, kid);
144 else
145 seq_puts(m, kid + n - 8);
146 }
147
148 seq_puts(m, " [");
149 /* put something here to indicate the key's capabilities */
150 seq_putc(m, ']');
151 }
152}
153
46c6f177
DH
154/*
155 * Preparse a asymmetric payload to get format the contents appropriately for the
156 * internal payload to cut down on the number of scans of the data performed.
157 *
158 * We also generate a proposed description from the contents of the key that
159 * can be used to name the key if the user doesn't want to provide one.
160 */
161static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
162{
163 struct asymmetric_key_parser *parser;
164 int ret;
165
166 pr_devel("==>%s()\n", __func__);
167
168 if (prep->datalen == 0)
169 return -EINVAL;
170
171 down_read(&asymmetric_key_parsers_sem);
172
173 ret = -EBADMSG;
174 list_for_each_entry(parser, &asymmetric_key_parsers, link) {
175 pr_debug("Trying parser '%s'\n", parser->name);
176
177 ret = parser->parse(prep);
178 if (ret != -EBADMSG) {
179 pr_debug("Parser recognised the format (ret %d)\n",
180 ret);
181 break;
182 }
183 }
184
185 up_read(&asymmetric_key_parsers_sem);
186 pr_devel("<==%s() = %d\n", __func__, ret);
187 return ret;
188}
189
190/*
191 * Clean up the preparse data
192 */
193static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
194{
195 struct asymmetric_key_subtype *subtype = prep->type_data[0];
196
197 pr_devel("==>%s()\n", __func__);
198
199 if (subtype) {
fc7c70e0 200 subtype->destroy(prep->payload[0]);
46c6f177
DH
201 module_put(subtype->owner);
202 }
203 kfree(prep->type_data[1]);
204 kfree(prep->description);
205}
206
964f3b3b
DH
207/*
208 * dispose of the data dangling from the corpse of a asymmetric key
209 */
210static void asymmetric_key_destroy(struct key *key)
211{
212 struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
213 if (subtype) {
214 subtype->destroy(key->payload.data);
215 module_put(subtype->owner);
216 key->type_data.p[0] = NULL;
217 }
218 kfree(key->type_data.p[1]);
219 key->type_data.p[1] = NULL;
220}
221
222struct key_type key_type_asymmetric = {
223 .name = "asymmetric",
46c6f177
DH
224 .preparse = asymmetric_key_preparse,
225 .free_preparse = asymmetric_key_free_preparse,
6a09d17b 226 .instantiate = generic_key_instantiate,
46291959 227 .match_preparse = asymmetric_key_match_preparse,
46291959 228 .match_free = asymmetric_key_match_free,
964f3b3b
DH
229 .destroy = asymmetric_key_destroy,
230 .describe = asymmetric_key_describe,
231};
232EXPORT_SYMBOL_GPL(key_type_asymmetric);
233
46c6f177
DH
234/**
235 * register_asymmetric_key_parser - Register a asymmetric key blob parser
236 * @parser: The parser to register
237 */
238int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
239{
240 struct asymmetric_key_parser *cursor;
241 int ret;
242
243 down_write(&asymmetric_key_parsers_sem);
244
245 list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
246 if (strcmp(cursor->name, parser->name) == 0) {
247 pr_err("Asymmetric key parser '%s' already registered\n",
248 parser->name);
249 ret = -EEXIST;
250 goto out;
251 }
252 }
253
254 list_add_tail(&parser->link, &asymmetric_key_parsers);
255
256 pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
257 ret = 0;
258
259out:
260 up_write(&asymmetric_key_parsers_sem);
261 return ret;
262}
263EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
264
265/**
266 * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
267 * @parser: The parser to unregister
268 */
269void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
270{
271 down_write(&asymmetric_key_parsers_sem);
272 list_del(&parser->link);
273 up_write(&asymmetric_key_parsers_sem);
274
275 pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
276}
277EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
278
964f3b3b
DH
279/*
280 * Module stuff
281 */
282static int __init asymmetric_key_init(void)
283{
284 return register_key_type(&key_type_asymmetric);
285}
286
287static void __exit asymmetric_key_cleanup(void)
288{
289 unregister_key_type(&key_type_asymmetric);
290}
291
292module_init(asymmetric_key_init);
293module_exit(asymmetric_key_cleanup);