Commit | Line | Data |
---|---|---|
c26fd69f DH |
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> | |
c26fd69f DH |
16 | #include <keys/asymmetric-subtype.h> |
17 | #include <keys/asymmetric-parser.h> | |
3be4beaf | 18 | #include <keys/system_keyring.h> |
c26fd69f DH |
19 | #include <crypto/hash.h> |
20 | #include "asymmetric_keys.h" | |
c26fd69f DH |
21 | #include "x509_parser.h" |
22 | ||
32c4741c | 23 | static bool use_builtin_keys; |
46963b77 | 24 | static struct asymmetric_key_id *ca_keyid; |
ffb70f61 DK |
25 | |
26 | #ifndef MODULE | |
f2b3dee4 MZ |
27 | static struct { |
28 | struct asymmetric_key_id id; | |
29 | unsigned char data[10]; | |
30 | } cakey; | |
31 | ||
ffb70f61 DK |
32 | static int __init ca_keys_setup(char *str) |
33 | { | |
34 | if (!str) /* default system keyring */ | |
35 | return 1; | |
36 | ||
46963b77 | 37 | if (strncmp(str, "id:", 3) == 0) { |
f2b3dee4 MZ |
38 | struct asymmetric_key_id *p = &cakey.id; |
39 | size_t hexlen = (strlen(str) - 3) / 2; | |
40 | int ret; | |
41 | ||
42 | if (hexlen == 0 || hexlen > sizeof(cakey.data)) { | |
43 | pr_err("Missing or invalid ca_keys id\n"); | |
44 | return 1; | |
45 | } | |
46 | ||
47 | ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen); | |
48 | if (ret < 0) | |
49 | pr_err("Unparsable ca_keys id hex string\n"); | |
50 | else | |
46963b77 DH |
51 | ca_keyid = p; /* owner key 'id:xxxxxx' */ |
52 | } else if (strcmp(str, "builtin") == 0) { | |
32c4741c | 53 | use_builtin_keys = true; |
46963b77 | 54 | } |
ffb70f61 DK |
55 | |
56 | return 1; | |
57 | } | |
58 | __setup("ca_keys=", ca_keys_setup); | |
59 | #endif | |
60 | ||
c26fd69f | 61 | /* |
b426beb6 DH |
62 | * Set up the signature parameters in an X.509 certificate. This involves |
63 | * digesting the signed data and extracting the signature. | |
c26fd69f | 64 | */ |
b426beb6 | 65 | int x509_get_sig_params(struct x509_certificate *cert) |
c26fd69f | 66 | { |
77d0910d | 67 | struct public_key_signature *sig = cert->sig; |
c26fd69f DH |
68 | struct crypto_shash *tfm; |
69 | struct shash_desc *desc; | |
77d0910d | 70 | size_t desc_size; |
c26fd69f DH |
71 | int ret; |
72 | ||
73 | pr_devel("==>%s()\n", __func__); | |
b426beb6 | 74 | |
6c2dc5ae DH |
75 | if (!cert->pub->pkey_algo) |
76 | cert->unsupported_key = true; | |
77 | ||
78 | if (!sig->pkey_algo) | |
79 | cert->unsupported_sig = true; | |
80 | ||
81 | /* We check the hash if we can - even if we can't then verify it */ | |
82 | if (!sig->hash_algo) { | |
83 | cert->unsupported_sig = true; | |
b426beb6 | 84 | return 0; |
6c2dc5ae | 85 | } |
b426beb6 | 86 | |
77d0910d DH |
87 | sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL); |
88 | if (!sig->s) | |
b426beb6 | 89 | return -ENOMEM; |
db6c43bd | 90 | |
77d0910d | 91 | sig->s_size = cert->raw_sig_size; |
b426beb6 | 92 | |
c26fd69f DH |
93 | /* Allocate the hashing algorithm we're going to need and find out how |
94 | * big the hash operational data will be. | |
95 | */ | |
77d0910d | 96 | tfm = crypto_alloc_shash(sig->hash_algo, 0, 0); |
41559420 DH |
97 | if (IS_ERR(tfm)) { |
98 | if (PTR_ERR(tfm) == -ENOENT) { | |
6c2dc5ae DH |
99 | cert->unsupported_sig = true; |
100 | return 0; | |
41559420 DH |
101 | } |
102 | return PTR_ERR(tfm); | |
103 | } | |
c26fd69f DH |
104 | |
105 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); | |
77d0910d | 106 | sig->digest_size = crypto_shash_digestsize(tfm); |
c26fd69f | 107 | |
c26fd69f | 108 | ret = -ENOMEM; |
77d0910d DH |
109 | sig->digest = kmalloc(sig->digest_size, GFP_KERNEL); |
110 | if (!sig->digest) | |
b426beb6 | 111 | goto error; |
c26fd69f | 112 | |
77d0910d DH |
113 | desc = kzalloc(desc_size, GFP_KERNEL); |
114 | if (!desc) | |
115 | goto error; | |
c26fd69f | 116 | |
b426beb6 DH |
117 | desc->tfm = tfm; |
118 | desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | |
c26fd69f DH |
119 | |
120 | ret = crypto_shash_init(desc); | |
121 | if (ret < 0) | |
77d0910d | 122 | goto error_2; |
b426beb6 | 123 | might_sleep(); |
77d0910d DH |
124 | ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest); |
125 | ||
126 | error_2: | |
127 | kfree(desc); | |
b426beb6 DH |
128 | error: |
129 | crypto_free_shash(tfm); | |
130 | pr_devel("<==%s() = %d\n", __func__, ret); | |
131 | return ret; | |
132 | } | |
c26fd69f | 133 | |
b426beb6 | 134 | /* |
6c2dc5ae DH |
135 | * Check for self-signedness in an X.509 cert and if found, check the signature |
136 | * immediately if we can. | |
b426beb6 | 137 | */ |
6c2dc5ae | 138 | int x509_check_for_self_signed(struct x509_certificate *cert) |
b426beb6 | 139 | { |
6c2dc5ae | 140 | int ret = 0; |
c26fd69f | 141 | |
b426beb6 | 142 | pr_devel("==>%s()\n", __func__); |
c26fd69f | 143 | |
ad3043fd DH |
144 | if (cert->raw_subject_size != cert->raw_issuer_size || |
145 | memcmp(cert->raw_subject, cert->raw_issuer, | |
146 | cert->raw_issuer_size) != 0) | |
147 | goto not_self_signed; | |
148 | ||
6c2dc5ae DH |
149 | if (cert->sig->auth_ids[0] || cert->sig->auth_ids[1]) { |
150 | /* If the AKID is present it may have one or two parts. If | |
151 | * both are supplied, both must match. | |
152 | */ | |
153 | bool a = asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]); | |
154 | bool b = asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0]); | |
155 | ||
156 | if (!a && !b) | |
157 | goto not_self_signed; | |
158 | ||
159 | ret = -EKEYREJECTED; | |
160 | if (((a && !b) || (b && !a)) && | |
161 | cert->sig->auth_ids[0] && cert->sig->auth_ids[1]) | |
162 | goto out; | |
163 | } | |
164 | ||
ad3043fd DH |
165 | ret = -EKEYREJECTED; |
166 | if (cert->pub->pkey_algo != cert->sig->pkey_algo) | |
167 | goto out; | |
168 | ||
6c2dc5ae DH |
169 | ret = public_key_verify_signature(cert->pub, cert->sig); |
170 | if (ret < 0) { | |
171 | if (ret == -ENOPKG) { | |
172 | cert->unsupported_sig = true; | |
173 | ret = 0; | |
174 | } | |
175 | goto out; | |
176 | } | |
177 | ||
178 | pr_devel("Cert Self-signature verified"); | |
179 | cert->self_signed = true; | |
c26fd69f | 180 | |
6c2dc5ae DH |
181 | out: |
182 | pr_devel("<==%s() = %d\n", __func__, ret); | |
c26fd69f | 183 | return ret; |
6c2dc5ae DH |
184 | |
185 | not_self_signed: | |
186 | pr_devel("<==%s() = 0 [not]\n", __func__); | |
187 | return 0; | |
c26fd69f DH |
188 | } |
189 | ||
3be4beaf MZ |
190 | /* |
191 | * Check the new certificate against the ones in the trust keyring. If one of | |
192 | * those is the signing key and validates the new certificate, then mark the | |
193 | * new certificate as being trusted. | |
194 | * | |
195 | * Return 0 if the new certificate was successfully validated, 1 if we couldn't | |
196 | * find a matching parent certificate in the trusted list and an error if there | |
197 | * is a matching certificate but the signature check fails. | |
198 | */ | |
199 | static int x509_validate_trust(struct x509_certificate *cert, | |
200 | struct key *trust_keyring) | |
201 | { | |
77d0910d | 202 | struct public_key_signature *sig = cert->sig; |
3be4beaf MZ |
203 | struct key *key; |
204 | int ret = 1; | |
205 | ||
6c2dc5ae DH |
206 | if (!sig->auth_ids[0] && !sig->auth_ids[1]) |
207 | return 1; | |
208 | ||
3be4beaf MZ |
209 | if (!trust_keyring) |
210 | return -EOPNOTSUPP; | |
77d0910d | 211 | if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid)) |
ffb70f61 | 212 | return -EPERM; |
6c2dc5ae DH |
213 | if (cert->unsupported_sig) |
214 | return -ENOPKG; | |
ffb70f61 | 215 | |
9eb02989 DH |
216 | key = find_asymmetric_key(trust_keyring, |
217 | sig->auth_ids[0], sig->auth_ids[1], false); | |
6c2dc5ae DH |
218 | if (IS_ERR(key)) |
219 | return PTR_ERR(key); | |
220 | ||
221 | if (!use_builtin_keys || | |
222 | test_bit(KEY_FLAG_BUILTIN, &key->flags)) { | |
223 | ret = public_key_verify_signature( | |
224 | key->payload.data[asym_crypto], cert->sig); | |
225 | if (ret == -ENOPKG) | |
226 | cert->unsupported_sig = true; | |
3be4beaf | 227 | } |
6c2dc5ae | 228 | key_put(key); |
3be4beaf MZ |
229 | return ret; |
230 | } | |
231 | ||
c26fd69f DH |
232 | /* |
233 | * Attempt to parse a data blob for a key as an X509 certificate. | |
234 | */ | |
235 | static int x509_key_preparse(struct key_preparsed_payload *prep) | |
236 | { | |
46963b77 | 237 | struct asymmetric_key_ids *kids; |
c26fd69f | 238 | struct x509_certificate *cert; |
46963b77 | 239 | const char *q; |
c26fd69f | 240 | size_t srlen, sulen; |
46963b77 | 241 | char *desc = NULL, *p; |
c26fd69f DH |
242 | int ret; |
243 | ||
244 | cert = x509_cert_parse(prep->data, prep->datalen); | |
245 | if (IS_ERR(cert)) | |
246 | return PTR_ERR(cert); | |
247 | ||
248 | pr_devel("Cert Issuer: %s\n", cert->issuer); | |
249 | pr_devel("Cert Subject: %s\n", cert->subject); | |
2ecdb23b | 250 | |
6c2dc5ae | 251 | if (cert->unsupported_key) { |
2ecdb23b DH |
252 | ret = -ENOPKG; |
253 | goto error_free_cert; | |
254 | } | |
255 | ||
4e8ae72a | 256 | pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo); |
fd19a3d1 | 257 | pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); |
c26fd69f | 258 | |
4e8ae72a | 259 | cert->pub->id_type = "X509"; |
c26fd69f | 260 | |
6c2dc5ae DH |
261 | /* See if we can derive the trustability of this certificate. |
262 | * | |
263 | * When it comes to self-signed certificates, we cannot evaluate | |
264 | * trustedness except by the fact that we obtained it from a trusted | |
265 | * location. So we just rely on x509_validate_trust() failing in this | |
266 | * case. | |
267 | * | |
268 | * Note that there's a possibility of a self-signed cert matching a | |
269 | * cert that we have (most likely a duplicate that we already trust) - | |
270 | * in which case it will be marked trusted. | |
271 | */ | |
272 | if (cert->unsupported_sig || cert->self_signed) { | |
273 | public_key_signature_free(cert->sig); | |
274 | cert->sig = NULL; | |
275 | } else { | |
276 | pr_devel("Cert Signature: %s + %s\n", | |
277 | cert->sig->pkey_algo, cert->sig->hash_algo); | |
278 | ||
3be4beaf | 279 | ret = x509_validate_trust(cert, get_system_trusted_keyring()); |
41c89b64 PM |
280 | if (ret) |
281 | ret = x509_validate_trust(cert, get_ima_mok_keyring()); | |
6c2dc5ae DH |
282 | if (ret == -EKEYREJECTED) |
283 | goto error_free_cert; | |
3be4beaf | 284 | if (!ret) |
6c2dc5ae | 285 | prep->trusted = true; |
c26fd69f DH |
286 | } |
287 | ||
288 | /* Propose a description */ | |
289 | sulen = strlen(cert->subject); | |
dd2f6c44 DH |
290 | if (cert->raw_skid) { |
291 | srlen = cert->raw_skid_size; | |
292 | q = cert->raw_skid; | |
293 | } else { | |
294 | srlen = cert->raw_serial_size; | |
295 | q = cert->raw_serial; | |
296 | } | |
46963b77 | 297 | |
c26fd69f | 298 | ret = -ENOMEM; |
46963b77 | 299 | desc = kmalloc(sulen + 2 + srlen * 2 + 1, GFP_KERNEL); |
c26fd69f DH |
300 | if (!desc) |
301 | goto error_free_cert; | |
46963b77 DH |
302 | p = memcpy(desc, cert->subject, sulen); |
303 | p += sulen; | |
304 | *p++ = ':'; | |
305 | *p++ = ' '; | |
306 | p = bin2hex(p, q, srlen); | |
307 | *p = 0; | |
308 | ||
309 | kids = kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL); | |
310 | if (!kids) | |
311 | goto error_free_desc; | |
312 | kids->id[0] = cert->id; | |
313 | kids->id[1] = cert->skid; | |
c26fd69f DH |
314 | |
315 | /* We're pinning the module by being linked against it */ | |
316 | __module_get(public_key_subtype.owner); | |
146aa8b1 DH |
317 | prep->payload.data[asym_subtype] = &public_key_subtype; |
318 | prep->payload.data[asym_key_ids] = kids; | |
319 | prep->payload.data[asym_crypto] = cert->pub; | |
77d0910d | 320 | prep->payload.data[asym_auth] = cert->sig; |
c26fd69f DH |
321 | prep->description = desc; |
322 | prep->quotalen = 100; | |
323 | ||
324 | /* We've finished with the certificate */ | |
325 | cert->pub = NULL; | |
46963b77 DH |
326 | cert->id = NULL; |
327 | cert->skid = NULL; | |
77d0910d | 328 | cert->sig = NULL; |
c26fd69f DH |
329 | desc = NULL; |
330 | ret = 0; | |
331 | ||
46963b77 DH |
332 | error_free_desc: |
333 | kfree(desc); | |
c26fd69f DH |
334 | error_free_cert: |
335 | x509_free_certificate(cert); | |
336 | return ret; | |
337 | } | |
338 | ||
339 | static struct asymmetric_key_parser x509_key_parser = { | |
340 | .owner = THIS_MODULE, | |
341 | .name = "x509", | |
342 | .parse = x509_key_preparse, | |
343 | }; | |
344 | ||
345 | /* | |
346 | * Module stuff | |
347 | */ | |
348 | static int __init x509_key_init(void) | |
349 | { | |
350 | return register_asymmetric_key_parser(&x509_key_parser); | |
351 | } | |
352 | ||
353 | static void __exit x509_key_exit(void) | |
354 | { | |
355 | unregister_asymmetric_key_parser(&x509_key_parser); | |
356 | } | |
357 | ||
358 | module_init(x509_key_init); | |
359 | module_exit(x509_key_exit); | |
e19aaa7d KK |
360 | |
361 | MODULE_DESCRIPTION("X.509 certificate parser"); | |
362 | MODULE_LICENSE("GPL"); |