diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c index 0d8f1db64..01a7c97de 100644 --- a/src/crypto/tls_internal.c +++ b/src/crypto/tls_internal.c @@ -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"); diff --git a/src/tls/tlsv1_client_ocsp.c b/src/tls/tlsv1_client_ocsp.c index 2d5cdb94a..1d7b68ca2 100644 --- a/src/tls/tlsv1_client_ocsp.c +++ b/src/tls/tlsv1_client_ocsp.c @@ -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; } diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c index ab0d9d76f..89ef196de 100644 --- a/src/tls/tlsv1_client_read.c +++ b/src/tls/tlsv1_client_read.c @@ -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 : diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c index 55555254e..75f222c4f 100644 --- a/src/tls/x509v3.c +++ b/src/tls/x509v3.c @@ -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; } } diff --git a/src/tls/x509v3.h b/src/tls/x509v3.h index dcdb4a30f..7df8e2ab0 100644 --- a/src/tls/x509v3.h +++ b/src/tls/x509v3.h @@ -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 {