Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
asymmetric_type.c
Go to the documentation of this file.
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 ([email protected])
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  */
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 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 {
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 
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 {
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 
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 {
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;
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",
206  .preparse = asymmetric_key_preparse,
207  .free_preparse = asymmetric_key_free_preparse,
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 
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 }
245 
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 }
259 
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);