~ubuntu-branches/ubuntu/gutsy/wpasupplicant/gutsy

« back to all changes in this revision

Viewing changes to eap_leap.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler, Alexander Sack
  • Date: 2007-08-26 16:06:57 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070826160657-2m8pxoweuxe8f93t
Tags: 0.6.0+0.5.8-0ubuntu1
* New upstream release
* remove patch 11_erroneous_manpage_ref, applied upstream
* remove patch 25_wpas_dbus_unregister_iface_fix, applied upstream

[ Alexander Sack ]
* bumping upstream version to replace development version 0.6.0 with
  this package from stable release branch.
* attempt to fix wierd timeout and high latency issues by going
  back to stable upstream version (0.5.9) (LP: #140763,
  LP: #141233).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}