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.
This commit is contained in:
Jouni Malinen 2008-12-14 13:12:20 +02:00
parent 6e783c6da9
commit 000a1de72b
9 changed files with 43 additions and 61 deletions

View file

@ -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,6 +659,17 @@ 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;
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_memcpy(isk, key, key_len);
os_free(key); os_free(key);

View file

@ -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;

View file

@ -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; key_len = 2 * MSCHAPV2_KEY_LEN;
} else {
key_len = 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) { /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e.,
get_asymetric_start_key(data->master_key, key, * 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); 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);
}
wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
key, key_len); key, key_len);

View file

@ -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) {

View file

@ -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) {

View file

@ -354,6 +354,17 @@ 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;
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_memcpy(isk, key, key_len);
os_free(key); os_free(key);

View file

@ -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;

View file

@ -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) {

View file

@ -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);