From c6268e103f99f2e76b439d8985fc3e3dc64143ea Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 21 Sep 2023 11:00:04 +0300 Subject: [PATCH] EAP-SIM/AKA server: Allow method specific identity exchange to be skipped While the EAP-SIM/AKA RFCs recommend against doing this, some deployed authentication servers use the identity from the EAP-Response/Identity directly without using an EAP method specific indication (AT_IDENTITY). Having a capability to configure hostapd EAP server to behave in this manner helps in increasing testing coverage for the EAP peer implementation. Signed-off-by: Jouni Malinen --- hostapd/hostapd.conf | 8 +++++++ src/eap_server/eap_i.h | 1 + src/eap_server/eap_server_aka.c | 19 +++++++++++++++- src/eap_server/eap_server_sim.c | 39 ++++++++++++++++++++++++++++----- 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index bafc9232b..b8d27112b 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1465,6 +1465,14 @@ eap_server=0 # 1 = use pseudonyms, but not fast reauthentication # 2 = do not use pseudonyms, but use fast reauthentication # 3 = use pseudonyms and use fast reauthentication (default) +# 4 = do not use pseudonyms or fast reauthentication and allow +# EAP-Response/Identity to be used without method specific identity exchange +# 5 = use pseudonyms, but not fast reauthentication and allow +# EAP-Response/Identity to be used without method specific identity exchange +# 6 = do not use pseudonyms, but use fast reauthentication and allow +# EAP-Response/Identity to be used without method specific identity exchange +# 7 = use pseudonyms and use fast reauthentication and allow +# EAP-Response/Identity to be used without method specific identity exchange #eap_sim_id=3 # IMSI privacy key (PEM encoded RSA 2048-bit private key) for decrypting diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h index 1c59bb0cc..10affa431 100644 --- a/src/eap_server/eap_i.h +++ b/src/eap_server/eap_i.h @@ -160,6 +160,7 @@ struct eap_sm { size_t identity_len; char *serial_num; char imsi[20]; + char sim_aka_permanent[20]; /* Whether Phase 2 method should validate identity match */ int require_identity_match; int lastId; /* Identifier used in the last EAP-Packet */ diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c index 5fb19e976..c154d7f6e 100644 --- a/src/eap_server/eap_server_aka.c +++ b/src/eap_server/eap_server_aka.c @@ -134,10 +134,17 @@ static void eap_aka_check_identity(struct eap_sm *sm, struct eap_aka_data *data) { char *username; + const u8 *identity = sm->identity; + size_t identity_len = sm->identity_len; + + if (sm->sim_aka_permanent[0]) { + identity = (const u8 *) sm->sim_aka_permanent; + identity_len = os_strlen(sm->sim_aka_permanent); + } /* Check if we already know the identity from EAP-Response/Identity */ - username = sim_get_username(sm->identity, sm->identity_len); + username = sim_get_username(identity, identity_len); if (username == NULL) return; @@ -150,6 +157,16 @@ static void eap_aka_check_identity(struct eap_sm *sm, return; } + if (sm->sim_aka_permanent[0] && data->state == IDENTITY) { + /* Skip AKA/Identity exchange since the permanent identity + * was recognized. */ + os_free(username); + os_strlcpy(data->permanent, sm->sim_aka_permanent, + sizeof(data->permanent)); + eap_aka_fullauth(sm, data); + return; + } + if ((data->eap_method == EAP_TYPE_AKA_PRIME && username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) || (data->eap_method == EAP_TYPE_AKA && diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c index 1bcf26c46..51faca95f 100644 --- a/src/eap_server/eap_server_sim.c +++ b/src/eap_server/eap_server_sim.c @@ -106,12 +106,28 @@ static struct wpabuf * eap_sim_build_start(struct eap_sm *sm, { struct eap_sim_msg *msg; u8 ver[2]; + bool id_req = true; wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start"); msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START); data->start_round++; - if (data->start_round == 1) { + + if (data->start_round == 1 && (sm->cfg->eap_sim_id & 0x04)) { + char *username; + + username = sim_get_username(sm->identity, sm->identity_len); + if (username && username[0] == EAP_SIM_REAUTH_ID_PREFIX && + eap_sim_db_get_reauth_entry(sm->cfg->eap_sim_db_priv, + username)) + id_req = false; + + os_free(username); + } + + if (!id_req) { + wpa_printf(MSG_DEBUG, " No identity request"); + } else if (data->start_round == 1) { /* * RFC 4186, Chap. 4.2.4 recommends that identity from EAP is * ignored and the SIM/Start is used to request the identity. @@ -434,6 +450,7 @@ static void eap_sim_process_start(struct eap_sm *sm, struct wpabuf *respData, struct eap_sim_attrs *attr) { + const u8 *identity; size_t identity_len; u8 ver_list[2]; u8 *new_identity; @@ -449,9 +466,13 @@ static void eap_sim_process_start(struct eap_sm *sm, goto skip_id_update; } + if ((sm->cfg->eap_sim_id & 0x04) && + (!attr->identity || attr->identity_len == 0)) + goto skip_id_attr; + /* - * We always request identity in SIM/Start, so the peer is required to - * have replied with one. + * Unless explicitly configured otherwise, we always request identity + * in SIM/Start, so the peer is required to have replied with one. */ if (!attr->identity || attr->identity_len == 0) { wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any " @@ -467,9 +488,17 @@ static void eap_sim_process_start(struct eap_sm *sm, os_memcpy(sm->identity, attr->identity, attr->identity_len); sm->identity_len = attr->identity_len; +skip_id_attr: + if (sm->sim_aka_permanent[0]) { + identity = (const u8 *) sm->sim_aka_permanent; + identity_len = os_strlen(sm->sim_aka_permanent); + } else { + identity = sm->identity; + identity_len = sm->identity_len; + } wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity", - sm->identity, sm->identity_len); - username = sim_get_username(sm->identity, sm->identity_len); + identity, identity_len); + username = sim_get_username(identity, identity_len); if (username == NULL) goto failed;