diff --git a/hostapd/hostapd.eap_user b/hostapd/hostapd.eap_user index ac9a5d896..12a2c6129 100644 --- a/hostapd/hostapd.eap_user +++ b/hostapd/hostapd.eap_user @@ -69,6 +69,9 @@ "3"* SIM,TTLS,TLS,PEAP,AKA "4"* AKA,TTLS,TLS,PEAP,SIM "5"* SIM,TTLS,TLS,PEAP,AKA +"6"* AKA' +"7"* AKA' +"8"* AKA' # Wildcard for all other identities * PEAP,TTLS,TLS,SIM,AKA @@ -89,3 +92,6 @@ "3"* SIM [2] "4"* AKA [2] "5"* SIM [2] +"6"* AKA' [2] +"7"* AKA' [2] +"8"* AKA' [2] diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h index af0a29a23..360193a98 100644 --- a/src/eap_common/eap_defs.h +++ b/src/eap_common/eap_defs.h @@ -60,7 +60,7 @@ typedef enum { EAP_TYPE_PSK = 47 /* RFC 4764 */, EAP_TYPE_SAKE = 48 /* RFC 4763 */, EAP_TYPE_IKEV2 = 49 /* RFC 5106 */, - EAP_TYPE_AKA_PRIME = 50 /* draft-arkko-eap-aka-kdf-10.txt */, + EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */, EAP_TYPE_GPSK = 51 /* RFC 5433 */, EAP_TYPE_PWD = 52 /* RFC 5931 */, EAP_TYPE_EXPANDED = 254 /* RFC 3748 */ diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index f13d2e3b9..50a779786 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -938,7 +938,7 @@ static int eap_sm_append_3gpp_realm(struct eap_sm *sm, char *imsi, static int eap_sm_imsi_identity(struct eap_sm *sm, struct eap_peer_config *conf) { - int aka = 0; + enum { EAP_SM_SIM, EAP_SM_AKA, EAP_SM_AKA_PRIME } method = EAP_SM_SIM; char imsi[100]; size_t imsi_len; struct eap_method_type *m = conf->eap_methods; @@ -965,9 +965,15 @@ static int eap_sm_imsi_identity(struct eap_sm *sm, for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF || m[i].method != EAP_TYPE_NONE); i++) { + if (m[i].vendor == EAP_VENDOR_IETF && + m[i].method == EAP_TYPE_AKA_PRIME) { + method = EAP_SM_AKA_PRIME; + break; + } + if (m[i].vendor == EAP_VENDOR_IETF && m[i].method == EAP_TYPE_AKA) { - aka = 1; + method = EAP_SM_AKA; break; } } @@ -980,7 +986,17 @@ static int eap_sm_imsi_identity(struct eap_sm *sm, return -1; } - conf->identity[0] = aka ? '0' : '1'; + switch (method) { + case EAP_SM_SIM: + conf->identity[0] = '1'; + break; + case EAP_SM_AKA: + conf->identity[0] = '0'; + break; + case EAP_SM_AKA_PRIME: + conf->identity[0] = '6'; + break; + } os_memcpy(conf->identity + 1, imsi, imsi_len); conf->identity_len = 1 + imsi_len; diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c index f30e38d88..1cec4d8ab 100644 --- a/src/eap_peer/eap_aka.c +++ b/src/eap_peer/eap_aka.c @@ -1,6 +1,6 @@ /* - * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf) - * Copyright (c) 2004-2008, Jouni Malinen + * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448) + * Copyright (c) 2004-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c index 54f6ba149..de05dd5a4 100644 --- a/src/eap_server/eap_server_aka.c +++ b/src/eap_server/eap_server_aka.c @@ -1,6 +1,6 @@ /* - * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf) - * Copyright (c) 2005-2008, Jouni Malinen + * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (RFC 5448) + * Copyright (c) 2005-2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -294,7 +294,10 @@ static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data, os_free(data->next_pseudonym); if (nonce_s == NULL) { data->next_pseudonym = - eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1); + eap_sim_db_get_next_pseudonym( + sm->eap_sim_db_priv, + data->eap_method == EAP_TYPE_AKA_PRIME ? + EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA); } else { /* Do not update pseudonym during re-authentication */ data->next_pseudonym = NULL; @@ -302,7 +305,10 @@ static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data, os_free(data->next_reauth_id); if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) { data->next_reauth_id = - eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1); + eap_sim_db_get_next_reauth_id( + sm->eap_sim_db_priv, + data->eap_method == EAP_TYPE_AKA_PRIME ? + EAP_SIM_DB_AKA_PRIME : EAP_SIM_DB_AKA); } else { wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication " "count exceeded - force full authentication"); @@ -620,7 +626,8 @@ static void eap_aka_determine_identity(struct eap_sm *sm, identity = data->reauth->identity; identity_len = data->reauth->identity_len; } else if (sm->identity && sm->identity_len > 0 && - sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) { + (sm->identity[0] == EAP_AKA_PERMANENT_PREFIX || + sm->identity[0] == EAP_AKA_PRIME_PERMANENT_PREFIX)) { identity = sm->identity; identity_len = sm->identity_len; } else { diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c index b578eccd9..60ab0d4c4 100644 --- a/src/eap_server/eap_server_sim.c +++ b/src/eap_server/eap_server_sim.c @@ -133,7 +133,8 @@ static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data, os_free(data->next_pseudonym); if (nonce_s == NULL) { data->next_pseudonym = - eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 0); + eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, + EAP_SIM_DB_SIM); } else { /* Do not update pseudonym during re-authentication */ data->next_pseudonym = NULL; @@ -141,7 +142,8 @@ static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data, os_free(data->next_reauth_id); if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) { data->next_reauth_id = - eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 0); + eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, + EAP_SIM_DB_SIM); } else { wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication " "count exceeded - force full authentication"); diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c index 9db26dc61..ce3238c9b 100644 --- a/src/eap_server/eap_sim_db.c +++ b/src/eap_server/eap_sim_db.c @@ -1,6 +1,6 @@ /* * hostapd / EAP-SIM database/authenticator gateway - * Copyright (c) 2005-2007, Jouni Malinen + * Copyright (c) 2005-2010, 2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -647,7 +647,8 @@ eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity, if (identity_len == 0 || (identity[0] != EAP_SIM_PSEUDONYM_PREFIX && - identity[0] != EAP_AKA_PSEUDONYM_PREFIX)) + identity[0] != EAP_AKA_PSEUDONYM_PREFIX && + identity[0] != EAP_AKA_PRIME_PSEUDONYM_PREFIX)) return NULL; /* Remove possible realm from identity */ @@ -685,7 +686,8 @@ eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity, if (identity_len == 0 || (identity[0] != EAP_SIM_PERMANENT_PREFIX && - identity[0] != EAP_AKA_PERMANENT_PREFIX)) + identity[0] != EAP_AKA_PERMANENT_PREFIX && + identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) return NULL; p = data->pseudonyms; @@ -710,7 +712,8 @@ eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity, if (identity_len == 0 || (identity[0] != EAP_SIM_REAUTH_ID_PREFIX && - identity[0] != EAP_AKA_REAUTH_ID_PREFIX)) + identity[0] != EAP_AKA_REAUTH_ID_PREFIX && + identity[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX)) return NULL; /* Remove possible realm from identity */ @@ -777,8 +780,9 @@ eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity, * @identity_len: Length of identity in bytes * Returns: 0 if the user is found or -1 on failure * - * In most cases, the user name is ['0','1'] | IMSI, i.e., 1 followed by the - * IMSI in ASCII format, ['2','3'] | pseudonym, or ['4','5'] | reauth_id. + * In most cases, the user name is ['0','1','6'] | IMSI, i.e., 1 followed by + * the IMSI in ASCII format for EAP-SIM, ['2','3','7'] | pseudonym, or + * ['4','5','7'] | reauth_id. */ int eap_sim_db_identity_known(void *priv, const u8 *identity, size_t identity_len) @@ -789,21 +793,24 @@ int eap_sim_db_identity_known(void *priv, const u8 *identity, return -1; if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX || - identity[0] == EAP_AKA_PSEUDONYM_PREFIX) { + identity[0] == EAP_AKA_PSEUDONYM_PREFIX || + identity[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) { struct eap_sim_pseudonym *p = eap_sim_db_get_pseudonym(data, identity, identity_len); return p ? 0 : -1; } if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX || - identity[0] == EAP_AKA_REAUTH_ID_PREFIX) { + identity[0] == EAP_AKA_REAUTH_ID_PREFIX || + identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) { struct eap_sim_reauth *r = eap_sim_db_get_reauth(data, identity, identity_len); return r ? 0 : -1; } if (identity[0] != EAP_SIM_PERMANENT_PREFIX && - identity[0] != EAP_AKA_PERMANENT_PREFIX) { + identity[0] != EAP_AKA_PERMANENT_PREFIX && + identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) { /* Unknown identity prefix */ return -1; } @@ -843,7 +850,7 @@ static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix) /** * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym * @priv: Private data pointer from eap_sim_db_init() - * @aka: Using EAP-AKA instead of EAP-SIM + * @method: EAP method (SIM/AKA/AKA') * Returns: Next pseudonym (allocated string) or %NULL on failure * * This function is used to generate a pseudonym for EAP-SIM. The returned @@ -851,18 +858,31 @@ static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix) * with eap_sim_db_add_pseudonym() once the authentication has been completed * successfully. Caller is responsible for freeing the returned buffer. */ -char * eap_sim_db_get_next_pseudonym(void *priv, int aka) +char * eap_sim_db_get_next_pseudonym(void *priv, enum eap_sim_db_method method) { struct eap_sim_db_data *data = priv; - return eap_sim_db_get_next(data, aka ? EAP_AKA_PSEUDONYM_PREFIX : - EAP_SIM_PSEUDONYM_PREFIX); + char prefix = EAP_SIM_REAUTH_ID_PREFIX; + + switch (method) { + case EAP_SIM_DB_SIM: + prefix = EAP_SIM_PSEUDONYM_PREFIX; + break; + case EAP_SIM_DB_AKA: + prefix = EAP_AKA_PSEUDONYM_PREFIX; + break; + case EAP_SIM_DB_AKA_PRIME: + prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX; + break; + } + + return eap_sim_db_get_next(data, prefix); } /** * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id * @priv: Private data pointer from eap_sim_db_init() - * @aka: Using EAP-AKA instead of EAP-SIM + * @method: EAP method (SIM/AKA/AKA') * Returns: Next reauth_id (allocated string) or %NULL on failure * * This function is used to generate a fast re-authentication identity for @@ -871,11 +891,24 @@ char * eap_sim_db_get_next_pseudonym(void *priv, int aka) * has been completed successfully. Caller is responsible for freeing the * returned buffer. */ -char * eap_sim_db_get_next_reauth_id(void *priv, int aka) +char * eap_sim_db_get_next_reauth_id(void *priv, enum eap_sim_db_method method) { struct eap_sim_db_data *data = priv; - return eap_sim_db_get_next(data, aka ? EAP_AKA_REAUTH_ID_PREFIX : - EAP_SIM_REAUTH_ID_PREFIX); + char prefix = EAP_SIM_REAUTH_ID_PREFIX; + + switch (method) { + case EAP_SIM_DB_SIM: + prefix = EAP_SIM_REAUTH_ID_PREFIX; + break; + case EAP_SIM_DB_AKA: + prefix = EAP_AKA_REAUTH_ID_PREFIX; + break; + case EAP_SIM_DB_AKA_PRIME: + prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX; + break; + } + + return eap_sim_db_get_next(data, prefix); } @@ -1156,7 +1189,7 @@ void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth) * called once the results become available. * * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in - * ASCII format. + * ASCII format for EAP-AKA and '6' | IMSI for EAP-AKA'. * * When using an external server for AKA authentication, this function can * always start a request and return EAP_SIM_DB_PENDING immediately if @@ -1178,7 +1211,8 @@ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity, char msg[40]; if (identity_len < 2 || identity == NULL || - identity[0] != EAP_AKA_PERMANENT_PREFIX) { + (identity[0] != EAP_AKA_PERMANENT_PREFIX && + identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", identity, identity_len); return EAP_SIM_DB_FAILURE; @@ -1281,7 +1315,8 @@ int eap_sim_db_resynchronize(void *priv, const u8 *identity, size_t i; if (identity_len < 2 || identity == NULL || - identity[0] != EAP_AKA_PERMANENT_PREFIX) { + (identity[0] != EAP_AKA_PERMANENT_PREFIX && + identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", identity, identity_len); return -1; diff --git a/src/eap_server/eap_sim_db.h b/src/eap_server/eap_sim_db.h index abe185ec5..1f6375aa2 100644 --- a/src/eap_server/eap_sim_db.h +++ b/src/eap_server/eap_sim_db.h @@ -1,6 +1,6 @@ /* * hostapd / EAP-SIM database/authenticator gateway - * Copyright (c) 2005-2007, Jouni Malinen + * Copyright (c) 2005-2008, 2012, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -18,6 +18,15 @@ #define EAP_AKA_PERMANENT_PREFIX '0' #define EAP_AKA_PSEUDONYM_PREFIX '2' #define EAP_AKA_REAUTH_ID_PREFIX '4' +#define EAP_AKA_PRIME_PERMANENT_PREFIX '6' +#define EAP_AKA_PRIME_PSEUDONYM_PREFIX '7' +#define EAP_AKA_PRIME_REAUTH_ID_PREFIX '8' + +enum eap_sim_db_method { + EAP_SIM_DB_SIM, + EAP_SIM_DB_AKA, + EAP_SIM_DB_AKA_PRIME +}; void * eap_sim_db_init(const char *config, void (*get_complete_cb)(void *ctx, void *session_ctx), @@ -36,9 +45,11 @@ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity, int eap_sim_db_identity_known(void *priv, const u8 *identity, size_t identity_len); -char * eap_sim_db_get_next_pseudonym(void *priv, int aka); +char * eap_sim_db_get_next_pseudonym(void *priv, + enum eap_sim_db_method method); -char * eap_sim_db_get_next_reauth_id(void *priv, int aka); +char * eap_sim_db_get_next_reauth_id(void *priv, + enum eap_sim_db_method method); int eap_sim_db_add_pseudonym(void *priv, const u8 *identity, size_t identity_len, char *pseudonym);