aboutsummaryrefslogtreecommitdiffstats
path: root/src/tls
diff options
context:
space:
mode:
authorJouni Malinen <jouni@qca.qualcomm.com>2015-12-22 17:39:37 (GMT)
committerJouni Malinen <j@w1.fi>2015-12-22 18:44:56 (GMT)
commitb5677752b2070e37aa7e04f625f08821bc086e55 (patch)
tree4c1a273fdf84869b16a29a9f983dc1b4941d0c0f /src/tls
parent8ea6a270030ab67bfc1551904c07ec296bbf9b91 (diff)
downloadhostap-b5677752b2070e37aa7e04f625f08821bc086e55.zip
hostap-b5677752b2070e37aa7e04f625f08821bc086e55.tar.gz
hostap-b5677752b2070e37aa7e04f625f08821bc086e55.tar.bz2
TLS client: OCSP stapling with ocsp_multi option (RFC 6961)
This adds a minimal support for using status_request_v2 extension and ocsp_multi format (OCSPResponseList instead of OCSPResponse) for CertificateStatus. This commit does not yet extend use of OCSP stapling to validate the intermediate CA certificates. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
Diffstat (limited to 'src/tls')
-rw-r--r--src/tls/tlsv1_client_read.c135
-rw-r--r--src/tls/tlsv1_client_write.c40
2 files changed, 136 insertions, 39 deletions
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index ff12452..ab0d9d7 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -790,13 +790,37 @@ 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;
- u32 ocsp_resp_len;
enum tls_ocsp_result res;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
@@ -850,6 +874,7 @@ static int tls_process_certificate_status(struct tlsv1_client *conn, u8 ct,
* CertificateStatusType status_type;
* select (status_type) {
* case ocsp: OCSPResponse;
+ * case ocsp_multi: OCSPResponseList;
* } response;
* } CertificateStatus;
*/
@@ -862,32 +887,84 @@ static int tls_process_certificate_status(struct tlsv1_client *conn, u8 ct,
wpa_printf(MSG_DEBUG, "TLSv1: CertificateStatus status_type %u",
status_type);
- if (status_type != 1 /* ocsp */) {
+ 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;
}
- /* 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 -1;
- }
- 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);
+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");
return -1;
}
- res = tls_process_ocsp_response(conn, pos, ocsp_resp_len);
- switch (res) {
- case TLS_OCSP_NO_RESPONSE:
- if (!(conn->flags & TLS_CONN_REQUIRE_OCSP))
- goto skip;
+ 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(
@@ -895,28 +972,8 @@ static int tls_process_certificate_status(struct tlsv1_client *conn, u8 ct,
TLS_FAIL_UNSPECIFIED,
"bad certificate status response");
return -1;
- case TLS_OCSP_INVALID:
- if (!(conn->flags & TLS_CONN_REQUIRE_OCSP))
- goto skip; /* ignore - process as if no response */
- tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
- if (conn->server_cert)
- tls_cert_chain_failure_event(
- conn, 0, conn->server_cert,
- TLS_FAIL_UNSPECIFIED,
- "bad certificate status response");
- return -1;
- case TLS_OCSP_GOOD:
- wpa_printf(MSG_DEBUG, "TLSv1: OCSP response good");
- break;
- case 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");
- return -1;
}
+
conn->ocsp_resp_received = 1;
skip:
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index 8e8cb5e..04d895e 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -192,6 +192,46 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
pos += 2;
WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
pos += 2;
+
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Add status_request_v2 extension for OCSP stapling");
+ /* ExtensionsType extension_type = status_request_v2(17) */
+ WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
+ pos += 2;
+ /* opaque extension_data<0..2^16-1> length */
+ WPA_PUT_BE16(pos, 7);
+ pos += 2;
+
+ /*
+ * RFC 6961, 2.2:
+ * struct {
+ * CertificateStatusType status_type;
+ * uint16 request_length;
+ * select (status_type) {
+ * case ocsp: OCSPStatusRequest;
+ * case ocsp_multi: OCSPStatusRequest;
+ * } request;
+ * } CertificateStatusRequestItemV2;
+ *
+ * enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
+ *
+ * struct {
+ * CertificateStatusRequestItemV2
+ * certificate_status_req_list<1..2^16-1>;
+ * } CertificateStatusRequestListV2;
+ */
+
+ /* certificate_status_req_list<1..2^16-1> */
+ WPA_PUT_BE16(pos, 5);
+ pos += 2;
+
+ /* CertificateStatusRequestItemV2 */
+ *pos++ = 2; /* status_type = ocsp_multi(2) */
+ /* OCSPStatusRequest as shown above for v1 */
+ WPA_PUT_BE16(pos, 0); /* responder_id_list(empty) */
+ pos += 2;
+ WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
+ pos += 2;
}
if (pos == ext_start + 2)