Blame view

crypto/asymmetric_keys/x509_cert_parser.c 15.8 KB
c26fd69fa   David Howells   X.509: Add a cryp...
1
2
3
4
5
6
7
8
9
10
11
12
13
  /* X.509 certificate parser
   *
   * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells (dhowells@redhat.com)
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public Licence
   * as published by the Free Software Foundation; either version
   * 2 of the Licence, or (at your option) any later version.
   */
  
  #define pr_fmt(fmt) "X.509: "fmt
  #include <linux/kernel.h>
ace0107a3   David Howells   X.509: Export cer...
14
  #include <linux/export.h>
c26fd69fa   David Howells   X.509: Add a cryp...
15
16
17
  #include <linux/slab.h>
  #include <linux/err.h>
  #include <linux/oid_registry.h>
db6c43bd2   Tadeusz Struk   crypto: KEYS: con...
18
  #include <crypto/public_key.h>
c26fd69fa   David Howells   X.509: Add a cryp...
19
20
  #include "x509_parser.h"
  #include "x509-asn1.h"
b92e6570a   David Howells   X.509: Extract bo...
21
  #include "x509_akid-asn1.h"
c26fd69fa   David Howells   X.509: Add a cryp...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  
  struct x509_parse_context {
  	struct x509_certificate	*cert;		/* Certificate being constructed */
  	unsigned long	data;			/* Start of data */
  	const void	*cert_start;		/* Start of cert content */
  	const void	*key;			/* Key data */
  	size_t		key_size;		/* Size of key data */
  	enum OID	last_oid;		/* Last OID encountered */
  	enum OID	algo_oid;		/* Algorithm OID */
  	unsigned char	nr_mpi;			/* Number of MPIs stored */
  	u8		o_size;			/* Size of organizationName (O) */
  	u8		cn_size;		/* Size of commonName (CN) */
  	u8		email_size;		/* Size of emailAddress */
  	u16		o_offset;		/* Offset of organizationName (O) */
  	u16		cn_offset;		/* Offset of commonName (CN) */
  	u16		email_offset;		/* Offset of emailAddress */
b92e6570a   David Howells   X.509: Extract bo...
38
39
40
41
  	unsigned	raw_akid_size;
  	const void	*raw_akid;		/* Raw authorityKeyId in ASN.1 */
  	const void	*akid_raw_issuer;	/* Raw directoryName in authorityKeyId */
  	unsigned	akid_raw_issuer_size;
c26fd69fa   David Howells   X.509: Add a cryp...
42
43
44
45
46
47
48
49
  };
  
  /*
   * Free an X.509 certificate
   */
  void x509_free_certificate(struct x509_certificate *cert)
  {
  	if (cert) {
3b7645631   David Howells   KEYS: Allow authe...
50
  		public_key_free(cert->pub);
77d0910d1   David Howells   X.509: Retain the...
51
  		public_key_signature_free(cert->sig);
c26fd69fa   David Howells   X.509: Add a cryp...
52
53
  		kfree(cert->issuer);
  		kfree(cert->subject);
46963b774   David Howells   KEYS: Overhaul ke...
54
55
  		kfree(cert->id);
  		kfree(cert->skid);
c26fd69fa   David Howells   X.509: Add a cryp...
56
57
58
  		kfree(cert);
  	}
  }
ace0107a3   David Howells   X.509: Export cer...
59
  EXPORT_SYMBOL_GPL(x509_free_certificate);
c26fd69fa   David Howells   X.509: Add a cryp...
60
61
62
63
64
65
66
67
  
  /*
   * Parse an X.509 certificate
   */
  struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
  {
  	struct x509_certificate *cert;
  	struct x509_parse_context *ctx;
46963b774   David Howells   KEYS: Overhaul ke...
68
  	struct asymmetric_key_id *kid;
c26fd69fa   David Howells   X.509: Add a cryp...
69
70
71
72
73
74
75
76
77
  	long ret;
  
  	ret = -ENOMEM;
  	cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL);
  	if (!cert)
  		goto error_no_cert;
  	cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
  	if (!cert->pub)
  		goto error_no_ctx;
77d0910d1   David Howells   X.509: Retain the...
78
79
80
  	cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL);
  	if (!cert->sig)
  		goto error_no_ctx;
c26fd69fa   David Howells   X.509: Add a cryp...
81
82
83
84
85
86
87
88
89
90
91
  	ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
  	if (!ctx)
  		goto error_no_ctx;
  
  	ctx->cert = cert;
  	ctx->data = (unsigned long)data;
  
  	/* Attempt to decode the certificate */
  	ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen);
  	if (ret < 0)
  		goto error_decode;
b92e6570a   David Howells   X.509: Extract bo...
92
93
94
95
96
97
98
99
100
101
102
103
104
  	/* Decode the AuthorityKeyIdentifier */
  	if (ctx->raw_akid) {
  		pr_devel("AKID: %u %*phN
  ",
  			 ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid);
  		ret = asn1_ber_decoder(&x509_akid_decoder, ctx,
  				       ctx->raw_akid, ctx->raw_akid_size);
  		if (ret < 0) {
  			pr_warn("Couldn't decode AuthKeyIdentifier
  ");
  			goto error_decode;
  		}
  	}
db6c43bd2   Tadeusz Struk   crypto: KEYS: con...
105
106
  	cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL);
  	if (!cert->pub->key)
c26fd69fa   David Howells   X.509: Add a cryp...
107
  		goto error_decode;
db6c43bd2   Tadeusz Struk   crypto: KEYS: con...
108
  	cert->pub->keylen = ctx->key_size;
6c2dc5ae4   David Howells   X.509: Extract si...
109
110
111
112
  	/* Grab the signature bits */
  	ret = x509_get_sig_params(cert);
  	if (ret < 0)
  		goto error_decode;
46963b774   David Howells   KEYS: Overhaul ke...
113
114
115
116
117
118
119
120
121
122
  	/* Generate cert issuer + serial number key ID */
  	kid = asymmetric_key_generate_id(cert->raw_serial,
  					 cert->raw_serial_size,
  					 cert->raw_issuer,
  					 cert->raw_issuer_size);
  	if (IS_ERR(kid)) {
  		ret = PTR_ERR(kid);
  		goto error_decode;
  	}
  	cert->id = kid;
6c2dc5ae4   David Howells   X.509: Extract si...
123
124
125
126
  	/* Detect self-signed certificates */
  	ret = x509_check_for_self_signed(cert);
  	if (ret < 0)
  		goto error_decode;
c26fd69fa   David Howells   X.509: Add a cryp...
127
128
129
130
  	kfree(ctx);
  	return cert;
  
  error_decode:
db6c43bd2   Tadeusz Struk   crypto: KEYS: con...
131
  	kfree(cert->pub->key);
c26fd69fa   David Howells   X.509: Add a cryp...
132
133
134
135
136
137
  	kfree(ctx);
  error_no_ctx:
  	x509_free_certificate(cert);
  error_no_cert:
  	return ERR_PTR(ret);
  }
ace0107a3   David Howells   X.509: Export cer...
138
  EXPORT_SYMBOL_GPL(x509_cert_parse);
c26fd69fa   David Howells   X.509: Add a cryp...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  
  /*
   * Note an OID when we find one for later processing when we know how
   * to interpret it.
   */
  int x509_note_OID(void *context, size_t hdrlen,
  	     unsigned char tag,
  	     const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
  
  	ctx->last_oid = look_up_OID(value, vlen);
  	if (ctx->last_oid == OID__NR) {
  		char buffer[50];
  		sprint_oid(value, vlen, buffer, sizeof(buffer));
cf75446e6   Randy Dunlap   asymmetric keys: ...
154
155
  		pr_debug("Unknown OID: [%lu] %s
  ",
c26fd69fa   David Howells   X.509: Add a cryp...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
  			 (unsigned long)value - ctx->data, buffer);
  	}
  	return 0;
  }
  
  /*
   * Save the position of the TBS data so that we can check the signature over it
   * later.
   */
  int x509_note_tbs_certificate(void *context, size_t hdrlen,
  			      unsigned char tag,
  			      const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
  
  	pr_debug("x509_note_tbs_certificate(,%zu,%02x,%ld,%zu)!
  ",
  		 hdrlen, tag, (unsigned long)value - ctx->data, vlen);
  
  	ctx->cert->tbs = value - hdrlen;
  	ctx->cert->tbs_size = vlen + hdrlen;
  	return 0;
  }
  
  /*
   * Record the public key algorithm
   */
  int x509_note_pkey_algo(void *context, size_t hdrlen,
  			unsigned char tag,
  			const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
  
  	pr_debug("PubKey Algo: %u
  ", ctx->last_oid);
  
  	switch (ctx->last_oid) {
  	case OID_md2WithRSAEncryption:
  	case OID_md3WithRSAEncryption:
  	default:
  		return -ENOPKG; /* Unsupported combination */
  
  	case OID_md4WithRSAEncryption:
77d0910d1   David Howells   X.509: Retain the...
199
200
  		ctx->cert->sig->hash_algo = "md4";
  		ctx->cert->sig->pkey_algo = "rsa";
c26fd69fa   David Howells   X.509: Add a cryp...
201
202
203
  		break;
  
  	case OID_sha1WithRSAEncryption:
77d0910d1   David Howells   X.509: Retain the...
204
205
  		ctx->cert->sig->hash_algo = "sha1";
  		ctx->cert->sig->pkey_algo = "rsa";
c26fd69fa   David Howells   X.509: Add a cryp...
206
207
208
  		break;
  
  	case OID_sha256WithRSAEncryption:
77d0910d1   David Howells   X.509: Retain the...
209
210
  		ctx->cert->sig->hash_algo = "sha256";
  		ctx->cert->sig->pkey_algo = "rsa";
c26fd69fa   David Howells   X.509: Add a cryp...
211
212
213
  		break;
  
  	case OID_sha384WithRSAEncryption:
77d0910d1   David Howells   X.509: Retain the...
214
215
  		ctx->cert->sig->hash_algo = "sha384";
  		ctx->cert->sig->pkey_algo = "rsa";
c26fd69fa   David Howells   X.509: Add a cryp...
216
217
218
  		break;
  
  	case OID_sha512WithRSAEncryption:
77d0910d1   David Howells   X.509: Retain the...
219
220
  		ctx->cert->sig->hash_algo = "sha512";
  		ctx->cert->sig->pkey_algo = "rsa";
c26fd69fa   David Howells   X.509: Add a cryp...
221
222
223
  		break;
  
  	case OID_sha224WithRSAEncryption:
77d0910d1   David Howells   X.509: Retain the...
224
225
  		ctx->cert->sig->hash_algo = "sha224";
  		ctx->cert->sig->pkey_algo = "rsa";
c26fd69fa   David Howells   X.509: Add a cryp...
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  		break;
  	}
  
  	ctx->algo_oid = ctx->last_oid;
  	return 0;
  }
  
  /*
   * Note the whereabouts and type of the signature.
   */
  int x509_note_signature(void *context, size_t hdrlen,
  			unsigned char tag,
  			const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
  
  	pr_debug("Signature type: %u size %zu
  ", ctx->last_oid, vlen);
  
  	if (ctx->last_oid != ctx->algo_oid) {
  		pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs
  ",
  			ctx->algo_oid, ctx->last_oid);
  		return -EINVAL;
  	}
b426beb6e   David Howells   X.509: Embed publ...
251
252
  	ctx->cert->raw_sig = value;
  	ctx->cert->raw_sig_size = vlen;
c26fd69fa   David Howells   X.509: Add a cryp...
253
254
255
256
  	return 0;
  }
  
  /*
84aabd46b   David Howells   X.509: Add bits n...
257
258
259
260
261
262
263
264
265
266
267
268
269
   * Note the certificate serial number
   */
  int x509_note_serial(void *context, size_t hdrlen,
  		     unsigned char tag,
  		     const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
  	ctx->cert->raw_serial = value;
  	ctx->cert->raw_serial_size = vlen;
  	return 0;
  }
  
  /*
c26fd69fa   David Howells   X.509: Add a cryp...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
   * Note some of the name segments from which we'll fabricate a name.
   */
  int x509_extract_name_segment(void *context, size_t hdrlen,
  			      unsigned char tag,
  			      const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
  
  	switch (ctx->last_oid) {
  	case OID_commonName:
  		ctx->cn_size = vlen;
  		ctx->cn_offset = (unsigned long)value - ctx->data;
  		break;
  	case OID_organizationName:
  		ctx->o_size = vlen;
  		ctx->o_offset = (unsigned long)value - ctx->data;
  		break;
  	case OID_email_address:
  		ctx->email_size = vlen;
  		ctx->email_offset = (unsigned long)value - ctx->data;
  		break;
  	default:
  		break;
  	}
  
  	return 0;
  }
  
  /*
   * Fabricate and save the issuer and subject names
   */
  static int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen,
  			       unsigned char tag,
  			       char **_name, size_t vlen)
  {
  	const void *name, *data = (const void *)ctx->data;
  	size_t namesize;
  	char *buffer;
  
  	if (*_name)
  		return -EINVAL;
  
  	/* Empty name string if no material */
  	if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) {
  		buffer = kmalloc(1, GFP_KERNEL);
  		if (!buffer)
  			return -ENOMEM;
  		buffer[0] = 0;
  		goto done;
  	}
  
  	if (ctx->cn_size && ctx->o_size) {
  		/* Consider combining O and CN, but use only the CN if it is
  		 * prefixed by the O, or a significant portion thereof.
  		 */
  		namesize = ctx->cn_size;
  		name = data + ctx->cn_offset;
  		if (ctx->cn_size >= ctx->o_size &&
  		    memcmp(data + ctx->cn_offset, data + ctx->o_offset,
  			   ctx->o_size) == 0)
  			goto single_component;
  		if (ctx->cn_size >= 7 &&
  		    ctx->o_size >= 7 &&
  		    memcmp(data + ctx->cn_offset, data + ctx->o_offset, 7) == 0)
  			goto single_component;
  
  		buffer = kmalloc(ctx->o_size + 2 + ctx->cn_size + 1,
  				 GFP_KERNEL);
  		if (!buffer)
  			return -ENOMEM;
  
  		memcpy(buffer,
  		       data + ctx->o_offset, ctx->o_size);
  		buffer[ctx->o_size + 0] = ':';
  		buffer[ctx->o_size + 1] = ' ';
  		memcpy(buffer + ctx->o_size + 2,
  		       data + ctx->cn_offset, ctx->cn_size);
  		buffer[ctx->o_size + 2 + ctx->cn_size] = 0;
  		goto done;
  
  	} else if (ctx->cn_size) {
  		namesize = ctx->cn_size;
  		name = data + ctx->cn_offset;
  	} else if (ctx->o_size) {
  		namesize = ctx->o_size;
  		name = data + ctx->o_offset;
  	} else {
  		namesize = ctx->email_size;
  		name = data + ctx->email_offset;
  	}
  
  single_component:
  	buffer = kmalloc(namesize + 1, GFP_KERNEL);
  	if (!buffer)
  		return -ENOMEM;
  	memcpy(buffer, name, namesize);
  	buffer[namesize] = 0;
  
  done:
  	*_name = buffer;
  	ctx->cn_size = 0;
  	ctx->o_size = 0;
  	ctx->email_size = 0;
  	return 0;
  }
  
  int x509_note_issuer(void *context, size_t hdrlen,
  		     unsigned char tag,
  		     const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
84aabd46b   David Howells   X.509: Add bits n...
381
382
  	ctx->cert->raw_issuer = value;
  	ctx->cert->raw_issuer_size = vlen;
c26fd69fa   David Howells   X.509: Add a cryp...
383
384
385
386
387
388
389
390
  	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
  }
  
  int x509_note_subject(void *context, size_t hdrlen,
  		      unsigned char tag,
  		      const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
84aabd46b   David Howells   X.509: Add bits n...
391
392
  	ctx->cert->raw_subject = value;
  	ctx->cert->raw_subject_size = vlen;
c26fd69fa   David Howells   X.509: Add a cryp...
393
394
395
396
397
398
399
400
401
402
403
404
405
406
  	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
  }
  
  /*
   * Extract the data for the public key algorithm
   */
  int x509_extract_key_data(void *context, size_t hdrlen,
  			  unsigned char tag,
  			  const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
  
  	if (ctx->last_oid != OID_rsaEncryption)
  		return -ENOPKG;
4e8ae72a7   David Howells   X.509: Make algo ...
407
  	ctx->cert->pub->pkey_algo = "rsa";
67f7d60b3   David Howells   KEYS: Store publi...
408
409
  
  	/* Discard the BIT STRING metadata */
c26fd69fa   David Howells   X.509: Add a cryp...
410
411
412
413
  	ctx->key = value + 1;
  	ctx->key_size = vlen - 1;
  	return 0;
  }
04b00bdb4   Chun-Yi Lee   X.509: Support pa...
414
415
  /* The keyIdentifier in AuthorityKeyIdentifier SEQUENCE is tag(CONT,PRIM,0) */
  #define SEQ_TAG_KEYID (ASN1_CONT << 6)
c26fd69fa   David Howells   X.509: Add a cryp...
416
417
418
419
420
421
422
423
  /*
   * Process certificate extensions that are used to qualify the certificate.
   */
  int x509_process_extension(void *context, size_t hdrlen,
  			   unsigned char tag,
  			   const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
46963b774   David Howells   KEYS: Overhaul ke...
424
  	struct asymmetric_key_id *kid;
c26fd69fa   David Howells   X.509: Add a cryp...
425
  	const unsigned char *v = value;
c26fd69fa   David Howells   X.509: Add a cryp...
426
427
428
429
430
431
  
  	pr_debug("Extension: %u
  ", ctx->last_oid);
  
  	if (ctx->last_oid == OID_subjectKeyIdentifier) {
  		/* Get hold of the key fingerprint */
46963b774   David Howells   KEYS: Overhaul ke...
432
  		if (ctx->cert->skid || vlen < 3)
c26fd69fa   David Howells   X.509: Add a cryp...
433
434
435
436
437
  			return -EBADMSG;
  		if (v[0] != ASN1_OTS || v[1] != vlen - 2)
  			return -EBADMSG;
  		v += 2;
  		vlen -= 2;
dd2f6c448   David Howells   X.509: If availab...
438
439
  		ctx->cert->raw_skid_size = vlen;
  		ctx->cert->raw_skid = v;
a4c6e57f4   David Howells   X.509: Change rec...
440
  		kid = asymmetric_key_generate_id(v, vlen, "", 0);
46963b774   David Howells   KEYS: Overhaul ke...
441
442
443
444
445
  		if (IS_ERR(kid))
  			return PTR_ERR(kid);
  		ctx->cert->skid = kid;
  		pr_debug("subjkeyid %*phN
  ", kid->len, kid->data);
c26fd69fa   David Howells   X.509: Add a cryp...
446
447
448
449
450
  		return 0;
  	}
  
  	if (ctx->last_oid == OID_authorityKeyIdentifier) {
  		/* Get hold of the CA key fingerprint */
b92e6570a   David Howells   X.509: Extract bo...
451
452
  		ctx->raw_akid = v;
  		ctx->raw_akid_size = vlen;
c26fd69fa   David Howells   X.509: Add a cryp...
453
454
455
456
457
  		return 0;
  	}
  
  	return 0;
  }
fd19a3d19   David Howells   PKCS#7: Improve a...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
  /**
   * x509_decode_time - Decode an X.509 time ASN.1 object
   * @_t: The time to fill in
   * @hdrlen: The length of the object header
   * @tag: The object tag
   * @value: The object value
   * @vlen: The size of the object value
   *
   * Decode an ASN.1 universal time or generalised time field into a struct the
   * kernel can handle and check it for validity.  The time is decoded thus:
   *
   *	[RFC5280 ยง4.1.2.5]
   *	CAs conforming to this profile MUST always encode certificate validity
   *	dates through the year 2049 as UTCTime; certificate validity dates in
   *	2050 or later MUST be encoded as GeneralizedTime.  Conforming
   *	applications MUST be able to process validity dates that are encoded in
   *	either UTCTime or GeneralizedTime.
c26fd69fa   David Howells   X.509: Add a cryp...
475
   */
fd19a3d19   David Howells   PKCS#7: Improve a...
476
477
478
  int x509_decode_time(time64_t *_t,  size_t hdrlen,
  		     unsigned char tag,
  		     const unsigned char *value, size_t vlen)
c26fd69fa   David Howells   X.509: Add a cryp...
479
  {
ac4cbedfd   David Howells   X.509: Fix leap y...
480
  	static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30,
fd19a3d19   David Howells   PKCS#7: Improve a...
481
  						       31, 31, 30, 31, 30, 31 };
c26fd69fa   David Howells   X.509: Add a cryp...
482
  	const unsigned char *p = value;
fd19a3d19   David Howells   PKCS#7: Improve a...
483
  	unsigned year, mon, day, hour, min, sec, mon_len;
c26fd69fa   David Howells   X.509: Add a cryp...
484

fd19a3d19   David Howells   PKCS#7: Improve a...
485
  #define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; })
c26fd69fa   David Howells   X.509: Add a cryp...
486
487
488
489
490
491
  #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; })
  
  	if (tag == ASN1_UNITIM) {
  		/* UTCTime: YYMMDDHHMMSSZ */
  		if (vlen != 13)
  			goto unsupported_time;
fd19a3d19   David Howells   PKCS#7: Improve a...
492
493
494
  		year = DD2bin(p);
  		if (year >= 50)
  			year += 1900;
c26fd69fa   David Howells   X.509: Add a cryp...
495
  		else
fd19a3d19   David Howells   PKCS#7: Improve a...
496
  			year += 2000;
c26fd69fa   David Howells   X.509: Add a cryp...
497
498
499
500
  	} else if (tag == ASN1_GENTIM) {
  		/* GenTime: YYYYMMDDHHMMSSZ */
  		if (vlen != 15)
  			goto unsupported_time;
fd19a3d19   David Howells   PKCS#7: Improve a...
501
502
503
  		year = DD2bin(p) * 100 + DD2bin(p);
  		if (year >= 1950 && year <= 2049)
  			goto invalid_time;
c26fd69fa   David Howells   X.509: Add a cryp...
504
505
506
  	} else {
  		goto unsupported_time;
  	}
fd19a3d19   David Howells   PKCS#7: Improve a...
507
508
509
510
511
  	mon  = DD2bin(p);
  	day = DD2bin(p);
  	hour = DD2bin(p);
  	min  = DD2bin(p);
  	sec  = DD2bin(p);
c26fd69fa   David Howells   X.509: Add a cryp...
512
513
514
  
  	if (*p != 'Z')
  		goto unsupported_time;
cc25b994a   David Howells   X.509: Fix the ti...
515
516
517
518
519
  	if (year < 1970 ||
  	    mon < 1 || mon > 12)
  		goto invalid_time;
  
  	mon_len = month_lengths[mon - 1];
fd19a3d19   David Howells   PKCS#7: Improve a...
520
521
522
523
  	if (mon == 2) {
  		if (year % 4 == 0) {
  			mon_len = 29;
  			if (year % 100 == 0) {
ac4cbedfd   David Howells   X.509: Fix leap y...
524
525
526
  				mon_len = 28;
  				if (year % 400 == 0)
  					mon_len = 29;
fd19a3d19   David Howells   PKCS#7: Improve a...
527
528
529
  			}
  		}
  	}
cc25b994a   David Howells   X.509: Fix the ti...
530
  	if (day < 1 || day > mon_len ||
7650cb80e   David Howells   X.509: Handle mid...
531
  	    hour > 24 || /* ISO 8601 permits 24:00:00 as midnight tomorrow */
4dd17c9c8   sudip   crypto: asymmetri...
532
  	    min > 59 ||
da02559c9   David Howells   X.509: Support le...
533
  	    sec > 60) /* ISO 8601 permits leap seconds [X.680 46.3] */
fd19a3d19   David Howells   PKCS#7: Improve a...
534
  		goto invalid_time;
cc25b994a   David Howells   X.509: Fix the ti...
535

fd19a3d19   David Howells   PKCS#7: Improve a...
536
  	*_t = mktime64(year, mon, day, hour, min, sec);
c26fd69fa   David Howells   X.509: Add a cryp...
537
538
539
  	return 0;
  
  unsupported_time:
fd19a3d19   David Howells   PKCS#7: Improve a...
540
541
542
543
544
545
546
547
  	pr_debug("Got unsupported time [tag %02x]: '%*phN'
  ",
  		 tag, (int)vlen, value);
  	return -EBADMSG;
  invalid_time:
  	pr_debug("Got invalid time [tag %02x]: '%*phN'
  ",
  		 tag, (int)vlen, value);
c26fd69fa   David Howells   X.509: Add a cryp...
548
549
  	return -EBADMSG;
  }
fd19a3d19   David Howells   PKCS#7: Improve a...
550
  EXPORT_SYMBOL_GPL(x509_decode_time);
c26fd69fa   David Howells   X.509: Add a cryp...
551
552
553
554
555
556
  
  int x509_note_not_before(void *context, size_t hdrlen,
  			 unsigned char tag,
  			 const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
fd19a3d19   David Howells   PKCS#7: Improve a...
557
  	return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen);
c26fd69fa   David Howells   X.509: Add a cryp...
558
559
560
561
562
563
564
  }
  
  int x509_note_not_after(void *context, size_t hdrlen,
  			unsigned char tag,
  			const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
fd19a3d19   David Howells   PKCS#7: Improve a...
565
  	return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen);
c26fd69fa   David Howells   X.509: Add a cryp...
566
  }
b92e6570a   David Howells   X.509: Extract bo...
567
568
569
570
571
572
573
574
575
576
577
578
579
  
  /*
   * Note a key identifier-based AuthorityKeyIdentifier
   */
  int x509_akid_note_kid(void *context, size_t hdrlen,
  		       unsigned char tag,
  		       const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
  	struct asymmetric_key_id *kid;
  
  	pr_debug("AKID: keyid: %*phN
  ", (int)vlen, value);
77d0910d1   David Howells   X.509: Retain the...
580
  	if (ctx->cert->sig->auth_ids[1])
b92e6570a   David Howells   X.509: Extract bo...
581
  		return 0;
a4c6e57f4   David Howells   X.509: Change rec...
582
  	kid = asymmetric_key_generate_id(value, vlen, "", 0);
b92e6570a   David Howells   X.509: Extract bo...
583
584
585
586
  	if (IS_ERR(kid))
  		return PTR_ERR(kid);
  	pr_debug("authkeyid %*phN
  ", kid->len, kid->data);
77d0910d1   David Howells   X.509: Retain the...
587
  	ctx->cert->sig->auth_ids[1] = kid;
b92e6570a   David Howells   X.509: Extract bo...
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
  	return 0;
  }
  
  /*
   * Note a directoryName in an AuthorityKeyIdentifier
   */
  int x509_akid_note_name(void *context, size_t hdrlen,
  			unsigned char tag,
  			const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
  
  	pr_debug("AKID: name: %*phN
  ", (int)vlen, value);
  
  	ctx->akid_raw_issuer = value;
  	ctx->akid_raw_issuer_size = vlen;
  	return 0;
  }
  
  /*
   * Note a serial number in an AuthorityKeyIdentifier
   */
  int x509_akid_note_serial(void *context, size_t hdrlen,
  			  unsigned char tag,
  			  const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
  	struct asymmetric_key_id *kid;
  
  	pr_debug("AKID: serial: %*phN
  ", (int)vlen, value);
77d0910d1   David Howells   X.509: Retain the...
620
  	if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0])
b92e6570a   David Howells   X.509: Extract bo...
621
622
623
624
625
626
627
628
629
630
631
  		return 0;
  
  	kid = asymmetric_key_generate_id(value,
  					 vlen,
  					 ctx->akid_raw_issuer,
  					 ctx->akid_raw_issuer_size);
  	if (IS_ERR(kid))
  		return PTR_ERR(kid);
  
  	pr_debug("authkeyid %*phN
  ", kid->len, kid->data);
77d0910d1   David Howells   X.509: Retain the...
632
  	ctx->cert->sig->auth_ids[0] = kid;
b92e6570a   David Howells   X.509: Extract bo...
633
634
  	return 0;
  }