]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[ocsp] Accept response certID with missing hashAlgorithm parameters
authorMichael Brown <mcb30@ipxe.org>
Sun, 10 Mar 2019 17:58:56 +0000 (17:58 +0000)
committerMichael Brown <mcb30@ipxe.org>
Sun, 10 Mar 2019 18:13:52 +0000 (18:13 +0000)
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>
src/crypto/ocsp.c
src/include/ipxe/ocsp.h

index b83f4c035b8b5b44981dffe8773f7a82b538e2c4..2c747fb39728ff6a3a18301badf78f95cc24d9fe 100644 (file)
@@ -145,7 +145,7 @@ static void ocsp_free ( struct refcnt *refcnt ) {
 static int ocsp_request ( struct ocsp_check *ocsp ) {
        struct digest_algorithm *digest = &ocsp_digest_algorithm;
        struct asn1_builder *builder = &ocsp->request.builder;
-       struct asn1_cursor *cert_id = &ocsp->request.cert_id;
+       struct asn1_cursor *cert_id_tail = &ocsp->request.cert_id_tail;
        uint8_t digest_ctx[digest->ctxsize];
        uint8_t name_digest[digest->digestsize];
        uint8_t pubkey_digest[digest->digestsize];
@@ -186,12 +186,14 @@ static int ocsp_request ( struct ocsp_check *ocsp ) {
        DBGC2_HDA ( ocsp, 0, builder->data, builder->len );
 
        /* Parse certificate ID for comparison with response */
-       cert_id->data = builder->data;
-       cert_id->len = builder->len;
-       if ( ( rc = ( asn1_enter ( cert_id, ASN1_SEQUENCE ),
-                     asn1_enter ( cert_id, ASN1_SEQUENCE ),
-                     asn1_enter ( cert_id, ASN1_SEQUENCE ),
-                     asn1_enter ( cert_id, ASN1_SEQUENCE ) ) ) != 0 ) {
+       cert_id_tail->data = builder->data;
+       cert_id_tail->len = builder->len;
+       if ( ( rc = ( asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
+                     asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
+                     asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
+                     asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
+                     asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
+                     asn1_skip ( cert_id_tail, ASN1_SEQUENCE ) ) ) != 0 ) {
                DBGC ( ocsp, "OCSP %p \"%s\" could not locate certID: %s\n",
                       ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
                return rc;
@@ -475,15 +477,31 @@ static int ocsp_parse_responder_id ( struct ocsp_check *ocsp,
 static int ocsp_parse_cert_id ( struct ocsp_check *ocsp,
                                const struct asn1_cursor *raw ) {
        struct asn1_cursor cursor;
+       struct asn1_algorithm *algorithm;
+       int rc;
 
-       /* Check certID matches request */
+       /* Check certID algorithm */
        memcpy ( &cursor, raw, sizeof ( cursor ) );
-       asn1_shrink_any ( &cursor );
-       if ( asn1_compare ( &cursor, &ocsp->request.cert_id ) != 0 ) {
+       asn1_enter ( &cursor, ASN1_SEQUENCE );
+       if ( ( rc = asn1_digest_algorithm ( &cursor, &algorithm ) ) != 0 ) {
+               DBGC ( ocsp, "OCSP %p \"%s\" certID unknown algorithm: %s\n",
+                      ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
+               return rc;
+       }
+       if ( algorithm->digest != &ocsp_digest_algorithm ) {
+               DBGC ( ocsp, "OCSP %p \"%s\" certID wrong algorithm %s\n",
+                      ocsp, x509_name ( ocsp->cert ),
+                      algorithm->digest->name );
+               return -EACCES_CERT_MISMATCH;
+       }
+
+       /* Check remaining certID fields */
+       asn1_skip ( &cursor, ASN1_SEQUENCE );
+       if ( asn1_compare ( &cursor, &ocsp->request.cert_id_tail ) != 0 ) {
                DBGC ( ocsp, "OCSP %p \"%s\" certID mismatch:\n",
                       ocsp, x509_name ( ocsp->cert ) );
-               DBGC_HDA ( ocsp, 0, ocsp->request.cert_id.data,
-                          ocsp->request.cert_id.len );
+               DBGC_HDA ( ocsp, 0, ocsp->request.cert_id_tail.data,
+                          ocsp->request.cert_id_tail.len );
                DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
                return -EACCES_CERT_MISMATCH;
        }
index be0bddc50e100d30402e4fd447883c1a85ffb42f..9eb70b2cc4685a474d057d5c66644f1301dd5122 100644 (file)
@@ -42,8 +42,8 @@ struct ocsp_check;
 struct ocsp_request {
        /** Request builder */
        struct asn1_builder builder;
-       /** Certificate ID */
-       struct asn1_cursor cert_id;
+       /** Certificate ID (excluding hashAlgorithm) */
+       struct asn1_cursor cert_id_tail;
 };
 
 /** An OCSP responder */