1b4d0d230SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2c26fd69fSDavid Howells /* X.509 certificate parser
3c26fd69fSDavid Howells  *
4c26fd69fSDavid Howells  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
5c26fd69fSDavid Howells  * Written by David Howells (dhowells@redhat.com)
6c26fd69fSDavid Howells  */
7c26fd69fSDavid Howells 
8c26fd69fSDavid Howells #define pr_fmt(fmt) "X.509: "fmt
9c26fd69fSDavid Howells #include <linux/kernel.h>
10ace0107aSDavid Howells #include <linux/export.h>
11c26fd69fSDavid Howells #include <linux/slab.h>
12c26fd69fSDavid Howells #include <linux/err.h>
13c26fd69fSDavid Howells #include <linux/oid_registry.h>
14db6c43bdSTadeusz Struk #include <crypto/public_key.h>
15c26fd69fSDavid Howells #include "x509_parser.h"
164fa8bc94SMasahiro Yamada #include "x509.asn1.h"
174fa8bc94SMasahiro Yamada #include "x509_akid.asn1.h"
18c26fd69fSDavid Howells 
19c26fd69fSDavid Howells struct x509_parse_context {
20c26fd69fSDavid Howells 	struct x509_certificate	*cert;		/* Certificate being constructed */
21c26fd69fSDavid Howells 	unsigned long	data;			/* Start of data */
22c26fd69fSDavid Howells 	const void	*key;			/* Key data */
23c26fd69fSDavid Howells 	size_t		key_size;		/* Size of key data */
24f1774cb8SVitaly Chikunov 	const void	*params;		/* Key parameters */
25f1774cb8SVitaly Chikunov 	size_t		params_size;		/* Size of key parameters */
268f2a7b51SEric Biggers 	enum OID	key_algo;		/* Algorithm used by the cert's key */
27c26fd69fSDavid Howells 	enum OID	last_oid;		/* Last OID encountered */
288f2a7b51SEric Biggers 	enum OID	sig_algo;		/* Algorithm used to sign the cert */
29c26fd69fSDavid Howells 	u8		o_size;			/* Size of organizationName (O) */
30c26fd69fSDavid Howells 	u8		cn_size;		/* Size of commonName (CN) */
31c26fd69fSDavid Howells 	u8		email_size;		/* Size of emailAddress */
32c26fd69fSDavid Howells 	u16		o_offset;		/* Offset of organizationName (O) */
33c26fd69fSDavid Howells 	u16		cn_offset;		/* Offset of commonName (CN) */
34c26fd69fSDavid Howells 	u16		email_offset;		/* Offset of emailAddress */
35b92e6570SDavid Howells 	unsigned	raw_akid_size;
36b92e6570SDavid Howells 	const void	*raw_akid;		/* Raw authorityKeyId in ASN.1 */
37b92e6570SDavid Howells 	const void	*akid_raw_issuer;	/* Raw directoryName in authorityKeyId */
38b92e6570SDavid Howells 	unsigned	akid_raw_issuer_size;
39c26fd69fSDavid Howells };
40c26fd69fSDavid Howells 
41c26fd69fSDavid Howells /*
42c26fd69fSDavid Howells  * Free an X.509 certificate
43c26fd69fSDavid Howells  */
x509_free_certificate(struct x509_certificate * cert)44c26fd69fSDavid Howells void x509_free_certificate(struct x509_certificate *cert)
45c26fd69fSDavid Howells {
46c26fd69fSDavid Howells 	if (cert) {
473b764563SDavid Howells 		public_key_free(cert->pub);
4877d0910dSDavid Howells 		public_key_signature_free(cert->sig);
49c26fd69fSDavid Howells 		kfree(cert->issuer);
50c26fd69fSDavid Howells 		kfree(cert->subject);
5146963b77SDavid Howells 		kfree(cert->id);
5246963b77SDavid Howells 		kfree(cert->skid);
53c26fd69fSDavid Howells 		kfree(cert);
54c26fd69fSDavid Howells 	}
55c26fd69fSDavid Howells }
56ace0107aSDavid Howells EXPORT_SYMBOL_GPL(x509_free_certificate);
57c26fd69fSDavid Howells 
58c26fd69fSDavid Howells /*
59c26fd69fSDavid Howells  * Parse an X.509 certificate
60c26fd69fSDavid Howells  */
x509_cert_parse(const void * data,size_t datalen)61c26fd69fSDavid Howells struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
62c26fd69fSDavid Howells {
63c26fd69fSDavid Howells 	struct x509_certificate *cert;
64c26fd69fSDavid Howells 	struct x509_parse_context *ctx;
6546963b77SDavid Howells 	struct asymmetric_key_id *kid;
66c26fd69fSDavid Howells 	long ret;
67c26fd69fSDavid Howells 
68c26fd69fSDavid Howells 	ret = -ENOMEM;
69c26fd69fSDavid Howells 	cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL);
70c26fd69fSDavid Howells 	if (!cert)
71c26fd69fSDavid Howells 		goto error_no_cert;
72c26fd69fSDavid Howells 	cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
73c26fd69fSDavid Howells 	if (!cert->pub)
74c26fd69fSDavid Howells 		goto error_no_ctx;
7577d0910dSDavid Howells 	cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL);
7677d0910dSDavid Howells 	if (!cert->sig)
7777d0910dSDavid Howells 		goto error_no_ctx;
78c26fd69fSDavid Howells 	ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
79c26fd69fSDavid Howells 	if (!ctx)
80c26fd69fSDavid Howells 		goto error_no_ctx;
81c26fd69fSDavid Howells 
82c26fd69fSDavid Howells 	ctx->cert = cert;
83c26fd69fSDavid Howells 	ctx->data = (unsigned long)data;
84c26fd69fSDavid Howells 
85c26fd69fSDavid Howells 	/* Attempt to decode the certificate */
86c26fd69fSDavid Howells 	ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen);
87c26fd69fSDavid Howells 	if (ret < 0)
88c26fd69fSDavid Howells 		goto error_decode;
89c26fd69fSDavid Howells 
90b92e6570SDavid Howells 	/* Decode the AuthorityKeyIdentifier */
91b92e6570SDavid Howells 	if (ctx->raw_akid) {
92b92e6570SDavid Howells 		pr_devel("AKID: %u %*phN\n",
93b92e6570SDavid Howells 			 ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid);
94b92e6570SDavid Howells 		ret = asn1_ber_decoder(&x509_akid_decoder, ctx,
95b92e6570SDavid Howells 				       ctx->raw_akid, ctx->raw_akid_size);
96b92e6570SDavid Howells 		if (ret < 0) {
97b92e6570SDavid Howells 			pr_warn("Couldn't decode AuthKeyIdentifier\n");
98b92e6570SDavid Howells 			goto error_decode;
99b92e6570SDavid Howells 		}
100b92e6570SDavid Howells 	}
101b92e6570SDavid Howells 
1024e880168SDan Carpenter 	ret = -ENOMEM;
103db6c43bdSTadeusz Struk 	cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL);
104db6c43bdSTadeusz Struk 	if (!cert->pub->key)
105c26fd69fSDavid Howells 		goto error_decode;
106c26fd69fSDavid Howells 
107db6c43bdSTadeusz Struk 	cert->pub->keylen = ctx->key_size;
108db6c43bdSTadeusz Struk 
109f1774cb8SVitaly Chikunov 	cert->pub->params = kmemdup(ctx->params, ctx->params_size, GFP_KERNEL);
110f1774cb8SVitaly Chikunov 	if (!cert->pub->params)
111f1774cb8SVitaly Chikunov 		goto error_decode;
112f1774cb8SVitaly Chikunov 
113f1774cb8SVitaly Chikunov 	cert->pub->paramlen = ctx->params_size;
114f1774cb8SVitaly Chikunov 	cert->pub->algo = ctx->key_algo;
115f1774cb8SVitaly Chikunov 
1166c2dc5aeSDavid Howells 	/* Grab the signature bits */
1176c2dc5aeSDavid Howells 	ret = x509_get_sig_params(cert);
1186c2dc5aeSDavid Howells 	if (ret < 0)
1196c2dc5aeSDavid Howells 		goto error_decode;
1206c2dc5aeSDavid Howells 
12146963b77SDavid Howells 	/* Generate cert issuer + serial number key ID */
12246963b77SDavid Howells 	kid = asymmetric_key_generate_id(cert->raw_serial,
12346963b77SDavid Howells 					 cert->raw_serial_size,
12446963b77SDavid Howells 					 cert->raw_issuer,
12546963b77SDavid Howells 					 cert->raw_issuer_size);
12646963b77SDavid Howells 	if (IS_ERR(kid)) {
12746963b77SDavid Howells 		ret = PTR_ERR(kid);
12846963b77SDavid Howells 		goto error_decode;
12946963b77SDavid Howells 	}
13046963b77SDavid Howells 	cert->id = kid;
13146963b77SDavid Howells 
1326c2dc5aeSDavid Howells 	/* Detect self-signed certificates */
1336c2dc5aeSDavid Howells 	ret = x509_check_for_self_signed(cert);
1346c2dc5aeSDavid Howells 	if (ret < 0)
1356c2dc5aeSDavid Howells 		goto error_decode;
1366c2dc5aeSDavid Howells 
137c26fd69fSDavid Howells 	kfree(ctx);
138c26fd69fSDavid Howells 	return cert;
139c26fd69fSDavid Howells 
140c26fd69fSDavid Howells error_decode:
141c26fd69fSDavid Howells 	kfree(ctx);
142c26fd69fSDavid Howells error_no_ctx:
143c26fd69fSDavid Howells 	x509_free_certificate(cert);
144c26fd69fSDavid Howells error_no_cert:
145c26fd69fSDavid Howells 	return ERR_PTR(ret);
146c26fd69fSDavid Howells }
147ace0107aSDavid Howells EXPORT_SYMBOL_GPL(x509_cert_parse);
148c26fd69fSDavid Howells 
149c26fd69fSDavid Howells /*
150c26fd69fSDavid Howells  * Note an OID when we find one for later processing when we know how
151c26fd69fSDavid Howells  * to interpret it.
152c26fd69fSDavid Howells  */
x509_note_OID(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)153c26fd69fSDavid Howells int x509_note_OID(void *context, size_t hdrlen,
154c26fd69fSDavid Howells 	     unsigned char tag,
155c26fd69fSDavid Howells 	     const void *value, size_t vlen)
156c26fd69fSDavid Howells {
157c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
158c26fd69fSDavid Howells 
159c26fd69fSDavid Howells 	ctx->last_oid = look_up_OID(value, vlen);
160c26fd69fSDavid Howells 	if (ctx->last_oid == OID__NR) {
161c26fd69fSDavid Howells 		char buffer[50];
162c26fd69fSDavid Howells 		sprint_oid(value, vlen, buffer, sizeof(buffer));
163cf75446eSRandy Dunlap 		pr_debug("Unknown OID: [%lu] %s\n",
164c26fd69fSDavid Howells 			 (unsigned long)value - ctx->data, buffer);
165c26fd69fSDavid Howells 	}
166c26fd69fSDavid Howells 	return 0;
167c26fd69fSDavid Howells }
168c26fd69fSDavid Howells 
169c26fd69fSDavid Howells /*
170c26fd69fSDavid Howells  * Save the position of the TBS data so that we can check the signature over it
171c26fd69fSDavid Howells  * later.
172c26fd69fSDavid Howells  */
x509_note_tbs_certificate(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)173c26fd69fSDavid Howells int x509_note_tbs_certificate(void *context, size_t hdrlen,
174c26fd69fSDavid Howells 			      unsigned char tag,
175c26fd69fSDavid Howells 			      const void *value, size_t vlen)
176c26fd69fSDavid Howells {
177c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
178c26fd69fSDavid Howells 
179c26fd69fSDavid Howells 	pr_debug("x509_note_tbs_certificate(,%zu,%02x,%ld,%zu)!\n",
180c26fd69fSDavid Howells 		 hdrlen, tag, (unsigned long)value - ctx->data, vlen);
181c26fd69fSDavid Howells 
182c26fd69fSDavid Howells 	ctx->cert->tbs = value - hdrlen;
183c26fd69fSDavid Howells 	ctx->cert->tbs_size = vlen + hdrlen;
184c26fd69fSDavid Howells 	return 0;
185c26fd69fSDavid Howells }
186c26fd69fSDavid Howells 
187c26fd69fSDavid Howells /*
1888f2a7b51SEric Biggers  * Record the algorithm that was used to sign this certificate.
189c26fd69fSDavid Howells  */
x509_note_sig_algo(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)1908f2a7b51SEric Biggers int x509_note_sig_algo(void *context, size_t hdrlen, unsigned char tag,
191c26fd69fSDavid Howells 		       const void *value, size_t vlen)
192c26fd69fSDavid Howells {
193c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
194c26fd69fSDavid Howells 
195c26fd69fSDavid Howells 	pr_debug("PubKey Algo: %u\n", ctx->last_oid);
196c26fd69fSDavid Howells 
197c26fd69fSDavid Howells 	switch (ctx->last_oid) {
198c26fd69fSDavid Howells 	case OID_md2WithRSAEncryption:
199c26fd69fSDavid Howells 	case OID_md3WithRSAEncryption:
200c26fd69fSDavid Howells 	default:
201c26fd69fSDavid Howells 		return -ENOPKG; /* Unsupported combination */
202c26fd69fSDavid Howells 
203c26fd69fSDavid Howells 	case OID_md4WithRSAEncryption:
20477d0910dSDavid Howells 		ctx->cert->sig->hash_algo = "md4";
20503988490SDavid Howells 		goto rsa_pkcs1;
206c26fd69fSDavid Howells 
207c26fd69fSDavid Howells 	case OID_sha1WithRSAEncryption:
20877d0910dSDavid Howells 		ctx->cert->sig->hash_algo = "sha1";
20903988490SDavid Howells 		goto rsa_pkcs1;
210c26fd69fSDavid Howells 
211c26fd69fSDavid Howells 	case OID_sha256WithRSAEncryption:
21277d0910dSDavid Howells 		ctx->cert->sig->hash_algo = "sha256";
21303988490SDavid Howells 		goto rsa_pkcs1;
214c26fd69fSDavid Howells 
215c26fd69fSDavid Howells 	case OID_sha384WithRSAEncryption:
21677d0910dSDavid Howells 		ctx->cert->sig->hash_algo = "sha384";
21703988490SDavid Howells 		goto rsa_pkcs1;
218c26fd69fSDavid Howells 
219c26fd69fSDavid Howells 	case OID_sha512WithRSAEncryption:
22077d0910dSDavid Howells 		ctx->cert->sig->hash_algo = "sha512";
22103988490SDavid Howells 		goto rsa_pkcs1;
222c26fd69fSDavid Howells 
223c26fd69fSDavid Howells 	case OID_sha224WithRSAEncryption:
22477d0910dSDavid Howells 		ctx->cert->sig->hash_algo = "sha224";
22503988490SDavid Howells 		goto rsa_pkcs1;
2260d7a7864SVitaly Chikunov 
227299f561aSStefan Berger 	case OID_id_ecdsa_with_sha1:
228299f561aSStefan Berger 		ctx->cert->sig->hash_algo = "sha1";
229299f561aSStefan Berger 		goto ecdsa;
230299f561aSStefan Berger 
231299f561aSStefan Berger 	case OID_id_ecdsa_with_sha224:
232299f561aSStefan Berger 		ctx->cert->sig->hash_algo = "sha224";
233299f561aSStefan Berger 		goto ecdsa;
234299f561aSStefan Berger 
235299f561aSStefan Berger 	case OID_id_ecdsa_with_sha256:
236299f561aSStefan Berger 		ctx->cert->sig->hash_algo = "sha256";
237299f561aSStefan Berger 		goto ecdsa;
238299f561aSStefan Berger 
239299f561aSStefan Berger 	case OID_id_ecdsa_with_sha384:
240299f561aSStefan Berger 		ctx->cert->sig->hash_algo = "sha384";
241299f561aSStefan Berger 		goto ecdsa;
242299f561aSStefan Berger 
243299f561aSStefan Berger 	case OID_id_ecdsa_with_sha512:
244299f561aSStefan Berger 		ctx->cert->sig->hash_algo = "sha512";
245299f561aSStefan Berger 		goto ecdsa;
246299f561aSStefan Berger 
2470d7a7864SVitaly Chikunov 	case OID_gost2012Signature256:
2480d7a7864SVitaly Chikunov 		ctx->cert->sig->hash_algo = "streebog256";
2490d7a7864SVitaly Chikunov 		goto ecrdsa;
2500d7a7864SVitaly Chikunov 
2510d7a7864SVitaly Chikunov 	case OID_gost2012Signature512:
2520d7a7864SVitaly Chikunov 		ctx->cert->sig->hash_algo = "streebog512";
2530d7a7864SVitaly Chikunov 		goto ecrdsa;
254254f84f5STianjia Zhang 
255254f84f5STianjia Zhang 	case OID_SM2_with_SM3:
256254f84f5STianjia Zhang 		ctx->cert->sig->hash_algo = "sm3";
257254f84f5STianjia Zhang 		goto sm2;
258c26fd69fSDavid Howells 	}
259c26fd69fSDavid Howells 
26003988490SDavid Howells rsa_pkcs1:
26103988490SDavid Howells 	ctx->cert->sig->pkey_algo = "rsa";
26203988490SDavid Howells 	ctx->cert->sig->encoding = "pkcs1";
2638f2a7b51SEric Biggers 	ctx->sig_algo = ctx->last_oid;
264c26fd69fSDavid Howells 	return 0;
2650d7a7864SVitaly Chikunov ecrdsa:
2660d7a7864SVitaly Chikunov 	ctx->cert->sig->pkey_algo = "ecrdsa";
2670d7a7864SVitaly Chikunov 	ctx->cert->sig->encoding = "raw";
2688f2a7b51SEric Biggers 	ctx->sig_algo = ctx->last_oid;
2690d7a7864SVitaly Chikunov 	return 0;
270254f84f5STianjia Zhang sm2:
271254f84f5STianjia Zhang 	ctx->cert->sig->pkey_algo = "sm2";
272254f84f5STianjia Zhang 	ctx->cert->sig->encoding = "raw";
2738f2a7b51SEric Biggers 	ctx->sig_algo = ctx->last_oid;
274254f84f5STianjia Zhang 	return 0;
275299f561aSStefan Berger ecdsa:
276299f561aSStefan Berger 	ctx->cert->sig->pkey_algo = "ecdsa";
277299f561aSStefan Berger 	ctx->cert->sig->encoding = "x962";
2788f2a7b51SEric Biggers 	ctx->sig_algo = ctx->last_oid;
279299f561aSStefan Berger 	return 0;
280c26fd69fSDavid Howells }
281c26fd69fSDavid Howells 
282c26fd69fSDavid Howells /*
283c26fd69fSDavid Howells  * Note the whereabouts and type of the signature.
284c26fd69fSDavid Howells  */
x509_note_signature(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)285c26fd69fSDavid Howells int x509_note_signature(void *context, size_t hdrlen,
286c26fd69fSDavid Howells 			unsigned char tag,
287c26fd69fSDavid Howells 			const void *value, size_t vlen)
288c26fd69fSDavid Howells {
289c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
290c26fd69fSDavid Howells 
2918f2a7b51SEric Biggers 	pr_debug("Signature: alg=%u, size=%zu\n", ctx->last_oid, vlen);
292c26fd69fSDavid Howells 
2938f2a7b51SEric Biggers 	/*
2948f2a7b51SEric Biggers 	 * In X.509 certificates, the signature's algorithm is stored in two
2958f2a7b51SEric Biggers 	 * places: inside the TBSCertificate (the data that is signed), and
2968f2a7b51SEric Biggers 	 * alongside the signature.  These *must* match.
2978f2a7b51SEric Biggers 	 */
2988f2a7b51SEric Biggers 	if (ctx->last_oid != ctx->sig_algo) {
2998f2a7b51SEric Biggers 		pr_warn("signatureAlgorithm (%u) differs from tbsCertificate.signature (%u)\n",
3008f2a7b51SEric Biggers 			ctx->last_oid, ctx->sig_algo);
301c26fd69fSDavid Howells 		return -EINVAL;
302c26fd69fSDavid Howells 	}
303c26fd69fSDavid Howells 
3040d7a7864SVitaly Chikunov 	if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 ||
305254f84f5STianjia Zhang 	    strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0 ||
306299f561aSStefan Berger 	    strcmp(ctx->cert->sig->pkey_algo, "sm2") == 0 ||
307299f561aSStefan Berger 	    strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0) {
308b65c32ecSMaciej S. Szmigiero 		/* Discard the BIT STRING metadata */
309b65c32ecSMaciej S. Szmigiero 		if (vlen < 1 || *(const u8 *)value != 0)
310b65c32ecSMaciej S. Szmigiero 			return -EBADMSG;
311b65c32ecSMaciej S. Szmigiero 
312b65c32ecSMaciej S. Szmigiero 		value++;
313b65c32ecSMaciej S. Szmigiero 		vlen--;
314b65c32ecSMaciej S. Szmigiero 	}
315b65c32ecSMaciej S. Szmigiero 
316b426beb6SDavid Howells 	ctx->cert->raw_sig = value;
317b426beb6SDavid Howells 	ctx->cert->raw_sig_size = vlen;
318c26fd69fSDavid Howells 	return 0;
319c26fd69fSDavid Howells }
320c26fd69fSDavid Howells 
321c26fd69fSDavid Howells /*
32284aabd46SDavid Howells  * Note the certificate serial number
32384aabd46SDavid Howells  */
x509_note_serial(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)32484aabd46SDavid Howells int x509_note_serial(void *context, size_t hdrlen,
32584aabd46SDavid Howells 		     unsigned char tag,
32684aabd46SDavid Howells 		     const void *value, size_t vlen)
32784aabd46SDavid Howells {
32884aabd46SDavid Howells 	struct x509_parse_context *ctx = context;
32984aabd46SDavid Howells 	ctx->cert->raw_serial = value;
33084aabd46SDavid Howells 	ctx->cert->raw_serial_size = vlen;
33184aabd46SDavid Howells 	return 0;
33284aabd46SDavid Howells }
33384aabd46SDavid Howells 
33484aabd46SDavid Howells /*
335c26fd69fSDavid Howells  * Note some of the name segments from which we'll fabricate a name.
336c26fd69fSDavid Howells  */
x509_extract_name_segment(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)337c26fd69fSDavid Howells int x509_extract_name_segment(void *context, size_t hdrlen,
338c26fd69fSDavid Howells 			      unsigned char tag,
339c26fd69fSDavid Howells 			      const void *value, size_t vlen)
340c26fd69fSDavid Howells {
341c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
342c26fd69fSDavid Howells 
343c26fd69fSDavid Howells 	switch (ctx->last_oid) {
344c26fd69fSDavid Howells 	case OID_commonName:
345c26fd69fSDavid Howells 		ctx->cn_size = vlen;
346c26fd69fSDavid Howells 		ctx->cn_offset = (unsigned long)value - ctx->data;
347c26fd69fSDavid Howells 		break;
348c26fd69fSDavid Howells 	case OID_organizationName:
349c26fd69fSDavid Howells 		ctx->o_size = vlen;
350c26fd69fSDavid Howells 		ctx->o_offset = (unsigned long)value - ctx->data;
351c26fd69fSDavid Howells 		break;
352c26fd69fSDavid Howells 	case OID_email_address:
353c26fd69fSDavid Howells 		ctx->email_size = vlen;
354c26fd69fSDavid Howells 		ctx->email_offset = (unsigned long)value - ctx->data;
355c26fd69fSDavid Howells 		break;
356c26fd69fSDavid Howells 	default:
357c26fd69fSDavid Howells 		break;
358c26fd69fSDavid Howells 	}
359c26fd69fSDavid Howells 
360c26fd69fSDavid Howells 	return 0;
361c26fd69fSDavid Howells }
362c26fd69fSDavid Howells 
363c26fd69fSDavid Howells /*
364c26fd69fSDavid Howells  * Fabricate and save the issuer and subject names
365c26fd69fSDavid Howells  */
x509_fabricate_name(struct x509_parse_context * ctx,size_t hdrlen,unsigned char tag,char ** _name,size_t vlen)366c26fd69fSDavid Howells static int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen,
367c26fd69fSDavid Howells 			       unsigned char tag,
368c26fd69fSDavid Howells 			       char **_name, size_t vlen)
369c26fd69fSDavid Howells {
370c26fd69fSDavid Howells 	const void *name, *data = (const void *)ctx->data;
371c26fd69fSDavid Howells 	size_t namesize;
372c26fd69fSDavid Howells 	char *buffer;
373c26fd69fSDavid Howells 
374c26fd69fSDavid Howells 	if (*_name)
375c26fd69fSDavid Howells 		return -EINVAL;
376c26fd69fSDavid Howells 
377c26fd69fSDavid Howells 	/* Empty name string if no material */
378c26fd69fSDavid Howells 	if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) {
379c26fd69fSDavid Howells 		buffer = kmalloc(1, GFP_KERNEL);
380c26fd69fSDavid Howells 		if (!buffer)
381c26fd69fSDavid Howells 			return -ENOMEM;
382c26fd69fSDavid Howells 		buffer[0] = 0;
383c26fd69fSDavid Howells 		goto done;
384c26fd69fSDavid Howells 	}
385c26fd69fSDavid Howells 
386c26fd69fSDavid Howells 	if (ctx->cn_size && ctx->o_size) {
387c26fd69fSDavid Howells 		/* Consider combining O and CN, but use only the CN if it is
388c26fd69fSDavid Howells 		 * prefixed by the O, or a significant portion thereof.
389c26fd69fSDavid Howells 		 */
390c26fd69fSDavid Howells 		namesize = ctx->cn_size;
391c26fd69fSDavid Howells 		name = data + ctx->cn_offset;
392c26fd69fSDavid Howells 		if (ctx->cn_size >= ctx->o_size &&
393c26fd69fSDavid Howells 		    memcmp(data + ctx->cn_offset, data + ctx->o_offset,
394c26fd69fSDavid Howells 			   ctx->o_size) == 0)
395c26fd69fSDavid Howells 			goto single_component;
396c26fd69fSDavid Howells 		if (ctx->cn_size >= 7 &&
397c26fd69fSDavid Howells 		    ctx->o_size >= 7 &&
398c26fd69fSDavid Howells 		    memcmp(data + ctx->cn_offset, data + ctx->o_offset, 7) == 0)
399c26fd69fSDavid Howells 			goto single_component;
400c26fd69fSDavid Howells 
401c26fd69fSDavid Howells 		buffer = kmalloc(ctx->o_size + 2 + ctx->cn_size + 1,
402c26fd69fSDavid Howells 				 GFP_KERNEL);
403c26fd69fSDavid Howells 		if (!buffer)
404c26fd69fSDavid Howells 			return -ENOMEM;
405c26fd69fSDavid Howells 
406c26fd69fSDavid Howells 		memcpy(buffer,
407c26fd69fSDavid Howells 		       data + ctx->o_offset, ctx->o_size);
408c26fd69fSDavid Howells 		buffer[ctx->o_size + 0] = ':';
409c26fd69fSDavid Howells 		buffer[ctx->o_size + 1] = ' ';
410c26fd69fSDavid Howells 		memcpy(buffer + ctx->o_size + 2,
411c26fd69fSDavid Howells 		       data + ctx->cn_offset, ctx->cn_size);
412c26fd69fSDavid Howells 		buffer[ctx->o_size + 2 + ctx->cn_size] = 0;
413c26fd69fSDavid Howells 		goto done;
414c26fd69fSDavid Howells 
415c26fd69fSDavid Howells 	} else if (ctx->cn_size) {
416c26fd69fSDavid Howells 		namesize = ctx->cn_size;
417c26fd69fSDavid Howells 		name = data + ctx->cn_offset;
418c26fd69fSDavid Howells 	} else if (ctx->o_size) {
419c26fd69fSDavid Howells 		namesize = ctx->o_size;
420c26fd69fSDavid Howells 		name = data + ctx->o_offset;
421c26fd69fSDavid Howells 	} else {
422c26fd69fSDavid Howells 		namesize = ctx->email_size;
423c26fd69fSDavid Howells 		name = data + ctx->email_offset;
424c26fd69fSDavid Howells 	}
425c26fd69fSDavid Howells 
426c26fd69fSDavid Howells single_component:
427c26fd69fSDavid Howells 	buffer = kmalloc(namesize + 1, GFP_KERNEL);
428c26fd69fSDavid Howells 	if (!buffer)
429c26fd69fSDavid Howells 		return -ENOMEM;
430c26fd69fSDavid Howells 	memcpy(buffer, name, namesize);
431c26fd69fSDavid Howells 	buffer[namesize] = 0;
432c26fd69fSDavid Howells 
433c26fd69fSDavid Howells done:
434c26fd69fSDavid Howells 	*_name = buffer;
435c26fd69fSDavid Howells 	ctx->cn_size = 0;
436c26fd69fSDavid Howells 	ctx->o_size = 0;
437c26fd69fSDavid Howells 	ctx->email_size = 0;
438c26fd69fSDavid Howells 	return 0;
439c26fd69fSDavid Howells }
440c26fd69fSDavid Howells 
x509_note_issuer(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)441c26fd69fSDavid Howells int x509_note_issuer(void *context, size_t hdrlen,
442c26fd69fSDavid Howells 		     unsigned char tag,
443c26fd69fSDavid Howells 		     const void *value, size_t vlen)
444c26fd69fSDavid Howells {
445c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
4467d30198eSAndrew Zaborowski 	struct asymmetric_key_id *kid;
4477d30198eSAndrew Zaborowski 
44884aabd46SDavid Howells 	ctx->cert->raw_issuer = value;
44984aabd46SDavid Howells 	ctx->cert->raw_issuer_size = vlen;
4507d30198eSAndrew Zaborowski 
4517d30198eSAndrew Zaborowski 	if (!ctx->cert->sig->auth_ids[2]) {
4527d30198eSAndrew Zaborowski 		kid = asymmetric_key_generate_id(value, vlen, "", 0);
4537d30198eSAndrew Zaborowski 		if (IS_ERR(kid))
4547d30198eSAndrew Zaborowski 			return PTR_ERR(kid);
4557d30198eSAndrew Zaborowski 		ctx->cert->sig->auth_ids[2] = kid;
4567d30198eSAndrew Zaborowski 	}
4577d30198eSAndrew Zaborowski 
458c26fd69fSDavid Howells 	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
459c26fd69fSDavid Howells }
460c26fd69fSDavid Howells 
x509_note_subject(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)461c26fd69fSDavid Howells int x509_note_subject(void *context, size_t hdrlen,
462c26fd69fSDavid Howells 		      unsigned char tag,
463c26fd69fSDavid Howells 		      const void *value, size_t vlen)
464c26fd69fSDavid Howells {
465c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
46684aabd46SDavid Howells 	ctx->cert->raw_subject = value;
46784aabd46SDavid Howells 	ctx->cert->raw_subject_size = vlen;
468c26fd69fSDavid Howells 	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
469c26fd69fSDavid Howells }
470c26fd69fSDavid Howells 
471c26fd69fSDavid Howells /*
472f1774cb8SVitaly Chikunov  * Extract the parameters for the public key
473f1774cb8SVitaly Chikunov  */
x509_note_params(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)474f1774cb8SVitaly Chikunov int x509_note_params(void *context, size_t hdrlen,
475f1774cb8SVitaly Chikunov 		     unsigned char tag,
476f1774cb8SVitaly Chikunov 		     const void *value, size_t vlen)
477f1774cb8SVitaly Chikunov {
478f1774cb8SVitaly Chikunov 	struct x509_parse_context *ctx = context;
479f1774cb8SVitaly Chikunov 
480f1774cb8SVitaly Chikunov 	/*
481f1774cb8SVitaly Chikunov 	 * AlgorithmIdentifier is used three times in the x509, we should skip
482f1774cb8SVitaly Chikunov 	 * first and ignore third, using second one which is after subject and
483f1774cb8SVitaly Chikunov 	 * before subjectPublicKey.
484f1774cb8SVitaly Chikunov 	 */
485f1774cb8SVitaly Chikunov 	if (!ctx->cert->raw_subject || ctx->key)
486f1774cb8SVitaly Chikunov 		return 0;
487f1774cb8SVitaly Chikunov 	ctx->params = value - hdrlen;
488f1774cb8SVitaly Chikunov 	ctx->params_size = vlen + hdrlen;
489f1774cb8SVitaly Chikunov 	return 0;
490f1774cb8SVitaly Chikunov }
491f1774cb8SVitaly Chikunov 
492f1774cb8SVitaly Chikunov /*
493c26fd69fSDavid Howells  * Extract the data for the public key algorithm
494c26fd69fSDavid Howells  */
x509_extract_key_data(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)495c26fd69fSDavid Howells int x509_extract_key_data(void *context, size_t hdrlen,
496c26fd69fSDavid Howells 			  unsigned char tag,
497c26fd69fSDavid Howells 			  const void *value, size_t vlen)
498c26fd69fSDavid Howells {
499c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
500d1a303e8SStefan Berger 	enum OID oid;
501c26fd69fSDavid Howells 
5020d7a7864SVitaly Chikunov 	ctx->key_algo = ctx->last_oid;
503254f84f5STianjia Zhang 	switch (ctx->last_oid) {
504254f84f5STianjia Zhang 	case OID_rsaEncryption:
5054e8ae72aSDavid Howells 		ctx->cert->pub->pkey_algo = "rsa";
506254f84f5STianjia Zhang 		break;
507254f84f5STianjia Zhang 	case OID_gost2012PKey256:
508254f84f5STianjia Zhang 	case OID_gost2012PKey512:
5090d7a7864SVitaly Chikunov 		ctx->cert->pub->pkey_algo = "ecrdsa";
510254f84f5STianjia Zhang 		break;
51174ad4334STianjia Zhang 	case OID_sm2:
51274ad4334STianjia Zhang 		ctx->cert->pub->pkey_algo = "sm2";
51374ad4334STianjia Zhang 		break;
514254f84f5STianjia Zhang 	case OID_id_ecPublicKey:
515d1a303e8SStefan Berger 		if (parse_OID(ctx->params, ctx->params_size, &oid) != 0)
516d1a303e8SStefan Berger 			return -EBADMSG;
517d1a303e8SStefan Berger 
518d1a303e8SStefan Berger 		switch (oid) {
519d1a303e8SStefan Berger 		case OID_sm2:
520254f84f5STianjia Zhang 			ctx->cert->pub->pkey_algo = "sm2";
521254f84f5STianjia Zhang 			break;
522299f561aSStefan Berger 		case OID_id_prime192v1:
523299f561aSStefan Berger 			ctx->cert->pub->pkey_algo = "ecdsa-nist-p192";
524299f561aSStefan Berger 			break;
525299f561aSStefan Berger 		case OID_id_prime256v1:
526299f561aSStefan Berger 			ctx->cert->pub->pkey_algo = "ecdsa-nist-p256";
527299f561aSStefan Berger 			break;
5282a8e6154SSaulo Alessandre 		case OID_id_ansip384r1:
5292a8e6154SSaulo Alessandre 			ctx->cert->pub->pkey_algo = "ecdsa-nist-p384";
5302a8e6154SSaulo Alessandre 			break;
531254f84f5STianjia Zhang 		default:
5320d7a7864SVitaly Chikunov 			return -ENOPKG;
533254f84f5STianjia Zhang 		}
534d1a303e8SStefan Berger 		break;
535d1a303e8SStefan Berger 	default:
536d1a303e8SStefan Berger 		return -ENOPKG;
537d1a303e8SStefan Berger 	}
53867f7d60bSDavid Howells 
53967f7d60bSDavid Howells 	/* Discard the BIT STRING metadata */
5400f30cbeaSEric Biggers 	if (vlen < 1 || *(const u8 *)value != 0)
5410f30cbeaSEric Biggers 		return -EBADMSG;
542c26fd69fSDavid Howells 	ctx->key = value + 1;
543c26fd69fSDavid Howells 	ctx->key_size = vlen - 1;
544c26fd69fSDavid Howells 	return 0;
545c26fd69fSDavid Howells }
546c26fd69fSDavid Howells 
54704b00bdbSChun-Yi Lee /* The keyIdentifier in AuthorityKeyIdentifier SEQUENCE is tag(CONT,PRIM,0) */
54804b00bdbSChun-Yi Lee #define SEQ_TAG_KEYID (ASN1_CONT << 6)
54904b00bdbSChun-Yi Lee 
550c26fd69fSDavid Howells /*
551c26fd69fSDavid Howells  * Process certificate extensions that are used to qualify the certificate.
552c26fd69fSDavid Howells  */
x509_process_extension(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)553c26fd69fSDavid Howells int x509_process_extension(void *context, size_t hdrlen,
554c26fd69fSDavid Howells 			   unsigned char tag,
555c26fd69fSDavid Howells 			   const void *value, size_t vlen)
556c26fd69fSDavid Howells {
557c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
55846963b77SDavid Howells 	struct asymmetric_key_id *kid;
559c26fd69fSDavid Howells 	const unsigned char *v = value;
560c26fd69fSDavid Howells 
561c26fd69fSDavid Howells 	pr_debug("Extension: %u\n", ctx->last_oid);
562c26fd69fSDavid Howells 
563c26fd69fSDavid Howells 	if (ctx->last_oid == OID_subjectKeyIdentifier) {
564c26fd69fSDavid Howells 		/* Get hold of the key fingerprint */
56546963b77SDavid Howells 		if (ctx->cert->skid || vlen < 3)
566c26fd69fSDavid Howells 			return -EBADMSG;
567c26fd69fSDavid Howells 		if (v[0] != ASN1_OTS || v[1] != vlen - 2)
568c26fd69fSDavid Howells 			return -EBADMSG;
569c26fd69fSDavid Howells 		v += 2;
570c26fd69fSDavid Howells 		vlen -= 2;
571c26fd69fSDavid Howells 
572dd2f6c44SDavid Howells 		ctx->cert->raw_skid_size = vlen;
573dd2f6c44SDavid Howells 		ctx->cert->raw_skid = v;
574a4c6e57fSDavid Howells 		kid = asymmetric_key_generate_id(v, vlen, "", 0);
57546963b77SDavid Howells 		if (IS_ERR(kid))
57646963b77SDavid Howells 			return PTR_ERR(kid);
57746963b77SDavid Howells 		ctx->cert->skid = kid;
57846963b77SDavid Howells 		pr_debug("subjkeyid %*phN\n", kid->len, kid->data);
579c26fd69fSDavid Howells 		return 0;
580c26fd69fSDavid Howells 	}
581c26fd69fSDavid Howells 
582*56767128SEric Snowberg 	if (ctx->last_oid == OID_keyUsage) {
583*56767128SEric Snowberg 		/*
584*56767128SEric Snowberg 		 * Get hold of the keyUsage bit string
585*56767128SEric Snowberg 		 * v[1] is the encoding size
586*56767128SEric Snowberg 		 *       (Expect either 0x02 or 0x03, making it 1 or 2 bytes)
587*56767128SEric Snowberg 		 * v[2] is the number of unused bits in the bit string
588*56767128SEric Snowberg 		 *       (If >= 3 keyCertSign is missing when v[1] = 0x02)
589*56767128SEric Snowberg 		 * v[3] and possibly v[4] contain the bit string
590*56767128SEric Snowberg 		 *
591*56767128SEric Snowberg 		 * From RFC 5280 4.2.1.3:
592*56767128SEric Snowberg 		 *   0x04 is where keyCertSign lands in this bit string
593*56767128SEric Snowberg 		 *   0x80 is where digitalSignature lands in this bit string
594*56767128SEric Snowberg 		 */
595*56767128SEric Snowberg 		if (v[0] != ASN1_BTS)
596*56767128SEric Snowberg 			return -EBADMSG;
597*56767128SEric Snowberg 		if (vlen < 4)
598*56767128SEric Snowberg 			return -EBADMSG;
599*56767128SEric Snowberg 		if (v[2] >= 8)
600*56767128SEric Snowberg 			return -EBADMSG;
601*56767128SEric Snowberg 		if (v[3] & 0x80)
602*56767128SEric Snowberg 			ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_DIGITALSIG;
603*56767128SEric Snowberg 		if (v[1] == 0x02 && v[2] <= 2 && (v[3] & 0x04))
604*56767128SEric Snowberg 			ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_KEYCERTSIGN;
605*56767128SEric Snowberg 		else if (vlen > 4 && v[1] == 0x03 && (v[3] & 0x04))
606*56767128SEric Snowberg 			ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_KEYCERTSIGN;
607*56767128SEric Snowberg 		return 0;
608*56767128SEric Snowberg 	}
609*56767128SEric Snowberg 
610c26fd69fSDavid Howells 	if (ctx->last_oid == OID_authorityKeyIdentifier) {
611c26fd69fSDavid Howells 		/* Get hold of the CA key fingerprint */
612b92e6570SDavid Howells 		ctx->raw_akid = v;
613b92e6570SDavid Howells 		ctx->raw_akid_size = vlen;
614c26fd69fSDavid Howells 		return 0;
615c26fd69fSDavid Howells 	}
616c26fd69fSDavid Howells 
61730eae2b0SEric Snowberg 	if (ctx->last_oid == OID_basicConstraints) {
61830eae2b0SEric Snowberg 		/*
61930eae2b0SEric Snowberg 		 * Get hold of the basicConstraints
62030eae2b0SEric Snowberg 		 * v[1] is the encoding size
62130eae2b0SEric Snowberg 		 *	(Expect 0x2 or greater, making it 1 or more bytes)
62230eae2b0SEric Snowberg 		 * v[2] is the encoding type
62330eae2b0SEric Snowberg 		 *	(Expect an ASN1_BOOL for the CA)
62430eae2b0SEric Snowberg 		 * v[3] is the contents of the ASN1_BOOL
62530eae2b0SEric Snowberg 		 *      (Expect 1 if the CA is TRUE)
62630eae2b0SEric Snowberg 		 * vlen should match the entire extension size
62730eae2b0SEric Snowberg 		 */
62830eae2b0SEric Snowberg 		if (v[0] != (ASN1_CONS_BIT | ASN1_SEQ))
62930eae2b0SEric Snowberg 			return -EBADMSG;
63030eae2b0SEric Snowberg 		if (vlen < 2)
63130eae2b0SEric Snowberg 			return -EBADMSG;
63230eae2b0SEric Snowberg 		if (v[1] != vlen - 2)
63330eae2b0SEric Snowberg 			return -EBADMSG;
63430eae2b0SEric Snowberg 		if (vlen >= 4 && v[1] != 0 && v[2] == ASN1_BOOL && v[3] == 1)
63530eae2b0SEric Snowberg 			ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_CA;
63630eae2b0SEric Snowberg 		return 0;
63730eae2b0SEric Snowberg 	}
63830eae2b0SEric Snowberg 
639c26fd69fSDavid Howells 	return 0;
640c26fd69fSDavid Howells }
641c26fd69fSDavid Howells 
642fd19a3d1SDavid Howells /**
643fd19a3d1SDavid Howells  * x509_decode_time - Decode an X.509 time ASN.1 object
644fd19a3d1SDavid Howells  * @_t: The time to fill in
645fd19a3d1SDavid Howells  * @hdrlen: The length of the object header
646fd19a3d1SDavid Howells  * @tag: The object tag
647fd19a3d1SDavid Howells  * @value: The object value
648fd19a3d1SDavid Howells  * @vlen: The size of the object value
649fd19a3d1SDavid Howells  *
650fd19a3d1SDavid Howells  * Decode an ASN.1 universal time or generalised time field into a struct the
651fd19a3d1SDavid Howells  * kernel can handle and check it for validity.  The time is decoded thus:
652fd19a3d1SDavid Howells  *
653fd19a3d1SDavid Howells  *	[RFC5280 §4.1.2.5]
654fd19a3d1SDavid Howells  *	CAs conforming to this profile MUST always encode certificate validity
655fd19a3d1SDavid Howells  *	dates through the year 2049 as UTCTime; certificate validity dates in
656fd19a3d1SDavid Howells  *	2050 or later MUST be encoded as GeneralizedTime.  Conforming
657fd19a3d1SDavid Howells  *	applications MUST be able to process validity dates that are encoded in
658fd19a3d1SDavid Howells  *	either UTCTime or GeneralizedTime.
659c26fd69fSDavid Howells  */
x509_decode_time(time64_t * _t,size_t hdrlen,unsigned char tag,const unsigned char * value,size_t vlen)660fd19a3d1SDavid Howells int x509_decode_time(time64_t *_t,  size_t hdrlen,
661c26fd69fSDavid Howells 		     unsigned char tag,
662c26fd69fSDavid Howells 		     const unsigned char *value, size_t vlen)
663c26fd69fSDavid Howells {
664ac4cbedfSDavid Howells 	static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30,
665fd19a3d1SDavid Howells 						       31, 31, 30, 31, 30, 31 };
666c26fd69fSDavid Howells 	const unsigned char *p = value;
667fd19a3d1SDavid Howells 	unsigned year, mon, day, hour, min, sec, mon_len;
668c26fd69fSDavid Howells 
669fd19a3d1SDavid Howells #define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; })
670c26fd69fSDavid Howells #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; })
671c26fd69fSDavid Howells 
672c26fd69fSDavid Howells 	if (tag == ASN1_UNITIM) {
673c26fd69fSDavid Howells 		/* UTCTime: YYMMDDHHMMSSZ */
674c26fd69fSDavid Howells 		if (vlen != 13)
675c26fd69fSDavid Howells 			goto unsupported_time;
676fd19a3d1SDavid Howells 		year = DD2bin(p);
677fd19a3d1SDavid Howells 		if (year >= 50)
678fd19a3d1SDavid Howells 			year += 1900;
679c26fd69fSDavid Howells 		else
680fd19a3d1SDavid Howells 			year += 2000;
681c26fd69fSDavid Howells 	} else if (tag == ASN1_GENTIM) {
682c26fd69fSDavid Howells 		/* GenTime: YYYYMMDDHHMMSSZ */
683c26fd69fSDavid Howells 		if (vlen != 15)
684c26fd69fSDavid Howells 			goto unsupported_time;
685fd19a3d1SDavid Howells 		year = DD2bin(p) * 100 + DD2bin(p);
686fd19a3d1SDavid Howells 		if (year >= 1950 && year <= 2049)
687fd19a3d1SDavid Howells 			goto invalid_time;
688c26fd69fSDavid Howells 	} else {
689c26fd69fSDavid Howells 		goto unsupported_time;
690c26fd69fSDavid Howells 	}
691c26fd69fSDavid Howells 
692fd19a3d1SDavid Howells 	mon  = DD2bin(p);
693fd19a3d1SDavid Howells 	day = DD2bin(p);
694fd19a3d1SDavid Howells 	hour = DD2bin(p);
695fd19a3d1SDavid Howells 	min  = DD2bin(p);
696fd19a3d1SDavid Howells 	sec  = DD2bin(p);
697c26fd69fSDavid Howells 
698c26fd69fSDavid Howells 	if (*p != 'Z')
699c26fd69fSDavid Howells 		goto unsupported_time;
700c26fd69fSDavid Howells 
701cc25b994SDavid Howells 	if (year < 1970 ||
702cc25b994SDavid Howells 	    mon < 1 || mon > 12)
703cc25b994SDavid Howells 		goto invalid_time;
704cc25b994SDavid Howells 
705cc25b994SDavid Howells 	mon_len = month_lengths[mon - 1];
706fd19a3d1SDavid Howells 	if (mon == 2) {
707fd19a3d1SDavid Howells 		if (year % 4 == 0) {
708fd19a3d1SDavid Howells 			mon_len = 29;
709fd19a3d1SDavid Howells 			if (year % 100 == 0) {
710fd19a3d1SDavid Howells 				mon_len = 28;
711ac4cbedfSDavid Howells 				if (year % 400 == 0)
712ac4cbedfSDavid Howells 					mon_len = 29;
713fd19a3d1SDavid Howells 			}
714fd19a3d1SDavid Howells 		}
715fd19a3d1SDavid Howells 	}
716fd19a3d1SDavid Howells 
717cc25b994SDavid Howells 	if (day < 1 || day > mon_len ||
7187650cb80SDavid Howells 	    hour > 24 || /* ISO 8601 permits 24:00:00 as midnight tomorrow */
7194dd17c9cSsudip 	    min > 59 ||
720da02559cSDavid Howells 	    sec > 60) /* ISO 8601 permits leap seconds [X.680 46.3] */
721fd19a3d1SDavid Howells 		goto invalid_time;
722fd19a3d1SDavid Howells 
723fd19a3d1SDavid Howells 	*_t = mktime64(year, mon, day, hour, min, sec);
724c26fd69fSDavid Howells 	return 0;
725c26fd69fSDavid Howells 
726c26fd69fSDavid Howells unsupported_time:
727fd19a3d1SDavid Howells 	pr_debug("Got unsupported time [tag %02x]: '%*phN'\n",
728fd19a3d1SDavid Howells 		 tag, (int)vlen, value);
729fd19a3d1SDavid Howells 	return -EBADMSG;
730fd19a3d1SDavid Howells invalid_time:
731fd19a3d1SDavid Howells 	pr_debug("Got invalid time [tag %02x]: '%*phN'\n",
732fd19a3d1SDavid Howells 		 tag, (int)vlen, value);
733c26fd69fSDavid Howells 	return -EBADMSG;
734c26fd69fSDavid Howells }
735fd19a3d1SDavid Howells EXPORT_SYMBOL_GPL(x509_decode_time);
736c26fd69fSDavid Howells 
x509_note_not_before(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)737c26fd69fSDavid Howells int x509_note_not_before(void *context, size_t hdrlen,
738c26fd69fSDavid Howells 			 unsigned char tag,
739c26fd69fSDavid Howells 			 const void *value, size_t vlen)
740c26fd69fSDavid Howells {
741c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
742fd19a3d1SDavid Howells 	return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen);
743c26fd69fSDavid Howells }
744c26fd69fSDavid Howells 
x509_note_not_after(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)745c26fd69fSDavid Howells int x509_note_not_after(void *context, size_t hdrlen,
746c26fd69fSDavid Howells 			unsigned char tag,
747c26fd69fSDavid Howells 			const void *value, size_t vlen)
748c26fd69fSDavid Howells {
749c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
750fd19a3d1SDavid Howells 	return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen);
751c26fd69fSDavid Howells }
752b92e6570SDavid Howells 
753b92e6570SDavid Howells /*
754b92e6570SDavid Howells  * Note a key identifier-based AuthorityKeyIdentifier
755b92e6570SDavid Howells  */
x509_akid_note_kid(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)756b92e6570SDavid Howells int x509_akid_note_kid(void *context, size_t hdrlen,
757b92e6570SDavid Howells 		       unsigned char tag,
758b92e6570SDavid Howells 		       const void *value, size_t vlen)
759b92e6570SDavid Howells {
760b92e6570SDavid Howells 	struct x509_parse_context *ctx = context;
761b92e6570SDavid Howells 	struct asymmetric_key_id *kid;
762b92e6570SDavid Howells 
763b92e6570SDavid Howells 	pr_debug("AKID: keyid: %*phN\n", (int)vlen, value);
764b92e6570SDavid Howells 
76577d0910dSDavid Howells 	if (ctx->cert->sig->auth_ids[1])
766b92e6570SDavid Howells 		return 0;
767b92e6570SDavid Howells 
768a4c6e57fSDavid Howells 	kid = asymmetric_key_generate_id(value, vlen, "", 0);
769b92e6570SDavid Howells 	if (IS_ERR(kid))
770b92e6570SDavid Howells 		return PTR_ERR(kid);
771b92e6570SDavid Howells 	pr_debug("authkeyid %*phN\n", kid->len, kid->data);
77277d0910dSDavid Howells 	ctx->cert->sig->auth_ids[1] = kid;
773b92e6570SDavid Howells 	return 0;
774b92e6570SDavid Howells }
775b92e6570SDavid Howells 
776b92e6570SDavid Howells /*
777b92e6570SDavid Howells  * Note a directoryName in an AuthorityKeyIdentifier
778b92e6570SDavid Howells  */
x509_akid_note_name(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)779b92e6570SDavid Howells int x509_akid_note_name(void *context, size_t hdrlen,
780b92e6570SDavid Howells 			unsigned char tag,
781b92e6570SDavid Howells 			const void *value, size_t vlen)
782b92e6570SDavid Howells {
783b92e6570SDavid Howells 	struct x509_parse_context *ctx = context;
784b92e6570SDavid Howells 
785b92e6570SDavid Howells 	pr_debug("AKID: name: %*phN\n", (int)vlen, value);
786b92e6570SDavid Howells 
787b92e6570SDavid Howells 	ctx->akid_raw_issuer = value;
788b92e6570SDavid Howells 	ctx->akid_raw_issuer_size = vlen;
789b92e6570SDavid Howells 	return 0;
790b92e6570SDavid Howells }
791b92e6570SDavid Howells 
792b92e6570SDavid Howells /*
793b92e6570SDavid Howells  * Note a serial number in an AuthorityKeyIdentifier
794b92e6570SDavid Howells  */
x509_akid_note_serial(void * context,size_t hdrlen,unsigned char tag,const void * value,size_t vlen)795b92e6570SDavid Howells int x509_akid_note_serial(void *context, size_t hdrlen,
796b92e6570SDavid Howells 			  unsigned char tag,
797b92e6570SDavid Howells 			  const void *value, size_t vlen)
798b92e6570SDavid Howells {
799b92e6570SDavid Howells 	struct x509_parse_context *ctx = context;
800b92e6570SDavid Howells 	struct asymmetric_key_id *kid;
801b92e6570SDavid Howells 
802b92e6570SDavid Howells 	pr_debug("AKID: serial: %*phN\n", (int)vlen, value);
803b92e6570SDavid Howells 
80477d0910dSDavid Howells 	if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0])
805b92e6570SDavid Howells 		return 0;
806b92e6570SDavid Howells 
807b92e6570SDavid Howells 	kid = asymmetric_key_generate_id(value,
808b92e6570SDavid Howells 					 vlen,
809b92e6570SDavid Howells 					 ctx->akid_raw_issuer,
810b92e6570SDavid Howells 					 ctx->akid_raw_issuer_size);
811b92e6570SDavid Howells 	if (IS_ERR(kid))
812b92e6570SDavid Howells 		return PTR_ERR(kid);
813b92e6570SDavid Howells 
814b92e6570SDavid Howells 	pr_debug("authkeyid %*phN\n", kid->len, kid->data);
81577d0910dSDavid Howells 	ctx->cert->sig->auth_ids[0] = kid;
816b92e6570SDavid Howells 	return 0;
817b92e6570SDavid Howells }
818