Selaa lähdekoodia

[crypto] Add framework for OCSP

Add support for constructing OCSP queries and parsing OCSP responses.
(There is no support yet for actually issuing an OCSP query via an
HTTP POST.)

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 vuotta sitten
vanhempi
commit
39ac285a8a
6 muutettua tiedostoa jossa 877 lisäystä ja 3 poistoa
  1. 749
    0
      src/crypto/ocsp.c
  2. 3
    3
      src/crypto/x509.c
  3. 11
    0
      src/include/ipxe/asn1.h
  4. 1
    0
      src/include/ipxe/errfile.h
  5. 108
    0
      src/include/ipxe/ocsp.h
  6. 5
    0
      src/include/ipxe/x509.h

+ 749
- 0
src/crypto/ocsp.c Näytä tiedosto

@@ -0,0 +1,749 @@
1
+/*
2
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+#include <stdint.h>
23
+#include <stdlib.h>
24
+#include <string.h>
25
+#include <errno.h>
26
+#include <ipxe/asn1.h>
27
+#include <ipxe/x509.h>
28
+#include <ipxe/sha1.h>
29
+#include <ipxe/ocsp.h>
30
+
31
+/** @file
32
+ *
33
+ * Online Certificate Status Protocol
34
+ *
35
+ */
36
+
37
+/* Disambiguate the various error causes */
38
+#define EACCES_CERT_STATUS						\
39
+	__einfo_error ( EINFO_EACCES_CERT_STATUS )
40
+#define EINFO_EACCES_CERT_STATUS					\
41
+	__einfo_uniqify ( EINFO_EACCES, 0x01,				\
42
+			  "Certificate status not good" )
43
+#define EACCES_CERT_MISMATCH						\
44
+	__einfo_error ( EINFO_EACCES_CERT_MISMATCH )
45
+#define EINFO_EACCES_CERT_MISMATCH					\
46
+	__einfo_uniqify ( EINFO_EACCES, 0x02,				\
47
+			  "Certificate ID mismatch" )
48
+#define EACCES_NON_OCSP_SIGNING						\
49
+	__einfo_error ( EINFO_EACCES_NON_OCSP_SIGNING )
50
+#define EINFO_EACCES_NON_OCSP_SIGNING					\
51
+	__einfo_uniqify ( EINFO_EACCES, 0x03,				\
52
+			  "Not an OCSP signing certificate" )
53
+#define EACCES_STALE							\
54
+	__einfo_error ( EINFO_EACCES_STALE )
55
+#define EINFO_EACCES_STALE						\
56
+	__einfo_uniqify ( EINFO_EACCES, 0x04,				\
57
+			  "Stale (or premature) OCSP repsonse" )
58
+#define EPROTO_MALFORMED_REQUEST					\
59
+	__einfo_error ( EINFO_EPROTO_MALFORMED_REQUEST )
60
+#define EINFO_EPROTO_MALFORMED_REQUEST					\
61
+	__einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_MALFORMED_REQUEST,	\
62
+			  "Illegal confirmation request" )
63
+#define EPROTO_INTERNAL_ERROR						\
64
+	__einfo_error ( EINFO_EPROTO_INTERNAL_ERROR )
65
+#define EINFO_EPROTO_INTERNAL_ERROR					\
66
+	__einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_INTERNAL_ERROR,	\
67
+			  "Internal error in issuer" )
68
+#define EPROTO_TRY_LATER						\
69
+	__einfo_error ( EINFO_EPROTO_TRY_LATER )
70
+#define EINFO_EPROTO_TRY_LATER						\
71
+	__einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_TRY_LATER,		\
72
+			  "Try again later" )
73
+#define EPROTO_SIG_REQUIRED						\
74
+	__einfo_error ( EINFO_EPROTO_SIG_REQUIRED )
75
+#define EINFO_EPROTO_SIG_REQUIRED					\
76
+	__einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_SIG_REQUIRED,	\
77
+			  "Must sign the request" )
78
+#define EPROTO_UNAUTHORIZED						\
79
+	__einfo_error ( EINFO_EPROTO_UNAUTHORIZED )
80
+#define EINFO_EPROTO_UNAUTHORIZED					\
81
+	__einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_UNAUTHORIZED,	\
82
+			  "Request unauthorized" )
83
+#define EPROTO_STATUS( status )						\
84
+	EUNIQ ( EPROTO, (status), EPROTO_MALFORMED_REQUEST,		\
85
+		EPROTO_INTERNAL_ERROR, EPROTO_TRY_LATER,		\
86
+		EPROTO_SIG_REQUIRED, EPROTO_UNAUTHORIZED )
87
+
88
+/** OCSP digest algorithm */
89
+#define ocsp_digest_algorithm sha1_algorithm
90
+
91
+/** OCSP digest algorithm identifier */
92
+static const uint8_t ocsp_algorithm_id[] =
93
+	{ OCSP_ALGORITHM_IDENTIFIER ( ASN1_OID_SHA1 ) };
94
+
95
+/** OCSP basic response type */
96
+static const uint8_t oid_basic_response_type[] = { ASN1_OID_OCSP_BASIC };
97
+
98
+/** OCSP basic response type cursor */
99
+static struct asn1_cursor oid_basic_response_type_cursor =
100
+	ASN1_OID_CURSOR ( oid_basic_response_type );
101
+
102
+/**
103
+ * Free OCSP check
104
+ *
105
+ * @v refcnt		Reference count
106
+ */
107
+static void ocsp_free ( struct refcnt *refcnt ) {
108
+	struct ocsp_check *ocsp =
109
+		container_of ( refcnt, struct ocsp_check, refcnt );
110
+
111
+	x509_put ( ocsp->cert );
112
+	x509_put ( ocsp->issuer );
113
+	free ( ocsp->request.builder.data );
114
+	free ( ocsp->response.data );
115
+	x509_put ( ocsp->response.signer );
116
+	free ( ocsp );
117
+}
118
+
119
+/**
120
+ * Build OCSP request
121
+ *
122
+ * @v ocsp		OCSP check
123
+ * @ret rc		Return status code
124
+ */
125
+static int ocsp_request ( struct ocsp_check *ocsp ) {
126
+	struct digest_algorithm *digest = &ocsp_digest_algorithm;
127
+	struct asn1_builder *builder = &ocsp->request.builder;
128
+	struct asn1_cursor *cert_id = &ocsp->request.cert_id;
129
+	uint8_t digest_ctx[digest->ctxsize];
130
+	uint8_t name_digest[digest->digestsize];
131
+	uint8_t pubkey_digest[digest->digestsize];
132
+	int rc;
133
+
134
+	/* Generate digests */
135
+	digest_init ( digest, digest_ctx );
136
+	digest_update ( digest, digest_ctx, ocsp->cert->issuer.raw.data,
137
+			ocsp->cert->issuer.raw.len );
138
+	digest_final ( digest, digest_ctx, name_digest );
139
+	digest_init ( digest, digest_ctx );
140
+	digest_update ( digest, digest_ctx,
141
+			ocsp->issuer->subject.public_key.raw_bits.data,
142
+			ocsp->issuer->subject.public_key.raw_bits.len );
143
+	digest_final ( digest, digest_ctx, pubkey_digest );
144
+
145
+	/* Construct request */
146
+	if ( ( rc = ( asn1_prepend_raw ( builder, ocsp->cert->serial.raw.data,
147
+					 ocsp->cert->serial.raw.len ),
148
+		      asn1_prepend ( builder, ASN1_OCTET_STRING,
149
+				     pubkey_digest, sizeof ( pubkey_digest ) ),
150
+		      asn1_prepend ( builder, ASN1_OCTET_STRING,
151
+				     name_digest, sizeof ( name_digest ) ),
152
+		      asn1_prepend ( builder, ASN1_SEQUENCE,
153
+				     ocsp_algorithm_id,
154
+				     sizeof ( ocsp_algorithm_id ) ),
155
+		      asn1_wrap ( builder, ASN1_SEQUENCE ),
156
+		      asn1_wrap ( builder, ASN1_SEQUENCE ),
157
+		      asn1_wrap ( builder, ASN1_SEQUENCE ),
158
+		      asn1_wrap ( builder, ASN1_SEQUENCE ),
159
+		      asn1_wrap ( builder, ASN1_SEQUENCE ) ) ) != 0 ) {
160
+		DBGC ( ocsp, "OCSP %p \"%s\" could not build request: %s\n",
161
+		       ocsp, ocsp->cert->subject.name, strerror ( rc ) );
162
+		return rc;
163
+	}
164
+	DBGC2 ( ocsp, "OCSP %p \"%s\" request is:\n",
165
+		ocsp, ocsp->cert->subject.name );
166
+	DBGC2_HDA ( ocsp, 0, builder->data, builder->len );
167
+
168
+	/* Parse certificate ID for comparison with response */
169
+	cert_id->data = builder->data;
170
+	cert_id->len = builder->len;
171
+	if ( ( rc = ( asn1_enter ( cert_id, ASN1_SEQUENCE ),
172
+		      asn1_enter ( cert_id, ASN1_SEQUENCE ),
173
+		      asn1_enter ( cert_id, ASN1_SEQUENCE ),
174
+		      asn1_enter ( cert_id, ASN1_SEQUENCE ) ) ) != 0 ) {
175
+		DBGC ( ocsp, "OCSP %p \"%s\" could not locate certID: %s\n",
176
+		       ocsp, ocsp->cert->subject.name, strerror ( rc ) );
177
+		return rc;
178
+	}
179
+
180
+	return 0;
181
+}
182
+
183
+/**
184
+ * Create OCSP check
185
+ *
186
+ * @v cert		Certificate to check
187
+ * @v issuer		Issuing certificate
188
+ * @ret ocsp		OCSP check
189
+ * @ret rc		Return status code
190
+ */
191
+int ocsp_check ( struct x509_certificate *cert,
192
+		 struct x509_certificate *issuer,
193
+		 struct ocsp_check **ocsp ) {
194
+	int rc;
195
+
196
+	/* Sanity checks */
197
+	assert ( cert != NULL );
198
+	assert ( issuer != NULL );
199
+	assert ( issuer->valid );
200
+
201
+	/* Allocate and initialise check */
202
+	*ocsp = zalloc ( sizeof ( **ocsp ) );
203
+	if ( ! *ocsp ) {
204
+		rc = -ENOMEM;
205
+		goto err_alloc;
206
+	}
207
+	ref_init ( &(*ocsp)->refcnt, ocsp_free );
208
+	(*ocsp)->cert = x509_get ( cert );
209
+	(*ocsp)->issuer = x509_get ( issuer );
210
+
211
+	/* Build request */
212
+	if ( ( rc = ocsp_request ( *ocsp ) ) != 0 )
213
+		goto err_request;
214
+
215
+	return 0;
216
+
217
+ err_request:
218
+	ocsp_put ( *ocsp );
219
+ err_alloc:
220
+	return rc;
221
+}
222
+
223
+/**
224
+ * Parse OCSP response status
225
+ *
226
+ * @v ocsp		OCSP check
227
+ * @v raw		ASN.1 cursor
228
+ * @ret rc		Return status code
229
+ */
230
+static int ocsp_parse_response_status ( struct ocsp_check *ocsp,
231
+					const struct asn1_cursor *raw ) {
232
+	struct asn1_cursor cursor;
233
+	uint8_t status;
234
+	int rc;
235
+
236
+	/* Enter responseStatus */
237
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
238
+	if ( ( rc = asn1_enter ( &cursor, ASN1_ENUMERATED ) ) != 0 ) {
239
+		DBGC ( ocsp, "OCSP %p \"%s\" could not locate responseStatus: "
240
+		       "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc ));
241
+		return rc;
242
+	}
243
+
244
+	/* Extract response status */
245
+	if ( cursor.len != sizeof ( status ) ) {
246
+		DBGC ( ocsp, "OCSP %p \"%s\" invalid status:\n",
247
+		       ocsp, ocsp->cert->subject.name );
248
+		DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
249
+		return -EINVAL;
250
+	}
251
+	memcpy ( &status, cursor.data, sizeof ( status ) );
252
+
253
+	/* Check response status */
254
+	if ( status != OCSP_STATUS_SUCCESSFUL ) {
255
+		DBGC ( ocsp, "OCSP %p \"%s\" response status %d\n",
256
+		       ocsp, ocsp->cert->subject.name, status );
257
+		return EPROTO_STATUS ( status );
258
+	}
259
+
260
+	return 0;
261
+}
262
+
263
+/**
264
+ * Parse OCSP response type
265
+ *
266
+ * @v ocsp		OCSP check
267
+ * @v raw		ASN.1 cursor
268
+ * @ret rc		Return status code
269
+ */
270
+static int ocsp_parse_response_type ( struct ocsp_check *ocsp,
271
+				      const struct asn1_cursor *raw ) {
272
+	struct asn1_cursor cursor;
273
+
274
+	/* Enter responseType */
275
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
276
+	asn1_enter ( &cursor, ASN1_OID );
277
+
278
+	/* Check responseType is "basic" */
279
+	if ( asn1_compare ( &oid_basic_response_type_cursor, &cursor ) != 0 ) {
280
+		DBGC ( ocsp, "OCSP %p \"%s\" response type not supported:\n",
281
+		       ocsp, ocsp->cert->subject.name );
282
+		DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
283
+		return -ENOTSUP;
284
+	}
285
+
286
+	return 0;
287
+}
288
+
289
+/**
290
+ * Parse OCSP certificate ID
291
+ *
292
+ * @v ocsp		OCSP check
293
+ * @v raw		ASN.1 cursor
294
+ * @ret rc		Return status code
295
+ */
296
+static int ocsp_parse_cert_id ( struct ocsp_check *ocsp,
297
+				const struct asn1_cursor *raw ) {
298
+	struct asn1_cursor cursor;
299
+
300
+	/* Check certID matches request */
301
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
302
+	asn1_shrink_any ( &cursor );
303
+	if ( asn1_compare ( &cursor, &ocsp->request.cert_id ) != 0 ) {
304
+		DBGC ( ocsp, "OCSP %p \"%s\" certID mismatch:\n",
305
+		       ocsp, ocsp->cert->subject.name );
306
+		DBGC_HDA ( ocsp, 0, ocsp->request.cert_id.data,
307
+			   ocsp->request.cert_id.len );
308
+		DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
309
+		return -EACCES_CERT_MISMATCH;
310
+	}
311
+
312
+	return 0;
313
+}
314
+
315
+/**
316
+ * Parse OCSP responses
317
+ *
318
+ * @v ocsp		OCSP check
319
+ * @v raw		ASN.1 cursor
320
+ * @ret rc		Return status code
321
+ */
322
+static int ocsp_parse_responses ( struct ocsp_check *ocsp,
323
+				  const struct asn1_cursor *raw ) {
324
+	struct ocsp_response *response = &ocsp->response;
325
+	struct asn1_cursor cursor;
326
+	int rc;
327
+
328
+	/* Enter responses */
329
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
330
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
331
+
332
+	/* Enter first singleResponse */
333
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
334
+
335
+	/* Parse certID */
336
+	if ( ( rc = ocsp_parse_cert_id ( ocsp, &cursor ) ) != 0 )
337
+		return rc;
338
+	asn1_skip_any ( &cursor );
339
+
340
+	/* Check certStatus */
341
+	if ( asn1_type ( &cursor ) != ASN1_IMPLICIT_TAG ( 0 ) ) {
342
+		DBGC ( ocsp, "OCSP %p \"%s\" non-good certStatus:\n",
343
+		       ocsp, ocsp->cert->subject.name );
344
+		DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
345
+		return -EACCES_CERT_STATUS;
346
+	}
347
+	asn1_skip_any ( &cursor );
348
+
349
+	/* Parse thisUpdate */
350
+	if ( ( rc = asn1_generalized_time ( &cursor,
351
+					    &response->this_update ) ) != 0 ) {
352
+		DBGC ( ocsp, "OCSP %p \"%s\" could not parse thisUpdate: %s\n",
353
+		       ocsp, ocsp->cert->subject.name, strerror ( rc ) );
354
+		return rc;
355
+	}
356
+	DBGC2 ( ocsp, "OCSP %p \"%s\" this update was at time %lld\n",
357
+		ocsp, ocsp->cert->subject.name, response->this_update );
358
+	asn1_skip_any ( &cursor );
359
+
360
+	/* Parse nextUpdate, if present */
361
+	if ( asn1_type ( &cursor ) == ASN1_EXPLICIT_TAG ( 0 ) ) {
362
+		asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
363
+		if ( ( rc = asn1_generalized_time ( &cursor,
364
+					     &response->next_update ) ) != 0 ) {
365
+			DBGC ( ocsp, "OCSP %p \"%s\" could not parse "
366
+			       "nextUpdate: %s\n", ocsp,
367
+			       ocsp->cert->subject.name, strerror ( rc ) );
368
+			return rc;
369
+		}
370
+		DBGC2 ( ocsp, "OCSP %p \"%s\" next update is at time %lld\n",
371
+			ocsp, ocsp->cert->subject.name, response->next_update );
372
+	} else {
373
+		/* If no nextUpdate is present, this indicates that
374
+		 * "newer revocation information is available all the
375
+		 * time".  Actually, this indicates that there is no
376
+		 * point to performing the OCSP check, since an
377
+		 * attacker could replay the response at any future
378
+		 * time and it would still be valid.
379
+		 */
380
+		DBGC ( ocsp, "OCSP %p \"%s\" responder is a moron\n",
381
+		       ocsp, ocsp->cert->subject.name );
382
+		response->next_update = time ( NULL );
383
+	}
384
+
385
+	return 0;
386
+}
387
+
388
+/**
389
+ * Parse OCSP response data
390
+ *
391
+ * @v ocsp		OCSP check
392
+ * @v raw		ASN.1 cursor
393
+ * @ret rc		Return status code
394
+ */
395
+static int ocsp_parse_tbs_response_data ( struct ocsp_check *ocsp,
396
+					  const struct asn1_cursor *raw ) {
397
+	struct ocsp_response *response = &ocsp->response;
398
+	struct asn1_cursor cursor;
399
+	int rc;
400
+
401
+	/* Record raw tbsResponseData */
402
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
403
+	asn1_shrink_any ( &cursor );
404
+	memcpy ( &response->tbs, &cursor, sizeof ( response->tbs ) );
405
+
406
+	/* Enter tbsResponseData */
407
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
408
+
409
+	/* Skip version, if present */
410
+	asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
411
+
412
+	/* Skip responderID */
413
+	asn1_skip_any ( &cursor );
414
+
415
+	/* Skip producedAt */
416
+	asn1_skip_any ( &cursor );
417
+
418
+	/* Parse responses */
419
+	if ( ( rc = ocsp_parse_responses ( ocsp, &cursor ) ) != 0 )
420
+		return rc;
421
+
422
+	return 0;
423
+}
424
+
425
+/**
426
+ * Parse OCSP certificates
427
+ *
428
+ * @v ocsp		OCSP check
429
+ * @v raw		ASN.1 cursor
430
+ * @ret rc		Return status code
431
+ */
432
+static int ocsp_parse_certs ( struct ocsp_check *ocsp,
433
+			      const struct asn1_cursor *raw ) {
434
+	struct ocsp_response *response = &ocsp->response;
435
+	struct asn1_cursor cursor;
436
+	int rc;
437
+
438
+	/* Enter certs */
439
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
440
+	asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
441
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
442
+
443
+	/* Parse certificate, if present.  The data structure permits
444
+	 * multiple certificates, but the protocol requires that the
445
+	 * OCSP signing certificate must either be the issuer itself,
446
+	 * or must be directly issued by the issuer (see RFC2560
447
+	 * section 4.2.2.2 "Authorized Responders").
448
+	 */
449
+	if ( ( cursor.len != 0 ) &&
450
+	     ( ( rc = x509_certificate ( cursor.data, cursor.len,
451
+					 &response->signer ) ) != 0 ) ) {
452
+		DBGC ( ocsp, "OCSP %p \"%s\" could not parse certificate: "
453
+		       "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc ));
454
+		DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
455
+		return rc;
456
+	}
457
+	DBGC2 ( ocsp, "OCSP %p \"%s\" response is signed by \"%s\"\n", ocsp,
458
+		ocsp->cert->subject.name, response->signer->subject.name );
459
+
460
+	return 0;
461
+}
462
+
463
+/**
464
+ * Parse OCSP basic response
465
+ *
466
+ * @v ocsp		OCSP check
467
+ * @v raw		ASN.1 cursor
468
+ * @ret rc		Return status code
469
+ */
470
+static int ocsp_parse_basic_response ( struct ocsp_check *ocsp,
471
+				       const struct asn1_cursor *raw ) {
472
+	struct ocsp_response *response = &ocsp->response;
473
+	struct asn1_algorithm **algorithm = &response->algorithm;
474
+	struct asn1_bit_string *signature = &response->signature;
475
+	struct asn1_cursor cursor;
476
+	int rc;
477
+
478
+	/* Enter BasicOCSPResponse */
479
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
480
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
481
+
482
+	/* Parse tbsResponseData */
483
+	if ( ( rc = ocsp_parse_tbs_response_data ( ocsp, &cursor ) ) != 0 )
484
+		return rc;
485
+	asn1_skip_any ( &cursor );
486
+
487
+	/* Parse signatureAlgorithm */
488
+	if ( ( rc = asn1_signature_algorithm ( &cursor, algorithm ) ) != 0 ) {
489
+		DBGC ( ocsp, "OCSP %p \"%s\" cannot parse signature "
490
+		       "algorithm: %s\n",
491
+		       ocsp, ocsp->cert->subject.name, strerror ( rc ) );
492
+		return rc;
493
+	}
494
+	DBGC2 ( ocsp, "OCSP %p \"%s\" signature algorithm is %s\n",
495
+		ocsp, ocsp->cert->subject.name, (*algorithm)->name );
496
+	asn1_skip_any ( &cursor );
497
+
498
+	/* Parse signature */
499
+	if ( ( rc = asn1_integral_bit_string ( &cursor, signature ) ) != 0 ) {
500
+		DBGC ( ocsp, "OCSP %p \"%s\" cannot parse signature: %s\n",
501
+		       ocsp, ocsp->cert->subject.name, strerror ( rc ) );
502
+		return rc;
503
+	}
504
+	asn1_skip_any ( &cursor );
505
+
506
+	/* Parse certs, if present */
507
+	if ( ( asn1_type ( &cursor ) == ASN1_EXPLICIT_TAG ( 0 ) ) &&
508
+	     ( ( rc = ocsp_parse_certs ( ocsp, &cursor ) ) != 0 ) )
509
+		return rc;
510
+
511
+	return 0;
512
+}
513
+
514
+/**
515
+ * Parse OCSP response bytes
516
+ *
517
+ * @v ocsp		OCSP check
518
+ * @v raw		ASN.1 cursor
519
+ * @ret rc		Return status code
520
+ */
521
+static int ocsp_parse_response_bytes ( struct ocsp_check *ocsp,
522
+				       const struct asn1_cursor *raw ) {
523
+	struct asn1_cursor cursor;
524
+	int rc;
525
+
526
+	/* Enter responseBytes */
527
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
528
+	asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
529
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
530
+
531
+	/* Parse responseType */
532
+	if ( ( rc = ocsp_parse_response_type ( ocsp, &cursor ) ) != 0 )
533
+		return rc;
534
+	asn1_skip_any ( &cursor );
535
+
536
+	/* Enter response */
537
+	asn1_enter ( &cursor, ASN1_OCTET_STRING );
538
+
539
+	/* Parse response */
540
+	if ( ( rc = ocsp_parse_basic_response ( ocsp, &cursor ) ) != 0 )
541
+		return rc;
542
+
543
+	return 0;
544
+}
545
+
546
+/**
547
+ * Parse OCSP response
548
+ *
549
+ * @v ocsp		OCSP check
550
+ * @v raw		ASN.1 cursor
551
+ * @ret rc		Return status code
552
+ */
553
+static int ocsp_parse_response ( struct ocsp_check *ocsp,
554
+				 const struct asn1_cursor *raw ) {
555
+	struct asn1_cursor cursor;
556
+	int rc;
557
+
558
+	/* Enter OCSPResponse */
559
+	memcpy ( &cursor, raw, sizeof ( cursor ) );
560
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
561
+
562
+	/* Parse responseStatus */
563
+	if ( ( rc = ocsp_parse_response_status ( ocsp, &cursor ) ) != 0 )
564
+		return rc;
565
+	asn1_skip_any ( &cursor );
566
+
567
+	/* Parse responseBytes */
568
+	if ( ( rc = ocsp_parse_response_bytes ( ocsp, &cursor ) ) != 0 )
569
+		return rc;
570
+
571
+	return 0;
572
+}
573
+
574
+/**
575
+ * Receive OCSP response
576
+ *
577
+ * @v ocsp		OCSP check
578
+ * @v data		Response data
579
+ * @v len		Length of response data
580
+ * @ret rc		Return status code
581
+ */
582
+int ocsp_response ( struct ocsp_check *ocsp, const void *data, size_t len ) {
583
+	struct ocsp_response *response = &ocsp->response;
584
+	struct asn1_cursor cursor;
585
+	int rc;
586
+
587
+	/* Duplicate data */
588
+	x509_put ( response->signer );
589
+	response->signer = NULL;
590
+	free ( response->data );
591
+	response->data = malloc ( len );
592
+	if ( ! response->data )
593
+		return -ENOMEM;
594
+	memcpy ( response->data, data, len );
595
+	cursor.data = response->data;
596
+	cursor.len = len;
597
+
598
+	/* Parse response */
599
+	if ( ( rc = ocsp_parse_response ( ocsp, &cursor ) ) != 0 )
600
+		return rc;
601
+
602
+	return 0;
603
+}
604
+
605
+/**
606
+ * OCSP dummy root certificate store
607
+ *
608
+ * OCSP validation uses no root certificates, since it takes place
609
+ * only when there already exists a validated issuer certificate.
610
+ */
611
+static struct x509_root ocsp_root = {
612
+	.digest = &ocsp_digest_algorithm,
613
+	.count = 0,
614
+	.fingerprints = NULL,
615
+};
616
+
617
+/**
618
+ * Check OCSP response signature
619
+ *
620
+ * @v ocsp		OCSP check
621
+ * @v signer		Signing certificate
622
+ * @ret rc		Return status code
623
+ */
624
+static int ocsp_check_signature ( struct ocsp_check *ocsp,
625
+				  struct x509_certificate *signer ) {
626
+	struct ocsp_response *response = &ocsp->response;
627
+	struct digest_algorithm *digest = response->algorithm->digest;
628
+	struct pubkey_algorithm *pubkey = response->algorithm->pubkey;
629
+	struct x509_public_key *public_key = &signer->subject.public_key;
630
+	uint8_t digest_ctx[ digest->ctxsize ];
631
+	uint8_t digest_out[ digest->digestsize ];
632
+	uint8_t pubkey_ctx[ pubkey->ctxsize ];
633
+	int rc;
634
+
635
+	/* Generate digest */
636
+	digest_init ( digest, digest_ctx );
637
+	digest_update ( digest, digest_ctx, response->tbs.data,
638
+			response->tbs.len );
639
+	digest_final ( digest, digest_ctx, digest_out );
640
+
641
+	/* Initialise public-key algorithm */
642
+	if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data,
643
+				  public_key->raw.len ) ) != 0 ) {
644
+		DBGC ( ocsp, "OCSP %p \"%s\" could not initialise public key: "
645
+		       "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc ));
646
+		goto err_init;
647
+	}
648
+
649
+	/* Verify digest */
650
+	if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out,
651
+				    response->signature.data,
652
+				    response->signature.len ) ) != 0 ) {
653
+		DBGC ( ocsp, "OCSP %p \"%s\" signature verification failed: "
654
+		       "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc ));
655
+		goto err_verify;
656
+	}
657
+
658
+	DBGC2 ( ocsp, "OCSP %p \"%s\" signature is correct\n",
659
+		ocsp, ocsp->cert->subject.name );
660
+
661
+ err_verify:
662
+	pubkey_final ( pubkey, pubkey_ctx );
663
+ err_init:
664
+	return rc;
665
+}
666
+
667
+/**
668
+ * Validate OCSP response
669
+ *
670
+ * @v ocsp		OCSP check
671
+ * @v time		Time at which to validate response
672
+ * @ret rc		Return status code
673
+ */
674
+int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) {
675
+	struct ocsp_response *response = &ocsp->response;
676
+	struct x509_certificate *signer = response->signer;
677
+	int rc;
678
+
679
+	/* Sanity checks */
680
+	assert ( response->data != NULL );
681
+	assert ( signer != NULL );
682
+
683
+	/* Validate signer, if applicable.  If the signer is not the
684
+	 * issuer, then it must be signed directly by the issuer.
685
+	 */
686
+	if ( signer != ocsp->issuer ) {
687
+		/* Forcibly invalidate the signer, since we need to
688
+		 * ensure that it was signed by our issuer (and not
689
+		 * some other issuer).  This prevents a sub-CA's OCSP
690
+		 * certificate from fraudulently signing OCSP
691
+		 * responses from the parent CA.
692
+		 */
693
+		x509_invalidate ( signer );
694
+		if ( ( rc = x509_validate ( signer, ocsp->issuer, time,
695
+					    &ocsp_root ) ) != 0 ) {
696
+			DBGC ( ocsp, "OCSP %p \"%s\" could not validate "
697
+			       "signer \"%s\": %s\n", ocsp,
698
+			       ocsp->cert->subject.name, signer->subject.name,
699
+			       strerror ( rc ) );
700
+			return rc;
701
+		}
702
+
703
+		/* If signer is not the issuer, then it must have the
704
+		 * extendedKeyUsage id-kp-OCSPSigning.
705
+		 */
706
+		if ( ! ( signer->extensions.ext_usage.bits &
707
+			 X509_OCSP_SIGNING ) ) {
708
+			DBGC ( ocsp, "OCSP %p \"%s\" signer \"%s\" is "
709
+			       "not an OCSP-signing certificate\n", ocsp,
710
+			       ocsp->cert->subject.name, signer->subject.name );
711
+			return -EACCES_NON_OCSP_SIGNING;
712
+		}
713
+	}
714
+
715
+	/* Check OCSP response signature */
716
+	if ( ( rc = ocsp_check_signature ( ocsp, signer ) ) != 0 )
717
+		return rc;
718
+
719
+	/* Check OCSP response is valid at the specified time
720
+	 * (allowing for some margin of error).
721
+	 */
722
+	if ( response->this_update > ( time - OCSP_ERROR_MARGIN_TIME ) ) {
723
+		DBGC ( ocsp, "OCSP %p \"%s\" response is not yet valid (at "
724
+		       "time %lld)\n", ocsp, ocsp->cert->subject.name, time );
725
+		return -EACCES_STALE;
726
+	}
727
+	if ( response->next_update < ( time + OCSP_ERROR_MARGIN_TIME ) ) {
728
+		DBGC ( ocsp, "OCSP %p \"%s\" response is stale (at time "
729
+		       "%lld)\n", ocsp, ocsp->cert->subject.name, time );
730
+		return -EACCES_STALE;
731
+	}
732
+	DBGC2 ( ocsp, "OCSP %p \"%s\" response is valid (at time %lld)\n",
733
+		ocsp, ocsp->cert->subject.name, time );
734
+
735
+	/* Mark certificate as passing OCSP verification */
736
+	ocsp->cert->extensions.auth_info.ocsp.good = 1;
737
+
738
+	/* Validate certificate against issuer */
739
+	if ( ( rc = x509_validate ( ocsp->cert, ocsp->issuer, time,
740
+				    &ocsp_root ) ) != 0 ) {
741
+		DBGC ( ocsp, "OCSP %p \"%s\" could not validate certificate: "
742
+		       "%s\n", ocsp, ocsp->cert->subject.name, strerror ( rc ));
743
+		return rc;
744
+	}
745
+	DBGC ( ocsp, "OCSP %p \"%s\" successfully validated using \"%s\"\n",
746
+	       ocsp, ocsp->cert->subject.name, signer->subject.name );
747
+
748
+	return 0;
749
+}

+ 3
- 3
src/crypto/x509.c Näytä tiedosto

@@ -1290,9 +1290,9 @@ int x509_check_time ( struct x509_certificate *cert, time_t time ) {
1290 1290
  * successfully validated then @c issuer, @c time, and @c root will be
1291 1291
  * ignored.
1292 1292
  */
1293
-static int x509_validate ( struct x509_certificate *cert,
1294
-			   struct x509_certificate *issuer,
1295
-			   time_t time, struct x509_root *root ) {
1293
+int x509_validate ( struct x509_certificate *cert,
1294
+		    struct x509_certificate *issuer,
1295
+		    time_t time, struct x509_root *root ) {
1296 1296
 	unsigned int max_path_remaining;
1297 1297
 	int rc;
1298 1298
 

+ 11
- 0
src/include/ipxe/asn1.h Näytä tiedosto

@@ -70,6 +70,9 @@ struct asn1_builder_header {
70 70
 /** ASN.1 object identifier */
71 71
 #define ASN1_OID 0x06
72 72
 
73
+/** ASN.1 enumeration */
74
+#define ASN1_ENUMERATED 0x0a
75
+
73 76
 /** ASN.1 UTC time */
74 77
 #define ASN1_UTC_TIME 0x17
75 78
 
@@ -204,6 +207,14 @@ struct asn1_builder_header {
204 207
 	ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ),		\
205 208
 	ASN1_OID_SINGLE ( 48 ), ASN1_OID_SINGLE ( 1 )
206 209
 
210
+/** ASN.1 OID for id-pkix-ocsp-basic ( 1.3.6.1.5.5.7.48.1.1) */
211
+#define ASN1_OID_OCSP_BASIC					\
212
+	ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 6 ),	\
213
+	ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 5 ),		\
214
+	ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ),		\
215
+	ASN1_OID_SINGLE ( 48 ), ASN1_OID_SINGLE ( 1 ),		\
216
+	ASN1_OID_SINGLE ( 1 )
217
+
207 218
 /** ASN.1 OID for id-kp-OCSPSigning (1.3.6.1.5.5.7.3.9) */
208 219
 #define ASN1_OID_OCSPSIGNING					\
209 220
 	ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 6 ),	\

+ 1
- 0
src/include/ipxe/errfile.h Näytä tiedosto

@@ -260,6 +260,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
260 260
 #define ERRFILE_menu_ui		      ( ERRFILE_OTHER | 0x002c0000 )
261 261
 #define ERRFILE_menu_cmd	      ( ERRFILE_OTHER | 0x002d0000 )
262 262
 #define ERRFILE_validator	      ( ERRFILE_OTHER | 0x002e0000 )
263
+#define ERRFILE_ocsp		      ( ERRFILE_OTHER | 0x002f0000 )
263 264
 
264 265
 /** @} */
265 266
 

+ 108
- 0
src/include/ipxe/ocsp.h Näytä tiedosto

@@ -0,0 +1,108 @@
1
+#ifndef _IPXE_OCSP_H
2
+#define _IPXE_OCSP_H
3
+
4
+/** @file
5
+ *
6
+ * Online Certificate Status Protocol
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+#include <stdarg.h>
13
+#include <time.h>
14
+#include <ipxe/asn1.h>
15
+#include <ipxe/x509.h>
16
+#include <ipxe/refcnt.h>
17
+
18
+/** OCSP algorithm identifier */
19
+#define OCSP_ALGORITHM_IDENTIFIER( ... )				\
20
+	ASN1_OID, VA_ARG_COUNT ( __VA_ARGS__ ), __VA_ARGS__,		\
21
+	ASN1_NULL, 0x00
22
+
23
+/* OCSP response statuses */
24
+#define OCSP_STATUS_SUCCESSFUL		0x00
25
+#define OCSP_STATUS_MALFORMED_REQUEST	0x01
26
+#define OCSP_STATUS_INTERNAL_ERROR	0x02
27
+#define OCSP_STATUS_TRY_LATER		0x03
28
+#define OCSP_STATUS_SIG_REQUIRED	0x05
29
+#define OCSP_STATUS_UNAUTHORIZED	0x06
30
+
31
+/** Margin of error allowed in OCSP response times
32
+ *
33
+ * We allow a generous margin of error: 12 hours to allow for the
34
+ * local time zone being non-GMT, plus 30 minutes to allow for general
35
+ * clock drift.
36
+ */
37
+#define OCSP_ERROR_MARGIN_TIME ( ( 12 * 60 + 30 ) * 60 )
38
+
39
+/** An OCSP request */
40
+struct ocsp_request {
41
+	/** Request builder */
42
+	struct asn1_builder builder;
43
+	/** Certificate ID */
44
+	struct asn1_cursor cert_id;
45
+};
46
+
47
+/** An OCSP response */
48
+struct ocsp_response {
49
+	/** Raw response */
50
+	void *data;
51
+	/** Raw tbsResponseData */
52
+	struct asn1_cursor tbs;
53
+	/** Time at which status is known to be correct */
54
+	time_t this_update;
55
+	/** Time at which newer status information will be available */
56
+	time_t next_update;
57
+	/** Signature algorithm */
58
+	struct asn1_algorithm *algorithm;
59
+	/** Signature value */
60
+	struct asn1_bit_string signature;
61
+	/** Signing certificate */
62
+	struct x509_certificate *signer;
63
+};
64
+
65
+/** An OCSP check */
66
+struct ocsp_check {
67
+	/** Reference count */
68
+	struct refcnt refcnt;
69
+	/** Certificate being checked */
70
+	struct x509_certificate *cert;
71
+	/** Issuing certificate */
72
+	struct x509_certificate *issuer;
73
+	/** Request */
74
+	struct ocsp_request request;
75
+	/** Response */
76
+	struct ocsp_response response;
77
+};
78
+
79
+/**
80
+ * Get reference to OCSP check
81
+ *
82
+ * @v ocsp		OCSP check
83
+ * @ret ocsp		OCSP check
84
+ */
85
+static inline __attribute__ (( always_inline )) struct ocsp_check *
86
+ocsp_get ( struct ocsp_check *ocsp ) {
87
+	ref_get ( &ocsp->refcnt );
88
+	return ocsp;
89
+}
90
+
91
+/**
92
+ * Drop reference to OCSP check
93
+ *
94
+ * @v ocsp		OCSP check
95
+ */
96
+static inline __attribute__ (( always_inline )) void
97
+ocsp_put ( struct ocsp_check *ocsp ) {
98
+	ref_put ( &ocsp->refcnt );
99
+}
100
+
101
+extern int ocsp_check ( struct x509_certificate *cert,
102
+			struct x509_certificate *issuer,
103
+			struct ocsp_check **ocsp );
104
+extern int ocsp_response ( struct ocsp_check *ocsp, const void *data,
105
+			   size_t len );
106
+extern int ocsp_validate ( struct ocsp_check *check, time_t time );
107
+
108
+#endif /* _IPXE_OCSP_H */

+ 5
- 0
src/include/ipxe/x509.h Näytä tiedosto

@@ -126,6 +126,8 @@ enum x509_extended_key_usage_bits {
126 126
 struct x509_ocsp_responder {
127 127
 	/** URI */
128 128
 	char *uri;
129
+	/** OCSP status is good */
130
+	int good;
129 131
 };
130 132
 
131 133
 /** X.509 certificate authority information access */
@@ -322,6 +324,9 @@ struct x509_root {
322 324
 
323 325
 extern int x509_certificate ( const void *data, size_t len,
324 326
 			      struct x509_certificate **cert );
327
+extern int x509_validate ( struct x509_certificate *cert,
328
+			   struct x509_certificate *issuer,
329
+			   time_t time, struct x509_root *root );
325 330
 
326 331
 extern struct x509_chain * x509_alloc_chain ( void );
327 332
 extern int x509_append ( struct x509_chain *chain,

Loading…
Peruuta
Tallenna