diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 427242d94..9b252e9a1 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1798,6 +1798,9 @@ void wpa_config_free_cred(struct wpa_cred *cred) os_free(cred->imsi); os_free(cred->milenage); os_free(cred->domain); + os_free(cred->eap_method); + os_free(cred->phase1); + os_free(cred->phase2); os_free(cred); } @@ -2251,6 +2254,23 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "eap") == 0) { + struct eap_method_type method; + method.method = eap_peer_get_type(value, &method.vendor); + if (method.vendor == EAP_VENDOR_IETF && + method.method == EAP_TYPE_NONE) { + wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' " + "for a credential", line, value); + return -1; + } + os_free(cred->eap_method); + cred->eap_method = os_malloc(sizeof(*cred->eap_method)); + if (cred->eap_method == NULL) + return -1; + os_memcpy(cred->eap_method, &method, sizeof(method)); + return 0; + } + val = wpa_config_parse_string(value, &len); if (val == NULL) { wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string " @@ -2318,6 +2338,18 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "phase1") == 0) { + os_free(cred->phase1); + cred->phase1 = val; + return 0; + } + + if (os_strcmp(var, "phase2") == 0) { + os_free(cred->phase2); + cred->phase2 = val; + return 0; + } + if (line) { wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.", line, var); diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 9ae57d018..5db919408 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -148,6 +148,29 @@ struct wpa_cred { * whether the AP is operated by the Home SP. */ char *domain; + + /** + * eap_method - EAP method to use + * + * Pre-configured EAP method to use with this credential or %NULL to + * indicate no EAP method is selected, i.e., the method will be + * selected automatically based on ANQP information. + */ + struct eap_method_type *eap_method; + + /** + * phase1 - Phase 1 (outer authentication) parameters + * + * Pre-configured EAP parameters or %NULL. + */ + char *phase1; + + /** + * phase2 - Phase 2 (inner authentication) parameters + * + * Pre-configured EAP parameters or %NULL. + */ + char *phase2; }; diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 7d3fbcd54..86f2ee3e9 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -15,6 +15,7 @@ #include "utils/pcsc_funcs.h" #include "drivers/driver.h" #include "eap_common/eap_defs.h" +#include "eap_peer/eap.h" #include "eap_peer/eap_methods.h" #include "wpa_supplicant_i.h" #include "config.h" @@ -733,6 +734,21 @@ fail: static int interworking_set_eap_params(struct wpa_ssid *ssid, struct wpa_cred *cred, int ttls) { + if (cred->eap_method) { + ttls = cred->eap_method->vendor == EAP_VENDOR_IETF && + cred->eap_method->method == EAP_TYPE_TTLS; + + os_free(ssid->eap.eap_methods); + ssid->eap.eap_methods = + os_malloc(sizeof(struct eap_method_type) * 2); + if (ssid->eap.eap_methods == NULL) + return -1; + os_memcpy(ssid->eap.eap_methods, cred->eap_method, + sizeof(*cred->eap_method)); + ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF; + ssid->eap.eap_methods[1].method = EAP_TYPE_NONE; + } + if (ttls && cred->username && cred->username[0]) { const char *pos; char *anon; @@ -784,6 +800,15 @@ static int interworking_set_eap_params(struct wpa_ssid *ssid, cred->private_key_passwd) < 0) return -1; + if (cred->phase1) { + os_free(ssid->eap.phase1); + ssid->eap.phase1 = os_strdup(cred->phase1); + } + if (cred->phase2) { + os_free(ssid->eap.phase2); + ssid->eap.phase2 = os_strdup(cred->phase2); + } + if (cred->ca_cert && cred->ca_cert[0] && wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0) return -1; diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index b3cacab54..fa4e39773 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -336,6 +336,17 @@ fast_reauth=1 # This is used to compare against the Domain Name List to figure out # whether the AP is operated by the Home SP. # +# eap: Pre-configured EAP method +# This optional field can be used to specify which EAP method will be +# used with this credential. If not set, the EAP method is selected +# automatically based on ANQP information (e.g., NAI Realm). +# +# phase1: Pre-configure Phase 1 (outer authentication) parameters +# This optional field is used with like the 'eap' parameter. +# +# phase2: Pre-configure Phase 2 (inner authentication) parameters +# This optional field is used with like the 'eap' parameter. +# # for example: # #cred={