kate(4): put missing \n into device_printf(9) calls
[dragonfly.git] / contrib / wpa_supplicant-0.5.8 / eap_leap.c
1 /*
2  * EAP peer method: LEAP
3  * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
4  *
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.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16
17 #include "common.h"
18 #include "eap_i.h"
19 #include "ms_funcs.h"
20 #include "crypto.h"
21
22 #define LEAP_VERSION 1
23 #define LEAP_CHALLENGE_LEN 8
24 #define LEAP_RESPONSE_LEN 24
25 #define LEAP_KEY_LEN 16
26
27
28 struct eap_leap_data {
29         enum {
30                 LEAP_WAIT_CHALLENGE,
31                 LEAP_WAIT_SUCCESS,
32                 LEAP_WAIT_RESPONSE,
33                 LEAP_DONE
34         } state;
35
36         u8 peer_challenge[LEAP_CHALLENGE_LEN];
37         u8 peer_response[LEAP_RESPONSE_LEN];
38
39         u8 ap_challenge[LEAP_CHALLENGE_LEN];
40         u8 ap_response[LEAP_RESPONSE_LEN];
41 };
42
43
44 static void * eap_leap_init(struct eap_sm *sm)
45 {
46         struct eap_leap_data *data;
47
48         data = os_zalloc(sizeof(*data));
49         if (data == NULL)
50                 return NULL;
51         data->state = LEAP_WAIT_CHALLENGE;
52
53         sm->leap_done = FALSE;
54         return data;
55 }
56
57
58 static void eap_leap_deinit(struct eap_sm *sm, void *priv)
59 {
60         os_free(priv);
61 }
62
63
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,
67                                      size_t *respDataLen)
68 {
69         struct eap_leap_data *data = priv;
70         const struct eap_hdr *req;
71         struct eap_hdr *resp;
72         const u8 *pos, *challenge, *identity, *password;
73         u8 challenge_len, *rpos;
74         size_t identity_len, password_len;
75
76         wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
77
78         identity = eap_get_config_identity(sm, &identity_len);
79         password = eap_get_config_password(sm, &password_len);
80         if (identity == NULL || password == NULL)
81                 return NULL;
82
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;
89         }
90         pos++;
91
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;
97         }
98         pos++;
99
100         pos++; /* skip unused byte */
101
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;
110         }
111         challenge = pos;
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);
115
116         wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response");
117
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);
121         if (resp == NULL)
122                 return NULL;
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);
132
133         data->state = LEAP_WAIT_SUCCESS;
134
135         return (u8 *) resp;
136 }
137
138
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)
142 {
143         struct eap_leap_data *data = priv;
144         const struct eap_hdr *req;
145         struct eap_hdr *resp;
146         u8 *pos;
147         const u8 *identity;
148         size_t identity_len;
149
150         wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");
151
152         identity = eap_get_config_identity(sm, &identity_len);
153         if (identity == NULL)
154                 return NULL;
155
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);
159                 ret->ignore = TRUE;
160                 return NULL;
161         }
162
163         req = (const struct eap_hdr *) reqData;
164
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);
168         if (resp == NULL)
169                 return NULL;
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 "
175                            "for challenge");
176                 os_free(resp);
177                 ret->ignore = TRUE;
178                 return NULL;
179         }
180         os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
181         wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos,
182                     LEAP_CHALLENGE_LEN);
183         pos += LEAP_CHALLENGE_LEN;
184         os_memcpy(pos, identity, identity_len);
185
186         data->state = LEAP_WAIT_RESPONSE;
187
188         return (u8 *) resp;
189 }
190
191
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)
195 {
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];
201         size_t password_len;
202
203         wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
204
205         password = eap_get_config_password(sm, &password_len);
206         if (password == NULL)
207                 return NULL;
208
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");
213                 ret->ignore = TRUE;
214                 return NULL;
215         }
216         pos++;
217
218         if (*pos != LEAP_VERSION) {
219                 wpa_printf(MSG_WARNING, "EAP-LEAP: Unsupported LEAP version "
220                            "%d", *pos);
221                 ret->ignore = TRUE;
222                 return NULL;
223         }
224         pos++;
225
226         pos++; /* skip unused byte */
227
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);
234                 ret->ignore = TRUE;
235                 return NULL;
236         }
237
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);
241
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);
245
246         ret->methodState = METHOD_DONE;
247         ret->allowNotifications = FALSE;
248
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;
255                 return NULL;
256         }
257
258         ret->decision = DECISION_UNCOND_SUCC;
259
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;
265
266         /* No more authentication messages expected; AP will send EAPOL-Key
267          * frames if encryption is enabled. */
268         return NULL;
269 }
270
271
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,
275                              size_t *respDataLen)
276 {
277         const struct eap_hdr *eap;
278         size_t len, password_len;
279         const u8 *password;
280
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);
285                 ret->ignore = TRUE;
286                 return NULL;
287         }
288
289         eap = (const struct eap_hdr *) reqData;
290
291         if (reqDataLen < sizeof(*eap) ||
292             (len = be_to_host16(eap->length)) > reqDataLen) {
293                 wpa_printf(MSG_INFO, "EAP-LEAP: Invalid frame");
294                 ret->ignore = TRUE;
295                 return NULL;
296         }
297
298         ret->ignore = FALSE;
299         ret->allowNotifications = TRUE;
300         ret->methodState = METHOD_MAY_CONT;
301         ret->decision = DECISION_FAIL;
302
303         sm->leap_done = FALSE;
304
305         switch (eap->code) {
306         case EAP_CODE_REQUEST:
307                 return eap_leap_process_request(sm, priv, ret, reqData, len,
308                                                 respDataLen);
309         case EAP_CODE_SUCCESS:
310                 return eap_leap_process_success(sm, priv, ret, reqData,
311                                                 respDataLen);
312         case EAP_CODE_RESPONSE:
313                 return eap_leap_process_response(sm, priv, ret, reqData, len);
314         default:
315                 wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
316                            "ignored", eap->code);
317                 ret->ignore = TRUE;
318                 return NULL;
319         }
320 }
321
322
323 static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
324 {
325         struct eap_leap_data *data = priv;
326         return data->state == LEAP_DONE;
327 }
328
329
330 static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
331 {
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;
336
337         if (data->state != LEAP_DONE)
338                 return NULL;
339
340         password = eap_get_config_password(sm, &password_len);
341         if (password == NULL)
342                 return NULL;
343
344         key = os_malloc(LEAP_KEY_LEN);
345         if (key == NULL)
346                 return NULL;
347
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",
351                         pw_hash_hash, 16);
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);
360
361         addr[0] = pw_hash_hash;
362         elen[0] = 16;
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);
373         *len = LEAP_KEY_LEN;
374
375         return key;
376 }
377
378
379 int eap_peer_leap_register(void)
380 {
381         struct eap_method *eap;
382         int ret;
383
384         eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
385                                     EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP");
386         if (eap == NULL)
387                 return -1;
388
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;
394
395         ret = eap_peer_method_register(eap);
396         if (ret)
397                 eap_peer_method_free(eap);
398         return ret;
399 }