1 From f6f7cead3661ceeef54b21f7e799c0afc98537ec Mon Sep 17 00:00:00 2001
2 From: Jouni Malinen <j@w1.fi>
3 Date: Sat, 8 Jul 2023 19:55:32 +0300
4 Subject: [PATCH] PEAP client: Update Phase 2 authentication requirements
6 The previous PEAP client behavior allowed the server to skip Phase 2
7 authentication with the expectation that the server was authenticated
8 during Phase 1 through TLS server certificate validation. Various PEAP
9 specifications are not exactly clear on what the behavior on this front
10 is supposed to be and as such, this ended up being more flexible than
11 the TTLS/FAST/TEAP cases. However, this is not really ideal when
12 unfortunately common misconfiguration of PEAP is used in deployed
13 devices where the server trust root (ca_cert) is not configured or the
14 user has an easy option for allowing this validation step to be skipped.
16 Change the default PEAP client behavior to be to require Phase 2
17 authentication to be successfully completed for cases where TLS session
18 resumption is not used and the client certificate has not been
19 configured. Those two exceptions are the main cases where a deployed
20 authentication server might skip Phase 2 and as such, where a more
21 strict default behavior could result in undesired interoperability
22 issues. Requiring Phase 2 authentication will end up disabling TLS
23 session resumption automatically to avoid interoperability issues.
25 Allow Phase 2 authentication behavior to be configured with a new phase1
26 configuration parameter option:
27 'phase2_auth' option can be used to control Phase 2 (i.e., within TLS
28 tunnel) behavior for PEAP:
29 * 0 = do not require Phase 2 authentication
30 * 1 = require Phase 2 authentication when client certificate
31 (private_key/client_cert) is no used and TLS session resumption was
33 * 2 = require Phase 2 authentication in all cases
35 Signed-off-by: Jouni Malinen <j@w1.fi>
38 Upstream-Status: Backport [https://w1.fi/cgit/hostap/commit/?id=8e6485a1bcb0baffdea9e55255a81270b768439c]
40 Signed-off-by: Claus Stovgaard <claus.stovgaard@gmail.com>
43 src/eap_peer/eap_config.h | 8 ++++++
44 src/eap_peer/eap_peap.c | 40 +++++++++++++++++++++++++++---
45 src/eap_peer/eap_tls_common.c | 6 +++++
46 src/eap_peer/eap_tls_common.h | 5 ++++
47 wpa_supplicant/wpa_supplicant.conf | 7 ++++++
48 5 files changed, 63 insertions(+), 3 deletions(-)
50 diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
51 index 3238f74..047eec2 100644
52 --- a/src/eap_peer/eap_config.h
53 +++ b/src/eap_peer/eap_config.h
54 @@ -469,6 +469,14 @@ struct eap_peer_config {
55 * 1 = use cryptobinding if server supports it
56 * 2 = require cryptobinding
58 + * phase2_auth option can be used to control Phase 2 (i.e., within TLS
59 + * tunnel) behavior for PEAP:
60 + * 0 = do not require Phase 2 authentication
61 + * 1 = require Phase 2 authentication when client certificate
62 + * (private_key/client_cert) is no used and TLS session resumption was
63 + * not used (default)
64 + * 2 = require Phase 2 authentication in all cases
66 * EAP-WSC (WPS) uses following options: pin=Device_Password and
69 diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
70 index 12e30df..6080697 100644
71 --- a/src/eap_peer/eap_peap.c
72 +++ b/src/eap_peer/eap_peap.c
73 @@ -67,6 +67,7 @@ struct eap_peap_data {
75 int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)
77 + enum { NO_AUTH, FOR_INITIAL, ALWAYS } phase2_auth;
81 @@ -114,6 +115,19 @@ static void eap_peap_parse_phase1(struct eap_peap_data *data,
82 wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding");
85 + if (os_strstr(phase1, "phase2_auth=0")) {
86 + data->phase2_auth = NO_AUTH;
87 + wpa_printf(MSG_DEBUG,
88 + "EAP-PEAP: Do not require Phase 2 authentication");
89 + } else if (os_strstr(phase1, "phase2_auth=1")) {
90 + data->phase2_auth = FOR_INITIAL;
91 + wpa_printf(MSG_DEBUG,
92 + "EAP-PEAP: Require Phase 2 authentication for initial connection");
93 + } else if (os_strstr(phase1, "phase2_auth=2")) {
94 + data->phase2_auth = ALWAYS;
95 + wpa_printf(MSG_DEBUG,
96 + "EAP-PEAP: Require Phase 2 authentication for all cases");
99 if (os_strstr(phase1, "tnc=soh2")) {
101 @@ -142,6 +156,7 @@ static void * eap_peap_init(struct eap_sm *sm)
102 data->force_peap_version = -1;
103 data->peap_outer_success = 2;
104 data->crypto_binding = OPTIONAL_BINDING;
105 + data->phase2_auth = FOR_INITIAL;
107 if (config && config->phase1)
108 eap_peap_parse_phase1(data, config->phase1);
109 @@ -454,6 +469,20 @@ static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
113 +static bool peap_phase2_sufficient(struct eap_sm *sm,
114 + struct eap_peap_data *data)
116 + if ((data->phase2_auth == ALWAYS ||
117 + (data->phase2_auth == FOR_INITIAL &&
118 + !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn) &&
119 + !data->ssl.client_cert_conf) ||
120 + data->phase2_eap_started) &&
121 + !data->phase2_eap_success)
128 * eap_tlv_process - Process a received EAP-TLV message and generate a response
129 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
130 @@ -568,6 +597,11 @@ static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
131 " - force failed Phase 2");
132 resp_status = EAP_TLV_RESULT_FAILURE;
133 ret->decision = DECISION_FAIL;
134 + } else if (!peap_phase2_sufficient(sm, data)) {
135 + wpa_printf(MSG_INFO,
136 + "EAP-PEAP: Server indicated Phase 2 success, but sufficient Phase 2 authentication has not been completed");
137 + resp_status = EAP_TLV_RESULT_FAILURE;
138 + ret->decision = DECISION_FAIL;
140 resp_status = EAP_TLV_RESULT_SUCCESS;
141 ret->decision = DECISION_UNCOND_SUCC;
142 @@ -887,8 +921,7 @@ continue_req:
143 /* EAP-Success within TLS tunnel is used to indicate
144 * shutdown of the TLS channel. The authentication has
146 - if (data->phase2_eap_started &&
147 - !data->phase2_eap_success) {
148 + if (!peap_phase2_sufficient(sm, data)) {
149 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
150 "Success used to indicate success, "
151 "but Phase 2 EAP was not yet "
152 @@ -1199,8 +1232,9 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
153 static bool eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
155 struct eap_peap_data *data = priv;
157 return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
158 - data->phase2_success;
159 + data->phase2_success && data->phase2_auth != ALWAYS;
163 diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
164 index c1837db..a53eeb1 100644
165 --- a/src/eap_peer/eap_tls_common.c
166 +++ b/src/eap_peer/eap_tls_common.c
167 @@ -239,6 +239,12 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
169 sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK);
172 + data->client_cert_conf = params->client_cert ||
173 + params->client_cert_blob ||
174 + params->private_key ||
175 + params->private_key_blob;
180 diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
181 index 9ac0012..3348634 100644
182 --- a/src/eap_peer/eap_tls_common.h
183 +++ b/src/eap_peer/eap_tls_common.h
184 @@ -79,6 +79,11 @@ struct eap_ssl_data {
185 * tls_v13 - Whether TLS v1.3 or newer is used
190 + * client_cert_conf: Whether client certificate has been configured
192 + bool client_cert_conf;
196 diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
197 index 6619d6b..d63f73c 100644
198 --- a/wpa_supplicant/wpa_supplicant.conf
199 +++ b/wpa_supplicant/wpa_supplicant.conf
200 @@ -1321,6 +1321,13 @@ fast_reauth=1
201 # * 0 = do not use cryptobinding (default)
202 # * 1 = use cryptobinding if server supports it
203 # * 2 = require cryptobinding
204 +# 'phase2_auth' option can be used to control Phase 2 (i.e., within TLS
205 +# tunnel) behavior for PEAP:
206 +# * 0 = do not require Phase 2 authentication
207 +# * 1 = require Phase 2 authentication when client certificate
208 +# (private_key/client_cert) is no used and TLS session resumption was
209 +# not used (default)
210 +# * 2 = require Phase 2 authentication in all cases
211 # EAP-WSC (WPS) uses following options: pin=<Device Password> or