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 const u8
*reqData
, size_t reqDataLen
,
74 struct eap_leap_data
*data
= priv
;
75 struct wpa_ssid
*config
= eap_get_config(sm
);
76 const struct eap_hdr
*req
;
78 const u8
*pos
, *challenge
;
79 u8 challenge_len
, *rpos
;
81 wpa_printf(MSG_DEBUG
, "EAP-LEAP: Processing EAP-Request");
83 req
= (const struct eap_hdr
*) reqData
;
84 pos
= (const u8
*) (req
+ 1);
85 if (reqDataLen
< sizeof(*req
) + 4 || *pos
!= EAP_TYPE_LEAP
) {
86 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid EAP-Request frame");
92 if (*pos
!= LEAP_VERSION
) {
93 wpa_printf(MSG_WARNING
, "EAP-LEAP: Unsupported LEAP version "
100 pos
++; /* skip unused byte */
102 challenge_len
= *pos
++;
103 if (challenge_len
!= LEAP_CHALLENGE_LEN
||
104 challenge_len
> reqDataLen
- sizeof(*req
) - 4) {
105 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid challenge "
106 "(challenge_len=%d reqDataLen=%lu)",
107 challenge_len
, (unsigned long) reqDataLen
);
112 memcpy(data
->peer_challenge
, challenge
, LEAP_CHALLENGE_LEN
);
113 wpa_hexdump(MSG_MSGDUMP
, "EAP-LEAP: Challenge from AP",
114 challenge
, LEAP_CHALLENGE_LEN
);
116 wpa_printf(MSG_DEBUG
, "EAP-LEAP: Generating Challenge Response");
118 *respDataLen
= sizeof(struct eap_hdr
) + 1 + 3 + LEAP_RESPONSE_LEN
+
119 config
->identity_len
;
120 resp
= malloc(*respDataLen
);
123 resp
->code
= EAP_CODE_RESPONSE
;
124 resp
->identifier
= req
->identifier
;
125 resp
->length
= host_to_be16(*respDataLen
);
126 rpos
= (u8
*) (resp
+ 1);
127 *rpos
++ = EAP_TYPE_LEAP
;
128 *rpos
++ = LEAP_VERSION
;
129 *rpos
++ = 0; /* unused */
130 *rpos
++ = LEAP_RESPONSE_LEN
;
131 nt_challenge_response(challenge
,
132 config
->password
, config
->password_len
, rpos
);
133 memcpy(data
->peer_response
, rpos
, LEAP_RESPONSE_LEN
);
134 wpa_hexdump(MSG_MSGDUMP
, "EAP-LEAP: Response",
135 rpos
, LEAP_RESPONSE_LEN
);
136 rpos
+= LEAP_RESPONSE_LEN
;
137 memcpy(rpos
, config
->identity
, config
->identity_len
);
139 data
->state
= LEAP_WAIT_SUCCESS
;
145 static u8
* eap_leap_process_success(struct eap_sm
*sm
, void *priv
,
146 struct eap_method_ret
*ret
,
147 const u8
*reqData
, size_t reqDataLen
,
150 struct eap_leap_data
*data
= priv
;
151 struct wpa_ssid
*config
= eap_get_config(sm
);
152 const struct eap_hdr
*req
;
153 struct eap_hdr
*resp
;
156 wpa_printf(MSG_DEBUG
, "EAP-LEAP: Processing EAP-Success");
158 if (data
->state
!= LEAP_WAIT_SUCCESS
) {
159 wpa_printf(MSG_INFO
, "EAP-LEAP: EAP-Success received in "
160 "unexpected state (%d) - ignored", data
->state
);
165 req
= (const struct eap_hdr
*) reqData
;
167 *respDataLen
= sizeof(struct eap_hdr
) + 1 + 3 + LEAP_CHALLENGE_LEN
+
168 config
->identity_len
;
169 resp
= malloc(*respDataLen
);
172 resp
->code
= EAP_CODE_REQUEST
;
173 resp
->identifier
= req
->identifier
;
174 resp
->length
= host_to_be16(*respDataLen
);
175 pos
= (u8
*) (resp
+ 1);
176 *pos
++ = EAP_TYPE_LEAP
;
177 *pos
++ = LEAP_VERSION
;
178 *pos
++ = 0; /* unused */
179 *pos
++ = LEAP_CHALLENGE_LEN
;
180 if (hostapd_get_rand(pos
, LEAP_CHALLENGE_LEN
)) {
181 wpa_printf(MSG_WARNING
, "EAP-LEAP: Failed to read random data "
187 memcpy(data
->ap_challenge
, pos
, LEAP_CHALLENGE_LEN
);
188 wpa_hexdump(MSG_MSGDUMP
, "EAP-LEAP: Challenge to AP/AS", pos
,
190 pos
+= LEAP_CHALLENGE_LEN
;
191 memcpy(pos
, config
->identity
, config
->identity_len
);
193 data
->state
= LEAP_WAIT_RESPONSE
;
199 static u8
* eap_leap_process_response(struct eap_sm
*sm
, void *priv
,
200 struct eap_method_ret
*ret
,
201 const u8
*reqData
, size_t reqDataLen
,
204 struct eap_leap_data
*data
= priv
;
205 struct wpa_ssid
*config
= eap_get_config(sm
);
206 const struct eap_hdr
*resp
;
208 u8 response_len
, pw_hash
[16], pw_hash_hash
[16],
209 expected
[LEAP_RESPONSE_LEN
];
211 wpa_printf(MSG_DEBUG
, "EAP-LEAP: Processing EAP-Response");
213 resp
= (const struct eap_hdr
*) reqData
;
214 pos
= (const u8
*) (resp
+ 1);
215 if (reqDataLen
< sizeof(*resp
) + 4 || *pos
!= EAP_TYPE_LEAP
) {
216 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid EAP-Response frame");
222 if (*pos
!= LEAP_VERSION
) {
223 wpa_printf(MSG_WARNING
, "EAP-LEAP: Unsupported LEAP version "
230 pos
++; /* skip unused byte */
232 response_len
= *pos
++;
233 if (response_len
!= LEAP_RESPONSE_LEN
||
234 response_len
> reqDataLen
- sizeof(*resp
) - 4) {
235 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid response "
236 "(response_len=%d reqDataLen=%lu)",
237 response_len
, (unsigned long) reqDataLen
);
242 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: Response from AP",
243 pos
, LEAP_RESPONSE_LEN
);
244 memcpy(data
->ap_response
, pos
, LEAP_RESPONSE_LEN
);
246 nt_password_hash(config
->password
, config
->password_len
, pw_hash
);
247 hash_nt_password_hash(pw_hash
, pw_hash_hash
);
248 challenge_response(data
->ap_challenge
, pw_hash_hash
, expected
);
250 ret
->methodState
= METHOD_DONE
;
251 ret
->allowNotifications
= FALSE
;
253 if (memcmp(pos
, expected
, LEAP_RESPONSE_LEN
) != 0) {
254 wpa_printf(MSG_WARNING
, "EAP-LEAP: AP sent an invalid "
255 "response - authentication failed");
256 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: Expected response from AP",
257 expected
, LEAP_RESPONSE_LEN
);
258 ret
->decision
= DECISION_FAIL
;
262 ret
->decision
= DECISION_UNCOND_SUCC
;
264 /* LEAP is somewhat odd method since it sends EAP-Success in the middle
265 * of the authentication. Use special variable to transit EAP state
266 * machine to SUCCESS state. */
267 sm
->leap_done
= TRUE
;
268 data
->state
= LEAP_DONE
;
270 /* No more authentication messages expected; AP will send EAPOL-Key
271 * frames if encryption is enabled. */
276 static u8
* eap_leap_process(struct eap_sm
*sm
, void *priv
,
277 struct eap_method_ret
*ret
,
278 const u8
*reqData
, size_t reqDataLen
,
281 struct wpa_ssid
*config
= eap_get_config(sm
);
282 const struct eap_hdr
*eap
;
285 if (config
== NULL
|| config
->password
== NULL
) {
286 wpa_printf(MSG_INFO
, "EAP-LEAP: Password not configured");
287 eap_sm_request_password(sm
, config
);
292 eap
= (const struct eap_hdr
*) reqData
;
294 if (reqDataLen
< sizeof(*eap
) ||
295 (len
= be_to_host16(eap
->length
)) > reqDataLen
) {
296 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid frame");
302 ret
->allowNotifications
= TRUE
;
303 ret
->methodState
= METHOD_MAY_CONT
;
304 ret
->decision
= DECISION_FAIL
;
306 sm
->leap_done
= FALSE
;
309 case EAP_CODE_REQUEST
:
310 return eap_leap_process_request(sm
, priv
, ret
, reqData
, len
,
312 case EAP_CODE_SUCCESS
:
313 return eap_leap_process_success(sm
, priv
, ret
, reqData
, len
,
315 case EAP_CODE_RESPONSE
:
316 return eap_leap_process_response(sm
, priv
, ret
, reqData
, len
,
319 wpa_printf(MSG_INFO
, "EAP-LEAP: Unexpected EAP code (%d) - "
320 "ignored", eap
->code
);
327 static Boolean
eap_leap_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
329 struct eap_leap_data
*data
= priv
;
330 return data
->state
== LEAP_DONE
;
334 static u8
* eap_leap_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
336 struct eap_leap_data
*data
= priv
;
337 struct wpa_ssid
*config
= eap_get_config(sm
);
338 u8
*key
, pw_hash_hash
[16], pw_hash
[16];
342 if (data
->state
!= LEAP_DONE
)
345 key
= malloc(LEAP_KEY_LEN
);
349 nt_password_hash(config
->password
, config
->password_len
, pw_hash
);
350 hash_nt_password_hash(pw_hash
, pw_hash_hash
);
351 wpa_hexdump_key(MSG_DEBUG
, "EAP-LEAP: pw_hash_hash",
353 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: peer_challenge",
354 data
->peer_challenge
, LEAP_CHALLENGE_LEN
);
355 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: peer_response",
356 data
->peer_response
, LEAP_RESPONSE_LEN
);
357 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: ap_challenge",
358 data
->ap_challenge
, LEAP_CHALLENGE_LEN
);
359 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: ap_response",
360 data
->ap_response
, LEAP_RESPONSE_LEN
);
362 addr
[0] = pw_hash_hash
;
364 addr
[1] = data
->ap_challenge
;
365 elen
[1] = LEAP_CHALLENGE_LEN
;
366 addr
[2] = data
->ap_response
;
367 elen
[2] = LEAP_RESPONSE_LEN
;
368 addr
[3] = data
->peer_challenge
;
369 elen
[3] = LEAP_CHALLENGE_LEN
;
370 addr
[4] = data
->peer_response
;
371 elen
[4] = LEAP_RESPONSE_LEN
;
372 md5_vector(5, addr
, elen
, key
);
373 wpa_hexdump_key(MSG_DEBUG
, "EAP-LEAP: master key", key
, LEAP_KEY_LEN
);
380 const struct eap_method eap_method_leap
=
382 .method
= EAP_TYPE_LEAP
,
384 .init
= eap_leap_init
,
385 .deinit
= eap_leap_deinit
,
386 .process
= eap_leap_process
,
387 .isKeyAvailable
= eap_leap_isKeyAvailable
,
388 .getKey
= eap_leap_getKey
,