xref: /openbmc/linux/crypto/asymmetric_keys/x509_public_key.c (revision b426beb6eeb0c81aeaa419f7444064abc9cb04ae)
1c26fd69fSDavid Howells /* Instantiate a public key crypto key from an X.509 Certificate
2c26fd69fSDavid Howells  *
3c26fd69fSDavid Howells  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
4c26fd69fSDavid Howells  * Written by David Howells (dhowells@redhat.com)
5c26fd69fSDavid Howells  *
6c26fd69fSDavid Howells  * This program is free software; you can redistribute it and/or
7c26fd69fSDavid Howells  * modify it under the terms of the GNU General Public Licence
8c26fd69fSDavid Howells  * as published by the Free Software Foundation; either version
9c26fd69fSDavid Howells  * 2 of the Licence, or (at your option) any later version.
10c26fd69fSDavid Howells  */
11c26fd69fSDavid Howells 
12c26fd69fSDavid Howells #define pr_fmt(fmt) "X.509: "fmt
13c26fd69fSDavid Howells #include <linux/module.h>
14c26fd69fSDavid Howells #include <linux/kernel.h>
15c26fd69fSDavid Howells #include <linux/slab.h>
16c26fd69fSDavid Howells #include <linux/err.h>
17c26fd69fSDavid Howells #include <linux/mpi.h>
18c26fd69fSDavid Howells #include <linux/asn1_decoder.h>
19c26fd69fSDavid Howells #include <keys/asymmetric-subtype.h>
20c26fd69fSDavid Howells #include <keys/asymmetric-parser.h>
21c26fd69fSDavid Howells #include <crypto/hash.h>
22c26fd69fSDavid Howells #include "asymmetric_keys.h"
23c26fd69fSDavid Howells #include "public_key.h"
24c26fd69fSDavid Howells #include "x509_parser.h"
25c26fd69fSDavid Howells 
26c26fd69fSDavid Howells /*
27*b426beb6SDavid Howells  * Set up the signature parameters in an X.509 certificate.  This involves
28*b426beb6SDavid Howells  * digesting the signed data and extracting the signature.
29c26fd69fSDavid Howells  */
30*b426beb6SDavid Howells int x509_get_sig_params(struct x509_certificate *cert)
31c26fd69fSDavid Howells {
32c26fd69fSDavid Howells 	struct crypto_shash *tfm;
33c26fd69fSDavid Howells 	struct shash_desc *desc;
34c26fd69fSDavid Howells 	size_t digest_size, desc_size;
35*b426beb6SDavid Howells 	void *digest;
36c26fd69fSDavid Howells 	int ret;
37c26fd69fSDavid Howells 
38c26fd69fSDavid Howells 	pr_devel("==>%s()\n", __func__);
39c26fd69fSDavid Howells 
40*b426beb6SDavid Howells 	if (cert->sig.rsa.s)
41*b426beb6SDavid Howells 		return 0;
42*b426beb6SDavid Howells 
43*b426beb6SDavid Howells 	cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
44*b426beb6SDavid Howells 	if (!cert->sig.rsa.s)
45*b426beb6SDavid Howells 		return -ENOMEM;
46*b426beb6SDavid Howells 	cert->sig.nr_mpi = 1;
47*b426beb6SDavid Howells 
48c26fd69fSDavid Howells 	/* Allocate the hashing algorithm we're going to need and find out how
49c26fd69fSDavid Howells 	 * big the hash operational data will be.
50c26fd69fSDavid Howells 	 */
51*b426beb6SDavid Howells 	tfm = crypto_alloc_shash(pkey_hash_algo_name[cert->sig.pkey_hash_algo], 0, 0);
52c26fd69fSDavid Howells 	if (IS_ERR(tfm))
53c26fd69fSDavid Howells 		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
54c26fd69fSDavid Howells 
55c26fd69fSDavid Howells 	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
56c26fd69fSDavid Howells 	digest_size = crypto_shash_digestsize(tfm);
57c26fd69fSDavid Howells 
58*b426beb6SDavid Howells 	/* We allocate the hash operational data storage on the end of the
59*b426beb6SDavid Howells 	 * digest storage space.
60c26fd69fSDavid Howells 	 */
61c26fd69fSDavid Howells 	ret = -ENOMEM;
62*b426beb6SDavid Howells 	digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
63*b426beb6SDavid Howells 	if (!digest)
64*b426beb6SDavid Howells 		goto error;
65c26fd69fSDavid Howells 
66*b426beb6SDavid Howells 	cert->sig.digest = digest;
67*b426beb6SDavid Howells 	cert->sig.digest_size = digest_size;
68c26fd69fSDavid Howells 
69*b426beb6SDavid Howells 	desc = digest + digest_size;
70c26fd69fSDavid Howells 	desc->tfm = tfm;
71c26fd69fSDavid Howells 	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
72c26fd69fSDavid Howells 
73c26fd69fSDavid Howells 	ret = crypto_shash_init(desc);
74c26fd69fSDavid Howells 	if (ret < 0)
75c26fd69fSDavid Howells 		goto error;
76*b426beb6SDavid Howells 	might_sleep();
77*b426beb6SDavid Howells 	ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
78c26fd69fSDavid Howells error:
79c26fd69fSDavid Howells 	crypto_free_shash(tfm);
80c26fd69fSDavid Howells 	pr_devel("<==%s() = %d\n", __func__, ret);
81c26fd69fSDavid Howells 	return ret;
82c26fd69fSDavid Howells }
83*b426beb6SDavid Howells EXPORT_SYMBOL_GPL(x509_get_sig_params);
84*b426beb6SDavid Howells 
85*b426beb6SDavid Howells /*
86*b426beb6SDavid Howells  * Check the signature on a certificate using the provided public key
87*b426beb6SDavid Howells  */
88*b426beb6SDavid Howells int x509_check_signature(const struct public_key *pub,
89*b426beb6SDavid Howells 			 struct x509_certificate *cert)
90*b426beb6SDavid Howells {
91*b426beb6SDavid Howells 	int ret;
92*b426beb6SDavid Howells 
93*b426beb6SDavid Howells 	pr_devel("==>%s()\n", __func__);
94*b426beb6SDavid Howells 
95*b426beb6SDavid Howells 	ret = x509_get_sig_params(cert);
96*b426beb6SDavid Howells 	if (ret < 0)
97*b426beb6SDavid Howells 		return ret;
98*b426beb6SDavid Howells 
99*b426beb6SDavid Howells 	ret = public_key_verify_signature(pub, &cert->sig);
100*b426beb6SDavid Howells 	pr_debug("Cert Verification: %d\n", ret);
101*b426beb6SDavid Howells 	return ret;
102*b426beb6SDavid Howells }
103*b426beb6SDavid Howells EXPORT_SYMBOL_GPL(x509_check_signature);
104c26fd69fSDavid Howells 
105c26fd69fSDavid Howells /*
106c26fd69fSDavid Howells  * Attempt to parse a data blob for a key as an X509 certificate.
107c26fd69fSDavid Howells  */
108c26fd69fSDavid Howells static int x509_key_preparse(struct key_preparsed_payload *prep)
109c26fd69fSDavid Howells {
110c26fd69fSDavid Howells 	struct x509_certificate *cert;
111a5752d11SDavid Howells 	struct tm now;
112c26fd69fSDavid Howells 	size_t srlen, sulen;
113c26fd69fSDavid Howells 	char *desc = NULL;
114c26fd69fSDavid Howells 	int ret;
115c26fd69fSDavid Howells 
116c26fd69fSDavid Howells 	cert = x509_cert_parse(prep->data, prep->datalen);
117c26fd69fSDavid Howells 	if (IS_ERR(cert))
118c26fd69fSDavid Howells 		return PTR_ERR(cert);
119c26fd69fSDavid Howells 
120c26fd69fSDavid Howells 	pr_devel("Cert Issuer: %s\n", cert->issuer);
121c26fd69fSDavid Howells 	pr_devel("Cert Subject: %s\n", cert->subject);
12267f7d60bSDavid Howells 	pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
1232f1c4fefSDavid Howells 	pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
124a5752d11SDavid Howells 		 cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
125a5752d11SDavid Howells 		 cert->valid_from.tm_mday, cert->valid_from.tm_hour,
126a5752d11SDavid Howells 		 cert->valid_from.tm_min,  cert->valid_from.tm_sec);
1272f1c4fefSDavid Howells 	pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n",
128a5752d11SDavid Howells 		 cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1,
129a5752d11SDavid Howells 		 cert->valid_to.tm_mday, cert->valid_to.tm_hour,
130a5752d11SDavid Howells 		 cert->valid_to.tm_min,  cert->valid_to.tm_sec);
131c26fd69fSDavid Howells 	pr_devel("Cert Signature: %s + %s\n",
132*b426beb6SDavid Howells 		 pkey_algo_name[cert->sig.pkey_algo],
133*b426beb6SDavid Howells 		 pkey_hash_algo_name[cert->sig.pkey_hash_algo]);
134c26fd69fSDavid Howells 
135c26fd69fSDavid Howells 	if (!cert->fingerprint || !cert->authority) {
136c26fd69fSDavid Howells 		pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n",
137c26fd69fSDavid Howells 			cert->subject);
138c26fd69fSDavid Howells 		ret = -EKEYREJECTED;
139c26fd69fSDavid Howells 		goto error_free_cert;
140c26fd69fSDavid Howells 	}
141c26fd69fSDavid Howells 
142a5752d11SDavid Howells 	time_to_tm(CURRENT_TIME.tv_sec, 0, &now);
1432f1c4fefSDavid Howells 	pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n",
144a5752d11SDavid Howells 		 now.tm_year + 1900, now.tm_mon + 1, now.tm_mday,
145a5752d11SDavid Howells 		 now.tm_hour, now.tm_min,  now.tm_sec);
146a5752d11SDavid Howells 	if (now.tm_year < cert->valid_from.tm_year ||
147a5752d11SDavid Howells 	    (now.tm_year == cert->valid_from.tm_year &&
148a5752d11SDavid Howells 	     (now.tm_mon < cert->valid_from.tm_mon ||
149a5752d11SDavid Howells 	      (now.tm_mon == cert->valid_from.tm_mon &&
150a5752d11SDavid Howells 	       (now.tm_mday < cert->valid_from.tm_mday ||
151a5752d11SDavid Howells 		(now.tm_mday == cert->valid_from.tm_mday &&
152a5752d11SDavid Howells 		 (now.tm_hour < cert->valid_from.tm_hour ||
153a5752d11SDavid Howells 		  (now.tm_hour == cert->valid_from.tm_hour &&
154a5752d11SDavid Howells 		   (now.tm_min < cert->valid_from.tm_min ||
155a5752d11SDavid Howells 		    (now.tm_min == cert->valid_from.tm_min &&
156a5752d11SDavid Howells 		     (now.tm_sec < cert->valid_from.tm_sec
157a5752d11SDavid Howells 		      ))))))))))) {
158c26fd69fSDavid Howells 		pr_warn("Cert %s is not yet valid\n", cert->fingerprint);
159c26fd69fSDavid Howells 		ret = -EKEYREJECTED;
160c26fd69fSDavid Howells 		goto error_free_cert;
161c26fd69fSDavid Howells 	}
162a5752d11SDavid Howells 	if (now.tm_year > cert->valid_to.tm_year ||
163a5752d11SDavid Howells 	    (now.tm_year == cert->valid_to.tm_year &&
164a5752d11SDavid Howells 	     (now.tm_mon > cert->valid_to.tm_mon ||
165a5752d11SDavid Howells 	      (now.tm_mon == cert->valid_to.tm_mon &&
166a5752d11SDavid Howells 	       (now.tm_mday > cert->valid_to.tm_mday ||
167a5752d11SDavid Howells 		(now.tm_mday == cert->valid_to.tm_mday &&
168a5752d11SDavid Howells 		 (now.tm_hour > cert->valid_to.tm_hour ||
169a5752d11SDavid Howells 		  (now.tm_hour == cert->valid_to.tm_hour &&
170a5752d11SDavid Howells 		   (now.tm_min > cert->valid_to.tm_min ||
171a5752d11SDavid Howells 		    (now.tm_min == cert->valid_to.tm_min &&
172a5752d11SDavid Howells 		     (now.tm_sec > cert->valid_to.tm_sec
173a5752d11SDavid Howells 		      ))))))))))) {
174c26fd69fSDavid Howells 		pr_warn("Cert %s has expired\n", cert->fingerprint);
175c26fd69fSDavid Howells 		ret = -EKEYEXPIRED;
176c26fd69fSDavid Howells 		goto error_free_cert;
177c26fd69fSDavid Howells 	}
178c26fd69fSDavid Howells 
17967f7d60bSDavid Howells 	cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
180c26fd69fSDavid Howells 	cert->pub->id_type = PKEY_ID_X509;
181c26fd69fSDavid Howells 
182c26fd69fSDavid Howells 	/* Check the signature on the key */
183c26fd69fSDavid Howells 	if (strcmp(cert->fingerprint, cert->authority) == 0) {
184c26fd69fSDavid Howells 		ret = x509_check_signature(cert->pub, cert);
185c26fd69fSDavid Howells 		if (ret < 0)
186c26fd69fSDavid Howells 			goto error_free_cert;
187c26fd69fSDavid Howells 	}
188c26fd69fSDavid Howells 
189c26fd69fSDavid Howells 	/* Propose a description */
190c26fd69fSDavid Howells 	sulen = strlen(cert->subject);
191c26fd69fSDavid Howells 	srlen = strlen(cert->fingerprint);
192c26fd69fSDavid Howells 	ret = -ENOMEM;
193c26fd69fSDavid Howells 	desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL);
194c26fd69fSDavid Howells 	if (!desc)
195c26fd69fSDavid Howells 		goto error_free_cert;
196c26fd69fSDavid Howells 	memcpy(desc, cert->subject, sulen);
197c26fd69fSDavid Howells 	desc[sulen] = ':';
198c26fd69fSDavid Howells 	desc[sulen + 1] = ' ';
199c26fd69fSDavid Howells 	memcpy(desc + sulen + 2, cert->fingerprint, srlen);
200c26fd69fSDavid Howells 	desc[sulen + 2 + srlen] = 0;
201c26fd69fSDavid Howells 
202c26fd69fSDavid Howells 	/* We're pinning the module by being linked against it */
203c26fd69fSDavid Howells 	__module_get(public_key_subtype.owner);
204c26fd69fSDavid Howells 	prep->type_data[0] = &public_key_subtype;
205c26fd69fSDavid Howells 	prep->type_data[1] = cert->fingerprint;
206c26fd69fSDavid Howells 	prep->payload = cert->pub;
207c26fd69fSDavid Howells 	prep->description = desc;
208c26fd69fSDavid Howells 	prep->quotalen = 100;
209c26fd69fSDavid Howells 
210c26fd69fSDavid Howells 	/* We've finished with the certificate */
211c26fd69fSDavid Howells 	cert->pub = NULL;
212c26fd69fSDavid Howells 	cert->fingerprint = NULL;
213c26fd69fSDavid Howells 	desc = NULL;
214c26fd69fSDavid Howells 	ret = 0;
215c26fd69fSDavid Howells 
216c26fd69fSDavid Howells error_free_cert:
217c26fd69fSDavid Howells 	x509_free_certificate(cert);
218c26fd69fSDavid Howells 	return ret;
219c26fd69fSDavid Howells }
220c26fd69fSDavid Howells 
221c26fd69fSDavid Howells static struct asymmetric_key_parser x509_key_parser = {
222c26fd69fSDavid Howells 	.owner	= THIS_MODULE,
223c26fd69fSDavid Howells 	.name	= "x509",
224c26fd69fSDavid Howells 	.parse	= x509_key_preparse,
225c26fd69fSDavid Howells };
226c26fd69fSDavid Howells 
227c26fd69fSDavid Howells /*
228c26fd69fSDavid Howells  * Module stuff
229c26fd69fSDavid Howells  */
230c26fd69fSDavid Howells static int __init x509_key_init(void)
231c26fd69fSDavid Howells {
232c26fd69fSDavid Howells 	return register_asymmetric_key_parser(&x509_key_parser);
233c26fd69fSDavid Howells }
234c26fd69fSDavid Howells 
235c26fd69fSDavid Howells static void __exit x509_key_exit(void)
236c26fd69fSDavid Howells {
237c26fd69fSDavid Howells 	unregister_asymmetric_key_parser(&x509_key_parser);
238c26fd69fSDavid Howells }
239c26fd69fSDavid Howells 
240c26fd69fSDavid Howells module_init(x509_key_init);
241c26fd69fSDavid Howells module_exit(x509_key_exit);
242