]>
Commit | Line | Data |
---|---|---|
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 <keys/asymmetric-subtype.h> | |
17 | #include <keys/asymmetric-parser.h> | |
18 | #include <keys/system_keyring.h> | |
19 | #include <crypto/hash.h> | |
20 | #include "asymmetric_keys.h" | |
21 | #include "x509_parser.h" | |
22 | ||
23 | /* | |
24 | * Set up the signature parameters in an X.509 certificate. This involves | |
25 | * digesting the signed data and extracting the signature. | |
26 | */ | |
27 | int x509_get_sig_params(struct x509_certificate *cert) | |
28 | { | |
29 | struct public_key_signature *sig = cert->sig; | |
30 | struct crypto_shash *tfm; | |
31 | struct shash_desc *desc; | |
32 | size_t desc_size; | |
33 | int ret; | |
34 | ||
35 | pr_devel("==>%s()\n", __func__); | |
36 | ||
37 | if (!cert->pub->pkey_algo) | |
38 | cert->unsupported_key = true; | |
39 | ||
40 | if (!sig->pkey_algo) | |
41 | cert->unsupported_sig = true; | |
42 | ||
43 | /* We check the hash if we can - even if we can't then verify it */ | |
44 | if (!sig->hash_algo) { | |
45 | cert->unsupported_sig = true; | |
46 | return 0; | |
47 | } | |
48 | ||
49 | sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL); | |
50 | if (!sig->s) | |
51 | return -ENOMEM; | |
52 | ||
53 | sig->s_size = cert->raw_sig_size; | |
54 | ||
55 | /* Allocate the hashing algorithm we're going to need and find out how | |
56 | * big the hash operational data will be. | |
57 | */ | |
58 | tfm = crypto_alloc_shash(sig->hash_algo, 0, 0); | |
59 | if (IS_ERR(tfm)) { | |
60 | if (PTR_ERR(tfm) == -ENOENT) { | |
61 | cert->unsupported_sig = true; | |
62 | return 0; | |
63 | } | |
64 | return PTR_ERR(tfm); | |
65 | } | |
66 | ||
67 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | |
68 | sig->digest_size = crypto_shash_digestsize(tfm); | |
69 | ||
70 | ret = -ENOMEM; | |
71 | sig->digest = kmalloc(sig->digest_size, GFP_KERNEL); | |
72 | if (!sig->digest) | |
73 | goto error; | |
74 | ||
75 | desc = kzalloc(desc_size, GFP_KERNEL); | |
76 | if (!desc) | |
77 | goto error; | |
78 | ||
79 | desc->tfm = tfm; | |
80 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | |
81 | ||
82 | ret = crypto_shash_init(desc); | |
83 | if (ret < 0) | |
84 | goto error_2; | |
85 | might_sleep(); | |
86 | ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest); | |
87 | if (ret < 0) | |
88 | goto error_2; | |
89 | ||
90 | ret = is_hash_blacklisted(sig->digest, sig->digest_size, "tbs"); | |
91 | if (ret == -EKEYREJECTED) { | |
92 | pr_err("Cert %*phN is blacklisted\n", | |
93 | sig->digest_size, sig->digest); | |
94 | cert->blacklisted = true; | |
95 | ret = 0; | |
96 | } | |
97 | ||
98 | error_2: | |
99 | kfree(desc); | |
100 | error: | |
101 | crypto_free_shash(tfm); | |
102 | pr_devel("<==%s() = %d\n", __func__, ret); | |
103 | return ret; | |
104 | } | |
105 | ||
106 | /* | |
107 | * Check for self-signedness in an X.509 cert and if found, check the signature | |
108 | * immediately if we can. | |
109 | */ | |
110 | int x509_check_for_self_signed(struct x509_certificate *cert) | |
111 | { | |
112 | int ret = 0; | |
113 | ||
114 | pr_devel("==>%s()\n", __func__); | |
115 | ||
116 | if (cert->raw_subject_size != cert->raw_issuer_size || | |
117 | memcmp(cert->raw_subject, cert->raw_issuer, | |
118 | cert->raw_issuer_size) != 0) | |
119 | goto not_self_signed; | |
120 | ||
121 | if (cert->sig->auth_ids[0] || cert->sig->auth_ids[1]) { | |
122 | /* If the AKID is present it may have one or two parts. If | |
123 | * both are supplied, both must match. | |
124 | */ | |
125 | bool a = asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]); | |
126 | bool b = asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0]); | |
127 | ||
128 | if (!a && !b) | |
129 | goto not_self_signed; | |
130 | ||
131 | ret = -EKEYREJECTED; | |
132 | if (((a && !b) || (b && !a)) && | |
133 | cert->sig->auth_ids[0] && cert->sig->auth_ids[1]) | |
134 | goto out; | |
135 | } | |
136 | ||
137 | ret = -EKEYREJECTED; | |
138 | if (cert->pub->pkey_algo != cert->sig->pkey_algo) | |
139 | goto out; | |
140 | ||
141 | ret = public_key_verify_signature(cert->pub, cert->sig); | |
142 | if (ret < 0) { | |
143 | if (ret == -ENOPKG) { | |
144 | cert->unsupported_sig = true; | |
145 | ret = 0; | |
146 | } | |
147 | goto out; | |
148 | } | |
149 | ||
150 | pr_devel("Cert Self-signature verified"); | |
151 | cert->self_signed = true; | |
152 | ||
153 | out: | |
154 | pr_devel("<==%s() = %d\n", __func__, ret); | |
155 | return ret; | |
156 | ||
157 | not_self_signed: | |
158 | pr_devel("<==%s() = 0 [not]\n", __func__); | |
159 | return 0; | |
160 | } | |
161 | ||
162 | /* | |
163 | * Attempt to parse a data blob for a key as an X509 certificate. | |
164 | */ | |
165 | static int x509_key_preparse(struct key_preparsed_payload *prep) | |
166 | { | |
167 | struct asymmetric_key_ids *kids; | |
168 | struct x509_certificate *cert; | |
169 | const char *q; | |
170 | size_t srlen, sulen; | |
171 | char *desc = NULL, *p; | |
172 | int ret; | |
173 | ||
174 | cert = x509_cert_parse(prep->data, prep->datalen); | |
175 | if (IS_ERR(cert)) | |
176 | return PTR_ERR(cert); | |
177 | ||
178 | pr_devel("Cert Issuer: %s\n", cert->issuer); | |
179 | pr_devel("Cert Subject: %s\n", cert->subject); | |
180 | ||
181 | if (cert->unsupported_key) { | |
182 | ret = -ENOPKG; | |
183 | goto error_free_cert; | |
184 | } | |
185 | ||
186 | pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo); | |
187 | pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); | |
188 | ||
189 | cert->pub->id_type = "X509"; | |
190 | ||
191 | if (cert->unsupported_sig) { | |
192 | public_key_signature_free(cert->sig); | |
193 | cert->sig = NULL; | |
194 | } else { | |
195 | pr_devel("Cert Signature: %s + %s\n", | |
196 | cert->sig->pkey_algo, cert->sig->hash_algo); | |
197 | } | |
198 | ||
199 | /* Don't permit addition of blacklisted keys */ | |
200 | ret = -EKEYREJECTED; | |
201 | if (cert->blacklisted) | |
202 | goto error_free_cert; | |
203 | ||
204 | /* Propose a description */ | |
205 | sulen = strlen(cert->subject); | |
206 | if (cert->raw_skid) { | |
207 | srlen = cert->raw_skid_size; | |
208 | q = cert->raw_skid; | |
209 | } else { | |
210 | srlen = cert->raw_serial_size; | |
211 | q = cert->raw_serial; | |
212 | } | |
213 | ||
214 | ret = -ENOMEM; | |
215 | desc = kmalloc(sulen + 2 + srlen * 2 + 1, GFP_KERNEL); | |
216 | if (!desc) | |
217 | goto error_free_cert; | |
218 | p = memcpy(desc, cert->subject, sulen); | |
219 | p += sulen; | |
220 | *p++ = ':'; | |
221 | *p++ = ' '; | |
222 | p = bin2hex(p, q, srlen); | |
223 | *p = 0; | |
224 | ||
225 | kids = kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL); | |
226 | if (!kids) | |
227 | goto error_free_desc; | |
228 | kids->id[0] = cert->id; | |
229 | kids->id[1] = cert->skid; | |
230 | ||
231 | /* We're pinning the module by being linked against it */ | |
232 | __module_get(public_key_subtype.owner); | |
233 | prep->payload.data[asym_subtype] = &public_key_subtype; | |
234 | prep->payload.data[asym_key_ids] = kids; | |
235 | prep->payload.data[asym_crypto] = cert->pub; | |
236 | prep->payload.data[asym_auth] = cert->sig; | |
237 | prep->description = desc; | |
238 | prep->quotalen = 100; | |
239 | ||
240 | /* We've finished with the certificate */ | |
241 | cert->pub = NULL; | |
242 | cert->id = NULL; | |
243 | cert->skid = NULL; | |
244 | cert->sig = NULL; | |
245 | desc = NULL; | |
246 | ret = 0; | |
247 | ||
248 | error_free_desc: | |
249 | kfree(desc); | |
250 | error_free_cert: | |
251 | x509_free_certificate(cert); | |
252 | return ret; | |
253 | } | |
254 | ||
255 | static struct asymmetric_key_parser x509_key_parser = { | |
256 | .owner = THIS_MODULE, | |
257 | .name = "x509", | |
258 | .parse = x509_key_preparse, | |
259 | }; | |
260 | ||
261 | /* | |
262 | * Module stuff | |
263 | */ | |
264 | static int __init x509_key_init(void) | |
265 | { | |
266 | return register_asymmetric_key_parser(&x509_key_parser); | |
267 | } | |
268 | ||
269 | static void __exit x509_key_exit(void) | |
270 | { | |
271 | unregister_asymmetric_key_parser(&x509_key_parser); | |
272 | } | |
273 | ||
274 | module_init(x509_key_init); | |
275 | module_exit(x509_key_exit); | |
276 | ||
277 | MODULE_DESCRIPTION("X.509 certificate parser"); | |
278 | MODULE_LICENSE("GPL"); |