]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
EAP-FAST: Move EAP-MSCHAPv2 special MSK handling into MSCHAPv2
authorJouni Malinen <quic_jouni@quicinc.com>
Thu, 1 Dec 2022 13:56:29 +0000 (15:56 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 1 Dec 2022 15:53:05 +0000 (17:53 +0200)
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 <quic_jouni@quicinc.com>
src/eap_peer/eap.c
src/eap_peer/eap_fast.c
src/eap_peer/eap_i.h
src/eap_peer/eap_mschapv2.c
src/eap_server/eap_i.h
src/eap_server/eap_server_fast.c
src/eap_server/eap_server_mschapv2.c

index a39a86d54f18b41fe93f20f01b2ff6c21977391e..d0706021312244fc23da97cceb096c6f87733181 100644 (file)
@@ -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;
 }
 
 
index b12cfee31ad8ec9862c99f473ecbf1359fecc185..d7677ca97d60fdf0970e1bfdd66e660eaa960188 100644 (file)
@@ -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;
index f43891e39d1cfd52e5be7beefebc68860010b22f..08dd569d6a60d90f5d206033e54cc474927f9eca 100644 (file)
@@ -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;
index 8ad4d18b3535393b6f893452bbe0aa08abba208d..e84ae16b47be90a6b89dc89a64b4e03b7669d4fe 100644 (file)
@@ -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;
        }
index 28bb564e9331b160794f325c08f1948a8fd858d7..1c59bb0cc62b03bccff41ef694632c3dd07c7077 100644 (file)
@@ -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;
 
index 55d48d91f6069c191b2bca8cf1c47b5804a1a5d5..0596334fd031089958dd2081b7c309e1cbe9e58d 100644 (file)
@@ -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;
index 9b3eb26ef4532bdf57ba945a554e7c07009442ae..3dc6a39418c26241fc508e117a375ec05920a115 100644 (file)
@@ -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;
        }