From 002087651478644070673f4db2ef4218f00ce6a1 Mon Sep 17 00:00:00 2001 From: Vidyullatha Kanchanapally Date: Fri, 2 Jun 2017 18:38:20 +0530 Subject: [PATCH] eap_proxy: Build realm from IMSI for proxy based EAP methods For proxy based EAP methods, the EAP identity is constructed in eap_proxy layer from IMSI when required. Realm information from identity is used to do ERP eventually, hence construct the realm for proxy based methods from IMSI in core wpa_supplicant to enable the ERP use case. Signed-off-by: Jouni Malinen --- src/eap_peer/eap.c | 154 +++++++++++++++++++++++---------- src/eap_peer/eap.h | 9 ++ src/eapol_supp/eapol_supp_sm.c | 5 +- src/eapol_supp/eapol_supp_sm.h | 2 +- 4 files changed, 121 insertions(+), 49 deletions(-) diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 359701c37..59967fdd7 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -121,15 +121,17 @@ static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt) /** - * eap_allowed_method - Check whether EAP method is allowed + * eap_config_allowed_method - Check whether EAP method is allowed * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @config: EAP configuration * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types * @method: EAP type * Returns: 1 = allowed EAP method, 0 = not allowed */ -int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method) +static int eap_config_allowed_method(struct eap_sm *sm, + struct eap_peer_config *config, + int vendor, u32 method) { - struct eap_peer_config *config = eap_get_config(sm); int i; struct eap_method_type *m; @@ -146,6 +148,57 @@ int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method) } +/** + * eap_allowed_method - Check whether EAP method is allowed + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types + * @method: EAP type + * Returns: 1 = allowed EAP method, 0 = not allowed + */ +int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method) +{ + return eap_config_allowed_method(sm, eap_get_config(sm), vendor, + method); +} + + +#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY) +static int eap_sm_append_3gpp_realm(struct eap_sm *sm, char *imsi, + size_t max_len, size_t *imsi_len, + int mnc_len) +{ + char *pos, mnc[4]; + + if (*imsi_len + 36 > max_len) { + wpa_printf(MSG_WARNING, "No room for realm in IMSI buffer"); + return -1; + } + + if (mnc_len != 2 && mnc_len != 3) + mnc_len = 3; + + if (mnc_len == 2) { + mnc[0] = '0'; + mnc[1] = imsi[3]; + mnc[2] = imsi[4]; + } else if (mnc_len == 3) { + mnc[0] = imsi[3]; + mnc[1] = imsi[4]; + mnc[2] = imsi[5]; + } + mnc[3] = '\0'; + + pos = imsi + *imsi_len; + pos += os_snprintf(pos, imsi + max_len - pos, + "@wlan.mnc%s.mcc%c%c%c.3gppnetwork.org", + mnc, imsi[0], imsi[1], imsi[2]); + *imsi_len = pos - imsi; + + return 0; +} +#endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */ + + /* * This state initializes state machine variables when the machine is * activated (portEnabled = TRUE). This is also used when re-starting @@ -412,6 +465,44 @@ static char * eap_get_realm(struct eap_sm *sm, struct eap_peer_config *config) } } +#ifdef CONFIG_EAP_PROXY + /* When identity is not provided in the config, build the realm from + * IMSI for eap_proxy based methods. + */ + if (!config->identity && !config->anonymous_identity && + sm->eapol_cb->get_imsi && + (eap_config_allowed_method(sm, config, EAP_VENDOR_IETF, + EAP_TYPE_SIM) || + eap_config_allowed_method(sm, config, EAP_VENDOR_IETF, + EAP_TYPE_AKA) || + eap_config_allowed_method(sm, config, EAP_VENDOR_IETF, + EAP_TYPE_AKA_PRIME))) { + char imsi[100]; + size_t imsi_len; + int mnc_len, pos; + + wpa_printf(MSG_DEBUG, "EAP: Build realm from IMSI (eap_proxy)"); + mnc_len = sm->eapol_cb->get_imsi(sm->eapol_ctx, imsi, + &imsi_len); + if (mnc_len < 0) + return NULL; + + pos = imsi_len + 1; /* points to the beginning of the realm */ + if (eap_sm_append_3gpp_realm(sm, imsi, sizeof(imsi), &imsi_len, + mnc_len) < 0) { + wpa_printf(MSG_WARNING, "Could not append realm"); + return NULL; + } + + realm = os_strdup(&imsi[pos]); + if (!realm) + return NULL; + + wpa_printf(MSG_DEBUG, "EAP: Generated realm '%s'", realm); + return realm; + } +#endif /* CONFIG_EAP_PROXY */ + return NULL; } @@ -1401,48 +1492,6 @@ static int mnc_len_from_imsi(const char *imsi) } -static int eap_sm_append_3gpp_realm(struct eap_sm *sm, char *imsi, - size_t max_len, size_t *imsi_len) -{ - int mnc_len; - char *pos, mnc[4]; - - if (*imsi_len + 36 > max_len) { - wpa_printf(MSG_WARNING, "No room for realm in IMSI buffer"); - return -1; - } - - /* MNC (2 or 3 digits) */ - mnc_len = scard_get_mnc_len(sm->scard_ctx); - if (mnc_len < 0) - mnc_len = mnc_len_from_imsi(imsi); - if (mnc_len < 0) { - wpa_printf(MSG_INFO, "Failed to get MNC length from (U)SIM " - "assuming 3"); - mnc_len = 3; - } - - if (mnc_len == 2) { - mnc[0] = '0'; - mnc[1] = imsi[3]; - mnc[2] = imsi[4]; - } else if (mnc_len == 3) { - mnc[0] = imsi[3]; - mnc[1] = imsi[4]; - mnc[2] = imsi[5]; - } - mnc[3] = '\0'; - - pos = imsi + *imsi_len; - pos += os_snprintf(pos, imsi + max_len - pos, - "@wlan.mnc%s.mcc%c%c%c.3gppnetwork.org", - mnc, imsi[0], imsi[1], imsi[2]); - *imsi_len = pos - imsi; - - return 0; -} - - static int eap_sm_imsi_identity(struct eap_sm *sm, struct eap_peer_config *conf) { @@ -1450,7 +1499,7 @@ static int eap_sm_imsi_identity(struct eap_sm *sm, char imsi[100]; size_t imsi_len; struct eap_method_type *m = conf->eap_methods; - int i; + int i, mnc_len; imsi_len = sizeof(imsi); if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) { @@ -1465,7 +1514,18 @@ static int eap_sm_imsi_identity(struct eap_sm *sm, return -1; } - if (eap_sm_append_3gpp_realm(sm, imsi, sizeof(imsi), &imsi_len) < 0) { + /* MNC (2 or 3 digits) */ + mnc_len = scard_get_mnc_len(sm->scard_ctx); + if (mnc_len < 0) + mnc_len = mnc_len_from_imsi(imsi); + if (mnc_len < 0) { + wpa_printf(MSG_INFO, "Failed to get MNC length from (U)SIM " + "assuming 3"); + mnc_len = 3; + } + + if (eap_sm_append_3gpp_realm(sm, imsi, sizeof(imsi), &imsi_len, + mnc_len) < 0) { wpa_printf(MSG_WARNING, "Could not add realm to SIM identity"); return -1; } diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h index 80fbbf260..6d415dcb9 100644 --- a/src/eap_peer/eap.h +++ b/src/eap_peer/eap.h @@ -260,6 +260,15 @@ struct eapol_callbacks { */ void (*eap_proxy_notify_sim_status)(void *ctx, enum eap_proxy_sim_state sim_state); + + /** + * get_imsi - Get the IMSI value from eap_proxy + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @imsi: Buffer for IMSI value + * @len: Buffer for returning IMSI length in octets + * Returns: MNC length (2 or 3) or -1 on error + */ + int (*get_imsi)(void *ctx, char *imsi, size_t *len); #endif /* CONFIG_EAP_PROXY */ /** diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index ade43d8ef..75c3429f7 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -2065,6 +2065,7 @@ static const struct eapol_callbacks eapol_cb = #ifdef CONFIG_EAP_PROXY eapol_sm_eap_proxy_cb, eapol_sm_eap_proxy_notify_sim_status, + eapol_sm_get_eap_proxy_imsi, #endif /* CONFIG_EAP_PROXY */ eapol_sm_set_anon_id }; @@ -2173,8 +2174,10 @@ int eapol_sm_failed(struct eapol_sm *sm) #ifdef CONFIG_EAP_PROXY -int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len) +int eapol_sm_get_eap_proxy_imsi(void *ctx, char *imsi, size_t *len) { + struct eapol_sm *sm = ctx; + if (sm->eap_proxy == NULL) return -1; return eap_proxy_get_imsi(sm->eap_proxy, imsi, len); diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h index aa91b8cd5..458d51dd1 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -339,7 +339,7 @@ void eapol_sm_erp_flush(struct eapol_sm *sm); struct wpabuf * eapol_sm_build_erp_reauth_start(struct eapol_sm *sm); void eapol_sm_process_erp_finish(struct eapol_sm *sm, const u8 *buf, size_t len); -int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len); +int eapol_sm_get_eap_proxy_imsi(void *ctx, char *imsi, size_t *len); int eapol_sm_update_erp_next_seq_num(struct eapol_sm *sm, u16 next_seq_num); int eapol_sm_get_erp_info(struct eapol_sm *sm, struct eap_peer_config *config, const u8 **username, size_t *username_len,