2 * EAP peer method: LEAP
3 * Copyright (c) 2004-2006, Jouni Malinen <j@w1.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.
22 #define LEAP_VERSION 1
23 #define LEAP_CHALLENGE_LEN 8
24 #define LEAP_RESPONSE_LEN 24
25 #define LEAP_KEY_LEN 16
28 struct eap_leap_data
{
36 u8 peer_challenge
[LEAP_CHALLENGE_LEN
];
37 u8 peer_response
[LEAP_RESPONSE_LEN
];
39 u8 ap_challenge
[LEAP_CHALLENGE_LEN
];
40 u8 ap_response
[LEAP_RESPONSE_LEN
];
44 static void * eap_leap_init(struct eap_sm
*sm
)
46 struct eap_leap_data
*data
;
48 data
= os_zalloc(sizeof(*data
));
51 data
->state
= LEAP_WAIT_CHALLENGE
;
53 sm
->leap_done
= FALSE
;
58 static void eap_leap_deinit(struct eap_sm
*sm
, void *priv
)
64 static u8
* eap_leap_process_request(struct eap_sm
*sm
, void *priv
,
65 struct eap_method_ret
*ret
,
66 const u8
*reqData
, size_t reqDataLen
,
69 struct eap_leap_data
*data
= priv
;
70 const struct eap_hdr
*req
;
72 const u8
*pos
, *challenge
, *identity
, *password
;
73 u8 challenge_len
, *rpos
;
74 size_t identity_len
, password_len
;
76 wpa_printf(MSG_DEBUG
, "EAP-LEAP: Processing EAP-Request");
78 identity
= eap_get_config_identity(sm
, &identity_len
);
79 password
= eap_get_config_password(sm
, &password_len
);
80 if (identity
== NULL
|| password
== NULL
)
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 os_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 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_LEAP
, respDataLen
,
119 3 + LEAP_RESPONSE_LEN
+ identity_len
,
120 EAP_CODE_RESPONSE
, req
->identifier
, &rpos
);
123 *rpos
++ = LEAP_VERSION
;
124 *rpos
++ = 0; /* unused */
125 *rpos
++ = LEAP_RESPONSE_LEN
;
126 nt_challenge_response(challenge
, password
, password_len
, rpos
);
127 os_memcpy(data
->peer_response
, rpos
, LEAP_RESPONSE_LEN
);
128 wpa_hexdump(MSG_MSGDUMP
, "EAP-LEAP: Response",
129 rpos
, LEAP_RESPONSE_LEN
);
130 rpos
+= LEAP_RESPONSE_LEN
;
131 os_memcpy(rpos
, identity
, identity_len
);
133 data
->state
= LEAP_WAIT_SUCCESS
;
139 static u8
* eap_leap_process_success(struct eap_sm
*sm
, void *priv
,
140 struct eap_method_ret
*ret
,
141 const u8
*reqData
, size_t *respDataLen
)
143 struct eap_leap_data
*data
= priv
;
144 const struct eap_hdr
*req
;
145 struct eap_hdr
*resp
;
150 wpa_printf(MSG_DEBUG
, "EAP-LEAP: Processing EAP-Success");
152 identity
= eap_get_config_identity(sm
, &identity_len
);
153 if (identity
== NULL
)
156 if (data
->state
!= LEAP_WAIT_SUCCESS
) {
157 wpa_printf(MSG_INFO
, "EAP-LEAP: EAP-Success received in "
158 "unexpected state (%d) - ignored", data
->state
);
163 req
= (const struct eap_hdr
*) reqData
;
165 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_LEAP
, respDataLen
,
166 3 + LEAP_CHALLENGE_LEN
+ identity_len
,
167 EAP_CODE_REQUEST
, req
->identifier
, &pos
);
170 *pos
++ = LEAP_VERSION
;
171 *pos
++ = 0; /* unused */
172 *pos
++ = LEAP_CHALLENGE_LEN
;
173 if (hostapd_get_rand(pos
, LEAP_CHALLENGE_LEN
)) {
174 wpa_printf(MSG_WARNING
, "EAP-LEAP: Failed to read random data "
180 os_memcpy(data
->ap_challenge
, pos
, LEAP_CHALLENGE_LEN
);
181 wpa_hexdump(MSG_MSGDUMP
, "EAP-LEAP: Challenge to AP/AS", pos
,
183 pos
+= LEAP_CHALLENGE_LEN
;
184 os_memcpy(pos
, identity
, identity_len
);
186 data
->state
= LEAP_WAIT_RESPONSE
;
192 static u8
* eap_leap_process_response(struct eap_sm
*sm
, void *priv
,
193 struct eap_method_ret
*ret
,
194 const u8
*reqData
, size_t reqDataLen
)
196 struct eap_leap_data
*data
= priv
;
197 const struct eap_hdr
*resp
;
198 const u8
*pos
, *password
;
199 u8 response_len
, pw_hash
[16], pw_hash_hash
[16],
200 expected
[LEAP_RESPONSE_LEN
];
203 wpa_printf(MSG_DEBUG
, "EAP-LEAP: Processing EAP-Response");
205 password
= eap_get_config_password(sm
, &password_len
);
206 if (password
== NULL
)
209 resp
= (const struct eap_hdr
*) reqData
;
210 pos
= (const u8
*) (resp
+ 1);
211 if (reqDataLen
< sizeof(*resp
) + 4 || *pos
!= EAP_TYPE_LEAP
) {
212 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid EAP-Response frame");
218 if (*pos
!= LEAP_VERSION
) {
219 wpa_printf(MSG_WARNING
, "EAP-LEAP: Unsupported LEAP version "
226 pos
++; /* skip unused byte */
228 response_len
= *pos
++;
229 if (response_len
!= LEAP_RESPONSE_LEN
||
230 response_len
> reqDataLen
- sizeof(*resp
) - 4) {
231 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid response "
232 "(response_len=%d reqDataLen=%lu)",
233 response_len
, (unsigned long) reqDataLen
);
238 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: Response from AP",
239 pos
, LEAP_RESPONSE_LEN
);
240 os_memcpy(data
->ap_response
, pos
, LEAP_RESPONSE_LEN
);
242 nt_password_hash(password
, password_len
, pw_hash
);
243 hash_nt_password_hash(pw_hash
, pw_hash_hash
);
244 challenge_response(data
->ap_challenge
, pw_hash_hash
, expected
);
246 ret
->methodState
= METHOD_DONE
;
247 ret
->allowNotifications
= FALSE
;
249 if (os_memcmp(pos
, expected
, LEAP_RESPONSE_LEN
) != 0) {
250 wpa_printf(MSG_WARNING
, "EAP-LEAP: AP sent an invalid "
251 "response - authentication failed");
252 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: Expected response from AP",
253 expected
, LEAP_RESPONSE_LEN
);
254 ret
->decision
= DECISION_FAIL
;
258 ret
->decision
= DECISION_UNCOND_SUCC
;
260 /* LEAP is somewhat odd method since it sends EAP-Success in the middle
261 * of the authentication. Use special variable to transit EAP state
262 * machine to SUCCESS state. */
263 sm
->leap_done
= TRUE
;
264 data
->state
= LEAP_DONE
;
266 /* No more authentication messages expected; AP will send EAPOL-Key
267 * frames if encryption is enabled. */
272 static u8
* eap_leap_process(struct eap_sm
*sm
, void *priv
,
273 struct eap_method_ret
*ret
,
274 const u8
*reqData
, size_t reqDataLen
,
277 const struct eap_hdr
*eap
;
278 size_t len
, password_len
;
281 password
= eap_get_config_password(sm
, &password_len
);
282 if (password
== NULL
) {
283 wpa_printf(MSG_INFO
, "EAP-LEAP: Password not configured");
284 eap_sm_request_password(sm
);
289 eap
= (const struct eap_hdr
*) reqData
;
291 if (reqDataLen
< sizeof(*eap
) ||
292 (len
= be_to_host16(eap
->length
)) > reqDataLen
) {
293 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid frame");
299 ret
->allowNotifications
= TRUE
;
300 ret
->methodState
= METHOD_MAY_CONT
;
301 ret
->decision
= DECISION_FAIL
;
303 sm
->leap_done
= FALSE
;
306 case EAP_CODE_REQUEST
:
307 return eap_leap_process_request(sm
, priv
, ret
, reqData
, len
,
309 case EAP_CODE_SUCCESS
:
310 return eap_leap_process_success(sm
, priv
, ret
, reqData
,
312 case EAP_CODE_RESPONSE
:
313 return eap_leap_process_response(sm
, priv
, ret
, reqData
, len
);
315 wpa_printf(MSG_INFO
, "EAP-LEAP: Unexpected EAP code (%d) - "
316 "ignored", eap
->code
);
323 static Boolean
eap_leap_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
325 struct eap_leap_data
*data
= priv
;
326 return data
->state
== LEAP_DONE
;
330 static u8
* eap_leap_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
332 struct eap_leap_data
*data
= priv
;
333 u8
*key
, pw_hash_hash
[16], pw_hash
[16];
334 const u8
*addr
[5], *password
;
335 size_t elen
[5], password_len
;
337 if (data
->state
!= LEAP_DONE
)
340 password
= eap_get_config_password(sm
, &password_len
);
341 if (password
== NULL
)
344 key
= os_malloc(LEAP_KEY_LEN
);
348 nt_password_hash(password
, password_len
, pw_hash
);
349 hash_nt_password_hash(pw_hash
, pw_hash_hash
);
350 wpa_hexdump_key(MSG_DEBUG
, "EAP-LEAP: pw_hash_hash",
352 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: peer_challenge",
353 data
->peer_challenge
, LEAP_CHALLENGE_LEN
);
354 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: peer_response",
355 data
->peer_response
, LEAP_RESPONSE_LEN
);
356 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: ap_challenge",
357 data
->ap_challenge
, LEAP_CHALLENGE_LEN
);
358 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: ap_response",
359 data
->ap_response
, LEAP_RESPONSE_LEN
);
361 addr
[0] = pw_hash_hash
;
363 addr
[1] = data
->ap_challenge
;
364 elen
[1] = LEAP_CHALLENGE_LEN
;
365 addr
[2] = data
->ap_response
;
366 elen
[2] = LEAP_RESPONSE_LEN
;
367 addr
[3] = data
->peer_challenge
;
368 elen
[3] = LEAP_CHALLENGE_LEN
;
369 addr
[4] = data
->peer_response
;
370 elen
[4] = LEAP_RESPONSE_LEN
;
371 md5_vector(5, addr
, elen
, key
);
372 wpa_hexdump_key(MSG_DEBUG
, "EAP-LEAP: master key", key
, LEAP_KEY_LEN
);
379 int eap_peer_leap_register(void)
381 struct eap_method
*eap
;
384 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
385 EAP_VENDOR_IETF
, EAP_TYPE_LEAP
, "LEAP");
389 eap
->init
= eap_leap_init
;
390 eap
->deinit
= eap_leap_deinit
;
391 eap
->process
= eap_leap_process
;
392 eap
->isKeyAvailable
= eap_leap_isKeyAvailable
;
393 eap
->getKey
= eap_leap_getKey
;
395 ret
= eap_peer_method_register(eap
);
397 eap_peer_method_free(eap
);