Browse Source

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'.
Jouni Malinen 16 years ago
parent
commit
01b0569437

+ 10 - 0
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) {

+ 6 - 0
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;

+ 1 - 1
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;

+ 12 - 0
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;

+ 1 - 0
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 */

+ 29 - 0
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);