From 01b05694372c718f88d921785f8f1133e9992c36 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 5 Dec 2008 22:25:47 +0200 Subject: [PATCH] Added protection against EAP-AKA' -> EAP-AKA bidding down attacks AT_BIDDING attribute is included in EAP-AKA/Challenge to allow peer to know whether the server would have preferred EAP-AKA'. --- src/eap_common/eap_sim_common.c | 10 ++++++++++ src/eap_common/eap_sim_common.h | 6 ++++++ src/eap_peer/eap.c | 2 +- src/eap_peer/eap_aka_prime.c | 12 ++++++++++++ src/eap_peer/eap_i.h | 1 + src/eap_server/eap_aka_prime.c | 29 +++++++++++++++++++++++++++++ 6 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/eap_common/eap_sim_common.c b/src/eap_common/eap_sim_common.c index a99791cd9..fccda0241 100644 --- a/src/eap_common/eap_sim_common.c +++ b/src/eap_common/eap_sim_common.c @@ -903,6 +903,16 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end, attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos); attr->kdf_count++; break; + case EAP_SIM_AT_BIDDING: + wpa_printf(MSG_DEBUG, "EAP-AKA: AT_BIDDING"); + if (alen != 2) { + wpa_printf(MSG_INFO, "EAP-AKA: Invalid " + "AT_BIDDING (len %lu)", + (unsigned long) alen); + return -1; + } + attr->bidding = apos; + break; #endif /* EAP_AKA_PRIME */ default: if (pos[0] < 128) { diff --git a/src/eap_common/eap_sim_common.h b/src/eap_common/eap_sim_common.h index 83df8d554..22f56ed2f 100644 --- a/src/eap_common/eap_sim_common.h +++ b/src/eap_common/eap_sim_common.h @@ -138,6 +138,7 @@ void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak, #define EAP_SIM_AT_NEXT_REAUTH_ID 133 /* only encrypted */ #define EAP_SIM_AT_CHECKCODE 134 /* only AKA */ #define EAP_SIM_AT_RESULT_IND 135 +#define EAP_SIM_AT_BIDDING 136 /* AT_NOTIFICATION notification code values */ #define EAP_SIM_GENERAL_FAILURE_AFTER_AUTH 0 @@ -149,6 +150,10 @@ void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak, /* EAP-AKA' AT_KDF Key Derivation Function values */ #define EAP_AKA_PRIME_KDF 1 +/* AT_BIDDING flags */ +#define EAP_AKA_BIDDING_FLAG_D 0x8000 + + enum eap_sim_id_req { NO_ID_REQ, ANY_ID, FULLAUTH_ID, PERMANENT_ID }; @@ -160,6 +165,7 @@ struct eap_sim_attrs { const u8 *nonce_mt, *identity, *res, *auts; const u8 *checkcode; const u8 *kdf_input; + const u8 *bidding; size_t num_chal, version_list_len, encr_data_len; size_t next_pseudonym_len, next_reauth_id_len, identity_len, res_len; size_t res_len_bits; diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 88377b9ed..5f1c9e04e 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -106,7 +106,7 @@ static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt) * @method: EAP type * Returns: 1 = allowed EAP method, 0 = not allowed */ -static int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method) +int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method) { struct eap_peer_config *config = eap_get_config(sm); int i; diff --git a/src/eap_peer/eap_aka_prime.c b/src/eap_peer/eap_aka_prime.c index 52f74eeef..bf1d472e6 100644 --- a/src/eap_peer/eap_aka_prime.c +++ b/src/eap_peer/eap_aka_prime.c @@ -791,6 +791,18 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm, data->kdf = EAP_AKA_PRIME_KDF; wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf); } + + if (data->eap_method == EAP_TYPE_AKA && attr->bidding) { + u16 flags = WPA_GET_BE16(attr->bidding); + if ((flags & EAP_AKA_BIDDING_FLAG_D) && + eap_allowed_method(sm, EAP_VENDOR_IETF, + EAP_TYPE_AKA_PRIME)) { + wpa_printf(MSG_WARNING, "EAP-AKA: Bidding down from " + "AKA' to AKA detected"); + /* Fail authentication as if AUTN had been incorrect */ + return eap_aka_authentication_reject(data, id); + } + } #endif /* EAP_AKA_PRIME */ data->reauth = 0; diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h index 73f3f838b..25c0bb6fc 100644 --- a/src/eap_peer/eap_i.h +++ b/src/eap_peer/eap_i.h @@ -349,5 +349,6 @@ void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob); const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm, const char *name); void eap_notify_pending(struct eap_sm *sm); +int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method); #endif /* EAP_I_H */ diff --git a/src/eap_server/eap_aka_prime.c b/src/eap_server/eap_aka_prime.c index 7cd50445e..19621323f 100644 --- a/src/eap_server/eap_aka_prime.c +++ b/src/eap_server/eap_aka_prime.c @@ -396,6 +396,35 @@ static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm, eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0); } +#ifdef EAP_AKA_PRIME + if (data->eap_method == EAP_TYPE_AKA) { + u16 flags = 0; + int i; + int aka_prime_preferred = 0; + + i = 0; + while (sm->user && i < EAP_MAX_METHODS && + (sm->user->methods[i].vendor != EAP_VENDOR_IETF || + sm->user->methods[i].method != EAP_TYPE_NONE)) { + if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) { + if (sm->user->methods[i].method == + EAP_TYPE_AKA) + break; + if (sm->user->methods[i].method == + EAP_TYPE_AKA_PRIME) { + aka_prime_preferred = 1; + break; + } + } + i++; + } + + if (aka_prime_preferred) + flags |= EAP_AKA_BIDDING_FLAG_D; + eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0); + } +#endif /* EAP_AKA_PRIME */ + wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); return eap_sim_msg_finish(msg, data->k_aut, NULL, 0);