diff --git a/src/tls/Makefile b/src/tls/Makefile index 27cdfcaa9..52a890a15 100644 --- a/src/tls/Makefile +++ b/src/tls/Makefile @@ -24,6 +24,7 @@ LIB_OBJS= \ tlsv1_client.o \ tlsv1_client_read.o \ tlsv1_client_write.o \ + tlsv1_client_ocsp.o \ tlsv1_common.o \ tlsv1_cred.o \ tlsv1_record.o \ diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c index 846d29320..cc404c156 100644 --- a/src/tls/tlsv1_client.c +++ b/src/tls/tlsv1_client.c @@ -1,6 +1,6 @@ /* * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246) - * Copyright (c) 2006-2014, Jouni Malinen + * Copyright (c) 2006-2015, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -11,6 +11,7 @@ #include "common.h" #include "crypto/sha1.h" #include "crypto/tls.h" +#include "x509v3.h" #include "tlsv1_common.h" #include "tlsv1_record.h" #include "tlsv1_client.h" @@ -494,6 +495,7 @@ void tlsv1_client_deinit(struct tlsv1_client *conn) tlsv1_client_free_dh(conn); tlsv1_cred_free(conn->cred); wpabuf_free(conn->partial_input); + x509_certificate_chain_free(conn->server_cert); os_free(conn); } diff --git a/src/tls/tlsv1_client_i.h b/src/tls/tlsv1_client_i.h index 6c4dbc710..12ec8df6c 100644 --- a/src/tls/tlsv1_client_i.h +++ b/src/tls/tlsv1_client_i.h @@ -36,6 +36,7 @@ struct tlsv1_client { unsigned int session_ticket_included:1; unsigned int use_session_ticket:1; unsigned int cert_in_cb:1; + unsigned int ocsp_resp_received:1; struct crypto_public_key *server_rsa_key; @@ -70,6 +71,8 @@ struct tlsv1_client { void (*event_cb)(void *ctx, enum tls_event ev, union tls_event_data *data); void *cb_ctx; + + struct x509_certificate *server_cert; }; @@ -87,4 +90,11 @@ int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct, const u8 *buf, size_t *len, u8 **out_data, size_t *out_len); +enum tls_ocsp_result { + TLS_OCSP_NO_RESPONSE, TLS_OCSP_INVALID, TLS_OCSP_GOOD, TLS_OCSP_REVOKED +}; + +enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn, + const u8 *resp, size_t len); + #endif /* TLSV1_CLIENT_I_H */ diff --git a/src/tls/tlsv1_client_ocsp.c b/src/tls/tlsv1_client_ocsp.c new file mode 100644 index 000000000..8d64527eb --- /dev/null +++ b/src/tls/tlsv1_client_ocsp.c @@ -0,0 +1,26 @@ +/* + * TLSv1 client - OCSP + * Copyright (c) 2015, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "crypto/tls.h" +#include "tlsv1_common.h" +#include "tlsv1_record.h" +#include "tlsv1_client.h" +#include "tlsv1_client_i.h" + + +enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn, + const u8 *resp, size_t len) +{ + wpa_hexdump(MSG_MSGDUMP, "TLSv1: OCSPResponse", resp, len); + + /* TODO */ + return TLS_OCSP_NO_RESPONSE; +} diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c index 04419f788..b1fa15f41 100644 --- a/src/tls/tlsv1_client_read.c +++ b/src/tls/tlsv1_client_read.c @@ -614,7 +614,12 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct, return -1; } - x509_certificate_chain_free(chain); + 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; @@ -785,6 +790,134 @@ fail: } +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) { + 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; + * } 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 */) { + 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); + 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; + tls_alert(conn, TLS_ALERT_LEVEL_FATAL, + TLS_ALERT_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); + 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: + *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) { @@ -826,6 +959,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); @@ -835,7 +972,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; @@ -989,6 +1128,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; diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index e949ce714..a558bbe21 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -981,6 +981,7 @@ OBJS += src/tls/tlsv1_cred.c OBJS += src/tls/tlsv1_client.c OBJS += src/tls/tlsv1_client_write.c OBJS += src/tls/tlsv1_client_read.c +OBJS += src/tls/tlsv1_client_ocsp.c OBJS += src/tls/asn1.c OBJS += src/tls/rsa.c OBJS += src/tls/x509v3.c diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index e3d3acf16..6bab7d1e4 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -1010,6 +1010,7 @@ OBJS += ../src/tls/tlsv1_cred.o OBJS += ../src/tls/tlsv1_client.o OBJS += ../src/tls/tlsv1_client_write.o OBJS += ../src/tls/tlsv1_client_read.o +OBJS += ../src/tls/tlsv1_client_ocsp.o OBJS += ../src/tls/asn1.o OBJS += ../src/tls/rsa.o OBJS += ../src/tls/x509v3.o