2 * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt)
3 * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
19 #include "eap_tls_common.h"
20 #include "config_ssid.h"
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
30 #define EAP_PEAP_VERSION 1
33 static void eap_peap_deinit(struct eap_sm *sm, void *priv);
36 struct eap_peap_data {
37 struct eap_ssl_data ssl;
39 int peap_version, force_peap_version, force_new_label;
41 const struct eap_method *phase2_method;
44 int phase2_eap_success;
45 int phase2_eap_started;
47 struct eap_method_type phase2_type;
48 struct eap_method_type *phase2_types;
49 size_t num_phase2_types;
51 int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
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 */
62 u8 *pending_phase2_req;
63 size_t pending_phase2_req_len;
67 static void * eap_peap_init(struct eap_sm *sm)
69 struct eap_peap_data *data;
70 struct wpa_ssid *config = eap_get_config(sm);
72 data = os_zalloc(sizeof(*data));
75 sm->peap_done = FALSE;
76 data->peap_version = EAP_PEAP_VERSION;
77 data->force_peap_version = -1;
78 data->peap_outer_success = 2;
80 if (config && config->phase1) {
81 char *pos = os_strstr(config->phase1, "peapver=");
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);
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 "
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 "
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");
111 if (config && config->phase2) {
112 char *start, *pos, *buf;
113 struct eap_method_type *methods = NULL, *_methods;
115 size_t num_methods = 0;
116 start = buf = os_strdup(config->phase2);
118 eap_peap_deinit(sm, data);
121 while (start && *start != '\0') {
123 pos = os_strstr(start, "auth=");
126 if (start != pos && *(pos - 1) != ' ') {
132 pos = os_strchr(start, ' ');
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);
142 _methods = os_realloc(
144 num_methods * sizeof(*methods));
145 if (_methods == NULL) {
148 eap_peap_deinit(sm, data);
152 methods[num_methods - 1].vendor = vendor;
153 methods[num_methods - 1].method = method;
159 data->phase2_types = methods;
160 data->num_phase2_types = num_methods;
162 if (data->phase2_types == NULL) {
164 eap_get_phase2_types(config, &data->num_phase2_types);
166 if (data->phase2_types == NULL) {
167 wpa_printf(MSG_ERROR, "EAP-PEAP: No Phase2 method available");
168 eap_peap_deinit(sm, data);
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;
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);
187 static void eap_peap_deinit(struct eap_sm *sm, void *priv)
189 struct eap_peap_data *data = priv;
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);
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)
208 struct eap_hdr *resp;
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
214 resp = os_malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
218 resp->code = EAP_CODE_RESPONSE;
219 resp->identifier = id;
221 pos = (u8 *) (resp + 1);
222 *pos++ = EAP_TYPE_PEAP;
223 *pos++ = data->peap_version;
225 res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
227 pos, data->ssl.tls_out_limit);
229 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt Phase 2 "
235 *out_len = sizeof(struct eap_hdr) + 2 + res;
236 resp->length = host_to_be16(*out_len);
237 *out_data = (u8 *) resp;
242 static int eap_peap_phase2_nak(struct eap_peap_data *data, struct eap_hdr *hdr,
243 u8 **resp, size_t *resp_len)
245 struct eap_hdr *resp_hdr;
246 u8 *pos = (u8 *) (hdr + 1);
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);
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) {
268 *pos++ = data->phase2_types[i].method;
271 resp_hdr->length = host_to_be16(*resp_len);
277 static int eap_peap_phase2_request(struct eap_sm *sm,
278 struct eap_peap_data *data,
279 struct eap_method_ret *ret,
281 u8 **resp, size_t *resp_len)
283 size_t len = be_to_host16(hdr->length);
285 struct eap_method_ret iret;
286 struct wpa_ssid *config = eap_get_config(sm);
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);
293 pos = (u8 *) (hdr + 1);
294 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
296 case EAP_TYPE_IDENTITY:
297 *resp = eap_sm_buildIdentity(sm, hdr->identifier, resp_len, 1);
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;
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;
316 if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
317 data->phase2_type.method == EAP_TYPE_NONE) {
319 for (i = 0; i < data->num_phase2_types; i++) {
320 if (data->phase2_types[i].vendor !=
322 data->phase2_types[i].method != *pos)
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);
336 if (*pos != data->phase2_type.method ||
337 *pos == EAP_TYPE_NONE) {
338 if (eap_peap_phase2_nak(data, hdr, resp, resp_len))
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) {
350 data->phase2_method->init(sm);
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;
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,
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;
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;
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)
398 int res, skip_change = 0;
399 struct eap_hdr *hdr, *rhdr;
401 size_t resp_len, len_decrypted, len, buf_len;
406 wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
407 " Phase 2", (unsigned long) in_len);
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;
425 msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len,
426 &msg_len, &need_more_input);
428 return need_more_input ? 1 : -1;
430 if (in_len == 0 && sm->workaround && data->phase2_success) {
432 * Cisco ACS seems to be using TLS ACK to terminate
433 * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
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;
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 "
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;
462 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
464 os_free(in_decrypted);
470 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted,
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 */
481 if (len_decrypted >= 5 && hdr->code == EAP_CODE_REQUEST &&
482 in_decrypted[4] == EAP_TYPE_TLV) {
486 if (data->peap_version == 0 && !skip_change) {
487 struct eap_hdr *nhdr = os_malloc(sizeof(struct eap_hdr) +
490 os_free(in_decrypted);
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) +
500 len_decrypted += sizeof(struct eap_hdr);
501 in_decrypted = (u8 *) nhdr;
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);
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);
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 "
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)",
535 (unsigned long) len_decrypted);
537 hdr->length = host_to_be16(len);
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);
544 case EAP_CODE_REQUEST:
545 if (eap_peap_phase2_request(sm, data, ret, hdr,
547 os_free(in_decrypted);
548 wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
549 "processing failed");
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
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);
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");
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);
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);
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;
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);
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);
619 wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
620 "Phase 2 EAP header", hdr->code);
624 os_free(in_decrypted);
628 size_t resp_send_len;
629 int skip_change2 = 0;
631 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
633 /* PEAP version changes */
634 if (resp_len >= 5 && resp[0] == EAP_CODE_RESPONSE &&
635 resp[4] == EAP_TYPE_TLV)
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);
642 resp_send_len = resp_len;
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 "
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,
663 const struct eap_hdr *req;
668 struct eap_peap_data *data = priv;
670 pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
671 reqData, reqDataLen, &left, &flags);
674 req = (const struct eap_hdr *) reqData;
675 id = req->identifier;
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,
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;
693 wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
695 left = 0; /* make sure that this frame is empty, even though it
696 * should always be, anyway */
700 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
702 res = eap_peap_decrypt(sm, data, ret, req, pos, left,
705 res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_PEAP,
706 data->peap_version, id, pos, left,
709 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
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";
724 label = "client EAP encryption";
725 wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
726 "key derivation", label);
728 eap_tls_derive_key(sm, &data->ssl, label,
730 if (data->key_data) {
731 wpa_hexdump_key(MSG_DEBUG,
732 "EAP-PEAP: Derived key",
736 wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
740 if (sm->workaround && data->resuming) {
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.
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;
763 * Application data included in the handshake message.
765 os_free(data->pending_phase2_req);
766 data->pending_phase2_req = resp;
767 data->pending_phase2_req_len = *respDataLen;
770 res = eap_peap_decrypt(sm, data, ret, req, pos, left,
775 if (ret->methodState == METHOD_DONE) {
776 ret->allowNotifications = FALSE;
780 return eap_tls_build_ack(&data->ssl, respDataLen, id,
781 EAP_TYPE_PEAP, data->peap_version);
788 static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
790 struct eap_peap_data *data = priv;
791 return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
792 data->phase2_success;
796 static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
798 struct eap_peap_data *data = priv;
799 os_free(data->pending_phase2_req);
800 data->pending_phase2_req = NULL;
804 static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
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)) {
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;
820 sm->peap_done = FALSE;
825 static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
826 size_t buflen, int verbose)
828 struct eap_peap_data *data = priv;
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",
836 data->phase2_method->name);
837 if (ret < 0 || (size_t) ret >= buflen - len)
845 static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
847 struct eap_peap_data *data = priv;
848 return data->key_data != NULL && data->phase2_success;
852 static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
854 struct eap_peap_data *data = priv;
857 if (data->key_data == NULL || !data->phase2_success)
860 key = os_malloc(EAP_TLS_KEY_LEN);
864 *len = EAP_TLS_KEY_LEN;
865 os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
871 int eap_peer_peap_register(void)
873 struct eap_method *eap;
876 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
877 EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
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;
891 ret = eap_peer_method_register(eap);
893 eap_peer_method_free(eap);