From: Jouni Malinen Date: Thu, 1 Dec 2022 13:56:29 +0000 (+0200) Subject: EAP-FAST: Move EAP-MSCHAPv2 special MSK handling into MSCHAPv2 X-Git-Tag: hostap_2_11~1430 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=364b6500b8cd162f666351102812ba3c1218ff2a;p=thirdparty%2Fhostap.git EAP-FAST: Move EAP-MSCHAPv2 special MSK handling into MSCHAPv2 EAP-FAST uses a special variant of EAP-MSHCAPv2 called EAP-FAST-MSCHAPv2 in RFC 5422. The only difference between that and EAP-MSCHAPv2 is in how the MSK is derived. While this was supposed to be specific to EAP-FAST, the same design has ended up getting deployed with EAP-TEAP as well. Move this special handling into EAP-MSCHAPv2 implementation so that it can be shared for both needs. Signed-off-by: Jouni Malinen --- diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index a39a86d54..d07060213 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -267,6 +267,7 @@ SM_STATE(EAP, INITIALIZE) sm->reauthInit = false; sm->erp_seq = (u32) -1; sm->use_machine_cred = 0; + sm->eap_fast_mschapv2 = false; } diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c index b12cfee31..d7677ca97 100644 --- a/src/eap_peer/eap_fast.c +++ b/src/eap_peer/eap_fast.c @@ -354,6 +354,7 @@ static int eap_fast_init_phase2_method(struct eap_sm *sm, sm->auth_challenge = data->key_block_p->server_challenge; sm->peer_challenge = data->key_block_p->client_challenge; } + sm->eap_fast_mschapv2 = true; sm->init_phase2 = 1; data->phase2_priv = data->phase2_method->init(sm); sm->init_phase2 = 0; @@ -693,18 +694,7 @@ static int eap_fast_get_phase2_key(struct eap_sm *sm, if (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); return 0; diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h index f43891e39..08dd569d6 100644 --- a/src/eap_peer/eap_i.h +++ b/src/eap_peer/eap_i.h @@ -365,6 +365,11 @@ struct eap_sm { /* Optional challenges generated in Phase 1 (EAP-FAST) */ u8 *peer_challenge, *auth_challenge; + /* Whether to use the EAP-FAST-MSCHAPv2 instantiation of EAP-MSCHAPv2. + * That variant is otherwise identical, but it generates the MSK using + * MS-MPPE keys in reverse order. */ + bool eap_fast_mschapv2; + int num_rounds; int num_rounds_short; int force_disabled; diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c index 8ad4d18b3..e84ae16b4 100644 --- a/src/eap_peer/eap_mschapv2.c +++ b/src/eap_peer/eap_mschapv2.c @@ -108,6 +108,12 @@ static void * eap_mschapv2_init(struct eap_sm *sm) if (data == NULL) return NULL; + wpa_printf(MSG_DEBUG, "EAP-%sMSCHAPv2 init%s%s", + sm->eap_fast_mschapv2 ? "FAST-" : "", + sm->peer_challenge && sm->auth_challenge ? + " with preset challenges" : "", + sm->init_phase2 ? " for Phase 2" : ""); + if (sm->peer_challenge) { data->peer_challenge = os_memdup(sm->peer_challenge, MSCHAPV2_CHAL_LEN); @@ -844,6 +850,7 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) struct eap_mschapv2_data *data = priv; u8 *key; int key_len; + bool first_is_send; if (!data->master_key_valid || !data->success) return NULL; @@ -854,12 +861,25 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) if (key == NULL) return NULL; - /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e., - * peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */ - if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, - 0) < 0 || + /* + * [MS-CHAP], 3.1.5.1 (Master Session Key (MSK) Derivation + * MSK = MasterReceiveKey + MasterSendKey + 32 bytes zeros (padding) + * On a Peer: + * MS-MPPE-Recv-Key = MasterSendKey + * MS-MPPE-Send-Key = MasterReceiveKey + * + * RFC 5422, 3.2.3 (Authenticating Using EAP-FAST-MSCHAPv2) + * MSK = MasterSendKey + MasterReceiveKey + * (i.e., reverse order and no padding) + * + * On Peer, EAP-MSCHAPv2 starts with Send key and EAP-FAST-MSCHAPv2 + * starts with Receive key. + */ + first_is_send = !sm->eap_fast_mschapv2; + if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, + first_is_send, 0) < 0 || get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN, - MSCHAPV2_KEY_LEN, 0, 0) < 0) { + MSCHAPV2_KEY_LEN, !first_is_send, 0) < 0) { os_free(key); return NULL; } diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h index 28bb564e9..1c59bb0cc 100644 --- a/src/eap_server/eap_i.h +++ b/src/eap_server/eap_i.h @@ -176,9 +176,15 @@ struct eap_sm { METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT } method_pending; + /* Optional challenges generated in Phase 1 (EAP-FAST) */ u8 *auth_challenge; u8 *peer_challenge; + /* Whether to use the EAP-FAST-MSCHAPv2 instantiation of EAP-MSCHAPv2. + * That variant is otherwise identical, but it generates the MSK using + * MS-MPPE keys in reverse order. */ + bool eap_fast_mschapv2; + struct wpabuf *assoc_wps_ie; struct wpabuf *assoc_p2p_ie; diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c index 55d48d91f..0596334fd 100644 --- a/src/eap_server/eap_server_fast.c +++ b/src/eap_server/eap_server_fast.c @@ -357,18 +357,7 @@ static int eap_fast_get_phase2_key(struct eap_sm *sm, if (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); return 0; @@ -961,6 +950,7 @@ static int eap_fast_phase2_init(struct eap_sm *sm, struct eap_fast_data *data, sm->auth_challenge = data->key_block_p->server_challenge; sm->peer_challenge = data->key_block_p->client_challenge; } + sm->eap_fast_mschapv2 = true; sm->init_phase2 = 1; data->phase2_priv = data->phase2_method->init(sm); sm->init_phase2 = 0; diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c index 9b3eb26ef..3dc6a3941 100644 --- a/src/eap_server/eap_server_mschapv2.c +++ b/src/eap_server/eap_server_mschapv2.c @@ -64,6 +64,12 @@ static void * eap_mschapv2_init(struct eap_sm *sm) return NULL; data->state = CHALLENGE; + wpa_printf(MSG_DEBUG, "EAP-%sMSCHAPv2 init%s%s", + sm->eap_fast_mschapv2 ? "FAST-" : "", + sm->peer_challenge && sm->auth_challenge ? + " with preset challenges" : "", + sm->init_phase2 ? " for Phase 2" : ""); + if (sm->auth_challenge) { os_memcpy(data->auth_challenge, sm->auth_challenge, CHALLENGE_LEN); @@ -542,6 +548,7 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) { struct eap_mschapv2_data *data = priv; u8 *key; + bool first_is_send; if (data->state != SUCCESS || !data->master_key_valid) return NULL; @@ -550,11 +557,26 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len) key = os_malloc(*len); if (key == NULL) return NULL; + /* + * [MS-CHAP], 3.1.5.1 (Master Session Key (MSK) Derivation + * MSK = MasterReceiveKey + MasterSendKey + 32 bytes zeros (padding) + * On an Authenticator: + * MS-MPPE-Recv-Key = MasterReceiveKey + * MS-MPPE-Send-Key = MasterSendKey + * + * RFC 5422, 3.2.3 (Authenticating Using EAP-FAST-MSCHAPv2) + * MSK = MasterSendKey + MasterReceiveKey + * (i.e., reverse order and no padding) + * + * On Peer, EAP-MSCHAPv2 starts with Send key and EAP-FAST-MSCHAPv2 + * starts with Receive key. + */ + first_is_send = sm->eap_fast_mschapv2; /* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */ - if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, - 1) < 0 || + if (get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, + first_is_send, 1) < 0 || get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN, - MSCHAPV2_KEY_LEN, 1, 1) < 0) { + MSCHAPV2_KEY_LEN, !first_is_send, 1) < 0) { os_free(key); return NULL; }