xref: /freebsd/contrib/wpa/src/eap_peer/eap_leap.c (revision c1d255d3)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * EAP peer method: LEAP
339beb93cSSam Leffler  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
12e28a4053SRui Paulo #include "crypto/ms_funcs.h"
13e28a4053SRui Paulo #include "crypto/crypto.h"
14f05cddf9SRui Paulo #include "crypto/random.h"
1539beb93cSSam Leffler #include "eap_i.h"
1639beb93cSSam Leffler 
1739beb93cSSam Leffler #define LEAP_VERSION 1
1839beb93cSSam Leffler #define LEAP_CHALLENGE_LEN 8
1939beb93cSSam Leffler #define LEAP_RESPONSE_LEN 24
2039beb93cSSam Leffler #define LEAP_KEY_LEN 16
2139beb93cSSam Leffler 
2239beb93cSSam Leffler 
2339beb93cSSam Leffler struct eap_leap_data {
2439beb93cSSam Leffler 	enum {
2539beb93cSSam Leffler 		LEAP_WAIT_CHALLENGE,
2639beb93cSSam Leffler 		LEAP_WAIT_SUCCESS,
2739beb93cSSam Leffler 		LEAP_WAIT_RESPONSE,
2839beb93cSSam Leffler 		LEAP_DONE
2939beb93cSSam Leffler 	} state;
3039beb93cSSam Leffler 
3139beb93cSSam Leffler 	u8 peer_challenge[LEAP_CHALLENGE_LEN];
3239beb93cSSam Leffler 	u8 peer_response[LEAP_RESPONSE_LEN];
3339beb93cSSam Leffler 
3439beb93cSSam Leffler 	u8 ap_challenge[LEAP_CHALLENGE_LEN];
3539beb93cSSam Leffler 	u8 ap_response[LEAP_RESPONSE_LEN];
3639beb93cSSam Leffler };
3739beb93cSSam Leffler 
3839beb93cSSam Leffler 
eap_leap_init(struct eap_sm * sm)3939beb93cSSam Leffler static void * eap_leap_init(struct eap_sm *sm)
4039beb93cSSam Leffler {
4139beb93cSSam Leffler 	struct eap_leap_data *data;
4239beb93cSSam Leffler 
4339beb93cSSam Leffler 	data = os_zalloc(sizeof(*data));
4439beb93cSSam Leffler 	if (data == NULL)
4539beb93cSSam Leffler 		return NULL;
4639beb93cSSam Leffler 	data->state = LEAP_WAIT_CHALLENGE;
4739beb93cSSam Leffler 
48*c1d255d3SCy Schubert 	sm->leap_done = false;
4939beb93cSSam Leffler 	return data;
5039beb93cSSam Leffler }
5139beb93cSSam Leffler 
5239beb93cSSam Leffler 
eap_leap_deinit(struct eap_sm * sm,void * priv)5339beb93cSSam Leffler static void eap_leap_deinit(struct eap_sm *sm, void *priv)
5439beb93cSSam Leffler {
5539beb93cSSam Leffler 	os_free(priv);
5639beb93cSSam Leffler }
5739beb93cSSam Leffler 
5839beb93cSSam Leffler 
eap_leap_process_request(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)5939beb93cSSam Leffler static struct wpabuf * eap_leap_process_request(struct eap_sm *sm, void *priv,
6039beb93cSSam Leffler 						struct eap_method_ret *ret,
6139beb93cSSam Leffler 						const struct wpabuf *reqData)
6239beb93cSSam Leffler {
6339beb93cSSam Leffler 	struct eap_leap_data *data = priv;
6439beb93cSSam Leffler 	struct wpabuf *resp;
6539beb93cSSam Leffler 	const u8 *pos, *challenge, *identity, *password;
6639beb93cSSam Leffler 	u8 challenge_len, *rpos;
6739beb93cSSam Leffler 	size_t identity_len, password_len, len;
6839beb93cSSam Leffler 	int pwhash;
6939beb93cSSam Leffler 
7039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
7139beb93cSSam Leffler 
7239beb93cSSam Leffler 	identity = eap_get_config_identity(sm, &identity_len);
7339beb93cSSam Leffler 	password = eap_get_config_password2(sm, &password_len, &pwhash);
7439beb93cSSam Leffler 	if (identity == NULL || password == NULL)
7539beb93cSSam Leffler 		return NULL;
7639beb93cSSam Leffler 
7739beb93cSSam Leffler 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
7839beb93cSSam Leffler 	if (pos == NULL || len < 3) {
7939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
80*c1d255d3SCy Schubert 		ret->ignore = true;
8139beb93cSSam Leffler 		return NULL;
8239beb93cSSam Leffler 	}
8339beb93cSSam Leffler 
8439beb93cSSam Leffler 	if (*pos != LEAP_VERSION) {
8539beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
8639beb93cSSam Leffler 			   "%d", *pos);
87*c1d255d3SCy Schubert 		ret->ignore = true;
8839beb93cSSam Leffler 		return NULL;
8939beb93cSSam Leffler 	}
9039beb93cSSam Leffler 	pos++;
9139beb93cSSam Leffler 
9239beb93cSSam Leffler 	pos++; /* skip unused byte */
9339beb93cSSam Leffler 
9439beb93cSSam Leffler 	challenge_len = *pos++;
9539beb93cSSam Leffler 	if (challenge_len != LEAP_CHALLENGE_LEN || challenge_len > len - 3) {
9639beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge "
9739beb93cSSam Leffler 			   "(challenge_len=%d reqDataLen=%lu)",
9839beb93cSSam Leffler 			   challenge_len, (unsigned long) wpabuf_len(reqData));
99*c1d255d3SCy Schubert 		ret->ignore = true;
10039beb93cSSam Leffler 		return NULL;
10139beb93cSSam Leffler 	}
10239beb93cSSam Leffler 	challenge = pos;
10339beb93cSSam Leffler 	os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN);
10439beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP",
10539beb93cSSam Leffler 		    challenge, LEAP_CHALLENGE_LEN);
10639beb93cSSam Leffler 
10739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response");
10839beb93cSSam Leffler 
10939beb93cSSam Leffler 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
11039beb93cSSam Leffler 			     3 + LEAP_RESPONSE_LEN + identity_len,
11139beb93cSSam Leffler 			     EAP_CODE_RESPONSE, eap_get_id(reqData));
11239beb93cSSam Leffler 	if (resp == NULL)
11339beb93cSSam Leffler 		return NULL;
11439beb93cSSam Leffler 	wpabuf_put_u8(resp, LEAP_VERSION);
11539beb93cSSam Leffler 	wpabuf_put_u8(resp, 0); /* unused */
11639beb93cSSam Leffler 	wpabuf_put_u8(resp, LEAP_RESPONSE_LEN);
11739beb93cSSam Leffler 	rpos = wpabuf_put(resp, LEAP_RESPONSE_LEN);
11885732ac8SCy Schubert 	if ((pwhash && challenge_response(challenge, password, rpos)) ||
11985732ac8SCy Schubert 	    (!pwhash &&
12085732ac8SCy Schubert 	     nt_challenge_response(challenge, password, password_len, rpos))) {
12185732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "EAP-LEAP: Failed to derive response");
122*c1d255d3SCy Schubert 		ret->ignore = true;
12385732ac8SCy Schubert 		wpabuf_free(resp);
12485732ac8SCy Schubert 		return NULL;
12585732ac8SCy Schubert 	}
12639beb93cSSam Leffler 	os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
12739beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response",
12839beb93cSSam Leffler 		    rpos, LEAP_RESPONSE_LEN);
12939beb93cSSam Leffler 	wpabuf_put_data(resp, identity, identity_len);
13039beb93cSSam Leffler 
13139beb93cSSam Leffler 	data->state = LEAP_WAIT_SUCCESS;
13239beb93cSSam Leffler 
13339beb93cSSam Leffler 	return resp;
13439beb93cSSam Leffler }
13539beb93cSSam Leffler 
13639beb93cSSam Leffler 
eap_leap_process_success(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)13739beb93cSSam Leffler static struct wpabuf * eap_leap_process_success(struct eap_sm *sm, void *priv,
13839beb93cSSam Leffler 						struct eap_method_ret *ret,
13939beb93cSSam Leffler 						const struct wpabuf *reqData)
14039beb93cSSam Leffler {
14139beb93cSSam Leffler 	struct eap_leap_data *data = priv;
14239beb93cSSam Leffler 	struct wpabuf *resp;
14339beb93cSSam Leffler 	u8 *pos;
14439beb93cSSam Leffler 	const u8 *identity;
14539beb93cSSam Leffler 	size_t identity_len;
14639beb93cSSam Leffler 
14739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");
14839beb93cSSam Leffler 
14939beb93cSSam Leffler 	identity = eap_get_config_identity(sm, &identity_len);
15039beb93cSSam Leffler 	if (identity == NULL)
15139beb93cSSam Leffler 		return NULL;
15239beb93cSSam Leffler 
15339beb93cSSam Leffler 	if (data->state != LEAP_WAIT_SUCCESS) {
15439beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in "
15539beb93cSSam Leffler 			   "unexpected state (%d) - ignored", data->state);
156*c1d255d3SCy Schubert 		ret->ignore = true;
15739beb93cSSam Leffler 		return NULL;
15839beb93cSSam Leffler 	}
15939beb93cSSam Leffler 
16039beb93cSSam Leffler 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP,
16139beb93cSSam Leffler 			     3 + LEAP_CHALLENGE_LEN + identity_len,
16239beb93cSSam Leffler 			     EAP_CODE_REQUEST, eap_get_id(reqData));
16339beb93cSSam Leffler 	if (resp == NULL)
16439beb93cSSam Leffler 		return NULL;
16539beb93cSSam Leffler 	wpabuf_put_u8(resp, LEAP_VERSION);
16639beb93cSSam Leffler 	wpabuf_put_u8(resp, 0); /* unused */
16739beb93cSSam Leffler 	wpabuf_put_u8(resp, LEAP_CHALLENGE_LEN);
16839beb93cSSam Leffler 	pos = wpabuf_put(resp, LEAP_CHALLENGE_LEN);
169f05cddf9SRui Paulo 	if (random_get_bytes(pos, LEAP_CHALLENGE_LEN)) {
17039beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data "
17139beb93cSSam Leffler 			   "for challenge");
17239beb93cSSam Leffler 		wpabuf_free(resp);
173*c1d255d3SCy Schubert 		ret->ignore = true;
17439beb93cSSam Leffler 		return NULL;
17539beb93cSSam Leffler 	}
17639beb93cSSam Leffler 	os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
17739beb93cSSam Leffler 	wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos,
17839beb93cSSam Leffler 		    LEAP_CHALLENGE_LEN);
17939beb93cSSam Leffler 	wpabuf_put_data(resp, identity, identity_len);
18039beb93cSSam Leffler 
18139beb93cSSam Leffler 	data->state = LEAP_WAIT_RESPONSE;
18239beb93cSSam Leffler 
18339beb93cSSam Leffler 	return resp;
18439beb93cSSam Leffler }
18539beb93cSSam Leffler 
18639beb93cSSam Leffler 
eap_leap_process_response(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)18739beb93cSSam Leffler static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv,
18839beb93cSSam Leffler 						 struct eap_method_ret *ret,
18939beb93cSSam Leffler 						 const struct wpabuf *reqData)
19039beb93cSSam Leffler {
19139beb93cSSam Leffler 	struct eap_leap_data *data = priv;
19239beb93cSSam Leffler 	const u8 *pos, *password;
19339beb93cSSam Leffler 	u8 response_len, pw_hash[16], pw_hash_hash[16],
19439beb93cSSam Leffler 		expected[LEAP_RESPONSE_LEN];
19539beb93cSSam Leffler 	size_t password_len, len;
19639beb93cSSam Leffler 	int pwhash;
19739beb93cSSam Leffler 
19839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
19939beb93cSSam Leffler 
20039beb93cSSam Leffler 	password = eap_get_config_password2(sm, &password_len, &pwhash);
20139beb93cSSam Leffler 	if (password == NULL)
20239beb93cSSam Leffler 		return NULL;
20339beb93cSSam Leffler 
20439beb93cSSam Leffler 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_LEAP, reqData, &len);
20539beb93cSSam Leffler 	if (pos == NULL || len < 3) {
20639beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame");
207*c1d255d3SCy Schubert 		ret->ignore = true;
20839beb93cSSam Leffler 		return NULL;
20939beb93cSSam Leffler 	}
21039beb93cSSam Leffler 
21139beb93cSSam Leffler 	if (*pos != LEAP_VERSION) {
21239beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
21339beb93cSSam Leffler 			   "%d", *pos);
214*c1d255d3SCy Schubert 		ret->ignore = true;
21539beb93cSSam Leffler 		return NULL;
21639beb93cSSam Leffler 	}
21739beb93cSSam Leffler 	pos++;
21839beb93cSSam Leffler 
21939beb93cSSam Leffler 	pos++; /* skip unused byte */
22039beb93cSSam Leffler 
22139beb93cSSam Leffler 	response_len = *pos++;
22239beb93cSSam Leffler 	if (response_len != LEAP_RESPONSE_LEN || response_len > len - 3) {
22339beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response "
22439beb93cSSam Leffler 			   "(response_len=%d reqDataLen=%lu)",
22539beb93cSSam Leffler 			   response_len, (unsigned long) wpabuf_len(reqData));
226*c1d255d3SCy Schubert 		ret->ignore = true;
22739beb93cSSam Leffler 		return NULL;
22839beb93cSSam Leffler 	}
22939beb93cSSam Leffler 
23039beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP",
23139beb93cSSam Leffler 		    pos, LEAP_RESPONSE_LEN);
23239beb93cSSam Leffler 	os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN);
23339beb93cSSam Leffler 
23439beb93cSSam Leffler 	if (pwhash) {
235e28a4053SRui Paulo 		if (hash_nt_password_hash(password, pw_hash_hash)) {
236*c1d255d3SCy Schubert 			ret->ignore = true;
237e28a4053SRui Paulo 			return NULL;
238e28a4053SRui Paulo 		}
23939beb93cSSam Leffler 	} else {
240e28a4053SRui Paulo 		if (nt_password_hash(password, password_len, pw_hash) ||
241e28a4053SRui Paulo 		    hash_nt_password_hash(pw_hash, pw_hash_hash)) {
242*c1d255d3SCy Schubert 			ret->ignore = true;
243e28a4053SRui Paulo 			return NULL;
244e28a4053SRui Paulo 		}
24539beb93cSSam Leffler 	}
24685732ac8SCy Schubert 	if (challenge_response(data->ap_challenge, pw_hash_hash, expected)) {
247*c1d255d3SCy Schubert 		ret->ignore = true;
24885732ac8SCy Schubert 		return NULL;
24985732ac8SCy Schubert 	}
25039beb93cSSam Leffler 
25139beb93cSSam Leffler 	ret->methodState = METHOD_DONE;
252*c1d255d3SCy Schubert 	ret->allowNotifications = false;
25339beb93cSSam Leffler 
2545b9c547cSRui Paulo 	if (os_memcmp_const(pos, expected, LEAP_RESPONSE_LEN) != 0) {
25539beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid "
25639beb93cSSam Leffler 			   "response - authentication failed");
25739beb93cSSam Leffler 		wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP",
25839beb93cSSam Leffler 			    expected, LEAP_RESPONSE_LEN);
25939beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
26039beb93cSSam Leffler 		return NULL;
26139beb93cSSam Leffler 	}
26239beb93cSSam Leffler 
26339beb93cSSam Leffler 	ret->decision = DECISION_UNCOND_SUCC;
26439beb93cSSam Leffler 
26539beb93cSSam Leffler 	/* LEAP is somewhat odd method since it sends EAP-Success in the middle
26639beb93cSSam Leffler 	 * of the authentication. Use special variable to transit EAP state
26739beb93cSSam Leffler 	 * machine to SUCCESS state. */
268*c1d255d3SCy Schubert 	sm->leap_done = true;
26939beb93cSSam Leffler 	data->state = LEAP_DONE;
27039beb93cSSam Leffler 
27139beb93cSSam Leffler 	/* No more authentication messages expected; AP will send EAPOL-Key
27239beb93cSSam Leffler 	 * frames if encryption is enabled. */
27339beb93cSSam Leffler 	return NULL;
27439beb93cSSam Leffler }
27539beb93cSSam Leffler 
27639beb93cSSam Leffler 
eap_leap_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)27739beb93cSSam Leffler static struct wpabuf * eap_leap_process(struct eap_sm *sm, void *priv,
27839beb93cSSam Leffler 					struct eap_method_ret *ret,
27939beb93cSSam Leffler 					const struct wpabuf *reqData)
28039beb93cSSam Leffler {
28139beb93cSSam Leffler 	const struct eap_hdr *eap;
28239beb93cSSam Leffler 	size_t password_len;
28339beb93cSSam Leffler 	const u8 *password;
28439beb93cSSam Leffler 
28539beb93cSSam Leffler 	password = eap_get_config_password(sm, &password_len);
28639beb93cSSam Leffler 	if (password == NULL) {
28739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured");
28839beb93cSSam Leffler 		eap_sm_request_password(sm);
289*c1d255d3SCy Schubert 		ret->ignore = true;
29039beb93cSSam Leffler 		return NULL;
29139beb93cSSam Leffler 	}
29239beb93cSSam Leffler 
29339beb93cSSam Leffler 	/*
29439beb93cSSam Leffler 	 * LEAP needs to be able to handle EAP-Success frame which does not
29539beb93cSSam Leffler 	 * include Type field. Consequently, eap_hdr_validate() cannot be used
29639beb93cSSam Leffler 	 * here. This validation will be done separately for EAP-Request and
29739beb93cSSam Leffler 	 * EAP-Response frames.
29839beb93cSSam Leffler 	 */
29939beb93cSSam Leffler 	eap = wpabuf_head(reqData);
30039beb93cSSam Leffler 	if (wpabuf_len(reqData) < sizeof(*eap) ||
30139beb93cSSam Leffler 	    be_to_host16(eap->length) > wpabuf_len(reqData)) {
30239beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame");
303*c1d255d3SCy Schubert 		ret->ignore = true;
30439beb93cSSam Leffler 		return NULL;
30539beb93cSSam Leffler 	}
30639beb93cSSam Leffler 
307*c1d255d3SCy Schubert 	ret->ignore = false;
308*c1d255d3SCy Schubert 	ret->allowNotifications = true;
30939beb93cSSam Leffler 	ret->methodState = METHOD_MAY_CONT;
31039beb93cSSam Leffler 	ret->decision = DECISION_FAIL;
31139beb93cSSam Leffler 
312*c1d255d3SCy Schubert 	sm->leap_done = false;
31339beb93cSSam Leffler 
31439beb93cSSam Leffler 	switch (eap->code) {
31539beb93cSSam Leffler 	case EAP_CODE_REQUEST:
31639beb93cSSam Leffler 		return eap_leap_process_request(sm, priv, ret, reqData);
31739beb93cSSam Leffler 	case EAP_CODE_SUCCESS:
31839beb93cSSam Leffler 		return eap_leap_process_success(sm, priv, ret, reqData);
31939beb93cSSam Leffler 	case EAP_CODE_RESPONSE:
32039beb93cSSam Leffler 		return eap_leap_process_response(sm, priv, ret, reqData);
32139beb93cSSam Leffler 	default:
32239beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
32339beb93cSSam Leffler 			   "ignored", eap->code);
324*c1d255d3SCy Schubert 		ret->ignore = true;
32539beb93cSSam Leffler 		return NULL;
32639beb93cSSam Leffler 	}
32739beb93cSSam Leffler }
32839beb93cSSam Leffler 
32939beb93cSSam Leffler 
eap_leap_isKeyAvailable(struct eap_sm * sm,void * priv)330*c1d255d3SCy Schubert static bool eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
33139beb93cSSam Leffler {
33239beb93cSSam Leffler 	struct eap_leap_data *data = priv;
33339beb93cSSam Leffler 	return data->state == LEAP_DONE;
33439beb93cSSam Leffler }
33539beb93cSSam Leffler 
33639beb93cSSam Leffler 
eap_leap_getKey(struct eap_sm * sm,void * priv,size_t * len)33739beb93cSSam Leffler static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
33839beb93cSSam Leffler {
33939beb93cSSam Leffler 	struct eap_leap_data *data = priv;
34039beb93cSSam Leffler 	u8 *key, pw_hash_hash[16], pw_hash[16];
34139beb93cSSam Leffler 	const u8 *addr[5], *password;
34239beb93cSSam Leffler 	size_t elen[5], password_len;
34339beb93cSSam Leffler 	int pwhash;
34439beb93cSSam Leffler 
34539beb93cSSam Leffler 	if (data->state != LEAP_DONE)
34639beb93cSSam Leffler 		return NULL;
34739beb93cSSam Leffler 
34839beb93cSSam Leffler 	password = eap_get_config_password2(sm, &password_len, &pwhash);
34939beb93cSSam Leffler 	if (password == NULL)
35039beb93cSSam Leffler 		return NULL;
35139beb93cSSam Leffler 
35239beb93cSSam Leffler 	key = os_malloc(LEAP_KEY_LEN);
35339beb93cSSam Leffler 	if (key == NULL)
35439beb93cSSam Leffler 		return NULL;
35539beb93cSSam Leffler 
356e28a4053SRui Paulo 	if (pwhash) {
357e28a4053SRui Paulo 		if (hash_nt_password_hash(password, pw_hash_hash)) {
358e28a4053SRui Paulo 			os_free(key);
359e28a4053SRui Paulo 			return NULL;
360e28a4053SRui Paulo 		}
361e28a4053SRui Paulo 	} else {
362e28a4053SRui Paulo 		if (nt_password_hash(password, password_len, pw_hash) ||
363e28a4053SRui Paulo 		    hash_nt_password_hash(pw_hash, pw_hash_hash)) {
364e28a4053SRui Paulo 			os_free(key);
365e28a4053SRui Paulo 			return NULL;
366e28a4053SRui Paulo 		}
36739beb93cSSam Leffler 	}
36839beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash",
36939beb93cSSam Leffler 			pw_hash_hash, 16);
37039beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge",
37139beb93cSSam Leffler 		    data->peer_challenge, LEAP_CHALLENGE_LEN);
37239beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response",
37339beb93cSSam Leffler 		    data->peer_response, LEAP_RESPONSE_LEN);
37439beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge",
37539beb93cSSam Leffler 		    data->ap_challenge, LEAP_CHALLENGE_LEN);
37639beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response",
37739beb93cSSam Leffler 		    data->ap_response, LEAP_RESPONSE_LEN);
37839beb93cSSam Leffler 
37939beb93cSSam Leffler 	addr[0] = pw_hash_hash;
38039beb93cSSam Leffler 	elen[0] = 16;
38139beb93cSSam Leffler 	addr[1] = data->ap_challenge;
38239beb93cSSam Leffler 	elen[1] = LEAP_CHALLENGE_LEN;
38339beb93cSSam Leffler 	addr[2] = data->ap_response;
38439beb93cSSam Leffler 	elen[2] = LEAP_RESPONSE_LEN;
38539beb93cSSam Leffler 	addr[3] = data->peer_challenge;
38639beb93cSSam Leffler 	elen[3] = LEAP_CHALLENGE_LEN;
38739beb93cSSam Leffler 	addr[4] = data->peer_response;
38839beb93cSSam Leffler 	elen[4] = LEAP_RESPONSE_LEN;
38939beb93cSSam Leffler 	md5_vector(5, addr, elen, key);
39039beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN);
39139beb93cSSam Leffler 	*len = LEAP_KEY_LEN;
39239beb93cSSam Leffler 
393206b73d0SCy Schubert 	forced_memzero(pw_hash, sizeof(pw_hash));
394206b73d0SCy Schubert 	forced_memzero(pw_hash_hash, sizeof(pw_hash_hash));
3955b9c547cSRui Paulo 
39639beb93cSSam Leffler 	return key;
39739beb93cSSam Leffler }
39839beb93cSSam Leffler 
39939beb93cSSam Leffler 
eap_peer_leap_register(void)40039beb93cSSam Leffler int eap_peer_leap_register(void)
40139beb93cSSam Leffler {
40239beb93cSSam Leffler 	struct eap_method *eap;
40339beb93cSSam Leffler 
40439beb93cSSam Leffler 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
40539beb93cSSam Leffler 				    EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP");
40639beb93cSSam Leffler 	if (eap == NULL)
40739beb93cSSam Leffler 		return -1;
40839beb93cSSam Leffler 
40939beb93cSSam Leffler 	eap->init = eap_leap_init;
41039beb93cSSam Leffler 	eap->deinit = eap_leap_deinit;
41139beb93cSSam Leffler 	eap->process = eap_leap_process;
41239beb93cSSam Leffler 	eap->isKeyAvailable = eap_leap_isKeyAvailable;
41339beb93cSSam Leffler 	eap->getKey = eap_leap_getKey;
41439beb93cSSam Leffler 
415780fb4a2SCy Schubert 	return eap_peer_method_register(eap);
41639beb93cSSam Leffler }
417