fix(wpa_supplicant): (PEAP client) Update Phase 2 auth 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
pull/13306/head
Kapil Gupta 2024-02-26 10:23:43 +05:30 zatwierdzone przez BOT
rodzic 3cd174ab09
commit 59a62f2af6
3 zmienionych plików z 49 dodań i 5 usunięć

Wyświetl plik

@ -66,6 +66,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 @@ eap_peap_parse_phase1(struct eap_peap_data *data,
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;
@ -145,6 +159,7 @@ eap_peap_init(struct eap_sm *sm)
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) < 0) {
@ -449,6 +464,19 @@ eap_tlv_validate_cryptobinding(struct eap_sm *sm,
return 0;
}
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
@ -565,6 +593,11 @@ eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
" - 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;
@ -939,8 +972,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 "
@ -1200,8 +1232,9 @@ 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;
}

Wyświetl plik

@ -94,7 +94,7 @@ static void eap_tls_params_from_conf1(struct tls_connection_params *params,
static int eap_tls_params_from_conf(struct eap_sm *sm,
struct eap_ssl_data *data,
struct tls_connection_params *params,
struct eap_peer_config *config)
struct eap_peer_config *config, int phase2)
{
os_memset(params, 0, sizeof(*params));
if (sm->workaround && data->eap_type != EAP_TYPE_FAST) {
@ -133,6 +133,12 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
return -1;
}
if (!phase2)
data->client_cert_conf = params->client_cert ||
params->client_cert_blob ||
params->private_key ||
params->private_key_blob;
return 0;
}
@ -210,7 +216,7 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
data->eap = sm;
data->eap_type = eap_type;
data->ssl_ctx = sm->ssl_ctx;
if (eap_tls_params_from_conf(sm, data, &params, config) < 0) /* no phase2 */
if (eap_tls_params_from_conf(sm, data, &params, config, data->phase2) < 0) /* no phase2 */
return -1;
if (eap_tls_init_connection(sm, data, config, &params) < 0)

Wyświetl plik

@ -73,6 +73,11 @@ struct eap_ssl_data {
* eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
*/
u8 eap_type;
/**
* client_cert_conf: Whether client certificate has been configured
*/
bool client_cert_conf;
};