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.
18 #include "crypto/ms_funcs.h"
19 #include "crypto/crypto.h"
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 if (hash_nt_password_hash(password
, pw_hash_hash
)) {
241 if (nt_password_hash(password
, password_len
, pw_hash
) ||
242 hash_nt_password_hash(pw_hash
, pw_hash_hash
)) {
247 challenge_response(data
->ap_challenge
, pw_hash_hash
, expected
);
249 ret
->methodState
= METHOD_DONE
;
250 ret
->allowNotifications
= FALSE
;
252 if (os_memcmp(pos
, expected
, LEAP_RESPONSE_LEN
) != 0) {
253 wpa_printf(MSG_WARNING
, "EAP-LEAP: AP sent an invalid "
254 "response - authentication failed");
255 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: Expected response from AP",
256 expected
, LEAP_RESPONSE_LEN
);
257 ret
->decision
= DECISION_FAIL
;
261 ret
->decision
= DECISION_UNCOND_SUCC
;
263 /* LEAP is somewhat odd method since it sends EAP-Success in the middle
264 * of the authentication. Use special variable to transit EAP state
265 * machine to SUCCESS state. */
266 sm
->leap_done
= TRUE
;
267 data
->state
= LEAP_DONE
;
269 /* No more authentication messages expected; AP will send EAPOL-Key
270 * frames if encryption is enabled. */
275 static struct wpabuf
* eap_leap_process(struct eap_sm
*sm
, void *priv
,
276 struct eap_method_ret
*ret
,
277 const struct wpabuf
*reqData
)
279 const struct eap_hdr
*eap
;
283 password
= eap_get_config_password(sm
, &password_len
);
284 if (password
== NULL
) {
285 wpa_printf(MSG_INFO
, "EAP-LEAP: Password not configured");
286 eap_sm_request_password(sm
);
292 * LEAP needs to be able to handle EAP-Success frame which does not
293 * include Type field. Consequently, eap_hdr_validate() cannot be used
294 * here. This validation will be done separately for EAP-Request and
295 * EAP-Response frames.
297 eap
= wpabuf_head(reqData
);
298 if (wpabuf_len(reqData
) < sizeof(*eap
) ||
299 be_to_host16(eap
->length
) > wpabuf_len(reqData
)) {
300 wpa_printf(MSG_INFO
, "EAP-LEAP: Invalid frame");
306 ret
->allowNotifications
= TRUE
;
307 ret
->methodState
= METHOD_MAY_CONT
;
308 ret
->decision
= DECISION_FAIL
;
310 sm
->leap_done
= FALSE
;
313 case EAP_CODE_REQUEST
:
314 return eap_leap_process_request(sm
, priv
, ret
, reqData
);
315 case EAP_CODE_SUCCESS
:
316 return eap_leap_process_success(sm
, priv
, ret
, reqData
);
317 case EAP_CODE_RESPONSE
:
318 return eap_leap_process_response(sm
, priv
, ret
, reqData
);
320 wpa_printf(MSG_INFO
, "EAP-LEAP: Unexpected EAP code (%d) - "
321 "ignored", eap
->code
);
328 static Boolean
eap_leap_isKeyAvailable(struct eap_sm
*sm
, void *priv
)
330 struct eap_leap_data
*data
= priv
;
331 return data
->state
== LEAP_DONE
;
335 static u8
* eap_leap_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
337 struct eap_leap_data
*data
= priv
;
338 u8
*key
, pw_hash_hash
[16], pw_hash
[16];
339 const u8
*addr
[5], *password
;
340 size_t elen
[5], password_len
;
343 if (data
->state
!= LEAP_DONE
)
346 password
= eap_get_config_password2(sm
, &password_len
, &pwhash
);
347 if (password
== NULL
)
350 key
= os_malloc(LEAP_KEY_LEN
);
355 if (hash_nt_password_hash(password
, pw_hash_hash
)) {
360 if (nt_password_hash(password
, password_len
, pw_hash
) ||
361 hash_nt_password_hash(pw_hash
, pw_hash_hash
)) {
366 wpa_hexdump_key(MSG_DEBUG
, "EAP-LEAP: pw_hash_hash",
368 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: peer_challenge",
369 data
->peer_challenge
, LEAP_CHALLENGE_LEN
);
370 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: peer_response",
371 data
->peer_response
, LEAP_RESPONSE_LEN
);
372 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: ap_challenge",
373 data
->ap_challenge
, LEAP_CHALLENGE_LEN
);
374 wpa_hexdump(MSG_DEBUG
, "EAP-LEAP: ap_response",
375 data
->ap_response
, LEAP_RESPONSE_LEN
);
377 addr
[0] = pw_hash_hash
;
379 addr
[1] = data
->ap_challenge
;
380 elen
[1] = LEAP_CHALLENGE_LEN
;
381 addr
[2] = data
->ap_response
;
382 elen
[2] = LEAP_RESPONSE_LEN
;
383 addr
[3] = data
->peer_challenge
;
384 elen
[3] = LEAP_CHALLENGE_LEN
;
385 addr
[4] = data
->peer_response
;
386 elen
[4] = LEAP_RESPONSE_LEN
;
387 md5_vector(5, addr
, elen
, key
);
388 wpa_hexdump_key(MSG_DEBUG
, "EAP-LEAP: master key", key
, LEAP_KEY_LEN
);
395 int eap_peer_leap_register(void)
397 struct eap_method
*eap
;
400 eap
= eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION
,
401 EAP_VENDOR_IETF
, EAP_TYPE_LEAP
, "LEAP");
405 eap
->init
= eap_leap_init
;
406 eap
->deinit
= eap_leap_deinit
;
407 eap
->process
= eap_leap_process
;
408 eap
->isKeyAvailable
= eap_leap_isKeyAvailable
;
409 eap
->getKey
= eap_leap_getKey
;
411 ret
= eap_peer_method_register(eap
);
413 eap_peer_method_free(eap
);