aboutsummaryrefslogtreecommitdiffstats
path: root/src/tls
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2015-12-13 21:11:32 (GMT)
committerJouni Malinen <j@w1.fi>2015-12-14 13:49:01 (GMT)
commitd560288a44109085d680259b4e1561d68b44bafd (patch)
treec0dec49b075b3e226a4143c8478a95850cf887e2 /src/tls
parenteeba1684532f95a9d1f2b4a6379cf77b9a924df7 (diff)
downloadhostap-d560288a44109085d680259b4e1561d68b44bafd.zip
hostap-d560288a44109085d680259b4e1561d68b44bafd.tar.gz
hostap-d560288a44109085d680259b4e1561d68b44bafd.tar.bz2
TLS: Parse CertificateStatus message
This allows the internal TLS client implementation to accept CertificateStatus message from the server when trying to use OCSP stapling. The actual OCSPResponse is not yet processed in this commit, but the CertificateStatus message is accepted to allow the TLS handshake to continue. Signed-off-by: Jouni Malinen <j@w1.fi>
Diffstat (limited to 'src/tls')
-rw-r--r--src/tls/Makefile1
-rw-r--r--src/tls/tlsv1_client.c4
-rw-r--r--src/tls/tlsv1_client_i.h10
-rw-r--r--src/tls/tlsv1_client_ocsp.c26
-rw-r--r--src/tls/tlsv1_client_read.c152
5 files changed, 190 insertions, 3 deletions
diff --git a/src/tls/Makefile b/src/tls/Makefile
index 27cdfca..52a890a 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 846d293..cc404c1 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 <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.
@@ -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 6c4dbc7..12ec8df 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 0000000..8d64527
--- /dev/null
+++ b/src/tls/tlsv1_client_ocsp.c
@@ -0,0 +1,26 @@
+/*
+ * TLSv1 client - OCSP
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * 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 04419f7..b1fa15f 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;