Cleaned up EAP-MSCHAPv2 key derivation
authorJouni Malinen <j@w1.fi>
Sun, 14 Dec 2008 11:12:20 +0000 (13:12 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 14 Dec 2008 11:12:20 +0000 (13:12 +0200)
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.

src/eap_peer/eap_fast.c
src/eap_peer/eap_i.h
src/eap_peer/eap_mschapv2.c
src/eap_peer/eap_peap.c
src/eap_peer/eap_ttls.c
src/eap_server/eap_fast.c
src/eap_server/eap_mschapv2.c
src/eap_server/eap_peap.c
wpa_supplicant/eapol_test.c

index b19f298..07e345f 100644 (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->init_phase2 = 1;
-       sm->mschapv2_full_key = 1;
        data->phase2_priv = data->phase2_method->init(sm);
        sm->init_phase2 = 0;
-       sm->mschapv2_full_key = 0;
        sm->auth_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)
                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);
 
        return 0;
index 25c0bb6..4b7029e 100644 (file)
@@ -328,7 +328,6 @@ struct eap_sm {
 
        /* Optional challenges generated in Phase 1 (EAP-FAST) */
        u8 *peer_challenge, *auth_challenge;
-       int mschapv2_full_key; /* Request full MSCHAPv2 key */
 
        int num_rounds;
        int force_disabled;
index e025442..b0c3ab7 100644 (file)
@@ -93,7 +93,6 @@ struct eap_mschapv2_data {
         */
        u8 *peer_challenge;
        u8 *auth_challenge;
-       int full_key;
 
        int phase2;
        u8 master_key[MSCHAPV2_MASTER_KEY_LEN];
@@ -114,10 +113,7 @@ static void * eap_mschapv2_init(struct eap_sm *sm)
        if (data == NULL)
                return NULL;
 
-       data->full_key = sm->mschapv2_full_key;
-
        if (sm->peer_challenge) {
-               data->full_key = 1;
                data->peer_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
                if (data->peer_challenge == NULL) {
                        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)
                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);
        if (key == 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",
                        key, key_len);
index f270498..11c93de 100644 (file)
@@ -238,21 +238,6 @@ static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data,
                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)
                key_len = isk_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);
                        if (data->phase2_method) {
                                sm->init_phase2 = 1;
-                               sm->mschapv2_full_key = 1;
                                data->phase2_priv =
                                        data->phase2_method->init(sm);
                                sm->init_phase2 = 0;
-                               sm->mschapv2_full_key = 0;
                        }
                }
                if (data->phase2_priv == NULL || data->phase2_method == NULL) {
index 737c3c1..e1a0fbd 100644 (file)
@@ -558,10 +558,8 @@ static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm,
                        EAP_VENDOR_IETF, method);
                if (data->phase2_method) {
                        sm->init_phase2 = 1;
-                       sm->mschapv2_full_key = 1;
                        data->phase2_priv = data->phase2_method->init(sm);
                        sm->init_phase2 = 0;
-                       sm->mschapv2_full_key = 0;
                }
        }
        if (data->phase2_priv == NULL || data->phase2_method == NULL) {
index da011d9..b474c99 100644 (file)
@@ -354,7 +354,18 @@ static int eap_fast_get_phase2_key(struct eap_sm *sm,
 
        if (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);
 
        return 0;
index f83421f..20e7ade 100644 (file)
@@ -524,9 +524,10 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
        key = os_malloc(*len);
        if (key == 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,
-                               MSCHAPV2_KEY_LEN, 1, 0);
+                               MSCHAPV2_KEY_LEN, 1, 1);
        wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
 
        return key;
index 5007d87..4b2d5a5 100644 (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);
                        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) {
index 4d96785..ecb3591 100644 (file)
@@ -560,6 +560,16 @@ static void ieee802_1x_get_keys(struct eapol_test_data *e,
                                keys->recv_len;
                        os_memcpy(e->authenticator_pmk, keys->recv,
                                  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);