]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
TLS: Parse CertificateStatus message
authorJouni Malinen <j@w1.fi>
Sun, 13 Dec 2015 21:11:32 +0000 (23:11 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 14 Dec 2015 13:49:01 +0000 (15:49 +0200)
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>
src/tls/Makefile
src/tls/tlsv1_client.c
src/tls/tlsv1_client_i.h
src/tls/tlsv1_client_ocsp.c [new file with mode: 0644]
src/tls/tlsv1_client_read.c
wpa_supplicant/Android.mk
wpa_supplicant/Makefile

index 27cdfcaa97489034c7d72cb38d3278100105c2d0..52a890a157d2efcba5ad94a3872500db0f0501af 100644 (file)
@@ -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 \
index 846d293202cf7e8e5c41407df02a7cb1d3eb0398..cc404c156e6586ac6d1ab131316b5800620205af 100644 (file)
@@ -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);
 }
 
index 6c4dbc71002f598cabaa2b9a3811dcf299b8bf2a..12ec8df6c3ac1f02b1bb7de5f01abe5e6f03c57f 100644 (file)
@@ -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 (file)
index 0000000..8d64527
--- /dev/null
@@ -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;
+}
index 04419f788cb57f0af9e75ad1fe6b42c22e832556..b1fa15f416def1d382677ee1cb19fa7840d7abcb 100644 (file)
@@ -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;
index e949ce714cd1b0628b61d505c5525f94755ff8e0..a558bbe21f8c5402619e2305066f041f6e0e942f 100644 (file)
@@ -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
index e3d3acf16337be9d68bc2b69cbc9ed2206ce3138..6bab7d1e4fa00f9ff7d272c5a9a0da7123f9613b 100644 (file)
@@ -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