diff options
author | Jouni Malinen <jouni@qca.qualcomm.com> | 2015-12-22 22:00:13 (GMT) |
---|---|---|
committer | Jouni Malinen <j@w1.fi> | 2015-12-23 22:54:30 (GMT) |
commit | 0764dd6849d295cf2922cd45158e73e44c07dd31 (patch) | |
tree | 8d5470b7ecf995164964f3c655a3de50a759cd56 /src/tls | |
parent | d6b536f7e576d06e91b0cd7669eb2b73954826f6 (diff) | |
download | hostap-0764dd6849d295cf2922cd45158e73e44c07dd31.zip hostap-0764dd6849d295cf2922cd45158e73e44c07dd31.tar.gz hostap-0764dd6849d295cf2922cd45158e73e44c07dd31.tar.bz2 |
TLS client: Multi-OCSP check to cover intermediate CAs
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>
Diffstat (limited to 'src/tls')
-rw-r--r-- | src/tls/tlsv1_client_ocsp.c | 54 | ||||
-rw-r--r-- | src/tls/tlsv1_client_read.c | 36 | ||||
-rw-r--r-- | src/tls/x509v3.c | 2 | ||||
-rw-r--r-- | src/tls/x509v3.h | 5 |
4 files changed, 81 insertions, 16 deletions
diff --git a/src/tls/tlsv1_client_ocsp.c b/src/tls/tlsv1_client_ocsp.c index 2d5cdb9..1d7b68c 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 ab0d9d7..89ef196 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 5555525..75f222c 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 dcdb4a3..7df8e2a 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 { |