Blame view

crypto/asymmetric_keys/x509_cert_parser.c 18.5 KB
b4d0d230c   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
c26fd69fa   David Howells   X.509: Add a cryp...
2
3
4
5
  /* X.509 certificate parser
   *
   * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells (dhowells@redhat.com)
c26fd69fa   David Howells   X.509: Add a cryp...
6
7
8
9
   */
  
  #define pr_fmt(fmt) "X.509: "fmt
  #include <linux/kernel.h>
ace0107a3   David Howells   X.509: Export cer...
10
  #include <linux/export.h>
c26fd69fa   David Howells   X.509: Add a cryp...
11
12
13
  #include <linux/slab.h>
  #include <linux/err.h>
  #include <linux/oid_registry.h>
db6c43bd2   Tadeusz Struk   crypto: KEYS: con...
14
  #include <crypto/public_key.h>
c26fd69fa   David Howells   X.509: Add a cryp...
15
  #include "x509_parser.h"
4fa8bc949   Masahiro Yamada   kbuild: rename *-...
16
17
  #include "x509.asn1.h"
  #include "x509_akid.asn1.h"
c26fd69fa   David Howells   X.509: Add a cryp...
18
19
20
21
22
23
24
  
  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 */
f1774cb89   Vitaly Chikunov   X.509: parse publ...
25
26
27
  	const void	*params;		/* Key parameters */
  	size_t		params_size;		/* Size of key parameters */
  	enum OID	key_algo;		/* Public key algorithm */
c26fd69fa   David Howells   X.509: Add a cryp...
28
29
30
31
32
33
34
35
36
  	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...
37
38
39
40
  	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...
41
42
43
44
45
46
47
48
  };
  
  /*
   * Free an X.509 certificate
   */
  void x509_free_certificate(struct x509_certificate *cert)
  {
  	if (cert) {
3b7645631   David Howells   KEYS: Allow authe...
49
  		public_key_free(cert->pub);
77d0910d1   David Howells   X.509: Retain the...
50
  		public_key_signature_free(cert->sig);
c26fd69fa   David Howells   X.509: Add a cryp...
51
52
  		kfree(cert->issuer);
  		kfree(cert->subject);
46963b774   David Howells   KEYS: Overhaul ke...
53
54
  		kfree(cert->id);
  		kfree(cert->skid);
c26fd69fa   David Howells   X.509: Add a cryp...
55
56
57
  		kfree(cert);
  	}
  }
ace0107a3   David Howells   X.509: Export cer...
58
  EXPORT_SYMBOL_GPL(x509_free_certificate);
c26fd69fa   David Howells   X.509: Add a cryp...
59
60
61
62
63
64
65
66
  
  /*
   * 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...
67
  	struct asymmetric_key_id *kid;
c26fd69fa   David Howells   X.509: Add a cryp...
68
69
70
71
72
73
74
75
76
  	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...
77
78
79
  	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...
80
81
82
83
84
85
86
87
88
89
90
  	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...
91
92
93
94
95
96
97
98
99
100
101
102
103
  	/* 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;
  		}
  	}
4e880168e   Dan Carpenter   X.509: Fix error ...
104
  	ret = -ENOMEM;
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;
f1774cb89   Vitaly Chikunov   X.509: parse publ...
109
110
111
112
113
114
  	cert->pub->params = kmemdup(ctx->params, ctx->params_size, GFP_KERNEL);
  	if (!cert->pub->params)
  		goto error_decode;
  
  	cert->pub->paramlen = ctx->params_size;
  	cert->pub->algo = ctx->key_algo;
6c2dc5ae4   David Howells   X.509: Extract si...
115
116
117
118
  	/* Grab the signature bits */
  	ret = x509_get_sig_params(cert);
  	if (ret < 0)
  		goto error_decode;
46963b774   David Howells   KEYS: Overhaul ke...
119
120
121
122
123
124
125
126
127
128
  	/* 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...
129
130
131
132
  	/* 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...
133
134
135
136
137
138
139
140
141
142
  	kfree(ctx);
  	return cert;
  
  error_decode:
  	kfree(ctx);
  error_no_ctx:
  	x509_free_certificate(cert);
  error_no_cert:
  	return ERR_PTR(ret);
  }
ace0107a3   David Howells   X.509: Export cer...
143
  EXPORT_SYMBOL_GPL(x509_cert_parse);
c26fd69fa   David Howells   X.509: Add a cryp...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  
  /*
   * 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: ...
159
160
  		pr_debug("Unknown OID: [%lu] %s
  ",
c26fd69fa   David Howells   X.509: Add a cryp...
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
199
200
201
202
203
  			 (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...
204
  		ctx->cert->sig->hash_algo = "md4";
039884907   David Howells   KEYS: Make the X....
205
  		goto rsa_pkcs1;
c26fd69fa   David Howells   X.509: Add a cryp...
206
207
  
  	case OID_sha1WithRSAEncryption:
77d0910d1   David Howells   X.509: Retain the...
208
  		ctx->cert->sig->hash_algo = "sha1";
039884907   David Howells   KEYS: Make the X....
209
  		goto rsa_pkcs1;
c26fd69fa   David Howells   X.509: Add a cryp...
210
211
  
  	case OID_sha256WithRSAEncryption:
77d0910d1   David Howells   X.509: Retain the...
212
  		ctx->cert->sig->hash_algo = "sha256";
039884907   David Howells   KEYS: Make the X....
213
  		goto rsa_pkcs1;
c26fd69fa   David Howells   X.509: Add a cryp...
214
215
  
  	case OID_sha384WithRSAEncryption:
77d0910d1   David Howells   X.509: Retain the...
216
  		ctx->cert->sig->hash_algo = "sha384";
039884907   David Howells   KEYS: Make the X....
217
  		goto rsa_pkcs1;
c26fd69fa   David Howells   X.509: Add a cryp...
218
219
  
  	case OID_sha512WithRSAEncryption:
77d0910d1   David Howells   X.509: Retain the...
220
  		ctx->cert->sig->hash_algo = "sha512";
039884907   David Howells   KEYS: Make the X....
221
  		goto rsa_pkcs1;
c26fd69fa   David Howells   X.509: Add a cryp...
222
223
  
  	case OID_sha224WithRSAEncryption:
77d0910d1   David Howells   X.509: Retain the...
224
  		ctx->cert->sig->hash_algo = "sha224";
039884907   David Howells   KEYS: Make the X....
225
  		goto rsa_pkcs1;
0d7a78643   Vitaly Chikunov   crypto: ecrdsa - ...
226

299f561a6   Stefan Berger   x509: Add support...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  	case OID_id_ecdsa_with_sha1:
  		ctx->cert->sig->hash_algo = "sha1";
  		goto ecdsa;
  
  	case OID_id_ecdsa_with_sha224:
  		ctx->cert->sig->hash_algo = "sha224";
  		goto ecdsa;
  
  	case OID_id_ecdsa_with_sha256:
  		ctx->cert->sig->hash_algo = "sha256";
  		goto ecdsa;
  
  	case OID_id_ecdsa_with_sha384:
  		ctx->cert->sig->hash_algo = "sha384";
  		goto ecdsa;
  
  	case OID_id_ecdsa_with_sha512:
  		ctx->cert->sig->hash_algo = "sha512";
  		goto ecdsa;
0d7a78643   Vitaly Chikunov   crypto: ecrdsa - ...
246
247
248
249
250
251
252
  	case OID_gost2012Signature256:
  		ctx->cert->sig->hash_algo = "streebog256";
  		goto ecrdsa;
  
  	case OID_gost2012Signature512:
  		ctx->cert->sig->hash_algo = "streebog512";
  		goto ecrdsa;
254f84f55   Tianjia Zhang   X.509: support OS...
253
254
255
256
  
  	case OID_SM2_with_SM3:
  		ctx->cert->sig->hash_algo = "sm3";
  		goto sm2;
c26fd69fa   David Howells   X.509: Add a cryp...
257
  	}
039884907   David Howells   KEYS: Make the X....
258
259
260
  rsa_pkcs1:
  	ctx->cert->sig->pkey_algo = "rsa";
  	ctx->cert->sig->encoding = "pkcs1";
c26fd69fa   David Howells   X.509: Add a cryp...
261
262
  	ctx->algo_oid = ctx->last_oid;
  	return 0;
0d7a78643   Vitaly Chikunov   crypto: ecrdsa - ...
263
264
265
266
267
  ecrdsa:
  	ctx->cert->sig->pkey_algo = "ecrdsa";
  	ctx->cert->sig->encoding = "raw";
  	ctx->algo_oid = ctx->last_oid;
  	return 0;
254f84f55   Tianjia Zhang   X.509: support OS...
268
269
270
271
272
  sm2:
  	ctx->cert->sig->pkey_algo = "sm2";
  	ctx->cert->sig->encoding = "raw";
  	ctx->algo_oid = ctx->last_oid;
  	return 0;
299f561a6   Stefan Berger   x509: Add support...
273
274
275
276
277
  ecdsa:
  	ctx->cert->sig->pkey_algo = "ecdsa";
  	ctx->cert->sig->encoding = "x962";
  	ctx->algo_oid = ctx->last_oid;
  	return 0;
c26fd69fa   David Howells   X.509: Add a cryp...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
  }
  
  /*
   * 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;
  	}
0d7a78643   Vitaly Chikunov   crypto: ecrdsa - ...
298
  	if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 ||
254f84f55   Tianjia Zhang   X.509: support OS...
299
  	    strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0 ||
299f561a6   Stefan Berger   x509: Add support...
300
301
  	    strcmp(ctx->cert->sig->pkey_algo, "sm2") == 0 ||
  	    strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0) {
b65c32ec5   Maciej S. Szmigiero   X.509: unpack RSA...
302
303
304
305
306
307
308
  		/* Discard the BIT STRING metadata */
  		if (vlen < 1 || *(const u8 *)value != 0)
  			return -EBADMSG;
  
  		value++;
  		vlen--;
  	}
b426beb6e   David Howells   X.509: Embed publ...
309
310
  	ctx->cert->raw_sig = value;
  	ctx->cert->raw_sig_size = vlen;
c26fd69fa   David Howells   X.509: Add a cryp...
311
312
313
314
  	return 0;
  }
  
  /*
84aabd46b   David Howells   X.509: Add bits n...
315
316
317
318
319
320
321
322
323
324
325
326
327
   * 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...
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
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
   * 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...
439
440
  	ctx->cert->raw_issuer = value;
  	ctx->cert->raw_issuer_size = vlen;
c26fd69fa   David Howells   X.509: Add a cryp...
441
442
443
444
445
446
447
448
  	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...
449
450
  	ctx->cert->raw_subject = value;
  	ctx->cert->raw_subject_size = vlen;
c26fd69fa   David Howells   X.509: Add a cryp...
451
452
453
454
  	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
  }
  
  /*
f1774cb89   Vitaly Chikunov   X.509: parse publ...
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
   * Extract the parameters for the public key
   */
  int x509_note_params(void *context, size_t hdrlen,
  		     unsigned char tag,
  		     const void *value, size_t vlen)
  {
  	struct x509_parse_context *ctx = context;
  
  	/*
  	 * AlgorithmIdentifier is used three times in the x509, we should skip
  	 * first and ignore third, using second one which is after subject and
  	 * before subjectPublicKey.
  	 */
  	if (!ctx->cert->raw_subject || ctx->key)
  		return 0;
  	ctx->params = value - hdrlen;
  	ctx->params_size = vlen + hdrlen;
  	return 0;
  }
  
  /*
c26fd69fa   David Howells   X.509: Add a cryp...
476
477
478
479
480
481
482
   * 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;
d1a303e86   Stefan Berger   x509: Detect sm2 ...
483
  	enum OID oid;
c26fd69fa   David Howells   X.509: Add a cryp...
484

0d7a78643   Vitaly Chikunov   crypto: ecrdsa - ...
485
  	ctx->key_algo = ctx->last_oid;
254f84f55   Tianjia Zhang   X.509: support OS...
486
487
  	switch (ctx->last_oid) {
  	case OID_rsaEncryption:
0d7a78643   Vitaly Chikunov   crypto: ecrdsa - ...
488
  		ctx->cert->pub->pkey_algo = "rsa";
254f84f55   Tianjia Zhang   X.509: support OS...
489
490
491
  		break;
  	case OID_gost2012PKey256:
  	case OID_gost2012PKey512:
0d7a78643   Vitaly Chikunov   crypto: ecrdsa - ...
492
  		ctx->cert->pub->pkey_algo = "ecrdsa";
254f84f55   Tianjia Zhang   X.509: support OS...
493
494
  		break;
  	case OID_id_ecPublicKey:
d1a303e86   Stefan Berger   x509: Detect sm2 ...
495
496
497
498
499
500
501
  		if (parse_OID(ctx->params, ctx->params_size, &oid) != 0)
  			return -EBADMSG;
  
  		switch (oid) {
  		case OID_sm2:
  			ctx->cert->pub->pkey_algo = "sm2";
  			break;
299f561a6   Stefan Berger   x509: Add support...
502
503
504
505
506
507
  		case OID_id_prime192v1:
  			ctx->cert->pub->pkey_algo = "ecdsa-nist-p192";
  			break;
  		case OID_id_prime256v1:
  			ctx->cert->pub->pkey_algo = "ecdsa-nist-p256";
  			break;
2a8e61543   Saulo Alessandre   x509: Add OID for...
508
509
510
  		case OID_id_ansip384r1:
  			ctx->cert->pub->pkey_algo = "ecdsa-nist-p384";
  			break;
d1a303e86   Stefan Berger   x509: Detect sm2 ...
511
512
513
  		default:
  			return -ENOPKG;
  		}
254f84f55   Tianjia Zhang   X.509: support OS...
514
515
  		break;
  	default:
c26fd69fa   David Howells   X.509: Add a cryp...
516
  		return -ENOPKG;
254f84f55   Tianjia Zhang   X.509: support OS...
517
  	}
c26fd69fa   David Howells   X.509: Add a cryp...
518

67f7d60b3   David Howells   KEYS: Store publi...
519
  	/* Discard the BIT STRING metadata */
0f30cbea0   Eric Biggers   X.509: reject inv...
520
521
  	if (vlen < 1 || *(const u8 *)value != 0)
  		return -EBADMSG;
c26fd69fa   David Howells   X.509: Add a cryp...
522
523
524
525
  	ctx->key = value + 1;
  	ctx->key_size = vlen - 1;
  	return 0;
  }
04b00bdb4   Chun-Yi Lee   X.509: Support pa...
526
527
  /* 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...
528
529
530
531
532
533
534
535
  /*
   * 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...
536
  	struct asymmetric_key_id *kid;
c26fd69fa   David Howells   X.509: Add a cryp...
537
  	const unsigned char *v = value;
c26fd69fa   David Howells   X.509: Add a cryp...
538
539
540
541
542
543
  
  	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...
544
  		if (ctx->cert->skid || vlen < 3)
c26fd69fa   David Howells   X.509: Add a cryp...
545
546
547
548
549
  			return -EBADMSG;
  		if (v[0] != ASN1_OTS || v[1] != vlen - 2)
  			return -EBADMSG;
  		v += 2;
  		vlen -= 2;
dd2f6c448   David Howells   X.509: If availab...
550
551
  		ctx->cert->raw_skid_size = vlen;
  		ctx->cert->raw_skid = v;
a4c6e57f4   David Howells   X.509: Change rec...
552
  		kid = asymmetric_key_generate_id(v, vlen, "", 0);
46963b774   David Howells   KEYS: Overhaul ke...
553
554
555
556
557
  		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...
558
559
560
561
562
  		return 0;
  	}
  
  	if (ctx->last_oid == OID_authorityKeyIdentifier) {
  		/* Get hold of the CA key fingerprint */
b92e6570a   David Howells   X.509: Extract bo...
563
564
  		ctx->raw_akid = v;
  		ctx->raw_akid_size = vlen;
c26fd69fa   David Howells   X.509: Add a cryp...
565
566
567
568
569
  		return 0;
  	}
  
  	return 0;
  }
fd19a3d19   David Howells   PKCS#7: Improve a...
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
  /**
   * 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...
587
   */
fd19a3d19   David Howells   PKCS#7: Improve a...
588
589
590
  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...
591
  {
ac4cbedfd   David Howells   X.509: Fix leap y...
592
  	static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30,
fd19a3d19   David Howells   PKCS#7: Improve a...
593
  						       31, 31, 30, 31, 30, 31 };
c26fd69fa   David Howells   X.509: Add a cryp...
594
  	const unsigned char *p = value;
fd19a3d19   David Howells   PKCS#7: Improve a...
595
  	unsigned year, mon, day, hour, min, sec, mon_len;
c26fd69fa   David Howells   X.509: Add a cryp...
596

fd19a3d19   David Howells   PKCS#7: Improve a...
597
  #define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; })
c26fd69fa   David Howells   X.509: Add a cryp...
598
599
600
601
602
603
  #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...
604
605
606
  		year = DD2bin(p);
  		if (year >= 50)
  			year += 1900;
c26fd69fa   David Howells   X.509: Add a cryp...
607
  		else
fd19a3d19   David Howells   PKCS#7: Improve a...
608
  			year += 2000;
c26fd69fa   David Howells   X.509: Add a cryp...
609
610
611
612
  	} else if (tag == ASN1_GENTIM) {
  		/* GenTime: YYYYMMDDHHMMSSZ */
  		if (vlen != 15)
  			goto unsupported_time;
fd19a3d19   David Howells   PKCS#7: Improve a...
613
614
615
  		year = DD2bin(p) * 100 + DD2bin(p);
  		if (year >= 1950 && year <= 2049)
  			goto invalid_time;
c26fd69fa   David Howells   X.509: Add a cryp...
616
617
618
  	} else {
  		goto unsupported_time;
  	}
fd19a3d19   David Howells   PKCS#7: Improve a...
619
620
621
622
623
  	mon  = DD2bin(p);
  	day = DD2bin(p);
  	hour = DD2bin(p);
  	min  = DD2bin(p);
  	sec  = DD2bin(p);
c26fd69fa   David Howells   X.509: Add a cryp...
624
625
626
  
  	if (*p != 'Z')
  		goto unsupported_time;
cc25b994a   David Howells   X.509: Fix the ti...
627
628
629
630
631
  	if (year < 1970 ||
  	    mon < 1 || mon > 12)
  		goto invalid_time;
  
  	mon_len = month_lengths[mon - 1];
fd19a3d19   David Howells   PKCS#7: Improve a...
632
633
634
635
  	if (mon == 2) {
  		if (year % 4 == 0) {
  			mon_len = 29;
  			if (year % 100 == 0) {
ac4cbedfd   David Howells   X.509: Fix leap y...
636
637
638
  				mon_len = 28;
  				if (year % 400 == 0)
  					mon_len = 29;
fd19a3d19   David Howells   PKCS#7: Improve a...
639
640
641
  			}
  		}
  	}
cc25b994a   David Howells   X.509: Fix the ti...
642
  	if (day < 1 || day > mon_len ||
7650cb80e   David Howells   X.509: Handle mid...
643
  	    hour > 24 || /* ISO 8601 permits 24:00:00 as midnight tomorrow */
4dd17c9c8   sudip   crypto: asymmetri...
644
  	    min > 59 ||
da02559c9   David Howells   X.509: Support le...
645
  	    sec > 60) /* ISO 8601 permits leap seconds [X.680 46.3] */
fd19a3d19   David Howells   PKCS#7: Improve a...
646
  		goto invalid_time;
cc25b994a   David Howells   X.509: Fix the ti...
647

fd19a3d19   David Howells   PKCS#7: Improve a...
648
  	*_t = mktime64(year, mon, day, hour, min, sec);
c26fd69fa   David Howells   X.509: Add a cryp...
649
650
651
  	return 0;
  
  unsupported_time:
fd19a3d19   David Howells   PKCS#7: Improve a...
652
653
654
655
656
657
658
659
  	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...
660
661
  	return -EBADMSG;
  }
fd19a3d19   David Howells   PKCS#7: Improve a...
662
  EXPORT_SYMBOL_GPL(x509_decode_time);
c26fd69fa   David Howells   X.509: Add a cryp...
663
664
665
666
667
668
  
  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...
669
  	return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen);
c26fd69fa   David Howells   X.509: Add a cryp...
670
671
672
673
674
675
676
  }
  
  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...
677
  	return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen);
c26fd69fa   David Howells   X.509: Add a cryp...
678
  }
b92e6570a   David Howells   X.509: Extract bo...
679
680
681
682
683
684
685
686
687
688
689
690
691
  
  /*
   * 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...
692
  	if (ctx->cert->sig->auth_ids[1])
b92e6570a   David Howells   X.509: Extract bo...
693
  		return 0;
a4c6e57f4   David Howells   X.509: Change rec...
694
  	kid = asymmetric_key_generate_id(value, vlen, "", 0);
b92e6570a   David Howells   X.509: Extract bo...
695
696
697
698
  	if (IS_ERR(kid))
  		return PTR_ERR(kid);
  	pr_debug("authkeyid %*phN
  ", kid->len, kid->data);
77d0910d1   David Howells   X.509: Retain the...
699
  	ctx->cert->sig->auth_ids[1] = kid;
b92e6570a   David Howells   X.509: Extract bo...
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
  	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...
732
  	if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0])
b92e6570a   David Howells   X.509: Extract bo...
733
734
735
736
737
738
739
740
741
742
743
  		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...
744
  	ctx->cert->sig->auth_ids[0] = kid;
b92e6570a   David Howells   X.509: Extract bo...
745
746
  	return 0;
  }