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
eap_leap_init(struct eap_sm * sm)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
eap_leap_deinit(struct eap_sm * sm,void * priv)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
eap_leap_process_request(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)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
eap_leap_process_success(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)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
eap_leap_process_response(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)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
eap_leap_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)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
eap_leap_isKeyAvailable(struct eap_sm * sm,void * priv)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
eap_leap_getKey(struct eap_sm * sm,void * priv,size_t * len)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
eap_peer_leap_register(void)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