More Broadcom 43xx PCI IDs.
[dragonfly/port-amd64.git] / contrib / wpa_supplicant-0.4.9 / eap_leap.c
bloba8677c16dabc56a9f480c21e17c37086f019d041
1 /*
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
10 * license.
12 * See README and COPYING for more details.
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
19 #include "common.h"
20 #include "eap_i.h"
21 #include "wpa_supplicant.h"
22 #include "config_ssid.h"
23 #include "ms_funcs.h"
24 #include "crypto.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 {
33 enum {
34 LEAP_WAIT_CHALLENGE,
35 LEAP_WAIT_SUCCESS,
36 LEAP_WAIT_RESPONSE,
37 LEAP_DONE
38 } state;
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));
53 if (data == NULL)
54 return NULL;
55 memset(data, 0, sizeof(*data));
56 data->state = LEAP_WAIT_CHALLENGE;
58 sm->leap_done = FALSE;
59 return data;
63 static void eap_leap_deinit(struct eap_sm *sm, void *priv)
65 free(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,
72 size_t *respDataLen)
74 struct eap_leap_data *data = priv;
75 struct wpa_ssid *config = eap_get_config(sm);
76 const struct eap_hdr *req;
77 struct eap_hdr *resp;
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");
87 ret->ignore = TRUE;
88 return NULL;
90 pos++;
92 if (*pos != LEAP_VERSION) {
93 wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
94 "%d", *pos);
95 ret->ignore = TRUE;
96 return NULL;
98 pos++;
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);
108 ret->ignore = TRUE;
109 return NULL;
111 challenge = pos;
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);
121 if (resp == NULL)
122 return NULL;
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;
141 return (u8 *) resp;
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,
148 size_t *respDataLen)
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;
154 u8 *pos;
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);
161 ret->ignore = TRUE;
162 return NULL;
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);
170 if (resp == NULL)
171 return NULL;
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 "
182 "for challenge");
183 free(resp);
184 ret->ignore = TRUE;
185 return NULL;
187 memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
188 wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos,
189 LEAP_CHALLENGE_LEN);
190 pos += LEAP_CHALLENGE_LEN;
191 memcpy(pos, config->identity, config->identity_len);
193 data->state = LEAP_WAIT_RESPONSE;
195 return (u8 *) resp;
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,
202 size_t *respDataLen)
204 struct eap_leap_data *data = priv;
205 struct wpa_ssid *config = eap_get_config(sm);
206 const struct eap_hdr *resp;
207 const u8 *pos;
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");
217 ret->ignore = TRUE;
218 return NULL;
220 pos++;
222 if (*pos != LEAP_VERSION) {
223 wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
224 "%d", *pos);
225 ret->ignore = TRUE;
226 return NULL;
228 pos++;
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);
238 ret->ignore = TRUE;
239 return NULL;
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;
259 return NULL;
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. */
272 return NULL;
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,
279 size_t *respDataLen)
281 struct wpa_ssid *config = eap_get_config(sm);
282 const struct eap_hdr *eap;
283 size_t len;
285 if (config == NULL || config->password == NULL) {
286 wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured");
287 eap_sm_request_password(sm, config);
288 ret->ignore = TRUE;
289 return NULL;
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");
297 ret->ignore = TRUE;
298 return NULL;
301 ret->ignore = FALSE;
302 ret->allowNotifications = TRUE;
303 ret->methodState = METHOD_MAY_CONT;
304 ret->decision = DECISION_FAIL;
306 sm->leap_done = FALSE;
308 switch (eap->code) {
309 case EAP_CODE_REQUEST:
310 return eap_leap_process_request(sm, priv, ret, reqData, len,
311 respDataLen);
312 case EAP_CODE_SUCCESS:
313 return eap_leap_process_success(sm, priv, ret, reqData, len,
314 respDataLen);
315 case EAP_CODE_RESPONSE:
316 return eap_leap_process_response(sm, priv, ret, reqData, len,
317 respDataLen);
318 default:
319 wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
320 "ignored", eap->code);
321 ret->ignore = TRUE;
322 return NULL;
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];
339 const u8 *addr[5];
340 size_t elen[5];
342 if (data->state != LEAP_DONE)
343 return NULL;
345 key = malloc(LEAP_KEY_LEN);
346 if (key == NULL)
347 return NULL;
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",
352 pw_hash_hash, 16);
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;
363 elen[0] = 16;
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);
374 *len = LEAP_KEY_LEN;
376 return key;
380 const struct eap_method eap_method_leap =
382 .method = EAP_TYPE_LEAP,
383 .name = "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,