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