2 * hostapd / 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.
18 #include <netinet/in.h>
23 #include "eap_tls_common.h"
27 /* Maximum supported PEAP version
28 * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
29 * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
30 * 2 = draft-josefsson-ppext-eap-tls-eap-07.txt
32 #define EAP_PEAP_VERSION 1
35 static void eap_peap_reset(struct eap_sm
*sm
, void *priv
);
38 struct eap_peap_data
{
39 struct eap_ssl_data ssl
;
41 START
, PHASE1
, PHASE2_START
, PHASE2_ID
, PHASE2_METHOD
,
42 PHASE2_TLV
, SUCCESS_REQ
, FAILURE_REQ
, SUCCESS
, FAILURE
46 const struct eap_method
*phase2_method
;
52 static const char * eap_peap_state_txt(int state
)
60 return "PHASE2_START";
64 return "PHASE2_METHOD";
81 static void eap_peap_state(struct eap_peap_data
*data
, int state
)
83 wpa_printf(MSG_DEBUG
, "EAP-PEAP: %s -> %s",
84 eap_peap_state_txt(data
->state
),
85 eap_peap_state_txt(state
));
90 static EapType
eap_peap_req_success(struct eap_sm
*sm
,
91 struct eap_peap_data
*data
)
93 if (data
->state
== FAILURE
|| data
->state
== FAILURE_REQ
) {
94 eap_peap_state(data
, FAILURE
);
98 if (data
->peap_version
== 0) {
99 sm
->tlv_request
= TLV_REQ_SUCCESS
;
100 eap_peap_state(data
, PHASE2_TLV
);
103 eap_peap_state(data
, SUCCESS_REQ
);
104 return EAP_TYPE_NONE
;
109 static EapType
eap_peap_req_failure(struct eap_sm
*sm
,
110 struct eap_peap_data
*data
)
112 if (data
->state
== FAILURE
|| data
->state
== FAILURE_REQ
||
113 data
->state
== SUCCESS_REQ
||
114 (data
->phase2_method
&&
115 data
->phase2_method
->method
== EAP_TYPE_TLV
)) {
116 eap_peap_state(data
, FAILURE
);
117 return EAP_TYPE_NONE
;
120 if (data
->peap_version
== 0) {
121 sm
->tlv_request
= TLV_REQ_FAILURE
;
122 eap_peap_state(data
, PHASE2_TLV
);
125 eap_peap_state(data
, FAILURE_REQ
);
126 return EAP_TYPE_NONE
;
131 static void * eap_peap_init(struct eap_sm
*sm
)
133 struct eap_peap_data
*data
;
135 data
= malloc(sizeof(*data
));
138 memset(data
, 0, sizeof(*data
));
139 data
->peap_version
= EAP_PEAP_VERSION
;
140 data
->force_version
= -1;
141 if (sm
->user
&& sm
->user
->force_version
>= 0) {
142 data
->force_version
= sm
->user
->force_version
;
143 wpa_printf(MSG_DEBUG
, "EAP-PEAP: forcing version %d",
144 data
->force_version
);
145 data
->peap_version
= data
->force_version
;
149 if (eap_tls_ssl_init(sm
, &data
->ssl
, 0)) {
150 wpa_printf(MSG_INFO
, "EAP-PEAP: Failed to initialize SSL.");
151 eap_peap_reset(sm
, data
);
159 static void eap_peap_reset(struct eap_sm
*sm
, void *priv
)
161 struct eap_peap_data
*data
= priv
;
164 if (data
->phase2_priv
&& data
->phase2_method
)
165 data
->phase2_method
->reset(sm
, data
->phase2_priv
);
166 eap_tls_ssl_deinit(sm
, &data
->ssl
);
171 static u8
* eap_peap_build_start(struct eap_sm
*sm
, struct eap_peap_data
*data
,
172 int id
, size_t *reqDataLen
)
177 *reqDataLen
= sizeof(*req
) + 2;
178 req
= malloc(*reqDataLen
);
180 wpa_printf(MSG_ERROR
, "EAP-PEAP: Failed to allocate memory for"
182 eap_peap_state(data
, FAILURE
);
186 req
->code
= EAP_CODE_REQUEST
;
187 req
->identifier
= id
;
188 req
->length
= htons(*reqDataLen
);
189 pos
= (u8
*) (req
+ 1);
190 *pos
++ = EAP_TYPE_PEAP
;
191 *pos
= EAP_TLS_FLAGS_START
| data
->peap_version
;
193 eap_peap_state(data
, PHASE1
);
199 static u8
* eap_peap_build_req(struct eap_sm
*sm
, struct eap_peap_data
*data
,
200 int id
, size_t *reqDataLen
)
205 res
= eap_tls_buildReq_helper(sm
, &data
->ssl
, EAP_TYPE_PEAP
,
206 data
->peap_version
, id
, &req
,
209 if (tls_connection_established(sm
->ssl_ctx
, data
->ssl
.conn
)) {
210 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Phase1 done, starting "
212 eap_peap_state(data
, PHASE2_START
);
216 return eap_tls_build_ack(reqDataLen
, id
, EAP_TYPE_PEAP
,
222 static u8
* eap_peap_encrypt(struct eap_sm
*sm
, struct eap_peap_data
*data
,
223 int id
, u8
*plain
, size_t plain_len
,
230 /* TODO: add support for fragmentation, if needed. This will need to
231 * add TLS Message Length field, if the frame is fragmented. */
232 req
= malloc(sizeof(struct eap_hdr
) + 2 + data
->ssl
.tls_out_limit
);
236 req
->code
= EAP_CODE_REQUEST
;
237 req
->identifier
= id
;
239 pos
= (u8
*) (req
+ 1);
240 *pos
++ = EAP_TYPE_PEAP
;
241 *pos
++ = data
->peap_version
;
243 res
= tls_connection_encrypt(sm
->ssl_ctx
, data
->ssl
.conn
,
245 pos
, data
->ssl
.tls_out_limit
);
247 wpa_printf(MSG_INFO
, "EAP-PEAP: Failed to encrypt Phase 2 "
253 *out_len
= sizeof(struct eap_hdr
) + 2 + res
;
254 req
->length
= host_to_be16(*out_len
);
259 static u8
* eap_peap_build_phase2_req(struct eap_sm
*sm
,
260 struct eap_peap_data
*data
,
261 int id
, size_t *reqDataLen
)
263 u8
*req
, *buf
, *encr_req
;
266 buf
= req
= data
->phase2_method
->buildReq(sm
, data
->phase2_priv
, id
,
271 wpa_hexdump_key(MSG_DEBUG
, "EAP-PEAP: Encrypting Phase 2 data",
274 if (data
->peap_version
== 0 &&
275 data
->phase2_method
->method
!= EAP_TYPE_TLV
) {
276 req
+= sizeof(struct eap_hdr
);
277 req_len
-= sizeof(struct eap_hdr
);
280 encr_req
= eap_peap_encrypt(sm
, data
, id
, req
, req_len
, reqDataLen
);
287 static u8
* eap_peap_build_phase2_term(struct eap_sm
*sm
,
288 struct eap_peap_data
*data
,
289 int id
, size_t *reqDataLen
, int success
)
295 req_len
= sizeof(*hdr
);
296 hdr
= malloc(req_len
);
301 memset(hdr
, 0, req_len
);
302 hdr
->code
= success
? EAP_CODE_SUCCESS
: EAP_CODE_FAILURE
;
303 hdr
->identifier
= id
;
304 hdr
->length
= htons(req_len
);
306 wpa_hexdump_key(MSG_DEBUG
, "EAP-PEAP: Encrypting Phase 2 data",
307 (u8
*) hdr
, req_len
);
309 encr_req
= eap_peap_encrypt(sm
, data
, id
, (u8
*) hdr
, req_len
,
317 static u8
* eap_peap_buildReq(struct eap_sm
*sm
, void *priv
, int id
,
320 struct eap_peap_data
*data
= priv
;
322 switch (data
->state
) {
324 return eap_peap_build_start(sm
, data
, id
, reqDataLen
);
326 return eap_peap_build_req(sm
, data
, id
, reqDataLen
);
330 return eap_peap_build_phase2_req(sm
, data
, id
, reqDataLen
);
332 return eap_peap_build_phase2_term(sm
, data
, id
, reqDataLen
, 1);
334 return eap_peap_build_phase2_term(sm
, data
, id
, reqDataLen
, 0);
336 wpa_printf(MSG_DEBUG
, "EAP-PEAP: %s - unexpected state %d",
337 __func__
, data
->state
);
343 static Boolean
eap_peap_check(struct eap_sm
*sm
, void *priv
,
344 u8
*respData
, size_t respDataLen
)
346 struct eap_hdr
*resp
;
350 resp
= (struct eap_hdr
*) respData
;
351 pos
= (u8
*) (resp
+ 1);
352 if (respDataLen
< sizeof(*resp
) + 2 || *pos
!= EAP_TYPE_PEAP
||
353 (len
= ntohs(resp
->length
)) > respDataLen
) {
354 wpa_printf(MSG_INFO
, "EAP-PEAP: Invalid frame");
362 static int eap_peap_phase2_init(struct eap_sm
*sm
, struct eap_peap_data
*data
,
365 if (data
->phase2_priv
&& data
->phase2_method
) {
366 data
->phase2_method
->reset(sm
, data
->phase2_priv
);
367 data
->phase2_method
= NULL
;
368 data
->phase2_priv
= NULL
;
370 data
->phase2_method
= eap_sm_get_eap_methods(eap_type
);
371 if (!data
->phase2_method
)
375 data
->phase2_priv
= data
->phase2_method
->init(sm
);
381 static void eap_peap_process_phase2_response(struct eap_sm
*sm
,
382 struct eap_peap_data
*data
,
383 u8
*in_data
, size_t in_len
)
385 u8 next_type
= EAP_TYPE_NONE
;
390 if (data
->phase2_priv
== NULL
) {
391 wpa_printf(MSG_DEBUG
, "EAP-PEAP: %s - Phase2 not "
392 "initialized?!", __func__
);
396 hdr
= (struct eap_hdr
*) in_data
;
397 pos
= (u8
*) (hdr
+ 1);
398 left
= in_len
- sizeof(*hdr
);
400 if (in_len
> sizeof(*hdr
) && *pos
== EAP_TYPE_NAK
) {
401 wpa_hexdump(MSG_DEBUG
, "EAP-PEAP: Phase2 type Nak'ed; "
402 "allowed types", pos
+ 1, left
- 1);
403 eap_sm_process_nak(sm
, pos
+ 1, left
- 1);
404 if (sm
->user
&& sm
->user_eap_method_index
< EAP_MAX_METHODS
&&
405 sm
->user
->methods
[sm
->user_eap_method_index
] !=
408 sm
->user
->methods
[sm
->user_eap_method_index
++];
409 wpa_printf(MSG_DEBUG
, "EAP-PEAP: try EAP type %d",
412 next_type
= eap_peap_req_failure(sm
, data
);
414 eap_peap_phase2_init(sm
, data
, next_type
);
418 if (data
->phase2_method
->check(sm
, data
->phase2_priv
, in_data
,
420 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Phase2 check() asked to "
421 "ignore the packet");
425 data
->phase2_method
->process(sm
, data
->phase2_priv
, in_data
, in_len
);
427 if (!data
->phase2_method
->isDone(sm
, data
->phase2_priv
))
431 if (!data
->phase2_method
->isSuccess(sm
, data
->phase2_priv
)) {
432 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Phase2 method failed");
433 next_type
= eap_peap_req_failure(sm
, data
);
434 eap_peap_phase2_init(sm
, data
, next_type
);
438 switch (data
->state
) {
440 if (eap_user_get(sm
, sm
->identity
, sm
->identity_len
, 1) != 0) {
441 wpa_hexdump_ascii(MSG_DEBUG
, "EAP_PEAP: Phase2 "
442 "Identity not found in the user "
444 sm
->identity
, sm
->identity_len
);
445 next_type
= eap_peap_req_failure(sm
, data
);
449 eap_peap_state(data
, PHASE2_METHOD
);
450 next_type
= sm
->user
->methods
[0];
451 sm
->user_eap_method_index
= 1;
452 wpa_printf(MSG_DEBUG
, "EAP-PEAP: try EAP type %d", next_type
);
455 next_type
= eap_peap_req_success(sm
, data
);
458 if (sm
->tlv_request
== TLV_REQ_SUCCESS
||
459 data
->state
== SUCCESS_REQ
) {
460 eap_peap_state(data
, SUCCESS
);
462 eap_peap_state(data
, FAILURE
);
468 wpa_printf(MSG_DEBUG
, "EAP-PEAP: %s - unexpected state %d",
469 __func__
, data
->state
);
473 eap_peap_phase2_init(sm
, data
, next_type
);
477 static void eap_peap_process_phase2(struct eap_sm
*sm
,
478 struct eap_peap_data
*data
,
479 struct eap_hdr
*resp
,
480 u8
*in_data
, size_t in_len
)
483 int buf_len
, len_decrypted
, len
, res
;
486 wpa_printf(MSG_DEBUG
, "EAP-PEAP: received %lu bytes encrypted data for"
487 " Phase 2", (unsigned long) in_len
);
489 res
= eap_tls_data_reassemble(sm
, &data
->ssl
, &in_data
, &in_len
);
490 if (res
< 0 || res
== 1)
494 if (data
->ssl
.tls_in_total
> buf_len
)
495 buf_len
= data
->ssl
.tls_in_total
;
496 in_decrypted
= malloc(buf_len
);
497 if (in_decrypted
== NULL
) {
498 free(data
->ssl
.tls_in
);
499 data
->ssl
.tls_in
= NULL
;
500 data
->ssl
.tls_in_len
= 0;
501 wpa_printf(MSG_WARNING
, "EAP-PEAP: failed to allocate memory "
506 len_decrypted
= tls_connection_decrypt(sm
->ssl_ctx
, data
->ssl
.conn
,
508 in_decrypted
, buf_len
);
509 free(data
->ssl
.tls_in
);
510 data
->ssl
.tls_in
= NULL
;
511 data
->ssl
.tls_in_len
= 0;
512 if (len_decrypted
< 0) {
513 wpa_printf(MSG_INFO
, "EAP-PEAP: Failed to decrypt Phase 2 "
516 eap_peap_state(data
, FAILURE
);
520 wpa_hexdump_key(MSG_DEBUG
, "EAP-PEAP: Decrypted Phase 2 EAP",
521 in_decrypted
, len_decrypted
);
523 hdr
= (struct eap_hdr
*) in_decrypted
;
525 if (data
->peap_version
== 0 && data
->state
!= PHASE2_TLV
) {
526 struct eap_hdr
*nhdr
= malloc(sizeof(struct eap_hdr
) +
532 memcpy((u8
*) (nhdr
+ 1), in_decrypted
, len_decrypted
);
534 nhdr
->code
= resp
->code
;
535 nhdr
->identifier
= resp
->identifier
;
536 nhdr
->length
= host_to_be16(sizeof(struct eap_hdr
) +
539 len_decrypted
+= sizeof(struct eap_hdr
);
540 in_decrypted
= (u8
*) nhdr
;
542 hdr
= (struct eap_hdr
*) in_decrypted
;
543 if (len_decrypted
< sizeof(*hdr
)) {
545 wpa_printf(MSG_INFO
, "EAP-PEAP: Too short Phase 2 "
546 "EAP frame (len=%d)", len_decrypted
);
547 eap_peap_req_failure(sm
, data
);
550 len
= be_to_host16(hdr
->length
);
551 if (len
> len_decrypted
) {
553 wpa_printf(MSG_INFO
, "EAP-PEAP: Length mismatch in "
554 "Phase 2 EAP frame (len=%d hdr->length=%d)",
556 eap_peap_req_failure(sm
, data
);
559 wpa_printf(MSG_DEBUG
, "EAP-PEAP: received Phase 2: code=%d "
560 "identifier=%d length=%d", hdr
->code
, hdr
->identifier
, len
);
562 case EAP_CODE_RESPONSE
:
563 eap_peap_process_phase2_response(sm
, data
, (u8
*) hdr
, len
);
565 case EAP_CODE_SUCCESS
:
566 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Phase 2 Success");
567 if (data
->state
== SUCCESS_REQ
) {
568 eap_peap_state(data
, SUCCESS
);
571 case EAP_CODE_FAILURE
:
572 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Phase 2 Failure");
573 eap_peap_state(data
, FAILURE
);
576 wpa_printf(MSG_INFO
, "EAP-PEAP: Unexpected code=%d in "
577 "Phase 2 EAP header", hdr
->code
);
585 static void eap_peap_process(struct eap_sm
*sm
, void *priv
,
586 u8
*respData
, size_t respDataLen
)
588 struct eap_peap_data
*data
= priv
;
589 struct eap_hdr
*resp
;
592 unsigned int tls_msg_len
;
595 resp
= (struct eap_hdr
*) respData
;
596 pos
= (u8
*) (resp
+ 1);
599 left
= htons(resp
->length
) - sizeof(struct eap_hdr
) - 2;
600 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Received packet(len=%lu) - "
601 "Flags 0x%02x", (unsigned long) respDataLen
, flags
);
602 peer_version
= flags
& EAP_PEAP_VERSION_MASK
;
603 if (data
->force_version
>= 0 && peer_version
!= data
->force_version
) {
604 wpa_printf(MSG_INFO
, "EAP-PEAP: peer did not select the forced"
605 " version (forced=%d peer=%d) - reject",
606 data
->force_version
, peer_version
);
607 eap_peap_state(data
, FAILURE
);
610 if (peer_version
< data
->peap_version
) {
611 wpa_printf(MSG_DEBUG
, "EAP-PEAP: peer ver=%d, own ver=%d; "
613 peer_version
, data
->peap_version
, peer_version
);
614 data
->peap_version
= peer_version
;
617 if (flags
& EAP_TLS_FLAGS_LENGTH_INCLUDED
) {
619 wpa_printf(MSG_INFO
, "EAP-PEAP: Short frame with TLS "
621 eap_peap_state(data
, FAILURE
);
624 tls_msg_len
= (pos
[0] << 24) | (pos
[1] << 16) | (pos
[2] << 8) |
626 wpa_printf(MSG_DEBUG
, "EAP-PEAP: TLS Message Length: %d",
628 if (data
->ssl
.tls_in_left
== 0) {
629 data
->ssl
.tls_in_total
= tls_msg_len
;
630 data
->ssl
.tls_in_left
= tls_msg_len
;
631 free(data
->ssl
.tls_in
);
632 data
->ssl
.tls_in
= NULL
;
633 data
->ssl
.tls_in_len
= 0;
639 switch (data
->state
) {
641 if (eap_tls_process_helper(sm
, &data
->ssl
, pos
, left
) < 0) {
642 wpa_printf(MSG_INFO
, "EAP-PEAP: TLS processing "
644 eap_peap_state(data
, FAILURE
);
648 eap_peap_state(data
, PHASE2_ID
);
649 eap_peap_phase2_init(sm
, data
, EAP_TYPE_IDENTITY
);
654 eap_peap_process_phase2(sm
, data
, resp
, pos
, left
);
657 eap_peap_state(data
, SUCCESS
);
660 eap_peap_state(data
, FAILURE
);
663 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Unexpected state %d in %s",
664 data
->state
, __func__
);
668 if (tls_connection_get_write_alerts(sm
->ssl_ctx
, data
->ssl
.conn
) > 1) {
669 wpa_printf(MSG_INFO
, "EAP-PEAP: Locally detected fatal error "
670 "in TLS processing");
671 eap_peap_state(data
, FAILURE
);
676 static Boolean
eap_peap_isDone(struct eap_sm
*sm
, void *priv
)
678 struct eap_peap_data
*data
= priv
;
679 return data
->state
== SUCCESS
|| data
->state
== FAILURE
;
683 static u8
* eap_peap_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
685 struct eap_peap_data
*data
= priv
;
688 if (data
->state
!= SUCCESS
)
691 /* TODO: PEAPv1 - different label in some cases */
692 eapKeyData
= eap_tls_derive_key(sm
, &data
->ssl
,
693 "client EAP encryption",
696 *len
= EAP_TLS_KEY_LEN
;
697 wpa_hexdump(MSG_DEBUG
, "EAP-PEAP: Derived key",
698 eapKeyData
, EAP_TLS_KEY_LEN
);
700 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Failed to derive key");
707 static Boolean
eap_peap_isSuccess(struct eap_sm
*sm
, void *priv
)
709 struct eap_peap_data
*data
= priv
;
710 return data
->state
== SUCCESS
;
714 const struct eap_method eap_method_peap
=
716 .method
= EAP_TYPE_PEAP
,
718 .init
= eap_peap_init
,
719 .reset
= eap_peap_reset
,
720 .buildReq
= eap_peap_buildReq
,
721 .check
= eap_peap_check
,
722 .process
= eap_peap_process
,
723 .isDone
= eap_peap_isDone
,
724 .getKey
= eap_peap_getKey
,
725 .isSuccess
= eap_peap_isSuccess
,