瀏覽代碼

[crypto] Automatically perform OCSP checks when applicable

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 年之前
父節點
當前提交
073331c2ee
共有 1 個檔案被更改,包括 195 行新增68 行删除
  1. 195
    68
      src/net/validator.c

+ 195
- 68
src/net/validator.c 查看文件

@@ -35,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
35 35
 #include <ipxe/dhcp.h>
36 36
 #include <ipxe/base64.h>
37 37
 #include <ipxe/crc32.h>
38
+#include <ipxe/ocsp.h>
38 39
 #include <ipxe/validator.h>
39 40
 
40 41
 /** @file
@@ -51,12 +52,19 @@ struct validator {
51 52
 	struct interface job;
52 53
 	/** Data transfer interface */
53 54
 	struct interface xfer;
55
+
54 56
 	/** Process */
55 57
 	struct process process;
58
+
56 59
 	/** X.509 certificate chain */
57 60
 	struct x509_chain *chain;
61
+	/** OCSP check */
62
+	struct ocsp_check *ocsp;
58 63
 	/** Data buffer */
59 64
 	struct xfer_buffer buffer;
65
+	/** Action to take upon completed transfer */
66
+	int ( * done ) ( struct validator *validator, const void *data,
67
+			 size_t len );
60 68
 };
61 69
 
62 70
 /**
@@ -70,6 +78,7 @@ static void validator_free ( struct refcnt *refcnt ) {
70 78
 
71 79
 	DBGC2 ( validator, "VALIDATOR %p freed\n", validator );
72 80
 	x509_chain_put ( validator->chain );
81
+	ocsp_put ( validator->ocsp );
73 82
 	xferbuf_done ( &validator->buffer );
74 83
 	free ( validator );
75 84
 }
@@ -122,6 +131,89 @@ struct setting crosscert_setting __setting ( SETTING_CRYPTO ) = {
122 131
 /** Default cross-signed certificate source */
123 132
 static const char crosscert_default[] = "http://ca.ipxe.org/auto";
124 133
 
134
+/**
135
+ * Append cross-signing certificates to certificate chain
136
+ *
137
+ * @v validator		Certificate validator
138
+ * @v data		Raw cross-signing certificate data
139
+ * @v len		Length of raw data
140
+ * @ret rc		Return status code
141
+ */
142
+static int validator_append ( struct validator *validator,
143
+			      const void *data, size_t len ) {
144
+	struct asn1_cursor cursor;
145
+	struct x509_chain *certs;
146
+	struct x509_certificate *cert;
147
+	struct x509_certificate *last;
148
+	int rc;
149
+
150
+	/* Allocate certificate list */
151
+	certs = x509_alloc_chain();
152
+	if ( ! certs ) {
153
+		rc = -ENOMEM;
154
+		goto err_alloc_certs;
155
+	}
156
+
157
+	/* Initialise cursor */
158
+	cursor.data = data;
159
+	cursor.len = len;
160
+
161
+	/* Enter certificateSet */
162
+	if ( ( rc = asn1_enter ( &cursor, ASN1_SET ) ) != 0 ) {
163
+		DBGC ( validator, "VALIDATOR %p could not enter "
164
+		       "certificateSet: %s\n", validator, strerror ( rc ) );
165
+		goto err_certificateset;
166
+	}
167
+
168
+	/* Add each certificate to list */
169
+	while ( cursor.len ) {
170
+
171
+		/* Add certificate to chain */
172
+		if ( ( rc = x509_append_raw ( certs, cursor.data,
173
+					      cursor.len ) ) != 0 ) {
174
+			DBGC ( validator, "VALIDATOR %p could not append "
175
+			       "certificate: %s\n",
176
+			       validator, strerror ( rc) );
177
+			DBGC_HDA ( validator, 0, cursor.data, cursor.len );
178
+			return rc;
179
+		}
180
+		cert = x509_last ( certs );
181
+		DBGC ( validator, "VALIDATOR %p found certificate %s\n",
182
+		       validator, cert->subject.name );
183
+
184
+		/* Move to next certificate */
185
+		asn1_skip_any ( &cursor );
186
+	}
187
+
188
+	/* Append certificates to chain */
189
+	last = x509_last ( validator->chain );
190
+	if ( ( rc = x509_auto_append ( validator->chain, certs ) ) != 0 ) {
191
+		DBGC ( validator, "VALIDATOR %p could not append "
192
+		       "certificates: %s\n", validator, strerror ( rc ) );
193
+		goto err_auto_append;
194
+	}
195
+
196
+	/* Check that at least one certificate has been added */
197
+	if ( last == x509_last ( validator->chain ) ) {
198
+		DBGC ( validator, "VALIDATOR %p failed to append any "
199
+		       "applicable certificates\n", validator );
200
+		rc = -EACCES;
201
+		goto err_no_progress;
202
+	}
203
+
204
+	/* Drop reference to certificate list */
205
+	x509_chain_put ( certs );
206
+
207
+	return 0;
208
+
209
+ err_no_progress:
210
+ err_auto_append:
211
+ err_certificateset:
212
+	x509_chain_put ( certs );
213
+ err_alloc_certs:
214
+	return rc;
215
+}
216
+
125 217
 /**
126 218
  * Start download of cross-signing certificate
127 219
  *
@@ -169,6 +261,9 @@ static int validator_start_download ( struct validator *validator,
169 261
 	DBGC ( validator, "VALIDATOR %p downloading cross-signed certificate "
170 262
 	       "from %s\n", validator, uri_string );
171 263
 
264
+	/* Set completion handler */
265
+	validator->done = validator_append;
266
+
172 267
 	/* Open URI */
173 268
 	if ( ( rc = xfer_open_uri_string ( &validator->xfer,
174 269
 					   uri_string ) ) != 0 ) {
@@ -188,87 +283,84 @@ static int validator_start_download ( struct validator *validator,
188 283
 	return rc;
189 284
 }
190 285
 
286
+/****************************************************************************
287
+ *
288
+ * OCSP checks
289
+ *
290
+ */
291
+
191 292
 /**
192
- * Append cross-signing certificates to certificate chain
293
+ * Validate OCSP response
193 294
  *
194 295
  * @v validator		Certificate validator
195
- * @v data		Raw cross-signing certificate data
296
+ * @v data		Raw OCSP response
196 297
  * @v len		Length of raw data
197 298
  * @ret rc		Return status code
198 299
  */
199
-static int validator_append ( struct validator *validator,
200
-			      const void *data, size_t len ) {
201
-	struct asn1_cursor cursor;
202
-	struct x509_chain *certs;
203
-	struct x509_certificate *cert;
204
-	struct x509_certificate *last;
300
+static int validator_ocsp_validate ( struct validator *validator,
301
+				     const void *data, size_t len ) {
302
+	time_t now;
205 303
 	int rc;
206 304
 
207
-	/* Allocate certificate list */
208
-	certs = x509_alloc_chain();
209
-	if ( ! certs ) {
210
-		rc = -ENOMEM;
211
-		goto err_alloc_certs;
305
+	/* Record OCSP response */
306
+	if ( ( rc = ocsp_response ( validator->ocsp, data, len ) ) != 0 ) {
307
+		DBGC ( validator, "VALIDATOR %p could not record OCSP "
308
+		       "response: %s\n", validator, strerror ( rc ) );
309
+		return rc;
212 310
 	}
213 311
 
214
-	/* Initialise cursor */
215
-	cursor.data = data;
216
-	cursor.len = len;
217
-
218
-	/* Enter certificateSet */
219
-	if ( ( rc = asn1_enter ( &cursor, ASN1_SET ) ) != 0 ) {
220
-		DBGC ( validator, "VALIDATOR %p could not enter "
221
-		       "certificateSet: %s\n", validator, strerror ( rc ) );
222
-		goto err_certificateset;
312
+	/* Validate OCSP response */
313
+	now = time ( NULL );
314
+	if ( ( rc = ocsp_validate ( validator->ocsp, now ) ) != 0 ) {
315
+		DBGC ( validator, "VALIDATOR %p could not validate OCSP "
316
+		       "response: %s\n", validator, strerror ( rc ) );
317
+		return rc;
223 318
 	}
224 319
 
225
-	/* Add each certificate to list */
226
-	while ( cursor.len ) {
320
+	/* Drop reference to OCSP check */
321
+	ocsp_put ( validator->ocsp );
322
+	validator->ocsp = NULL;
227 323
 
228
-		/* Add certificate to chain */
229
-		if ( ( rc = x509_append_raw ( certs, cursor.data,
230
-					      cursor.len ) ) != 0 ) {
231
-			DBGC ( validator, "VALIDATOR %p could not append "
232
-			       "certificate: %s\n",
233
-			       validator, strerror ( rc) );
234
-			DBGC_HDA ( validator, 0, cursor.data, cursor.len );
235
-			return rc;
236
-		}
237
-		cert = x509_last ( certs );
238
-		DBGC ( validator, "VALIDATOR %p found certificate %s\n",
239
-		       validator, cert->subject.name );
324
+	return 0;
325
+}
240 326
 
241
-		/* Move to next certificate */
242
-		asn1_skip_any ( &cursor );
243
-	}
327
+/**
328
+ * Start OCSP check
329
+ *
330
+ * @v validator		Certificate validator
331
+ * @v cert		Certificate to check
332
+ * @v issuer		Issuing certificate
333
+ * @ret rc		Return status code
334
+ */
335
+static int validator_start_ocsp ( struct validator *validator,
336
+				  struct x509_certificate *cert,
337
+				  struct x509_certificate *issuer ) {
338
+	const char *uri_string;
339
+	int rc;
244 340
 
245
-	/* Append certificates to chain */
246
-	last = x509_last ( validator->chain );
247
-	if ( ( rc = x509_auto_append ( validator->chain, certs ) ) != 0 ) {
248
-		DBGC ( validator, "VALIDATOR %p could not append "
249
-		       "certificates: %s\n", validator, strerror ( rc ) );
250
-		goto err_auto_append;
341
+	/* Create OCSP check */
342
+	assert ( validator->ocsp == NULL );
343
+	if ( ( rc = ocsp_check ( cert, issuer, &validator->ocsp ) ) != 0 ) {
344
+		DBGC ( validator, "VALIDATOR %p could not create OCSP check: "
345
+		       "%s\n", validator, strerror ( rc ) );
346
+		return rc;
251 347
 	}
252 348
 
253
-	/* Check that at least one certificate has been added */
254
-	if ( last == x509_last ( validator->chain ) ) {
255
-		DBGC ( validator, "VALIDATOR %p failed to append any "
256
-		       "applicable certificates\n", validator );
257
-		rc = -EACCES;
258
-		goto err_no_progress;
259
-	}
349
+	/* Set completion handler */
350
+	validator->done = validator_ocsp_validate;
260 351
 
261
-	/* Drop reference to certificate list */
262
-	x509_chain_put ( certs );
352
+	/* Open URI */
353
+	uri_string = validator->ocsp->uri_string;
354
+	DBGC ( validator, "VALIDATOR %p performing OCSP check at %s\n",
355
+	       validator, uri_string );
356
+	if ( ( rc = xfer_open_uri_string ( &validator->xfer,
357
+					   uri_string ) ) != 0 ) {
358
+		DBGC ( validator, "VALIDATOR %p could not open %s: %s\n",
359
+		       validator, uri_string, strerror ( rc ) );
360
+		return rc;
361
+	}
263 362
 
264 363
 	return 0;
265
-
266
- err_no_progress:
267
- err_auto_append:
268
- err_certificateset:
269
-	x509_chain_put ( certs );
270
- err_alloc_certs:
271
-	return rc;
272 364
 }
273 365
 
274 366
 /****************************************************************************
@@ -290,14 +382,15 @@ static void validator_xfer_close ( struct validator *validator, int rc ) {
290 382
 
291 383
 	/* Check for errors */
292 384
 	if ( rc != 0 ) {
293
-		DBGC ( validator, "VALIDATOR %p download failed: %s\n",
385
+		DBGC ( validator, "VALIDATOR %p transfer failed: %s\n",
294 386
 		       validator, strerror ( rc ) );
295
-		goto err_download;
387
+		goto err_transfer;
296 388
 	}
297
-	DBGC2 ( validator, "VALIDATOR %p download complete\n", validator );
389
+	DBGC2 ( validator, "VALIDATOR %p transfer complete\n", validator );
298 390
 
299
-	/* Append downloaded certificates */
300
-	if ( ( rc = validator_append ( validator, validator->buffer.data,
391
+	/* Process completed download */
392
+	assert ( validator->done != NULL );
393
+	if ( ( rc = validator->done ( validator, validator->buffer.data,
301 394
 				       validator->buffer.len ) ) != 0 )
302 395
 		goto err_append;
303 396
 
@@ -310,7 +403,7 @@ static void validator_xfer_close ( struct validator *validator, int rc ) {
310 403
 	return;
311 404
 
312 405
  err_append:
313
- err_download:
406
+ err_transfer:
314 407
 	validator_finished ( validator, rc );
315 408
 }
316 409
 
@@ -361,7 +454,11 @@ static struct interface_descriptor validator_xfer_desc =
361 454
  * @v validator		Certificate validator
362 455
  */
363 456
 static void validator_step ( struct validator *validator ) {
364
-	struct x509_certificate *last = x509_last ( validator->chain );
457
+	struct x509_link *link;
458
+	struct x509_link *previous;
459
+	struct x509_certificate *cert;
460
+	struct x509_certificate *issuer = NULL;
461
+	struct x509_certificate *last;
365 462
 	time_t now;
366 463
 	int rc;
367 464
 
@@ -376,9 +473,39 @@ static void validator_step ( struct validator *validator ) {
376 473
 		return;
377 474
 	}
378 475
 
476
+	/* If there is a certificate that could be validated using
477
+	 * OCSP, try it.
478
+	 */
479
+	list_for_each_entry ( link, &validator->chain->links, list ) {
480
+		cert = issuer;
481
+		issuer = link->cert;
482
+		previous = link;
483
+		if ( ! cert )
484
+			continue;
485
+		if ( ! issuer->valid )
486
+			continue;
487
+		/* The issuer is valid, but this certificate is not
488
+		 * yet valid.  If OCSP is applicable, start it.
489
+		 */
490
+		if ( cert->extensions.auth_info.ocsp.uri &&
491
+		     ( ! cert->extensions.auth_info.ocsp.good ) ) {
492
+			/* Start OCSP */
493
+			if ( ( rc = validator_start_ocsp ( validator, cert,
494
+							   issuer ) ) != 0 ) {
495
+				validator_finished ( validator, rc );
496
+				return;
497
+			}
498
+			return;
499
+		}
500
+		/* Otherwise, this is a permanent failure */
501
+		validator_finished ( validator, rc );
502
+		return;
503
+	}
504
+
379 505
 	/* If chain ends with a self-issued certificate, then there is
380 506
 	 * nothing more to do.
381 507
 	 */
508
+	last = x509_last ( validator->chain );
382 509
 	if ( asn1_compare ( &last->issuer.raw, &last->subject.raw ) == 0 ) {
383 510
 		validator_finished ( validator, rc );
384 511
 		return;

Loading…
取消
儲存