16d49e1aeSJan Lentfer /* 26d49e1aeSJan Lentfer * EAP peer method: LEAP 36d49e1aeSJan Lentfer * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 46d49e1aeSJan Lentfer * 53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license. 63ff40c12SJohn Marino * See README for more details. 76d49e1aeSJan Lentfer */ 86d49e1aeSJan Lentfer 96d49e1aeSJan Lentfer #include "includes.h" 106d49e1aeSJan Lentfer 116d49e1aeSJan Lentfer #include "common.h" 123ff40c12SJohn Marino #include "crypto/ms_funcs.h" 133ff40c12SJohn Marino #include "crypto/crypto.h" 143ff40c12SJohn Marino #include "crypto/random.h" 156d49e1aeSJan Lentfer #include "eap_i.h" 166d49e1aeSJan Lentfer 176d49e1aeSJan Lentfer #define LEAP_VERSION 1 186d49e1aeSJan Lentfer #define LEAP_CHALLENGE_LEN 8 196d49e1aeSJan Lentfer #define LEAP_RESPONSE_LEN 24 206d49e1aeSJan Lentfer #define LEAP_KEY_LEN 16 216d49e1aeSJan Lentfer 226d49e1aeSJan Lentfer 236d49e1aeSJan Lentfer struct eap_leap_data { 246d49e1aeSJan Lentfer enum { 256d49e1aeSJan Lentfer LEAP_WAIT_CHALLENGE, 266d49e1aeSJan Lentfer LEAP_WAIT_SUCCESS, 276d49e1aeSJan Lentfer LEAP_WAIT_RESPONSE, 286d49e1aeSJan Lentfer LEAP_DONE 296d49e1aeSJan Lentfer } state; 306d49e1aeSJan Lentfer 316d49e1aeSJan Lentfer u8 peer_challenge[LEAP_CHALLENGE_LEN]; 326d49e1aeSJan Lentfer u8 peer_response[LEAP_RESPONSE_LEN]; 336d49e1aeSJan Lentfer 346d49e1aeSJan Lentfer u8 ap_challenge[LEAP_CHALLENGE_LEN]; 356d49e1aeSJan Lentfer u8 ap_response[LEAP_RESPONSE_LEN]; 366d49e1aeSJan Lentfer }; 376d49e1aeSJan Lentfer 386d49e1aeSJan Lentfer 396d49e1aeSJan Lentfer static void * eap_leap_init(struct eap_sm *sm) 406d49e1aeSJan Lentfer { 416d49e1aeSJan Lentfer struct eap_leap_data *data; 426d49e1aeSJan Lentfer 436d49e1aeSJan Lentfer data = os_zalloc(sizeof(*data)); 446d49e1aeSJan Lentfer if (data == NULL) 456d49e1aeSJan Lentfer return NULL; 466d49e1aeSJan Lentfer data->state = LEAP_WAIT_CHALLENGE; 476d49e1aeSJan Lentfer 486d49e1aeSJan Lentfer sm->leap_done = FALSE; 496d49e1aeSJan Lentfer return data; 506d49e1aeSJan Lentfer } 516d49e1aeSJan Lentfer 526d49e1aeSJan Lentfer 536d49e1aeSJan Lentfer static void eap_leap_deinit(struct eap_sm *sm, void *priv) 546d49e1aeSJan Lentfer { 556d49e1aeSJan Lentfer os_free(priv); 566d49e1aeSJan Lentfer } 576d49e1aeSJan Lentfer 586d49e1aeSJan Lentfer 596d49e1aeSJan Lentfer static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv, 606d49e1aeSJan Lentfer struct eap_method_ret *ret, 616d49e1aeSJan Lentfer const struct wpabuf *reqData) 626d49e1aeSJan Lentfer { 636d49e1aeSJan Lentfer struct eap_leap_data *data = priv; 646d49e1aeSJan Lentfer struct wpabuf *resp; 656d49e1aeSJan Lentfer const u8 *pos, *challenge, *identity, *password; 666d49e1aeSJan Lentfer u8 challenge_len, *rpos; 676d49e1aeSJan Lentfer size_t identity_len, password_len, len; 686d49e1aeSJan Lentfer int pwhash; 696d49e1aeSJan Lentfer 706d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request"); 716d49e1aeSJan Lentfer 726d49e1aeSJan Lentfer identity = eap_get_config_identity(sm, &identity_len); 736d49e1aeSJan Lentfer password = eap_get_config_password2(sm, &password_len, &pwhash); 746d49e1aeSJan Lentfer if (identity == NULL || password == NULL) 756d49e1aeSJan Lentfer return NULL; 766d49e1aeSJan Lentfer 776d49e1aeSJan Lentfer pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len); 786d49e1aeSJan Lentfer if (pos == NULL || len < 3) { 796d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame"); 806d49e1aeSJan Lentfer ret->ignore = TRUE; 816d49e1aeSJan Lentfer return NULL; 826d49e1aeSJan Lentfer } 836d49e1aeSJan Lentfer 846d49e1aeSJan Lentfer if (*pos != LEAP_VERSION) { 856d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " 866d49e1aeSJan Lentfer "%d", *pos); 876d49e1aeSJan Lentfer ret->ignore = TRUE; 886d49e1aeSJan Lentfer return NULL; 896d49e1aeSJan Lentfer } 906d49e1aeSJan Lentfer pos++; 916d49e1aeSJan Lentfer 926d49e1aeSJan Lentfer pos++; /* skip unused byte */ 936d49e1aeSJan Lentfer 946d49e1aeSJan Lentfer challenge_len = *pos++; 956d49e1aeSJan Lentfer if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > len - 3) { 966d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge " 976d49e1aeSJan Lentfer "(challenge_len=%d reqDataLen=%lu)", 986d49e1aeSJan Lentfer challenge_len, (unsigned long) wpabuf_len(reqData)); 996d49e1aeSJan Lentfer ret->ignore = TRUE; 1006d49e1aeSJan Lentfer return NULL; 1016d49e1aeSJan Lentfer } 1026d49e1aeSJan Lentfer challenge = pos; 1036d49e1aeSJan Lentfer os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN); 1046d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP", 1056d49e1aeSJan Lentfer challenge, LEAP_CHALLENGE_LEN); 1066d49e1aeSJan Lentfer 1076d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response"); 1086d49e1aeSJan Lentfer 1096d49e1aeSJan Lentfer resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, 1106d49e1aeSJan Lentfer 3 + LEAP_RESPONSE_LEN + identity_len, 1116d49e1aeSJan Lentfer EAP_CODE_RESPONSE, eap_get_id(reqData)); 1126d49e1aeSJan Lentfer if (resp == NULL) 1136d49e1aeSJan Lentfer return NULL; 1146d49e1aeSJan Lentfer wpabuf_put_u8(resp, LEAP_VERSION); 1156d49e1aeSJan Lentfer wpabuf_put_u8(resp, 0); /* unused */ 1166d49e1aeSJan Lentfer wpabuf_put_u8(resp, LEAP_RESPONSE_LEN); 1176d49e1aeSJan Lentfer rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN); 118*a1157835SDaniel Fojt if ((pwhash && challenge_response(challenge, password, rpos)) || 119*a1157835SDaniel Fojt (!pwhash && 120*a1157835SDaniel Fojt nt_challenge_response(challenge, password, password_len, rpos))) { 121*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "EAP-LEAP: Failed to derive response"); 122*a1157835SDaniel Fojt ret->ignore = TRUE; 123*a1157835SDaniel Fojt wpabuf_free(resp); 124*a1157835SDaniel Fojt return NULL; 125*a1157835SDaniel Fojt } 1266d49e1aeSJan Lentfer os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN); 1276d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response", 1286d49e1aeSJan Lentfer rpos, LEAP_RESPONSE_LEN); 1296d49e1aeSJan Lentfer wpabuf_put_data(resp, identity, identity_len); 1306d49e1aeSJan Lentfer 1316d49e1aeSJan Lentfer data->state = LEAP_WAIT_SUCCESS; 1326d49e1aeSJan Lentfer 1336d49e1aeSJan Lentfer return resp; 1346d49e1aeSJan Lentfer } 1356d49e1aeSJan Lentfer 1366d49e1aeSJan Lentfer 1376d49e1aeSJan Lentfer static struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv, 1386d49e1aeSJan Lentfer struct eap_method_ret *ret, 1396d49e1aeSJan Lentfer const struct wpabuf *reqData) 1406d49e1aeSJan Lentfer { 1416d49e1aeSJan Lentfer struct eap_leap_data *data = priv; 1426d49e1aeSJan Lentfer struct wpabuf *resp; 1436d49e1aeSJan Lentfer u8 *pos; 1446d49e1aeSJan Lentfer const u8 *identity; 1456d49e1aeSJan Lentfer size_t identity_len; 1466d49e1aeSJan Lentfer 1476d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success"); 1486d49e1aeSJan Lentfer 1496d49e1aeSJan Lentfer identity = eap_get_config_identity(sm, &identity_len); 1506d49e1aeSJan Lentfer if (identity == NULL) 1516d49e1aeSJan Lentfer return NULL; 1526d49e1aeSJan Lentfer 1536d49e1aeSJan Lentfer if (data->state != LEAP_WAIT_SUCCESS) { 1546d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in " 1556d49e1aeSJan Lentfer "unexpected state (%d) - ignored", data->state); 1566d49e1aeSJan Lentfer ret->ignore = TRUE; 1576d49e1aeSJan Lentfer return NULL; 1586d49e1aeSJan Lentfer } 1596d49e1aeSJan Lentfer 1606d49e1aeSJan Lentfer resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, 1616d49e1aeSJan Lentfer 3 + LEAP_CHALLENGE_LEN + identity_len, 1626d49e1aeSJan Lentfer EAP_CODE_REQUEST, eap_get_id(reqData)); 1636d49e1aeSJan Lentfer if (resp == NULL) 1646d49e1aeSJan Lentfer return NULL; 1656d49e1aeSJan Lentfer wpabuf_put_u8(resp, LEAP_VERSION); 1666d49e1aeSJan Lentfer wpabuf_put_u8(resp, 0); /* unused */ 1676d49e1aeSJan Lentfer wpabuf_put_u8(resp, LEAP_CHALLENGE_LEN); 1686d49e1aeSJan Lentfer pos = wpabuf_put(resp, LEAP_CHALLENGE_LEN); 1693ff40c12SJohn Marino if (random_get_bytes(pos, LEAP_CHALLENGE_LEN)) { 1706d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data " 1716d49e1aeSJan Lentfer "for challenge"); 1726d49e1aeSJan Lentfer wpabuf_free(resp); 1736d49e1aeSJan Lentfer ret->ignore = TRUE; 1746d49e1aeSJan Lentfer return NULL; 1756d49e1aeSJan Lentfer } 1766d49e1aeSJan Lentfer os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN); 1776d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos, 1786d49e1aeSJan Lentfer LEAP_CHALLENGE_LEN); 1796d49e1aeSJan Lentfer wpabuf_put_data(resp, identity, identity_len); 1806d49e1aeSJan Lentfer 1816d49e1aeSJan Lentfer data->state = LEAP_WAIT_RESPONSE; 1826d49e1aeSJan Lentfer 1836d49e1aeSJan Lentfer return resp; 1846d49e1aeSJan Lentfer } 1856d49e1aeSJan Lentfer 1866d49e1aeSJan Lentfer 1876d49e1aeSJan Lentfer static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv, 1886d49e1aeSJan Lentfer struct eap_method_ret *ret, 1896d49e1aeSJan Lentfer const struct wpabuf *reqData) 1906d49e1aeSJan Lentfer { 1916d49e1aeSJan Lentfer struct eap_leap_data *data = priv; 1926d49e1aeSJan Lentfer const u8 *pos, *password; 1936d49e1aeSJan Lentfer u8 response_len, pw_hash[16], pw_hash_hash[16], 1946d49e1aeSJan Lentfer expected[LEAP_RESPONSE_LEN]; 1956d49e1aeSJan Lentfer size_t password_len, len; 1966d49e1aeSJan Lentfer int pwhash; 1976d49e1aeSJan Lentfer 1986d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response"); 1996d49e1aeSJan Lentfer 2006d49e1aeSJan Lentfer password = eap_get_config_password2(sm, &password_len, &pwhash); 2016d49e1aeSJan Lentfer if (password == NULL) 2026d49e1aeSJan Lentfer return NULL; 2036d49e1aeSJan Lentfer 2046d49e1aeSJan Lentfer pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len); 2056d49e1aeSJan Lentfer if (pos == NULL || len < 3) { 2066d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame"); 2076d49e1aeSJan Lentfer ret->ignore = TRUE; 2086d49e1aeSJan Lentfer return NULL; 2096d49e1aeSJan Lentfer } 2106d49e1aeSJan Lentfer 2116d49e1aeSJan Lentfer if (*pos != LEAP_VERSION) { 2126d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " 2136d49e1aeSJan Lentfer "%d", *pos); 2146d49e1aeSJan Lentfer ret->ignore = TRUE; 2156d49e1aeSJan Lentfer return NULL; 2166d49e1aeSJan Lentfer } 2176d49e1aeSJan Lentfer pos++; 2186d49e1aeSJan Lentfer 2196d49e1aeSJan Lentfer pos++; /* skip unused byte */ 2206d49e1aeSJan Lentfer 2216d49e1aeSJan Lentfer response_len = *pos++; 2226d49e1aeSJan Lentfer if (response_len != LEAP_RESPONSE_LEN || response_len > len - 3) { 2236d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response " 2246d49e1aeSJan Lentfer "(response_len=%d reqDataLen=%lu)", 2256d49e1aeSJan Lentfer response_len, (unsigned long) wpabuf_len(reqData)); 2266d49e1aeSJan Lentfer ret->ignore = TRUE; 2276d49e1aeSJan Lentfer return NULL; 2286d49e1aeSJan Lentfer } 2296d49e1aeSJan Lentfer 2306d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP", 2316d49e1aeSJan Lentfer pos, LEAP_RESPONSE_LEN); 2326d49e1aeSJan Lentfer os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN); 2336d49e1aeSJan Lentfer 2346d49e1aeSJan Lentfer if (pwhash) { 2353ff40c12SJohn Marino if (hash_nt_password_hash(password, pw_hash_hash)) { 2363ff40c12SJohn Marino ret->ignore = TRUE; 2373ff40c12SJohn Marino return NULL; 2383ff40c12SJohn Marino } 2396d49e1aeSJan Lentfer } else { 2403ff40c12SJohn Marino if (nt_password_hash(password, password_len, pw_hash) || 2413ff40c12SJohn Marino hash_nt_password_hash(pw_hash, pw_hash_hash)) { 2423ff40c12SJohn Marino ret->ignore = TRUE; 2433ff40c12SJohn Marino return NULL; 2443ff40c12SJohn Marino } 2456d49e1aeSJan Lentfer } 246*a1157835SDaniel Fojt if (challenge_response(data->ap_challenge, pw_hash_hash, expected)) { 247*a1157835SDaniel Fojt ret->ignore = TRUE; 248*a1157835SDaniel Fojt return NULL; 249*a1157835SDaniel Fojt } 2506d49e1aeSJan Lentfer 2516d49e1aeSJan Lentfer ret->methodState = METHOD_DONE; 2526d49e1aeSJan Lentfer ret->allowNotifications = FALSE; 2536d49e1aeSJan Lentfer 254*a1157835SDaniel Fojt if (os_memcmp_const(pos, expected, LEAP_RESPONSE_LEN) != 0) { 2556d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid " 2566d49e1aeSJan Lentfer "response - authentication failed"); 2576d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP", 2586d49e1aeSJan Lentfer expected, LEAP_RESPONSE_LEN); 2596d49e1aeSJan Lentfer ret->decision = DECISION_FAIL; 2606d49e1aeSJan Lentfer return NULL; 2616d49e1aeSJan Lentfer } 2626d49e1aeSJan Lentfer 2636d49e1aeSJan Lentfer ret->decision = DECISION_UNCOND_SUCC; 2646d49e1aeSJan Lentfer 2656d49e1aeSJan Lentfer /* LEAP is somewhat odd method since it sends EAP-Success in the middle 2666d49e1aeSJan Lentfer * of the authentication. Use special variable to transit EAP state 2676d49e1aeSJan Lentfer * machine to SUCCESS state. */ 2686d49e1aeSJan Lentfer sm->leap_done = TRUE; 2696d49e1aeSJan Lentfer data->state = LEAP_DONE; 2706d49e1aeSJan Lentfer 2716d49e1aeSJan Lentfer /* No more authentication messages expected; AP will send EAPOL-Key 2726d49e1aeSJan Lentfer * frames if encryption is enabled. */ 2736d49e1aeSJan Lentfer return NULL; 2746d49e1aeSJan Lentfer } 2756d49e1aeSJan Lentfer 2766d49e1aeSJan Lentfer 2776d49e1aeSJan Lentfer static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv, 2786d49e1aeSJan Lentfer struct eap_method_ret *ret, 2796d49e1aeSJan Lentfer const struct wpabuf *reqData) 2806d49e1aeSJan Lentfer { 2816d49e1aeSJan Lentfer const struct eap_hdr *eap; 2826d49e1aeSJan Lentfer size_t password_len; 2836d49e1aeSJan Lentfer const u8 *password; 2846d49e1aeSJan Lentfer 2856d49e1aeSJan Lentfer password = eap_get_config_password(sm, &password_len); 2866d49e1aeSJan Lentfer if (password == NULL) { 2876d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured"); 2886d49e1aeSJan Lentfer eap_sm_request_password(sm); 2896d49e1aeSJan Lentfer ret->ignore = TRUE; 2906d49e1aeSJan Lentfer return NULL; 2916d49e1aeSJan Lentfer } 2926d49e1aeSJan Lentfer 2936d49e1aeSJan Lentfer /* 2946d49e1aeSJan Lentfer * LEAP needs to be able to handle EAP-Success frame which does not 2956d49e1aeSJan Lentfer * include Type field. Consequently, eap_hdr_validate() cannot be used 2966d49e1aeSJan Lentfer * here. This validation will be done separately for EAP-Request and 2976d49e1aeSJan Lentfer * EAP-Response frames. 2986d49e1aeSJan Lentfer */ 2996d49e1aeSJan Lentfer eap = wpabuf_head(reqData); 3006d49e1aeSJan Lentfer if (wpabuf_len(reqData) < sizeof(*eap) || 3016d49e1aeSJan Lentfer be_to_host16(eap->length) > wpabuf_len(reqData)) { 3026d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame"); 3036d49e1aeSJan Lentfer ret->ignore = TRUE; 3046d49e1aeSJan Lentfer return NULL; 3056d49e1aeSJan Lentfer } 3066d49e1aeSJan Lentfer 3076d49e1aeSJan Lentfer ret->ignore = FALSE; 3086d49e1aeSJan Lentfer ret->allowNotifications = TRUE; 3096d49e1aeSJan Lentfer ret->methodState = METHOD_MAY_CONT; 3106d49e1aeSJan Lentfer ret->decision = DECISION_FAIL; 3116d49e1aeSJan Lentfer 3126d49e1aeSJan Lentfer sm->leap_done = FALSE; 3136d49e1aeSJan Lentfer 3146d49e1aeSJan Lentfer switch (eap->code) { 3156d49e1aeSJan Lentfer case EAP_CODE_REQUEST: 3166d49e1aeSJan Lentfer return eap_leap_process_request(sm, priv, ret, reqData); 3176d49e1aeSJan Lentfer case EAP_CODE_SUCCESS: 3186d49e1aeSJan Lentfer return eap_leap_process_success(sm, priv, ret, reqData); 3196d49e1aeSJan Lentfer case EAP_CODE_RESPONSE: 3206d49e1aeSJan Lentfer return eap_leap_process_response(sm, priv, ret, reqData); 3216d49e1aeSJan Lentfer default: 3226d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - " 3236d49e1aeSJan Lentfer "ignored", eap->code); 3246d49e1aeSJan Lentfer ret->ignore = TRUE; 3256d49e1aeSJan Lentfer return NULL; 3266d49e1aeSJan Lentfer } 3276d49e1aeSJan Lentfer } 3286d49e1aeSJan Lentfer 3296d49e1aeSJan Lentfer 3306d49e1aeSJan Lentfer static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv) 3316d49e1aeSJan Lentfer { 3326d49e1aeSJan Lentfer struct eap_leap_data *data = priv; 3336d49e1aeSJan Lentfer return data->state == LEAP_DONE; 3346d49e1aeSJan Lentfer } 3356d49e1aeSJan Lentfer 3366d49e1aeSJan Lentfer 3376d49e1aeSJan Lentfer static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) 3386d49e1aeSJan Lentfer { 3396d49e1aeSJan Lentfer struct eap_leap_data *data = priv; 3406d49e1aeSJan Lentfer u8 *key, pw_hash_hash[16], pw_hash[16]; 3416d49e1aeSJan Lentfer const u8 *addr[5], *password; 3426d49e1aeSJan Lentfer size_t elen[5], password_len; 3436d49e1aeSJan Lentfer int pwhash; 3446d49e1aeSJan Lentfer 3456d49e1aeSJan Lentfer if (data->state != LEAP_DONE) 3466d49e1aeSJan Lentfer return NULL; 3476d49e1aeSJan Lentfer 3486d49e1aeSJan Lentfer password = eap_get_config_password2(sm, &password_len, &pwhash); 3496d49e1aeSJan Lentfer if (password == NULL) 3506d49e1aeSJan Lentfer return NULL; 3516d49e1aeSJan Lentfer 3526d49e1aeSJan Lentfer key = os_malloc(LEAP_KEY_LEN); 3536d49e1aeSJan Lentfer if (key == NULL) 3546d49e1aeSJan Lentfer return NULL; 3556d49e1aeSJan Lentfer 3563ff40c12SJohn Marino if (pwhash) { 3573ff40c12SJohn Marino if (hash_nt_password_hash(password, pw_hash_hash)) { 3583ff40c12SJohn Marino os_free(key); 3593ff40c12SJohn Marino return NULL; 3603ff40c12SJohn Marino } 3613ff40c12SJohn Marino } else { 3623ff40c12SJohn Marino if (nt_password_hash(password, password_len, pw_hash) || 3633ff40c12SJohn Marino hash_nt_password_hash(pw_hash, pw_hash_hash)) { 3643ff40c12SJohn Marino os_free(key); 3653ff40c12SJohn Marino return NULL; 3663ff40c12SJohn Marino } 3676d49e1aeSJan Lentfer } 3686d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash", 3696d49e1aeSJan Lentfer pw_hash_hash, 16); 3706d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge", 3716d49e1aeSJan Lentfer data->peer_challenge, LEAP_CHALLENGE_LEN); 3726d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response", 3736d49e1aeSJan Lentfer data->peer_response, LEAP_RESPONSE_LEN); 3746d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge", 3756d49e1aeSJan Lentfer data->ap_challenge, LEAP_CHALLENGE_LEN); 3766d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response", 3776d49e1aeSJan Lentfer data->ap_response, LEAP_RESPONSE_LEN); 3786d49e1aeSJan Lentfer 3796d49e1aeSJan Lentfer addr[0] = pw_hash_hash; 3806d49e1aeSJan Lentfer elen[0] = 16; 3816d49e1aeSJan Lentfer addr[1] = data->ap_challenge; 3826d49e1aeSJan Lentfer elen[1] = LEAP_CHALLENGE_LEN; 3836d49e1aeSJan Lentfer addr[2] = data->ap_response; 3846d49e1aeSJan Lentfer elen[2] = LEAP_RESPONSE_LEN; 3856d49e1aeSJan Lentfer addr[3] = data->peer_challenge; 3866d49e1aeSJan Lentfer elen[3] = LEAP_CHALLENGE_LEN; 3876d49e1aeSJan Lentfer addr[4] = data->peer_response; 3886d49e1aeSJan Lentfer elen[4] = LEAP_RESPONSE_LEN; 3896d49e1aeSJan Lentfer md5_vector(5, addr, elen, key); 3906d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN); 3916d49e1aeSJan Lentfer *len = LEAP_KEY_LEN; 3926d49e1aeSJan Lentfer 393*a1157835SDaniel Fojt forced_memzero(pw_hash, sizeof(pw_hash)); 394*a1157835SDaniel Fojt forced_memzero(pw_hash_hash, sizeof(pw_hash_hash)); 395*a1157835SDaniel Fojt 3966d49e1aeSJan Lentfer return key; 3976d49e1aeSJan Lentfer } 3986d49e1aeSJan Lentfer 3996d49e1aeSJan Lentfer 4006d49e1aeSJan Lentfer int eap_peer_leap_register(void) 4016d49e1aeSJan Lentfer { 4026d49e1aeSJan Lentfer struct eap_method *eap; 4036d49e1aeSJan Lentfer 4046d49e1aeSJan Lentfer eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 4056d49e1aeSJan Lentfer EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP"); 4066d49e1aeSJan Lentfer if (eap == NULL) 4076d49e1aeSJan Lentfer return -1; 4086d49e1aeSJan Lentfer 4096d49e1aeSJan Lentfer eap->init = eap_leap_init; 4106d49e1aeSJan Lentfer eap->deinit = eap_leap_deinit; 4116d49e1aeSJan Lentfer eap->process = eap_leap_process; 4126d49e1aeSJan Lentfer eap->isKeyAvailable = eap_leap_isKeyAvailable; 4136d49e1aeSJan Lentfer eap->getKey = eap_leap_getKey; 4146d49e1aeSJan Lentfer 415*a1157835SDaniel Fojt return eap_peer_method_register(eap); 4166d49e1aeSJan Lentfer } 417