Browse Source

[crypto] Allow certificate chains to be long-lived data structures

At present, certificate chain validation is treated as an
instantaneous process that can be carried out using only data that is
already in memory.  This model does not allow for validation to
include non-instantaneous steps, such as downloading a cross-signing
certificate, or determining certificate revocation status via OCSP.

Redesign the internal representation of certificate chains to allow
chains to outlive the scope of the original source of certificates
(such as a TLS Certificate record).

Allow for certificates to be cached, so that each certificate needs to
be validated only once.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 years ago
parent
commit
557f467bab
9 changed files with 1075 additions and 463 deletions
  1. 274
    109
      src/crypto/cms.c
  2. 362
    116
      src/crypto/x509.c
  3. 39
    14
      src/include/ipxe/cms.h
  4. 3
    0
      src/include/ipxe/tls.h
  5. 132
    24
      src/include/ipxe/x509.h
  6. 94
    67
      src/net/tls.c
  7. 25
    18
      src/tests/cms_test.c
  8. 134
    109
      src/tests/x509_test.c
  9. 12
    6
      src/usr/imgtrust.c

+ 274
- 109
src/crypto/cms.c View File

32
 #include <errno.h>
32
 #include <errno.h>
33
 #include <ipxe/asn1.h>
33
 #include <ipxe/asn1.h>
34
 #include <ipxe/x509.h>
34
 #include <ipxe/x509.h>
35
+#include <ipxe/malloc.h>
35
 #include <ipxe/uaccess.h>
36
 #include <ipxe/uaccess.h>
36
 #include <ipxe/cms.h>
37
 #include <ipxe/cms.h>
37
 
38
 
44
 	__einfo_error ( EINFO_EACCES_NON_CODE_SIGNING )
45
 	__einfo_error ( EINFO_EACCES_NON_CODE_SIGNING )
45
 #define EINFO_EACCES_NON_CODE_SIGNING \
46
 #define EINFO_EACCES_NON_CODE_SIGNING \
46
 	__einfo_uniqify ( EINFO_EACCES, 0x02, "Not a code-signing certificate" )
47
 	__einfo_uniqify ( EINFO_EACCES, 0x02, "Not a code-signing certificate" )
47
-#define EACCES_INCOMPLETE \
48
-	__einfo_error ( EINFO_EACCES_INCOMPLETE )
49
-#define EINFO_EACCES_INCOMPLETE \
50
-	__einfo_uniqify ( EINFO_EACCES, 0x03, "Incomplete certificate chain" )
51
 #define EACCES_WRONG_NAME \
48
 #define EACCES_WRONG_NAME \
52
 	__einfo_error ( EINFO_EACCES_WRONG_NAME )
49
 	__einfo_error ( EINFO_EACCES_WRONG_NAME )
53
 #define EINFO_EACCES_WRONG_NAME \
50
 #define EINFO_EACCES_WRONG_NAME \
54
 	__einfo_uniqify ( EINFO_EACCES, 0x04, "Incorrect certificate name" )
51
 	__einfo_uniqify ( EINFO_EACCES, 0x04, "Incorrect certificate name" )
52
+#define EACCES_NO_SIGNATURES \
53
+	__einfo_error ( EINFO_EACCES_NO_SIGNATURES )
54
+#define EINFO_EACCES_NO_SIGNATURES \
55
+	__einfo_uniqify ( EINFO_EACCES, 0x05, "No signatures present" )
55
 #define EINVAL_DIGEST \
56
 #define EINVAL_DIGEST \
56
 	__einfo_error ( EINFO_EINVAL_DIGEST )
57
 	__einfo_error ( EINFO_EINVAL_DIGEST )
57
 #define EINFO_EINVAL_DIGEST \
58
 #define EINFO_EINVAL_DIGEST \
107
 	return 0;
108
 	return 0;
108
 }
109
 }
109
 
110
 
111
+/**
112
+ * Parse CMS signature certificate list
113
+ *
114
+ * @v sig		CMS signature
115
+ * @v raw		ASN.1 cursor
116
+ * @ret rc		Return status code
117
+ */
118
+static int cms_parse_certificates ( struct cms_signature *sig,
119
+				    const struct asn1_cursor *raw ) {
120
+	struct asn1_cursor cursor;
121
+	struct x509_certificate *cert;
122
+	int rc;
123
+
124
+	/* Enter certificates */
125
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
126
+	asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
127
+
128
+	/* Add each certificate */
129
+	while ( cursor.len ) {
130
+
131
+		/* Parse certificate */
132
+		if ( ( rc = x509_certificate ( cursor.data, cursor.len,
133
+					       &cert ) ) != 0 ) {
134
+			DBGC ( sig, "CMS %p could not parse certificate: %s\n",
135
+			       sig, strerror ( rc) );
136
+			DBGC_HDA ( sig, 0, cursor.data, cursor.len );
137
+			goto err_parse;
138
+		}
139
+		DBGC ( sig, "CMS %p found certificate %s\n",
140
+		       sig, cert->subject.name );
141
+
142
+		/* Add certificate to list */
143
+		if ( ( rc = x509_append ( sig->certificates, cert ) ) != 0 ) {
144
+			DBGC ( sig, "CMS %p could not append certificate: %s\n",
145
+			       sig, strerror ( rc ) );
146
+			goto err_append;
147
+		}
148
+
149
+		/* Drop reference to certificate */
150
+		x509_put ( cert );
151
+		cert = NULL;
152
+
153
+		/* Move to next certificate */
154
+		asn1_skip_any ( &cursor );
155
+	}
156
+
157
+	return 0;
158
+
159
+ err_append:
160
+	x509_put ( cert );
161
+ err_parse:
162
+	return rc;
163
+}
164
+
165
+/**
166
+ * Identify CMS signature certificate by issuer and serial number
167
+ *
168
+ * @v sig		CMS signature
169
+ * @v issuer		Issuer
170
+ * @v serial		Serial number
171
+ * @ret cert		X.509 certificate, or NULL if not found
172
+ */
173
+static struct x509_certificate *
174
+cms_find_issuer_serial ( struct cms_signature *sig,
175
+			 const struct asn1_cursor *issuer,
176
+			 const struct asn1_cursor *serial ) {
177
+	struct x509_link *link;
178
+	struct x509_certificate *cert;
179
+
180
+	/* Scan through certificate list */
181
+	list_for_each_entry ( link, &sig->certificates->links, list ) {
182
+
183
+		/* Check issuer and serial number */
184
+		cert = link->cert;
185
+		if ( ( asn1_compare ( issuer, &cert->issuer.raw ) == 0 ) &&
186
+		     ( asn1_compare ( serial, &cert->serial.raw ) == 0 ) )
187
+			return cert;
188
+	}
189
+
190
+	return NULL;
191
+}
192
+
193
+/**
194
+ * Identify CMS signature certificate by subject
195
+ *
196
+ * @v sig		CMS signature
197
+ * @v subject		Subject
198
+ * @ret cert		X.509 certificate, or NULL if not found
199
+ */
200
+static struct x509_certificate *
201
+cms_find_subject ( struct cms_signature *sig,
202
+		   const struct asn1_cursor *subject ) {
203
+	struct x509_link *link;
204
+	struct x509_certificate *cert;
205
+
206
+	/* Scan through certificate list */
207
+	list_for_each_entry ( link, &sig->certificates->links, list ) {
208
+
209
+		/* Check subject */
210
+		cert = link->cert;
211
+		if ( asn1_compare ( subject, &cert->subject.raw ) == 0 )
212
+			return cert;
213
+	}
214
+
215
+	return NULL;
216
+}
217
+
110
 /**
218
 /**
111
  * Parse CMS signature signer identifier
219
  * Parse CMS signature signer identifier
112
  *
220
  *
119
 					 struct cms_signer_info *info,
227
 					 struct cms_signer_info *info,
120
 					 const struct asn1_cursor *raw ) {
228
 					 const struct asn1_cursor *raw ) {
121
 	struct asn1_cursor cursor;
229
 	struct asn1_cursor cursor;
230
+	struct asn1_cursor serial;
231
+	struct asn1_cursor issuer;
232
+	struct x509_certificate *cert;
233
+	struct x509_certificate *previous;
122
 	int rc;
234
 	int rc;
123
 
235
 
124
 	/* Enter issuerAndSerialNumber */
236
 	/* Enter issuerAndSerialNumber */
125
 	memcpy ( &cursor, raw, sizeof ( cursor ) );
237
 	memcpy ( &cursor, raw, sizeof ( cursor ) );
126
 	asn1_enter ( &cursor, ASN1_SEQUENCE );
238
 	asn1_enter ( &cursor, ASN1_SEQUENCE );
127
 
239
 
128
-	/* Record issuer */
129
-	memcpy ( &info->issuer, &cursor, sizeof ( info->issuer ) );
130
-	if ( ( rc = asn1_shrink ( &info->issuer, ASN1_SEQUENCE ) ) != 0 ) {
240
+	/* Identify issuer */
241
+	memcpy ( &issuer, &cursor, sizeof ( issuer ) );
242
+	if ( ( rc = asn1_shrink ( &issuer, ASN1_SEQUENCE ) ) != 0 ) {
131
 		DBGC ( sig, "CMS %p/%p could not locate issuer: %s\n",
243
 		DBGC ( sig, "CMS %p/%p could not locate issuer: %s\n",
132
 		       sig, info, strerror ( rc ) );
244
 		       sig, info, strerror ( rc ) );
133
 		DBGC_HDA ( sig, 0, raw->data, raw->len );
245
 		DBGC_HDA ( sig, 0, raw->data, raw->len );
134
 		return rc;
246
 		return rc;
135
 	}
247
 	}
136
 	DBGC ( sig, "CMS %p/%p issuer is:\n", sig, info );
248
 	DBGC ( sig, "CMS %p/%p issuer is:\n", sig, info );
137
-	DBGC_HDA ( sig, 0, info->issuer.data, info->issuer.len );
249
+	DBGC_HDA ( sig, 0, issuer.data, issuer.len );
138
 	asn1_skip_any ( &cursor );
250
 	asn1_skip_any ( &cursor );
139
 
251
 
140
-	/* Record serialNumber */
141
-	memcpy ( &info->serial, &cursor, sizeof ( info->serial ) );
142
-	if ( ( rc = asn1_shrink ( &info->serial, ASN1_INTEGER ) ) != 0 ) {
252
+	/* Identify serialNumber */
253
+	memcpy ( &serial, &cursor, sizeof ( serial ) );
254
+	if ( ( rc = asn1_shrink ( &serial, ASN1_INTEGER ) ) != 0 ) {
143
 		DBGC ( sig, "CMS %p/%p could not locate serialNumber: %s\n",
255
 		DBGC ( sig, "CMS %p/%p could not locate serialNumber: %s\n",
144
 		       sig, info, strerror ( rc ) );
256
 		       sig, info, strerror ( rc ) );
145
 		DBGC_HDA ( sig, 0, raw->data, raw->len );
257
 		DBGC_HDA ( sig, 0, raw->data, raw->len );
146
 		return rc;
258
 		return rc;
147
 	}
259
 	}
148
 	DBGC ( sig, "CMS %p/%p serial number is:\n", sig, info );
260
 	DBGC ( sig, "CMS %p/%p serial number is:\n", sig, info );
149
-	DBGC_HDA ( sig, 0, info->serial.data, info->serial.len );
261
+	DBGC_HDA ( sig, 0, serial.data, serial.len );
262
+
263
+	/* Identify certificate */
264
+	cert = cms_find_issuer_serial ( sig, &issuer, &serial );
265
+	if ( ! cert ) {
266
+		DBGC ( sig, "CMS %p/%p could not identify signer's "
267
+		       "certificate\n", sig, info );
268
+		return -ENOENT;
269
+	}
270
+
271
+	/* Create certificate chain */
272
+	do {
273
+		/* Add certificate to chain */
274
+		if ( ( rc = x509_append ( info->chain, cert ) ) != 0 ) {
275
+			DBGC ( sig, "CMS %p/%p could not append certificate: "
276
+			       "%s\n", sig, info, strerror ( rc ) );
277
+			return rc;
278
+		}
279
+		DBGC ( sig, "CMS %p/%p added certificate %s\n",
280
+		       sig, info, cert->subject.name );
281
+
282
+		/* Locate next certificate in chain, if any */
283
+		previous = cert;
284
+		cert = cms_find_subject ( sig, &cert->issuer.raw );
285
+
286
+	} while ( ( cert != NULL ) && ( cert != previous ) );
150
 
287
 
151
 	return 0;
288
 	return 0;
152
 }
289
 }
249
 	}
386
 	}
250
 
387
 
251
 	/* Record signature */
388
 	/* Record signature */
252
-	info->signature = cursor.data;
253
 	info->signature_len = cursor.len;
389
 	info->signature_len = cursor.len;
390
+	info->signature = malloc ( info->signature_len );
391
+	if ( ! info->signature )
392
+		return -ENOMEM;
393
+	memcpy ( info->signature, cursor.data, info->signature_len );
254
 	DBGC ( sig, "CMS %p/%p signature value is:\n", sig, info );
394
 	DBGC ( sig, "CMS %p/%p signature value is:\n", sig, info );
255
 	DBGC_HDA ( sig, 0, info->signature, info->signature_len );
395
 	DBGC_HDA ( sig, 0, info->signature, info->signature_len );
256
 
396
 
307
  * Parse CMS signature from ASN.1 data
447
  * Parse CMS signature from ASN.1 data
308
  *
448
  *
309
  * @v sig		CMS signature
449
  * @v sig		CMS signature
310
- * @v data		Raw signature data
311
- * @v len		Length of raw data
450
+ * @v raw		ASN.1 cursor
312
  * @ret rc		Return status code
451
  * @ret rc		Return status code
313
  */
452
  */
314
-int cms_parse ( struct cms_signature *sig, const void *data, size_t len ) {
453
+static int cms_parse ( struct cms_signature *sig,
454
+		       const struct asn1_cursor *raw ) {
315
 	struct asn1_cursor cursor;
455
 	struct asn1_cursor cursor;
456
+	struct cms_signer_info *info;
316
 	int rc;
457
 	int rc;
317
 
458
 
318
-	/* Initialise signature */
319
-	memset ( sig, 0, sizeof ( *sig ) );
320
-	cursor.data = data;
321
-	cursor.len = len;
322
-
323
 	/* Enter contentInfo */
459
 	/* Enter contentInfo */
460
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
324
 	asn1_enter ( &cursor, ASN1_SEQUENCE );
461
 	asn1_enter ( &cursor, ASN1_SEQUENCE );
325
 
462
 
326
 	/* Parse contentType */
463
 	/* Parse contentType */
464
+
327
 	if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 )
465
 	if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 )
328
 		return rc;
466
 		return rc;
329
 	asn1_skip_any ( &cursor );
467
 	asn1_skip_any ( &cursor );
343
 	/* Skip encapContentInfo */
481
 	/* Skip encapContentInfo */
344
 	asn1_skip ( &cursor, ASN1_SEQUENCE );
482
 	asn1_skip ( &cursor, ASN1_SEQUENCE );
345
 
483
 
346
-	/* Record certificates */
347
-	memcpy ( &sig->certificates, &cursor, sizeof ( sig->certificates ) );
348
-	if ( ( rc = asn1_enter ( &sig->certificates,
349
-				 ASN1_EXPLICIT_TAG ( 0 ) ) ) != 0 ) {
350
-		DBGC ( sig, "CMS %p could not locate certificates:\n", sig );
351
-		DBGC_HDA ( sig, 0, data, len );
484
+	/* Parse certificates */
485
+	if ( ( rc = cms_parse_certificates ( sig, &cursor ) ) != 0 )
352
 		return rc;
486
 		return rc;
353
-	}
354
 	asn1_skip_any ( &cursor );
487
 	asn1_skip_any ( &cursor );
355
 
488
 
356
 	/* Skip crls, if present */
489
 	/* Skip crls, if present */
359
 	/* Enter signerInfos */
492
 	/* Enter signerInfos */
360
 	asn1_enter ( &cursor, ASN1_SET );
493
 	asn1_enter ( &cursor, ASN1_SET );
361
 
494
 
362
-	/* Parse first signerInfo */
363
-	if ( ( rc = cms_parse_signer_info ( sig, &sig->info, &cursor ) ) != 0 )
364
-		return rc;
495
+	/* Add each signerInfo.  Errors are handled by ensuring that
496
+	 * cms_put() will always be able to free any allocated memory.
497
+	 */
498
+	while ( cursor.len ) {
499
+
500
+		/* Allocate signer information block */
501
+		info = zalloc ( sizeof ( *info ) );
502
+		if ( ! info )
503
+			return -ENOMEM;
504
+		list_add ( &info->list, &sig->info );
505
+
506
+		/* Allocate certificate chain */
507
+		info->chain = x509_alloc_chain();
508
+		if ( ! info->chain )
509
+			return -ENOMEM;
510
+
511
+		/* Parse signerInfo */
512
+		if ( ( rc = cms_parse_signer_info ( sig, info,
513
+						    &cursor ) ) != 0 )
514
+			return rc;
515
+		asn1_skip_any ( &cursor );
516
+	}
365
 
517
 
366
 	return 0;
518
 	return 0;
367
 }
519
 }
368
 
520
 
369
-/** CMS certificate chain context */
370
-struct cms_chain_context {
371
-	/** Signature */
372
-	struct cms_signature *sig;
373
-	/** Signer information */
521
+/**
522
+ * Free CMS signature
523
+ *
524
+ * @v refcnt		Reference count
525
+ */
526
+static void cms_free ( struct refcnt *refcnt ) {
527
+	struct cms_signature *sig =
528
+		container_of ( refcnt, struct cms_signature, refcnt );
374
 	struct cms_signer_info *info;
529
 	struct cms_signer_info *info;
375
-};
530
+	struct cms_signer_info *tmp;
531
+
532
+	list_for_each_entry_safe ( info, tmp, &sig->info, list ) {
533
+		list_del ( &info->list );
534
+		x509_chain_put ( info->chain );
535
+		free ( info->signature );
536
+		free ( info );
537
+	}
538
+	x509_chain_put ( sig->certificates );
539
+	free ( sig );
540
+}
376
 
541
 
377
 /**
542
 /**
378
- * Parse next certificate in chain
543
+ * Create CMS signature
379
  *
544
  *
380
- * @v cert		X.509 certificate to parse
381
- * @v previous		Previous X.509 certificate, or NULL
382
- * @v ctx		Chain context
545
+ * @v data		Raw signature data
546
+ * @v len		Length of raw data
547
+ * @ret sig		CMS signature
383
  * @ret rc		Return status code
548
  * @ret rc		Return status code
549
+ *
550
+ * On success, the caller holds a reference to the CMS signature, and
551
+ * is responsible for ultimately calling cms_put().
384
  */
552
  */
385
-static int cms_parse_next ( struct x509_certificate *cert,
386
-			    const struct x509_certificate *previous,
387
-			    void *ctx ) {
388
-	struct cms_chain_context *context = ctx;
389
-	struct cms_signature *sig = context->sig;
390
-	struct cms_signer_info *info = context->info;
553
+int cms_signature ( const void *data, size_t len, struct cms_signature **sig ) {
391
 	struct asn1_cursor cursor;
554
 	struct asn1_cursor cursor;
392
 	int rc;
555
 	int rc;
393
 
556
 
394
-	/* Search for relevant certificate */
395
-	memcpy ( &cursor, &sig->certificates, sizeof ( cursor ) );
396
-	while ( cursor.len ) {
557
+	/* Allocate and initialise signature */
558
+	*sig = zalloc ( sizeof ( **sig ) );
559
+	if ( ! *sig ) {
560
+		rc = -ENOMEM;
561
+		goto err_alloc;
562
+	}
563
+	ref_init ( &(*sig)->refcnt, cms_free );
564
+	INIT_LIST_HEAD ( &(*sig)->info );
565
+
566
+	/* Allocate certificate list */
567
+	(*sig)->certificates = x509_alloc_chain();
568
+	if ( ! (*sig)->certificates ) {
569
+		rc = -ENOMEM;
570
+		goto err_alloc_chain;
571
+	}
397
 
572
 
398
-		/* Parse certificate */
399
-		if ( ( rc = x509_parse ( cert, cursor.data,
400
-					 cursor.len ) ) != 0 ) {
401
-			DBGC ( sig, "CMS %p/%p could not parse certificate:\n",
402
-			       sig, info );
403
-			DBGC_HDA ( sig, 0, cursor.data, cursor.len );
404
-			return rc;
405
-		}
573
+	/* Initialise cursor */
574
+	cursor.data = data;
575
+	cursor.len = len;
576
+	asn1_shrink_any ( &cursor );
406
 
577
 
407
-		if ( previous == NULL ) {
408
-			/* First certificate: check issuer and serial
409
-			 * number against signer info
410
-			 */
411
-			if ( ( asn1_compare ( &info->issuer,
412
-					      &cert->issuer.raw ) == 0 ) &&
413
-			     ( asn1_compare ( &info->serial,
414
-					      &cert->serial.raw ) == 0 ) ) {
415
-				return 0;
416
-			}
417
-		} else {
418
-			/* Subsequent certificates: check subject
419
-			 * against previous certificate's issuer.
420
-			 */
421
-			if ( asn1_compare ( &previous->issuer.raw,
422
-					    &cert->subject.raw ) == 0 ) {
423
-				return 0;
424
-			}
425
-		}
578
+	/* Parse signature */
579
+	if ( ( rc = cms_parse ( *sig, &cursor ) ) != 0 )
580
+		goto err_parse;
426
 
581
 
427
-		/* Move to next certificate */
428
-		asn1_skip_any ( &cursor );
429
-	}
582
+	return 0;
430
 
583
 
431
-	DBGC ( sig, "CMS %p/%p reached end of certificate chain\n", sig, info );
432
-	return -EACCES_INCOMPLETE;
584
+ err_parse:
585
+ err_alloc_chain:
586
+	cms_put ( *sig );
587
+ err_alloc:
588
+	return rc;
433
 }
589
 }
434
 
590
 
435
 /**
591
 /**
525
  * @v info		Signer information
681
  * @v info		Signer information
526
  * @v data		Signed data
682
  * @v data		Signed data
527
  * @v len		Length of signed data
683
  * @v len		Length of signed data
528
- * @v name		Required common name, or NULL to allow any name
529
  * @v time		Time at which to validate certificates
684
  * @v time		Time at which to validate certificates
530
  * @v root		Root certificate store, or NULL to use default
685
  * @v root		Root certificate store, or NULL to use default
531
  * @ret rc		Return status code
686
  * @ret rc		Return status code
533
 static int cms_verify_signer_info ( struct cms_signature *sig,
688
 static int cms_verify_signer_info ( struct cms_signature *sig,
534
 				    struct cms_signer_info *info,
689
 				    struct cms_signer_info *info,
535
 				    userptr_t data, size_t len,
690
 				    userptr_t data, size_t len,
536
-				    const char *name, time_t time,
537
-				    struct x509_root *root ) {
538
-	struct cms_chain_context context;
539
-	struct x509_certificate cert;
691
+				    time_t time, struct x509_root *root ) {
692
+	struct x509_certificate *cert;
540
 	int rc;
693
 	int rc;
541
 
694
 
542
 	/* Validate certificate chain */
695
 	/* Validate certificate chain */
543
-	context.sig = sig;
544
-	context.info = info;
545
-	if ( ( rc = x509_validate_chain ( cms_parse_next, &context, time, root,
546
-					  &cert ) ) != 0 ) {
696
+	if ( ( rc = x509_validate_chain ( info->chain, time, root ) ) != 0 ) {
547
 		DBGC ( sig, "CMS %p/%p could not validate chain: %s\n",
697
 		DBGC ( sig, "CMS %p/%p could not validate chain: %s\n",
548
 		       sig, info, strerror ( rc ) );
698
 		       sig, info, strerror ( rc ) );
549
 		return rc;
699
 		return rc;
550
 	}
700
 	}
551
 
701
 
702
+	/* Extract code-signing certificate */
703
+	cert = x509_first ( info->chain );
704
+	assert ( cert != NULL );
705
+
552
 	/* Check that certificate can create digital signatures */
706
 	/* Check that certificate can create digital signatures */
553
-	if ( ! ( cert.extensions.usage.bits & X509_DIGITAL_SIGNATURE ) ) {
707
+	if ( ! ( cert->extensions.usage.bits & X509_DIGITAL_SIGNATURE ) ) {
554
 		DBGC ( sig, "CMS %p/%p certificate cannot create signatures\n",
708
 		DBGC ( sig, "CMS %p/%p certificate cannot create signatures\n",
555
 		       sig, info );
709
 		       sig, info );
556
 		return -EACCES_NON_SIGNING;
710
 		return -EACCES_NON_SIGNING;
557
 	}
711
 	}
558
 
712
 
559
 	/* Check that certificate can sign code */
713
 	/* Check that certificate can sign code */
560
-	if ( ! ( cert.extensions.ext_usage.bits & X509_CODE_SIGNING ) ) {
714
+	if ( ! ( cert->extensions.ext_usage.bits & X509_CODE_SIGNING ) ) {
561
 		DBGC ( sig, "CMS %p/%p certificate is not code-signing\n",
715
 		DBGC ( sig, "CMS %p/%p certificate is not code-signing\n",
562
 		       sig, info );
716
 		       sig, info );
563
 		return -EACCES_NON_CODE_SIGNING;
717
 		return -EACCES_NON_CODE_SIGNING;
564
 	}
718
 	}
565
 
719
 
566
-	/* Check certificate name, if applicable */
567
-	if ( ( name != NULL ) &&
568
-	     ( ( cert.subject.name.len != strlen ( name ) ) ||
569
-	       ( memcmp ( cert.subject.name.data, name,
570
-			  cert.subject.name.len ) != 0 ) ) ) {
571
-		DBGC ( sig, "CMS %p/%p certificate name incorrect\n",
572
-		       sig, info );
573
-		return -EACCES_WRONG_NAME;
574
-	}
575
-
576
 	/* Verify digest */
720
 	/* Verify digest */
577
-	if ( ( rc = cms_verify_digest ( sig, info, &cert, data, len ) ) != 0 )
721
+	if ( ( rc = cms_verify_digest ( sig, info, cert, data, len ) ) != 0 )
578
 		return rc;
722
 		return rc;
579
 
723
 
580
 	return 0;
724
 	return 0;
586
  * @v sig		CMS signature
730
  * @v sig		CMS signature
587
  * @v data		Signed data
731
  * @v data		Signed data
588
  * @v len		Length of signed data
732
  * @v len		Length of signed data
589
- * @v name		Required common name, or NULL to allow any name
733
+ * @v name		Required common name, or NULL to check all signatures
590
  * @v time		Time at which to validate certificates
734
  * @v time		Time at which to validate certificates
591
  * @v root		Root certificate store, or NULL to use default
735
  * @v root		Root certificate store, or NULL to use default
592
  * @ret rc		Return status code
736
  * @ret rc		Return status code
593
  */
737
  */
594
 int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
738
 int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
595
 		 const char *name, time_t time, struct x509_root *root ) {
739
 		 const char *name, time_t time, struct x509_root *root ) {
740
+	struct cms_signer_info *info;
741
+	struct x509_certificate *cert;
742
+	int count = 0;
596
 	int rc;
743
 	int rc;
597
 
744
 
598
-	/* Verify using first signerInfo */
599
-	if ( ( rc = cms_verify_signer_info ( sig, &sig->info, data, len,
600
-					     name, time, root ) ) != 0 )
601
-		return rc;
745
+	/* Verify using all signerInfos */
746
+	list_for_each_entry ( info, &sig->info, list ) {
747
+		cert = x509_first ( info->chain );
748
+		if ( name && ( strcmp ( name, cert->subject.name ) != 0 ) )
749
+			continue;
750
+		if ( ( rc = cms_verify_signer_info ( sig, info, data, len,
751
+						     time, root ) ) != 0 )
752
+			return rc;
753
+		count++;
754
+	}
755
+
756
+	/* Check that we have verified at least one signature */
757
+	if ( count == 0 ) {
758
+		if ( name ) {
759
+			DBGC ( sig, "CMS %p had no signatures matching name "
760
+			       "%s\n", sig, name );
761
+			return -EACCES_WRONG_NAME;
762
+		} else {
763
+			DBGC ( sig, "CMS %p had no signatures\n", sig );
764
+			return -EACCES_NO_SIGNATURES;
765
+		}
766
+	}
602
 
767
 
603
 	return 0;
768
 	return 0;
604
 }
769
 }

+ 362
- 116
src/crypto/x509.c View File

18
 
18
 
19
 FILE_LICENCE ( GPL2_OR_LATER );
19
 FILE_LICENCE ( GPL2_OR_LATER );
20
 
20
 
21
+#include <stdlib.h>
21
 #include <string.h>
22
 #include <string.h>
22
 #include <ctype.h>
23
 #include <ctype.h>
23
 #include <time.h>
24
 #include <time.h>
24
 #include <errno.h>
25
 #include <errno.h>
25
 #include <assert.h>
26
 #include <assert.h>
27
+#include <ipxe/list.h>
28
+#include <ipxe/malloc.h>
26
 #include <ipxe/asn1.h>
29
 #include <ipxe/asn1.h>
27
 #include <ipxe/crypto.h>
30
 #include <ipxe/crypto.h>
28
 #include <ipxe/md5.h>
31
 #include <ipxe/md5.h>
97
 	__einfo_error ( EINFO_EACCES_UNTRUSTED )
100
 	__einfo_error ( EINFO_EACCES_UNTRUSTED )
98
 #define EINFO_EACCES_UNTRUSTED \
101
 #define EINFO_EACCES_UNTRUSTED \
99
 	__einfo_uniqify ( EINFO_EACCES, 0x06, "Untrusted root certificate" )
102
 	__einfo_uniqify ( EINFO_EACCES, 0x06, "Untrusted root certificate" )
103
+#define EACCES_OUT_OF_ORDER \
104
+	__einfo_error ( EINFO_EACCES_OUT_OF_ORDER )
105
+#define EINFO_EACCES_OUT_OF_ORDER \
106
+	__einfo_uniqify ( EINFO_EACCES, 0x07, "Validation out of order" )
107
+#define EACCES_EMPTY \
108
+	__einfo_error ( EINFO_EACCES_EMPTY )
109
+#define EINFO_EACCES_EMPTY \
110
+	__einfo_uniqify ( EINFO_EACCES, 0x08, "Empty certificate chain" )
111
+
112
+/** Certificate cache */
113
+static LIST_HEAD ( x509_cache );
114
+
115
+/**
116
+ * Free X.509 certificate
117
+ *
118
+ * @v refcnt		Reference count
119
+ */
120
+static void x509_free ( struct refcnt *refcnt ) {
121
+	struct x509_certificate *cert =
122
+		container_of ( refcnt, struct x509_certificate, refcnt );
123
+
124
+	DBGC ( cert, "X509 %p freed\n", cert );
125
+	free ( cert->subject.name );
126
+	free ( cert->extensions.auth_info.ocsp.uri );
127
+	free ( cert );
128
+}
129
+
130
+/**
131
+ * Discard a cached certificate
132
+ *
133
+ * @ret discarded	Number of cached items discarded
134
+ */
135
+static unsigned int x509_discard ( void ) {
136
+	struct x509_certificate *cert;
137
+
138
+	/* Discard the least recently used certificate for which the
139
+	 * only reference is held by the cache itself.
140
+	 */
141
+	list_for_each_entry_reverse ( cert, &x509_cache, list ) {
142
+		if ( cert->refcnt.count == 0 ) {
143
+			list_del ( &cert->list );
144
+			x509_put ( cert );
145
+			return 1;
146
+		}
147
+	}
148
+	return 0;
149
+}
150
+
151
+/** X.509 cache discarder */
152
+struct cache_discarder x509_cache_discarder __cache_discarder = {
153
+	.discard = x509_discard,
154
+};
100
 
155
 
101
 /** "commonName" object identifier */
156
 /** "commonName" object identifier */
102
 static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME };
157
 static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME };
113
  * @v raw		ASN.1 cursor
168
  * @v raw		ASN.1 cursor
114
  * @ret rc		Return status code
169
  * @ret rc		Return status code
115
  */
170
  */
116
-int x509_parse_pubkey_algorithm ( struct x509_certificate *cert,
117
-				  struct asn1_algorithm **algorithm,
118
-				  const struct asn1_cursor *raw ) {
171
+static int x509_parse_pubkey_algorithm ( struct x509_certificate *cert,
172
+					 struct asn1_algorithm **algorithm,
173
+					 const struct asn1_cursor *raw ) {
119
 
174
 
120
 	/* Parse algorithm */
175
 	/* Parse algorithm */
121
 	*algorithm = asn1_algorithm ( raw );
176
 	*algorithm = asn1_algorithm ( raw );
486
  * @v raw		ASN.1 cursor
541
  * @v raw		ASN.1 cursor
487
  * @ret rc		Return status code
542
  * @ret rc		Return status code
488
  */
543
  */
489
-static int x509_parse_common_name ( struct x509_certificate *cert,
490
-				    struct x509_string *name,
544
+static int x509_parse_common_name ( struct x509_certificate *cert, char **name,
491
 				    const struct asn1_cursor *raw ) {
545
 				    const struct asn1_cursor *raw ) {
492
 	struct asn1_cursor cursor;
546
 	struct asn1_cursor cursor;
493
 	struct asn1_cursor oid_cursor;
547
 	struct asn1_cursor oid_cursor;
500
 
554
 
501
 	/* Scan through name list */
555
 	/* Scan through name list */
502
 	for ( ; cursor.len ; asn1_skip_any ( &cursor ) ) {
556
 	for ( ; cursor.len ; asn1_skip_any ( &cursor ) ) {
557
+
558
+		/* Check for "commonName" OID */
503
 		memcpy ( &oid_cursor, &cursor, sizeof ( oid_cursor ) );
559
 		memcpy ( &oid_cursor, &cursor, sizeof ( oid_cursor ) );
504
 		asn1_enter ( &oid_cursor, ASN1_SET );
560
 		asn1_enter ( &oid_cursor, ASN1_SET );
505
 		asn1_enter ( &oid_cursor, ASN1_SEQUENCE );
561
 		asn1_enter ( &oid_cursor, ASN1_SEQUENCE );
513
 			DBGC_HDA ( cert, 0, raw->data, raw->len );
569
 			DBGC_HDA ( cert, 0, raw->data, raw->len );
514
 			return rc;
570
 			return rc;
515
 		}
571
 		}
516
-		name->data = name_cursor.data;
517
-		name->len = name_cursor.len;
572
+
573
+		/* Allocate name */
574
+		*name = zalloc ( name_cursor.len + 1 /* NUL */ );
575
+		if ( ! *name )
576
+			return -ENOMEM;
577
+		memcpy ( *name, name_cursor.data, name_cursor.len );
518
 		return 0;
578
 		return 0;
519
 	}
579
 	}
520
 
580
 
533
 static int x509_parse_subject ( struct x509_certificate *cert,
593
 static int x509_parse_subject ( struct x509_certificate *cert,
534
 				const struct asn1_cursor *raw ) {
594
 				const struct asn1_cursor *raw ) {
535
 	struct x509_subject *subject = &cert->subject;
595
 	struct x509_subject *subject = &cert->subject;
536
-	struct x509_string *name = &subject->name;
596
+	char **name = &subject->name;
537
 	int rc;
597
 	int rc;
538
 
598
 
539
 	/* Record raw subject */
599
 	/* Record raw subject */
545
 	/* Parse common name */
605
 	/* Parse common name */
546
 	if ( ( rc = x509_parse_common_name ( cert, name, raw ) ) != 0 )
606
 	if ( ( rc = x509_parse_common_name ( cert, name, raw ) ) != 0 )
547
 		return rc;
607
 		return rc;
548
-	DBGC ( cert, "X509 %p common name is:\n", cert );
549
-	DBGC_HDA ( cert, 0, name->data, name->len );
608
+	DBGC ( cert, "X509 %p common name is \"%s\":\n", cert, *name );
550
 
609
 
551
 	return 0;
610
 	return 0;
552
 }
611
 }
625
 		return 0;
684
 		return 0;
626
 
685
 
627
 	/* Parse "pathLenConstraint", if present and applicable */
686
 	/* Parse "pathLenConstraint", if present and applicable */
628
-	basic->path_len = -1U; /* Default is unlimited */
687
+	basic->path_len = X509_PATH_LEN_UNLIMITED;
629
 	if ( asn1_type ( &cursor ) == ASN1_INTEGER ) {
688
 	if ( asn1_type ( &cursor ) == ASN1_INTEGER ) {
630
 		if ( ( rc = asn1_integer ( &cursor, &path_len ) ) != 0 ) {
689
 		if ( ( rc = asn1_integer ( &cursor, &path_len ) ) != 0 ) {
631
 			DBGC ( cert, "X509 %p cannot parse pathLenConstraint: "
690
 			DBGC ( cert, "X509 %p cannot parse pathLenConstraint: "
783
 	}
842
 	}
784
 
843
 
785
 	/* Record URI */
844
 	/* Record URI */
786
-	ocsp->uri.data = cursor.data;
787
-	ocsp->uri.len = cursor.len;
788
-	DBGC ( cert, "X509 %p OCSP URI is:\n", cert );
789
-	DBGC_HDA ( cert, 0, ocsp->uri.data, ocsp->uri.len );
845
+	ocsp->uri = zalloc ( cursor.len + 1 /* NUL */ );
846
+	if ( ! ocsp->uri )
847
+		return -ENOMEM;
848
+	memcpy ( ocsp->uri, cursor.data, cursor.len );
849
+	DBGC ( cert, "X509 %p OCSP URI is %s:\n", cert, ocsp->uri );
790
 
850
 
791
 	return 0;
851
 	return 0;
792
 }
852
 }
1112
  * Parse X.509 certificate from ASN.1 data
1172
  * Parse X.509 certificate from ASN.1 data
1113
  *
1173
  *
1114
  * @v cert		X.509 certificate
1174
  * @v cert		X.509 certificate
1115
- * @v data		Raw certificate data
1116
- * @v len		Length of raw data
1175
+ * @v raw		ASN.1 cursor
1117
  * @ret rc		Return status code
1176
  * @ret rc		Return status code
1118
  */
1177
  */
1119
-int x509_parse ( struct x509_certificate *cert, const void *data, size_t len ) {
1178
+static int x509_parse ( struct x509_certificate *cert,
1179
+			const struct asn1_cursor *raw ) {
1120
 	struct x509_signature *signature = &cert->signature;
1180
 	struct x509_signature *signature = &cert->signature;
1121
 	struct asn1_algorithm **signature_algorithm = &signature->algorithm;
1181
 	struct asn1_algorithm **signature_algorithm = &signature->algorithm;
1122
 	struct x509_bit_string *signature_value = &signature->value;
1182
 	struct x509_bit_string *signature_value = &signature->value;
1123
 	struct asn1_cursor cursor;
1183
 	struct asn1_cursor cursor;
1124
 	int rc;
1184
 	int rc;
1125
 
1185
 
1126
-	/* Initialise certificate */
1127
-	memset ( cert, 0, sizeof ( *cert ) );
1128
-	cert->raw.data = data;
1129
-	cert->raw.len = len;
1130
-	asn1_shrink_any ( &cert->raw );
1186
+	/* Record raw certificate */
1187
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
1188
+	memcpy ( &cert->raw, &cursor, sizeof ( cert->raw ) );
1131
 
1189
 
1132
 	/* Enter certificate */
1190
 	/* Enter certificate */
1133
-	memcpy ( &cursor, &cert->raw, sizeof ( cursor ) );
1134
 	asn1_enter ( &cursor, ASN1_SEQUENCE );
1191
 	asn1_enter ( &cursor, ASN1_SEQUENCE );
1135
 
1192
 
1136
 	/* Parse tbsCertificate */
1193
 	/* Parse tbsCertificate */
1168
 }
1225
 }
1169
 
1226
 
1170
 /**
1227
 /**
1171
- * Verify X.509 certificate signature
1228
+ * Create X.509 certificate
1229
+ *
1230
+ * @v data		Raw certificate data
1231
+ * @v len		Length of raw data
1232
+ * @ret cert		X.509 certificate
1233
+ * @ret rc		Return status code
1234
+ *
1235
+ * On success, the caller holds a reference to the X.509 certificate,
1236
+ * and is responsible for ultimately calling x509_put().
1237
+ */
1238
+int x509_certificate ( const void *data, size_t len,
1239
+		       struct x509_certificate **cert ) {
1240
+	struct asn1_cursor cursor;
1241
+	void *raw;
1242
+	int rc;
1243
+
1244
+	/* Initialise cursor */
1245
+	cursor.data = data;
1246
+	cursor.len = len;
1247
+	asn1_shrink_any ( &cursor );
1248
+
1249
+	/* Search for certificate within cache */
1250
+	list_for_each_entry ( (*cert), &x509_cache, list ) {
1251
+		if ( asn1_compare ( &cursor, &(*cert)->raw ) == 0 ) {
1252
+
1253
+			DBGC ( *cert, "X509 %p \"%s\" cache hit\n",
1254
+			       *cert, (*cert)->subject.name );
1255
+
1256
+			/* Mark as most recently used */
1257
+			list_del ( &(*cert)->list );
1258
+			list_add ( &(*cert)->list, &x509_cache );
1259
+
1260
+			/* Add caller's reference */
1261
+			x509_get ( *cert );
1262
+
1263
+			return 0;
1264
+		}
1265
+	}
1266
+
1267
+	/* Allocate and initialise certificate */
1268
+	*cert = zalloc ( sizeof ( **cert ) + cursor.len );
1269
+	if ( ! *cert )
1270
+		return -ENOMEM;
1271
+	ref_init ( &(*cert)->refcnt, x509_free );
1272
+	INIT_LIST_HEAD ( &(*cert)->list );
1273
+	raw = ( *cert + 1 );
1274
+
1275
+	/* Copy raw data */
1276
+	memcpy ( raw, cursor.data, cursor.len );
1277
+	cursor.data = raw;
1278
+
1279
+	/* Parse certificate */
1280
+	if ( ( rc = x509_parse ( *cert, &cursor ) ) != 0 ) {
1281
+		x509_put ( *cert );
1282
+		return rc;
1283
+	}
1284
+
1285
+	/* Add certificate to cache */
1286
+	x509_get ( *cert );
1287
+	list_add ( &(*cert)->list, &x509_cache );
1288
+
1289
+	return 0;
1290
+}
1291
+
1292
+/**
1293
+ * Check X.509 certificate signature
1172
  *
1294
  *
1173
  * @v cert		X.509 certificate
1295
  * @v cert		X.509 certificate
1174
  * @v public_key	X.509 public key
1296
  * @v public_key	X.509 public key
1192
 	digest_init ( digest, digest_ctx );
1314
 	digest_init ( digest, digest_ctx );
1193
 	digest_update ( digest, digest_ctx, cert->tbs.data, cert->tbs.len );
1315
 	digest_update ( digest, digest_ctx, cert->tbs.data, cert->tbs.len );
1194
 	digest_final ( digest, digest_ctx, digest_out );
1316
 	digest_final ( digest, digest_ctx, digest_out );
1195
-	DBGC ( cert, "X509 %p digest:\n", cert );
1317
+	DBGC ( cert, "X509 %p \"%s\" digest:\n", cert, cert->subject.name );
1196
 	DBGC_HDA ( cert, 0, digest_out, sizeof ( digest_out ) );
1318
 	DBGC_HDA ( cert, 0, digest_out, sizeof ( digest_out ) );
1197
 
1319
 
1198
 	/* Check that signature public key algorithm matches signer */
1320
 	/* Check that signature public key algorithm matches signer */
1199
 	if ( public_key->algorithm->pubkey != pubkey ) {
1321
 	if ( public_key->algorithm->pubkey != pubkey ) {
1200
-		DBGC ( cert, "X509 %p signature algorithm %s does not match "
1201
-		       "signer's algorithm %s\n",
1202
-		       cert, algorithm->name, public_key->algorithm->name );
1322
+		DBGC ( cert, "X509 %p \"%s\" signature algorithm %s does not "
1323
+		       "match signer's algorithm %s\n",
1324
+		       cert, cert->subject.name, algorithm->name,
1325
+		       public_key->algorithm->name );
1203
 		rc = -EINVAL_ALGORITHM_MISMATCH;
1326
 		rc = -EINVAL_ALGORITHM_MISMATCH;
1204
 		goto err_mismatch;
1327
 		goto err_mismatch;
1205
 	}
1328
 	}
1207
 	/* Verify signature using signer's public key */
1330
 	/* Verify signature using signer's public key */
1208
 	if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data,
1331
 	if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data,
1209
 				  public_key->raw.len ) ) != 0 ) {
1332
 				  public_key->raw.len ) ) != 0 ) {
1210
-		DBGC ( cert, "X509 %p cannot initialise public key: %s\n",
1211
-		       cert, strerror ( rc ) );
1333
+		DBGC ( cert, "X509 %p \"%s\" cannot initialise public key: "
1334
+		       "%s\n", cert, cert->subject.name, strerror ( rc ) );
1212
 		goto err_pubkey_init;
1335
 		goto err_pubkey_init;
1213
 	}
1336
 	}
1214
 	if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out,
1337
 	if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out,
1215
 				    signature->value.data,
1338
 				    signature->value.data,
1216
 				    signature->value.len ) ) != 0 ) {
1339
 				    signature->value.len ) ) != 0 ) {
1217
-		DBGC ( cert, "X509 %p signature verification failed: %s\n",
1218
-		       cert, strerror ( rc ) );
1340
+		DBGC ( cert, "X509 %p \"%s\" signature verification failed: "
1341
+		       "%s\n", cert, cert->subject.name, strerror ( rc ) );
1219
 		goto err_pubkey_verify;
1342
 		goto err_pubkey_verify;
1220
 	}
1343
 	}
1221
 
1344
 
1230
 }
1353
 }
1231
 
1354
 
1232
 /**
1355
 /**
1233
- * Validate X.509 certificate against issuer certificate
1356
+ * Check X.509 certificate against issuer certificate
1234
  *
1357
  *
1235
  * @v cert		X.509 certificate
1358
  * @v cert		X.509 certificate
1236
  * @v issuer		X.509 issuer certificate
1359
  * @v issuer		X.509 issuer certificate
1237
  * @ret rc		Return status code
1360
  * @ret rc		Return status code
1238
  */
1361
  */
1239
-int x509_validate_issuer ( struct x509_certificate *cert,
1240
-			   struct x509_certificate *issuer ) {
1362
+int x509_check_issuer ( struct x509_certificate *cert,
1363
+			struct x509_certificate *issuer ) {
1241
 	struct x509_public_key *public_key = &issuer->subject.public_key;
1364
 	struct x509_public_key *public_key = &issuer->subject.public_key;
1242
 	int rc;
1365
 	int rc;
1243
 
1366
 
1254
 	 * for some enjoyable ranting on this subject.
1377
 	 * for some enjoyable ranting on this subject.
1255
 	 */
1378
 	 */
1256
 	if ( asn1_compare ( &cert->issuer.raw, &issuer->subject.raw ) != 0 ) {
1379
 	if ( asn1_compare ( &cert->issuer.raw, &issuer->subject.raw ) != 0 ) {
1257
-		DBGC ( cert, "X509 %p issuer does not match X509 %p subject\n",
1258
-		       cert, issuer );
1380
+		DBGC ( cert, "X509 %p \"%s\" issuer does not match X509 %p "
1381
+		       "\"%s\" subject\n", cert, cert->subject.name,
1382
+		       issuer, issuer->subject.name );
1259
 		DBGC_HDA ( cert, 0, cert->issuer.raw.data,
1383
 		DBGC_HDA ( cert, 0, cert->issuer.raw.data,
1260
 			   cert->issuer.raw.len );
1384
 			   cert->issuer.raw.len );
1261
 		DBGC_HDA ( issuer, 0, issuer->subject.raw.data,
1385
 		DBGC_HDA ( issuer, 0, issuer->subject.raw.data,
1265
 
1389
 
1266
 	/* Check that issuer is allowed to sign certificates */
1390
 	/* Check that issuer is allowed to sign certificates */
1267
 	if ( ! issuer->extensions.basic.ca ) {
1391
 	if ( ! issuer->extensions.basic.ca ) {
1268
-		DBGC ( issuer, "X509 %p cannot sign X509 %p: not a CA "
1269
-		       "certificate\n", issuer, cert );
1392
+		DBGC ( issuer, "X509 %p \"%s\" cannot sign X509 %p \"%s\": "
1393
+		       "not a CA certificate\n", issuer, issuer->subject.name,
1394
+		       cert, cert->subject.name );
1270
 		return -EACCES_NOT_CA;
1395
 		return -EACCES_NOT_CA;
1271
 	}
1396
 	}
1272
 	if ( issuer->extensions.usage.present &&
1397
 	if ( issuer->extensions.usage.present &&
1273
 	     ( ! ( issuer->extensions.usage.bits & X509_KEY_CERT_SIGN ) ) ) {
1398
 	     ( ! ( issuer->extensions.usage.bits & X509_KEY_CERT_SIGN ) ) ) {
1274
-		DBGC ( issuer, "X509 %p cannot sign X509 %p: no keyCertSign "
1275
-		       "usage\n", issuer, cert );
1399
+		DBGC ( issuer, "X509 %p \"%s\" cannot sign X509 %p \"%s\": "
1400
+		       "no keyCertSign usage\n", issuer, issuer->subject.name,
1401
+		       cert, cert->subject.name );
1276
 		return -EACCES_KEY_USAGE;
1402
 		return -EACCES_KEY_USAGE;
1277
 	}
1403
 	}
1278
 
1404
 
1280
 	if ( ( rc = x509_check_signature ( cert, public_key ) ) != 0 )
1406
 	if ( ( rc = x509_check_signature ( cert, public_key ) ) != 0 )
1281
 		return rc;
1407
 		return rc;
1282
 
1408
 
1283
-	DBGC ( cert, "X509 %p successfully validated using X509 %p\n",
1284
-	       cert, issuer );
1285
 	return 0;
1409
 	return 0;
1286
 }
1410
 }
1287
 
1411
 
1293
  * @v fingerprint	Fingerprint buffer
1417
  * @v fingerprint	Fingerprint buffer
1294
  */
1418
  */
1295
 void x509_fingerprint ( struct x509_certificate *cert,
1419
 void x509_fingerprint ( struct x509_certificate *cert,
1296
-			struct digest_algorithm *digest, void *fingerprint ) {
1420
+			struct digest_algorithm *digest,
1421
+			void *fingerprint ) {
1297
 	uint8_t ctx[ digest->ctxsize ];
1422
 	uint8_t ctx[ digest->ctxsize ];
1298
 
1423
 
1299
 	/* Calculate fingerprint */
1424
 	/* Calculate fingerprint */
1303
 }
1428
 }
1304
 
1429
 
1305
 /**
1430
 /**
1306
- * Validate X.509 root certificate
1431
+ * Check X.509 root certificate
1307
  *
1432
  *
1308
  * @v cert		X.509 certificate
1433
  * @v cert		X.509 certificate
1309
  * @v root		X.509 root certificate store
1434
  * @v root		X.509 root certificate store
1310
  * @ret rc		Return status code
1435
  * @ret rc		Return status code
1311
  */
1436
  */
1312
-int x509_validate_root ( struct x509_certificate *cert,
1313
-			 struct x509_root *root ) {
1437
+int x509_check_root ( struct x509_certificate *cert, struct x509_root *root ) {
1314
 	struct digest_algorithm *digest = root->digest;
1438
 	struct digest_algorithm *digest = root->digest;
1315
 	uint8_t fingerprint[ digest->digestsize ];
1439
 	uint8_t fingerprint[ digest->digestsize ];
1316
 	const uint8_t *root_fingerprint = root->fingerprints;
1440
 	const uint8_t *root_fingerprint = root->fingerprints;
1323
 	for ( i = 0 ; i < root->count ; i++ ) {
1447
 	for ( i = 0 ; i < root->count ; i++ ) {
1324
 		if ( memcmp ( fingerprint, root_fingerprint,
1448
 		if ( memcmp ( fingerprint, root_fingerprint,
1325
 			      sizeof ( fingerprint ) ) == 0 ) {
1449
 			      sizeof ( fingerprint ) ) == 0 ) {
1326
-			DBGC ( cert, "X509 %p is a root certificate\n", cert );
1450
+			DBGC ( cert, "X509 %p \"%s\" is a root certificate\n",
1451
+			       cert, cert->subject.name );
1327
 			return 0;
1452
 			return 0;
1328
 		}
1453
 		}
1329
 		root_fingerprint += sizeof ( fingerprint );
1454
 		root_fingerprint += sizeof ( fingerprint );
1330
 	}
1455
 	}
1331
 
1456
 
1332
-	DBGC ( cert, "X509 %p is not a root certificate\n", cert );
1457
+	DBGC ( cert, "X509 %p \"%s\" is not a root certificate\n",
1458
+	       cert, cert->subject.name );
1333
 	return -ENOENT;
1459
 	return -ENOENT;
1334
 }
1460
 }
1335
 
1461
 
1336
 /**
1462
 /**
1337
- * Validate X.509 certificate validity period
1463
+ * Check X.509 certificate validity period
1338
  *
1464
  *
1339
  * @v cert		X.509 certificate
1465
  * @v cert		X.509 certificate
1340
- * @v time		Time at which to validate certificate
1466
+ * @v time		Time at which to check certificate
1341
  * @ret rc		Return status code
1467
  * @ret rc		Return status code
1342
  */
1468
  */
1343
-int x509_validate_time ( struct x509_certificate *cert, time_t time ) {
1469
+int x509_check_time ( struct x509_certificate *cert, time_t time ) {
1344
 	struct x509_validity *validity = &cert->validity;
1470
 	struct x509_validity *validity = &cert->validity;
1345
 
1471
 
1346
 	/* Check validity period */
1472
 	/* Check validity period */
1347
 	if ( time < validity->not_before.time ) {
1473
 	if ( time < validity->not_before.time ) {
1348
-		DBGC ( cert, "X509 %p is not yet valid (at time %lld)\n",
1349
-		       cert, time );
1474
+		DBGC ( cert, "X509 %p \"%s\" is not yet valid (at time %lld)\n",
1475
+		       cert, cert->subject.name, time );
1350
 		return -EACCES_EXPIRED;
1476
 		return -EACCES_EXPIRED;
1351
 	}
1477
 	}
1352
 	if ( time > validity->not_after.time ) {
1478
 	if ( time > validity->not_after.time ) {
1353
-		DBGC ( cert, "X509 %p has expired (at time %lld)\n",
1354
-		       cert, time );
1479
+		DBGC ( cert, "X509 %p \"%s\" has expired (at time %lld)\n",
1480
+		       cert, cert->subject.name, time );
1355
 		return -EACCES_EXPIRED;
1481
 		return -EACCES_EXPIRED;
1356
 	}
1482
 	}
1357
 
1483
 
1358
-	DBGC ( cert, "X509 %p is valid (at time %lld)\n", cert, time );
1484
+	DBGC ( cert, "X509 %p \"%s\" is valid (at time %lld)\n",
1485
+	       cert, cert->subject.name, time );
1359
 	return 0;
1486
 	return 0;
1360
 }
1487
 }
1361
 
1488
 
1362
 /**
1489
 /**
1363
- * Validate X.509 certificate chain
1490
+ * Validate X.509 certificate
1364
  *
1491
  *
1365
- * @v parse_next	Parse next X.509 certificate in chain
1366
- * @v context		Context for parse_next()
1367
- * @v time		Time at which to validate certificates
1492
+ * @v cert		X.509 certificate
1493
+ * @v issuer		Issuing X.509 certificate (or NULL)
1494
+ * @v time		Time at which to validate certificate
1368
  * @v root		Root certificate store, or NULL to use default
1495
  * @v root		Root certificate store, or NULL to use default
1369
- * @v first		Initial X.509 certificate to fill in, or NULL
1370
  * @ret rc		Return status code
1496
  * @ret rc		Return status code
1497
+ *
1498
+ * The issuing certificate must have already been validated.
1499
+ *
1500
+ * Validation results are cached: if a certificate has already been
1501
+ * successfully validated then @c issuer, @c time, and @c root will be
1502
+ * ignored.
1371
  */
1503
  */
1372
-int x509_validate_chain ( int ( * parse_next )
1373
-			  ( struct x509_certificate *cert,
1374
-			    const struct x509_certificate *previous,
1375
-			    void *context ),
1376
-			  void *context, time_t time, struct x509_root *root,
1377
-			  struct x509_certificate *first ) {
1378
-	struct x509_certificate temp[2];
1379
-	struct x509_certificate *current = &temp[0];
1380
-	struct x509_certificate *next = &temp[1];
1381
-	struct x509_certificate *swap;
1382
-	unsigned int path_len = 0;
1504
+static int x509_validate ( struct x509_certificate *cert,
1505
+			   struct x509_certificate *issuer,
1506
+			   time_t time, struct x509_root *root ) {
1507
+	unsigned int max_path_remaining;
1383
 	int rc;
1508
 	int rc;
1384
 
1509
 
1385
 	/* Use default root certificate store if none specified */
1510
 	/* Use default root certificate store if none specified */
1386
 	if ( ! root )
1511
 	if ( ! root )
1387
 		root = &root_certificates;
1512
 		root = &root_certificates;
1388
 
1513
 
1389
-	/* Get first certificate in chain */
1390
-	if ( ( rc = parse_next ( current, NULL, context ) ) != 0 ) {
1391
-		DBGC ( context, "X509 chain %p could not get first "
1392
-		       "certificate: %s\n", context, strerror ( rc ) );
1514
+	/* Return success if certificate has already been validated */
1515
+	if ( cert->valid )
1516
+		return 0;
1517
+
1518
+	/* Fail if certificate is invalid at specified time */
1519
+	if ( ( rc = x509_check_time ( cert, time ) ) != 0 )
1393
 		return rc;
1520
 		return rc;
1521
+
1522
+	/* Succeed if certificate is a trusted root certificate */
1523
+	if ( x509_check_root ( cert, root ) == 0 ) {
1524
+		cert->valid = 1;
1525
+		cert->path_remaining = ( cert->extensions.basic.path_len + 1 );
1526
+		return 0;
1394
 	}
1527
 	}
1395
 
1528
 
1396
-	/* Record first certificate, if applicable */
1397
-	if ( first )
1398
-		memcpy ( first, current, sizeof ( *first ) );
1529
+	/* Fail unless we have an issuer */
1530
+	if ( ! issuer ) {
1531
+		DBGC ( cert, "X509 %p \"%s\" has no issuer\n",
1532
+		       cert, cert->subject.name );
1533
+		return -EACCES_UNTRUSTED;
1534
+	}
1399
 
1535
 
1400
-	/* Process chain */
1401
-	while ( 1 ) {
1536
+	/* Fail unless issuer has already been validated */
1537
+	if ( ! issuer->valid ) {
1538
+		DBGC ( cert, "X509 %p \"%s\" issuer %p \"%s\" has not yet "
1539
+		       "been validated\n", cert, cert->subject.name,
1540
+		       issuer, issuer->subject.name );
1541
+		return -EACCES_OUT_OF_ORDER;
1542
+	}
1402
 
1543
 
1403
-		/* Check that certificate is valid at specified time */
1404
-		if ( ( rc = x509_validate_time ( current, time ) ) != 0 )
1405
-			return rc;
1544
+	/* Fail if issuing certificate cannot validate this certificate */
1545
+	if ( ( rc = x509_check_issuer ( cert, issuer ) ) != 0 )
1546
+		return rc;
1406
 
1547
 
1407
-		/* Succeed if we have reached a trusted root certificate */
1408
-		if ( x509_validate_root ( current, root ) == 0 )
1409
-			return 0;
1548
+	/* Fail if path length constraint is violated */
1549
+	if ( issuer->path_remaining == 0 ) {
1550
+		DBGC ( cert, "X509 %p \"%s\" issuer %p \"%s\" path length "
1551
+		       "exceeded\n", cert, cert->subject.name,
1552
+		       issuer, issuer->subject.name );
1553
+		return -EACCES_PATH_LEN;
1554
+	}
1410
 
1555
 
1411
-		/* Fail if we have reached an untrusted root certificate */
1412
-		if ( asn1_compare ( &current->issuer.raw,
1413
-				    &current->subject.raw ) == 0 ) {
1414
-			DBGC ( context, "X509 chain %p reached untrusted root "
1415
-			       "certificate\n", context );
1416
-			return -EACCES_UNTRUSTED;
1417
-		}
1556
+	/* Calculate effective path length */
1557
+	cert->path_remaining = ( issuer->path_remaining - 1 );
1558
+	max_path_remaining = ( cert->extensions.basic.path_len + 1 );
1559
+	if ( cert->path_remaining > max_path_remaining )
1560
+		cert->path_remaining = max_path_remaining;
1418
 
1561
 
1419
-		/* Get next certificate in chain */
1420
-		if ( ( rc = parse_next ( next, current, context ) ) != 0 ) {
1421
-			DBGC ( context, "X509 chain %p could not get next "
1422
-			       "certificate: %s\n", context, strerror ( rc ) );
1423
-			return rc;
1424
-		}
1562
+	/* Mark certificate as valid */
1563
+	cert->valid = 1;
1425
 
1564
 
1426
-		/* Validate current certificate against next certificate */
1427
-		if ( ( rc = x509_validate_issuer ( current, next ) ) != 0 )
1428
-			return rc;
1565
+	DBGC ( cert, "X509 %p \"%s\" successfully validated using issuer %p "
1566
+	       "\"%s\"\n", cert, cert->subject.name,
1567
+	       issuer, issuer->subject.name );
1568
+	return 0;
1569
+}
1570
+
1571
+/**
1572
+ * Free X.509 certificate chain
1573
+ *
1574
+ * @v refcnt		Reference count
1575
+ */
1576
+static void x509_free_chain ( struct refcnt *refcnt ) {
1577
+	struct x509_chain *chain =
1578
+		container_of ( refcnt, struct x509_chain, refcnt );
1579
+	struct x509_link *link;
1580
+	struct x509_link *tmp;
1581
+
1582
+	DBGC ( chain, "X509 chain %p freed\n", chain );
1583
+
1584
+	/* Free each link in the chain */
1585
+	list_for_each_entry_safe ( link, tmp, &chain->links, list ) {
1586
+		x509_put ( link->cert );
1587
+		list_del ( &link->list );
1588
+		free ( link );
1589
+	}
1590
+
1591
+	/* Free chain */
1592
+	free ( chain );
1593
+}
1594
+
1595
+/**
1596
+ * Allocate X.509 certificate chain
1597
+ *
1598
+ * @ret chain		X.509 certificate chain, or NULL
1599
+ */
1600
+struct x509_chain * x509_alloc_chain ( void ) {
1601
+	struct x509_chain *chain;
1602
+
1603
+	/* Allocate chain */
1604
+	chain = zalloc ( sizeof ( *chain ) );
1605
+	if ( ! chain )
1606
+		return NULL;
1607
+
1608
+	/* Initialise chain */
1609
+	ref_init ( &chain->refcnt, x509_free_chain );
1610
+	INIT_LIST_HEAD ( &chain->links );
1611
+
1612
+	DBGC ( chain, "X509 chain %p allocated\n", chain );
1613
+	return chain;
1614
+}
1615
+
1616
+/**
1617
+ * Append X.509 certificate to X.509 certificate chain
1618
+ *
1619
+ * @v chain		X.509 certificate chain
1620
+ * @v cert		X.509 certificate
1621
+ * @ret rc		Return status code
1622
+ */
1623
+int x509_append ( struct x509_chain *chain, struct x509_certificate *cert ) {
1624
+	struct x509_link *link;
1625
+
1626
+	/* Allocate link */
1627
+	link = zalloc ( sizeof ( *link ) );
1628
+	if ( ! link )
1629
+		return -ENOMEM;
1630
+
1631
+	/* Add link to chain */
1632
+	link->cert = x509_get ( cert );
1633
+	list_add_tail ( &link->list, &chain->links );
1634
+	DBGC ( chain, "X509 chain %p added X509 %p \"%s\"\n",
1635
+	       chain, cert, cert->subject.name );
1636
+
1637
+	return 0;
1638
+}
1639
+
1640
+/**
1641
+ * Validate X.509 certificate chain
1642
+ *
1643
+ * @v chain		X.509 certificate chain
1644
+ * @v time		Time at which to validate certificates
1645
+ * @v root		Root certificate store, or NULL to use default
1646
+ * @ret rc		Return status code
1647
+ */
1648
+int x509_validate_chain ( struct x509_chain *chain, time_t time,
1649
+			  struct x509_root *root ) {
1650
+	struct x509_certificate *issuer = NULL;
1651
+	struct x509_link *link;
1652
+	int rc;
1429
 
1653
 
1430
-		/* Validate path length constraint */
1431
-		if ( path_len > next->extensions.basic.path_len ) {
1432
-			DBGC ( context, "X509 chain %p path length %d exceeds "
1433
-			       "maximum %d\n", context, path_len,
1434
-			       next->extensions.basic.path_len );
1435
-			return -EACCES_PATH_LEN;
1654
+	/* Sanity check */
1655
+	if ( list_empty ( &chain->links ) ) {
1656
+		DBGC ( chain, "X509 chain %p is empty\n", chain );
1657
+		return -EACCES_EMPTY;
1658
+	}
1659
+
1660
+	/* Find first certificate that can be validated as a
1661
+	 * standalone (i.e.  is already valid, or can be validated as
1662
+	 * a trusted root certificate).
1663
+	 */
1664
+	list_for_each_entry ( link, &chain->links, list ) {
1665
+
1666
+		/* Try validating this certificate as a standalone */
1667
+		if ( ( rc = x509_validate ( link->cert, NULL, time,
1668
+					    root ) ) != 0 )
1669
+			continue;
1670
+
1671
+		/* Work back up to start of chain, performing pairwise
1672
+		 * validation.
1673
+		 */
1674
+		issuer = link->cert;
1675
+		list_for_each_entry_continue_reverse ( link, &chain->links,
1676
+						       list ) {
1677
+
1678
+			/* Validate this certificate against its issuer */
1679
+			if ( ( rc = x509_validate ( link->cert, issuer, time,
1680
+						    root ) ) != 0 )
1681
+				return rc;
1682
+			issuer = link->cert;
1436
 		}
1683
 		}
1437
-		path_len++;
1438
 
1684
 
1439
-		/* Move to next certificate in chain */
1440
-		swap = current;
1441
-		current = next;
1442
-		next = swap;
1685
+		return 0;
1443
 	}
1686
 	}
1687
+
1688
+	DBGC ( chain, "X509 chain %p found no valid certificates\n", chain );
1689
+	return -EACCES_UNTRUSTED;
1444
 }
1690
 }

+ 39
- 14
src/include/ipxe/cms.h View File

13
 #include <ipxe/asn1.h>
13
 #include <ipxe/asn1.h>
14
 #include <ipxe/crypto.h>
14
 #include <ipxe/crypto.h>
15
 #include <ipxe/x509.h>
15
 #include <ipxe/x509.h>
16
+#include <ipxe/refcnt.h>
16
 #include <ipxe/uaccess.h>
17
 #include <ipxe/uaccess.h>
17
 
18
 
18
 /** CMS signer information */
19
 /** CMS signer information */
19
 struct cms_signer_info {
20
 struct cms_signer_info {
20
-	/** Issuer name */
21
-	struct asn1_cursor issuer;
22
-	/** Serial number */
23
-	struct asn1_cursor serial;
21
+	/** List of signer information blocks */
22
+	struct list_head list;
23
+
24
+	/** Certificate chain */
25
+	struct x509_chain *chain;
26
+
24
 	/** Digest algorithm */
27
 	/** Digest algorithm */
25
 	struct digest_algorithm *digest;
28
 	struct digest_algorithm *digest;
26
 	/** Public-key algorithm */
29
 	/** Public-key algorithm */
27
 	struct pubkey_algorithm *pubkey;
30
 	struct pubkey_algorithm *pubkey;
31
+
28
 	/** Signature */
32
 	/** Signature */
29
-	const void *signature;
33
+	void *signature;
30
 	/** Length of signature */
34
 	/** Length of signature */
31
 	size_t signature_len;
35
 	size_t signature_len;
32
 };
36
 };
33
 
37
 
34
 /** A CMS signature */
38
 /** A CMS signature */
35
 struct cms_signature {
39
 struct cms_signature {
36
-	/** Raw certificate list */
37
-	struct asn1_cursor certificates;
38
-	/** Signer information
39
-	 *
40
-	 * We currently use only the first signer information block.
41
-	 */
42
-	struct cms_signer_info info;
40
+	/** Reference count */
41
+	struct refcnt refcnt;
42
+	/** List of all certificates */
43
+	struct x509_chain *certificates;
44
+	/** List of signer information blocks */
45
+	struct list_head info;
43
 };
46
 };
44
 
47
 
45
-extern int cms_parse ( struct cms_signature *sig, const void *data,
46
-		       size_t len );
48
+/**
49
+ * Get reference to CMS signature
50
+ *
51
+ * @v sig		CMS signature
52
+ * @ret sig		CMS signature
53
+ */
54
+static inline __attribute__ (( always_inline )) struct cms_signature *
55
+cms_get ( struct cms_signature *sig ) {
56
+	ref_get ( &sig->refcnt );
57
+	return sig;
58
+}
59
+
60
+/**
61
+ * Drop reference to CMS signature
62
+ *
63
+ * @v sig		CMS signature
64
+ */
65
+static inline __attribute__ (( always_inline )) void
66
+cms_put ( struct cms_signature *sig ) {
67
+	ref_put ( &sig->refcnt );
68
+}
69
+
70
+extern int cms_signature ( const void *data, size_t len,
71
+			   struct cms_signature **sig );
47
 extern int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
72
 extern int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
48
 			const char *name, time_t time, struct x509_root *root );
73
 			const char *name, time_t time, struct x509_root *root );
49
 
74
 

+ 3
- 0
src/include/ipxe/tls.h View File

235
 	/** Public-key algorithm used for Certificate Verify (if sent) */
235
 	/** Public-key algorithm used for Certificate Verify (if sent) */
236
 	struct pubkey_algorithm *verify_pubkey;
236
 	struct pubkey_algorithm *verify_pubkey;
237
 
237
 
238
+	/** Server certificate chain */
239
+	struct x509_chain *chain;
240
+
238
 	/** TX sequence number */
241
 	/** TX sequence number */
239
 	uint64_t tx_seq;
242
 	uint64_t tx_seq;
240
 	/** TX pending transmissions */
243
 	/** TX pending transmissions */

+ 132
- 24
src/include/ipxe/x509.h View File

13
 #include <stddef.h>
13
 #include <stddef.h>
14
 #include <time.h>
14
 #include <time.h>
15
 #include <ipxe/asn1.h>
15
 #include <ipxe/asn1.h>
16
+#include <ipxe/refcnt.h>
17
+#include <ipxe/list.h>
16
 
18
 
17
 /** An X.509 bit string */
19
 /** An X.509 bit string */
18
 struct x509_bit_string {
20
 struct x509_bit_string {
50
 	struct x509_time not_after;
52
 	struct x509_time not_after;
51
 };
53
 };
52
 
54
 
53
-/** An X.509 string */
54
-struct x509_string {
55
-	/** String (not NUL-terminated) */
56
-	const void *data;
57
-	/** Length of name */
58
-	size_t len;
59
-};
60
-
61
 /** An X.509 certificate public key */
55
 /** An X.509 certificate public key */
62
 struct x509_public_key {
56
 struct x509_public_key {
63
 	/** Raw public key */
57
 	/** Raw public key */
71
 	/** Raw subject */
65
 	/** Raw subject */
72
 	struct asn1_cursor raw;
66
 	struct asn1_cursor raw;
73
 	/** Common name */
67
 	/** Common name */
74
-	struct x509_string name;
68
+	char *name;
75
 	/** Public key information */
69
 	/** Public key information */
76
 	struct x509_public_key public_key;
70
 	struct x509_public_key public_key;
77
 };
71
 };
92
 	unsigned int path_len;
86
 	unsigned int path_len;
93
 };
87
 };
94
 
88
 
89
+/** Unlimited path length
90
+ *
91
+ * We use -2U, since this quantity represents one *fewer* than the
92
+ * maximum number of remaining certificates in a chain.
93
+ */
94
+#define X509_PATH_LEN_UNLIMITED -2U
95
+
95
 /** An X.509 certificate key usage */
96
 /** An X.509 certificate key usage */
96
 struct x509_key_usage {
97
 struct x509_key_usage {
97
 	/** Key usage extension is present */
98
 	/** Key usage extension is present */
131
 /** X.509 certificate OCSP responder */
132
 /** X.509 certificate OCSP responder */
132
 struct x509_ocsp_responder {
133
 struct x509_ocsp_responder {
133
 	/** URI */
134
 	/** URI */
134
-	struct x509_string uri;
135
+	char *uri;
135
 };
136
 };
136
 
137
 
137
 /** X.509 certificate authority information access */
138
 /** X.509 certificate authority information access */
154
 
155
 
155
 /** An X.509 certificate */
156
 /** An X.509 certificate */
156
 struct x509_certificate {
157
 struct x509_certificate {
158
+	/** Reference count */
159
+	struct refcnt refcnt;
160
+	/** List of certificates in cache */
161
+	struct list_head list;
162
+
163
+	/** Certificate has been validated */
164
+	int valid;
165
+	/** Maximum number of subsequent certificates in chain */
166
+	unsigned int path_remaining;
167
+
157
 	/** Raw certificate */
168
 	/** Raw certificate */
158
 	struct asn1_cursor raw;
169
 	struct asn1_cursor raw;
159
 	/** Version */
170
 	/** Version */
176
 	struct x509_extensions extensions;
187
 	struct x509_extensions extensions;
177
 };
188
 };
178
 
189
 
190
+/**
191
+ * Get reference to X.509 certificate
192
+ *
193
+ * @v cert		X.509 certificate
194
+ * @ret cert		X.509 certificate
195
+ */
196
+static inline __attribute__ (( always_inline )) struct x509_certificate *
197
+x509_get ( struct x509_certificate *cert ) {
198
+	ref_get ( &cert->refcnt );
199
+	return cert;
200
+}
201
+
202
+/**
203
+ * Drop reference to X.509 certificate
204
+ *
205
+ * @v cert		X.509 certificate
206
+ */
207
+static inline __attribute__ (( always_inline )) void
208
+x509_put ( struct x509_certificate *cert ) {
209
+	ref_put ( &cert->refcnt );
210
+}
211
+
212
+/** A link in an X.509 certificate chain */
213
+struct x509_link {
214
+	/** List of links */
215
+	struct list_head list;
216
+	/** Certificate */
217
+	struct x509_certificate *cert;
218
+};
219
+
220
+/** An X.509 certificate chain */
221
+struct x509_chain {
222
+	/** Reference count */
223
+	struct refcnt refcnt;
224
+	/** List of links */
225
+	struct list_head links;
226
+};
227
+
228
+/**
229
+ * Get reference to X.509 certificate chain
230
+ *
231
+ * @v chain		X.509 certificate chain
232
+ * @ret chain		X.509 certificate chain
233
+ */
234
+static inline __attribute__ (( always_inline )) struct x509_chain *
235
+x509_chain_get ( struct x509_chain *chain ) {
236
+	ref_get ( &chain->refcnt );
237
+	return chain;
238
+}
239
+
240
+/**
241
+ * Drop reference to X.509 certificate chain
242
+ *
243
+ * @v chain		X.509 certificate chain
244
+ */
245
+static inline __attribute__ (( always_inline )) void
246
+x509_chain_put ( struct x509_chain *chain ) {
247
+	ref_put ( &chain->refcnt );
248
+}
249
+
250
+/**
251
+ * Get first certificate in X.509 certificate chain
252
+ *
253
+ * @v chain		X.509 certificate chain
254
+ * @ret cert		X.509 certificate, or NULL
255
+ */
256
+static inline __attribute__ (( always_inline )) struct x509_certificate *
257
+x509_first ( struct x509_chain *chain ) {
258
+	struct x509_link *link;
259
+
260
+	link = list_first_entry ( &chain->links, struct x509_link, list );
261
+	return ( link ? link->cert : NULL );
262
+}
263
+
179
 /** An X.509 extension */
264
 /** An X.509 extension */
180
 struct x509_extension {
265
 struct x509_extension {
181
 	/** Name */
266
 	/** Name */
228
 	const void *fingerprints;
313
 	const void *fingerprints;
229
 };
314
 };
230
 
315
 
231
-extern int x509_parse ( struct x509_certificate *cert,
232
-			const void *data, size_t len );
233
-extern int x509_validate_issuer ( struct x509_certificate *cert,
234
-				  struct x509_certificate *issuer );
316
+extern int x509_certificate ( const void *data, size_t len,
317
+			      struct x509_certificate **cert );
318
+
319
+extern struct x509_chain * x509_alloc_chain ( void );
320
+extern int x509_append ( struct x509_chain *chain,
321
+			 struct x509_certificate *cert );
322
+extern int x509_validate_chain ( struct x509_chain *chain, time_t time,
323
+				 struct x509_root *root );
324
+
325
+/* Functions exposed only for unit testing */
326
+extern int x509_check_issuer ( struct x509_certificate *cert,
327
+			       struct x509_certificate *issuer );
235
 extern void x509_fingerprint ( struct x509_certificate *cert,
328
 extern void x509_fingerprint ( struct x509_certificate *cert,
236
 			       struct digest_algorithm *digest,
329
 			       struct digest_algorithm *digest,
237
 			       void *fingerprint );
330
 			       void *fingerprint );
238
-extern int x509_validate_root ( struct x509_certificate *cert,
239
-				struct x509_root *root );
240
-extern int x509_validate_time ( struct x509_certificate *cert, time_t time );
241
-extern int x509_validate_chain ( int ( * parse_next )
242
-				 ( struct x509_certificate *cert,
243
-				   const struct x509_certificate *previous,
244
-				   void *context ),
245
-				 void *context, time_t time,
246
-				 struct x509_root *root,
247
-				 struct x509_certificate *first );
331
+extern int x509_check_root ( struct x509_certificate *cert,
332
+			     struct x509_root *root );
333
+extern int x509_check_time ( struct x509_certificate *cert, time_t time );
334
+
335
+/**
336
+ * Invalidate X.509 certificate
337
+ *
338
+ * @v cert		X.509 certificate
339
+ */
340
+static inline void x509_invalidate ( struct x509_certificate *cert ) {
341
+	cert->valid = 0;
342
+	cert->path_remaining = 0;
343
+}
344
+
345
+/**
346
+ * Invalidate X.509 certificate chain
347
+ *
348
+ * @v chain		X.509 certificate chain
349
+ */
350
+static inline void x509_invalidate_chain ( struct x509_chain *chain ) {
351
+	struct x509_link *link;
352
+
353
+	list_for_each_entry ( link, &chain->links, list )
354
+		x509_invalidate ( link->cert );
355
+}
248
 
356
 
249
 #endif /* _IPXE_X509_H */
357
 #endif /* _IPXE_X509_H */

+ 94
- 67
src/net/tls.c View File

46
 #include <ipxe/tls.h>
46
 #include <ipxe/tls.h>
47
 
47
 
48
 /* Disambiguate the various error causes */
48
 /* Disambiguate the various error causes */
49
-#define EACCES_INCOMPLETE \
50
-	__einfo_error ( EINFO_EACCES_INCOMPLETE )
51
-#define EINFO_EACCES_INCOMPLETE \
52
-	__einfo_uniqify ( EINFO_EACCES, 0x01, "Incomplete certificate chain" )
53
 #define EACCES_WRONG_NAME \
49
 #define EACCES_WRONG_NAME \
54
 	__einfo_error ( EINFO_EACCES_WRONG_NAME )
50
 	__einfo_error ( EINFO_EACCES_WRONG_NAME )
55
 #define EINFO_EACCES_WRONG_NAME \
51
 #define EINFO_EACCES_WRONG_NAME \
184
 	tls_clear_cipher ( tls, &tls->rx_cipherspec );
180
 	tls_clear_cipher ( tls, &tls->rx_cipherspec );
185
 	tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
181
 	tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
186
 	free ( tls->rx_data );
182
 	free ( tls->rx_data );
183
+	x509_chain_put ( tls->chain );
187
 
184
 
188
 	/* Free TLS structure itself */
185
 	/* Free TLS structure itself */
189
 	free ( tls );	
186
 	free ( tls );	
899
 			uint8_t data[ client_certificate.len ];
896
 			uint8_t data[ client_certificate.len ];
900
 		} __attribute__ (( packed )) certificates[num_certificates];
897
 		} __attribute__ (( packed )) certificates[num_certificates];
901
 	} __attribute__ (( packed )) *certificate;
898
 	} __attribute__ (( packed )) *certificate;
902
-	struct x509_certificate cert;
899
+	struct x509_certificate *cert;
903
 	int rc;
900
 	int rc;
904
 
901
 
905
 	/* If we have a certificate to send, determine the applicable
902
 	/* If we have a certificate to send, determine the applicable
909
 	if ( num_certificates ) {
906
 	if ( num_certificates ) {
910
 
907
 
911
 		/* Parse certificate to determine public-key algorithm */
908
 		/* Parse certificate to determine public-key algorithm */
912
-		if ( ( rc = x509_parse ( &cert, client_certificate.data,
913
-					 client_certificate.len ) ) != 0 ) {
909
+		if ( ( rc = x509_certificate ( client_certificate.data,
910
+					       client_certificate.len,
911
+					       &cert ) ) != 0 ) {
914
 			DBGC ( tls, "TLS %p could not parse client "
912
 			DBGC ( tls, "TLS %p could not parse client "
915
 			       "certificate: %s\n", tls, strerror ( rc ) );
913
 			       "certificate: %s\n", tls, strerror ( rc ) );
916
 			return rc;
914
 			return rc;
917
 		}
915
 		}
918
-		tls->verify_pubkey = cert.signature_algorithm->pubkey;
916
+		tls->verify_pubkey = cert->signature_algorithm->pubkey;
917
+		x509_put ( cert );
918
+		cert = NULL;
919
 
919
 
920
 		/* Schedule CertificateVerify transmission */
920
 		/* Schedule CertificateVerify transmission */
921
 		tls->tx_pending |= TLS_TX_CERTIFICATE_VERIFY;
921
 		tls->tx_pending |= TLS_TX_CERTIFICATE_VERIFY;
1267
 	return 0;
1267
 	return 0;
1268
 }
1268
 }
1269
 
1269
 
1270
-/** TLS certificate chain context */
1271
-struct tls_certificate_context {
1272
-	/** TLS session */
1273
-	struct tls_session *tls;
1274
-	/** Current certificate */
1275
-	const void *current;
1276
-	/** End of certificates */
1277
-	const void *end;
1278
-};
1279
-
1280
 /**
1270
 /**
1281
- * Parse next certificate in TLS certificate list
1271
+ * Parse certificate chain
1282
  *
1272
  *
1283
- * @v cert		X.509 certificate to fill in
1284
- * @v previous		Previous X.509 certificate, or NULL
1285
- * @v ctx		Context
1273
+ * @v tls		TLS session
1274
+ * @v data		Certificate chain
1275
+ * @v len		Length of certificate chain
1286
  * @ret rc		Return status code
1276
  * @ret rc		Return status code
1287
  */
1277
  */
1288
-static int tls_parse_next ( struct x509_certificate *cert,
1289
-			    const struct x509_certificate *previous __unused,
1290
-			    void *ctx ) {
1291
-	struct tls_certificate_context *context = ctx;
1292
-	struct tls_session *tls = context->tls;
1278
+static int tls_parse_chain ( struct tls_session *tls,
1279
+			     const void *data, size_t len ) {
1280
+	const void *end = ( data + len );
1293
 	const struct {
1281
 	const struct {
1294
 		uint8_t length[3];
1282
 		uint8_t length[3];
1295
-		uint8_t certificate[0];
1296
-	} __attribute__ (( packed )) *current = context->current;
1297
-	const void *data;
1283
+		uint8_t data[0];
1284
+	} __attribute__ (( packed )) *certificate;
1285
+	size_t certificate_len;
1286
+	struct x509_certificate *cert;
1298
 	const void *next;
1287
 	const void *next;
1299
-	size_t len;
1300
 	int rc;
1288
 	int rc;
1301
 
1289
 
1302
-	/* Return error at end of chain */
1303
-	if ( context->current >= context->end ) {
1304
-		DBGC ( tls, "TLS %p reached end of certificate chain\n", tls );
1305
-		return -EACCES_INCOMPLETE;
1306
-	}
1290
+	/* Free any existing certificate chain */
1291
+	x509_chain_put ( tls->chain );
1292
+	tls->chain = NULL;
1307
 
1293
 
1308
-	/* Extract current certificate and update context */
1309
-	data = current->certificate;
1310
-	len = tls_uint24 ( current->length );
1311
-	next = ( data + len );
1312
-	if ( next > context->end ) {
1313
-		DBGC ( tls, "TLS %p overlength certificate\n", tls );
1314
-		DBGC_HDA ( tls, 0, context->current,
1315
-			   ( context->end - context->current ) );
1316
-		return -EINVAL;
1294
+	/* Create certificate chain */
1295
+	tls->chain = x509_alloc_chain();
1296
+	if ( ! tls->chain ) {
1297
+		rc = -ENOMEM;
1298
+		goto err_alloc_chain;
1317
 	}
1299
 	}
1318
-	context->current = next;
1319
 
1300
 
1320
-	/* Parse current certificate */
1321
-	if ( ( rc = x509_parse ( cert, data, len ) ) != 0 ) {
1322
-		DBGC ( tls, "TLS %p could not parse certificate: %s\n",
1323
-		       tls, strerror ( rc ) );
1324
-		return rc;
1301
+	/* Add certificates to chain */
1302
+	while ( data < end ) {
1303
+
1304
+		/* Extract raw certificate data */
1305
+		certificate = data;
1306
+		certificate_len = tls_uint24 ( certificate->length );
1307
+		next = ( certificate->data + certificate_len );
1308
+		if ( next > end ) {
1309
+			DBGC ( tls, "TLS %p overlength certificate:\n", tls );
1310
+			DBGC_HDA ( tls, 0, data, ( end - data ) );
1311
+			rc = -EINVAL;
1312
+			goto err_overlength;
1313
+		}
1314
+
1315
+		/* Parse certificate */
1316
+		if ( ( rc = x509_certificate ( certificate->data,
1317
+					       certificate_len,
1318
+					       &cert ) ) != 0 ) {
1319
+			DBGC ( tls, "TLS %p could not parse certificate: %s\n",
1320
+			       tls, strerror ( rc ) );
1321
+			DBGC_HDA ( tls, 0, data, ( end - data ) );
1322
+			goto err_parse;
1323
+		}
1324
+		DBGC ( tls, "TLS %p found certificate %s\n",
1325
+		       tls, cert->subject.name );
1326
+
1327
+		/* Append certificate to chain */
1328
+		if ( ( rc = x509_append ( tls->chain, cert ) ) != 0 ) {
1329
+			DBGC ( tls, "TLS %p could not append certificate: %s\n",
1330
+			       tls, strerror ( rc ) );
1331
+			goto err_append;
1332
+		}
1333
+
1334
+		/* Drop reference to certificate */
1335
+		x509_put ( cert );
1336
+		cert = NULL;
1337
+
1338
+		/* Move to next certificate in list */
1339
+		data = next;
1325
 	}
1340
 	}
1326
 
1341
 
1327
 	return 0;
1342
 	return 0;
1343
+
1344
+ err_append:
1345
+	x509_put ( cert );
1346
+ err_parse:
1347
+ err_overlength:
1348
+	x509_chain_put ( tls->chain );
1349
+	tls->chain = NULL;
1350
+ err_alloc_chain:
1351
+	return rc;
1328
 }
1352
 }
1329
 
1353
 
1330
 /**
1354
 /**
1341
 		uint8_t length[3];
1365
 		uint8_t length[3];
1342
 		uint8_t certificates[0];
1366
 		uint8_t certificates[0];
1343
 	} __attribute__ (( packed )) *certificate = data;
1367
 	} __attribute__ (( packed )) *certificate = data;
1344
-	size_t elements_len = tls_uint24 ( certificate->length );
1345
-	const void *end = ( certificate->certificates + elements_len );
1368
+	size_t certificates_len = tls_uint24 ( certificate->length );
1369
+	const void *end = ( certificate->certificates + certificates_len );
1346
 	struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
1370
 	struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
1347
 	struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
1371
 	struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
1348
-	struct tls_certificate_context context;
1349
-	struct x509_certificate cert;
1350
-	struct x509_string *name = &cert.subject.name;
1351
-	struct x509_public_key *key = &cert.subject.public_key;
1372
+	struct x509_certificate *cert;
1352
 	time_t now;
1373
 	time_t now;
1353
 	int rc;
1374
 	int rc;
1354
 
1375
 
1360
 		return -EINVAL;
1381
 		return -EINVAL;
1361
 	}
1382
 	}
1362
 
1383
 
1363
-	/* Parse first certificate and validate certificate chain */
1364
-	context.tls = tls;
1365
-	context.current = certificate->certificates;
1366
-	context.end = end;
1384
+	/* Parse certificate chain */
1385
+	if ( ( rc = tls_parse_chain ( tls, certificate->certificates,
1386
+				      certificates_len ) ) != 0 )
1387
+		return rc;
1388
+
1389
+	/* Validate certificate chain */
1367
 	now = time ( NULL );
1390
 	now = time ( NULL );
1368
-	if ( ( rc = x509_validate_chain ( tls_parse_next, &context,
1369
-					  now, NULL, &cert ) ) != 0 ) {
1391
+	if ( ( rc = x509_validate_chain ( tls->chain, now, NULL ) ) != 0 ) {
1370
 		DBGC ( tls, "TLS %p could not validate certificate chain: %s\n",
1392
 		DBGC ( tls, "TLS %p could not validate certificate chain: %s\n",
1371
 		       tls, strerror ( rc ) );
1393
 		       tls, strerror ( rc ) );
1372
 		return rc;
1394
 		return rc;
1373
 	}
1395
 	}
1374
 
1396
 
1397
+	/* Extract first certificate */
1398
+	cert = x509_first ( tls->chain );
1399
+	assert ( cert != NULL );
1400
+
1375
 	/* Verify server name */
1401
 	/* Verify server name */
1376
-	if ( ( name->len != strlen ( tls->name ) ) ||
1377
-	     ( memcmp ( name->data, tls->name, name->len ) != 0 ) ) {
1378
-		DBGC ( tls, "TLS %p server name incorrect\n", tls );
1402
+	if ( strcmp ( tls->name, cert->subject.name ) != 0 ) {
1403
+		DBGC ( tls, "TLS %p server name incorrect (expected %s, got "
1404
+		       "%s)\n", tls, tls->name, cert->subject.name );
1379
 		return -EACCES_WRONG_NAME;
1405
 		return -EACCES_WRONG_NAME;
1380
 	}
1406
 	}
1381
 
1407
 
1382
 	/* Initialise public key algorithm */
1408
 	/* Initialise public key algorithm */
1383
 	if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx,
1409
 	if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx,
1384
-				  key->raw.data, key->raw.len ) ) != 0 ) {
1410
+				  cert->subject.public_key.raw.data,
1411
+				  cert->subject.public_key.raw.len ) ) != 0 ) {
1385
 		DBGC ( tls, "TLS %p cannot initialise public key: %s\n",
1412
 		DBGC ( tls, "TLS %p cannot initialise public key: %s\n",
1386
 		       tls, strerror ( rc ) );
1413
 		       tls, strerror ( rc ) );
1387
 		return rc;
1414
 		return rc;

+ 25
- 18
src/tests/cms_test.c View File

52
 	const void *data;
52
 	const void *data;
53
 	/** Length of data */
53
 	/** Length of data */
54
 	size_t len;
54
 	size_t len;
55
+
56
+	/** Parsed signature */
57
+	struct cms_signature *sig;
55
 };
58
 };
56
 
59
 
57
 /** Define inline data */
60
 /** Define inline data */
1331
 /**
1334
 /**
1332
  * Report signature parsing test result
1335
  * Report signature parsing test result
1333
  *
1336
  *
1334
- * @v sig		Test signature
1337
+ * @v sgn		Test signature
1335
  */
1338
  */
1336
-#define cms_parse_ok( sig ) do {					\
1337
-	struct cms_signature temp;					\
1338
-	ok ( cms_parse ( &temp, (sig)->data, (sig)->len ) == 0 );	\
1339
+#define cms_signature_ok( sgn ) do {					\
1340
+	ok ( cms_signature ( (sgn)->data, (sgn)->len,			\
1341
+			     &(sgn)->sig ) == 0 );			\
1339
 	} while ( 0 )
1342
 	} while ( 0 )
1340
 
1343
 
1341
 /**
1344
 /**
1342
  * Report signature verification test result
1345
  * Report signature verification test result
1343
  *
1346
  *
1344
- * @v sig		Test signature
1347
+ * @v sgn		Test signature
1345
  * @v code		Test signed code
1348
  * @v code		Test signed code
1346
  * @v name		Test verification name
1349
  * @v name		Test verification name
1347
  * @v time		Test verification time
1350
  * @v time		Test verification time
1348
  * @v root		Test root certificate store
1351
  * @v root		Test root certificate store
1349
  */
1352
  */
1350
-#define cms_verify_ok( sig, code, name, time, root ) do {		\
1351
-	struct cms_signature temp;					\
1352
-	ok ( cms_parse ( &temp, (sig)->data, (sig)->len ) == 0 );	\
1353
-	ok ( cms_verify ( &temp, virt_to_user ( (code)->data ),		\
1353
+#define cms_verify_ok( sgn, code, name, time, root ) do {		\
1354
+	x509_invalidate_chain ( (sgn)->sig->certificates );		\
1355
+	ok ( cms_verify ( (sgn)->sig, virt_to_user ( (code)->data ),	\
1354
 			  (code)->len, name, time, root ) == 0 );	\
1356
 			  (code)->len, name, time, root ) == 0 );	\
1355
 	} while ( 0 )
1357
 	} while ( 0 )
1356
 
1358
 
1357
 /**
1359
 /**
1358
  * Report signature verification failure test result
1360
  * Report signature verification failure test result
1359
  *
1361
  *
1360
- * @v sig		Test signature
1362
+ * @v sgn		Test signature
1361
  * @v code		Test signed code
1363
  * @v code		Test signed code
1362
  * @v name		Test verification name
1364
  * @v name		Test verification name
1363
  * @v time		Test verification time
1365
  * @v time		Test verification time
1364
  * @v root		Test root certificate store
1366
  * @v root		Test root certificate store
1365
  */
1367
  */
1366
-#define cms_verify_fail_ok( sig, code, name, time, root ) do {		\
1367
-	struct cms_signature temp;					\
1368
-	ok ( cms_parse ( &temp, (sig)->data, (sig)->len ) == 0 );	\
1369
-	ok ( cms_verify ( &temp, virt_to_user ( (code)->data ),		\
1368
+#define cms_verify_fail_ok( sgn, code, name, time, root ) do {		\
1369
+	x509_invalidate_chain ( (sgn)->sig->certificates );		\
1370
+	ok ( cms_verify ( (sgn)->sig, virt_to_user ( (code)->data ),	\
1370
 			  (code)->len, name, time, root ) != 0 );	\
1371
 			  (code)->len, name, time, root ) != 0 );	\
1371
 	} while ( 0 )
1372
 	} while ( 0 )
1372
 
1373
 
1377
 static void cms_test_exec ( void ) {
1378
 static void cms_test_exec ( void ) {
1378
 
1379
 
1379
 	/* Check that all signatures can be parsed */
1380
 	/* Check that all signatures can be parsed */
1380
-	cms_parse_ok ( &codesigned_sig );
1381
-	cms_parse_ok ( &brokenchain_sig );
1382
-	cms_parse_ok ( &genericsigned_sig );
1383
-	cms_parse_ok ( &nonsigned_sig );
1381
+	cms_signature_ok ( &codesigned_sig );
1382
+	cms_signature_ok ( &brokenchain_sig );
1383
+	cms_signature_ok ( &genericsigned_sig );
1384
+	cms_signature_ok ( &nonsigned_sig );
1384
 
1385
 
1385
 	/* Check good signature */
1386
 	/* Check good signature */
1386
 	cms_verify_ok ( &codesigned_sig, &test_code,
1387
 	cms_verify_ok ( &codesigned_sig, &test_code,
1415
 	/* Check expired signature */
1416
 	/* Check expired signature */
1416
 	cms_verify_fail_ok ( &codesigned_sig, &test_code,
1417
 	cms_verify_fail_ok ( &codesigned_sig, &test_code,
1417
 			     NULL, test_expired, &test_root );
1418
 			     NULL, test_expired, &test_root );
1419
+
1420
+	/* Drop signature references */
1421
+	cms_put ( nonsigned_sig.sig );
1422
+	cms_put ( genericsigned_sig.sig );
1423
+	cms_put ( brokenchain_sig.sig );
1424
+	cms_put ( codesigned_sig.sig );
1418
 }
1425
 }
1419
 
1426
 
1420
 /** CMS self-test */
1427
 /** CMS self-test */

+ 134
- 109
src/tests/x509_test.c View File

31
 #include <string.h>
31
 #include <string.h>
32
 #include <errno.h>
32
 #include <errno.h>
33
 #include <ipxe/x509.h>
33
 #include <ipxe/x509.h>
34
+#include <ipxe/asn1.h>
34
 #include <ipxe/sha256.h>
35
 #include <ipxe/sha256.h>
35
 #include <ipxe/test.h>
36
 #include <ipxe/test.h>
36
 
37
 
45
 	size_t len;
46
 	size_t len;
46
 	/** Fingerprint */
47
 	/** Fingerprint */
47
 	const void *fingerprint;
48
 	const void *fingerprint;
49
+
50
+	/** Parsed certificate */
51
+	struct x509_certificate *cert;
48
 };
52
 };
49
 
53
 
50
 /** An X.509 test certificate chain */
54
 /** An X.509 test certificate chain */
53
 	struct x509_test_certificate **certs;
57
 	struct x509_test_certificate **certs;
54
 	/** Number of certificates */
58
 	/** Number of certificates */
55
 	unsigned int count;
59
 	unsigned int count;
60
+
61
+	/** Parsed certificate chain */
62
+	struct x509_chain *chain;
56
 };
63
 };
57
 
64
 
58
 /** Define inline certificate data */
65
 /** Define inline certificate data */
683
 /** Time at which CA test certificates are invalid */
690
 /** Time at which CA test certificates are invalid */
684
 static time_t test_ca_expired = 2205014905ULL; /* Wed Nov 16 00:08:25 2039 */
691
 static time_t test_ca_expired = 2205014905ULL; /* Wed Nov 16 00:08:25 2039 */
685
 
692
 
686
-/** An X.509 test certificate chain context */
687
-struct x509_test_chain_context {
688
-	/** Test certificate chain */
689
-	struct x509_test_chain *chain;
690
-	/** Index within chain */
691
-	unsigned int index;
692
-};
693
-
694
 /**
693
 /**
695
- * Parse next certificate in chain
694
+ * Report certificate parsing test result
696
  *
695
  *
697
- * @v cert		X.509 certificate to parse
698
- * @v previous		Previous X.509 certificate, or NULL
699
- * @v ctx		Chain context
700
- * @ret rc		Return status code
696
+ * @v crt		Test certificate
701
  */
697
  */
702
-static int
703
-x509_test_parse_next ( struct x509_certificate *cert,
704
-		       const struct x509_certificate *previous __unused,
705
-		       void *ctx ) {
706
-	struct x509_test_chain_context *context = ctx;
707
-	struct x509_test_certificate *test_cert;
708
-
709
-	/* Return error at end of chain */
710
-	if ( context->index >= context->chain->count )
711
-		return -ENOENT;
712
-
713
-	/* Get next test certificate */
714
-	test_cert = context->chain->certs[ context->index++ ];
715
-
716
-	/* Parse certificate */
717
-	return x509_parse ( cert, test_cert->data, test_cert->len );
718
-}
698
+#define x509_certificate_ok( crt ) do {					\
699
+	ok ( x509_certificate ( (crt)->data, (crt)->len,		\
700
+				&(crt)->cert ) == 0 );			\
701
+	} while ( 0 )
719
 
702
 
720
 /**
703
 /**
721
- * Report certificate parsing test result
704
+ * Report cached certificate parsing test result
722
  *
705
  *
723
- * @v cert		Test certificate
706
+ * @v crt		Test certificate
724
  */
707
  */
725
-#define x509_parse_ok( cert ) do {					\
726
-	struct x509_certificate temp;					\
727
-	ok ( x509_parse ( &temp, (cert)->data, (cert)->len ) == 0 );	\
708
+#define x509_cached_ok( crt ) do {					\
709
+	struct x509_certificate *temp;					\
710
+	ok ( x509_certificate ( (crt)->data, (crt)->len,		\
711
+				&temp ) == 0 );				\
712
+	ok ( temp == (crt)->cert );					\
713
+	x509_put ( temp );						\
728
 	} while ( 0 )
714
 	} while ( 0 )
729
 
715
 
730
 /**
716
 /**
731
  * Report certificate fingerprint test result
717
  * Report certificate fingerprint test result
732
  *
718
  *
733
- * @v cert		Test certificate
719
+ * @v crt		Test certificate
734
  */
720
  */
735
-#define x509_fingerprint_ok( cert ) do {				\
736
-	struct x509_certificate temp;					\
721
+#define x509_fingerprint_ok( crt ) do {					\
737
 	uint8_t fingerprint[ x509_test_algorithm.digestsize ];		\
722
 	uint8_t fingerprint[ x509_test_algorithm.digestsize ];		\
738
-	ok ( x509_parse ( &temp, (cert)->data, (cert)->len ) == 0 );	\
739
-	x509_fingerprint ( &temp, &x509_test_algorithm, fingerprint );	\
740
-	ok ( memcmp ( fingerprint, (cert)->fingerprint,			\
723
+	x509_fingerprint ( (crt)->cert, &x509_test_algorithm,		\
724
+			   fingerprint );				\
725
+	ok ( memcmp ( fingerprint, (crt)->fingerprint,			\
741
 		      sizeof ( fingerprint ) ) == 0 );			\
726
 		      sizeof ( fingerprint ) ) == 0 );			\
742
 	} while ( 0 )
727
 	} while ( 0 )
743
 
728
 
744
 /**
729
 /**
745
  * Report certificate issuer validation test result
730
  * Report certificate issuer validation test result
746
  *
731
  *
747
- * @v cert		Test certificate
732
+ * @v crt		Test certificate
748
  * @v issuer		Test issuer
733
  * @v issuer		Test issuer
749
  */
734
  */
750
-#define x509_validate_issuer_ok( cert, issuer ) do {			\
751
-	struct x509_certificate cert_temp;				\
752
-	struct x509_certificate issuer_temp;				\
753
-	ok ( x509_parse ( &cert_temp, (cert)->data,			\
754
-			  (cert)->len ) == 0 );				\
755
-	ok ( x509_parse ( &issuer_temp, (issuer)->data,			\
756
-			  (issuer)->len ) == 0 );			\
757
-	ok ( x509_validate_issuer ( &cert_temp, &issuer_temp ) == 0 );	\
735
+#define x509_check_issuer_ok( crt, issuer ) do {			\
736
+	ok ( x509_check_issuer ( (crt)->cert, (issuer)->cert ) == 0 );	\
758
 	} while ( 0 )
737
 	} while ( 0 )
759
 
738
 
760
 /**
739
 /**
761
  * Report certificate issuer validation failure test result
740
  * Report certificate issuer validation failure test result
762
  *
741
  *
763
- * @v cert		Test certificate
742
+ * @v crt		Test certificate
764
  * @v issuer		Test issuer
743
  * @v issuer		Test issuer
765
  */
744
  */
766
-#define x509_validate_issuer_fail_ok( cert, issuer ) do {		\
767
-	struct x509_certificate cert_temp;				\
768
-	struct x509_certificate issuer_temp;				\
769
-	ok ( x509_parse ( &cert_temp, (cert)->data,			\
770
-			  (cert)->len ) == 0 );				\
771
-	ok ( x509_parse ( &issuer_temp, (issuer)->data,			\
772
-			  (issuer)->len ) == 0 );			\
773
-	ok ( x509_validate_issuer ( &cert_temp, &issuer_temp ) != 0 );	\
745
+#define x509_check_issuer_fail_ok( crt, issuer ) do {			\
746
+	ok ( x509_check_issuer ( (crt)->cert, (issuer)->cert ) != 0 );	\
774
 	} while ( 0 )
747
 	} while ( 0 )
775
 
748
 
776
 /**
749
 /**
777
  * Report certificate root validation test result
750
  * Report certificate root validation test result
778
  *
751
  *
779
- * @v cert		Test certificate
752
+ * @v crt		Test certificate
780
  * @v root		Test root certificate store
753
  * @v root		Test root certificate store
781
  */
754
  */
782
-#define x509_validate_root_ok( cert, root ) do {			\
783
-	struct x509_certificate temp;					\
784
-	ok ( x509_parse ( &temp, (cert)->data, (cert)->len ) == 0 );	\
785
-	ok ( x509_validate_root ( &temp, root ) == 0 );			\
755
+#define x509_check_root_ok( crt, root ) do {				\
756
+	ok ( x509_check_root ( (crt)->cert, root ) == 0 );		\
786
 	} while ( 0 )
757
 	} while ( 0 )
787
 
758
 
788
 /**
759
 /**
789
  * Report certificate root validation failure test result
760
  * Report certificate root validation failure test result
790
  *
761
  *
791
- * @v cert		Test certificate
762
+ * @v crt		Test certificate
792
  * @v root		Test root certificate store
763
  * @v root		Test root certificate store
793
  */
764
  */
794
-#define x509_validate_root_fail_ok( cert, root ) do {			\
795
-	struct x509_certificate temp;					\
796
-	ok ( x509_parse ( &temp, (cert)->data, (cert)->len ) == 0 );	\
797
-	ok ( x509_validate_root ( &temp, root ) != 0 );			\
765
+#define x509_check_root_fail_ok( crt, root ) do {			\
766
+	ok ( x509_check_root ( (crt)->cert, root ) != 0 );		\
798
 	} while ( 0 )
767
 	} while ( 0 )
799
 
768
 
800
 /**
769
 /**
801
  * Report certificate time validation test result
770
  * Report certificate time validation test result
802
  *
771
  *
803
- * @v cert		Test certificate
772
+ * @v crt		Test certificate
804
  * @v time		Test time
773
  * @v time		Test time
805
  */
774
  */
806
-#define x509_validate_time_ok( cert, time ) do {			\
807
-	struct x509_certificate temp;					\
808
-	ok ( x509_parse ( &temp, (cert)->data, (cert)->len ) == 0 );	\
809
-	ok ( x509_validate_time ( &temp, time ) == 0 );			\
775
+#define x509_check_time_ok( crt, time ) do {				\
776
+	ok ( x509_check_time ( (crt)->cert, time ) == 0 );		\
810
 	} while ( 0 )
777
 	} while ( 0 )
811
 
778
 
812
 /**
779
 /**
813
  * Report certificate time validation failure test result
780
  * Report certificate time validation failure test result
814
  *
781
  *
815
- * @v cert		Test certificate
782
+ * @v crt		Test certificate
816
  * @v time		Test time
783
  * @v time		Test time
817
  */
784
  */
818
-#define x509_validate_time_fail_ok( cert, time ) do {			\
819
-	struct x509_certificate temp;					\
820
-	ok ( x509_parse ( &temp, (cert)->data, (cert)->len ) == 0 );	\
821
-	ok ( x509_validate_time ( &temp, time ) != 0 );			\
785
+#define x509_check_time_fail_ok( crt, time ) do {			\
786
+	ok ( x509_check_time ( (crt)->cert, time ) != 0 );		\
787
+	} while ( 0 )
788
+
789
+/**
790
+ * Report certificate chain parsing test result
791
+ *
792
+ * @v chn		Test certificate chain
793
+ */
794
+#define x509_chain_ok( chn ) do {					\
795
+	unsigned int i;							\
796
+	struct x509_certificate *first;					\
797
+	(chn)->chain = x509_alloc_chain();				\
798
+	ok ( (chn)->chain != NULL );					\
799
+	for ( i = 0 ; i < (chn)->count ; i++ ) {			\
800
+		ok ( x509_append ( (chn)->chain,			\
801
+				   (chn)->certs[i]->cert ) == 0 );	\
802
+	}								\
803
+	first = x509_first ( (chn)->chain );				\
804
+	ok ( first != NULL );						\
805
+	ok ( first->raw.len == (chn)->certs[0]->len );			\
806
+	ok ( memcmp ( first->raw.data, (chn)->certs[0]->data,		\
807
+		      first->raw.len ) == 0 );				\
822
 	} while ( 0 )
808
 	} while ( 0 )
823
 
809
 
824
 /**
810
 /**
825
  * Report certificate chain validation test result
811
  * Report certificate chain validation test result
826
  *
812
  *
827
- * @v chain		Test certificate chain
813
+ * @v chn		Test certificate chain
828
  * @v time		Test certificate validation time
814
  * @v time		Test certificate validation time
829
  * @v root		Test root certificate store
815
  * @v root		Test root certificate store
830
  */
816
  */
831
-#define x509_validate_chain_ok( chain, time, root ) do {		\
832
-	struct x509_test_chain_context context = { (chain), 0 };	\
833
-	struct x509_certificate temp;					\
834
-	ok ( x509_validate_chain ( x509_test_parse_next, &context,	\
835
-				   (time), (root), &temp ) == 0 );	\
836
-	ok ( temp.raw.data == (chain)->certs[0]->data );		\
837
-	ok ( temp.raw.len == (chain)->certs[0]->len );			\
817
+#define x509_validate_chain_ok( chn, time, root ) do {			\
818
+	x509_invalidate_chain ( (chn)->chain );				\
819
+	ok ( x509_validate_chain ( (chn)->chain, (time),		\
820
+				   (root) ) == 0 );			\
838
 	} while ( 0 )
821
 	} while ( 0 )
839
 
822
 
840
 /**
823
 /**
841
  * Report certificate chain validation failure test result
824
  * Report certificate chain validation failure test result
842
  *
825
  *
843
- * @v chain		Test certificate chain
826
+ * @v chn		Test certificate chain
844
  * @v time		Test certificate validation time
827
  * @v time		Test certificate validation time
845
  * @v root		Test root certificate store
828
  * @v root		Test root certificate store
846
  */
829
  */
847
-#define x509_validate_chain_fail_ok( chain, time, root ) do {		\
848
-	struct x509_test_chain_context context = { (chain), 0 };	\
849
-	struct x509_certificate temp;					\
850
-	ok ( x509_validate_chain ( x509_test_parse_next, &context,	\
851
-				   (time), (root), &temp ) != 0 );	\
830
+#define x509_validate_chain_fail_ok( chn, time, root ) do {		\
831
+	x509_invalidate_chain ( (chn)->chain );				\
832
+	ok ( x509_validate_chain ( (chn)->chain, (time),		\
833
+				   (root) ) != 0 );			\
852
 	} while ( 0 )
834
 	} while ( 0 )
853
 
835
 
854
 /**
836
 /**
857
  */
839
  */
858
 static void x509_test_exec ( void ) {
840
 static void x509_test_exec ( void ) {
859
 
841
 
842
+	/* Parse all certificates */
843
+	x509_certificate_ok ( &root_crt );
844
+	x509_certificate_ok ( &intermediate_crt );
845
+	x509_certificate_ok ( &leaf_crt );
846
+	x509_certificate_ok ( &useless_crt );
847
+	x509_certificate_ok ( &server_crt );
848
+	x509_certificate_ok ( &not_ca_crt );
849
+	x509_certificate_ok ( &bad_path_len_crt );
850
+
851
+	/* Check cache functionality */
852
+	x509_cached_ok ( &root_crt );
853
+	x509_cached_ok ( &intermediate_crt );
854
+	x509_cached_ok ( &leaf_crt );
855
+	x509_cached_ok ( &useless_crt );
856
+	x509_cached_ok ( &server_crt );
857
+	x509_cached_ok ( &not_ca_crt );
858
+	x509_cached_ok ( &bad_path_len_crt );
859
+
860
 	/* Check all certificate fingerprints */
860
 	/* Check all certificate fingerprints */
861
 	x509_fingerprint_ok ( &root_crt );
861
 	x509_fingerprint_ok ( &root_crt );
862
 	x509_fingerprint_ok ( &intermediate_crt );
862
 	x509_fingerprint_ok ( &intermediate_crt );
867
 	x509_fingerprint_ok ( &bad_path_len_crt );
867
 	x509_fingerprint_ok ( &bad_path_len_crt );
868
 
868
 
869
 	/* Check pairwise issuing */
869
 	/* Check pairwise issuing */
870
-	x509_validate_issuer_ok ( &intermediate_crt, &root_crt );
871
-	x509_validate_issuer_ok ( &leaf_crt, &intermediate_crt );
872
-	x509_validate_issuer_ok ( &useless_crt, &leaf_crt );
873
-	x509_validate_issuer_ok ( &server_crt, &leaf_crt );
874
-	x509_validate_issuer_fail_ok ( &not_ca_crt, &server_crt );
875
-	x509_validate_issuer_ok ( &bad_path_len_crt, &useless_crt );
870
+	x509_check_issuer_ok ( &intermediate_crt, &root_crt );
871
+	x509_check_issuer_ok ( &leaf_crt, &intermediate_crt );
872
+	x509_check_issuer_ok ( &useless_crt, &leaf_crt );
873
+	x509_check_issuer_ok ( &server_crt, &leaf_crt );
874
+	x509_check_issuer_fail_ok ( &not_ca_crt, &server_crt );
875
+	x509_check_issuer_ok ( &bad_path_len_crt, &useless_crt );
876
 
876
 
877
 	/* Check root certificate stores */
877
 	/* Check root certificate stores */
878
-	x509_validate_root_ok ( &root_crt, &test_root );
879
-	x509_validate_root_fail_ok ( &intermediate_crt, &test_root );
880
-	x509_validate_root_ok ( &intermediate_crt, &intermediate_root );
881
-	x509_validate_root_fail_ok ( &root_crt, &intermediate_root );
882
-	x509_validate_root_fail_ok ( &root_crt, &dummy_root );
878
+	x509_check_root_ok ( &root_crt, &test_root );
879
+	x509_check_root_fail_ok ( &intermediate_crt, &test_root );
880
+	x509_check_root_ok ( &intermediate_crt, &intermediate_root );
881
+	x509_check_root_fail_ok ( &root_crt, &intermediate_root );
882
+	x509_check_root_fail_ok ( &root_crt, &dummy_root );
883
 
883
 
884
 	/* Check certificate validity periods */
884
 	/* Check certificate validity periods */
885
-	x509_validate_time_ok ( &server_crt, test_time );
886
-	x509_validate_time_fail_ok ( &server_crt, test_expired );
887
-	x509_validate_time_ok ( &root_crt, test_time );
888
-	x509_validate_time_ok ( &root_crt, test_expired );
889
-	x509_validate_time_fail_ok ( &root_crt, test_ca_expired );
885
+	x509_check_time_ok ( &server_crt, test_time );
886
+	x509_check_time_fail_ok ( &server_crt, test_expired );
887
+	x509_check_time_ok ( &root_crt, test_time );
888
+	x509_check_time_ok ( &root_crt, test_expired );
889
+	x509_check_time_fail_ok ( &root_crt, test_ca_expired );
890
+
891
+	/* Parse all certificate chains */
892
+	x509_chain_ok ( &server_chain );
893
+	x509_chain_ok ( &broken_server_chain );
894
+	x509_chain_ok ( &incomplete_server_chain );
895
+	x509_chain_ok ( &not_ca_chain );
896
+	x509_chain_ok ( &useless_chain );
897
+	x509_chain_ok ( &bad_path_len_chain );
890
 
898
 
891
 	/* Check certificate chains */
899
 	/* Check certificate chains */
892
 	x509_validate_chain_ok ( &server_chain, test_time, &test_root );
900
 	x509_validate_chain_ok ( &server_chain, test_time, &test_root );
908
 	x509_validate_chain_ok ( &useless_chain, test_expired, &test_root );
916
 	x509_validate_chain_ok ( &useless_chain, test_expired, &test_root );
909
 	x509_validate_chain_fail_ok ( &useless_chain, test_ca_expired,
917
 	x509_validate_chain_fail_ok ( &useless_chain, test_ca_expired,
910
 				      &test_root );
918
 				      &test_root );
919
+
920
+	/* Drop chain references */
921
+	x509_chain_put ( bad_path_len_chain.chain );
922
+	x509_chain_put ( useless_chain.chain );
923
+	x509_chain_put ( not_ca_chain.chain );
924
+	x509_chain_put ( incomplete_server_chain.chain );
925
+	x509_chain_put ( broken_server_chain.chain );
926
+	x509_chain_put ( server_chain.chain );
927
+
928
+	/* Drop certificate references */
929
+	x509_put ( bad_path_len_crt.cert );
930
+	x509_put ( not_ca_crt.cert );
931
+	x509_put ( server_crt.cert );
932
+	x509_put ( useless_crt.cert );
933
+	x509_put ( leaf_crt.cert );
934
+	x509_put ( intermediate_crt.cert );
935
+	x509_put ( root_crt.cert );
911
 }
936
 }
912
 
937
 
913
 /** X.509 self-test */
938
 /** X.509 self-test */

+ 12
- 6
src/usr/imgtrust.c View File

45
 		const char *name ) {
45
 		const char *name ) {
46
 	size_t len;
46
 	size_t len;
47
 	void *data;
47
 	void *data;
48
-	struct cms_signature sig;
48
+	struct cms_signature *sig;
49
 	time_t now;
49
 	time_t now;
50
 	int rc;
50
 	int rc;
51
 
51
 
62
 	copy_from_user ( data, signature->data, 0, len );
62
 	copy_from_user ( data, signature->data, 0, len );
63
 
63
 
64
 	/* Parse signature */
64
 	/* Parse signature */
65
-	if ( ( rc = cms_parse ( &sig, data, len ) ) != 0 )
65
+	if ( ( rc = cms_signature ( data, len, &sig ) ) != 0 )
66
 		goto err_parse;
66
 		goto err_parse;
67
 
67
 
68
+	/* Free internal copy of signature */
69
+	free ( data );
70
+	data = NULL;
71
+
68
 	/* Use signature to verify image */
72
 	/* Use signature to verify image */
69
 	now = time ( NULL );
73
 	now = time ( NULL );
70
-	if ( ( rc = cms_verify ( &sig, image->data, image->len,
74
+	if ( ( rc = cms_verify ( sig, image->data, image->len,
71
 				 name, now, NULL ) ) != 0 )
75
 				 name, now, NULL ) ) != 0 )
72
 		goto err_verify;
76
 		goto err_verify;
73
 
77
 
78
+	/* Drop reference to signature */
79
+	cms_put ( sig );
80
+	sig = NULL;
81
+
74
 	/* Mark image as trusted */
82
 	/* Mark image as trusted */
75
 	image_trust ( image );
83
 	image_trust ( image );
76
 	syslog ( LOG_NOTICE, "Image \"%s\" signature OK\n", image->name );
84
 	syslog ( LOG_NOTICE, "Image \"%s\" signature OK\n", image->name );
77
 
85
 
78
-	/* Free internal copy of signature */
79
-	free ( data );
80
-
81
 	return 0;
86
 	return 0;
82
 
87
 
83
  err_verify:
88
  err_verify:
89
+	cms_put ( sig );
84
  err_parse:
90
  err_parse:
85
 	free ( data );
91
 	free ( data );
86
  err_alloc:
92
  err_alloc:

Loading…
Cancel
Save