drivers: power: report battery voltage in AOSP compatible format
[GitHub/mt8127/android_kernel_alcatel_ttab.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
964f3b3b
DH
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 */
33static int asymmetric_key_match(const struct key *key, const void *description)
34{
35 const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
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 */
86static 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
46c6f177
DH
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 */
120static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
121{
122 struct asymmetric_key_parser *parser;
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 */
152static 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
964f3b3b
DH
166/*
167 * Instantiate a asymmetric_key defined key. The key was preparsed, so we just
168 * have to transfer the data here.
169 */
170static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
171{
46c6f177
DH
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;
964f3b3b
DH
187}
188
189/*
190 * dispose of the data dangling from the corpse of a asymmetric key
191 */
192static 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
204struct key_type key_type_asymmetric = {
205 .name = "asymmetric",
46c6f177
DH
206 .preparse = asymmetric_key_preparse,
207 .free_preparse = asymmetric_key_free_preparse,
964f3b3b
DH
208 .instantiate = asymmetric_key_instantiate,
209 .match = asymmetric_key_match,
210 .destroy = asymmetric_key_destroy,
211 .describe = asymmetric_key_describe,
212};
213EXPORT_SYMBOL_GPL(key_type_asymmetric);
214
46c6f177
DH
215/**
216 * register_asymmetric_key_parser - Register a asymmetric key blob parser
217 * @parser: The parser to register
218 */
219int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
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
240out:
241 up_write(&asymmetric_key_parsers_sem);
242 return ret;
243}
244EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
245
246/**
247 * unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
248 * @parser: The parser to unregister
249 */
250void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
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}
258EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
259
964f3b3b
DH
260/*
261 * Module stuff
262 */
263static int __init asymmetric_key_init(void)
264{
265 return register_key_type(&key_type_asymmetric);
266}
267
268static void __exit asymmetric_key_cleanup(void)
269{
270 unregister_key_type(&key_type_asymmetric);
271}
272
273module_init(asymmetric_key_init);
274module_exit(asymmetric_key_cleanup);