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