2 * WPA Supplicant / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt)
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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.
21 #include "eap_tls_common.h"
22 #include "wpa_supplicant.h"
23 #include "config_ssid.h"
28 /* Maximum supported PEAP version
29 * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
30 * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
31 * 2 = draft-josefsson-ppext-eap-tls-eap-07.txt
33 #define EAP_PEAP_VERSION 1
36 static void eap_peap_deinit(struct eap_sm *sm, void *priv);
39 struct eap_peap_data {
40 struct eap_ssl_data ssl;
42 int peap_version, force_peap_version, force_new_label;
44 const struct eap_method *phase2_method;
50 size_t num_phase2_types;
52 int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
54 * 1 = reply with tunneled EAP-Success to inner
55 * EAP-Success and expect AS to send outer
56 * (unencrypted) EAP-Success after this
57 * 2 = reply with PEAP/TLS ACK to inner
58 * EAP-Success and expect AS to send outer
59 * (unencrypted) EAP-Success after this */
60 int resuming; /* starting a resumed session */
63 u8 *pending_phase2_req;
64 size_t pending_phase2_req_len;
68 static void * eap_peap_init(struct eap_sm *sm)
70 struct eap_peap_data *data;
71 struct wpa_ssid *config = eap_get_config(sm);
73 data = malloc(sizeof(*data));
76 sm->peap_done = FALSE;
77 memset(data, 0, sizeof(*data));
78 data->peap_version = EAP_PEAP_VERSION;
79 data->force_peap_version = -1;
80 data->peap_outer_success = 2;
82 if (config && config->phase1) {
83 char *pos = strstr(config->phase1, "peapver=");
85 data->force_peap_version = atoi(pos + 8);
86 data->peap_version = data->force_peap_version;
87 wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version "
88 "%d", data->force_peap_version);
91 if (strstr(config->phase1, "peaplabel=1")) {
92 data->force_new_label = 1;
93 wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for "
97 if (strstr(config->phase1, "peap_outer_success=0")) {
98 data->peap_outer_success = 0;
99 wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate "
100 "authentication on tunneled EAP-Success");
101 } else if (strstr(config->phase1, "peap_outer_success=1")) {
102 data->peap_outer_success = 1;
103 wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled "
104 "EAP-Success after receiving tunneled "
106 } else if (strstr(config->phase1, "peap_outer_success=2")) {
107 data->peap_outer_success = 2;
108 wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK "
109 "after receiving tunneled EAP-Success");
113 if (config && config->phase2) {
114 char *start, *pos, *buf;
115 u8 method, *methods = NULL, *_methods;
116 size_t num_methods = 0;
117 start = buf = strdup(config->phase2);
119 eap_peap_deinit(sm, data);
122 while (start && *start != '\0') {
123 pos = strstr(start, "auth=");
126 if (start != pos && *(pos - 1) != ' ') {
132 pos = strchr(start, ' ');
135 method = eap_get_phase2_type(start);
136 if (method == EAP_TYPE_NONE) {
137 wpa_printf(MSG_ERROR, "EAP-PEAP: Unsupported "
138 "Phase2 method '%s'", start);
141 _methods = realloc(methods, num_methods);
142 if (_methods == NULL) {
144 eap_peap_deinit(sm, data);
148 methods[num_methods - 1] = method;
154 data->phase2_types = methods;
155 data->num_phase2_types = num_methods;
157 if (data->phase2_types == NULL) {
159 eap_get_phase2_types(config, &data->num_phase2_types);
161 if (data->phase2_types == NULL) {
162 wpa_printf(MSG_ERROR, "EAP-PEAP: No Phase2 method available");
163 eap_peap_deinit(sm, data);
166 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 EAP types",
167 data->phase2_types, data->num_phase2_types);
168 data->phase2_type = EAP_TYPE_NONE;
170 if (eap_tls_ssl_init(sm, &data->ssl, config)) {
171 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
172 eap_peap_deinit(sm, data);
180 static void eap_peap_deinit(struct eap_sm *sm, void *priv)
182 struct eap_peap_data *data = priv;
185 if (data->phase2_priv && data->phase2_method)
186 data->phase2_method->deinit(sm, data->phase2_priv);
187 free(data->phase2_types);
188 eap_tls_ssl_deinit(sm, &data->ssl);
189 free(data->key_data);
190 free(data->pending_phase2_req);
195 static int eap_peap_encrypt(struct eap_sm *sm, struct eap_peap_data *data,
196 int id, u8 *plain, size_t plain_len,
197 u8 **out_data, size_t *out_len)
201 struct eap_hdr *resp;
203 /* TODO: add support for fragmentation, if needed. This will need to
204 * add TLS Message Length field, if the frame is fragmented.
205 * Note: Microsoft IAS did not seem to like TLS Message Length with
207 resp = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
211 resp->code = EAP_CODE_RESPONSE;
212 resp->identifier = id;
214 pos = (u8 *) (resp + 1);
215 *pos++ = EAP_TYPE_PEAP;
216 *pos++ = data->peap_version;
218 res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
220 pos, data->ssl.tls_out_limit);
222 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt Phase 2 "
228 *out_len = sizeof(struct eap_hdr) + 2 + res;
229 resp->length = host_to_be16(*out_len);
230 *out_data = (u8 *) resp;
235 static int eap_peap_phase2_nak(struct eap_sm *sm,
236 struct eap_peap_data *data,
238 u8 **resp, size_t *resp_len)
240 struct eap_hdr *resp_hdr;
241 u8 *pos = (u8 *) (hdr + 1);
243 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: Nak type=%d", *pos);
244 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Allowed Phase2 EAP types",
245 data->phase2_types, data->num_phase2_types);
246 *resp_len = sizeof(struct eap_hdr) + 1 + data->num_phase2_types;
247 *resp = malloc(*resp_len);
251 resp_hdr = (struct eap_hdr *) (*resp);
252 resp_hdr->code = EAP_CODE_RESPONSE;
253 resp_hdr->identifier = hdr->identifier;
254 resp_hdr->length = host_to_be16(*resp_len);
255 pos = (u8 *) (resp_hdr + 1);
256 *pos++ = EAP_TYPE_NAK;
257 memcpy(pos, data->phase2_types, data->num_phase2_types);
263 static int eap_peap_phase2_request(struct eap_sm *sm,
264 struct eap_peap_data *data,
265 struct eap_method_ret *ret,
268 u8 **resp, size_t *resp_len)
270 size_t len = be_to_host16(hdr->length);
272 struct eap_method_ret iret;
273 struct wpa_ssid *config = eap_get_config(sm);
275 if (len <= sizeof(struct eap_hdr)) {
276 wpa_printf(MSG_INFO, "EAP-PEAP: too short "
277 "Phase 2 request (len=%lu)", (unsigned long) len);
280 pos = (u8 *) (hdr + 1);
281 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
283 case EAP_TYPE_IDENTITY:
284 *resp = eap_sm_buildIdentity(sm, req->identifier, resp_len, 1);
287 memset(&iret, 0, sizeof(iret));
288 if (eap_tlv_process(sm, &iret, hdr, resp, resp_len)) {
289 ret->methodState = METHOD_DONE;
290 ret->decision = DECISION_FAIL;
293 if (iret.methodState == METHOD_DONE ||
294 iret.methodState == METHOD_MAY_CONT) {
295 ret->methodState = iret.methodState;
296 ret->decision = iret.decision;
297 data->phase2_success = 1;
301 if (data->phase2_type == EAP_TYPE_NONE) {
303 for (i = 0; i < data->num_phase2_types; i++) {
304 if (data->phase2_types[i] != *pos)
307 data->phase2_type = *pos;
308 wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
309 "Phase 2 EAP method %d",
314 if (*pos != data->phase2_type || *pos == EAP_TYPE_NONE) {
315 if (eap_peap_phase2_nak(sm, data, hdr, resp, resp_len))
320 if (data->phase2_priv == NULL) {
321 data->phase2_method = eap_sm_get_eap_methods(*pos);
322 if (data->phase2_method) {
325 data->phase2_method->init(sm);
329 if (data->phase2_priv == NULL || data->phase2_method == NULL) {
330 wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
331 "Phase 2 EAP method %d", *pos);
332 ret->methodState = METHOD_DONE;
333 ret->decision = DECISION_FAIL;
336 memset(&iret, 0, sizeof(iret));
337 *resp = data->phase2_method->process(sm, data->phase2_priv,
338 &iret, (u8 *) hdr, len,
340 if ((iret.methodState == METHOD_DONE ||
341 iret.methodState == METHOD_MAY_CONT) &&
342 (iret.decision == DECISION_UNCOND_SUCC ||
343 iret.decision == DECISION_COND_SUCC)) {
344 data->phase2_success = 1;
350 (config->pending_req_identity || config->pending_req_password ||
351 config->pending_req_otp)) {
352 free(data->pending_phase2_req);
353 data->pending_phase2_req = malloc(len);
354 if (data->pending_phase2_req) {
355 memcpy(data->pending_phase2_req, hdr, len);
356 data->pending_phase2_req_len = len;
364 static int eap_peap_decrypt(struct eap_sm *sm,
365 struct eap_peap_data *data,
366 struct eap_method_ret *ret,
368 u8 *in_data, size_t in_len,
369 u8 **out_data, size_t *out_len)
372 int buf_len, len_decrypted, len, skip_change = 0, res;
373 struct eap_hdr *hdr, *rhdr;
377 wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
378 " Phase 2", (unsigned long) in_len);
380 if (data->pending_phase2_req) {
381 wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
382 "skip decryption and use old data");
383 /* Clear TLS reassembly state. */
384 free(data->ssl.tls_in);
385 data->ssl.tls_in = NULL;
386 data->ssl.tls_in_len = 0;
387 data->ssl.tls_in_left = 0;
388 data->ssl.tls_in_total = 0;
389 in_decrypted = data->pending_phase2_req;
390 data->pending_phase2_req = NULL;
391 len_decrypted = data->pending_phase2_req_len;
396 res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len);
397 if (res < 0 || res == 1)
400 if (in_len == 0 && sm->workaround && data->phase2_success) {
402 * Cisco ACS seems to be using TLS ACK to terminate
403 * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
405 wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
406 "expected data - acknowledge with TLS ACK since "
407 "Phase 2 has been completed");
408 ret->decision = DECISION_COND_SUCC;
409 ret->methodState = METHOD_DONE;
414 if (data->ssl.tls_in_total > buf_len)
415 buf_len = data->ssl.tls_in_total;
416 in_decrypted = malloc(buf_len);
417 if (in_decrypted == NULL) {
418 free(data->ssl.tls_in);
419 data->ssl.tls_in = NULL;
420 data->ssl.tls_in_len = 0;
421 wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory "
426 len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
428 in_decrypted, buf_len);
429 free(data->ssl.tls_in);
430 data->ssl.tls_in = NULL;
431 data->ssl.tls_in_len = 0;
432 if (len_decrypted < 0) {
433 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
440 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted,
443 hdr = (struct eap_hdr *) in_decrypted;
444 if (len_decrypted == 5 && hdr->code == EAP_CODE_REQUEST &&
445 be_to_host16(hdr->length) == 5 &&
446 in_decrypted[4] == EAP_TYPE_IDENTITY) {
447 /* At least FreeRADIUS seems to send full EAP header with
448 * EAP Request Identity */
451 if (len_decrypted >= 5 && hdr->code == EAP_CODE_REQUEST &&
452 in_decrypted[4] == EAP_TYPE_TLV) {
456 if (data->peap_version == 0 && !skip_change) {
457 struct eap_hdr *nhdr = malloc(sizeof(struct eap_hdr) +
463 memcpy((u8 *) (nhdr + 1), in_decrypted, len_decrypted);
465 nhdr->code = req->code;
466 nhdr->identifier = req->identifier;
467 nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
470 len_decrypted += sizeof(struct eap_hdr);
471 in_decrypted = (u8 *) nhdr;
473 hdr = (struct eap_hdr *) in_decrypted;
474 if (len_decrypted < sizeof(*hdr)) {
476 wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
477 "EAP frame (len=%d)", len_decrypted);
480 len = be_to_host16(hdr->length);
481 if (len > len_decrypted) {
483 wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
484 "Phase 2 EAP frame (len=%d hdr->length=%d)",
488 if (len < len_decrypted) {
489 wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
490 "shorter length than full decrypted data (%d < %d)",
492 if (sm->workaround && len == 4 && len_decrypted == 5 &&
493 in_decrypted[4] == EAP_TYPE_IDENTITY) {
494 /* Radiator 3.9 seems to set Phase 2 EAP header to use
495 * incorrect length for the EAP-Request Identity
496 * packet, so fix the inner header to interoperate..
497 * This was fixed in 2004-06-23 patch for Radiator and
498 * this workaround can be removed at some point. */
499 wpa_printf(MSG_INFO, "EAP-PEAP: workaround -> replace "
500 "Phase 2 EAP header len (%d) with real "
501 "decrypted len (%d)", len, len_decrypted);
503 hdr->length = host_to_be16(len);
506 wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
507 "identifier=%d length=%d", hdr->code, hdr->identifier, len);
509 case EAP_CODE_REQUEST:
510 if (eap_peap_phase2_request(sm, data, ret, req, hdr,
513 wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
514 "processing failed");
518 case EAP_CODE_SUCCESS:
519 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
520 if (data->peap_version == 1) {
521 /* EAP-Success within TLS tunnel is used to indicate
522 * shutdown of the TLS channel. The authentication has
524 wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
525 "EAP-Success within TLS tunnel - "
526 "authentication completed");
527 ret->decision = DECISION_UNCOND_SUCC;
528 ret->methodState = METHOD_DONE;
529 data->phase2_success = 1;
530 if (data->peap_outer_success == 2) {
532 wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
533 "to finish authentication");
535 } else if (data->peap_outer_success == 1) {
536 /* Reply with EAP-Success within the TLS
537 * channel to complete the authentication. */
538 resp_len = sizeof(struct eap_hdr);
539 resp = malloc(resp_len);
541 memset(resp, 0, resp_len);
542 rhdr = (struct eap_hdr *) resp;
543 rhdr->code = EAP_CODE_SUCCESS;
544 rhdr->identifier = hdr->identifier;
545 rhdr->length = host_to_be16(resp_len);
548 /* No EAP-Success expected for Phase 1 (outer,
549 * unencrypted auth), so force EAP state
550 * machine to SUCCESS state. */
551 sm->peap_done = TRUE;
557 case EAP_CODE_FAILURE:
558 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
559 ret->decision = DECISION_FAIL;
560 ret->methodState = METHOD_MAY_CONT;
561 ret->allowNotifications = FALSE;
562 /* Reply with EAP-Failure within the TLS channel to complete
563 * failure reporting. */
564 resp_len = sizeof(struct eap_hdr);
565 resp = malloc(resp_len);
567 memset(resp, 0, resp_len);
568 rhdr = (struct eap_hdr *) resp;
569 rhdr->code = EAP_CODE_FAILURE;
570 rhdr->identifier = hdr->identifier;
571 rhdr->length = host_to_be16(resp_len);
575 wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
576 "Phase 2 EAP header", hdr->code);
584 size_t resp_send_len;
587 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
589 /* PEAP version changes */
590 if (resp_len >= 5 && resp[0] == EAP_CODE_RESPONSE &&
591 resp[4] == EAP_TYPE_TLV)
593 if (data->peap_version == 0 && !skip_change) {
594 resp_pos = resp + sizeof(struct eap_hdr);
595 resp_send_len = resp_len - sizeof(struct eap_hdr);
598 resp_send_len = resp_len;
601 if (eap_peap_encrypt(sm, data, req->identifier,
602 resp_pos, resp_send_len,
603 out_data, out_len)) {
604 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
614 static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
615 struct eap_method_ret *ret,
616 u8 *reqData, size_t reqDataLen,
621 unsigned int tls_msg_len;
622 u8 flags, *pos, *resp, id;
623 struct eap_peap_data *data = priv;
625 if (tls_get_errors(sm->ssl_ctx)) {
626 wpa_printf(MSG_INFO, "EAP-PEAP: TLS errors detected");
631 req = (struct eap_hdr *) reqData;
632 pos = (u8 *) (req + 1);
633 if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_PEAP ||
634 (left = be_to_host16(req->length)) > reqDataLen) {
635 wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
639 left -= sizeof(struct eap_hdr);
640 id = req->identifier;
644 wpa_printf(MSG_DEBUG, "EAP-PEAP: Received packet(len=%lu) - "
645 "Flags 0x%02x", (unsigned long) reqDataLen, flags);
646 if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
648 wpa_printf(MSG_INFO, "EAP-PEAP: Short frame with TLS "
653 tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
655 wpa_printf(MSG_DEBUG, "EAP-PEAP: TLS Message Length: %d",
657 if (data->ssl.tls_in_left == 0) {
658 data->ssl.tls_in_total = tls_msg_len;
659 data->ssl.tls_in_left = tls_msg_len;
660 free(data->ssl.tls_in);
661 data->ssl.tls_in = NULL;
662 data->ssl.tls_in_len = 0;
669 ret->methodState = METHOD_CONT;
670 ret->decision = DECISION_FAIL;
671 ret->allowNotifications = TRUE;
673 if (flags & EAP_TLS_FLAGS_START) {
674 wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
675 "ver=%d)", flags & EAP_PEAP_VERSION_MASK,
677 if ((flags & EAP_PEAP_VERSION_MASK) < data->peap_version)
678 data->peap_version = flags & EAP_PEAP_VERSION_MASK;
679 if (data->force_peap_version >= 0 &&
680 data->force_peap_version != data->peap_version) {
681 wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
682 "forced PEAP version %d",
683 data->force_peap_version);
684 ret->methodState = METHOD_DONE;
685 ret->decision = DECISION_FAIL;
686 ret->allowNotifications = FALSE;
689 wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
691 left = 0; /* make sure that this frame is empty, even though it
692 * should always be, anyway */
696 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
698 res = eap_peap_decrypt(sm, data, ret, req, pos, left,
701 res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_PEAP,
702 data->peap_version, id, pos, left,
705 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
707 wpa_printf(MSG_DEBUG,
708 "EAP-PEAP: TLS done, proceed to Phase 2");
709 free(data->key_data);
710 /* draft-josefsson-ppext-eap-tls-eap-05.txt
711 * specifies that PEAPv1 would use "client PEAP
712 * encryption" as the label. However, most existing
713 * PEAPv1 implementations seem to be using the old
714 * label, "client EAP encryption", instead. Use the old
715 * label by default, but allow it to be configured with
716 * phase1 parameter peaplabel=1. */
717 if (data->peap_version > 1 || data->force_new_label)
718 label = "client PEAP encryption";
720 label = "client EAP encryption";
721 wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
722 "key derivation", label);
724 eap_tls_derive_key(sm, &data->ssl, label,
726 if (data->key_data) {
727 wpa_hexdump_key(MSG_DEBUG,
728 "EAP-PEAP: Derived key",
732 wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
736 if (sm->workaround && data->peap_version == 1 &&
739 * At least one RADIUS server (Aegis v1.1.6;
740 * but not v1.1.4) seems to be terminating
741 * PEAPv1 session resumption with outer
742 * EAP-Success. This does not seem to follow
743 * draft-josefsson-pppext-eap-tls-eap-05.txt
744 * section 4.2, so only allow this if EAP
745 * workarounds are enabled.
747 wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
748 "allow outer EAP-Success to "
749 "terminate PEAPv1 resumption");
750 ret->decision = DECISION_COND_SUCC;
751 data->phase2_success = 1;
758 if (ret->methodState == METHOD_DONE) {
759 ret->allowNotifications = FALSE;
763 return eap_tls_build_ack(&data->ssl, respDataLen, id,
764 EAP_TYPE_PEAP, data->peap_version);
771 static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
773 struct eap_peap_data *data = priv;
774 return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
775 data->phase2_success;
779 static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
781 struct eap_peap_data *data = priv;
782 free(data->pending_phase2_req);
783 data->pending_phase2_req = NULL;
787 static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
789 struct eap_peap_data *data = priv;
790 free(data->key_data);
791 data->key_data = NULL;
792 if (eap_tls_reauth_init(sm, &data->ssl)) {
796 data->phase2_success = 0;
798 sm->peap_done = FALSE;
803 static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
804 size_t buflen, int verbose)
806 struct eap_peap_data *data = priv;
809 len = eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
810 if (data->phase2_method) {
811 len += snprintf(buf + len, buflen - len,
812 "EAP-PEAPv%d Phase2 method=%s\n",
813 data->peap_version, data->phase2_method->name);
819 static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
821 struct eap_peap_data *data = priv;
822 return data->key_data != NULL && data->phase2_success;
826 static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
828 struct eap_peap_data *data = priv;
831 if (data->key_data == NULL || !data->phase2_success)
834 key = malloc(EAP_TLS_KEY_LEN);
838 *len = EAP_TLS_KEY_LEN;
839 memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
845 const struct eap_method eap_method_peap =
847 .method = EAP_TYPE_PEAP,
849 .init = eap_peap_init,
850 .deinit = eap_peap_deinit,
851 .process = eap_peap_process,
852 .isKeyAvailable = eap_peap_isKeyAvailable,
853 .getKey = eap_peap_getKey,
854 .get_status = eap_peap_get_status,
855 .has_reauth_data = eap_peap_has_reauth_data,
856 .deinit_for_reauth = eap_peap_deinit_for_reauth,
857 .init_for_reauth = eap_peap_init_for_reauth,