~ubuntu-branches/ubuntu/vivid/wpasupplicant/vivid

« back to all changes in this revision

Viewing changes to eap_peap.c

  • Committer: Bazaar Package Importer
  • Author(s): Kel Modderman
  • Date: 2008-03-12 20:03:04 UTC
  • mfrom: (1.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080312200304-4331y9wj46pdd34z
Tags: 0.6.3-1
* New upstream release.
* Drop patches applied upstream:
  - debian/patches/30_wpa_gui_qt4_eventhistoryui_rework.patch
  - debian/patches/31_wpa_gui_qt4_eventhistory_always_scrollbar.patch
  - debian/patches/32_wpa_gui_qt4_eventhistory_scroll_with_events.patch
  - debian/patches/40_dbus_ssid_data.patch
* Tidy up the clean target of debian/rules. Now that the madwifi headers are
  handled differently we no longer need to do any cleanup.
* Fix formatting error in debian/ifupdown/wpa_action.8 to make lintian
  quieter.
* Add patch to fix formatting errors in manpages build from sgml source. Use
  <emphasis> tags to hightlight keywords instead of surrounding them in
  strong quotes.
  - debian/patches/41_manpage_format_fixes.patch
* wpasupplicant binary package no longer suggests pcscd, guessnet, iproute
  or wireless-tools, nor does it recommend dhcp3-client. These are not
  needed.
* Add debian/patches/10_silence_siocsiwauth_icotl_failure.patch to disable
  ioctl failure messages that occur under normal conditions.
* Cherry pick two upstream git commits concerning the dbus interface:
  - debian/patches/11_avoid_dbus_version_namespace.patch
  - debian/patches/12_fix_potential_use_after_free.patch
* Add debian/patches/42_manpage_explain_available_drivers.patch to explain
  that not all of the driver backends are available in the provided
  wpa_supplicant binary, and that the canonical list of supported driver
  backends can be retrieved from the wpa_supplicant -h (help) output.
  (Closes: #466910)
* Add debian/patches/20_wpa_gui_qt4_disable_link_prl.patch to remove
  link_prl CONFIG compile flag added by qmake-qt4 >= 4.3.4-2 to avoid excess
  linking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt)
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 "eap_tls_common.h"
20
 
#include "config_ssid.h"
21
 
#include "tls.h"
22
 
#include "eap_tlv.h"
23
 
 
24
 
 
25
 
/* Maximum supported PEAP version
26
 
 * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
27
 
 * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
28
 
 * 2 = draft-josefsson-ppext-eap-tls-eap-07.txt
29
 
 */
30
 
#define EAP_PEAP_VERSION 1
31
 
 
32
 
 
33
 
static void eap_peap_deinit(struct eap_sm *sm, void *priv);
34
 
 
35
 
 
36
 
struct eap_peap_data {
37
 
        struct eap_ssl_data ssl;
38
 
 
39
 
        int peap_version, force_peap_version, force_new_label;
40
 
 
41
 
        const struct eap_method *phase2_method;
42
 
        void *phase2_priv;
43
 
        int phase2_success;
44
 
 
45
 
        struct eap_method_type phase2_type;
46
 
        struct eap_method_type *phase2_types;
47
 
        size_t num_phase2_types;
48
 
 
49
 
        int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
50
 
                                 * EAP-Success
51
 
                                 * 1 = reply with tunneled EAP-Success to inner
52
 
                                 * EAP-Success and expect AS to send outer
53
 
                                 * (unencrypted) EAP-Success after this
54
 
                                 * 2 = reply with PEAP/TLS ACK to inner
55
 
                                 * EAP-Success and expect AS to send outer
56
 
                                 * (unencrypted) EAP-Success after this */
57
 
        int resuming; /* starting a resumed session */
58
 
        u8 *key_data;
59
 
 
60
 
        u8 *pending_phase2_req;
61
 
        size_t pending_phase2_req_len;
62
 
};
63
 
 
64
 
 
65
 
static void * eap_peap_init(struct eap_sm *sm)
66
 
{
67
 
        struct eap_peap_data *data;
68
 
        struct wpa_ssid *config = eap_get_config(sm);
69
 
 
70
 
        data = os_zalloc(sizeof(*data));
71
 
        if (data == NULL)
72
 
                return NULL;
73
 
        sm->peap_done = FALSE;
74
 
        data->peap_version = EAP_PEAP_VERSION;
75
 
        data->force_peap_version = -1;
76
 
        data->peap_outer_success = 2;
77
 
 
78
 
        if (config && config->phase1) {
79
 
                char *pos = os_strstr(config->phase1, "peapver=");
80
 
                if (pos) {
81
 
                        data->force_peap_version = atoi(pos + 8);
82
 
                        data->peap_version = data->force_peap_version;
83
 
                        wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version "
84
 
                                   "%d", data->force_peap_version);
85
 
                }
86
 
 
87
 
                if (os_strstr(config->phase1, "peaplabel=1")) {
88
 
                        data->force_new_label = 1;
89
 
                        wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for "
90
 
                                   "key derivation");
91
 
                }
92
 
 
93
 
                if (os_strstr(config->phase1, "peap_outer_success=0")) {
94
 
                        data->peap_outer_success = 0;
95
 
                        wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate "
96
 
                                   "authentication on tunneled EAP-Success");
97
 
                } else if (os_strstr(config->phase1, "peap_outer_success=1")) {
98
 
                        data->peap_outer_success = 1;
99
 
                        wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled "
100
 
                                   "EAP-Success after receiving tunneled "
101
 
                                   "EAP-Success");
102
 
                } else if (os_strstr(config->phase1, "peap_outer_success=2")) {
103
 
                        data->peap_outer_success = 2;
104
 
                        wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK "
105
 
                                   "after receiving tunneled EAP-Success");
106
 
                }
107
 
        }
108
 
 
109
 
        if (config && config->phase2) {
110
 
                char *start, *pos, *buf;
111
 
                struct eap_method_type *methods = NULL, *_methods;
112
 
                u8 method;
113
 
                size_t num_methods = 0;
114
 
                start = buf = os_strdup(config->phase2);
115
 
                if (buf == NULL) {
116
 
                        eap_peap_deinit(sm, data);
117
 
                        return NULL;
118
 
                }
119
 
                while (start && *start != '\0') {
120
 
                        int vendor;
121
 
                        pos = os_strstr(start, "auth=");
122
 
                        if (pos == NULL)
123
 
                                break;
124
 
                        if (start != pos && *(pos - 1) != ' ') {
125
 
                                start = pos + 5;
126
 
                                continue;
127
 
                        }
128
 
 
129
 
                        start = pos + 5;
130
 
                        pos = os_strchr(start, ' ');
131
 
                        if (pos)
132
 
                                *pos++ = '\0';
133
 
                        method = eap_get_phase2_type(start, &vendor);
134
 
                        if (vendor == EAP_VENDOR_IETF &&
135
 
                            method == EAP_TYPE_NONE) {
136
 
                                wpa_printf(MSG_ERROR, "EAP-PEAP: Unsupported "
137
 
                                           "Phase2 method '%s'", start);
138
 
                        } else {
139
 
                                num_methods++;
140
 
                                _methods = os_realloc(
141
 
                                        methods,
142
 
                                        num_methods * sizeof(*methods));
143
 
                                if (_methods == NULL) {
144
 
                                        os_free(methods);
145
 
                                        os_free(buf);
146
 
                                        eap_peap_deinit(sm, data);
147
 
                                        return NULL;
148
 
                                }
149
 
                                methods = _methods;
150
 
                                methods[num_methods - 1].vendor = vendor;
151
 
                                methods[num_methods - 1].method = method;
152
 
                        }
153
 
 
154
 
                        start = pos;
155
 
                }
156
 
                os_free(buf);
157
 
                data->phase2_types = methods;
158
 
                data->num_phase2_types = num_methods;
159
 
        }
160
 
        if (data->phase2_types == NULL) {
161
 
                data->phase2_types =
162
 
                        eap_get_phase2_types(config, &data->num_phase2_types);
163
 
        }
164
 
        if (data->phase2_types == NULL) {
165
 
                wpa_printf(MSG_ERROR, "EAP-PEAP: No Phase2 method available");
166
 
                eap_peap_deinit(sm, data);
167
 
                return NULL;
168
 
        }
169
 
        wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 EAP types",
170
 
                    (u8 *) data->phase2_types,
171
 
                    data->num_phase2_types * sizeof(struct eap_method_type));
172
 
        data->phase2_type.vendor = EAP_VENDOR_IETF;
173
 
        data->phase2_type.method = EAP_TYPE_NONE;
174
 
 
175
 
        if (eap_tls_ssl_init(sm, &data->ssl, config)) {
176
 
                wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
177
 
                eap_peap_deinit(sm, data);
178
 
                return NULL;
179
 
        }
180
 
 
181
 
        return data;
182
 
}
183
 
 
184
 
 
185
 
static void eap_peap_deinit(struct eap_sm *sm, void *priv)
186
 
{
187
 
        struct eap_peap_data *data = priv;
188
 
        if (data == NULL)
189
 
                return;
190
 
        if (data->phase2_priv && data->phase2_method)
191
 
                data->phase2_method->deinit(sm, data->phase2_priv);
192
 
        os_free(data->phase2_types);
193
 
        eap_tls_ssl_deinit(sm, &data->ssl);
194
 
        os_free(data->key_data);
195
 
        os_free(data->pending_phase2_req);
196
 
        os_free(data);
197
 
}
198
 
 
199
 
 
200
 
static int eap_peap_encrypt(struct eap_sm *sm, struct eap_peap_data *data,
201
 
                            int id, const u8 *plain, size_t plain_len,
202
 
                            u8 **out_data, size_t *out_len)
203
 
{
204
 
        int res;
205
 
        u8 *pos;
206
 
        struct eap_hdr *resp;
207
 
 
208
 
        /* TODO: add support for fragmentation, if needed. This will need to
209
 
         * add TLS Message Length field, if the frame is fragmented.
210
 
         * Note: Microsoft IAS did not seem to like TLS Message Length with
211
 
         * PEAP/MSCHAPv2. */
212
 
        resp = os_malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
213
 
        if (resp == NULL)
214
 
                return -1;
215
 
 
216
 
        resp->code = EAP_CODE_RESPONSE;
217
 
        resp->identifier = id;
218
 
 
219
 
        pos = (u8 *) (resp + 1);
220
 
        *pos++ = EAP_TYPE_PEAP;
221
 
        *pos++ = data->peap_version;
222
 
 
223
 
        res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
224
 
                                     plain, plain_len,
225
 
                                     pos, data->ssl.tls_out_limit);
226
 
        if (res < 0) {
227
 
                wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt Phase 2 "
228
 
                           "data");
229
 
                os_free(resp);
230
 
                return -1;
231
 
        }
232
 
 
233
 
        *out_len = sizeof(struct eap_hdr) + 2 + res;
234
 
        resp->length = host_to_be16(*out_len);
235
 
        *out_data = (u8 *) resp;
236
 
        return 0;
237
 
}
238
 
 
239
 
 
240
 
static int eap_peap_phase2_nak(struct eap_peap_data *data, struct eap_hdr *hdr,
241
 
                               u8 **resp, size_t *resp_len)
242
 
{
243
 
        struct eap_hdr *resp_hdr;
244
 
        u8 *pos = (u8 *) (hdr + 1);
245
 
        size_t i;
246
 
 
247
 
        /* TODO: add support for expanded Nak */
248
 
        wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: Nak type=%d", *pos);
249
 
        wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Allowed Phase2 EAP types",
250
 
                    (u8 *) data->phase2_types,
251
 
                    data->num_phase2_types * sizeof(struct eap_method_type));
252
 
        *resp_len = sizeof(struct eap_hdr) + 1;
253
 
        *resp = os_malloc(*resp_len + data->num_phase2_types);
254
 
        if (*resp == NULL)
255
 
                return -1;
256
 
 
257
 
        resp_hdr = (struct eap_hdr *) (*resp);
258
 
        resp_hdr->code = EAP_CODE_RESPONSE;
259
 
        resp_hdr->identifier = hdr->identifier;
260
 
        pos = (u8 *) (resp_hdr + 1);
261
 
        *pos++ = EAP_TYPE_NAK;
262
 
        for (i = 0; i < data->num_phase2_types; i++) {
263
 
                if (data->phase2_types[i].vendor == EAP_VENDOR_IETF &&
264
 
                    data->phase2_types[i].method < 256) {
265
 
                        (*resp_len)++;
266
 
                        *pos++ = data->phase2_types[i].method;
267
 
                }
268
 
        }
269
 
        resp_hdr->length = host_to_be16(*resp_len);
270
 
 
271
 
        return 0;
272
 
}
273
 
 
274
 
 
275
 
static int eap_peap_phase2_request(struct eap_sm *sm,
276
 
                                   struct eap_peap_data *data,
277
 
                                   struct eap_method_ret *ret,
278
 
                                   struct eap_hdr *hdr,
279
 
                                   u8 **resp, size_t *resp_len)
280
 
{
281
 
        size_t len = be_to_host16(hdr->length);
282
 
        u8 *pos;
283
 
        struct eap_method_ret iret;
284
 
        struct wpa_ssid *config = eap_get_config(sm);
285
 
 
286
 
        if (len <= sizeof(struct eap_hdr)) {
287
 
                wpa_printf(MSG_INFO, "EAP-PEAP: too short "
288
 
                           "Phase 2 request (len=%lu)", (unsigned long) len);
289
 
                return -1;
290
 
        }
291
 
        pos = (u8 *) (hdr + 1);
292
 
        wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
293
 
        switch (*pos) {
294
 
        case EAP_TYPE_IDENTITY:
295
 
                *resp = eap_sm_buildIdentity(sm, hdr->identifier, resp_len, 1);
296
 
                break;
297
 
        case EAP_TYPE_TLV:
298
 
                os_memset(&iret, 0, sizeof(iret));
299
 
                if (eap_tlv_process(sm, &iret, hdr, resp, resp_len)) {
300
 
                        ret->methodState = METHOD_DONE;
301
 
                        ret->decision = DECISION_FAIL;
302
 
                        return -1;
303
 
                }
304
 
                if (iret.methodState == METHOD_DONE ||
305
 
                    iret.methodState == METHOD_MAY_CONT) {
306
 
                        ret->methodState = iret.methodState;
307
 
                        ret->decision = iret.decision;
308
 
                        data->phase2_success = 1;
309
 
                }
310
 
                break;
311
 
        default:
312
 
                if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
313
 
                    data->phase2_type.method == EAP_TYPE_NONE) {
314
 
                        size_t i;
315
 
                        for (i = 0; i < data->num_phase2_types; i++) {
316
 
                                if (data->phase2_types[i].vendor !=
317
 
                                    EAP_VENDOR_IETF ||
318
 
                                    data->phase2_types[i].method != *pos)
319
 
                                        continue;
320
 
 
321
 
                                data->phase2_type.vendor =
322
 
                                        data->phase2_types[i].vendor;
323
 
                                data->phase2_type.method =
324
 
                                        data->phase2_types[i].method;
325
 
                                wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
326
 
                                           "Phase 2 EAP vendor %d method %d",
327
 
                                           data->phase2_type.vendor,
328
 
                                           data->phase2_type.method);
329
 
                                break;
330
 
                        }
331
 
                }
332
 
                if (*pos != data->phase2_type.method ||
333
 
                    *pos == EAP_TYPE_NONE) {
334
 
                        if (eap_peap_phase2_nak(data, hdr, resp, resp_len))
335
 
                                return -1;
336
 
                        return 0;
337
 
                }
338
 
 
339
 
                if (data->phase2_priv == NULL) {
340
 
                        data->phase2_method = eap_sm_get_eap_methods(
341
 
                                data->phase2_type.vendor,
342
 
                                data->phase2_type.method);
343
 
                        if (data->phase2_method) {
344
 
                                sm->init_phase2 = 1;
345
 
                                data->phase2_priv =
346
 
                                        data->phase2_method->init(sm);
347
 
                                sm->init_phase2 = 0;
348
 
                        }
349
 
                }
350
 
                if (data->phase2_priv == NULL || data->phase2_method == NULL) {
351
 
                        wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
352
 
                                   "Phase 2 EAP method %d", *pos);
353
 
                        ret->methodState = METHOD_DONE;
354
 
                        ret->decision = DECISION_FAIL;
355
 
                        return -1;
356
 
                }
357
 
                os_memset(&iret, 0, sizeof(iret));
358
 
                *resp = data->phase2_method->process(sm, data->phase2_priv,
359
 
                                                     &iret, (u8 *) hdr, len,
360
 
                                                     resp_len);
361
 
                if ((iret.methodState == METHOD_DONE ||
362
 
                     iret.methodState == METHOD_MAY_CONT) &&
363
 
                    (iret.decision == DECISION_UNCOND_SUCC ||
364
 
                     iret.decision == DECISION_COND_SUCC)) {
365
 
                        data->phase2_success = 1;
366
 
                }
367
 
                break;
368
 
        }
369
 
 
370
 
        if (*resp == NULL &&
371
 
            (config->pending_req_identity || config->pending_req_password ||
372
 
             config->pending_req_otp || config->pending_req_new_password)) {
373
 
                os_free(data->pending_phase2_req);
374
 
                data->pending_phase2_req = os_malloc(len);
375
 
                if (data->pending_phase2_req) {
376
 
                        os_memcpy(data->pending_phase2_req, hdr, len);
377
 
                        data->pending_phase2_req_len = len;
378
 
                }
379
 
        }
380
 
 
381
 
        return 0;
382
 
}
383
 
 
384
 
 
385
 
static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
386
 
                            struct eap_method_ret *ret,
387
 
                            const struct eap_hdr *req,
388
 
                            const u8 *in_data, size_t in_len,
389
 
                            u8 **out_data, size_t *out_len)
390
 
{
391
 
        u8 *in_decrypted;
392
 
        int res, skip_change = 0;
393
 
        struct eap_hdr *hdr, *rhdr;
394
 
        u8 *resp = NULL;
395
 
        size_t resp_len, len_decrypted, len, buf_len;
396
 
        const u8 *msg;
397
 
        size_t msg_len;
398
 
        int need_more_input;
399
 
 
400
 
        wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
401
 
                   " Phase 2", (unsigned long) in_len);
402
 
 
403
 
        if (data->pending_phase2_req) {
404
 
                wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
405
 
                           "skip decryption and use old data");
406
 
                /* Clear TLS reassembly state. */
407
 
                os_free(data->ssl.tls_in);
408
 
                data->ssl.tls_in = NULL;
409
 
                data->ssl.tls_in_len = 0;
410
 
                data->ssl.tls_in_left = 0;
411
 
                data->ssl.tls_in_total = 0;
412
 
                in_decrypted = data->pending_phase2_req;
413
 
                data->pending_phase2_req = NULL;
414
 
                len_decrypted = data->pending_phase2_req_len;
415
 
                skip_change = 1;
416
 
                goto continue_req;
417
 
        }
418
 
 
419
 
        msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len,
420
 
                                      &msg_len, &need_more_input);
421
 
        if (msg == NULL)
422
 
                return need_more_input ? 1 : -1;
423
 
 
424
 
        if (in_len == 0 && sm->workaround && data->phase2_success) {
425
 
                /*
426
 
                 * Cisco ACS seems to be using TLS ACK to terminate
427
 
                 * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
428
 
                 */
429
 
                wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
430
 
                           "expected data - acknowledge with TLS ACK since "
431
 
                           "Phase 2 has been completed");
432
 
                ret->decision = DECISION_COND_SUCC;
433
 
                ret->methodState = METHOD_DONE;
434
 
                return 1;
435
 
        }
436
 
 
437
 
        buf_len = in_len;
438
 
        if (data->ssl.tls_in_total > buf_len)
439
 
                buf_len = data->ssl.tls_in_total;
440
 
        in_decrypted = os_malloc(buf_len);
441
 
        if (in_decrypted == NULL) {
442
 
                os_free(data->ssl.tls_in);
443
 
                data->ssl.tls_in = NULL;
444
 
                data->ssl.tls_in_len = 0;
445
 
                wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory "
446
 
                           "for decryption");
447
 
                return -1;
448
 
        }
449
 
 
450
 
        res = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
451
 
                                     msg, msg_len, in_decrypted, buf_len);
452
 
        os_free(data->ssl.tls_in);
453
 
        data->ssl.tls_in = NULL;
454
 
        data->ssl.tls_in_len = 0;
455
 
        if (res < 0) {
456
 
                wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
457
 
                           "data");
458
 
                os_free(in_decrypted);
459
 
                return 0;
460
 
        }
461
 
        len_decrypted = res;
462
 
 
463
 
continue_req:
464
 
        wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted,
465
 
                    len_decrypted);
466
 
 
467
 
        hdr = (struct eap_hdr *) in_decrypted;
468
 
        if (len_decrypted == 5 && hdr->code == EAP_CODE_REQUEST &&
469
 
            be_to_host16(hdr->length) == 5 &&
470
 
            in_decrypted[4] == EAP_TYPE_IDENTITY) {
471
 
                /* At least FreeRADIUS seems to send full EAP header with
472
 
                 * EAP Request Identity */
473
 
                skip_change = 1;
474
 
        }
475
 
        if (len_decrypted >= 5 && hdr->code == EAP_CODE_REQUEST &&
476
 
            in_decrypted[4] == EAP_TYPE_TLV) {
477
 
                skip_change = 1;
478
 
        }
479
 
 
480
 
        if (data->peap_version == 0 && !skip_change) {
481
 
                struct eap_hdr *nhdr = os_malloc(sizeof(struct eap_hdr) +
482
 
                                                 len_decrypted);
483
 
                if (nhdr == NULL) {
484
 
                        os_free(in_decrypted);
485
 
                        return 0;
486
 
                }
487
 
                os_memcpy((u8 *) (nhdr + 1), in_decrypted, len_decrypted);
488
 
                os_free(in_decrypted);
489
 
                nhdr->code = req->code;
490
 
                nhdr->identifier = req->identifier;
491
 
                nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
492
 
                                            len_decrypted);
493
 
 
494
 
                len_decrypted += sizeof(struct eap_hdr);
495
 
                in_decrypted = (u8 *) nhdr;
496
 
        }
497
 
        hdr = (struct eap_hdr *) in_decrypted;
498
 
        if (len_decrypted < sizeof(*hdr)) {
499
 
                os_free(in_decrypted);
500
 
                wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
501
 
                           "EAP frame (len=%lu)",
502
 
                           (unsigned long) len_decrypted);
503
 
                return 0;
504
 
        }
505
 
        len = be_to_host16(hdr->length);
506
 
        if (len > len_decrypted) {
507
 
                os_free(in_decrypted);
508
 
                wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
509
 
                           "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
510
 
                           (unsigned long) len_decrypted, (unsigned long) len);
511
 
                return 0;
512
 
        }
513
 
        if (len < len_decrypted) {
514
 
                wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
515
 
                           "shorter length than full decrypted data "
516
 
                           "(%lu < %lu)",
517
 
                           (unsigned long) len, (unsigned long) len_decrypted);
518
 
                if (sm->workaround && len == 4 && len_decrypted == 5 &&
519
 
                    in_decrypted[4] == EAP_TYPE_IDENTITY) {
520
 
                        /* Radiator 3.9 seems to set Phase 2 EAP header to use
521
 
                         * incorrect length for the EAP-Request Identity
522
 
                         * packet, so fix the inner header to interoperate..
523
 
                         * This was fixed in 2004-06-23 patch for Radiator and
524
 
                         * this workaround can be removed at some point. */
525
 
                        wpa_printf(MSG_INFO, "EAP-PEAP: workaround -> replace "
526
 
                                   "Phase 2 EAP header len (%lu) with real "
527
 
                                   "decrypted len (%lu)",
528
 
                                   (unsigned long) len,
529
 
                                   (unsigned long) len_decrypted);
530
 
                        len = len_decrypted;
531
 
                        hdr->length = host_to_be16(len);
532
 
                }
533
 
        }
534
 
        wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
535
 
                   "identifier=%d length=%lu", hdr->code, hdr->identifier,
536
 
                   (unsigned long) len);
537
 
        switch (hdr->code) {
538
 
        case EAP_CODE_REQUEST:
539
 
                if (eap_peap_phase2_request(sm, data, ret, hdr,
540
 
                                            &resp, &resp_len)) {
541
 
                        os_free(in_decrypted);
542
 
                        wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
543
 
                                   "processing failed");
544
 
                        return 0;
545
 
                }
546
 
                break;
547
 
        case EAP_CODE_SUCCESS:
548
 
                wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
549
 
                if (data->peap_version == 1) {
550
 
                        /* EAP-Success within TLS tunnel is used to indicate
551
 
                         * shutdown of the TLS channel. The authentication has
552
 
                         * been completed. */
553
 
                        wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
554
 
                                   "EAP-Success within TLS tunnel - "
555
 
                                   "authentication completed");
556
 
                        ret->decision = DECISION_UNCOND_SUCC;
557
 
                        ret->methodState = METHOD_DONE;
558
 
                        data->phase2_success = 1;
559
 
                        if (data->peap_outer_success == 2) {
560
 
                                os_free(in_decrypted);
561
 
                                wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
562
 
                                           "to finish authentication");
563
 
                                return 1;
564
 
                        } else if (data->peap_outer_success == 1) {
565
 
                                /* Reply with EAP-Success within the TLS
566
 
                                 * channel to complete the authentication. */
567
 
                                resp_len = sizeof(struct eap_hdr);
568
 
                                resp = os_zalloc(resp_len);
569
 
                                if (resp) {
570
 
                                        rhdr = (struct eap_hdr *) resp;
571
 
                                        rhdr->code = EAP_CODE_SUCCESS;
572
 
                                        rhdr->identifier = hdr->identifier;
573
 
                                        rhdr->length = host_to_be16(resp_len);
574
 
                                }
575
 
                        } else {
576
 
                                /* No EAP-Success expected for Phase 1 (outer,
577
 
                                 * unencrypted auth), so force EAP state
578
 
                                 * machine to SUCCESS state. */
579
 
                                sm->peap_done = TRUE;
580
 
                        }
581
 
                } else {
582
 
                        /* FIX: ? */
583
 
                }
584
 
                break;
585
 
        case EAP_CODE_FAILURE:
586
 
                wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
587
 
                ret->decision = DECISION_FAIL;
588
 
                ret->methodState = METHOD_MAY_CONT;
589
 
                ret->allowNotifications = FALSE;
590
 
                /* Reply with EAP-Failure within the TLS channel to complete
591
 
                 * failure reporting. */
592
 
                resp_len = sizeof(struct eap_hdr);
593
 
                resp = os_zalloc(resp_len);
594
 
                if (resp) {
595
 
                        rhdr = (struct eap_hdr *) resp;
596
 
                        rhdr->code = EAP_CODE_FAILURE;
597
 
                        rhdr->identifier = hdr->identifier;
598
 
                        rhdr->length = host_to_be16(resp_len);
599
 
                }
600
 
                break;
601
 
        default:
602
 
                wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
603
 
                           "Phase 2 EAP header", hdr->code);
604
 
                break;
605
 
        }
606
 
 
607
 
        os_free(in_decrypted);
608
 
 
609
 
        if (resp) {
610
 
                u8 *resp_pos;
611
 
                size_t resp_send_len;
612
 
                int skip_change2 = 0;
613
 
 
614
 
                wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
615
 
                                resp, resp_len);
616
 
                /* PEAP version changes */
617
 
                if (resp_len >= 5 && resp[0] == EAP_CODE_RESPONSE &&
618
 
                    resp[4] == EAP_TYPE_TLV)
619
 
                        skip_change2 = 1;
620
 
                if (data->peap_version == 0 && !skip_change2) {
621
 
                        resp_pos = resp + sizeof(struct eap_hdr);
622
 
                        resp_send_len = resp_len - sizeof(struct eap_hdr);
623
 
                } else {
624
 
                        resp_pos = resp;
625
 
                        resp_send_len = resp_len;
626
 
                }
627
 
 
628
 
                if (eap_peap_encrypt(sm, data, req->identifier,
629
 
                                     resp_pos, resp_send_len,
630
 
                                     out_data, out_len)) {
631
 
                        wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
632
 
                                   "a Phase 2 frame");
633
 
                }
634
 
                os_free(resp);
635
 
        }
636
 
 
637
 
        return 0;
638
 
}
639
 
 
640
 
 
641
 
static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
642
 
                             struct eap_method_ret *ret,
643
 
                             const u8 *reqData, size_t reqDataLen,
644
 
                             size_t *respDataLen)
645
 
{
646
 
        const struct eap_hdr *req;
647
 
        size_t left;
648
 
        int res;
649
 
        u8 flags, *resp, id;
650
 
        const u8 *pos;
651
 
        struct eap_peap_data *data = priv;
652
 
 
653
 
        pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
654
 
                                   reqData, reqDataLen, &left, &flags);
655
 
        if (pos == NULL)
656
 
                return NULL;
657
 
        req = (const struct eap_hdr *) reqData;
658
 
        id = req->identifier;
659
 
 
660
 
        if (flags & EAP_TLS_FLAGS_START) {
661
 
                wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
662
 
                           "ver=%d)", flags & EAP_PEAP_VERSION_MASK,
663
 
                        data->peap_version);
664
 
                if ((flags & EAP_PEAP_VERSION_MASK) < data->peap_version)
665
 
                        data->peap_version = flags & EAP_PEAP_VERSION_MASK;
666
 
                if (data->force_peap_version >= 0 &&
667
 
                    data->force_peap_version != data->peap_version) {
668
 
                        wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
669
 
                                   "forced PEAP version %d",
670
 
                                   data->force_peap_version);
671
 
                        ret->methodState = METHOD_DONE;
672
 
                        ret->decision = DECISION_FAIL;
673
 
                        ret->allowNotifications = FALSE;
674
 
                        return NULL;
675
 
                }
676
 
                wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
677
 
                           data->peap_version);
678
 
                left = 0; /* make sure that this frame is empty, even though it
679
 
                           * should always be, anyway */
680
 
        }
681
 
 
682
 
        resp = NULL;
683
 
        if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
684
 
            !data->resuming) {
685
 
                res = eap_peap_decrypt(sm, data, ret, req, pos, left,
686
 
                                       &resp, respDataLen);
687
 
        } else {
688
 
                res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_PEAP,
689
 
                                             data->peap_version, id, pos, left,
690
 
                                             &resp, respDataLen);
691
 
 
692
 
                if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
693
 
                        char *label;
694
 
                        wpa_printf(MSG_DEBUG,
695
 
                                   "EAP-PEAP: TLS done, proceed to Phase 2");
696
 
                        os_free(data->key_data);
697
 
                        /* draft-josefsson-ppext-eap-tls-eap-05.txt
698
 
                         * specifies that PEAPv1 would use "client PEAP
699
 
                         * encryption" as the label. However, most existing
700
 
                         * PEAPv1 implementations seem to be using the old
701
 
                         * label, "client EAP encryption", instead. Use the old
702
 
                         * label by default, but allow it to be configured with
703
 
                         * phase1 parameter peaplabel=1. */
704
 
                        if (data->peap_version > 1 || data->force_new_label)
705
 
                                label = "client PEAP encryption";
706
 
                        else
707
 
                                label = "client EAP encryption";
708
 
                        wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
709
 
                                   "key derivation", label);
710
 
                        data->key_data =
711
 
                                eap_tls_derive_key(sm, &data->ssl, label,
712
 
                                                   EAP_TLS_KEY_LEN);
713
 
                        if (data->key_data) {
714
 
                                wpa_hexdump_key(MSG_DEBUG, 
715
 
                                                "EAP-PEAP: Derived key",
716
 
                                                data->key_data,
717
 
                                                EAP_TLS_KEY_LEN);
718
 
                        } else {
719
 
                                wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
720
 
                                           "derive key");
721
 
                        }
722
 
 
723
 
                        if (sm->workaround && data->resuming) {
724
 
                                /*
725
 
                                 * At least few RADIUS servers (Aegis v1.1.6;
726
 
                                 * but not v1.1.4; and Cisco ACS) seem to be
727
 
                                 * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
728
 
                                 * ACS) session resumption with outer
729
 
                                 * EAP-Success. This does not seem to follow
730
 
                                 * draft-josefsson-pppext-eap-tls-eap-05.txt
731
 
                                 * section 4.2, so only allow this if EAP
732
 
                                 * workarounds are enabled.
733
 
                                 */
734
 
                                wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
735
 
                                           "allow outer EAP-Success to "
736
 
                                           "terminate PEAP resumption");
737
 
                                ret->decision = DECISION_COND_SUCC;
738
 
                                data->phase2_success = 1;
739
 
                        }
740
 
 
741
 
                        data->resuming = 0;
742
 
                }
743
 
 
744
 
                if (res == 2) {
745
 
                        /*
746
 
                         * Application data included in the handshake message.
747
 
                         */
748
 
                        os_free(data->pending_phase2_req);
749
 
                        data->pending_phase2_req = resp;
750
 
                        data->pending_phase2_req_len = *respDataLen;
751
 
                        resp = NULL;
752
 
                        *respDataLen = 0;
753
 
                        res = eap_peap_decrypt(sm, data, ret, req, pos, left,
754
 
                                               &resp, respDataLen);
755
 
                }
756
 
        }
757
 
 
758
 
        if (ret->methodState == METHOD_DONE) {
759
 
                ret->allowNotifications = FALSE;
760
 
        }
761
 
 
762
 
        if (res == 1) {
763
 
                return eap_tls_build_ack(&data->ssl, respDataLen, id,
764
 
                                         EAP_TYPE_PEAP, data->peap_version);
765
 
        }
766
 
 
767
 
        return resp;
768
 
}
769
 
 
770
 
 
771
 
static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
772
 
{
773
 
        struct eap_peap_data *data = priv;
774
 
        return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
775
 
                data->phase2_success;
776
 
}
777
 
 
778
 
 
779
 
static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
780
 
{
781
 
        struct eap_peap_data *data = priv;
782
 
        os_free(data->pending_phase2_req);
783
 
        data->pending_phase2_req = NULL;
784
 
}
785
 
 
786
 
 
787
 
static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
788
 
{
789
 
        struct eap_peap_data *data = priv;
790
 
        os_free(data->key_data);
791
 
        data->key_data = NULL;
792
 
        if (eap_tls_reauth_init(sm, &data->ssl)) {
793
 
                os_free(data);
794
 
                return NULL;
795
 
        }
796
 
        if (data->phase2_priv && data->phase2_method &&
797
 
            data->phase2_method->init_for_reauth)
798
 
                data->phase2_method->init_for_reauth(sm, data->phase2_priv);
799
 
        data->phase2_success = 0;
800
 
        data->resuming = 1;
801
 
        sm->peap_done = FALSE;
802
 
        return priv;
803
 
}
804
 
 
805
 
 
806
 
static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
807
 
                               size_t buflen, int verbose)
808
 
{
809
 
        struct eap_peap_data *data = priv;
810
 
        int len, ret;
811
 
 
812
 
        len = eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
813
 
        if (data->phase2_method) {
814
 
                ret = os_snprintf(buf + len, buflen - len,
815
 
                                  "EAP-PEAPv%d Phase2 method=%s\n",
816
 
                                  data->peap_version,
817
 
                                  data->phase2_method->name);
818
 
                if (ret < 0 || (size_t) ret >= buflen - len)
819
 
                        return len;
820
 
                len += ret;
821
 
        }
822
 
        return len;
823
 
}
824
 
 
825
 
 
826
 
static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
827
 
{
828
 
        struct eap_peap_data *data = priv;
829
 
        return data->key_data != NULL && data->phase2_success;
830
 
}
831
 
 
832
 
 
833
 
static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
834
 
{
835
 
        struct eap_peap_data *data = priv;
836
 
        u8 *key;
837
 
 
838
 
        if (data->key_data == NULL || !data->phase2_success)
839
 
                return NULL;
840
 
 
841
 
        key = os_malloc(EAP_TLS_KEY_LEN);
842
 
        if (key == NULL)
843
 
                return NULL;
844
 
 
845
 
        *len = EAP_TLS_KEY_LEN;
846
 
        os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
847
 
 
848
 
        return key;
849
 
}
850
 
 
851
 
 
852
 
int eap_peer_peap_register(void)
853
 
{
854
 
        struct eap_method *eap;
855
 
        int ret;
856
 
 
857
 
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
858
 
                                    EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
859
 
        if (eap == NULL)
860
 
                return -1;
861
 
 
862
 
        eap->init = eap_peap_init;
863
 
        eap->deinit = eap_peap_deinit;
864
 
        eap->process = eap_peap_process;
865
 
        eap->isKeyAvailable = eap_peap_isKeyAvailable;
866
 
        eap->getKey = eap_peap_getKey;
867
 
        eap->get_status = eap_peap_get_status;
868
 
        eap->has_reauth_data = eap_peap_has_reauth_data;
869
 
        eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
870
 
        eap->init_for_reauth = eap_peap_init_for_reauth;
871
 
 
872
 
        ret = eap_peer_method_register(eap);
873
 
        if (ret)
874
 
                eap_peer_method_free(eap);
875
 
        return ret;
876
 
}