18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP peer method: LEAP 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license. 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details. 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/ms_funcs.h" 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h" 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/random.h" 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_i.h" 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define LEAP_VERSION 1 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define LEAP_CHALLENGE_LEN 8 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define LEAP_RESPONSE_LEN 24 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define LEAP_KEY_LEN 16 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eap_leap_data { 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt enum { 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt LEAP_WAIT_CHALLENGE, 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt LEAP_WAIT_SUCCESS, 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt LEAP_WAIT_RESPONSE, 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt LEAP_DONE 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } state; 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 peer_challenge[LEAP_CHALLENGE_LEN]; 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 peer_response[LEAP_RESPONSE_LEN]; 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 ap_challenge[LEAP_CHALLENGE_LEN]; 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 ap_response[LEAP_RESPONSE_LEN]; 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}; 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * eap_leap_init(struct eap_sm *sm) 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_leap_data *data; 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data = os_zalloc(sizeof(*data)); 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data == NULL) 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = LEAP_WAIT_CHALLENGE; 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->leap_done = FALSE; 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data; 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eap_leap_deinit(struct eap_sm *sm, void *priv) 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(priv); 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv, 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_method_ret *ret, 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct wpabuf *reqData) 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_leap_data *data = priv; 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *resp; 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *challenge, *identity, *password; 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 challenge_len, *rpos; 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t identity_len, password_len, len; 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pwhash; 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request"); 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt identity = eap_get_config_identity(sm, &identity_len); 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt password = eap_get_config_password2(sm, &password_len, &pwhash); 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (identity == NULL || password == NULL) 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len); 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == NULL || len < 3) { 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame"); 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*pos != LEAP_VERSION) { 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%d", *pos); 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos++; 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos++; /* skip unused byte */ 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt challenge_len = *pos++; 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > len - 3) { 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge " 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(challenge_len=%d reqDataLen=%lu)", 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt challenge_len, (unsigned long) wpabuf_len(reqData)); 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt challenge = pos; 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN); 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP", 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt challenge, LEAP_CHALLENGE_LEN); 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response"); 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3 + LEAP_RESPONSE_LEN + identity_len, 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_CODE_RESPONSE, eap_get_id(reqData)); 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (resp == NULL) 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(resp, LEAP_VERSION); 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(resp, 0); /* unused */ 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(resp, LEAP_RESPONSE_LEN); 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN); 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pwhash) 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt challenge_response(challenge, password, rpos); 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nt_challenge_response(challenge, password, password_len, rpos); 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN); 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response", 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rpos, LEAP_RESPONSE_LEN); 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(resp, identity, identity_len); 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = LEAP_WAIT_SUCCESS; 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return resp; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv, 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_method_ret *ret, 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct wpabuf *reqData) 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_leap_data *data = priv; 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *resp; 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *pos; 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *identity; 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t identity_len; 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success"); 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt identity = eap_get_config_identity(sm, &identity_len); 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (identity == NULL) 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state != LEAP_WAIT_SUCCESS) { 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in " 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "unexpected state (%d) - ignored", data->state); 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3 + LEAP_CHALLENGE_LEN + identity_len, 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_CODE_REQUEST, eap_get_id(reqData)); 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (resp == NULL) 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(resp, LEAP_VERSION); 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(resp, 0); /* unused */ 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_u8(resp, LEAP_CHALLENGE_LEN); 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = wpabuf_put(resp, LEAP_CHALLENGE_LEN); 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (random_get_bytes(pos, LEAP_CHALLENGE_LEN)) { 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data " 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "for challenge"); 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(resp); 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN); 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos, 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt LEAP_CHALLENGE_LEN); 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_data(resp, identity, identity_len); 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = LEAP_WAIT_RESPONSE; 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return resp; 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv, 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_method_ret *ret, 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct wpabuf *reqData) 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_leap_data *data = priv; 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *pos, *password; 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 response_len, pw_hash[16], pw_hash_hash[16], 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt expected[LEAP_RESPONSE_LEN]; 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t password_len, len; 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pwhash; 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response"); 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt password = eap_get_config_password2(sm, &password_len, &pwhash); 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (password == NULL) 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len); 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos == NULL || len < 3) { 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame"); 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*pos != LEAP_VERSION) { 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version " 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%d", *pos); 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos++; 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos++; /* skip unused byte */ 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt response_len = *pos++; 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (response_len != LEAP_RESPONSE_LEN || response_len > len - 3) { 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response " 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "(response_len=%d reqDataLen=%lu)", 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt response_len, (unsigned long) wpabuf_len(reqData)); 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP", 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos, LEAP_RESPONSE_LEN); 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN); 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pwhash) { 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hash_nt_password_hash(password, pw_hash_hash)) { 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (nt_password_hash(password, password_len, pw_hash) || 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash_nt_password_hash(pw_hash, pw_hash_hash)) { 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt challenge_response(data->ap_challenge, pw_hash_hash, expected); 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->methodState = METHOD_DONE; 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->allowNotifications = FALSE; 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) { 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid " 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "response - authentication failed"); 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP", 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt expected, LEAP_RESPONSE_LEN); 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->decision = DECISION_FAIL; 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->decision = DECISION_UNCOND_SUCC; 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* LEAP is somewhat odd method since it sends EAP-Success in the middle 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * of the authentication. Use special variable to transit EAP state 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * machine to SUCCESS state. */ 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->leap_done = TRUE; 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->state = LEAP_DONE; 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* No more authentication messages expected; AP will send EAPOL-Key 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * frames if encryption is enabled. */ 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv, 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_method_ret *ret, 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct wpabuf *reqData) 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct eap_hdr *eap; 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t password_len; 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *password; 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt password = eap_get_config_password(sm, &password_len); 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (password == NULL) { 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured"); 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_sm_request_password(sm); 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * LEAP needs to be able to handle EAP-Success frame which does not 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * include Type field. Consequently, eap_hdr_validate() cannot be used 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * here. This validation will be done separately for EAP-Request and 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAP-Response frames. 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap = wpabuf_head(reqData); 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (wpabuf_len(reqData) < sizeof(*eap) || 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt be_to_host16(eap->length) > wpabuf_len(reqData)) { 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame"); 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = FALSE; 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->allowNotifications = TRUE; 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->methodState = METHOD_MAY_CONT; 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->decision = DECISION_FAIL; 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->leap_done = FALSE; 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (eap->code) { 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case EAP_CODE_REQUEST: 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_leap_process_request(sm, priv, ret, reqData); 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case EAP_CODE_SUCCESS: 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_leap_process_success(sm, priv, ret, reqData); 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case EAP_CODE_RESPONSE: 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eap_leap_process_response(sm, priv, ret, reqData); 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt default: 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - " 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "ignored", eap->code); 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret->ignore = TRUE; 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv) 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_leap_data *data = priv; 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return data->state == LEAP_DONE; 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_leap_data *data = priv; 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u8 *key, pw_hash_hash[16], pw_hash[16]; 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const u8 *addr[5], *password; 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t elen[5], password_len; 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int pwhash; 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (data->state != LEAP_DONE) 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt password = eap_get_config_password2(sm, &password_len, &pwhash); 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (password == NULL) 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt key = os_malloc(LEAP_KEY_LEN); 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (key == NULL) 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pwhash) { 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (hash_nt_password_hash(password, pw_hash_hash)) { 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (nt_password_hash(password, password_len, pw_hash) || 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash_nt_password_hash(pw_hash, pw_hash_hash)) { 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(key); 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash", 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pw_hash_hash, 16); 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge", 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->peer_challenge, LEAP_CHALLENGE_LEN); 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response", 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->peer_response, LEAP_RESPONSE_LEN); 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge", 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ap_challenge, LEAP_CHALLENGE_LEN); 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response", 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data->ap_response, LEAP_RESPONSE_LEN); 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[0] = pw_hash_hash; 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[0] = 16; 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[1] = data->ap_challenge; 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[1] = LEAP_CHALLENGE_LEN; 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[2] = data->ap_response; 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[2] = LEAP_RESPONSE_LEN; 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[3] = data->peer_challenge; 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[3] = LEAP_CHALLENGE_LEN; 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr[4] = data->peer_response; 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt elen[4] = LEAP_RESPONSE_LEN; 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt md5_vector(5, addr, elen, key); 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN); 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *len = LEAP_KEY_LEN; 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return key; 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eap_peer_leap_register(void) 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct eap_method *eap; 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret; 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP"); 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eap == NULL) 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->init = eap_leap_init; 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->deinit = eap_leap_deinit; 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->process = eap_leap_process; 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->isKeyAvailable = eap_leap_isKeyAvailable; 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap->getKey = eap_leap_getKey; 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = eap_peer_method_register(eap); 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret) 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eap_peer_method_free(eap); 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 411