1c26fd69fSDavid Howells /* X.509 certificate parser
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/kernel.h>
14ace0107aSDavid Howells #include <linux/export.h>
15c26fd69fSDavid Howells #include <linux/slab.h>
16c26fd69fSDavid Howells #include <linux/err.h>
17c26fd69fSDavid Howells #include <linux/oid_registry.h>
18db6c43bdSTadeusz Struk #include <crypto/public_key.h>
19c26fd69fSDavid Howells #include "x509_parser.h"
20c26fd69fSDavid Howells #include "x509-asn1.h"
21b92e6570SDavid Howells #include "x509_akid-asn1.h"
22c26fd69fSDavid Howells 
23c26fd69fSDavid Howells struct x509_parse_context {
24c26fd69fSDavid Howells 	struct x509_certificate	*cert;		/* Certificate being constructed */
25c26fd69fSDavid Howells 	unsigned long	data;			/* Start of data */
26c26fd69fSDavid Howells 	const void	*cert_start;		/* Start of cert content */
27c26fd69fSDavid Howells 	const void	*key;			/* Key data */
28c26fd69fSDavid Howells 	size_t		key_size;		/* Size of key data */
29c26fd69fSDavid Howells 	enum OID	last_oid;		/* Last OID encountered */
30c26fd69fSDavid Howells 	enum OID	algo_oid;		/* Algorithm OID */
31c26fd69fSDavid Howells 	unsigned char	nr_mpi;			/* Number of MPIs stored */
32c26fd69fSDavid Howells 	u8		o_size;			/* Size of organizationName (O) */
33c26fd69fSDavid Howells 	u8		cn_size;		/* Size of commonName (CN) */
34c26fd69fSDavid Howells 	u8		email_size;		/* Size of emailAddress */
35c26fd69fSDavid Howells 	u16		o_offset;		/* Offset of organizationName (O) */
36c26fd69fSDavid Howells 	u16		cn_offset;		/* Offset of commonName (CN) */
37c26fd69fSDavid Howells 	u16		email_offset;		/* Offset of emailAddress */
38b92e6570SDavid Howells 	unsigned	raw_akid_size;
39b92e6570SDavid Howells 	const void	*raw_akid;		/* Raw authorityKeyId in ASN.1 */
40b92e6570SDavid Howells 	const void	*akid_raw_issuer;	/* Raw directoryName in authorityKeyId */
41b92e6570SDavid Howells 	unsigned	akid_raw_issuer_size;
42c26fd69fSDavid Howells };
43c26fd69fSDavid Howells 
44c26fd69fSDavid Howells /*
45c26fd69fSDavid Howells  * Free an X.509 certificate
46c26fd69fSDavid Howells  */
47c26fd69fSDavid Howells void x509_free_certificate(struct x509_certificate *cert)
48c26fd69fSDavid Howells {
49c26fd69fSDavid Howells 	if (cert) {
503b764563SDavid Howells 		public_key_free(cert->pub);
5177d0910dSDavid Howells 		public_key_signature_free(cert->sig);
52c26fd69fSDavid Howells 		kfree(cert->issuer);
53c26fd69fSDavid Howells 		kfree(cert->subject);
5446963b77SDavid Howells 		kfree(cert->id);
5546963b77SDavid Howells 		kfree(cert->skid);
56c26fd69fSDavid Howells 		kfree(cert);
57c26fd69fSDavid Howells 	}
58c26fd69fSDavid Howells }
59ace0107aSDavid Howells EXPORT_SYMBOL_GPL(x509_free_certificate);
60c26fd69fSDavid Howells 
61c26fd69fSDavid Howells /*
62c26fd69fSDavid Howells  * Parse an X.509 certificate
63c26fd69fSDavid Howells  */
64c26fd69fSDavid Howells struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
65c26fd69fSDavid Howells {
66c26fd69fSDavid Howells 	struct x509_certificate *cert;
67c26fd69fSDavid Howells 	struct x509_parse_context *ctx;
6846963b77SDavid Howells 	struct asymmetric_key_id *kid;
69c26fd69fSDavid Howells 	long ret;
70c26fd69fSDavid Howells 
71c26fd69fSDavid Howells 	ret = -ENOMEM;
72c26fd69fSDavid Howells 	cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL);
73c26fd69fSDavid Howells 	if (!cert)
74c26fd69fSDavid Howells 		goto error_no_cert;
75c26fd69fSDavid Howells 	cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
76c26fd69fSDavid Howells 	if (!cert->pub)
77c26fd69fSDavid Howells 		goto error_no_ctx;
7877d0910dSDavid Howells 	cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL);
7977d0910dSDavid Howells 	if (!cert->sig)
8077d0910dSDavid Howells 		goto error_no_ctx;
81c26fd69fSDavid Howells 	ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
82c26fd69fSDavid Howells 	if (!ctx)
83c26fd69fSDavid Howells 		goto error_no_ctx;
84c26fd69fSDavid Howells 
85c26fd69fSDavid Howells 	ctx->cert = cert;
86c26fd69fSDavid Howells 	ctx->data = (unsigned long)data;
87c26fd69fSDavid Howells 
88c26fd69fSDavid Howells 	/* Attempt to decode the certificate */
89c26fd69fSDavid Howells 	ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen);
90c26fd69fSDavid Howells 	if (ret < 0)
91c26fd69fSDavid Howells 		goto error_decode;
92c26fd69fSDavid Howells 
93b92e6570SDavid Howells 	/* Decode the AuthorityKeyIdentifier */
94b92e6570SDavid Howells 	if (ctx->raw_akid) {
95b92e6570SDavid Howells 		pr_devel("AKID: %u %*phN\n",
96b92e6570SDavid Howells 			 ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid);
97b92e6570SDavid Howells 		ret = asn1_ber_decoder(&x509_akid_decoder, ctx,
98b92e6570SDavid Howells 				       ctx->raw_akid, ctx->raw_akid_size);
99b92e6570SDavid Howells 		if (ret < 0) {
100b92e6570SDavid Howells 			pr_warn("Couldn't decode AuthKeyIdentifier\n");
101b92e6570SDavid Howells 			goto error_decode;
102b92e6570SDavid Howells 		}
103b92e6570SDavid Howells 	}
104b92e6570SDavid Howells 
105db6c43bdSTadeusz Struk 	cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL);
106db6c43bdSTadeusz Struk 	if (!cert->pub->key)
107c26fd69fSDavid Howells 		goto error_decode;
108c26fd69fSDavid Howells 
109db6c43bdSTadeusz Struk 	cert->pub->keylen = ctx->key_size;
110db6c43bdSTadeusz Struk 
11146963b77SDavid Howells 	/* Generate cert issuer + serial number key ID */
11246963b77SDavid Howells 	kid = asymmetric_key_generate_id(cert->raw_serial,
11346963b77SDavid Howells 					 cert->raw_serial_size,
11446963b77SDavid Howells 					 cert->raw_issuer,
11546963b77SDavid Howells 					 cert->raw_issuer_size);
11646963b77SDavid Howells 	if (IS_ERR(kid)) {
11746963b77SDavid Howells 		ret = PTR_ERR(kid);
11846963b77SDavid Howells 		goto error_decode;
11946963b77SDavid Howells 	}
12046963b77SDavid Howells 	cert->id = kid;
12146963b77SDavid Howells 
122c26fd69fSDavid Howells 	kfree(ctx);
123c26fd69fSDavid Howells 	return cert;
124c26fd69fSDavid Howells 
125c26fd69fSDavid Howells error_decode:
126db6c43bdSTadeusz Struk 	kfree(cert->pub->key);
127c26fd69fSDavid Howells 	kfree(ctx);
128c26fd69fSDavid Howells error_no_ctx:
129c26fd69fSDavid Howells 	x509_free_certificate(cert);
130c26fd69fSDavid Howells error_no_cert:
131c26fd69fSDavid Howells 	return ERR_PTR(ret);
132c26fd69fSDavid Howells }
133ace0107aSDavid Howells EXPORT_SYMBOL_GPL(x509_cert_parse);
134c26fd69fSDavid Howells 
135c26fd69fSDavid Howells /*
136c26fd69fSDavid Howells  * Note an OID when we find one for later processing when we know how
137c26fd69fSDavid Howells  * to interpret it.
138c26fd69fSDavid Howells  */
139c26fd69fSDavid Howells int x509_note_OID(void *context, size_t hdrlen,
140c26fd69fSDavid Howells 	     unsigned char tag,
141c26fd69fSDavid Howells 	     const void *value, size_t vlen)
142c26fd69fSDavid Howells {
143c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
144c26fd69fSDavid Howells 
145c26fd69fSDavid Howells 	ctx->last_oid = look_up_OID(value, vlen);
146c26fd69fSDavid Howells 	if (ctx->last_oid == OID__NR) {
147c26fd69fSDavid Howells 		char buffer[50];
148c26fd69fSDavid Howells 		sprint_oid(value, vlen, buffer, sizeof(buffer));
149cf75446eSRandy Dunlap 		pr_debug("Unknown OID: [%lu] %s\n",
150c26fd69fSDavid Howells 			 (unsigned long)value - ctx->data, buffer);
151c26fd69fSDavid Howells 	}
152c26fd69fSDavid Howells 	return 0;
153c26fd69fSDavid Howells }
154c26fd69fSDavid Howells 
155c26fd69fSDavid Howells /*
156c26fd69fSDavid Howells  * Save the position of the TBS data so that we can check the signature over it
157c26fd69fSDavid Howells  * later.
158c26fd69fSDavid Howells  */
159c26fd69fSDavid Howells int x509_note_tbs_certificate(void *context, size_t hdrlen,
160c26fd69fSDavid Howells 			      unsigned char tag,
161c26fd69fSDavid Howells 			      const void *value, size_t vlen)
162c26fd69fSDavid Howells {
163c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
164c26fd69fSDavid Howells 
165c26fd69fSDavid Howells 	pr_debug("x509_note_tbs_certificate(,%zu,%02x,%ld,%zu)!\n",
166c26fd69fSDavid Howells 		 hdrlen, tag, (unsigned long)value - ctx->data, vlen);
167c26fd69fSDavid Howells 
168c26fd69fSDavid Howells 	ctx->cert->tbs = value - hdrlen;
169c26fd69fSDavid Howells 	ctx->cert->tbs_size = vlen + hdrlen;
170c26fd69fSDavid Howells 	return 0;
171c26fd69fSDavid Howells }
172c26fd69fSDavid Howells 
173c26fd69fSDavid Howells /*
174c26fd69fSDavid Howells  * Record the public key algorithm
175c26fd69fSDavid Howells  */
176c26fd69fSDavid Howells int x509_note_pkey_algo(void *context, size_t hdrlen,
177c26fd69fSDavid Howells 			unsigned char tag,
178c26fd69fSDavid Howells 			const void *value, size_t vlen)
179c26fd69fSDavid Howells {
180c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
181c26fd69fSDavid Howells 
182c26fd69fSDavid Howells 	pr_debug("PubKey Algo: %u\n", ctx->last_oid);
183c26fd69fSDavid Howells 
184c26fd69fSDavid Howells 	switch (ctx->last_oid) {
185c26fd69fSDavid Howells 	case OID_md2WithRSAEncryption:
186c26fd69fSDavid Howells 	case OID_md3WithRSAEncryption:
187c26fd69fSDavid Howells 	default:
188c26fd69fSDavid Howells 		return -ENOPKG; /* Unsupported combination */
189c26fd69fSDavid Howells 
190c26fd69fSDavid Howells 	case OID_md4WithRSAEncryption:
19177d0910dSDavid Howells 		ctx->cert->sig->hash_algo = "md4";
19277d0910dSDavid Howells 		ctx->cert->sig->pkey_algo = "rsa";
193c26fd69fSDavid Howells 		break;
194c26fd69fSDavid Howells 
195c26fd69fSDavid Howells 	case OID_sha1WithRSAEncryption:
19677d0910dSDavid Howells 		ctx->cert->sig->hash_algo = "sha1";
19777d0910dSDavid Howells 		ctx->cert->sig->pkey_algo = "rsa";
198c26fd69fSDavid Howells 		break;
199c26fd69fSDavid Howells 
200c26fd69fSDavid Howells 	case OID_sha256WithRSAEncryption:
20177d0910dSDavid Howells 		ctx->cert->sig->hash_algo = "sha256";
20277d0910dSDavid Howells 		ctx->cert->sig->pkey_algo = "rsa";
203c26fd69fSDavid Howells 		break;
204c26fd69fSDavid Howells 
205c26fd69fSDavid Howells 	case OID_sha384WithRSAEncryption:
20677d0910dSDavid Howells 		ctx->cert->sig->hash_algo = "sha384";
20777d0910dSDavid Howells 		ctx->cert->sig->pkey_algo = "rsa";
208c26fd69fSDavid Howells 		break;
209c26fd69fSDavid Howells 
210c26fd69fSDavid Howells 	case OID_sha512WithRSAEncryption:
21177d0910dSDavid Howells 		ctx->cert->sig->hash_algo = "sha512";
21277d0910dSDavid Howells 		ctx->cert->sig->pkey_algo = "rsa";
213c26fd69fSDavid Howells 		break;
214c26fd69fSDavid Howells 
215c26fd69fSDavid Howells 	case OID_sha224WithRSAEncryption:
21677d0910dSDavid Howells 		ctx->cert->sig->hash_algo = "sha224";
21777d0910dSDavid Howells 		ctx->cert->sig->pkey_algo = "rsa";
218c26fd69fSDavid Howells 		break;
219c26fd69fSDavid Howells 	}
220c26fd69fSDavid Howells 
221c26fd69fSDavid Howells 	ctx->algo_oid = ctx->last_oid;
222c26fd69fSDavid Howells 	return 0;
223c26fd69fSDavid Howells }
224c26fd69fSDavid Howells 
225c26fd69fSDavid Howells /*
226c26fd69fSDavid Howells  * Note the whereabouts and type of the signature.
227c26fd69fSDavid Howells  */
228c26fd69fSDavid Howells int x509_note_signature(void *context, size_t hdrlen,
229c26fd69fSDavid Howells 			unsigned char tag,
230c26fd69fSDavid Howells 			const void *value, size_t vlen)
231c26fd69fSDavid Howells {
232c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
233c26fd69fSDavid Howells 
234c26fd69fSDavid Howells 	pr_debug("Signature type: %u size %zu\n", ctx->last_oid, vlen);
235c26fd69fSDavid Howells 
236c26fd69fSDavid Howells 	if (ctx->last_oid != ctx->algo_oid) {
237c26fd69fSDavid Howells 		pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n",
238c26fd69fSDavid Howells 			ctx->algo_oid, ctx->last_oid);
239c26fd69fSDavid Howells 		return -EINVAL;
240c26fd69fSDavid Howells 	}
241c26fd69fSDavid Howells 
242b426beb6SDavid Howells 	ctx->cert->raw_sig = value;
243b426beb6SDavid Howells 	ctx->cert->raw_sig_size = vlen;
244c26fd69fSDavid Howells 	return 0;
245c26fd69fSDavid Howells }
246c26fd69fSDavid Howells 
247c26fd69fSDavid Howells /*
24884aabd46SDavid Howells  * Note the certificate serial number
24984aabd46SDavid Howells  */
25084aabd46SDavid Howells int x509_note_serial(void *context, size_t hdrlen,
25184aabd46SDavid Howells 		     unsigned char tag,
25284aabd46SDavid Howells 		     const void *value, size_t vlen)
25384aabd46SDavid Howells {
25484aabd46SDavid Howells 	struct x509_parse_context *ctx = context;
25584aabd46SDavid Howells 	ctx->cert->raw_serial = value;
25684aabd46SDavid Howells 	ctx->cert->raw_serial_size = vlen;
25784aabd46SDavid Howells 	return 0;
25884aabd46SDavid Howells }
25984aabd46SDavid Howells 
26084aabd46SDavid Howells /*
261c26fd69fSDavid Howells  * Note some of the name segments from which we'll fabricate a name.
262c26fd69fSDavid Howells  */
263c26fd69fSDavid Howells int x509_extract_name_segment(void *context, size_t hdrlen,
264c26fd69fSDavid Howells 			      unsigned char tag,
265c26fd69fSDavid Howells 			      const void *value, size_t vlen)
266c26fd69fSDavid Howells {
267c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
268c26fd69fSDavid Howells 
269c26fd69fSDavid Howells 	switch (ctx->last_oid) {
270c26fd69fSDavid Howells 	case OID_commonName:
271c26fd69fSDavid Howells 		ctx->cn_size = vlen;
272c26fd69fSDavid Howells 		ctx->cn_offset = (unsigned long)value - ctx->data;
273c26fd69fSDavid Howells 		break;
274c26fd69fSDavid Howells 	case OID_organizationName:
275c26fd69fSDavid Howells 		ctx->o_size = vlen;
276c26fd69fSDavid Howells 		ctx->o_offset = (unsigned long)value - ctx->data;
277c26fd69fSDavid Howells 		break;
278c26fd69fSDavid Howells 	case OID_email_address:
279c26fd69fSDavid Howells 		ctx->email_size = vlen;
280c26fd69fSDavid Howells 		ctx->email_offset = (unsigned long)value - ctx->data;
281c26fd69fSDavid Howells 		break;
282c26fd69fSDavid Howells 	default:
283c26fd69fSDavid Howells 		break;
284c26fd69fSDavid Howells 	}
285c26fd69fSDavid Howells 
286c26fd69fSDavid Howells 	return 0;
287c26fd69fSDavid Howells }
288c26fd69fSDavid Howells 
289c26fd69fSDavid Howells /*
290c26fd69fSDavid Howells  * Fabricate and save the issuer and subject names
291c26fd69fSDavid Howells  */
292c26fd69fSDavid Howells static int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen,
293c26fd69fSDavid Howells 			       unsigned char tag,
294c26fd69fSDavid Howells 			       char **_name, size_t vlen)
295c26fd69fSDavid Howells {
296c26fd69fSDavid Howells 	const void *name, *data = (const void *)ctx->data;
297c26fd69fSDavid Howells 	size_t namesize;
298c26fd69fSDavid Howells 	char *buffer;
299c26fd69fSDavid Howells 
300c26fd69fSDavid Howells 	if (*_name)
301c26fd69fSDavid Howells 		return -EINVAL;
302c26fd69fSDavid Howells 
303c26fd69fSDavid Howells 	/* Empty name string if no material */
304c26fd69fSDavid Howells 	if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) {
305c26fd69fSDavid Howells 		buffer = kmalloc(1, GFP_KERNEL);
306c26fd69fSDavid Howells 		if (!buffer)
307c26fd69fSDavid Howells 			return -ENOMEM;
308c26fd69fSDavid Howells 		buffer[0] = 0;
309c26fd69fSDavid Howells 		goto done;
310c26fd69fSDavid Howells 	}
311c26fd69fSDavid Howells 
312c26fd69fSDavid Howells 	if (ctx->cn_size && ctx->o_size) {
313c26fd69fSDavid Howells 		/* Consider combining O and CN, but use only the CN if it is
314c26fd69fSDavid Howells 		 * prefixed by the O, or a significant portion thereof.
315c26fd69fSDavid Howells 		 */
316c26fd69fSDavid Howells 		namesize = ctx->cn_size;
317c26fd69fSDavid Howells 		name = data + ctx->cn_offset;
318c26fd69fSDavid Howells 		if (ctx->cn_size >= ctx->o_size &&
319c26fd69fSDavid Howells 		    memcmp(data + ctx->cn_offset, data + ctx->o_offset,
320c26fd69fSDavid Howells 			   ctx->o_size) == 0)
321c26fd69fSDavid Howells 			goto single_component;
322c26fd69fSDavid Howells 		if (ctx->cn_size >= 7 &&
323c26fd69fSDavid Howells 		    ctx->o_size >= 7 &&
324c26fd69fSDavid Howells 		    memcmp(data + ctx->cn_offset, data + ctx->o_offset, 7) == 0)
325c26fd69fSDavid Howells 			goto single_component;
326c26fd69fSDavid Howells 
327c26fd69fSDavid Howells 		buffer = kmalloc(ctx->o_size + 2 + ctx->cn_size + 1,
328c26fd69fSDavid Howells 				 GFP_KERNEL);
329c26fd69fSDavid Howells 		if (!buffer)
330c26fd69fSDavid Howells 			return -ENOMEM;
331c26fd69fSDavid Howells 
332c26fd69fSDavid Howells 		memcpy(buffer,
333c26fd69fSDavid Howells 		       data + ctx->o_offset, ctx->o_size);
334c26fd69fSDavid Howells 		buffer[ctx->o_size + 0] = ':';
335c26fd69fSDavid Howells 		buffer[ctx->o_size + 1] = ' ';
336c26fd69fSDavid Howells 		memcpy(buffer + ctx->o_size + 2,
337c26fd69fSDavid Howells 		       data + ctx->cn_offset, ctx->cn_size);
338c26fd69fSDavid Howells 		buffer[ctx->o_size + 2 + ctx->cn_size] = 0;
339c26fd69fSDavid Howells 		goto done;
340c26fd69fSDavid Howells 
341c26fd69fSDavid Howells 	} else if (ctx->cn_size) {
342c26fd69fSDavid Howells 		namesize = ctx->cn_size;
343c26fd69fSDavid Howells 		name = data + ctx->cn_offset;
344c26fd69fSDavid Howells 	} else if (ctx->o_size) {
345c26fd69fSDavid Howells 		namesize = ctx->o_size;
346c26fd69fSDavid Howells 		name = data + ctx->o_offset;
347c26fd69fSDavid Howells 	} else {
348c26fd69fSDavid Howells 		namesize = ctx->email_size;
349c26fd69fSDavid Howells 		name = data + ctx->email_offset;
350c26fd69fSDavid Howells 	}
351c26fd69fSDavid Howells 
352c26fd69fSDavid Howells single_component:
353c26fd69fSDavid Howells 	buffer = kmalloc(namesize + 1, GFP_KERNEL);
354c26fd69fSDavid Howells 	if (!buffer)
355c26fd69fSDavid Howells 		return -ENOMEM;
356c26fd69fSDavid Howells 	memcpy(buffer, name, namesize);
357c26fd69fSDavid Howells 	buffer[namesize] = 0;
358c26fd69fSDavid Howells 
359c26fd69fSDavid Howells done:
360c26fd69fSDavid Howells 	*_name = buffer;
361c26fd69fSDavid Howells 	ctx->cn_size = 0;
362c26fd69fSDavid Howells 	ctx->o_size = 0;
363c26fd69fSDavid Howells 	ctx->email_size = 0;
364c26fd69fSDavid Howells 	return 0;
365c26fd69fSDavid Howells }
366c26fd69fSDavid Howells 
367c26fd69fSDavid Howells int x509_note_issuer(void *context, size_t hdrlen,
368c26fd69fSDavid Howells 		     unsigned char tag,
369c26fd69fSDavid Howells 		     const void *value, size_t vlen)
370c26fd69fSDavid Howells {
371c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
37284aabd46SDavid Howells 	ctx->cert->raw_issuer = value;
37384aabd46SDavid Howells 	ctx->cert->raw_issuer_size = vlen;
374c26fd69fSDavid Howells 	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
375c26fd69fSDavid Howells }
376c26fd69fSDavid Howells 
377c26fd69fSDavid Howells int x509_note_subject(void *context, size_t hdrlen,
378c26fd69fSDavid Howells 		      unsigned char tag,
379c26fd69fSDavid Howells 		      const void *value, size_t vlen)
380c26fd69fSDavid Howells {
381c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
38284aabd46SDavid Howells 	ctx->cert->raw_subject = value;
38384aabd46SDavid Howells 	ctx->cert->raw_subject_size = vlen;
384c26fd69fSDavid Howells 	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
385c26fd69fSDavid Howells }
386c26fd69fSDavid Howells 
387c26fd69fSDavid Howells /*
388c26fd69fSDavid Howells  * Extract the data for the public key algorithm
389c26fd69fSDavid Howells  */
390c26fd69fSDavid Howells int x509_extract_key_data(void *context, size_t hdrlen,
391c26fd69fSDavid Howells 			  unsigned char tag,
392c26fd69fSDavid Howells 			  const void *value, size_t vlen)
393c26fd69fSDavid Howells {
394c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
395c26fd69fSDavid Howells 
396c26fd69fSDavid Howells 	if (ctx->last_oid != OID_rsaEncryption)
397c26fd69fSDavid Howells 		return -ENOPKG;
398c26fd69fSDavid Howells 
3994e8ae72aSDavid Howells 	ctx->cert->pub->pkey_algo = "rsa";
40067f7d60bSDavid Howells 
40167f7d60bSDavid Howells 	/* Discard the BIT STRING metadata */
402c26fd69fSDavid Howells 	ctx->key = value + 1;
403c26fd69fSDavid Howells 	ctx->key_size = vlen - 1;
404c26fd69fSDavid Howells 	return 0;
405c26fd69fSDavid Howells }
406c26fd69fSDavid Howells 
40704b00bdbSChun-Yi Lee /* The keyIdentifier in AuthorityKeyIdentifier SEQUENCE is tag(CONT,PRIM,0) */
40804b00bdbSChun-Yi Lee #define SEQ_TAG_KEYID (ASN1_CONT << 6)
40904b00bdbSChun-Yi Lee 
410c26fd69fSDavid Howells /*
411c26fd69fSDavid Howells  * Process certificate extensions that are used to qualify the certificate.
412c26fd69fSDavid Howells  */
413c26fd69fSDavid Howells int x509_process_extension(void *context, size_t hdrlen,
414c26fd69fSDavid Howells 			   unsigned char tag,
415c26fd69fSDavid Howells 			   const void *value, size_t vlen)
416c26fd69fSDavid Howells {
417c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
41846963b77SDavid Howells 	struct asymmetric_key_id *kid;
419c26fd69fSDavid Howells 	const unsigned char *v = value;
420c26fd69fSDavid Howells 
421c26fd69fSDavid Howells 	pr_debug("Extension: %u\n", ctx->last_oid);
422c26fd69fSDavid Howells 
423c26fd69fSDavid Howells 	if (ctx->last_oid == OID_subjectKeyIdentifier) {
424c26fd69fSDavid Howells 		/* Get hold of the key fingerprint */
42546963b77SDavid Howells 		if (ctx->cert->skid || vlen < 3)
426c26fd69fSDavid Howells 			return -EBADMSG;
427c26fd69fSDavid Howells 		if (v[0] != ASN1_OTS || v[1] != vlen - 2)
428c26fd69fSDavid Howells 			return -EBADMSG;
429c26fd69fSDavid Howells 		v += 2;
430c26fd69fSDavid Howells 		vlen -= 2;
431c26fd69fSDavid Howells 
432dd2f6c44SDavid Howells 		ctx->cert->raw_skid_size = vlen;
433dd2f6c44SDavid Howells 		ctx->cert->raw_skid = v;
434a4c6e57fSDavid Howells 		kid = asymmetric_key_generate_id(v, vlen, "", 0);
43546963b77SDavid Howells 		if (IS_ERR(kid))
43646963b77SDavid Howells 			return PTR_ERR(kid);
43746963b77SDavid Howells 		ctx->cert->skid = kid;
43846963b77SDavid Howells 		pr_debug("subjkeyid %*phN\n", kid->len, kid->data);
439c26fd69fSDavid Howells 		return 0;
440c26fd69fSDavid Howells 	}
441c26fd69fSDavid Howells 
442c26fd69fSDavid Howells 	if (ctx->last_oid == OID_authorityKeyIdentifier) {
443c26fd69fSDavid Howells 		/* Get hold of the CA key fingerprint */
444b92e6570SDavid Howells 		ctx->raw_akid = v;
445b92e6570SDavid Howells 		ctx->raw_akid_size = vlen;
446c26fd69fSDavid Howells 		return 0;
447c26fd69fSDavid Howells 	}
448c26fd69fSDavid Howells 
449c26fd69fSDavid Howells 	return 0;
450c26fd69fSDavid Howells }
451c26fd69fSDavid Howells 
452fd19a3d1SDavid Howells /**
453fd19a3d1SDavid Howells  * x509_decode_time - Decode an X.509 time ASN.1 object
454fd19a3d1SDavid Howells  * @_t: The time to fill in
455fd19a3d1SDavid Howells  * @hdrlen: The length of the object header
456fd19a3d1SDavid Howells  * @tag: The object tag
457fd19a3d1SDavid Howells  * @value: The object value
458fd19a3d1SDavid Howells  * @vlen: The size of the object value
459fd19a3d1SDavid Howells  *
460fd19a3d1SDavid Howells  * Decode an ASN.1 universal time or generalised time field into a struct the
461fd19a3d1SDavid Howells  * kernel can handle and check it for validity.  The time is decoded thus:
462fd19a3d1SDavid Howells  *
463fd19a3d1SDavid Howells  *	[RFC5280 §4.1.2.5]
464fd19a3d1SDavid Howells  *	CAs conforming to this profile MUST always encode certificate validity
465fd19a3d1SDavid Howells  *	dates through the year 2049 as UTCTime; certificate validity dates in
466fd19a3d1SDavid Howells  *	2050 or later MUST be encoded as GeneralizedTime.  Conforming
467fd19a3d1SDavid Howells  *	applications MUST be able to process validity dates that are encoded in
468fd19a3d1SDavid Howells  *	either UTCTime or GeneralizedTime.
469c26fd69fSDavid Howells  */
470fd19a3d1SDavid Howells int x509_decode_time(time64_t *_t,  size_t hdrlen,
471c26fd69fSDavid Howells 		     unsigned char tag,
472c26fd69fSDavid Howells 		     const unsigned char *value, size_t vlen)
473c26fd69fSDavid Howells {
474ac4cbedfSDavid Howells 	static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30,
475fd19a3d1SDavid Howells 						       31, 31, 30, 31, 30, 31 };
476c26fd69fSDavid Howells 	const unsigned char *p = value;
477fd19a3d1SDavid Howells 	unsigned year, mon, day, hour, min, sec, mon_len;
478c26fd69fSDavid Howells 
479fd19a3d1SDavid Howells #define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; })
480c26fd69fSDavid Howells #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; })
481c26fd69fSDavid Howells 
482c26fd69fSDavid Howells 	if (tag == ASN1_UNITIM) {
483c26fd69fSDavid Howells 		/* UTCTime: YYMMDDHHMMSSZ */
484c26fd69fSDavid Howells 		if (vlen != 13)
485c26fd69fSDavid Howells 			goto unsupported_time;
486fd19a3d1SDavid Howells 		year = DD2bin(p);
487fd19a3d1SDavid Howells 		if (year >= 50)
488fd19a3d1SDavid Howells 			year += 1900;
489c26fd69fSDavid Howells 		else
490fd19a3d1SDavid Howells 			year += 2000;
491c26fd69fSDavid Howells 	} else if (tag == ASN1_GENTIM) {
492c26fd69fSDavid Howells 		/* GenTime: YYYYMMDDHHMMSSZ */
493c26fd69fSDavid Howells 		if (vlen != 15)
494c26fd69fSDavid Howells 			goto unsupported_time;
495fd19a3d1SDavid Howells 		year = DD2bin(p) * 100 + DD2bin(p);
496fd19a3d1SDavid Howells 		if (year >= 1950 && year <= 2049)
497fd19a3d1SDavid Howells 			goto invalid_time;
498c26fd69fSDavid Howells 	} else {
499c26fd69fSDavid Howells 		goto unsupported_time;
500c26fd69fSDavid Howells 	}
501c26fd69fSDavid Howells 
502fd19a3d1SDavid Howells 	mon  = DD2bin(p);
503fd19a3d1SDavid Howells 	day = DD2bin(p);
504fd19a3d1SDavid Howells 	hour = DD2bin(p);
505fd19a3d1SDavid Howells 	min  = DD2bin(p);
506fd19a3d1SDavid Howells 	sec  = DD2bin(p);
507c26fd69fSDavid Howells 
508c26fd69fSDavid Howells 	if (*p != 'Z')
509c26fd69fSDavid Howells 		goto unsupported_time;
510c26fd69fSDavid Howells 
511cc25b994SDavid Howells 	if (year < 1970 ||
512cc25b994SDavid Howells 	    mon < 1 || mon > 12)
513cc25b994SDavid Howells 		goto invalid_time;
514cc25b994SDavid Howells 
515cc25b994SDavid Howells 	mon_len = month_lengths[mon - 1];
516fd19a3d1SDavid Howells 	if (mon == 2) {
517fd19a3d1SDavid Howells 		if (year % 4 == 0) {
518fd19a3d1SDavid Howells 			mon_len = 29;
519fd19a3d1SDavid Howells 			if (year % 100 == 0) {
520fd19a3d1SDavid Howells 				mon_len = 28;
521ac4cbedfSDavid Howells 				if (year % 400 == 0)
522ac4cbedfSDavid Howells 					mon_len = 29;
523fd19a3d1SDavid Howells 			}
524fd19a3d1SDavid Howells 		}
525fd19a3d1SDavid Howells 	}
526fd19a3d1SDavid Howells 
527cc25b994SDavid Howells 	if (day < 1 || day > mon_len ||
5287650cb80SDavid Howells 	    hour > 24 || /* ISO 8601 permits 24:00:00 as midnight tomorrow */
5294dd17c9cSsudip 	    min > 59 ||
530da02559cSDavid Howells 	    sec > 60) /* ISO 8601 permits leap seconds [X.680 46.3] */
531fd19a3d1SDavid Howells 		goto invalid_time;
532fd19a3d1SDavid Howells 
533fd19a3d1SDavid Howells 	*_t = mktime64(year, mon, day, hour, min, sec);
534c26fd69fSDavid Howells 	return 0;
535c26fd69fSDavid Howells 
536c26fd69fSDavid Howells unsupported_time:
537fd19a3d1SDavid Howells 	pr_debug("Got unsupported time [tag %02x]: '%*phN'\n",
538fd19a3d1SDavid Howells 		 tag, (int)vlen, value);
539fd19a3d1SDavid Howells 	return -EBADMSG;
540fd19a3d1SDavid Howells invalid_time:
541fd19a3d1SDavid Howells 	pr_debug("Got invalid time [tag %02x]: '%*phN'\n",
542fd19a3d1SDavid Howells 		 tag, (int)vlen, value);
543c26fd69fSDavid Howells 	return -EBADMSG;
544c26fd69fSDavid Howells }
545fd19a3d1SDavid Howells EXPORT_SYMBOL_GPL(x509_decode_time);
546c26fd69fSDavid Howells 
547c26fd69fSDavid Howells int x509_note_not_before(void *context, size_t hdrlen,
548c26fd69fSDavid Howells 			 unsigned char tag,
549c26fd69fSDavid Howells 			 const void *value, size_t vlen)
550c26fd69fSDavid Howells {
551c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
552fd19a3d1SDavid Howells 	return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen);
553c26fd69fSDavid Howells }
554c26fd69fSDavid Howells 
555c26fd69fSDavid Howells int x509_note_not_after(void *context, size_t hdrlen,
556c26fd69fSDavid Howells 			unsigned char tag,
557c26fd69fSDavid Howells 			const void *value, size_t vlen)
558c26fd69fSDavid Howells {
559c26fd69fSDavid Howells 	struct x509_parse_context *ctx = context;
560fd19a3d1SDavid Howells 	return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen);
561c26fd69fSDavid Howells }
562b92e6570SDavid Howells 
563b92e6570SDavid Howells /*
564b92e6570SDavid Howells  * Note a key identifier-based AuthorityKeyIdentifier
565b92e6570SDavid Howells  */
566b92e6570SDavid Howells int x509_akid_note_kid(void *context, size_t hdrlen,
567b92e6570SDavid Howells 		       unsigned char tag,
568b92e6570SDavid Howells 		       const void *value, size_t vlen)
569b92e6570SDavid Howells {
570b92e6570SDavid Howells 	struct x509_parse_context *ctx = context;
571b92e6570SDavid Howells 	struct asymmetric_key_id *kid;
572b92e6570SDavid Howells 
573b92e6570SDavid Howells 	pr_debug("AKID: keyid: %*phN\n", (int)vlen, value);
574b92e6570SDavid Howells 
57577d0910dSDavid Howells 	if (ctx->cert->sig->auth_ids[1])
576b92e6570SDavid Howells 		return 0;
577b92e6570SDavid Howells 
578a4c6e57fSDavid Howells 	kid = asymmetric_key_generate_id(value, vlen, "", 0);
579b92e6570SDavid Howells 	if (IS_ERR(kid))
580b92e6570SDavid Howells 		return PTR_ERR(kid);
581b92e6570SDavid Howells 	pr_debug("authkeyid %*phN\n", kid->len, kid->data);
58277d0910dSDavid Howells 	ctx->cert->sig->auth_ids[1] = kid;
583b92e6570SDavid Howells 	return 0;
584b92e6570SDavid Howells }
585b92e6570SDavid Howells 
586b92e6570SDavid Howells /*
587b92e6570SDavid Howells  * Note a directoryName in an AuthorityKeyIdentifier
588b92e6570SDavid Howells  */
589b92e6570SDavid Howells int x509_akid_note_name(void *context, size_t hdrlen,
590b92e6570SDavid Howells 			unsigned char tag,
591b92e6570SDavid Howells 			const void *value, size_t vlen)
592b92e6570SDavid Howells {
593b92e6570SDavid Howells 	struct x509_parse_context *ctx = context;
594b92e6570SDavid Howells 
595b92e6570SDavid Howells 	pr_debug("AKID: name: %*phN\n", (int)vlen, value);
596b92e6570SDavid Howells 
597b92e6570SDavid Howells 	ctx->akid_raw_issuer = value;
598b92e6570SDavid Howells 	ctx->akid_raw_issuer_size = vlen;
599b92e6570SDavid Howells 	return 0;
600b92e6570SDavid Howells }
601b92e6570SDavid Howells 
602b92e6570SDavid Howells /*
603b92e6570SDavid Howells  * Note a serial number in an AuthorityKeyIdentifier
604b92e6570SDavid Howells  */
605b92e6570SDavid Howells int x509_akid_note_serial(void *context, size_t hdrlen,
606b92e6570SDavid Howells 			  unsigned char tag,
607b92e6570SDavid Howells 			  const void *value, size_t vlen)
608b92e6570SDavid Howells {
609b92e6570SDavid Howells 	struct x509_parse_context *ctx = context;
610b92e6570SDavid Howells 	struct asymmetric_key_id *kid;
611b92e6570SDavid Howells 
612b92e6570SDavid Howells 	pr_debug("AKID: serial: %*phN\n", (int)vlen, value);
613b92e6570SDavid Howells 
61477d0910dSDavid Howells 	if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0])
615b92e6570SDavid Howells 		return 0;
616b92e6570SDavid Howells 
617b92e6570SDavid Howells 	kid = asymmetric_key_generate_id(value,
618b92e6570SDavid Howells 					 vlen,
619b92e6570SDavid Howells 					 ctx->akid_raw_issuer,
620b92e6570SDavid Howells 					 ctx->akid_raw_issuer_size);
621b92e6570SDavid Howells 	if (IS_ERR(kid))
622b92e6570SDavid Howells 		return PTR_ERR(kid);
623b92e6570SDavid Howells 
624b92e6570SDavid Howells 	pr_debug("authkeyid %*phN\n", kid->len, kid->data);
62577d0910dSDavid Howells 	ctx->cert->sig->auth_ids[0] = kid;
626b92e6570SDavid Howells 	return 0;
627b92e6570SDavid Howells }
628