EAP-FAST peer: Support vendor EAP method in Phase 2

The implementation was previously hardcoded to use only the non-expanded
IETF EAP methods in Phase 2. Extend that to allow vendor EAP methods
with expanded header to be used.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2019-08-17 15:58:26 +03:00
parent f32f76231e
commit 357c1062dc

View file

@ -364,22 +364,24 @@ static int eap_fast_init_phase2_method(struct eap_sm *sm,
} }
static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type) static int eap_fast_select_phase2_method(struct eap_fast_data *data,
int vendor, enum eap_type type)
{ {
size_t i; size_t i;
/* TODO: TNC with anonymous provisioning; need to require both /* TODO: TNC with anonymous provisioning; need to require both
* completed MSCHAPv2 and TNC */ * completed MSCHAPv2 and TNC */
if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) { if (data->anon_provisioning &&
wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed " (vendor != EAP_VENDOR_IETF || type != EAP_TYPE_MSCHAPV2)) {
"during unauthenticated provisioning; reject phase2" wpa_printf(MSG_INFO,
" type %d", type); "EAP-FAST: Only EAP-MSCHAPv2 is allowed during unauthenticated provisioning; reject phase2 type %u:%u",
vendor, type);
return -1; return -1;
} }
#ifdef EAP_TNC #ifdef EAP_TNC
if (type == EAP_TYPE_TNC) { if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_TNC) {
data->phase2_type.vendor = EAP_VENDOR_IETF; data->phase2_type.vendor = EAP_VENDOR_IETF;
data->phase2_type.method = EAP_TYPE_TNC; data->phase2_type.method = EAP_TYPE_TNC;
wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP " wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
@ -391,7 +393,7 @@ static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type)
#endif /* EAP_TNC */ #endif /* EAP_TNC */
for (i = 0; i < data->num_phase2_types; i++) { for (i = 0; i < data->num_phase2_types; i++) {
if (data->phase2_types[i].vendor != EAP_VENDOR_IETF || if (data->phase2_types[i].vendor != vendor ||
data->phase2_types[i].method != type) data->phase2_types[i].method != type)
continue; continue;
@ -404,7 +406,9 @@ static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type)
break; break;
} }
if (type != data->phase2_type.method || type == EAP_TYPE_NONE) if (vendor != data->phase2_type.vendor ||
type != data->phase2_type.method ||
(vendor == EAP_VENDOR_IETF && type == EAP_TYPE_NONE))
return -1; return -1;
return 0; return 0;
@ -422,6 +426,8 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
struct eap_method_ret iret; struct eap_method_ret iret;
struct eap_peer_config *config = eap_get_config(sm); struct eap_peer_config *config = eap_get_config(sm);
struct wpabuf msg; struct wpabuf msg;
int vendor = EAP_VENDOR_IETF;
enum eap_type method;
if (len <= sizeof(struct eap_hdr)) { if (len <= sizeof(struct eap_hdr)) {
wpa_printf(MSG_INFO, "EAP-FAST: too short " wpa_printf(MSG_INFO, "EAP-FAST: too short "
@ -429,14 +435,27 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
return -1; return -1;
} }
pos = (u8 *) (hdr + 1); pos = (u8 *) (hdr + 1);
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos); method = *pos;
if (*pos == EAP_TYPE_IDENTITY) { if (method == EAP_TYPE_EXPANDED) {
if (len < sizeof(struct eap_hdr) + 8) {
wpa_printf(MSG_INFO,
"EAP-FAST: Too short Phase 2 request (expanded header) (len=%lu)",
(unsigned long) len);
return -1;
}
vendor = WPA_GET_BE24(pos + 1);
method = WPA_GET_BE32(pos + 4);
}
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%u:%u",
vendor, method);
if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_IDENTITY) {
*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
return 0; return 0;
} }
if (data->phase2_priv && data->phase2_method && if (data->phase2_priv && data->phase2_method &&
*pos != data->phase2_type.method) { (vendor != data->phase2_type.vendor ||
method != data->phase2_type.method)) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - " wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - "
"deinitialize previous method"); "deinitialize previous method");
data->phase2_method->deinit(sm, data->phase2_priv); data->phase2_method->deinit(sm, data->phase2_priv);
@ -448,7 +467,7 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
if (data->phase2_type.vendor == EAP_VENDOR_IETF && if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
data->phase2_type.method == EAP_TYPE_NONE && data->phase2_type.method == EAP_TYPE_NONE &&
eap_fast_select_phase2_method(data, *pos) < 0) { eap_fast_select_phase2_method(data, vendor, method) < 0) {
if (eap_peer_tls_phase2_nak(data->phase2_types, if (eap_peer_tls_phase2_nak(data->phase2_types,
data->num_phase2_types, data->num_phase2_types,
hdr, resp)) hdr, resp))
@ -459,8 +478,9 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
if ((data->phase2_priv == NULL && if ((data->phase2_priv == NULL &&
eap_fast_init_phase2_method(sm, data) < 0) || eap_fast_init_phase2_method(sm, data) < 0) ||
data->phase2_method == NULL) { data->phase2_method == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize " wpa_printf(MSG_INFO,
"Phase 2 EAP method %d", *pos); "EAP-FAST: Failed to initialize Phase 2 EAP method %u:%u",
vendor, method);
ret->methodState = METHOD_DONE; ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL; ret->decision = DECISION_FAIL;
return -1; return -1;