aboutsummaryrefslogtreecommitdiffstats
path: root/src/tls
diff options
context:
space:
mode:
authorJouni Malinen <jouni@qca.qualcomm.com>2015-12-22 22:00:13 (GMT)
committerJouni Malinen <j@w1.fi>2015-12-23 22:54:30 (GMT)
commit0764dd6849d295cf2922cd45158e73e44c07dd31 (patch)
tree8d5470b7ecf995164964f3c655a3de50a759cd56 /src/tls
parentd6b536f7e576d06e91b0cd7669eb2b73954826f6 (diff)
downloadhostap-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.c54
-rw-r--r--src/tls/tlsv1_client_read.c36
-rw-r--r--src/tls/x509v3.c2
-rw-r--r--src/tls/x509v3.h5
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 {