Browse Source

[ocsp] Accept response certID with missing hashAlgorithm parameters

One of the design goals of ASN.1 DER is to provide a canonical
serialization of a data structure, thereby allowing for equality of
values to be tested by simply comparing the serialized bytes.

Some OCSP servers will modify the request certID to omit the optional
(and null) "parameters" portion of the hashAlgorithm.  This is
arguably legal but breaks the ability to perform a straightforward
bitwise comparison on the entire certID field between request and
response.

Fix by comparing the OID-identified hashAlgorithm separately from the
remaining certID fields.

Originally-fixed-by: Thilo Fromm <Thilo@kinvolk.io>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 5 years ago
parent
commit
b6ffe28a21
2 changed files with 32 additions and 14 deletions
  1. 30
    12
      src/crypto/ocsp.c
  2. 2
    2
      src/include/ipxe/ocsp.h

+ 30
- 12
src/crypto/ocsp.c View File

145
 static int ocsp_request ( struct ocsp_check *ocsp ) {
145
 static int ocsp_request ( struct ocsp_check *ocsp ) {
146
 	struct digest_algorithm *digest = &ocsp_digest_algorithm;
146
 	struct digest_algorithm *digest = &ocsp_digest_algorithm;
147
 	struct asn1_builder *builder = &ocsp->request.builder;
147
 	struct asn1_builder *builder = &ocsp->request.builder;
148
-	struct asn1_cursor *cert_id = &ocsp->request.cert_id;
148
+	struct asn1_cursor *cert_id_tail = &ocsp->request.cert_id_tail;
149
 	uint8_t digest_ctx[digest->ctxsize];
149
 	uint8_t digest_ctx[digest->ctxsize];
150
 	uint8_t name_digest[digest->digestsize];
150
 	uint8_t name_digest[digest->digestsize];
151
 	uint8_t pubkey_digest[digest->digestsize];
151
 	uint8_t pubkey_digest[digest->digestsize];
186
 	DBGC2_HDA ( ocsp, 0, builder->data, builder->len );
186
 	DBGC2_HDA ( ocsp, 0, builder->data, builder->len );
187
 
187
 
188
 	/* Parse certificate ID for comparison with response */
188
 	/* Parse certificate ID for comparison with response */
189
-	cert_id->data = builder->data;
190
-	cert_id->len = builder->len;
191
-	if ( ( rc = ( asn1_enter ( cert_id, ASN1_SEQUENCE ),
192
-		      asn1_enter ( cert_id, ASN1_SEQUENCE ),
193
-		      asn1_enter ( cert_id, ASN1_SEQUENCE ),
194
-		      asn1_enter ( cert_id, ASN1_SEQUENCE ) ) ) != 0 ) {
189
+	cert_id_tail->data = builder->data;
190
+	cert_id_tail->len = builder->len;
191
+	if ( ( rc = ( asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
192
+		      asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
193
+		      asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
194
+		      asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
195
+		      asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
196
+		      asn1_skip ( cert_id_tail, ASN1_SEQUENCE ) ) ) != 0 ) {
195
 		DBGC ( ocsp, "OCSP %p \"%s\" could not locate certID: %s\n",
197
 		DBGC ( ocsp, "OCSP %p \"%s\" could not locate certID: %s\n",
196
 		       ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
198
 		       ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
197
 		return rc;
199
 		return rc;
475
 static int ocsp_parse_cert_id ( struct ocsp_check *ocsp,
477
 static int ocsp_parse_cert_id ( struct ocsp_check *ocsp,
476
 				const struct asn1_cursor *raw ) {
478
 				const struct asn1_cursor *raw ) {
477
 	struct asn1_cursor cursor;
479
 	struct asn1_cursor cursor;
480
+	struct asn1_algorithm *algorithm;
481
+	int rc;
478
 
482
 
479
-	/* Check certID matches request */
483
+	/* Check certID algorithm */
480
 	memcpy ( &cursor, raw, sizeof ( cursor ) );
484
 	memcpy ( &cursor, raw, sizeof ( cursor ) );
481
-	asn1_shrink_any ( &cursor );
482
-	if ( asn1_compare ( &cursor, &ocsp->request.cert_id ) != 0 ) {
485
+	asn1_enter ( &cursor, ASN1_SEQUENCE );
486
+	if ( ( rc = asn1_digest_algorithm ( &cursor, &algorithm ) ) != 0 ) {
487
+		DBGC ( ocsp, "OCSP %p \"%s\" certID unknown algorithm: %s\n",
488
+		       ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
489
+		return rc;
490
+	}
491
+	if ( algorithm->digest != &ocsp_digest_algorithm ) {
492
+		DBGC ( ocsp, "OCSP %p \"%s\" certID wrong algorithm %s\n",
493
+		       ocsp, x509_name ( ocsp->cert ),
494
+		       algorithm->digest->name );
495
+		return -EACCES_CERT_MISMATCH;
496
+	}
497
+
498
+	/* Check remaining certID fields */
499
+	asn1_skip ( &cursor, ASN1_SEQUENCE );
500
+	if ( asn1_compare ( &cursor, &ocsp->request.cert_id_tail ) != 0 ) {
483
 		DBGC ( ocsp, "OCSP %p \"%s\" certID mismatch:\n",
501
 		DBGC ( ocsp, "OCSP %p \"%s\" certID mismatch:\n",
484
 		       ocsp, x509_name ( ocsp->cert ) );
502
 		       ocsp, x509_name ( ocsp->cert ) );
485
-		DBGC_HDA ( ocsp, 0, ocsp->request.cert_id.data,
486
-			   ocsp->request.cert_id.len );
503
+		DBGC_HDA ( ocsp, 0, ocsp->request.cert_id_tail.data,
504
+			   ocsp->request.cert_id_tail.len );
487
 		DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
505
 		DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
488
 		return -EACCES_CERT_MISMATCH;
506
 		return -EACCES_CERT_MISMATCH;
489
 	}
507
 	}

+ 2
- 2
src/include/ipxe/ocsp.h View File

42
 struct ocsp_request {
42
 struct ocsp_request {
43
 	/** Request builder */
43
 	/** Request builder */
44
 	struct asn1_builder builder;
44
 	struct asn1_builder builder;
45
-	/** Certificate ID */
46
-	struct asn1_cursor cert_id;
45
+	/** Certificate ID (excluding hashAlgorithm) */
46
+	struct asn1_cursor cert_id_tail;
47
 };
47
 };
48
 
48
 
49
 /** An OCSP responder */
49
 /** An OCSP responder */

Loading…
Cancel
Save