diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /crypto/asymmetric_keys | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'crypto/asymmetric_keys')
-rw-r--r-- | crypto/asymmetric_keys/Kconfig | 38 | ||||
-rw-r--r-- | crypto/asymmetric_keys/Makefile | 27 | ||||
-rw-r--r-- | crypto/asymmetric_keys/asymmetric_keys.h | 15 | ||||
-rw-r--r-- | crypto/asymmetric_keys/asymmetric_type.c | 274 | ||||
-rw-r--r-- | crypto/asymmetric_keys/public_key.c | 108 | ||||
-rw-r--r-- | crypto/asymmetric_keys/public_key.h | 30 | ||||
-rw-r--r-- | crypto/asymmetric_keys/rsa.c | 277 | ||||
-rw-r--r-- | crypto/asymmetric_keys/signature.c | 49 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509.asn1 | 60 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_cert_parser.c | 496 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_parser.h | 36 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 239 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_rsakey.asn1 | 4 |
13 files changed, 0 insertions, 1653 deletions
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig deleted file mode 100644 index 6d2c2ea1255..00000000000 --- a/crypto/asymmetric_keys/Kconfig +++ /dev/null | |||
@@ -1,38 +0,0 @@ | |||
1 | menuconfig ASYMMETRIC_KEY_TYPE | ||
2 | tristate "Asymmetric (public-key cryptographic) key type" | ||
3 | depends on KEYS | ||
4 | help | ||
5 | This option provides support for a key type that holds the data for | ||
6 | the asymmetric keys used for public key cryptographic operations such | ||
7 | as encryption, decryption, signature generation and signature | ||
8 | verification. | ||
9 | |||
10 | if ASYMMETRIC_KEY_TYPE | ||
11 | |||
12 | config ASYMMETRIC_PUBLIC_KEY_SUBTYPE | ||
13 | tristate "Asymmetric public-key crypto algorithm subtype" | ||
14 | select MPILIB | ||
15 | help | ||
16 | This option provides support for asymmetric public key type handling. | ||
17 | If signature generation and/or verification are to be used, | ||
18 | appropriate hash algorithms (such as SHA-1) must be available. | ||
19 | ENOPKG will be reported if the requisite algorithm is unavailable. | ||
20 | |||
21 | config PUBLIC_KEY_ALGO_RSA | ||
22 | tristate "RSA public-key algorithm" | ||
23 | depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE | ||
24 | select MPILIB_EXTRA | ||
25 | help | ||
26 | This option enables support for the RSA algorithm (PKCS#1, RFC3447). | ||
27 | |||
28 | config X509_CERTIFICATE_PARSER | ||
29 | tristate "X.509 certificate parser" | ||
30 | depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE | ||
31 | select ASN1 | ||
32 | select OID_REGISTRY | ||
33 | help | ||
34 | This option procides support for parsing X.509 format blobs for key | ||
35 | data and provides the ability to instantiate a crypto key from a | ||
36 | public key packet found inside the certificate. | ||
37 | |||
38 | endif # ASYMMETRIC_KEY_TYPE | ||
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile deleted file mode 100644 index 0727204aab6..00000000000 --- a/crypto/asymmetric_keys/Makefile +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | # | ||
2 | # Makefile for asymmetric cryptographic keys | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o | ||
6 | |||
7 | asymmetric_keys-y := asymmetric_type.o signature.o | ||
8 | |||
9 | obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o | ||
10 | obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o | ||
11 | |||
12 | # | ||
13 | # X.509 Certificate handling | ||
14 | # | ||
15 | obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o | ||
16 | x509_key_parser-y := \ | ||
17 | x509-asn1.o \ | ||
18 | x509_rsakey-asn1.o \ | ||
19 | x509_cert_parser.o \ | ||
20 | x509_public_key.o | ||
21 | |||
22 | $(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h | ||
23 | $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h | ||
24 | $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h | ||
25 | |||
26 | clean-files += x509-asn1.c x509-asn1.h | ||
27 | clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h | ||
diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h deleted file mode 100644 index 515b6343081..00000000000 --- a/crypto/asymmetric_keys/asymmetric_keys.h +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | /* Internal definitions for asymmetric key type | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | static inline const char *asymmetric_key_id(const struct key *key) | ||
13 | { | ||
14 | return key->type_data.p[1]; | ||
15 | } | ||
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c deleted file mode 100644 index cf807654d22..00000000000 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ /dev/null | |||
@@ -1,274 +0,0 @@ | |||
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 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 | { | ||
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 | */ | ||
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 | { | ||
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 | */ | ||
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 | |||
215 | /** | ||
216 | * register_asymmetric_key_parser - Register a asymmetric key blob parser | ||
217 | * @parser: The parser to register | ||
218 | */ | ||
219 | int 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 | |||
240 | out: | ||
241 | up_write(&asymmetric_key_parsers_sem); | ||
242 | return ret; | ||
243 | } | ||
244 | EXPORT_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 | */ | ||
250 | void 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 | } | ||
258 | EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser); | ||
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); | ||
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c deleted file mode 100644 index cb2e29180a8..00000000000 --- a/crypto/asymmetric_keys/public_key.c +++ /dev/null | |||
@@ -1,108 +0,0 @@ | |||
1 | /* In-software asymmetric public-key crypto subtype | ||
2 | * | ||
3 | * See Documentation/crypto/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 | |||
14 | #define pr_fmt(fmt) "PKEY: "fmt | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/export.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/seq_file.h> | ||
20 | #include <keys/asymmetric-subtype.h> | ||
21 | #include "public_key.h" | ||
22 | |||
23 | MODULE_LICENSE("GPL"); | ||
24 | |||
25 | const char *const pkey_algo[PKEY_ALGO__LAST] = { | ||
26 | [PKEY_ALGO_DSA] = "DSA", | ||
27 | [PKEY_ALGO_RSA] = "RSA", | ||
28 | }; | ||
29 | EXPORT_SYMBOL_GPL(pkey_algo); | ||
30 | |||
31 | const char *const pkey_hash_algo[PKEY_HASH__LAST] = { | ||
32 | [PKEY_HASH_MD4] = "md4", | ||
33 | [PKEY_HASH_MD5] = "md5", | ||
34 | [PKEY_HASH_SHA1] = "sha1", | ||
35 | [PKEY_HASH_RIPE_MD_160] = "rmd160", | ||
36 | [PKEY_HASH_SHA256] = "sha256", | ||
37 | [PKEY_HASH_SHA384] = "sha384", | ||
38 | [PKEY_HASH_SHA512] = "sha512", | ||
39 | [PKEY_HASH_SHA224] = "sha224", | ||
40 | }; | ||
41 | EXPORT_SYMBOL_GPL(pkey_hash_algo); | ||
42 | |||
43 | const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = { | ||
44 | [PKEY_ID_PGP] = "PGP", | ||
45 | [PKEY_ID_X509] = "X509", | ||
46 | }; | ||
47 | EXPORT_SYMBOL_GPL(pkey_id_type); | ||
48 | |||
49 | /* | ||
50 | * Provide a part of a description of the key for /proc/keys. | ||
51 | */ | ||
52 | static void public_key_describe(const struct key *asymmetric_key, | ||
53 | struct seq_file *m) | ||
54 | { | ||
55 | struct public_key *key = asymmetric_key->payload.data; | ||
56 | |||
57 | if (key) | ||
58 | seq_printf(m, "%s.%s", | ||
59 | pkey_id_type[key->id_type], key->algo->name); | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * Destroy a public key algorithm key. | ||
64 | */ | ||
65 | void public_key_destroy(void *payload) | ||
66 | { | ||
67 | struct public_key *key = payload; | ||
68 | int i; | ||
69 | |||
70 | if (key) { | ||
71 | for (i = 0; i < ARRAY_SIZE(key->mpi); i++) | ||
72 | mpi_free(key->mpi[i]); | ||
73 | kfree(key); | ||
74 | } | ||
75 | } | ||
76 | EXPORT_SYMBOL_GPL(public_key_destroy); | ||
77 | |||
78 | /* | ||
79 | * Verify a signature using a public key. | ||
80 | */ | ||
81 | static int public_key_verify_signature(const struct key *key, | ||
82 | const struct public_key_signature *sig) | ||
83 | { | ||
84 | const struct public_key *pk = key->payload.data; | ||
85 | |||
86 | if (!pk->algo->verify_signature) | ||
87 | return -ENOTSUPP; | ||
88 | |||
89 | if (sig->nr_mpi != pk->algo->n_sig_mpi) { | ||
90 | pr_debug("Signature has %u MPI not %u\n", | ||
91 | sig->nr_mpi, pk->algo->n_sig_mpi); | ||
92 | return -EINVAL; | ||
93 | } | ||
94 | |||
95 | return pk->algo->verify_signature(pk, sig); | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * Public key algorithm asymmetric key subtype | ||
100 | */ | ||
101 | struct asymmetric_key_subtype public_key_subtype = { | ||
102 | .owner = THIS_MODULE, | ||
103 | .name = "public_key", | ||
104 | .describe = public_key_describe, | ||
105 | .destroy = public_key_destroy, | ||
106 | .verify_signature = public_key_verify_signature, | ||
107 | }; | ||
108 | EXPORT_SYMBOL_GPL(public_key_subtype); | ||
diff --git a/crypto/asymmetric_keys/public_key.h b/crypto/asymmetric_keys/public_key.h deleted file mode 100644 index 5e5e3562689..00000000000 --- a/crypto/asymmetric_keys/public_key.h +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | /* Public key algorithm internals | ||
2 | * | ||
3 | * See Documentation/crypto/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 | |||
14 | #include <crypto/public_key.h> | ||
15 | |||
16 | extern struct asymmetric_key_subtype public_key_subtype; | ||
17 | |||
18 | /* | ||
19 | * Public key algorithm definition. | ||
20 | */ | ||
21 | struct public_key_algorithm { | ||
22 | const char *name; | ||
23 | u8 n_pub_mpi; /* Number of MPIs in public key */ | ||
24 | u8 n_sec_mpi; /* Number of MPIs in secret key */ | ||
25 | u8 n_sig_mpi; /* Number of MPIs in a signature */ | ||
26 | int (*verify_signature)(const struct public_key *key, | ||
27 | const struct public_key_signature *sig); | ||
28 | }; | ||
29 | |||
30 | extern const struct public_key_algorithm RSA_public_key_algorithm; | ||
diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c deleted file mode 100644 index 4a6a0696f8a..00000000000 --- a/crypto/asymmetric_keys/rsa.c +++ /dev/null | |||
@@ -1,277 +0,0 @@ | |||
1 | /* RSA asymmetric public-key algorithm [RFC3447] | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "RSA: "fmt | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include "public_key.h" | ||
17 | |||
18 | MODULE_LICENSE("GPL"); | ||
19 | MODULE_DESCRIPTION("RSA Public Key Algorithm"); | ||
20 | |||
21 | #define kenter(FMT, ...) \ | ||
22 | pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__) | ||
23 | #define kleave(FMT, ...) \ | ||
24 | pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__) | ||
25 | |||
26 | /* | ||
27 | * Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2]. | ||
28 | */ | ||
29 | static const u8 RSA_digest_info_MD5[] = { | ||
30 | 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, | ||
31 | 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */ | ||
32 | 0x05, 0x00, 0x04, 0x10 | ||
33 | }; | ||
34 | |||
35 | static const u8 RSA_digest_info_SHA1[] = { | ||
36 | 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, | ||
37 | 0x2B, 0x0E, 0x03, 0x02, 0x1A, | ||
38 | 0x05, 0x00, 0x04, 0x14 | ||
39 | }; | ||
40 | |||
41 | static const u8 RSA_digest_info_RIPE_MD_160[] = { | ||
42 | 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, | ||
43 | 0x2B, 0x24, 0x03, 0x02, 0x01, | ||
44 | 0x05, 0x00, 0x04, 0x14 | ||
45 | }; | ||
46 | |||
47 | static const u8 RSA_digest_info_SHA224[] = { | ||
48 | 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, | ||
49 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, | ||
50 | 0x05, 0x00, 0x04, 0x1C | ||
51 | }; | ||
52 | |||
53 | static const u8 RSA_digest_info_SHA256[] = { | ||
54 | 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, | ||
55 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, | ||
56 | 0x05, 0x00, 0x04, 0x20 | ||
57 | }; | ||
58 | |||
59 | static const u8 RSA_digest_info_SHA384[] = { | ||
60 | 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, | ||
61 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, | ||
62 | 0x05, 0x00, 0x04, 0x30 | ||
63 | }; | ||
64 | |||
65 | static const u8 RSA_digest_info_SHA512[] = { | ||
66 | 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, | ||
67 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, | ||
68 | 0x05, 0x00, 0x04, 0x40 | ||
69 | }; | ||
70 | |||
71 | static const struct { | ||
72 | const u8 *data; | ||
73 | size_t size; | ||
74 | } RSA_ASN1_templates[PKEY_HASH__LAST] = { | ||
75 | #define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) } | ||
76 | [PKEY_HASH_MD5] = _(MD5), | ||
77 | [PKEY_HASH_SHA1] = _(SHA1), | ||
78 | [PKEY_HASH_RIPE_MD_160] = _(RIPE_MD_160), | ||
79 | [PKEY_HASH_SHA256] = _(SHA256), | ||
80 | [PKEY_HASH_SHA384] = _(SHA384), | ||
81 | [PKEY_HASH_SHA512] = _(SHA512), | ||
82 | [PKEY_HASH_SHA224] = _(SHA224), | ||
83 | #undef _ | ||
84 | }; | ||
85 | |||
86 | /* | ||
87 | * RSAVP1() function [RFC3447 sec 5.2.2] | ||
88 | */ | ||
89 | static int RSAVP1(const struct public_key *key, MPI s, MPI *_m) | ||
90 | { | ||
91 | MPI m; | ||
92 | int ret; | ||
93 | |||
94 | /* (1) Validate 0 <= s < n */ | ||
95 | if (mpi_cmp_ui(s, 0) < 0) { | ||
96 | kleave(" = -EBADMSG [s < 0]"); | ||
97 | return -EBADMSG; | ||
98 | } | ||
99 | if (mpi_cmp(s, key->rsa.n) >= 0) { | ||
100 | kleave(" = -EBADMSG [s >= n]"); | ||
101 | return -EBADMSG; | ||
102 | } | ||
103 | |||
104 | m = mpi_alloc(0); | ||
105 | if (!m) | ||
106 | return -ENOMEM; | ||
107 | |||
108 | /* (2) m = s^e mod n */ | ||
109 | ret = mpi_powm(m, s, key->rsa.e, key->rsa.n); | ||
110 | if (ret < 0) { | ||
111 | mpi_free(m); | ||
112 | return ret; | ||
113 | } | ||
114 | |||
115 | *_m = m; | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * Integer to Octet String conversion [RFC3447 sec 4.1] | ||
121 | */ | ||
122 | static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X) | ||
123 | { | ||
124 | unsigned X_size, x_size; | ||
125 | int X_sign; | ||
126 | u8 *X; | ||
127 | |||
128 | /* Make sure the string is the right length. The number should begin | ||
129 | * with { 0x00, 0x01, ... } so we have to account for 15 leading zero | ||
130 | * bits not being reported by MPI. | ||
131 | */ | ||
132 | x_size = mpi_get_nbits(x); | ||
133 | pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8); | ||
134 | if (x_size != xLen * 8 - 15) | ||
135 | return -ERANGE; | ||
136 | |||
137 | X = mpi_get_buffer(x, &X_size, &X_sign); | ||
138 | if (!X) | ||
139 | return -ENOMEM; | ||
140 | if (X_sign < 0) { | ||
141 | kfree(X); | ||
142 | return -EBADMSG; | ||
143 | } | ||
144 | if (X_size != xLen - 1) { | ||
145 | kfree(X); | ||
146 | return -EBADMSG; | ||
147 | } | ||
148 | |||
149 | *_X = X; | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | /* | ||
154 | * Perform the RSA signature verification. | ||
155 | * @H: Value of hash of data and metadata | ||
156 | * @EM: The computed signature value | ||
157 | * @k: The size of EM (EM[0] is an invalid location but should hold 0x00) | ||
158 | * @hash_size: The size of H | ||
159 | * @asn1_template: The DigestInfo ASN.1 template | ||
160 | * @asn1_size: Size of asm1_template[] | ||
161 | */ | ||
162 | static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size, | ||
163 | const u8 *asn1_template, size_t asn1_size) | ||
164 | { | ||
165 | unsigned PS_end, T_offset, i; | ||
166 | |||
167 | kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size); | ||
168 | |||
169 | if (k < 2 + 1 + asn1_size + hash_size) | ||
170 | return -EBADMSG; | ||
171 | |||
172 | /* Decode the EMSA-PKCS1-v1_5 */ | ||
173 | if (EM[1] != 0x01) { | ||
174 | kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]); | ||
175 | return -EBADMSG; | ||
176 | } | ||
177 | |||
178 | T_offset = k - (asn1_size + hash_size); | ||
179 | PS_end = T_offset - 1; | ||
180 | if (EM[PS_end] != 0x00) { | ||
181 | kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]); | ||
182 | return -EBADMSG; | ||
183 | } | ||
184 | |||
185 | for (i = 2; i < PS_end; i++) { | ||
186 | if (EM[i] != 0xff) { | ||
187 | kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]); | ||
188 | return -EBADMSG; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) { | ||
193 | kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]"); | ||
194 | return -EBADMSG; | ||
195 | } | ||
196 | |||
197 | if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) { | ||
198 | kleave(" = -EKEYREJECTED [EM[T] hash mismatch]"); | ||
199 | return -EKEYREJECTED; | ||
200 | } | ||
201 | |||
202 | kleave(" = 0"); | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | /* | ||
207 | * Perform the verification step [RFC3447 sec 8.2.2]. | ||
208 | */ | ||
209 | static int RSA_verify_signature(const struct public_key *key, | ||
210 | const struct public_key_signature *sig) | ||
211 | { | ||
212 | size_t tsize; | ||
213 | int ret; | ||
214 | |||
215 | /* Variables as per RFC3447 sec 8.2.2 */ | ||
216 | const u8 *H = sig->digest; | ||
217 | u8 *EM = NULL; | ||
218 | MPI m = NULL; | ||
219 | size_t k; | ||
220 | |||
221 | kenter(""); | ||
222 | |||
223 | if (!RSA_ASN1_templates[sig->pkey_hash_algo].data) | ||
224 | return -ENOTSUPP; | ||
225 | |||
226 | /* (1) Check the signature size against the public key modulus size */ | ||
227 | k = mpi_get_nbits(key->rsa.n); | ||
228 | tsize = mpi_get_nbits(sig->rsa.s); | ||
229 | |||
230 | /* According to RFC 4880 sec 3.2, length of MPI is computed starting | ||
231 | * from most significant bit. So the RFC 3447 sec 8.2.2 size check | ||
232 | * must be relaxed to conform with shorter signatures - so we fail here | ||
233 | * only if signature length is longer than modulus size. | ||
234 | */ | ||
235 | pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize); | ||
236 | if (k < tsize) { | ||
237 | ret = -EBADMSG; | ||
238 | goto error; | ||
239 | } | ||
240 | |||
241 | /* Round up and convert to octets */ | ||
242 | k = (k + 7) / 8; | ||
243 | |||
244 | /* (2b) Apply the RSAVP1 verification primitive to the public key */ | ||
245 | ret = RSAVP1(key, sig->rsa.s, &m); | ||
246 | if (ret < 0) | ||
247 | goto error; | ||
248 | |||
249 | /* (2c) Convert the message representative (m) to an encoded message | ||
250 | * (EM) of length k octets. | ||
251 | * | ||
252 | * NOTE! The leading zero byte is suppressed by MPI, so we pass a | ||
253 | * pointer to the _preceding_ byte to RSA_verify()! | ||
254 | */ | ||
255 | ret = RSA_I2OSP(m, k, &EM); | ||
256 | if (ret < 0) | ||
257 | goto error; | ||
258 | |||
259 | ret = RSA_verify(H, EM - 1, k, sig->digest_size, | ||
260 | RSA_ASN1_templates[sig->pkey_hash_algo].data, | ||
261 | RSA_ASN1_templates[sig->pkey_hash_algo].size); | ||
262 | |||
263 | error: | ||
264 | kfree(EM); | ||
265 | mpi_free(m); | ||
266 | kleave(" = %d", ret); | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | const struct public_key_algorithm RSA_public_key_algorithm = { | ||
271 | .name = "RSA", | ||
272 | .n_pub_mpi = 2, | ||
273 | .n_sec_mpi = 3, | ||
274 | .n_sig_mpi = 1, | ||
275 | .verify_signature = RSA_verify_signature, | ||
276 | }; | ||
277 | EXPORT_SYMBOL_GPL(RSA_public_key_algorithm); | ||
diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c deleted file mode 100644 index 50b3f880b4f..00000000000 --- a/crypto/asymmetric_keys/signature.c +++ /dev/null | |||
@@ -1,49 +0,0 @@ | |||
1 | /* Signature verification with an asymmetric key | ||
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 | |||
14 | #include <keys/asymmetric-subtype.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <crypto/public_key.h> | ||
18 | #include "asymmetric_keys.h" | ||
19 | |||
20 | /** | ||
21 | * verify_signature - Initiate the use of an asymmetric key to verify a signature | ||
22 | * @key: The asymmetric key to verify against | ||
23 | * @sig: The signature to check | ||
24 | * | ||
25 | * Returns 0 if successful or else an error. | ||
26 | */ | ||
27 | int verify_signature(const struct key *key, | ||
28 | const struct public_key_signature *sig) | ||
29 | { | ||
30 | const struct asymmetric_key_subtype *subtype; | ||
31 | int ret; | ||
32 | |||
33 | pr_devel("==>%s()\n", __func__); | ||
34 | |||
35 | if (key->type != &key_type_asymmetric) | ||
36 | return -EINVAL; | ||
37 | subtype = asymmetric_key_subtype(key); | ||
38 | if (!subtype || | ||
39 | !key->payload.data) | ||
40 | return -EINVAL; | ||
41 | if (!subtype->verify_signature) | ||
42 | return -ENOTSUPP; | ||
43 | |||
44 | ret = subtype->verify_signature(key, sig); | ||
45 | |||
46 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
47 | return ret; | ||
48 | } | ||
49 | EXPORT_SYMBOL_GPL(verify_signature); | ||
diff --git a/crypto/asymmetric_keys/x509.asn1 b/crypto/asymmetric_keys/x509.asn1 deleted file mode 100644 index bf32b3dff08..00000000000 --- a/crypto/asymmetric_keys/x509.asn1 +++ /dev/null | |||
@@ -1,60 +0,0 @@ | |||
1 | Certificate ::= SEQUENCE { | ||
2 | tbsCertificate TBSCertificate ({ x509_note_tbs_certificate }), | ||
3 | signatureAlgorithm AlgorithmIdentifier, | ||
4 | signature BIT STRING ({ x509_note_signature }) | ||
5 | } | ||
6 | |||
7 | TBSCertificate ::= SEQUENCE { | ||
8 | version [ 0 ] Version DEFAULT, | ||
9 | serialNumber CertificateSerialNumber, | ||
10 | signature AlgorithmIdentifier ({ x509_note_pkey_algo }), | ||
11 | issuer Name ({ x509_note_issuer }), | ||
12 | validity Validity, | ||
13 | subject Name ({ x509_note_subject }), | ||
14 | subjectPublicKeyInfo SubjectPublicKeyInfo, | ||
15 | issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL, | ||
16 | subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL, | ||
17 | extensions [ 3 ] Extensions OPTIONAL | ||
18 | } | ||
19 | |||
20 | Version ::= INTEGER | ||
21 | CertificateSerialNumber ::= INTEGER | ||
22 | |||
23 | AlgorithmIdentifier ::= SEQUENCE { | ||
24 | algorithm OBJECT IDENTIFIER ({ x509_note_OID }), | ||
25 | parameters ANY OPTIONAL | ||
26 | } | ||
27 | |||
28 | Name ::= SEQUENCE OF RelativeDistinguishedName | ||
29 | |||
30 | RelativeDistinguishedName ::= SET OF AttributeValueAssertion | ||
31 | |||
32 | AttributeValueAssertion ::= SEQUENCE { | ||
33 | attributeType OBJECT IDENTIFIER ({ x509_note_OID }), | ||
34 | attributeValue ANY ({ x509_extract_name_segment }) | ||
35 | } | ||
36 | |||
37 | Validity ::= SEQUENCE { | ||
38 | notBefore Time ({ x509_note_not_before }), | ||
39 | notAfter Time ({ x509_note_not_after }) | ||
40 | } | ||
41 | |||
42 | Time ::= CHOICE { | ||
43 | utcTime UTCTime, | ||
44 | generalTime GeneralizedTime | ||
45 | } | ||
46 | |||
47 | SubjectPublicKeyInfo ::= SEQUENCE { | ||
48 | algorithm AlgorithmIdentifier, | ||
49 | subjectPublicKey BIT STRING ({ x509_extract_key_data }) | ||
50 | } | ||
51 | |||
52 | UniqueIdentifier ::= BIT STRING | ||
53 | |||
54 | Extensions ::= SEQUENCE OF Extension | ||
55 | |||
56 | Extension ::= SEQUENCE { | ||
57 | extnid OBJECT IDENTIFIER ({ x509_note_OID }), | ||
58 | critical BOOLEAN DEFAULT, | ||
59 | extnValue OCTET STRING ({ x509_process_extension }) | ||
60 | } | ||
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c deleted file mode 100644 index 7fabc4c0199..00000000000 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ /dev/null | |||
@@ -1,496 +0,0 @@ | |||
1 | /* X.509 certificate parser | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "X.509: "fmt | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/oid_registry.h> | ||
17 | #include "public_key.h" | ||
18 | #include "x509_parser.h" | ||
19 | #include "x509-asn1.h" | ||
20 | #include "x509_rsakey-asn1.h" | ||
21 | |||
22 | struct x509_parse_context { | ||
23 | struct x509_certificate *cert; /* Certificate being constructed */ | ||
24 | unsigned long data; /* Start of data */ | ||
25 | const void *cert_start; /* Start of cert content */ | ||
26 | const void *key; /* Key data */ | ||
27 | size_t key_size; /* Size of key data */ | ||
28 | enum OID last_oid; /* Last OID encountered */ | ||
29 | enum OID algo_oid; /* Algorithm OID */ | ||
30 | unsigned char nr_mpi; /* Number of MPIs stored */ | ||
31 | u8 o_size; /* Size of organizationName (O) */ | ||
32 | u8 cn_size; /* Size of commonName (CN) */ | ||
33 | u8 email_size; /* Size of emailAddress */ | ||
34 | u16 o_offset; /* Offset of organizationName (O) */ | ||
35 | u16 cn_offset; /* Offset of commonName (CN) */ | ||
36 | u16 email_offset; /* Offset of emailAddress */ | ||
37 | }; | ||
38 | |||
39 | /* | ||
40 | * Free an X.509 certificate | ||
41 | */ | ||
42 | void x509_free_certificate(struct x509_certificate *cert) | ||
43 | { | ||
44 | if (cert) { | ||
45 | public_key_destroy(cert->pub); | ||
46 | kfree(cert->issuer); | ||
47 | kfree(cert->subject); | ||
48 | kfree(cert->fingerprint); | ||
49 | kfree(cert->authority); | ||
50 | kfree(cert); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | /* | ||
55 | * Parse an X.509 certificate | ||
56 | */ | ||
57 | struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | ||
58 | { | ||
59 | struct x509_certificate *cert; | ||
60 | struct x509_parse_context *ctx; | ||
61 | long ret; | ||
62 | |||
63 | ret = -ENOMEM; | ||
64 | cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL); | ||
65 | if (!cert) | ||
66 | goto error_no_cert; | ||
67 | cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL); | ||
68 | if (!cert->pub) | ||
69 | goto error_no_ctx; | ||
70 | ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL); | ||
71 | if (!ctx) | ||
72 | goto error_no_ctx; | ||
73 | |||
74 | ctx->cert = cert; | ||
75 | ctx->data = (unsigned long)data; | ||
76 | |||
77 | /* Attempt to decode the certificate */ | ||
78 | ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen); | ||
79 | if (ret < 0) | ||
80 | goto error_decode; | ||
81 | |||
82 | /* Decode the public key */ | ||
83 | ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx, | ||
84 | ctx->key, ctx->key_size); | ||
85 | if (ret < 0) | ||
86 | goto error_decode; | ||
87 | |||
88 | kfree(ctx); | ||
89 | return cert; | ||
90 | |||
91 | error_decode: | ||
92 | kfree(ctx); | ||
93 | error_no_ctx: | ||
94 | x509_free_certificate(cert); | ||
95 | error_no_cert: | ||
96 | return ERR_PTR(ret); | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * Note an OID when we find one for later processing when we know how | ||
101 | * to interpret it. | ||
102 | */ | ||
103 | int x509_note_OID(void *context, size_t hdrlen, | ||
104 | unsigned char tag, | ||
105 | const void *value, size_t vlen) | ||
106 | { | ||
107 | struct x509_parse_context *ctx = context; | ||
108 | |||
109 | ctx->last_oid = look_up_OID(value, vlen); | ||
110 | if (ctx->last_oid == OID__NR) { | ||
111 | char buffer[50]; | ||
112 | sprint_oid(value, vlen, buffer, sizeof(buffer)); | ||
113 | pr_debug("Unknown OID: [%lu] %s\n", | ||
114 | (unsigned long)value - ctx->data, buffer); | ||
115 | } | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * Save the position of the TBS data so that we can check the signature over it | ||
121 | * later. | ||
122 | */ | ||
123 | int x509_note_tbs_certificate(void *context, size_t hdrlen, | ||
124 | unsigned char tag, | ||
125 | const void *value, size_t vlen) | ||
126 | { | ||
127 | struct x509_parse_context *ctx = context; | ||
128 | |||
129 | pr_debug("x509_note_tbs_certificate(,%zu,%02x,%ld,%zu)!\n", | ||
130 | hdrlen, tag, (unsigned long)value - ctx->data, vlen); | ||
131 | |||
132 | ctx->cert->tbs = value - hdrlen; | ||
133 | ctx->cert->tbs_size = vlen + hdrlen; | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * Record the public key algorithm | ||
139 | */ | ||
140 | int x509_note_pkey_algo(void *context, size_t hdrlen, | ||
141 | unsigned char tag, | ||
142 | const void *value, size_t vlen) | ||
143 | { | ||
144 | struct x509_parse_context *ctx = context; | ||
145 | |||
146 | pr_debug("PubKey Algo: %u\n", ctx->last_oid); | ||
147 | |||
148 | switch (ctx->last_oid) { | ||
149 | case OID_md2WithRSAEncryption: | ||
150 | case OID_md3WithRSAEncryption: | ||
151 | default: | ||
152 | return -ENOPKG; /* Unsupported combination */ | ||
153 | |||
154 | case OID_md4WithRSAEncryption: | ||
155 | ctx->cert->sig_hash_algo = PKEY_HASH_MD5; | ||
156 | ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; | ||
157 | break; | ||
158 | |||
159 | case OID_sha1WithRSAEncryption: | ||
160 | ctx->cert->sig_hash_algo = PKEY_HASH_SHA1; | ||
161 | ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; | ||
162 | break; | ||
163 | |||
164 | case OID_sha256WithRSAEncryption: | ||
165 | ctx->cert->sig_hash_algo = PKEY_HASH_SHA256; | ||
166 | ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; | ||
167 | break; | ||
168 | |||
169 | case OID_sha384WithRSAEncryption: | ||
170 | ctx->cert->sig_hash_algo = PKEY_HASH_SHA384; | ||
171 | ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; | ||
172 | break; | ||
173 | |||
174 | case OID_sha512WithRSAEncryption: | ||
175 | ctx->cert->sig_hash_algo = PKEY_HASH_SHA512; | ||
176 | ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; | ||
177 | break; | ||
178 | |||
179 | case OID_sha224WithRSAEncryption: | ||
180 | ctx->cert->sig_hash_algo = PKEY_HASH_SHA224; | ||
181 | ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA; | ||
182 | break; | ||
183 | } | ||
184 | |||
185 | ctx->algo_oid = ctx->last_oid; | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * Note the whereabouts and type of the signature. | ||
191 | */ | ||
192 | int x509_note_signature(void *context, size_t hdrlen, | ||
193 | unsigned char tag, | ||
194 | const void *value, size_t vlen) | ||
195 | { | ||
196 | struct x509_parse_context *ctx = context; | ||
197 | |||
198 | pr_debug("Signature type: %u size %zu\n", ctx->last_oid, vlen); | ||
199 | |||
200 | if (ctx->last_oid != ctx->algo_oid) { | ||
201 | pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n", | ||
202 | ctx->algo_oid, ctx->last_oid); | ||
203 | return -EINVAL; | ||
204 | } | ||
205 | |||
206 | ctx->cert->sig = value; | ||
207 | ctx->cert->sig_size = vlen; | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Note some of the name segments from which we'll fabricate a name. | ||
213 | */ | ||
214 | int x509_extract_name_segment(void *context, size_t hdrlen, | ||
215 | unsigned char tag, | ||
216 | const void *value, size_t vlen) | ||
217 | { | ||
218 | struct x509_parse_context *ctx = context; | ||
219 | |||
220 | switch (ctx->last_oid) { | ||
221 | case OID_commonName: | ||
222 | ctx->cn_size = vlen; | ||
223 | ctx->cn_offset = (unsigned long)value - ctx->data; | ||
224 | break; | ||
225 | case OID_organizationName: | ||
226 | ctx->o_size = vlen; | ||
227 | ctx->o_offset = (unsigned long)value - ctx->data; | ||
228 | break; | ||
229 | case OID_email_address: | ||
230 | ctx->email_size = vlen; | ||
231 | ctx->email_offset = (unsigned long)value - ctx->data; | ||
232 | break; | ||
233 | default: | ||
234 | break; | ||
235 | } | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * Fabricate and save the issuer and subject names | ||
242 | */ | ||
243 | static int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen, | ||
244 | unsigned char tag, | ||
245 | char **_name, size_t vlen) | ||
246 | { | ||
247 | const void *name, *data = (const void *)ctx->data; | ||
248 | size_t namesize; | ||
249 | char *buffer; | ||
250 | |||
251 | if (*_name) | ||
252 | return -EINVAL; | ||
253 | |||
254 | /* Empty name string if no material */ | ||
255 | if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) { | ||
256 | buffer = kmalloc(1, GFP_KERNEL); | ||
257 | if (!buffer) | ||
258 | return -ENOMEM; | ||
259 | buffer[0] = 0; | ||
260 | goto done; | ||
261 | } | ||
262 | |||
263 | if (ctx->cn_size && ctx->o_size) { | ||
264 | /* Consider combining O and CN, but use only the CN if it is | ||
265 | * prefixed by the O, or a significant portion thereof. | ||
266 | */ | ||
267 | namesize = ctx->cn_size; | ||
268 | name = data + ctx->cn_offset; | ||
269 | if (ctx->cn_size >= ctx->o_size && | ||
270 | memcmp(data + ctx->cn_offset, data + ctx->o_offset, | ||
271 | ctx->o_size) == 0) | ||
272 | goto single_component; | ||
273 | if (ctx->cn_size >= 7 && | ||
274 | ctx->o_size >= 7 && | ||
275 | memcmp(data + ctx->cn_offset, data + ctx->o_offset, 7) == 0) | ||
276 | goto single_component; | ||
277 | |||
278 | buffer = kmalloc(ctx->o_size + 2 + ctx->cn_size + 1, | ||
279 | GFP_KERNEL); | ||
280 | if (!buffer) | ||
281 | return -ENOMEM; | ||
282 | |||
283 | memcpy(buffer, | ||
284 | data + ctx->o_offset, ctx->o_size); | ||
285 | buffer[ctx->o_size + 0] = ':'; | ||
286 | buffer[ctx->o_size + 1] = ' '; | ||
287 | memcpy(buffer + ctx->o_size + 2, | ||
288 | data + ctx->cn_offset, ctx->cn_size); | ||
289 | buffer[ctx->o_size + 2 + ctx->cn_size] = 0; | ||
290 | goto done; | ||
291 | |||
292 | } else if (ctx->cn_size) { | ||
293 | namesize = ctx->cn_size; | ||
294 | name = data + ctx->cn_offset; | ||
295 | } else if (ctx->o_size) { | ||
296 | namesize = ctx->o_size; | ||
297 | name = data + ctx->o_offset; | ||
298 | } else { | ||
299 | namesize = ctx->email_size; | ||
300 | name = data + ctx->email_offset; | ||
301 | } | ||
302 | |||
303 | single_component: | ||
304 | buffer = kmalloc(namesize + 1, GFP_KERNEL); | ||
305 | if (!buffer) | ||
306 | return -ENOMEM; | ||
307 | memcpy(buffer, name, namesize); | ||
308 | buffer[namesize] = 0; | ||
309 | |||
310 | done: | ||
311 | *_name = buffer; | ||
312 | ctx->cn_size = 0; | ||
313 | ctx->o_size = 0; | ||
314 | ctx->email_size = 0; | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | int x509_note_issuer(void *context, size_t hdrlen, | ||
319 | unsigned char tag, | ||
320 | const void *value, size_t vlen) | ||
321 | { | ||
322 | struct x509_parse_context *ctx = context; | ||
323 | return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen); | ||
324 | } | ||
325 | |||
326 | int x509_note_subject(void *context, size_t hdrlen, | ||
327 | unsigned char tag, | ||
328 | const void *value, size_t vlen) | ||
329 | { | ||
330 | struct x509_parse_context *ctx = context; | ||
331 | return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen); | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * Extract the data for the public key algorithm | ||
336 | */ | ||
337 | int x509_extract_key_data(void *context, size_t hdrlen, | ||
338 | unsigned char tag, | ||
339 | const void *value, size_t vlen) | ||
340 | { | ||
341 | struct x509_parse_context *ctx = context; | ||
342 | |||
343 | if (ctx->last_oid != OID_rsaEncryption) | ||
344 | return -ENOPKG; | ||
345 | |||
346 | /* There seems to be an extraneous 0 byte on the front of the data */ | ||
347 | ctx->cert->pkey_algo = PKEY_ALGO_RSA; | ||
348 | ctx->key = value + 1; | ||
349 | ctx->key_size = vlen - 1; | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | /* | ||
354 | * Extract a RSA public key value | ||
355 | */ | ||
356 | int rsa_extract_mpi(void *context, size_t hdrlen, | ||
357 | unsigned char tag, | ||
358 | const void *value, size_t vlen) | ||
359 | { | ||
360 | struct x509_parse_context *ctx = context; | ||
361 | MPI mpi; | ||
362 | |||
363 | if (ctx->nr_mpi >= ARRAY_SIZE(ctx->cert->pub->mpi)) { | ||
364 | pr_err("Too many public key MPIs in certificate\n"); | ||
365 | return -EBADMSG; | ||
366 | } | ||
367 | |||
368 | mpi = mpi_read_raw_data(value, vlen); | ||
369 | if (!mpi) | ||
370 | return -ENOMEM; | ||
371 | |||
372 | ctx->cert->pub->mpi[ctx->nr_mpi++] = mpi; | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | /* | ||
377 | * Process certificate extensions that are used to qualify the certificate. | ||
378 | */ | ||
379 | int x509_process_extension(void *context, size_t hdrlen, | ||
380 | unsigned char tag, | ||
381 | const void *value, size_t vlen) | ||
382 | { | ||
383 | struct x509_parse_context *ctx = context; | ||
384 | const unsigned char *v = value; | ||
385 | char *f; | ||
386 | int i; | ||
387 | |||
388 | pr_debug("Extension: %u\n", ctx->last_oid); | ||
389 | |||
390 | if (ctx->last_oid == OID_subjectKeyIdentifier) { | ||
391 | /* Get hold of the key fingerprint */ | ||
392 | if (vlen < 3) | ||
393 | return -EBADMSG; | ||
394 | if (v[0] != ASN1_OTS || v[1] != vlen - 2) | ||
395 | return -EBADMSG; | ||
396 | v += 2; | ||
397 | vlen -= 2; | ||
398 | |||
399 | f = kmalloc(vlen * 2 + 1, GFP_KERNEL); | ||
400 | if (!f) | ||
401 | return -ENOMEM; | ||
402 | for (i = 0; i < vlen; i++) | ||
403 | sprintf(f + i * 2, "%02x", v[i]); | ||
404 | pr_debug("fingerprint %s\n", f); | ||
405 | ctx->cert->fingerprint = f; | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | if (ctx->last_oid == OID_authorityKeyIdentifier) { | ||
410 | /* Get hold of the CA key fingerprint */ | ||
411 | if (vlen < 5) | ||
412 | return -EBADMSG; | ||
413 | if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5)) || | ||
414 | v[1] != vlen - 2 || | ||
415 | v[2] != (ASN1_CONT << 6) || | ||
416 | v[3] != vlen - 4) | ||
417 | return -EBADMSG; | ||
418 | v += 4; | ||
419 | vlen -= 4; | ||
420 | |||
421 | f = kmalloc(vlen * 2 + 1, GFP_KERNEL); | ||
422 | if (!f) | ||
423 | return -ENOMEM; | ||
424 | for (i = 0; i < vlen; i++) | ||
425 | sprintf(f + i * 2, "%02x", v[i]); | ||
426 | pr_debug("authority %s\n", f); | ||
427 | ctx->cert->authority = f; | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | /* | ||
435 | * Record a certificate time. | ||
436 | */ | ||
437 | static int x509_note_time(struct tm *tm, size_t hdrlen, | ||
438 | unsigned char tag, | ||
439 | const unsigned char *value, size_t vlen) | ||
440 | { | ||
441 | const unsigned char *p = value; | ||
442 | |||
443 | #define dec2bin(X) ((X) - '0') | ||
444 | #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) | ||
445 | |||
446 | if (tag == ASN1_UNITIM) { | ||
447 | /* UTCTime: YYMMDDHHMMSSZ */ | ||
448 | if (vlen != 13) | ||
449 | goto unsupported_time; | ||
450 | tm->tm_year = DD2bin(p); | ||
451 | if (tm->tm_year >= 50) | ||
452 | tm->tm_year += 1900; | ||
453 | else | ||
454 | tm->tm_year += 2000; | ||
455 | } else if (tag == ASN1_GENTIM) { | ||
456 | /* GenTime: YYYYMMDDHHMMSSZ */ | ||
457 | if (vlen != 15) | ||
458 | goto unsupported_time; | ||
459 | tm->tm_year = DD2bin(p) * 100 + DD2bin(p); | ||
460 | } else { | ||
461 | goto unsupported_time; | ||
462 | } | ||
463 | |||
464 | tm->tm_year -= 1900; | ||
465 | tm->tm_mon = DD2bin(p) - 1; | ||
466 | tm->tm_mday = DD2bin(p); | ||
467 | tm->tm_hour = DD2bin(p); | ||
468 | tm->tm_min = DD2bin(p); | ||
469 | tm->tm_sec = DD2bin(p); | ||
470 | |||
471 | if (*p != 'Z') | ||
472 | goto unsupported_time; | ||
473 | |||
474 | return 0; | ||
475 | |||
476 | unsupported_time: | ||
477 | pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n", | ||
478 | tag, (int)vlen, (int)vlen, value); | ||
479 | return -EBADMSG; | ||
480 | } | ||
481 | |||
482 | int x509_note_not_before(void *context, size_t hdrlen, | ||
483 | unsigned char tag, | ||
484 | const void *value, size_t vlen) | ||
485 | { | ||
486 | struct x509_parse_context *ctx = context; | ||
487 | return x509_note_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); | ||
488 | } | ||
489 | |||
490 | int x509_note_not_after(void *context, size_t hdrlen, | ||
491 | unsigned char tag, | ||
492 | const void *value, size_t vlen) | ||
493 | { | ||
494 | struct x509_parse_context *ctx = context; | ||
495 | return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); | ||
496 | } | ||
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h deleted file mode 100644 index f86dc5fcc4a..00000000000 --- a/crypto/asymmetric_keys/x509_parser.h +++ /dev/null | |||
@@ -1,36 +0,0 @@ | |||
1 | /* X.509 certificate parser internal definitions | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <crypto/public_key.h> | ||
13 | |||
14 | struct x509_certificate { | ||
15 | struct x509_certificate *next; | ||
16 | struct public_key *pub; /* Public key details */ | ||
17 | char *issuer; /* Name of certificate issuer */ | ||
18 | char *subject; /* Name of certificate subject */ | ||
19 | char *fingerprint; /* Key fingerprint as hex */ | ||
20 | char *authority; /* Authority key fingerprint as hex */ | ||
21 | struct tm valid_from; | ||
22 | struct tm valid_to; | ||
23 | enum pkey_algo pkey_algo : 8; /* Public key algorithm */ | ||
24 | enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */ | ||
25 | enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */ | ||
26 | const void *tbs; /* Signed data */ | ||
27 | size_t tbs_size; /* Size of signed data */ | ||
28 | const void *sig; /* Signature data */ | ||
29 | size_t sig_size; /* Size of sigature */ | ||
30 | }; | ||
31 | |||
32 | /* | ||
33 | * x509_cert_parser.c | ||
34 | */ | ||
35 | extern void x509_free_certificate(struct x509_certificate *cert); | ||
36 | extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); | ||
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c deleted file mode 100644 index 06007f0e880..00000000000 --- a/crypto/asymmetric_keys/x509_public_key.c +++ /dev/null | |||
@@ -1,239 +0,0 @@ | |||
1 | /* Instantiate a public key crypto key from an X.509 Certificate | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #define pr_fmt(fmt) "X.509: "fmt | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/mpi.h> | ||
18 | #include <linux/asn1_decoder.h> | ||
19 | #include <keys/asymmetric-subtype.h> | ||
20 | #include <keys/asymmetric-parser.h> | ||
21 | #include <crypto/hash.h> | ||
22 | #include "asymmetric_keys.h" | ||
23 | #include "public_key.h" | ||
24 | #include "x509_parser.h" | ||
25 | |||
26 | static const | ||
27 | struct public_key_algorithm *x509_public_key_algorithms[PKEY_ALGO__LAST] = { | ||
28 | [PKEY_ALGO_DSA] = NULL, | ||
29 | #if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \ | ||
30 | defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE) | ||
31 | [PKEY_ALGO_RSA] = &RSA_public_key_algorithm, | ||
32 | #endif | ||
33 | }; | ||
34 | |||
35 | /* | ||
36 | * Check the signature on a certificate using the provided public key | ||
37 | */ | ||
38 | static int x509_check_signature(const struct public_key *pub, | ||
39 | const struct x509_certificate *cert) | ||
40 | { | ||
41 | struct public_key_signature *sig; | ||
42 | struct crypto_shash *tfm; | ||
43 | struct shash_desc *desc; | ||
44 | size_t digest_size, desc_size; | ||
45 | int ret; | ||
46 | |||
47 | pr_devel("==>%s()\n", __func__); | ||
48 | |||
49 | /* Allocate the hashing algorithm we're going to need and find out how | ||
50 | * big the hash operational data will be. | ||
51 | */ | ||
52 | tfm = crypto_alloc_shash(pkey_hash_algo[cert->sig_hash_algo], 0, 0); | ||
53 | if (IS_ERR(tfm)) | ||
54 | return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm); | ||
55 | |||
56 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | ||
57 | digest_size = crypto_shash_digestsize(tfm); | ||
58 | |||
59 | /* We allocate the hash operational data storage on the end of our | ||
60 | * context data. | ||
61 | */ | ||
62 | ret = -ENOMEM; | ||
63 | sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL); | ||
64 | if (!sig) | ||
65 | goto error_no_sig; | ||
66 | |||
67 | sig->pkey_hash_algo = cert->sig_hash_algo; | ||
68 | sig->digest = (u8 *)sig + sizeof(*sig) + desc_size; | ||
69 | sig->digest_size = digest_size; | ||
70 | |||
71 | desc = (void *)sig + sizeof(*sig); | ||
72 | desc->tfm = tfm; | ||
73 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
74 | |||
75 | ret = crypto_shash_init(desc); | ||
76 | if (ret < 0) | ||
77 | goto error; | ||
78 | |||
79 | ret = -ENOMEM; | ||
80 | sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size); | ||
81 | if (!sig->rsa.s) | ||
82 | goto error; | ||
83 | |||
84 | ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest); | ||
85 | if (ret < 0) | ||
86 | goto error_mpi; | ||
87 | |||
88 | ret = pub->algo->verify_signature(pub, sig); | ||
89 | |||
90 | pr_debug("Cert Verification: %d\n", ret); | ||
91 | |||
92 | error_mpi: | ||
93 | mpi_free(sig->rsa.s); | ||
94 | error: | ||
95 | kfree(sig); | ||
96 | error_no_sig: | ||
97 | crypto_free_shash(tfm); | ||
98 | |||
99 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * Attempt to parse a data blob for a key as an X509 certificate. | ||
105 | */ | ||
106 | static int x509_key_preparse(struct key_preparsed_payload *prep) | ||
107 | { | ||
108 | struct x509_certificate *cert; | ||
109 | struct tm now; | ||
110 | size_t srlen, sulen; | ||
111 | char *desc = NULL; | ||
112 | int ret; | ||
113 | |||
114 | cert = x509_cert_parse(prep->data, prep->datalen); | ||
115 | if (IS_ERR(cert)) | ||
116 | return PTR_ERR(cert); | ||
117 | |||
118 | pr_devel("Cert Issuer: %s\n", cert->issuer); | ||
119 | pr_devel("Cert Subject: %s\n", cert->subject); | ||
120 | pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]); | ||
121 | pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", | ||
122 | cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, | ||
123 | cert->valid_from.tm_mday, cert->valid_from.tm_hour, | ||
124 | cert->valid_from.tm_min, cert->valid_from.tm_sec); | ||
125 | pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n", | ||
126 | cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1, | ||
127 | cert->valid_to.tm_mday, cert->valid_to.tm_hour, | ||
128 | cert->valid_to.tm_min, cert->valid_to.tm_sec); | ||
129 | pr_devel("Cert Signature: %s + %s\n", | ||
130 | pkey_algo[cert->sig_pkey_algo], | ||
131 | pkey_hash_algo[cert->sig_hash_algo]); | ||
132 | |||
133 | if (!cert->fingerprint || !cert->authority) { | ||
134 | pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n", | ||
135 | cert->subject); | ||
136 | ret = -EKEYREJECTED; | ||
137 | goto error_free_cert; | ||
138 | } | ||
139 | |||
140 | time_to_tm(CURRENT_TIME.tv_sec, 0, &now); | ||
141 | pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n", | ||
142 | now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, | ||
143 | now.tm_hour, now.tm_min, now.tm_sec); | ||
144 | if (now.tm_year < cert->valid_from.tm_year || | ||
145 | (now.tm_year == cert->valid_from.tm_year && | ||
146 | (now.tm_mon < cert->valid_from.tm_mon || | ||
147 | (now.tm_mon == cert->valid_from.tm_mon && | ||
148 | (now.tm_mday < cert->valid_from.tm_mday || | ||
149 | (now.tm_mday == cert->valid_from.tm_mday && | ||
150 | (now.tm_hour < cert->valid_from.tm_hour || | ||
151 | (now.tm_hour == cert->valid_from.tm_hour && | ||
152 | (now.tm_min < cert->valid_from.tm_min || | ||
153 | (now.tm_min == cert->valid_from.tm_min && | ||
154 | (now.tm_sec < cert->valid_from.tm_sec | ||
155 | ))))))))))) { | ||
156 | pr_warn("Cert %s is not yet valid\n", cert->fingerprint); | ||
157 | ret = -EKEYREJECTED; | ||
158 | goto error_free_cert; | ||
159 | } | ||
160 | if (now.tm_year > cert->valid_to.tm_year || | ||
161 | (now.tm_year == cert->valid_to.tm_year && | ||
162 | (now.tm_mon > cert->valid_to.tm_mon || | ||
163 | (now.tm_mon == cert->valid_to.tm_mon && | ||
164 | (now.tm_mday > cert->valid_to.tm_mday || | ||
165 | (now.tm_mday == cert->valid_to.tm_mday && | ||
166 | (now.tm_hour > cert->valid_to.tm_hour || | ||
167 | (now.tm_hour == cert->valid_to.tm_hour && | ||
168 | (now.tm_min > cert->valid_to.tm_min || | ||
169 | (now.tm_min == cert->valid_to.tm_min && | ||
170 | (now.tm_sec > cert->valid_to.tm_sec | ||
171 | ))))))))))) { | ||
172 | pr_warn("Cert %s has expired\n", cert->fingerprint); | ||
173 | ret = -EKEYEXPIRED; | ||
174 | goto error_free_cert; | ||
175 | } | ||
176 | |||
177 | cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo]; | ||
178 | cert->pub->id_type = PKEY_ID_X509; | ||
179 | |||
180 | /* Check the signature on the key */ | ||
181 | if (strcmp(cert->fingerprint, cert->authority) == 0) { | ||
182 | ret = x509_check_signature(cert->pub, cert); | ||
183 | if (ret < 0) | ||
184 | goto error_free_cert; | ||
185 | } | ||
186 | |||
187 | /* Propose a description */ | ||
188 | sulen = strlen(cert->subject); | ||
189 | srlen = strlen(cert->fingerprint); | ||
190 | ret = -ENOMEM; | ||
191 | desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL); | ||
192 | if (!desc) | ||
193 | goto error_free_cert; | ||
194 | memcpy(desc, cert->subject, sulen); | ||
195 | desc[sulen] = ':'; | ||
196 | desc[sulen + 1] = ' '; | ||
197 | memcpy(desc + sulen + 2, cert->fingerprint, srlen); | ||
198 | desc[sulen + 2 + srlen] = 0; | ||
199 | |||
200 | /* We're pinning the module by being linked against it */ | ||
201 | __module_get(public_key_subtype.owner); | ||
202 | prep->type_data[0] = &public_key_subtype; | ||
203 | prep->type_data[1] = cert->fingerprint; | ||
204 | prep->payload = cert->pub; | ||
205 | prep->description = desc; | ||
206 | prep->quotalen = 100; | ||
207 | |||
208 | /* We've finished with the certificate */ | ||
209 | cert->pub = NULL; | ||
210 | cert->fingerprint = NULL; | ||
211 | desc = NULL; | ||
212 | ret = 0; | ||
213 | |||
214 | error_free_cert: | ||
215 | x509_free_certificate(cert); | ||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | static struct asymmetric_key_parser x509_key_parser = { | ||
220 | .owner = THIS_MODULE, | ||
221 | .name = "x509", | ||
222 | .parse = x509_key_preparse, | ||
223 | }; | ||
224 | |||
225 | /* | ||
226 | * Module stuff | ||
227 | */ | ||
228 | static int __init x509_key_init(void) | ||
229 | { | ||
230 | return register_asymmetric_key_parser(&x509_key_parser); | ||
231 | } | ||
232 | |||
233 | static void __exit x509_key_exit(void) | ||
234 | { | ||
235 | unregister_asymmetric_key_parser(&x509_key_parser); | ||
236 | } | ||
237 | |||
238 | module_init(x509_key_init); | ||
239 | module_exit(x509_key_exit); | ||
diff --git a/crypto/asymmetric_keys/x509_rsakey.asn1 b/crypto/asymmetric_keys/x509_rsakey.asn1 deleted file mode 100644 index 4ec7cc6532c..00000000000 --- a/crypto/asymmetric_keys/x509_rsakey.asn1 +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | RSAPublicKey ::= SEQUENCE { | ||
2 | modulus INTEGER ({ rsa_extract_mpi }), -- n | ||
3 | publicExponent INTEGER ({ rsa_extract_mpi }) -- e | ||
4 | } | ||