summaryrefslogtreecommitdiffstats
path: root/contrib/wpa/src/tls/tlsv1_client_read.c
diff options
context:
space:
mode:
authorRenato Botelho <renato@netgate.com>2019-05-15 08:43:46 -0300
committerRenato Botelho <renato@netgate.com>2019-05-15 08:43:46 -0300
commit4a2bfdce1333812530dc82117658c9fdcdbd5632 (patch)
tree3cfcd3cc8bf04122ea5b0c40c8f03397af2d5b90 /contrib/wpa/src/tls/tlsv1_client_read.c
parentfed039d3092243b82f8b05665ff26c241f04f948 (diff)
parent03a7fd6cb603ce806894914f45b7c0d0c453ad50 (diff)
downloadFreeBSD-src-4a2bfdce1333812530dc82117658c9fdcdbd5632.zip
FreeBSD-src-4a2bfdce1333812530dc82117658c9fdcdbd5632.tar.gz
Merge remote-tracking branch 'origin/releng/11.2' into RELENG_2_4_4
Diffstat (limited to 'contrib/wpa/src/tls/tlsv1_client_read.c')
-rw-r--r--contrib/wpa/src/tls/tlsv1_client_read.c496
1 files changed, 477 insertions, 19 deletions
diff --git a/contrib/wpa/src/tls/tlsv1_client_read.c b/contrib/wpa/src/tls/tlsv1_client_read.c
index 9ce9680..80874e5 100644
--- a/contrib/wpa/src/tls/tlsv1_client_read.c
+++ b/contrib/wpa/src/tls/tlsv1_client_read.c
@@ -1,6 +1,6 @@
/*
* TLSv1 client - read handshake message
- * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -27,6 +27,54 @@ static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len);
+static int tls_version_disabled(struct tlsv1_client *conn, u16 ver)
+{
+ return (((conn->flags & TLS_CONN_DISABLE_TLSv1_0) &&
+ ver == TLS_VERSION_1) ||
+ ((conn->flags & TLS_CONN_DISABLE_TLSv1_1) &&
+ ver == TLS_VERSION_1_1) ||
+ ((conn->flags & TLS_CONN_DISABLE_TLSv1_2) &&
+ ver == TLS_VERSION_1_2));
+}
+
+
+static int tls_process_server_hello_extensions(struct tlsv1_client *conn,
+ const u8 *pos, size_t len)
+{
+ const u8 *end = pos + len;
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello extensions",
+ pos, len);
+ while (pos < end) {
+ u16 ext, elen;
+
+ if (end - pos < 4) {
+ wpa_printf(MSG_INFO, "TLSv1: Truncated ServerHello extension header");
+ return -1;
+ }
+
+ ext = WPA_GET_BE16(pos);
+ pos += 2;
+ elen = WPA_GET_BE16(pos);
+ pos += 2;
+
+ if (elen > end - pos) {
+ wpa_printf(MSG_INFO, "TLSv1: Truncated ServerHello extension");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: ServerHello ExtensionType %u",
+ ext);
+ wpa_hexdump(MSG_DEBUG, "TLSv1: ServerHello extension data",
+ pos, elen);
+
+ pos += elen;
+ }
+
+ return 0;
+}
+
+
static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -76,7 +124,8 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
if (end - pos < 2)
goto decode_error;
tls_version = WPA_GET_BE16(pos);
- if (!tls_version_ok(tls_version)) {
+ if (!tls_version_ok(tls_version) ||
+ tls_version_disabled(conn, tls_version)) {
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
"ServerHello %u.%u", pos[0], pos[1]);
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -165,8 +214,24 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
}
pos++;
+ if (end - pos >= 2) {
+ u16 ext_len;
+
+ ext_len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < ext_len) {
+ wpa_printf(MSG_INFO,
+ "TLSv1: Invalid ServerHello extension length: %u (left: %u)",
+ ext_len, (unsigned int) (end - pos));
+ goto decode_error;
+ }
+
+ if (tls_process_server_hello_extensions(conn, pos, ext_len))
+ goto decode_error;
+ pos += ext_len;
+ }
+
if (end != pos) {
- /* TODO: ServerHello extensions */
wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
"end of ServerHello", pos, end - pos);
goto decode_error;
@@ -211,6 +276,73 @@ decode_error:
}
+static void tls_peer_cert_event(struct tlsv1_client *conn, int depth,
+ struct x509_certificate *cert)
+{
+ union tls_event_data ev;
+ struct wpabuf *cert_buf = NULL;
+#ifdef CONFIG_SHA256
+ u8 hash[32];
+#endif /* CONFIG_SHA256 */
+ char subject[128];
+
+ if (!conn->event_cb)
+ return;
+
+ os_memset(&ev, 0, sizeof(ev));
+ if ((conn->cred && conn->cred->cert_probe) || conn->cert_in_cb) {
+ cert_buf = wpabuf_alloc_copy(cert->cert_start,
+ cert->cert_len);
+ ev.peer_cert.cert = cert_buf;
+ }
+#ifdef CONFIG_SHA256
+ if (cert_buf) {
+ const u8 *addr[1];
+ size_t len[1];
+ addr[0] = wpabuf_head(cert_buf);
+ len[0] = wpabuf_len(cert_buf);
+ if (sha256_vector(1, addr, len, hash) == 0) {
+ ev.peer_cert.hash = hash;
+ ev.peer_cert.hash_len = sizeof(hash);
+ }
+ }
+#endif /* CONFIG_SHA256 */
+
+ ev.peer_cert.depth = depth;
+ x509_name_string(&cert->subject, subject, sizeof(subject));
+ ev.peer_cert.subject = subject;
+
+ conn->event_cb(conn->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+ wpabuf_free(cert_buf);
+}
+
+
+static void tls_cert_chain_failure_event(struct tlsv1_client *conn, int depth,
+ struct x509_certificate *cert,
+ enum tls_fail_reason reason,
+ const char *reason_txt)
+{
+ struct wpabuf *cert_buf = NULL;
+ union tls_event_data ev;
+ char subject[128];
+
+ if (!conn->event_cb || !cert)
+ return;
+
+ os_memset(&ev, 0, sizeof(ev));
+ ev.cert_fail.depth = depth;
+ x509_name_string(&cert->subject, subject, sizeof(subject));
+ ev.peer_cert.subject = subject;
+ ev.cert_fail.reason = reason;
+ ev.cert_fail.reason_txt = reason_txt;
+ cert_buf = wpabuf_alloc_copy(cert->cert_start,
+ cert->cert_len);
+ ev.cert_fail.cert = cert_buf;
+ conn->event_cb(conn->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+ wpabuf_free(cert_buf);
+}
+
+
static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -354,6 +486,8 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
return -1;
}
+ tls_peer_cert_event(conn, idx, cert);
+
if (last == NULL)
chain = cert;
else
@@ -364,31 +498,99 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
pos += cert_len;
}
- if (conn->cred &&
- x509_certificate_chain_validate(conn->cred->trusted_certs, chain,
- &reason, conn->disable_time_checks)
- < 0) {
+ if (conn->cred && conn->cred->server_cert_only && chain) {
+ u8 hash[SHA256_MAC_LEN];
+ char buf[128];
+
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Validate server certificate hash");
+ x509_name_string(&chain->subject, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "TLSv1: 0: %s", buf);
+ if (sha256_vector(1, &chain->cert_start, &chain->cert_len,
+ hash) < 0 ||
+ os_memcmp(conn->cred->srv_cert_hash, hash,
+ SHA256_MAC_LEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Server certificate hash mismatch");
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: SHA256 hash",
+ hash, SHA256_MAC_LEN);
+ if (conn->event_cb) {
+ union tls_event_data ev;
+
+ os_memset(&ev, 0, sizeof(ev));
+ ev.cert_fail.reason = TLS_FAIL_UNSPECIFIED;
+ ev.cert_fail.reason_txt =
+ "Server certificate mismatch";
+ ev.cert_fail.subject = buf;
+ conn->event_cb(conn->cb_ctx,
+ TLS_CERT_CHAIN_FAILURE, &ev);
+ }
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+ } else if (conn->cred && conn->cred->cert_probe) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Reject server certificate on probe-only rune");
+ if (conn->event_cb) {
+ union tls_event_data ev;
+ char buf[128];
+
+ os_memset(&ev, 0, sizeof(ev));
+ ev.cert_fail.reason = TLS_FAIL_SERVER_CHAIN_PROBE;
+ ev.cert_fail.reason_txt =
+ "Server certificate chain probe";
+ if (chain) {
+ x509_name_string(&chain->subject, buf,
+ sizeof(buf));
+ ev.cert_fail.subject = buf;
+ }
+ conn->event_cb(conn->cb_ctx, TLS_CERT_CHAIN_FAILURE,
+ &ev);
+ }
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
+ } else if (conn->cred && conn->cred->ca_cert_verify &&
+ x509_certificate_chain_validate(
+ conn->cred->trusted_certs, chain, &reason,
+ !!(conn->flags & TLS_CONN_DISABLE_TIME_CHECKS))
+ < 0) {
int tls_reason;
wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
"validation failed (reason=%d)", reason);
switch (reason) {
case X509_VALIDATE_BAD_CERTIFICATE:
tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+ tls_cert_chain_failure_event(
+ conn, 0, chain, TLS_FAIL_BAD_CERTIFICATE,
+ "bad certificate");
break;
case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
break;
case X509_VALIDATE_CERTIFICATE_REVOKED:
tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
+ tls_cert_chain_failure_event(
+ conn, 0, chain, TLS_FAIL_REVOKED,
+ "certificate revoked");
break;
case X509_VALIDATE_CERTIFICATE_EXPIRED:
tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
+ tls_cert_chain_failure_event(
+ conn, 0, chain, TLS_FAIL_EXPIRED,
+ "certificate has expired or is not yet valid");
break;
case X509_VALIDATE_CERTIFICATE_UNKNOWN:
tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
break;
case X509_VALIDATE_UNKNOWN_CA:
tls_reason = TLS_ALERT_UNKNOWN_CA;
+ tls_cert_chain_failure_event(
+ conn, 0, chain, TLS_FAIL_UNTRUSTED,
+ "unknown CA");
break;
default:
tls_reason = TLS_ALERT_BAD_CERTIFICATE;
@@ -399,7 +601,25 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
return -1;
}
- x509_certificate_chain_free(chain);
+ if (conn->cred && !conn->cred->server_cert_only && chain &&
+ (chain->extensions_present & X509_EXT_EXT_KEY_USAGE) &&
+ !(chain->ext_key_usage &
+ (X509_EXT_KEY_USAGE_ANY | X509_EXT_KEY_USAGE_SERVER_AUTH))) {
+ tls_cert_chain_failure_event(
+ conn, 0, chain, TLS_FAIL_BAD_CERTIFICATE,
+ "certificate not allowed for server authentication");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ if (conn->flags & TLS_CONN_REQUEST_OCSP) {
+ x509_certificate_chain_free(conn->server_cert);
+ conn->server_cert = chain;
+ } else {
+ x509_certificate_chain_free(chain);
+ }
*in_len = end - in_data;
@@ -465,10 +685,9 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
pos, conn->dh_p_len);
goto fail;
}
- conn->dh_p = os_malloc(conn->dh_p_len);
+ conn->dh_p = os_memdup(pos, conn->dh_p_len);
if (conn->dh_p == NULL)
goto fail;
- os_memcpy(conn->dh_p, pos, conn->dh_p_len);
pos += conn->dh_p_len;
wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
conn->dh_p, conn->dh_p_len);
@@ -480,10 +699,9 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
if (val == 0 || val > (size_t) (end - pos))
goto fail;
conn->dh_g_len = val;
- conn->dh_g = os_malloc(conn->dh_g_len);
+ conn->dh_g = os_memdup(pos, conn->dh_g_len);
if (conn->dh_g == NULL)
goto fail;
- os_memcpy(conn->dh_g, pos, conn->dh_g_len);
pos += conn->dh_g_len;
wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
conn->dh_g, conn->dh_g_len);
@@ -497,17 +715,16 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
if (val == 0 || val > (size_t) (end - pos))
goto fail;
conn->dh_ys_len = val;
- conn->dh_ys = os_malloc(conn->dh_ys_len);
+ conn->dh_ys = os_memdup(pos, conn->dh_ys_len);
if (conn->dh_ys == NULL)
goto fail;
- os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
pos += conn->dh_ys_len;
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
conn->dh_ys, conn->dh_ys_len);
server_params_end = pos;
if (key_exchange == TLS_KEY_X_DHE_RSA) {
- u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+ u8 hash[64];
int hlen;
if (conn->rl.tls_version == TLS_VERSION_1_2) {
@@ -524,18 +741,21 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
*/
if (end - pos < 2)
goto fail;
- if (pos[0] != TLS_HASH_ALG_SHA256 ||
+ if ((pos[0] != TLS_HASH_ALG_SHA256 &&
+ pos[0] != TLS_HASH_ALG_SHA384 &&
+ pos[0] != TLS_HASH_ALG_SHA512) ||
pos[1] != TLS_SIGN_ALG_RSA) {
wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/signature(%u) algorithm",
pos[0], pos[1]);
goto fail;
}
- pos += 2;
hlen = tlsv12_key_x_server_params_hash(
- conn->rl.tls_version, conn->client_random,
+ conn->rl.tls_version, pos[0],
+ conn->client_random,
conn->server_random, server_params,
server_params_end - server_params, hash);
+ pos += 2;
#else /* CONFIG_TLSV12 */
goto fail;
#endif /* CONFIG_TLSV12 */
@@ -567,6 +787,229 @@ fail:
}
+static enum tls_ocsp_result
+tls_process_certificate_status_ocsp_response(struct tlsv1_client *conn,
+ const u8 *pos, size_t len)
+{
+ const u8 *end = pos + len;
+ u32 ocsp_resp_len;
+
+ /* opaque OCSPResponse<1..2^24-1>; */
+ if (end - pos < 3) {
+ wpa_printf(MSG_INFO, "TLSv1: Too short OCSPResponse");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return TLS_OCSP_INVALID;
+ }
+ ocsp_resp_len = WPA_GET_BE24(pos);
+ pos += 3;
+ if (end - pos < ocsp_resp_len) {
+ wpa_printf(MSG_INFO, "TLSv1: Truncated OCSPResponse");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return TLS_OCSP_INVALID;
+ }
+
+ return tls_process_ocsp_response(conn, pos, ocsp_resp_len);
+}
+
+
+static int tls_process_certificate_status(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ 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,
+ "TLSv1: Expected Handshake; received content type 0x%x",
+ ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Too short CertificateStatus (left=%lu)",
+ (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Mismatch in CertificateStatus length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ end = pos + len;
+
+ if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Received unexpected handshake message %d (expected CertificateStatus)",
+ type);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateStatus");
+
+ /*
+ * struct {
+ * CertificateStatusType status_type;
+ * select (status_type) {
+ * case ocsp: OCSPResponse;
+ * case ocsp_multi: OCSPResponseList;
+ * } response;
+ * } CertificateStatus;
+ */
+ if (end - pos < 1) {
+ wpa_printf(MSG_INFO, "TLSv1: Too short CertificateStatus");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ status_type = *pos++;
+ wpa_printf(MSG_DEBUG, "TLSv1: CertificateStatus status_type %u",
+ status_type);
+
+ if (status_type == 1 /* ocsp */) {
+ res = tls_process_certificate_status_ocsp_response(
+ conn, pos, end - pos);
+ } else if (status_type == 2 /* ocsp_multi */) {
+ int good = 0, revoked = 0;
+ u32 resp_len;
+
+ res = TLS_OCSP_NO_RESPONSE;
+
+ /*
+ * opaque OCSPResponse<0..2^24-1>;
+ *
+ * struct {
+ * OCSPResponse ocsp_response_list<1..2^24-1>;
+ * } OCSPResponseList;
+ */
+ if (end - pos < 3) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Truncated OCSPResponseList");
+ res = TLS_OCSP_INVALID;
+ goto done;
+ }
+ resp_len = WPA_GET_BE24(pos);
+ pos += 3;
+ if (end - pos < resp_len) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Truncated OCSPResponseList(len=%u)",
+ resp_len);
+ res = TLS_OCSP_INVALID;
+ goto done;
+ }
+ end = pos + resp_len;
+
+ while (end - pos >= 3) {
+ resp_len = WPA_GET_BE24(pos);
+ pos += 3;
+ if (resp_len > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Truncated OCSPResponse(len=%u; left=%d) in ocsp_multi",
+ resp_len, (int) (end - pos));
+ res = TLS_OCSP_INVALID;
+ break;
+ }
+ if (!resp_len)
+ continue; /* Skip an empty response */
+ res = tls_process_certificate_status_ocsp_response(
+ conn, pos - 3, resp_len + 3);
+ if (res == TLS_OCSP_REVOKED)
+ revoked++;
+ else if (res == TLS_OCSP_GOOD)
+ good++;
+ pos += resp_len;
+ }
+
+ if (revoked)
+ res = TLS_OCSP_REVOKED;
+ else if (good)
+ res = TLS_OCSP_GOOD;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Ignore unsupported CertificateStatus");
+ goto skip;
+ }
+
+done:
+ if (res == TLS_OCSP_REVOKED) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_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 :
+ TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+ if (conn->server_cert)
+ tls_cert_chain_failure_event(
+ conn, 0, conn->server_cert,
+ TLS_FAIL_UNSPECIFIED,
+ "bad certificate status response");
+ return -1;
+ }
+
+ conn->ocsp_resp_received = 1;
+
+skip:
+ *in_len = end - in_data;
+
+ conn->state = SERVER_KEY_EXCHANGE;
+
+ return 0;
+}
+
+
static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -608,6 +1051,10 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
end = pos + len;
+ if ((conn->flags & TLS_CONN_REQUEST_OCSP) &&
+ type == TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS)
+ return tls_process_certificate_status(conn, ct, in_data,
+ in_len);
if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
return tls_process_certificate_request(conn, ct, in_data,
in_len);
@@ -617,7 +1064,9 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) {
wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
"message %d (expected ServerKeyExchange/"
- "CertificateRequest/ServerHelloDone)", type);
+ "CertificateRequest/ServerHelloDone%s)", type,
+ (conn->flags & TLS_CONN_REQUEST_OCSP) ?
+ "/CertificateStatus" : "");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -771,6 +1220,15 @@ static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
+ if ((conn->flags & TLS_CONN_REQUIRE_OCSP) &&
+ !conn->ocsp_resp_received) {
+ wpa_printf(MSG_INFO,
+ "TLSv1: No OCSP response received - reject handshake");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+ return -1;
+ }
+
*in_len = end - in_data;
conn->state = CLIENT_KEY_EXCHANGE;
OpenPOWER on IntegriCloud