Import wpa_supplicant 0.5.8
[dragonfly.git] / contrib / wpa_supplicant-0.5.8 / 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
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 }