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 /*
27  * Set up the signature parameters in an X.509 certificate.  This involves
28  * digesting the signed data and extracting the signature.
29  */
30 int x509_get_sig_params(struct x509_certificate *cert)
31 {
32 	struct crypto_shash *tfm;
33 	struct shash_desc *desc;
34 	size_t digest_size, desc_size;
35 	void *digest;
36 	int ret;
37 
38 	pr_devel("==>%s()\n", __func__);
39 
40 	if (cert->sig.rsa.s)
41 		return 0;
42 
43 	cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
44 	if (!cert->sig.rsa.s)
45 		return -ENOMEM;
46 	cert->sig.nr_mpi = 1;
47 
48 	/* Allocate the hashing algorithm we're going to need and find out how
49 	 * big the hash operational data will be.
50 	 */
51 	tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0);
52 	if (IS_ERR(tfm))
53 		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
54 
55 	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
56 	digest_size = crypto_shash_digestsize(tfm);
57 
58 	/* We allocate the hash operational data storage on the end of the
59 	 * digest storage space.
60 	 */
61 	ret = -ENOMEM;
62 	digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
63 	if (!digest)
64 		goto error;
65 
66 	cert->sig.digest = digest;
67 	cert->sig.digest_size = digest_size;
68 
69 	desc = digest + digest_size;
70 	desc->tfm = tfm;
71 	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
72 
73 	ret = crypto_shash_init(desc);
74 	if (ret < 0)
75 		goto error;
76 	might_sleep();
77 	ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
78 error:
79 	crypto_free_shash(tfm);
80 	pr_devel("<==%s() = %d\n", __func__, ret);
81 	return ret;
82 }
83 EXPORT_SYMBOL_GPL(x509_get_sig_params);
84 
85 /*
86  * Check the signature on a certificate using the provided public key
87  */
88 int x509_check_signature(const struct public_key *pub,
89 			 struct x509_certificate *cert)
90 {
91 	int ret;
92 
93 	pr_devel("==>%s()\n", __func__);
94 
95 	ret = x509_get_sig_params(cert);
96 	if (ret < 0)
97 		return ret;
98 
99 	ret = public_key_verify_signature(pub, &cert->sig);
100 	pr_debug("Cert Verification: %d\n", ret);
101 	return ret;
102 }
103 EXPORT_SYMBOL_GPL(x509_check_signature);
104 
105 /*
106  * Attempt to parse a data blob for a key as an X509 certificate.
107  */
108 static int x509_key_preparse(struct key_preparsed_payload *prep)
109 {
110 	struct x509_certificate *cert;
111 	size_t srlen, sulen;
112 	char *desc = NULL;
113 	int ret;
114 
115 	cert = x509_cert_parse(prep->data, prep->datalen);
116 	if (IS_ERR(cert))
117 		return PTR_ERR(cert);
118 
119 	pr_devel("Cert Issuer: %s\n", cert->issuer);
120 	pr_devel("Cert Subject: %s\n", cert->subject);
121 
122 	if (cert->pub->pkey_algo >= PKEY_ALGO__LAST ||
123 	    cert->sig.pkey_algo >= PKEY_ALGO__LAST ||
124 	    cert->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
125 	    !pkey_algo[cert->pub->pkey_algo] ||
126 	    !pkey_algo[cert->sig.pkey_algo] ||
127 	    !hash_algo_name[cert->sig.pkey_hash_algo]) {
128 		ret = -ENOPKG;
129 		goto error_free_cert;
130 	}
131 
132 	pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
133 	pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
134 		 cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
135 		 cert->valid_from.tm_mday, cert->valid_from.tm_hour,
136 		 cert->valid_from.tm_min,  cert->valid_from.tm_sec);
137 	pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n",
138 		 cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1,
139 		 cert->valid_to.tm_mday, cert->valid_to.tm_hour,
140 		 cert->valid_to.tm_min,  cert->valid_to.tm_sec);
141 	pr_devel("Cert Signature: %s + %s\n",
142 		 pkey_algo_name[cert->sig.pkey_algo],
143 		 hash_algo_name[cert->sig.pkey_hash_algo]);
144 
145 	if (!cert->fingerprint) {
146 		pr_warn("Cert for '%s' must have a SubjKeyId extension\n",
147 			cert->subject);
148 		ret = -EKEYREJECTED;
149 		goto error_free_cert;
150 	}
151 
152 	cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
153 	cert->pub->id_type = PKEY_ID_X509;
154 
155 	/* Check the signature on the key if it appears to be self-signed */
156 	if (!cert->authority ||
157 	    strcmp(cert->fingerprint, cert->authority) == 0) {
158 		ret = x509_check_signature(cert->pub, cert);
159 		if (ret < 0)
160 			goto error_free_cert;
161 	}
162 
163 	/* Propose a description */
164 	sulen = strlen(cert->subject);
165 	srlen = strlen(cert->fingerprint);
166 	ret = -ENOMEM;
167 	desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL);
168 	if (!desc)
169 		goto error_free_cert;
170 	memcpy(desc, cert->subject, sulen);
171 	desc[sulen] = ':';
172 	desc[sulen + 1] = ' ';
173 	memcpy(desc + sulen + 2, cert->fingerprint, srlen);
174 	desc[sulen + 2 + srlen] = 0;
175 
176 	/* We're pinning the module by being linked against it */
177 	__module_get(public_key_subtype.owner);
178 	prep->type_data[0] = &public_key_subtype;
179 	prep->type_data[1] = cert->fingerprint;
180 	prep->payload = cert->pub;
181 	prep->description = desc;
182 	prep->quotalen = 100;
183 
184 	/* We've finished with the certificate */
185 	cert->pub = NULL;
186 	cert->fingerprint = NULL;
187 	desc = NULL;
188 	ret = 0;
189 
190 error_free_cert:
191 	x509_free_certificate(cert);
192 	return ret;
193 }
194 
195 static struct asymmetric_key_parser x509_key_parser = {
196 	.owner	= THIS_MODULE,
197 	.name	= "x509",
198 	.parse	= x509_key_preparse,
199 };
200 
201 /*
202  * Module stuff
203  */
204 static int __init x509_key_init(void)
205 {
206 	return register_asymmetric_key_parser(&x509_key_parser);
207 }
208 
209 static void __exit x509_key_exit(void)
210 {
211 	unregister_asymmetric_key_parser(&x509_key_parser);
212 }
213 
214 module_init(x509_key_init);
215 module_exit(x509_key_exit);
216 
217 MODULE_DESCRIPTION("X.509 certificate parser");
218 MODULE_LICENSE("GPL");
219