2 * EAP peer method: LEAP
3 * Copyright (c) 2004-2007, 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 struct wpabuf
* eap_leap_process_request(struct eap_sm
*sm
, void *priv
,
65 struct eap_method_ret
*ret
,
66 const struct wpabuf
*reqData
)
68 struct eap_leap_data
*data
= priv
;
70 const u8
*pos
, *challenge
, *identity
, *password
;
71 u8 challenge_len
, *rpos
;
72 size_t identity_len
, password_len
, len
;
75 wpa_printf(MSG_DEBUG
, "EAP-LEAP: Processing EAP-Request");
77 identity
= eap_get_config_identity(sm
, &identity_len
);
78 password
= eap_get_config_password2(sm
, &password_len
, &pwhash
);
79 if (identity
== NULL
|| password
== NULL
)
82 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_LEAP
, reqData
, &len
);
83 if (pos
== NULL
|| len
< 3) {
84 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid EAP-Request frame");
89 if (*pos
!= LEAP_VERSION
) {
90 wpa_printf(MSG_WARNING
, "EAP-LEAP: Unsupported LEAP version "
97 pos
++; /* skip unused byte */
99 challenge_len
= *pos
++;
100 if (challenge_len
!= LEAP_CHALLENGE_LEN
|| challenge_len
> len
- 3) {
101 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid challenge "
102 "(challenge_len=%d reqDataLen=%lu)",
103 challenge_len
, (unsigned long) wpabuf_len(reqData
));
108 os_memcpy(data
->peer_challenge
, challenge
, LEAP_CHALLENGE_LEN
);
109 wpa_hexdump(MSG_MSGDUMP
, "EAP-LEAP: Challenge from AP",
110 challenge
, LEAP_CHALLENGE_LEN
);
112 wpa_printf(MSG_DEBUG
, "EAP-LEAP: Generating Challenge Response");
114 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_LEAP
,
115 3 + LEAP_RESPONSE_LEN
+ identity_len
,
116 EAP_CODE_RESPONSE
, eap_get_id(reqData
));
119 wpabuf_put_u8(resp
, LEAP_VERSION
);
120 wpabuf_put_u8(resp
, 0); /* unused */
121 wpabuf_put_u8(resp
, LEAP_RESPONSE_LEN
);
122 rpos
= wpabuf_put(resp
, LEAP_RESPONSE_LEN
);
124 challenge_response(challenge
, password
, rpos
);
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 wpabuf_put_data(resp
, identity
, identity_len
);
132 data
->state
= LEAP_WAIT_SUCCESS
;
138 static struct wpabuf
* eap_leap_process_success(struct eap_sm
*sm
, void *priv
,
139 struct eap_method_ret
*ret
,
140 const struct wpabuf
*reqData
)
142 struct eap_leap_data
*data
= priv
;
148 wpa_printf(MSG_DEBUG
, "EAP-LEAP: Processing EAP-Success");
150 identity
= eap_get_config_identity(sm
, &identity_len
);
151 if (identity
== NULL
)
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 resp
= eap_msg_alloc(EAP_VENDOR_IETF
, EAP_TYPE_LEAP
,
162 3 + LEAP_CHALLENGE_LEN
+ identity_len
,
163 EAP_CODE_REQUEST
, eap_get_id(reqData
));
166 wpabuf_put_u8(resp
, LEAP_VERSION
);
167 wpabuf_put_u8(resp
, 0); /* unused */
168 wpabuf_put_u8(resp
, LEAP_CHALLENGE_LEN
);
169 pos
= wpabuf_put(resp
, LEAP_CHALLENGE_LEN
);
170 if (os_get_random(pos
, LEAP_CHALLENGE_LEN
)) {
171 wpa_printf(MSG_WARNING
, "EAP-LEAP: Failed to read random data "
177 os_memcpy(data
->ap_challenge
, pos
, LEAP_CHALLENGE_LEN
);
178 wpa_hexdump(MSG_MSGDUMP
, "EAP-LEAP: Challenge to AP/AS", pos
,
180 wpabuf_put_data(resp
, identity
, identity_len
);
182 data
->state
= LEAP_WAIT_RESPONSE
;
188 static struct wpabuf
* eap_leap_process_response(struct eap_sm
*sm
, void *priv
,
189 struct eap_method_ret
*ret
,
190 const struct wpabuf
*reqData
)
192 struct eap_leap_data
*data
= priv
;
193 const u8
*pos
, *password
;
194 u8 response_len
, pw_hash
[16], pw_hash_hash
[16],
195 expected
[LEAP_RESPONSE_LEN
];
196 size_t password_len
, len
;
199 wpa_printf(MSG_DEBUG
, "EAP-LEAP: Processing EAP-Response");
201 password
= eap_get_config_password2(sm
, &password_len
, &pwhash
);
202 if (password
== NULL
)
205 pos
= eap_hdr_validate(EAP_VENDOR_IETF
, EAP_TYPE_LEAP
, reqData
, &len
);
206 if (pos
== NULL
|| len
< 3) {
207 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid EAP-Response frame");
212 if (*pos
!= LEAP_VERSION
) {
213 wpa_printf(MSG_WARNING
, "EAP-LEAP: Unsupported LEAP version "
220 pos
++; /* skip unused byte */
222 response_len
= *pos
++;
223 if (response_len
!= LEAP_RESPONSE_LEN
|| response_len
> len
- 3) {
224 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid response "
225 "(response_len=%d reqDataLen=%lu)",
226 response_len
, (unsigned long) wpabuf_len(reqData
));
231 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: Response from AP",
232 pos
, LEAP_RESPONSE_LEN
);
233 os_memcpy(data
->ap_response
, pos
, LEAP_RESPONSE_LEN
);
236 hash_nt_password_hash(password
, pw_hash_hash
);
238 nt_password_hash(password
, password_len
, pw_hash
);
239 hash_nt_password_hash(pw_hash
, pw_hash_hash
);
241 challenge_response(data
->ap_challenge
, pw_hash_hash
, expected
);
243 ret
->methodState
= METHOD_DONE
;
244 ret
->allowNotifications
= FALSE
;
246 if (os_memcmp(pos
, expected
, LEAP_RESPONSE_LEN
) != 0) {
247 wpa_printf(MSG_WARNING
, "EAP-LEAP: AP sent an invalid "
248 "response - authentication failed");
249 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: Expected response from AP",
250 expected
, LEAP_RESPONSE_LEN
);
251 ret
->decision
= DECISION_FAIL
;
255 ret
->decision
= DECISION_UNCOND_SUCC
;
257 /* LEAP is somewhat odd method since it sends EAP-Success in the middle
258 * of the authentication. Use special variable to transit EAP state
259 * machine to SUCCESS state. */
260 sm
->leap_done
= TRUE
;
261 data
->state
= LEAP_DONE
;
263 /* No more authentication messages expected; AP will send EAPOL-Key
264 * frames if encryption is enabled. */
269 static struct wpabuf
* eap_leap_process(struct eap_sm
*sm
, void *priv
,
270 struct eap_method_ret
*ret
,
271 const struct wpabuf
*reqData
)
273 const struct eap_hdr
*eap
;
277 password
= eap_get_config_password(sm
, &password_len
);
278 if (password
== NULL
) {
279 wpa_printf(MSG_INFO
, "EAP-LEAP: Password not configured");
280 eap_sm_request_password(sm
);
286 * LEAP needs to be able to handle EAP-Success frame which does not
287 * include Type field. Consequently, eap_hdr_validate() cannot be used
288 * here. This validation will be done separately for EAP-Request and
289 * EAP-Response frames.
291 eap
= wpabuf_head(reqData
);
292 if (wpabuf_len(reqData
) < sizeof(*eap
) ||
293 be_to_host16(eap
->length
) > wpabuf_len(reqData
)) {
294 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid frame");
300 ret
->allowNotifications
= TRUE
;
301 ret
->methodState
= METHOD_MAY_CONT
;
302 ret
->decision
= DECISION_FAIL
;
304 sm
->leap_done
= FALSE
;
307 case EAP_CODE_REQUEST
:
308 return eap_leap_process_request(sm
, priv
, ret
, reqData
);
309 case EAP_CODE_SUCCESS
:
310 return eap_leap_process_success(sm
, priv
, ret
, reqData
);
311 case EAP_CODE_RESPONSE
:
312 return eap_leap_process_response(sm
, priv
, ret
, reqData
);
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 u8
*key
, pw_hash_hash
[16], pw_hash
[16];
333 const u8
*addr
[5], *password
;
334 size_t elen
[5], password_len
;
337 if (data
->state
!= LEAP_DONE
)
340 password
= eap_get_config_password2(sm
, &password_len
, &pwhash
);
341 if (password
== NULL
)
344 key
= os_malloc(LEAP_KEY_LEN
);
349 hash_nt_password_hash(password
, pw_hash_hash
);
351 nt_password_hash(password
, password_len
, pw_hash
);
352 hash_nt_password_hash(pw_hash
, pw_hash_hash
);
354 wpa_hexdump_key(MSG_DEBUG
, "EAP-LEAP: pw_hash_hash",
356 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: peer_challenge",
357 data
->peer_challenge
, LEAP_CHALLENGE_LEN
);
358 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: peer_response",
359 data
->peer_response
, LEAP_RESPONSE_LEN
);
360 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: ap_challenge",
361 data
->ap_challenge
, LEAP_CHALLENGE_LEN
);
362 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: ap_response",
363 data
->ap_response
, LEAP_RESPONSE_LEN
);
365 addr
[0] = pw_hash_hash
;
367 addr
[1] = data
->ap_challenge
;
368 elen
[1] = LEAP_CHALLENGE_LEN
;
369 addr
[2] = data
->ap_response
;
370 elen
[2] = LEAP_RESPONSE_LEN
;
371 addr
[3] = data
->peer_challenge
;
372 elen
[3] = LEAP_CHALLENGE_LEN
;
373 addr
[4] = data
->peer_response
;
374 elen
[4] = LEAP_RESPONSE_LEN
;
375 md5_vector(5, addr
, elen
, key
);
376 wpa_hexdump_key(MSG_DEBUG
, "EAP-LEAP: master key", key
, LEAP_KEY_LEN
);
383 int eap_peer_leap_register(void)
385 struct eap_method
*eap
;
388 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
389 EAP_VENDOR_IETF
, EAP_TYPE_LEAP
, "LEAP");
393 eap
->init
= eap_leap_init
;
394 eap
->deinit
= eap_leap_deinit
;
395 eap
->process
= eap_leap_process
;
396 eap
->isKeyAvailable
= eap_leap_isKeyAvailable
;
397 eap
->getKey
= eap_leap_getKey
;
399 ret
= eap_peer_method_register(eap
);
401 eap_peer_method_free(eap
);