xref: /openbmc/linux/crypto/asymmetric_keys/x509_public_key.c (revision 146aa8b1453bd8f1ff2304ffb71b4ee0eb9acdcc)
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>
213be4beafSMimi Zohar #include <keys/system_keyring.h>
22c26fd69fSDavid Howells #include <crypto/hash.h>
23c26fd69fSDavid Howells #include "asymmetric_keys.h"
24c26fd69fSDavid Howells #include "public_key.h"
25c26fd69fSDavid Howells #include "x509_parser.h"
26c26fd69fSDavid Howells 
2732c4741cSDmitry Kasatkin static bool use_builtin_keys;
2846963b77SDavid Howells static struct asymmetric_key_id *ca_keyid;
29ffb70f61SDmitry Kasatkin 
30ffb70f61SDmitry Kasatkin #ifndef MODULE
31f2b3dee4SMimi Zohar static struct {
32f2b3dee4SMimi Zohar 	struct asymmetric_key_id id;
33f2b3dee4SMimi Zohar 	unsigned char data[10];
34f2b3dee4SMimi Zohar } cakey;
35f2b3dee4SMimi Zohar 
36ffb70f61SDmitry Kasatkin static int __init ca_keys_setup(char *str)
37ffb70f61SDmitry Kasatkin {
38ffb70f61SDmitry Kasatkin 	if (!str)		/* default system keyring */
39ffb70f61SDmitry Kasatkin 		return 1;
40ffb70f61SDmitry Kasatkin 
4146963b77SDavid Howells 	if (strncmp(str, "id:", 3) == 0) {
42f2b3dee4SMimi Zohar 		struct asymmetric_key_id *p = &cakey.id;
43f2b3dee4SMimi Zohar 		size_t hexlen = (strlen(str) - 3) / 2;
44f2b3dee4SMimi Zohar 		int ret;
45f2b3dee4SMimi Zohar 
46f2b3dee4SMimi Zohar 		if (hexlen == 0 || hexlen > sizeof(cakey.data)) {
47f2b3dee4SMimi Zohar 			pr_err("Missing or invalid ca_keys id\n");
48f2b3dee4SMimi Zohar 			return 1;
49f2b3dee4SMimi Zohar 		}
50f2b3dee4SMimi Zohar 
51f2b3dee4SMimi Zohar 		ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen);
52f2b3dee4SMimi Zohar 		if (ret < 0)
53f2b3dee4SMimi Zohar 			pr_err("Unparsable ca_keys id hex string\n");
54f2b3dee4SMimi Zohar 		else
5546963b77SDavid Howells 			ca_keyid = p;	/* owner key 'id:xxxxxx' */
5646963b77SDavid Howells 	} else if (strcmp(str, "builtin") == 0) {
5732c4741cSDmitry Kasatkin 		use_builtin_keys = true;
5846963b77SDavid Howells 	}
59ffb70f61SDmitry Kasatkin 
60ffb70f61SDmitry Kasatkin 	return 1;
61ffb70f61SDmitry Kasatkin }
62ffb70f61SDmitry Kasatkin __setup("ca_keys=", ca_keys_setup);
63ffb70f61SDmitry Kasatkin #endif
64ffb70f61SDmitry Kasatkin 
655ce43ad2SDavid Howells /**
665ce43ad2SDavid Howells  * x509_request_asymmetric_key - Request a key by X.509 certificate params.
675ce43ad2SDavid Howells  * @keyring: The keys to search.
684573b64aSDavid Howells  * @id: The issuer & serialNumber to look for or NULL.
694573b64aSDavid Howells  * @skid: The subjectKeyIdentifier to look for or NULL.
70f1b731dbSDmitry Kasatkin  * @partial: Use partial match if true, exact if false.
715ce43ad2SDavid Howells  *
724573b64aSDavid Howells  * Find a key in the given keyring by identifier.  The preferred identifier is
734573b64aSDavid Howells  * the issuer + serialNumber and the fallback identifier is the
744573b64aSDavid Howells  * subjectKeyIdentifier.  If both are given, the lookup is by the former, but
754573b64aSDavid Howells  * the latter must also match.
763be4beafSMimi Zohar  */
775ce43ad2SDavid Howells struct key *x509_request_asymmetric_key(struct key *keyring,
784573b64aSDavid Howells 					const struct asymmetric_key_id *id,
794573b64aSDavid Howells 					const struct asymmetric_key_id *skid,
80f1b731dbSDmitry Kasatkin 					bool partial)
813be4beafSMimi Zohar {
824573b64aSDavid Howells 	struct key *key;
834573b64aSDavid Howells 	key_ref_t ref;
844573b64aSDavid Howells 	const char *lookup;
854573b64aSDavid Howells 	char *req, *p;
864573b64aSDavid Howells 	int len;
874573b64aSDavid Howells 
884573b64aSDavid Howells 	if (id) {
894573b64aSDavid Howells 		lookup = id->data;
904573b64aSDavid Howells 		len = id->len;
914573b64aSDavid Howells 	} else {
924573b64aSDavid Howells 		lookup = skid->data;
934573b64aSDavid Howells 		len = skid->len;
944573b64aSDavid Howells 	}
953be4beafSMimi Zohar 
9646963b77SDavid Howells 	/* Construct an identifier "id:<keyid>". */
974573b64aSDavid Howells 	p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
984573b64aSDavid Howells 	if (!req)
993be4beafSMimi Zohar 		return ERR_PTR(-ENOMEM);
1003be4beafSMimi Zohar 
101f1b731dbSDmitry Kasatkin 	if (partial) {
10246963b77SDavid Howells 		*p++ = 'i';
10346963b77SDavid Howells 		*p++ = 'd';
104f1b731dbSDmitry Kasatkin 	} else {
105f1b731dbSDmitry Kasatkin 		*p++ = 'e';
106f1b731dbSDmitry Kasatkin 		*p++ = 'x';
107f1b731dbSDmitry Kasatkin 	}
10846963b77SDavid Howells 	*p++ = ':';
1094573b64aSDavid Howells 	p = bin2hex(p, lookup, len);
11046963b77SDavid Howells 	*p = 0;
1113be4beafSMimi Zohar 
1124573b64aSDavid Howells 	pr_debug("Look up: \"%s\"\n", req);
1133be4beafSMimi Zohar 
1144573b64aSDavid Howells 	ref = keyring_search(make_key_ref(keyring, 1),
1154573b64aSDavid Howells 			     &key_type_asymmetric, req);
1164573b64aSDavid Howells 	if (IS_ERR(ref))
1174573b64aSDavid Howells 		pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
1184573b64aSDavid Howells 	kfree(req);
1193be4beafSMimi Zohar 
1204573b64aSDavid Howells 	if (IS_ERR(ref)) {
1214573b64aSDavid Howells 		switch (PTR_ERR(ref)) {
1223be4beafSMimi Zohar 			/* Hide some search errors */
1233be4beafSMimi Zohar 		case -EACCES:
1243be4beafSMimi Zohar 		case -ENOTDIR:
1253be4beafSMimi Zohar 		case -EAGAIN:
1263be4beafSMimi Zohar 			return ERR_PTR(-ENOKEY);
1273be4beafSMimi Zohar 		default:
1284573b64aSDavid Howells 			return ERR_CAST(ref);
1293be4beafSMimi Zohar 		}
1303be4beafSMimi Zohar 	}
1313be4beafSMimi Zohar 
1324573b64aSDavid Howells 	key = key_ref_to_ptr(ref);
1334573b64aSDavid Howells 	if (id && skid) {
1344573b64aSDavid Howells 		const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
1354573b64aSDavid Howells 		if (!kids->id[1]) {
1364573b64aSDavid Howells 			pr_debug("issuer+serial match, but expected SKID missing\n");
1374573b64aSDavid Howells 			goto reject;
1384573b64aSDavid Howells 		}
1394573b64aSDavid Howells 		if (!asymmetric_key_id_same(skid, kids->id[1])) {
1404573b64aSDavid Howells 			pr_debug("issuer+serial match, but SKID does not\n");
1414573b64aSDavid Howells 			goto reject;
1424573b64aSDavid Howells 		}
1434573b64aSDavid Howells 	}
1444573b64aSDavid Howells 
1454573b64aSDavid Howells 	pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
1464573b64aSDavid Howells 	return key;
1474573b64aSDavid Howells 
1484573b64aSDavid Howells reject:
1494573b64aSDavid Howells 	key_put(key);
1504573b64aSDavid Howells 	return ERR_PTR(-EKEYREJECTED);
1513be4beafSMimi Zohar }
152cf5b50fdSDavid Howells EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
1533be4beafSMimi Zohar 
154c26fd69fSDavid Howells /*
155b426beb6SDavid Howells  * Set up the signature parameters in an X.509 certificate.  This involves
156b426beb6SDavid Howells  * digesting the signed data and extracting the signature.
157c26fd69fSDavid Howells  */
158b426beb6SDavid Howells int x509_get_sig_params(struct x509_certificate *cert)
159c26fd69fSDavid Howells {
160c26fd69fSDavid Howells 	struct crypto_shash *tfm;
161c26fd69fSDavid Howells 	struct shash_desc *desc;
162c26fd69fSDavid Howells 	size_t digest_size, desc_size;
163b426beb6SDavid Howells 	void *digest;
164c26fd69fSDavid Howells 	int ret;
165c26fd69fSDavid Howells 
166c26fd69fSDavid Howells 	pr_devel("==>%s()\n", __func__);
167c26fd69fSDavid Howells 
16841559420SDavid Howells 	if (cert->unsupported_crypto)
16941559420SDavid Howells 		return -ENOPKG;
170b426beb6SDavid Howells 	if (cert->sig.rsa.s)
171b426beb6SDavid Howells 		return 0;
172b426beb6SDavid Howells 
173b426beb6SDavid Howells 	cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
174b426beb6SDavid Howells 	if (!cert->sig.rsa.s)
175b426beb6SDavid Howells 		return -ENOMEM;
176b426beb6SDavid Howells 	cert->sig.nr_mpi = 1;
177b426beb6SDavid Howells 
178c26fd69fSDavid Howells 	/* Allocate the hashing algorithm we're going to need and find out how
179c26fd69fSDavid Howells 	 * big the hash operational data will be.
180c26fd69fSDavid Howells 	 */
1813fe78ca2SDmitry Kasatkin 	tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0);
18241559420SDavid Howells 	if (IS_ERR(tfm)) {
18341559420SDavid Howells 		if (PTR_ERR(tfm) == -ENOENT) {
18441559420SDavid Howells 			cert->unsupported_crypto = true;
18541559420SDavid Howells 			return -ENOPKG;
18641559420SDavid Howells 		}
18741559420SDavid Howells 		return PTR_ERR(tfm);
18841559420SDavid Howells 	}
189c26fd69fSDavid Howells 
190c26fd69fSDavid Howells 	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
191c26fd69fSDavid Howells 	digest_size = crypto_shash_digestsize(tfm);
192c26fd69fSDavid Howells 
193b426beb6SDavid Howells 	/* We allocate the hash operational data storage on the end of the
194b426beb6SDavid Howells 	 * digest storage space.
195c26fd69fSDavid Howells 	 */
196c26fd69fSDavid Howells 	ret = -ENOMEM;
197b426beb6SDavid Howells 	digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
198b426beb6SDavid Howells 	if (!digest)
199b426beb6SDavid Howells 		goto error;
200c26fd69fSDavid Howells 
201b426beb6SDavid Howells 	cert->sig.digest = digest;
202b426beb6SDavid Howells 	cert->sig.digest_size = digest_size;
203c26fd69fSDavid Howells 
204b426beb6SDavid Howells 	desc = digest + digest_size;
205c26fd69fSDavid Howells 	desc->tfm = tfm;
206c26fd69fSDavid Howells 	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
207c26fd69fSDavid Howells 
208c26fd69fSDavid Howells 	ret = crypto_shash_init(desc);
209c26fd69fSDavid Howells 	if (ret < 0)
210c26fd69fSDavid Howells 		goto error;
211b426beb6SDavid Howells 	might_sleep();
212b426beb6SDavid Howells 	ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
213c26fd69fSDavid Howells error:
214c26fd69fSDavid Howells 	crypto_free_shash(tfm);
215c26fd69fSDavid Howells 	pr_devel("<==%s() = %d\n", __func__, ret);
216c26fd69fSDavid Howells 	return ret;
217c26fd69fSDavid Howells }
218b426beb6SDavid Howells EXPORT_SYMBOL_GPL(x509_get_sig_params);
219b426beb6SDavid Howells 
220b426beb6SDavid Howells /*
221b426beb6SDavid Howells  * Check the signature on a certificate using the provided public key
222b426beb6SDavid Howells  */
223b426beb6SDavid Howells int x509_check_signature(const struct public_key *pub,
224b426beb6SDavid Howells 			 struct x509_certificate *cert)
225b426beb6SDavid Howells {
226b426beb6SDavid Howells 	int ret;
227b426beb6SDavid Howells 
228b426beb6SDavid Howells 	pr_devel("==>%s()\n", __func__);
229b426beb6SDavid Howells 
230b426beb6SDavid Howells 	ret = x509_get_sig_params(cert);
231b426beb6SDavid Howells 	if (ret < 0)
232b426beb6SDavid Howells 		return ret;
233b426beb6SDavid Howells 
234b426beb6SDavid Howells 	ret = public_key_verify_signature(pub, &cert->sig);
23541559420SDavid Howells 	if (ret == -ENOPKG)
23641559420SDavid Howells 		cert->unsupported_crypto = true;
237b426beb6SDavid Howells 	pr_debug("Cert Verification: %d\n", ret);
238b426beb6SDavid Howells 	return ret;
239b426beb6SDavid Howells }
240b426beb6SDavid Howells EXPORT_SYMBOL_GPL(x509_check_signature);
241c26fd69fSDavid Howells 
242c26fd69fSDavid Howells /*
2433be4beafSMimi Zohar  * Check the new certificate against the ones in the trust keyring.  If one of
2443be4beafSMimi Zohar  * those is the signing key and validates the new certificate, then mark the
2453be4beafSMimi Zohar  * new certificate as being trusted.
2463be4beafSMimi Zohar  *
2473be4beafSMimi Zohar  * Return 0 if the new certificate was successfully validated, 1 if we couldn't
2483be4beafSMimi Zohar  * find a matching parent certificate in the trusted list and an error if there
2493be4beafSMimi Zohar  * is a matching certificate but the signature check fails.
2503be4beafSMimi Zohar  */
2513be4beafSMimi Zohar static int x509_validate_trust(struct x509_certificate *cert,
2523be4beafSMimi Zohar 			       struct key *trust_keyring)
2533be4beafSMimi Zohar {
2543be4beafSMimi Zohar 	struct key *key;
2553be4beafSMimi Zohar 	int ret = 1;
2563be4beafSMimi Zohar 
2573be4beafSMimi Zohar 	if (!trust_keyring)
2583be4beafSMimi Zohar 		return -EOPNOTSUPP;
2593be4beafSMimi Zohar 
260b92e6570SDavid Howells 	if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid))
261ffb70f61SDmitry Kasatkin 		return -EPERM;
262ffb70f61SDmitry Kasatkin 
2634573b64aSDavid Howells 	key = x509_request_asymmetric_key(trust_keyring,
2644573b64aSDavid Howells 					  cert->akid_id, cert->akid_skid,
265f1b731dbSDmitry Kasatkin 					  false);
2663be4beafSMimi Zohar 	if (!IS_ERR(key))  {
26732c4741cSDmitry Kasatkin 		if (!use_builtin_keys
26832c4741cSDmitry Kasatkin 		    || test_bit(KEY_FLAG_BUILTIN, &key->flags))
269*146aa8b1SDavid Howells 			ret = x509_check_signature(key->payload.data[asym_crypto],
270*146aa8b1SDavid Howells 						   cert);
2713be4beafSMimi Zohar 		key_put(key);
2723be4beafSMimi Zohar 	}
2733be4beafSMimi Zohar 	return ret;
2743be4beafSMimi Zohar }
2753be4beafSMimi Zohar 
2763be4beafSMimi Zohar /*
277c26fd69fSDavid Howells  * Attempt to parse a data blob for a key as an X509 certificate.
278c26fd69fSDavid Howells  */
279c26fd69fSDavid Howells static int x509_key_preparse(struct key_preparsed_payload *prep)
280c26fd69fSDavid Howells {
28146963b77SDavid Howells 	struct asymmetric_key_ids *kids;
282c26fd69fSDavid Howells 	struct x509_certificate *cert;
28346963b77SDavid Howells 	const char *q;
284c26fd69fSDavid Howells 	size_t srlen, sulen;
28546963b77SDavid Howells 	char *desc = NULL, *p;
286c26fd69fSDavid Howells 	int ret;
287c26fd69fSDavid Howells 
288c26fd69fSDavid Howells 	cert = x509_cert_parse(prep->data, prep->datalen);
289c26fd69fSDavid Howells 	if (IS_ERR(cert))
290c26fd69fSDavid Howells 		return PTR_ERR(cert);
291c26fd69fSDavid Howells 
292c26fd69fSDavid Howells 	pr_devel("Cert Issuer: %s\n", cert->issuer);
293c26fd69fSDavid Howells 	pr_devel("Cert Subject: %s\n", cert->subject);
2942ecdb23bSDavid Howells 
2952ecdb23bSDavid Howells 	if (cert->pub->pkey_algo >= PKEY_ALGO__LAST ||
2962ecdb23bSDavid Howells 	    cert->sig.pkey_algo >= PKEY_ALGO__LAST ||
2972ecdb23bSDavid Howells 	    cert->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
2982ecdb23bSDavid Howells 	    !pkey_algo[cert->pub->pkey_algo] ||
2992ecdb23bSDavid Howells 	    !pkey_algo[cert->sig.pkey_algo] ||
3003fe78ca2SDmitry Kasatkin 	    !hash_algo_name[cert->sig.pkey_hash_algo]) {
3012ecdb23bSDavid Howells 		ret = -ENOPKG;
3022ecdb23bSDavid Howells 		goto error_free_cert;
3032ecdb23bSDavid Howells 	}
3042ecdb23bSDavid Howells 
30567f7d60bSDavid Howells 	pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
306fd19a3d1SDavid Howells 	pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to);
307c7c8bb23SDmitry Kasatkin 	pr_devel("Cert Signature: %s + %s\n",
308c7c8bb23SDmitry Kasatkin 		 pkey_algo_name[cert->sig.pkey_algo],
3093fe78ca2SDmitry Kasatkin 		 hash_algo_name[cert->sig.pkey_hash_algo]);
310c26fd69fSDavid Howells 
31167f7d60bSDavid Howells 	cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
312c26fd69fSDavid Howells 	cert->pub->id_type = PKEY_ID_X509;
313c26fd69fSDavid Howells 
31417334cabSDavid Howells 	/* Check the signature on the key if it appears to be self-signed */
3154573b64aSDavid Howells 	if ((!cert->akid_skid && !cert->akid_id) ||
3164573b64aSDavid Howells 	    asymmetric_key_id_same(cert->skid, cert->akid_skid) ||
3174573b64aSDavid Howells 	    asymmetric_key_id_same(cert->id, cert->akid_id)) {
3183be4beafSMimi Zohar 		ret = x509_check_signature(cert->pub, cert); /* self-signed */
319c26fd69fSDavid Howells 		if (ret < 0)
320c26fd69fSDavid Howells 			goto error_free_cert;
3213be4beafSMimi Zohar 	} else if (!prep->trusted) {
3223be4beafSMimi Zohar 		ret = x509_validate_trust(cert, get_system_trusted_keyring());
3233be4beafSMimi Zohar 		if (!ret)
3243be4beafSMimi Zohar 			prep->trusted = 1;
325c26fd69fSDavid Howells 	}
326c26fd69fSDavid Howells 
327c26fd69fSDavid Howells 	/* Propose a description */
328c26fd69fSDavid Howells 	sulen = strlen(cert->subject);
329dd2f6c44SDavid Howells 	if (cert->raw_skid) {
330dd2f6c44SDavid Howells 		srlen = cert->raw_skid_size;
331dd2f6c44SDavid Howells 		q = cert->raw_skid;
332dd2f6c44SDavid Howells 	} else {
33346963b77SDavid Howells 		srlen = cert->raw_serial_size;
33446963b77SDavid Howells 		q = cert->raw_serial;
335dd2f6c44SDavid Howells 	}
33646963b77SDavid Howells 
337c26fd69fSDavid Howells 	ret = -ENOMEM;
33846963b77SDavid Howells 	desc = kmalloc(sulen + 2 + srlen * 2 + 1, GFP_KERNEL);
339c26fd69fSDavid Howells 	if (!desc)
340c26fd69fSDavid Howells 		goto error_free_cert;
34146963b77SDavid Howells 	p = memcpy(desc, cert->subject, sulen);
34246963b77SDavid Howells 	p += sulen;
34346963b77SDavid Howells 	*p++ = ':';
34446963b77SDavid Howells 	*p++ = ' ';
34546963b77SDavid Howells 	p = bin2hex(p, q, srlen);
34646963b77SDavid Howells 	*p = 0;
34746963b77SDavid Howells 
34846963b77SDavid Howells 	kids = kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL);
34946963b77SDavid Howells 	if (!kids)
35046963b77SDavid Howells 		goto error_free_desc;
35146963b77SDavid Howells 	kids->id[0] = cert->id;
35246963b77SDavid Howells 	kids->id[1] = cert->skid;
353c26fd69fSDavid Howells 
354c26fd69fSDavid Howells 	/* We're pinning the module by being linked against it */
355c26fd69fSDavid Howells 	__module_get(public_key_subtype.owner);
356*146aa8b1SDavid Howells 	prep->payload.data[asym_subtype] = &public_key_subtype;
357*146aa8b1SDavid Howells 	prep->payload.data[asym_key_ids] = kids;
358*146aa8b1SDavid Howells 	prep->payload.data[asym_crypto] = cert->pub;
359c26fd69fSDavid Howells 	prep->description = desc;
360c26fd69fSDavid Howells 	prep->quotalen = 100;
361c26fd69fSDavid Howells 
362c26fd69fSDavid Howells 	/* We've finished with the certificate */
363c26fd69fSDavid Howells 	cert->pub = NULL;
36446963b77SDavid Howells 	cert->id = NULL;
36546963b77SDavid Howells 	cert->skid = NULL;
366c26fd69fSDavid Howells 	desc = NULL;
367c26fd69fSDavid Howells 	ret = 0;
368c26fd69fSDavid Howells 
36946963b77SDavid Howells error_free_desc:
37046963b77SDavid Howells 	kfree(desc);
371c26fd69fSDavid Howells error_free_cert:
372c26fd69fSDavid Howells 	x509_free_certificate(cert);
373c26fd69fSDavid Howells 	return ret;
374c26fd69fSDavid Howells }
375c26fd69fSDavid Howells 
376c26fd69fSDavid Howells static struct asymmetric_key_parser x509_key_parser = {
377c26fd69fSDavid Howells 	.owner	= THIS_MODULE,
378c26fd69fSDavid Howells 	.name	= "x509",
379c26fd69fSDavid Howells 	.parse	= x509_key_preparse,
380c26fd69fSDavid Howells };
381c26fd69fSDavid Howells 
382c26fd69fSDavid Howells /*
383c26fd69fSDavid Howells  * Module stuff
384c26fd69fSDavid Howells  */
385c26fd69fSDavid Howells static int __init x509_key_init(void)
386c26fd69fSDavid Howells {
387c26fd69fSDavid Howells 	return register_asymmetric_key_parser(&x509_key_parser);
388c26fd69fSDavid Howells }
389c26fd69fSDavid Howells 
390c26fd69fSDavid Howells static void __exit x509_key_exit(void)
391c26fd69fSDavid Howells {
392c26fd69fSDavid Howells 	unregister_asymmetric_key_parser(&x509_key_parser);
393c26fd69fSDavid Howells }
394c26fd69fSDavid Howells 
395c26fd69fSDavid Howells module_init(x509_key_init);
396c26fd69fSDavid Howells module_exit(x509_key_exit);
397e19aaa7dSKonstantin Khlebnikov 
398e19aaa7dSKonstantin Khlebnikov MODULE_DESCRIPTION("X.509 certificate parser");
399e19aaa7dSKonstantin Khlebnikov MODULE_LICENSE("GPL");
400