2 * WPA Supplicant / EAP-LEAP
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
21 #include "wpa_supplicant.h"
22 #include "config_ssid.h"
26 #define LEAP_VERSION 1
27 #define LEAP_CHALLENGE_LEN 8
28 #define LEAP_RESPONSE_LEN 24
29 #define LEAP_KEY_LEN 16
32 struct eap_leap_data {
40 u8 peer_challenge[LEAP_CHALLENGE_LEN];
41 u8 peer_response[LEAP_RESPONSE_LEN];
43 u8 ap_challenge[LEAP_CHALLENGE_LEN];
44 u8 ap_response[LEAP_RESPONSE_LEN];
48 static void * eap_leap_init(struct eap_sm *sm)
50 struct eap_leap_data *data;
52 data = malloc(sizeof(*data));
55 memset(data, 0, sizeof(*data));
56 data->state = LEAP_WAIT_CHALLENGE;
58 sm->leap_done = FALSE;
63 static void eap_leap_deinit(struct eap_sm *sm, void *priv)
69 static u8 * eap_leap_process_request(struct eap_sm *sm, void *priv,
70 struct eap_method_ret *ret,
71 u8 *reqData, size_t reqDataLen,
74 struct eap_leap_data *data = priv;
75 struct wpa_ssid *config = eap_get_config(sm);
76 struct eap_hdr *req, *resp;
77 u8 *pos, *challenge, challenge_len;
79 wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
81 req = (struct eap_hdr *) reqData;
82 pos = (u8 *) (req + 1);
83 if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_LEAP) {
84 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
90 if (*pos != LEAP_VERSION) {
91 wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
98 pos++; /* skip unused byte */
100 challenge_len = *pos++;
101 if (challenge_len != LEAP_CHALLENGE_LEN ||
102 challenge_len > reqDataLen - sizeof(*req) - 4) {
103 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge "
104 "(challenge_len=%d reqDataLen=%lu",
105 challenge_len, (unsigned long) reqDataLen);
110 memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN);
111 wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP",
112 challenge, LEAP_CHALLENGE_LEN);
114 wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response");
116 *respDataLen = sizeof(struct eap_hdr) + 1 + 3 + LEAP_RESPONSE_LEN +
117 config->identity_len;
118 resp = malloc(*respDataLen);
121 resp->code = EAP_CODE_RESPONSE;
122 resp->identifier = req->identifier;
123 resp->length = host_to_be16(*respDataLen);
124 pos = (u8 *) (resp + 1);
125 *pos++ = EAP_TYPE_LEAP;
126 *pos++ = LEAP_VERSION;
127 *pos++ = 0; /* unused */
128 *pos++ = LEAP_RESPONSE_LEN;
129 nt_challenge_response(challenge,
130 config->password, config->password_len, pos);
131 memcpy(data->peer_response, pos, LEAP_RESPONSE_LEN);
132 wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response", pos, LEAP_RESPONSE_LEN);
133 pos += LEAP_RESPONSE_LEN;
134 memcpy(pos, config->identity, config->identity_len);
136 data->state = LEAP_WAIT_SUCCESS;
142 static u8 * eap_leap_process_success(struct eap_sm *sm, void *priv,
143 struct eap_method_ret *ret,
144 u8 *reqData, size_t reqDataLen,
147 struct eap_leap_data *data = priv;
148 struct wpa_ssid *config = eap_get_config(sm);
149 struct eap_hdr *req, *resp;
152 wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");
154 if (data->state != LEAP_WAIT_SUCCESS) {
155 wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in "
156 "unexpected state (%d) - ignored", data->state);
161 req = (struct eap_hdr *) reqData;
163 *respDataLen = sizeof(struct eap_hdr) + 1 + 3 + LEAP_CHALLENGE_LEN +
164 config->identity_len;
165 resp = malloc(*respDataLen);
168 resp->code = EAP_CODE_REQUEST;
169 resp->identifier = req->identifier;
170 resp->length = host_to_be16(*respDataLen);
171 pos = (u8 *) (resp + 1);
172 *pos++ = EAP_TYPE_LEAP;
173 *pos++ = LEAP_VERSION;
174 *pos++ = 0; /* unused */
175 *pos++ = LEAP_CHALLENGE_LEN;
176 if (hostapd_get_rand(pos, LEAP_CHALLENGE_LEN)) {
177 wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data "
183 memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
184 wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos,
186 pos += LEAP_CHALLENGE_LEN;
187 memcpy(pos, config->identity, config->identity_len);
189 data->state = LEAP_WAIT_RESPONSE;
195 static u8 * eap_leap_process_response(struct eap_sm *sm, void *priv,
196 struct eap_method_ret *ret,
197 u8 *reqData, size_t reqDataLen,
200 struct eap_leap_data *data = priv;
201 struct wpa_ssid *config = eap_get_config(sm);
202 struct eap_hdr *resp;
203 u8 *pos, response_len, pw_hash[16], pw_hash_hash[16],
204 expected[LEAP_RESPONSE_LEN];
206 wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
208 resp = (struct eap_hdr *) reqData;
209 pos = (u8 *) (resp + 1);
210 if (reqDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_LEAP) {
211 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame");
217 if (*pos != LEAP_VERSION) {
218 wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
225 pos++; /* skip unused byte */
227 response_len = *pos++;
228 if (response_len != LEAP_RESPONSE_LEN ||
229 response_len > reqDataLen - sizeof(*resp) - 4) {
230 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response "
231 "(response_len=%d reqDataLen=%lu",
232 response_len, (unsigned long) reqDataLen);
237 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP",
238 pos, LEAP_RESPONSE_LEN);
239 memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN);
241 nt_password_hash(config->password, config->password_len, pw_hash);
242 hash_nt_password_hash(pw_hash, pw_hash_hash);
243 challenge_response(data->ap_challenge, pw_hash_hash, expected);
245 ret->methodState = METHOD_DONE;
246 ret->allowNotifications = FALSE;
248 if (memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) {
249 wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid "
250 "response - authentication failed");
251 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP",
252 expected, LEAP_RESPONSE_LEN);
253 ret->decision = DECISION_FAIL;
257 ret->decision = DECISION_UNCOND_SUCC;
259 /* LEAP is somewhat odd method since it sends EAP-Success in the middle
260 * of the authentication. Use special variable to transit EAP state
261 * machine to SUCCESS state. */
262 sm->leap_done = TRUE;
263 data->state = LEAP_DONE;
265 /* No more authentication messages expected; AP will send EAPOL-Key
266 * frames if encryption is enabled. */
271 static u8 * eap_leap_process(struct eap_sm *sm, void *priv,
272 struct eap_method_ret *ret,
273 u8 *reqData, size_t reqDataLen,
276 struct wpa_ssid *config = eap_get_config(sm);
280 if (config == NULL || config->password == NULL) {
281 wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured");
282 eap_sm_request_password(sm, config);
287 eap = (struct eap_hdr *) reqData;
289 if (reqDataLen < sizeof(*eap) ||
290 (len = be_to_host16(eap->length)) > reqDataLen) {
291 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame");
297 ret->allowNotifications = TRUE;
298 ret->methodState = METHOD_CONT;
299 ret->decision = DECISION_FAIL;
301 sm->leap_done = FALSE;
304 case EAP_CODE_REQUEST:
305 return eap_leap_process_request(sm, priv, ret, reqData, len,
307 case EAP_CODE_SUCCESS:
308 return eap_leap_process_success(sm, priv, ret, reqData, len,
310 case EAP_CODE_RESPONSE:
311 return eap_leap_process_response(sm, priv, ret, reqData, len,
314 wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
315 "ignored", eap->code);
322 static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
324 struct eap_leap_data *data = priv;
325 return data->state == LEAP_DONE;
329 static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
331 struct eap_leap_data *data = priv;
332 struct wpa_ssid *config = eap_get_config(sm);
333 u8 *key, pw_hash_hash[16], pw_hash[16];
336 if (data->state != LEAP_DONE)
339 key = malloc(LEAP_KEY_LEN);
343 nt_password_hash(config->password, config->password_len, pw_hash);
344 hash_nt_password_hash(pw_hash, pw_hash_hash);
345 wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash",
347 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_challenge",
348 data->peer_challenge, LEAP_CHALLENGE_LEN);
349 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: peer_response",
350 data->peer_response, LEAP_RESPONSE_LEN);
351 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_challenge",
352 data->ap_challenge, LEAP_CHALLENGE_LEN);
353 wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response",
354 data->ap_response, LEAP_RESPONSE_LEN);
357 MD5Update(&context, pw_hash_hash, 16);
358 MD5Update(&context, data->ap_challenge, LEAP_CHALLENGE_LEN);
359 MD5Update(&context, data->ap_response, LEAP_RESPONSE_LEN);
360 MD5Update(&context, data->peer_challenge, LEAP_CHALLENGE_LEN);
361 MD5Update(&context, data->peer_response, LEAP_RESPONSE_LEN);
362 MD5Final(key, &context);
363 wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN);
370 const struct eap_method eap_method_leap =
372 .method = EAP_TYPE_LEAP,
374 .init = eap_leap_init,
375 .deinit = eap_leap_deinit,
376 .process = eap_leap_process,
377 .isKeyAvailable = eap_leap_isKeyAvailable,
378 .getKey = eap_leap_getKey,