hostapd: backport fix for CVE-2023-52160
authorHauke Mehrtens <hauke@hauke-m.de>
Tue, 13 Feb 2024 21:50:12 +0000 (22:50 +0100)
committerHauke Mehrtens <hauke@hauke-m.de>
Thu, 22 Feb 2024 20:50:16 +0000 (21:50 +0100)
Fix a authentication bypass problem in WPA Enterprise client mode. See
here for details: https://www.top10vpn.com/research/wifi-vulnerabilities/
This problem was assigned CVE-2023-52160

This problem was fixed in upstream hostapd in June 2023. Hostapd used in
OpenWrt 23.05 and later already contains this fix..

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
package/network/services/hostapd/patches/060-CVE-2023-52160-PEAP-client-Update-Phase-2-authentication-requiremen.patch [new file with mode: 0644]

diff --git a/package/network/services/hostapd/patches/060-CVE-2023-52160-PEAP-client-Update-Phase-2-authentication-requiremen.patch b/package/network/services/hostapd/patches/060-CVE-2023-52160-PEAP-client-Update-Phase-2-authentication-requiremen.patch
new file mode 100644 (file)
index 0000000..01c261a
--- /dev/null
@@ -0,0 +1,197 @@
+From 8e6485a1bcb0baffdea9e55255a81270b768439c Mon Sep 17 00:00:00 2001
+From: Jouni Malinen <j@w1.fi>
+Date: Sat, 8 Jul 2023 19:55:32 +0300
+Subject: PEAP client: Update Phase 2 authentication requirements
+
+The previous PEAP client behavior allowed the server to skip Phase 2
+authentication with the expectation that the server was authenticated
+during Phase 1 through TLS server certificate validation. Various PEAP
+specifications are not exactly clear on what the behavior on this front
+is supposed to be and as such, this ended up being more flexible than
+the TTLS/FAST/TEAP cases. However, this is not really ideal when
+unfortunately common misconfiguration of PEAP is used in deployed
+devices where the server trust root (ca_cert) is not configured or the
+user has an easy option for allowing this validation step to be skipped.
+
+Change the default PEAP client behavior to be to require Phase 2
+authentication to be successfully completed for cases where TLS session
+resumption is not used and the client certificate has not been
+configured. Those two exceptions are the main cases where a deployed
+authentication server might skip Phase 2 and as such, where a more
+strict default behavior could result in undesired interoperability
+issues. Requiring Phase 2 authentication will end up disabling TLS
+session resumption automatically to avoid interoperability issues.
+
+Allow Phase 2 authentication behavior to be configured with a new phase1
+configuration parameter option:
+'phase2_auth' option can be used to control Phase 2 (i.e., within TLS
+tunnel) behavior for PEAP:
+ * 0 = do not require Phase 2 authentication
+ * 1 = require Phase 2 authentication when client certificate
+   (private_key/client_cert) is no used and TLS session resumption was
+   not used (default)
+ * 2 = require Phase 2 authentication in all cases
+
+Signed-off-by: Jouni Malinen <j@w1.fi>
+---
+ src/eap_peer/eap_config.h          |  8 ++++++
+ src/eap_peer/eap_peap.c            | 40 +++++++++++++++++++++++++++---
+ src/eap_peer/eap_tls_common.c      |  6 +++++
+ src/eap_peer/eap_tls_common.h      |  5 ++++
+ wpa_supplicant/wpa_supplicant.conf |  7 ++++++
+ 5 files changed, 63 insertions(+), 3 deletions(-)
+
+--- a/src/eap_peer/eap_config.h
++++ b/src/eap_peer/eap_config.h
+@@ -469,6 +469,14 @@ struct eap_peer_config {
+        * 1 = use cryptobinding if server supports it
+        * 2 = require cryptobinding
+        *
++       * phase2_auth option can be used to control Phase 2 (i.e., within TLS
++       * tunnel) behavior for PEAP:
++       * 0 = do not require Phase 2 authentication
++       * 1 = require Phase 2 authentication when client certificate
++       *  (private_key/client_cert) is no used and TLS session resumption was
++       *  not used (default)
++       * 2 = require Phase 2 authentication in all cases
++       *
+        * EAP-WSC (WPS) uses following options: pin=Device_Password and
+        * uuid=Device_UUID
+        *
+--- a/src/eap_peer/eap_peap.c
++++ b/src/eap_peer/eap_peap.c
+@@ -67,6 +67,7 @@ struct eap_peap_data {
+       u8 cmk[20];
+       int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)
+                 * is enabled. */
++      enum { NO_AUTH, FOR_INITIAL, ALWAYS } phase2_auth;
+ };
+@@ -114,6 +115,19 @@ static void eap_peap_parse_phase1(struct
+               wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding");
+       }
++      if (os_strstr(phase1, "phase2_auth=0")) {
++              data->phase2_auth = NO_AUTH;
++              wpa_printf(MSG_DEBUG,
++                         "EAP-PEAP: Do not require Phase 2 authentication");
++      } else if (os_strstr(phase1, "phase2_auth=1")) {
++              data->phase2_auth = FOR_INITIAL;
++              wpa_printf(MSG_DEBUG,
++                         "EAP-PEAP: Require Phase 2 authentication for initial connection");
++      } else if (os_strstr(phase1, "phase2_auth=2")) {
++              data->phase2_auth = ALWAYS;
++              wpa_printf(MSG_DEBUG,
++                         "EAP-PEAP: Require Phase 2 authentication for all cases");
++      }
+ #ifdef EAP_TNC
+       if (os_strstr(phase1, "tnc=soh2")) {
+               data->soh = 2;
+@@ -142,6 +156,7 @@ static void * eap_peap_init(struct eap_s
+       data->force_peap_version = -1;
+       data->peap_outer_success = 2;
+       data->crypto_binding = OPTIONAL_BINDING;
++      data->phase2_auth = FOR_INITIAL;
+       if (config && config->phase1)
+               eap_peap_parse_phase1(data, config->phase1);
+@@ -454,6 +469,20 @@ static int eap_tlv_validate_cryptobindin
+ }
++static bool peap_phase2_sufficient(struct eap_sm *sm,
++                                 struct eap_peap_data *data)
++{
++      if ((data->phase2_auth == ALWAYS ||
++           (data->phase2_auth == FOR_INITIAL &&
++            !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn) &&
++            !data->ssl.client_cert_conf) ||
++           data->phase2_eap_started) &&
++          !data->phase2_eap_success)
++              return false;
++      return true;
++}
++
++
+ /**
+  * eap_tlv_process - Process a received EAP-TLV message and generate a response
+  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+@@ -568,6 +597,11 @@ static int eap_tlv_process(struct eap_sm
+                                          " - force failed Phase 2");
+                               resp_status = EAP_TLV_RESULT_FAILURE;
+                               ret->decision = DECISION_FAIL;
++                      } else if (!peap_phase2_sufficient(sm, data)) {
++                              wpa_printf(MSG_INFO,
++                                         "EAP-PEAP: Server indicated Phase 2 success, but sufficient Phase 2 authentication has not been completed");
++                              resp_status = EAP_TLV_RESULT_FAILURE;
++                              ret->decision = DECISION_FAIL;
+                       } else {
+                               resp_status = EAP_TLV_RESULT_SUCCESS;
+                               ret->decision = DECISION_UNCOND_SUCC;
+@@ -887,8 +921,7 @@ continue_req:
+                       /* EAP-Success within TLS tunnel is used to indicate
+                        * shutdown of the TLS channel. The authentication has
+                        * been completed. */
+-                      if (data->phase2_eap_started &&
+-                          !data->phase2_eap_success) {
++                      if (!peap_phase2_sufficient(sm, data)) {
+                               wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
+                                          "Success used to indicate success, "
+                                          "but Phase 2 EAP was not yet "
+@@ -1199,8 +1232,9 @@ static struct wpabuf * eap_peap_process(
+ static bool eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
+ {
+       struct eap_peap_data *data = priv;
++
+       return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
+-              data->phase2_success;
++              data->phase2_success && data->phase2_auth != ALWAYS;
+ }
+--- a/src/eap_peer/eap_tls_common.c
++++ b/src/eap_peer/eap_tls_common.c
+@@ -239,6 +239,12 @@ static int eap_tls_params_from_conf(stru
+       sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK);
++      if (!phase2)
++              data->client_cert_conf = params->client_cert ||
++                      params->client_cert_blob ||
++                      params->private_key ||
++                      params->private_key_blob;
++
+       return 0;
+ }
+--- a/src/eap_peer/eap_tls_common.h
++++ b/src/eap_peer/eap_tls_common.h
+@@ -79,6 +79,11 @@ struct eap_ssl_data {
+        * tls_v13 - Whether TLS v1.3 or newer is used
+        */
+       int tls_v13;
++
++      /**
++       * client_cert_conf: Whether client certificate has been configured
++       */
++      bool client_cert_conf;
+ };
+--- a/wpa_supplicant/wpa_supplicant.conf
++++ b/wpa_supplicant/wpa_supplicant.conf
+@@ -1321,6 +1321,13 @@ fast_reauth=1
+ #      * 0 = do not use cryptobinding (default)
+ #      * 1 = use cryptobinding if server supports it
+ #      * 2 = require cryptobinding
++#     'phase2_auth' option can be used to control Phase 2 (i.e., within TLS
++#     tunnel) behavior for PEAP:
++#      * 0 = do not require Phase 2 authentication
++#      * 1 = require Phase 2 authentication when client certificate
++#        (private_key/client_cert) is no used and TLS session resumption was
++#        not used (default)
++#      * 2 = require Phase 2 authentication in all cases
+ #     EAP-WSC (WPS) uses following options: pin=<Device Password> or
+ #     pbc=1.
+ #