Browse Source

Cleaned up EAP-MSCHAPv2 key derivation

Changed peer to derive the full key (both MS-MPPE-Recv-Key and
MS-MPPE-Send-Key for total of 32 octets) to match with server
implementation.

Swapped the order of MPPE keys in MSK derivation since server
MS-MPPE-Recv-Key | MS-MPPE-Send-Key matches with the order specified for
EAP-TLS MSK derivation. This means that PEAPv0 cryptobinding is now
using EAP-MSCHAPv2 MSK as-is for ISK while EAP-FAST will need to swap
the order of the MPPE keys to get ISK in a way that interoperates with
Cisco EAP-FAST implementation.
Jouni Malinen 16 years ago
parent
commit
000a1de72b

+ 12 - 3
src/eap_peer/eap_fast.c

@@ -343,10 +343,8 @@ static int eap_fast_init_phase2_method(struct eap_sm *sm,
 		sm->peer_challenge = data->key_block_p->client_challenge;
 		sm->peer_challenge = data->key_block_p->client_challenge;
 	}
 	}
 	sm->init_phase2 = 1;
 	sm->init_phase2 = 1;
-	sm->mschapv2_full_key = 1;
 	data->phase2_priv = data->phase2_method->init(sm);
 	data->phase2_priv = data->phase2_method->init(sm);
 	sm->init_phase2 = 0;
 	sm->init_phase2 = 0;
-	sm->mschapv2_full_key = 0;
 	sm->auth_challenge = NULL;
 	sm->auth_challenge = NULL;
 	sm->peer_challenge = NULL;
 	sm->peer_challenge = NULL;
 
 
@@ -661,7 +659,18 @@ static int eap_fast_get_phase2_key(struct eap_sm *sm,
 
 
 	if (key_len > isk_len)
 	if (key_len > isk_len)
 		key_len = isk_len;
 		key_len = isk_len;
-	os_memcpy(isk, key, key_len);
+	if (key_len == 32 &&
+	    data->phase2_method->vendor == EAP_VENDOR_IETF &&
+	    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
+		/*
+		 * EAP-FAST uses reverse order for MS-MPPE keys when deriving
+		 * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct
+		 * ISK for EAP-FAST cryptobinding.
+		 */
+		os_memcpy(isk, key + 16, 16);
+		os_memcpy(isk + 16, key, 16);
+	} else
+		os_memcpy(isk, key, key_len);
 	os_free(key);
 	os_free(key);
 
 
 	return 0;
 	return 0;

+ 0 - 1
src/eap_peer/eap_i.h

@@ -328,7 +328,6 @@ struct eap_sm {
 
 
 	/* Optional challenges generated in Phase 1 (EAP-FAST) */
 	/* Optional challenges generated in Phase 1 (EAP-FAST) */
 	u8 *peer_challenge, *auth_challenge;
 	u8 *peer_challenge, *auth_challenge;
-	int mschapv2_full_key; /* Request full MSCHAPv2 key */
 
 
 	int num_rounds;
 	int num_rounds;
 	int force_disabled;
 	int force_disabled;

+ 6 - 20
src/eap_peer/eap_mschapv2.c

@@ -93,7 +93,6 @@ struct eap_mschapv2_data {
 	 */
 	 */
 	u8 *peer_challenge;
 	u8 *peer_challenge;
 	u8 *auth_challenge;
 	u8 *auth_challenge;
-	int full_key;
 
 
 	int phase2;
 	int phase2;
 	u8 master_key[MSCHAPV2_MASTER_KEY_LEN];
 	u8 master_key[MSCHAPV2_MASTER_KEY_LEN];
@@ -114,10 +113,7 @@ static void * eap_mschapv2_init(struct eap_sm *sm)
 	if (data == NULL)
 	if (data == NULL)
 		return NULL;
 		return NULL;
 
 
-	data->full_key = sm->mschapv2_full_key;
-
 	if (sm->peer_challenge) {
 	if (sm->peer_challenge) {
-		data->full_key = 1;
 		data->peer_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
 		data->peer_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
 		if (data->peer_challenge == NULL) {
 		if (data->peer_challenge == NULL) {
 			eap_mschapv2_deinit(sm, data);
 			eap_mschapv2_deinit(sm, data);
@@ -830,27 +826,17 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
 	if (!data->master_key_valid || !data->success)
 	if (!data->master_key_valid || !data->success)
 		return NULL;
 		return NULL;
 
 
-	if (data->full_key) {
-		/* EAP-FAST needs both send and receive keys */
-		key_len = 2 * MSCHAPV2_KEY_LEN;
-	} else {
-		key_len = MSCHAPV2_KEY_LEN;
-	}
+	key_len = 2 * MSCHAPV2_KEY_LEN;
 
 
 	key = os_malloc(key_len);
 	key = os_malloc(key_len);
 	if (key == NULL)
 	if (key == NULL)
 		return NULL;
 		return NULL;
 
 
-	if (data->full_key) {
-		get_asymetric_start_key(data->master_key, key,
-					MSCHAPV2_KEY_LEN, 0, 0);
-		get_asymetric_start_key(data->master_key,
-					key + MSCHAPV2_KEY_LEN,
-					MSCHAPV2_KEY_LEN, 1, 0);
-	} else {
-		get_asymetric_start_key(data->master_key, key,
-					MSCHAPV2_KEY_LEN, 1, 0);
-	}
+	/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e.,
+	 *	peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */
+	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0);
+	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
+				MSCHAPV2_KEY_LEN, 0, 0);
 
 
 	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
 	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
 			key, key_len);
 			key, key_len);

+ 0 - 17
src/eap_peer/eap_peap.c

@@ -238,21 +238,6 @@ static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data,
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if (key_len == 32 &&
-	    data->phase2_method->vendor == EAP_VENDOR_IETF &&
-	    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
-		/*
-		 * Microsoft uses reverse order for MS-MPPE keys in
-		 * EAP-PEAP when compared to EAP-FAST derivation of
-		 * ISK. Swap the keys here to get the correct ISK for
-		 * EAP-PEAPv0 cryptobinding.
-		 */
-		u8 tmp[16];
-		os_memcpy(tmp, key, 16);
-		os_memcpy(key, key + 16, 16);
-		os_memcpy(key + 16, tmp, 16);
-	}
-
 	if (key_len > isk_len)
 	if (key_len > isk_len)
 		key_len = isk_len;
 		key_len = isk_len;
 	os_memcpy(isk, key, key_len);
 	os_memcpy(isk, key, key_len);
@@ -731,11 +716,9 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
 				data->phase2_type.method);
 				data->phase2_type.method);
 			if (data->phase2_method) {
 			if (data->phase2_method) {
 				sm->init_phase2 = 1;
 				sm->init_phase2 = 1;
-				sm->mschapv2_full_key = 1;
 				data->phase2_priv =
 				data->phase2_priv =
 					data->phase2_method->init(sm);
 					data->phase2_method->init(sm);
 				sm->init_phase2 = 0;
 				sm->init_phase2 = 0;
-				sm->mschapv2_full_key = 0;
 			}
 			}
 		}
 		}
 		if (data->phase2_priv == NULL || data->phase2_method == NULL) {
 		if (data->phase2_priv == NULL || data->phase2_method == NULL) {

+ 0 - 2
src/eap_peer/eap_ttls.c

@@ -558,10 +558,8 @@ static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm,
 			EAP_VENDOR_IETF, method);
 			EAP_VENDOR_IETF, method);
 		if (data->phase2_method) {
 		if (data->phase2_method) {
 			sm->init_phase2 = 1;
 			sm->init_phase2 = 1;
-			sm->mschapv2_full_key = 1;
 			data->phase2_priv = data->phase2_method->init(sm);
 			data->phase2_priv = data->phase2_method->init(sm);
 			sm->init_phase2 = 0;
 			sm->init_phase2 = 0;
-			sm->mschapv2_full_key = 0;
 		}
 		}
 	}
 	}
 	if (data->phase2_priv == NULL || data->phase2_method == NULL) {
 	if (data->phase2_priv == NULL || data->phase2_method == NULL) {

+ 12 - 1
src/eap_server/eap_fast.c

@@ -354,7 +354,18 @@ static int eap_fast_get_phase2_key(struct eap_sm *sm,
 
 
 	if (key_len > isk_len)
 	if (key_len > isk_len)
 		key_len = isk_len;
 		key_len = isk_len;
-	os_memcpy(isk, key, key_len);
+	if (key_len == 32 &&
+	    data->phase2_method->vendor == EAP_VENDOR_IETF &&
+	    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
+		/*
+		 * EAP-FAST uses reverse order for MS-MPPE keys when deriving
+		 * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct
+		 * ISK for EAP-FAST cryptobinding.
+		 */
+		os_memcpy(isk, key + 16, 16);
+		os_memcpy(isk + 16, key, 16);
+	} else
+		os_memcpy(isk, key, key_len);
 	os_free(key);
 	os_free(key);
 
 
 	return 0;
 	return 0;

+ 3 - 2
src/eap_server/eap_mschapv2.c

@@ -524,9 +524,10 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
 	key = os_malloc(*len);
 	key = os_malloc(*len);
 	if (key == NULL)
 	if (key == NULL)
 		return NULL;
 		return NULL;
-	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 0);
+	/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */
+	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 1);
 	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
 	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
-				MSCHAPV2_KEY_LEN, 1, 0);
+				MSCHAPV2_KEY_LEN, 1, 1);
 	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
 	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
 
 
 	return key;
 	return key;

+ 0 - 15
src/eap_server/eap_peap.c

@@ -975,21 +975,6 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
 			eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
 			eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
 			return;
 			return;
 		}
 		}
-
-		if (data->phase2_key_len == 32 &&
-		    data->phase2_method->vendor == EAP_VENDOR_IETF &&
-		    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
-			/*
-			 * Microsoft uses reverse order for MS-MPPE keys in
-			 * EAP-PEAP when compared to EAP-FAST derivation of
-			 * ISK. Swap the keys here to get the correct ISK for
-			 * EAP-PEAPv0 cryptobinding.
-			 */
-			u8 tmp[16];
-			os_memcpy(tmp, data->phase2_key, 16);
-			os_memcpy(data->phase2_key, data->phase2_key + 16, 16);
-			os_memcpy(data->phase2_key + 16, tmp, 16);
-		}
 	}
 	}
 
 
 	switch (data->state) {
 	switch (data->state) {

+ 10 - 0
wpa_supplicant/eapol_test.c

@@ -560,6 +560,16 @@ static void ieee802_1x_get_keys(struct eapol_test_data *e,
 				keys->recv_len;
 				keys->recv_len;
 			os_memcpy(e->authenticator_pmk, keys->recv,
 			os_memcpy(e->authenticator_pmk, keys->recv,
 				  e->authenticator_pmk_len);
 				  e->authenticator_pmk_len);
+			if (e->authenticator_pmk_len == 16 && keys->send &&
+			    keys->send_len == 16) {
+				/* MS-CHAP-v2 derives 16 octet keys */
+				wpa_printf(MSG_DEBUG, "Use MS-MPPE-Send-Key "
+					   "to extend PMK to 32 octets");
+				os_memcpy(e->authenticator_pmk +
+					  e->authenticator_pmk_len,
+					  keys->send, keys->send_len);
+				e->authenticator_pmk_len += keys->send_len;
+			}
 		}
 		}
 
 
 		os_free(keys->send);
 		os_free(keys->send);