]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
TLS client: Multi-OCSP check to cover intermediate CAs
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 22 Dec 2015 22:00:13 +0000 (00:00 +0200)
committerJouni Malinen <j@w1.fi>
Wed, 23 Dec 2015 22:54:30 +0000 (00:54 +0200)
This extends multi-OCSP support to verify status for intermediate CAs in
the server certificate chain.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/crypto/tls_internal.c
src/tls/tlsv1_client_ocsp.c
src/tls/tlsv1_client_read.c
src/tls/x509v3.c
src/tls/x509v3.h

index 0d8f1db647685b3db38606bdbb967f9513541a41..01a7c97de3e611c15cbe8ec24cb51603a045815f 100644 (file)
@@ -200,12 +200,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
        if (conn->client == NULL)
                return -1;
 
-       if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
-               wpa_printf(MSG_INFO,
-                          "TLS: ocsp=3 not supported");
-               return -1;
-       }
-
        if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
                wpa_printf(MSG_INFO,
                           "TLS: tls_ext_cert_check=1 not supported");
index 2d5cdb94aa9bdfd12c30ca9788cbe888d5804be2..1d7b68ca286ed51b1f412353686c2d6210ad6889 100644 (file)
@@ -316,6 +316,7 @@ static int tls_process_ocsp_single_response(struct tlsv1_client *conn,
 
 static enum tls_ocsp_result
 tls_process_ocsp_responses(struct tlsv1_client *conn,
+                          struct x509_certificate *cert,
                           struct x509_certificate *issuer, const u8 *resp,
                           size_t len)
 {
@@ -335,8 +336,7 @@ tls_process_ocsp_responses(struct tlsv1_client *conn,
                                   hdr.class, hdr.tag);
                        return TLS_OCSP_INVALID;
                }
-               if (tls_process_ocsp_single_response(conn, conn->server_cert,
-                                                    issuer,
+               if (tls_process_ocsp_single_response(conn, cert, issuer,
                                                     hdr.payload, hdr.length,
                                                     &res) == 0)
                        return res;
@@ -350,8 +350,9 @@ tls_process_ocsp_responses(struct tlsv1_client *conn,
 
 
 static enum tls_ocsp_result
-tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp,
-                               size_t len)
+tls_process_basic_ocsp_response(struct tlsv1_client *conn,
+                               struct x509_certificate *srv_cert,
+                               const u8 *resp, size_t len)
 {
        struct asn1_hdr hdr;
        const u8 *pos, *end;
@@ -365,6 +366,7 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp,
        struct x509_name name; /* used if key_hash == NULL */
        char buf[100];
        os_time_t produced_at;
+       enum tls_ocsp_result res;
 
        wpa_hexdump(MSG_MSGDUMP, "OCSP: BasicOCSPResponse", resp, len);
 
@@ -594,20 +596,20 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp,
                /* Ignore for now. */
        }
 
-       if (!conn->server_cert) {
+       if (!srv_cert) {
                wpa_printf(MSG_DEBUG,
                           "OCSP: Server certificate not known - cannot check OCSP response");
                goto no_resp;
        }
 
-       if (conn->server_cert->next) {
+       if (srv_cert->next) {
                /* Issuer has already been verified in the chain */
-               issuer = conn->server_cert->next;
+               issuer = srv_cert->next;
        } else {
                /* Find issuer from the set of trusted certificates */
                for (issuer = conn->cred ? conn->cred->trusted_certs : NULL;
                     issuer; issuer = issuer->next) {
-                       if (x509_name_compare(&conn->server_cert->issuer,
+                       if (x509_name_compare(&srv_cert->issuer,
                                              &issuer->subject) == 0)
                                break;
                }
@@ -625,7 +627,7 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp,
        } else {
                for (signer = certs; signer; signer = signer->next) {
                        if (!ocsp_responder_id_match(signer, &name, key_hash) ||
-                           x509_name_compare(&conn->server_cert->issuer,
+                           x509_name_compare(&srv_cert->issuer,
                                              &issuer->subject) != 0 ||
                            !(signer->ext_key_usage &
                              X509_EXT_KEY_USAGE_OCSP) ||
@@ -654,8 +656,13 @@ tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp,
                    return TLS_OCSP_INVALID;
        }
 
-       return tls_process_ocsp_responses(conn, issuer, responses,
-                                         responses_len);
+       res = tls_process_ocsp_responses(conn, srv_cert, issuer,
+                                        responses, responses_len);
+       if (res == TLS_OCSP_REVOKED)
+               srv_cert->ocsp_revoked = 1;
+       else if (res == TLS_OCSP_GOOD)
+               srv_cert->ocsp_good = 1;
+       return res;
 
 no_resp:
        x509_free_name(&name);
@@ -677,6 +684,9 @@ enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
        u8 resp_status;
        struct asn1_oid oid;
        char obuf[80];
+       struct x509_certificate *cert;
+       enum tls_ocsp_result res = TLS_OCSP_NO_RESPONSE;
+       enum tls_ocsp_result res_first = res;
 
        wpa_hexdump(MSG_MSGDUMP, "TLSv1: OCSPResponse", resp, len);
 
@@ -769,5 +779,25 @@ enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
                return TLS_OCSP_INVALID;
        }
 
-       return tls_process_basic_ocsp_response(conn, hdr.payload, hdr.length);
+       cert = conn->server_cert;
+       while (cert) {
+               if (!cert->ocsp_good && !cert->ocsp_revoked) {
+                       char sbuf[128];
+
+                       x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
+                       wpa_printf(MSG_DEBUG,
+                                  "OCSP: Trying to find certificate status for %s",
+                                  sbuf);
+
+                       res = tls_process_basic_ocsp_response(conn, cert,
+                                                             hdr.payload,
+                                                             hdr.length);
+                       if (cert == conn->server_cert)
+                               res_first = res;
+               }
+               if (res == TLS_OCSP_REVOKED || cert->issuer_trusted)
+                       break;
+               cert = cert->next;
+       }
+       return res == TLS_OCSP_REVOKED ? res : res_first;
 }
index ab0d9d76f13f45181cbd77e35708b88f21aca1ef..89ef196dee65001553aaa9db34fd46c136b91e96 100644 (file)
@@ -822,6 +822,8 @@ static int tls_process_certificate_status(struct tlsv1_client *conn, u8 ct,
        size_t left, len;
        u8 type, status_type;
        enum tls_ocsp_result res;
+       struct x509_certificate *cert;
+       int depth;
 
        if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
                wpa_printf(MSG_DEBUG,
@@ -955,13 +957,39 @@ done:
        if (res == TLS_OCSP_REVOKED) {
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
                          TLS_ALERT_CERTIFICATE_REVOKED);
-               if (conn->server_cert)
-                       tls_cert_chain_failure_event(
-                               conn, 0, conn->server_cert, TLS_FAIL_REVOKED,
-                               "certificate revoked");
+               for (cert = conn->server_cert, depth = 0; cert;
+                    cert = cert->next, depth++) {
+                       if (cert->ocsp_revoked) {
+                               tls_cert_chain_failure_event(
+                                       conn, depth, cert, TLS_FAIL_REVOKED,
+                                       "certificate revoked");
+                       }
+               }
                return -1;
        }
 
+       if (conn->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+               /*
+                * Verify that each certificate on the chain that is not part
+                * of the trusted certificates has a good status. If not,
+                * terminate handshake.
+                */
+               for (cert = conn->server_cert, depth = 0; cert;
+                    cert = cert->next, depth++) {
+                       if (!cert->ocsp_good) {
+                               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                         TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+                               tls_cert_chain_failure_event(
+                                       conn, depth, cert,
+                                       TLS_FAIL_UNSPECIFIED,
+                                       "bad certificate status response");
+                               return -1;
+                       }
+                       if (cert->issuer_trusted)
+                               break;
+               }
+       }
+
        if ((conn->flags & TLS_CONN_REQUIRE_OCSP) && res != TLS_OCSP_GOOD) {
                tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
                          res == TLS_OCSP_INVALID ? TLS_ALERT_DECODE_ERROR :
index 55555254ea41af1be116677bd757137c6a8f03ec..75f222c4f2495a96b61d51a94239e48a9c37d5c7 100644 (file)
@@ -2038,6 +2038,7 @@ int x509_certificate_chain_validate(struct x509_certificate *trusted,
        os_get_time(&now);
 
        for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
+               cert->issuer_trusted = 0;
                x509_name_string(&cert->subject, buf, sizeof(buf)); 
                wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
 
@@ -2123,6 +2124,7 @@ int x509_certificate_chain_validate(struct x509_certificate *trusted,
 
                        wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
                                   "found to complete the chain");
+                       cert->issuer_trusted = 1;
                        chain_trusted = 1;
                }
        }
index dcdb4a30f0c0f1d04646b731bca7a4166f72f9e3..7df8e2ab0870c9359c16c33118c480856bb864ff 100644 (file)
@@ -106,6 +106,11 @@ struct x509_certificate {
        size_t cert_len;
        const u8 *tbs_cert_start;
        size_t tbs_cert_len;
+
+       /* Meta data used for certificate validation */
+       unsigned int ocsp_good:1;
+       unsigned int ocsp_revoked:1;
+       unsigned int issuer_trusted:1;
 };
 
 enum {