2 * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt)
3 * Copyright (c) 2004-2007, 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.
20 #include "eap_tls_common.h"
24 /* Maximum supported PEAP version
25 * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
26 * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
27 * 2 = draft-josefsson-ppext-eap-tls-eap-07.txt
29 #define EAP_PEAP_VERSION 1
32 static void eap_peap_reset(struct eap_sm
*sm
, void *priv
);
35 struct eap_peap_data
{
36 struct eap_ssl_data ssl
;
38 START
, PHASE1
, PHASE2_START
, PHASE2_ID
, PHASE2_METHOD
,
39 PHASE2_TLV
, SUCCESS_REQ
, FAILURE_REQ
, SUCCESS
, FAILURE
43 const struct eap_method
*phase2_method
;
49 static const char * eap_peap_state_txt(int state
)
57 return "PHASE2_START";
61 return "PHASE2_METHOD";
78 static void eap_peap_state(struct eap_peap_data
*data
, int state
)
80 wpa_printf(MSG_DEBUG
, "EAP-PEAP: %s -> %s",
81 eap_peap_state_txt(data
->state
),
82 eap_peap_state_txt(state
));
87 static EapType
eap_peap_req_success(struct eap_sm
*sm
,
88 struct eap_peap_data
*data
)
90 if (data
->state
== FAILURE
|| data
->state
== FAILURE_REQ
) {
91 eap_peap_state(data
, FAILURE
);
95 if (data
->peap_version
== 0) {
96 sm
->tlv_request
= TLV_REQ_SUCCESS
;
97 eap_peap_state(data
, PHASE2_TLV
);
100 eap_peap_state(data
, SUCCESS_REQ
);
101 return EAP_TYPE_NONE
;
106 static EapType
eap_peap_req_failure(struct eap_sm
*sm
,
107 struct eap_peap_data
*data
)
109 if (data
->state
== FAILURE
|| data
->state
== FAILURE_REQ
||
110 data
->state
== SUCCESS_REQ
||
111 (data
->phase2_method
&&
112 data
->phase2_method
->method
== EAP_TYPE_TLV
)) {
113 eap_peap_state(data
, FAILURE
);
114 return EAP_TYPE_NONE
;
117 if (data
->peap_version
== 0) {
118 sm
->tlv_request
= TLV_REQ_FAILURE
;
119 eap_peap_state(data
, PHASE2_TLV
);
122 eap_peap_state(data
, FAILURE_REQ
);
123 return EAP_TYPE_NONE
;
128 static void * eap_peap_init(struct eap_sm
*sm
)
130 struct eap_peap_data
*data
;
132 data
= wpa_zalloc(sizeof(*data
));
135 data
->peap_version
= EAP_PEAP_VERSION
;
136 data
->force_version
= -1;
137 if (sm
->user
&& sm
->user
->force_version
>= 0) {
138 data
->force_version
= sm
->user
->force_version
;
139 wpa_printf(MSG_DEBUG
, "EAP-PEAP: forcing version %d",
140 data
->force_version
);
141 data
->peap_version
= data
->force_version
;
145 if (eap_tls_ssl_init(sm
, &data
->ssl
, 0)) {
146 wpa_printf(MSG_INFO
, "EAP-PEAP: Failed to initialize SSL.");
147 eap_peap_reset(sm
, data
);
155 static void eap_peap_reset(struct eap_sm
*sm
, void *priv
)
157 struct eap_peap_data
*data
= priv
;
160 if (data
->phase2_priv
&& data
->phase2_method
)
161 data
->phase2_method
->reset(sm
, data
->phase2_priv
);
162 eap_tls_ssl_deinit(sm
, &data
->ssl
);
167 static u8
* eap_peap_build_start(struct eap_sm
*sm
, struct eap_peap_data
*data
,
168 int id
, size_t *reqDataLen
)
173 *reqDataLen
= sizeof(*req
) + 2;
174 req
= malloc(*reqDataLen
);
176 wpa_printf(MSG_ERROR
, "EAP-PEAP: Failed to allocate memory for"
178 eap_peap_state(data
, FAILURE
);
182 req
->code
= EAP_CODE_REQUEST
;
183 req
->identifier
= id
;
184 req
->length
= htons(*reqDataLen
);
185 pos
= (u8
*) (req
+ 1);
186 *pos
++ = EAP_TYPE_PEAP
;
187 *pos
= EAP_TLS_FLAGS_START
| data
->peap_version
;
189 eap_peap_state(data
, PHASE1
);
195 static u8
* eap_peap_build_req(struct eap_sm
*sm
, struct eap_peap_data
*data
,
196 int id
, size_t *reqDataLen
)
201 res
= eap_tls_buildReq_helper(sm
, &data
->ssl
, EAP_TYPE_PEAP
,
202 data
->peap_version
, id
, &req
,
205 if (tls_connection_established(sm
->ssl_ctx
, data
->ssl
.conn
)) {
206 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Phase1 done, starting "
208 eap_peap_state(data
, PHASE2_START
);
212 return eap_tls_build_ack(reqDataLen
, id
, EAP_TYPE_PEAP
,
218 static u8
* eap_peap_encrypt(struct eap_sm
*sm
, struct eap_peap_data
*data
,
219 int id
, u8
*plain
, size_t plain_len
,
226 /* TODO: add support for fragmentation, if needed. This will need to
227 * add TLS Message Length field, if the frame is fragmented. */
228 req
= malloc(sizeof(struct eap_hdr
) + 2 + data
->ssl
.tls_out_limit
);
232 req
->code
= EAP_CODE_REQUEST
;
233 req
->identifier
= id
;
235 pos
= (u8
*) (req
+ 1);
236 *pos
++ = EAP_TYPE_PEAP
;
237 *pos
++ = data
->peap_version
;
239 res
= tls_connection_encrypt(sm
->ssl_ctx
, data
->ssl
.conn
,
241 pos
, data
->ssl
.tls_out_limit
);
243 wpa_printf(MSG_INFO
, "EAP-PEAP: Failed to encrypt Phase 2 "
249 *out_len
= sizeof(struct eap_hdr
) + 2 + res
;
250 req
->length
= host_to_be16(*out_len
);
255 static u8
* eap_peap_build_phase2_req(struct eap_sm
*sm
,
256 struct eap_peap_data
*data
,
257 int id
, size_t *reqDataLen
)
259 u8
*req
, *buf
, *encr_req
;
262 buf
= req
= data
->phase2_method
->buildReq(sm
, data
->phase2_priv
, id
,
267 wpa_hexdump_key(MSG_DEBUG
, "EAP-PEAP: Encrypting Phase 2 data",
270 if (data
->peap_version
== 0 &&
271 data
->phase2_method
->method
!= EAP_TYPE_TLV
) {
272 req
+= sizeof(struct eap_hdr
);
273 req_len
-= sizeof(struct eap_hdr
);
276 encr_req
= eap_peap_encrypt(sm
, data
, id
, req
, req_len
, reqDataLen
);
283 static u8
* eap_peap_build_phase2_term(struct eap_sm
*sm
,
284 struct eap_peap_data
*data
,
285 int id
, size_t *reqDataLen
, int success
)
291 req_len
= sizeof(*hdr
);
292 hdr
= wpa_zalloc(req_len
);
296 hdr
->code
= success
? EAP_CODE_SUCCESS
: EAP_CODE_FAILURE
;
297 hdr
->identifier
= id
;
298 hdr
->length
= htons(req_len
);
300 wpa_hexdump_key(MSG_DEBUG
, "EAP-PEAP: Encrypting Phase 2 data",
301 (u8
*) hdr
, req_len
);
303 encr_req
= eap_peap_encrypt(sm
, data
, id
, (u8
*) hdr
, req_len
,
311 static u8
* eap_peap_buildReq(struct eap_sm
*sm
, void *priv
, int id
,
314 struct eap_peap_data
*data
= priv
;
316 switch (data
->state
) {
318 return eap_peap_build_start(sm
, data
, id
, reqDataLen
);
320 return eap_peap_build_req(sm
, data
, id
, reqDataLen
);
324 return eap_peap_build_phase2_req(sm
, data
, id
, reqDataLen
);
326 return eap_peap_build_phase2_term(sm
, data
, id
, reqDataLen
, 1);
328 return eap_peap_build_phase2_term(sm
, data
, id
, reqDataLen
, 0);
330 wpa_printf(MSG_DEBUG
, "EAP-PEAP: %s - unexpected state %d",
331 __func__
, data
->state
);
337 static Boolean
eap_peap_check(struct eap_sm
*sm
, void *priv
,
338 u8
*respData
, size_t respDataLen
)
340 struct eap_hdr
*resp
;
343 resp
= (struct eap_hdr
*) respData
;
344 pos
= (u8
*) (resp
+ 1);
345 if (respDataLen
< sizeof(*resp
) + 2 || *pos
!= EAP_TYPE_PEAP
||
346 (ntohs(resp
->length
)) > respDataLen
) {
347 wpa_printf(MSG_INFO
, "EAP-PEAP: Invalid frame");
355 static int eap_peap_phase2_init(struct eap_sm
*sm
, struct eap_peap_data
*data
,
358 if (data
->phase2_priv
&& data
->phase2_method
) {
359 data
->phase2_method
->reset(sm
, data
->phase2_priv
);
360 data
->phase2_method
= NULL
;
361 data
->phase2_priv
= NULL
;
363 data
->phase2_method
= eap_sm_get_eap_methods(EAP_VENDOR_IETF
,
365 if (!data
->phase2_method
)
369 data
->phase2_priv
= data
->phase2_method
->init(sm
);
375 static void eap_peap_process_phase2_response(struct eap_sm
*sm
,
376 struct eap_peap_data
*data
,
377 u8
*in_data
, size_t in_len
)
379 u8 next_type
= EAP_TYPE_NONE
;
384 if (data
->phase2_priv
== NULL
) {
385 wpa_printf(MSG_DEBUG
, "EAP-PEAP: %s - Phase2 not "
386 "initialized?!", __func__
);
390 hdr
= (struct eap_hdr
*) in_data
;
391 pos
= (u8
*) (hdr
+ 1);
393 if (in_len
> sizeof(*hdr
) && *pos
== EAP_TYPE_NAK
) {
394 left
= in_len
- sizeof(*hdr
);
395 wpa_hexdump(MSG_DEBUG
, "EAP-PEAP: Phase2 type Nak'ed; "
396 "allowed types", pos
+ 1, left
- 1);
397 eap_sm_process_nak(sm
, pos
+ 1, left
- 1);
398 if (sm
->user
&& sm
->user_eap_method_index
< EAP_MAX_METHODS
&&
399 sm
->user
->methods
[sm
->user_eap_method_index
].method
!=
401 next_type
= sm
->user
->methods
[
402 sm
->user_eap_method_index
++].method
;
403 wpa_printf(MSG_DEBUG
, "EAP-PEAP: try EAP type %d",
406 next_type
= eap_peap_req_failure(sm
, data
);
408 eap_peap_phase2_init(sm
, data
, next_type
);
412 if (data
->phase2_method
->check(sm
, data
->phase2_priv
, in_data
,
414 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Phase2 check() asked to "
415 "ignore the packet");
419 data
->phase2_method
->process(sm
, data
->phase2_priv
, in_data
, in_len
);
421 if (!data
->phase2_method
->isDone(sm
, data
->phase2_priv
))
425 if (!data
->phase2_method
->isSuccess(sm
, data
->phase2_priv
)) {
426 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Phase2 method failed");
427 next_type
= eap_peap_req_failure(sm
, data
);
428 eap_peap_phase2_init(sm
, data
, next_type
);
432 switch (data
->state
) {
434 if (eap_user_get(sm
, sm
->identity
, sm
->identity_len
, 1) != 0) {
435 wpa_hexdump_ascii(MSG_DEBUG
, "EAP_PEAP: Phase2 "
436 "Identity not found in the user "
438 sm
->identity
, sm
->identity_len
);
439 next_type
= eap_peap_req_failure(sm
, data
);
443 eap_peap_state(data
, PHASE2_METHOD
);
444 next_type
= sm
->user
->methods
[0].method
;
445 sm
->user_eap_method_index
= 1;
446 wpa_printf(MSG_DEBUG
, "EAP-PEAP: try EAP type %d", next_type
);
449 next_type
= eap_peap_req_success(sm
, data
);
452 if (sm
->tlv_request
== TLV_REQ_SUCCESS
||
453 data
->state
== SUCCESS_REQ
) {
454 eap_peap_state(data
, SUCCESS
);
456 eap_peap_state(data
, FAILURE
);
462 wpa_printf(MSG_DEBUG
, "EAP-PEAP: %s - unexpected state %d",
463 __func__
, data
->state
);
467 eap_peap_phase2_init(sm
, data
, next_type
);
471 static void eap_peap_process_phase2(struct eap_sm
*sm
,
472 struct eap_peap_data
*data
,
473 struct eap_hdr
*resp
,
474 u8
*in_data
, size_t in_len
)
477 int len_decrypted
, len
, res
;
481 wpa_printf(MSG_DEBUG
, "EAP-PEAP: received %lu bytes encrypted data for"
482 " Phase 2", (unsigned long) in_len
);
484 res
= eap_tls_data_reassemble(sm
, &data
->ssl
, &in_data
, &in_len
);
485 if (res
< 0 || res
== 1)
489 if (data
->ssl
.tls_in_total
> buf_len
)
490 buf_len
= data
->ssl
.tls_in_total
;
491 in_decrypted
= malloc(buf_len
);
492 if (in_decrypted
== NULL
) {
493 free(data
->ssl
.tls_in
);
494 data
->ssl
.tls_in
= NULL
;
495 data
->ssl
.tls_in_len
= 0;
496 wpa_printf(MSG_WARNING
, "EAP-PEAP: failed to allocate memory "
501 len_decrypted
= tls_connection_decrypt(sm
->ssl_ctx
, data
->ssl
.conn
,
503 in_decrypted
, buf_len
);
504 free(data
->ssl
.tls_in
);
505 data
->ssl
.tls_in
= NULL
;
506 data
->ssl
.tls_in_len
= 0;
507 if (len_decrypted
< 0) {
508 wpa_printf(MSG_INFO
, "EAP-PEAP: Failed to decrypt Phase 2 "
511 eap_peap_state(data
, FAILURE
);
515 wpa_hexdump_key(MSG_DEBUG
, "EAP-PEAP: Decrypted Phase 2 EAP",
516 in_decrypted
, len_decrypted
);
518 hdr
= (struct eap_hdr
*) in_decrypted
;
520 if (data
->peap_version
== 0 && data
->state
!= PHASE2_TLV
) {
521 struct eap_hdr
*nhdr
= malloc(sizeof(struct eap_hdr
) +
527 memcpy((u8
*) (nhdr
+ 1), in_decrypted
, len_decrypted
);
529 nhdr
->code
= resp
->code
;
530 nhdr
->identifier
= resp
->identifier
;
531 nhdr
->length
= host_to_be16(sizeof(struct eap_hdr
) +
534 len_decrypted
+= sizeof(struct eap_hdr
);
535 in_decrypted
= (u8
*) nhdr
;
537 hdr
= (struct eap_hdr
*) in_decrypted
;
538 if (len_decrypted
< (int) sizeof(*hdr
)) {
540 wpa_printf(MSG_INFO
, "EAP-PEAP: Too short Phase 2 "
541 "EAP frame (len=%d)", len_decrypted
);
542 eap_peap_req_failure(sm
, data
);
545 len
= be_to_host16(hdr
->length
);
546 if (len
> len_decrypted
) {
548 wpa_printf(MSG_INFO
, "EAP-PEAP: Length mismatch in "
549 "Phase 2 EAP frame (len=%d hdr->length=%d)",
551 eap_peap_req_failure(sm
, data
);
554 wpa_printf(MSG_DEBUG
, "EAP-PEAP: received Phase 2: code=%d "
555 "identifier=%d length=%d", hdr
->code
, hdr
->identifier
, len
);
557 case EAP_CODE_RESPONSE
:
558 eap_peap_process_phase2_response(sm
, data
, (u8
*) hdr
, len
);
560 case EAP_CODE_SUCCESS
:
561 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Phase 2 Success");
562 if (data
->state
== SUCCESS_REQ
) {
563 eap_peap_state(data
, SUCCESS
);
566 case EAP_CODE_FAILURE
:
567 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Phase 2 Failure");
568 eap_peap_state(data
, FAILURE
);
571 wpa_printf(MSG_INFO
, "EAP-PEAP: Unexpected code=%d in "
572 "Phase 2 EAP header", hdr
->code
);
580 static void eap_peap_process(struct eap_sm
*sm
, void *priv
,
581 u8
*respData
, size_t respDataLen
)
583 struct eap_peap_data
*data
= priv
;
584 struct eap_hdr
*resp
;
587 unsigned int tls_msg_len
;
590 resp
= (struct eap_hdr
*) respData
;
591 pos
= (u8
*) (resp
+ 1);
594 left
= htons(resp
->length
) - sizeof(struct eap_hdr
) - 2;
595 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Received packet(len=%lu) - "
596 "Flags 0x%02x", (unsigned long) respDataLen
, flags
);
597 peer_version
= flags
& EAP_PEAP_VERSION_MASK
;
598 if (data
->force_version
>= 0 && peer_version
!= data
->force_version
) {
599 wpa_printf(MSG_INFO
, "EAP-PEAP: peer did not select the forced"
600 " version (forced=%d peer=%d) - reject",
601 data
->force_version
, peer_version
);
602 eap_peap_state(data
, FAILURE
);
605 if (peer_version
< data
->peap_version
) {
606 wpa_printf(MSG_DEBUG
, "EAP-PEAP: peer ver=%d, own ver=%d; "
608 peer_version
, data
->peap_version
, peer_version
);
609 data
->peap_version
= peer_version
;
611 if (flags
& EAP_TLS_FLAGS_LENGTH_INCLUDED
) {
613 wpa_printf(MSG_INFO
, "EAP-PEAP: Short frame with TLS "
615 eap_peap_state(data
, FAILURE
);
618 tls_msg_len
= (pos
[0] << 24) | (pos
[1] << 16) | (pos
[2] << 8) |
620 wpa_printf(MSG_DEBUG
, "EAP-PEAP: TLS Message Length: %d",
622 if (data
->ssl
.tls_in_left
== 0) {
623 data
->ssl
.tls_in_total
= tls_msg_len
;
624 data
->ssl
.tls_in_left
= tls_msg_len
;
625 free(data
->ssl
.tls_in
);
626 data
->ssl
.tls_in
= NULL
;
627 data
->ssl
.tls_in_len
= 0;
633 switch (data
->state
) {
635 if (eap_tls_process_helper(sm
, &data
->ssl
, pos
, left
) < 0) {
636 wpa_printf(MSG_INFO
, "EAP-PEAP: TLS processing "
638 eap_peap_state(data
, FAILURE
);
642 eap_peap_state(data
, PHASE2_ID
);
643 eap_peap_phase2_init(sm
, data
, EAP_TYPE_IDENTITY
);
648 eap_peap_process_phase2(sm
, data
, resp
, pos
, left
);
651 eap_peap_state(data
, SUCCESS
);
654 eap_peap_state(data
, FAILURE
);
657 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Unexpected state %d in %s",
658 data
->state
, __func__
);
662 if (tls_connection_get_write_alerts(sm
->ssl_ctx
, data
->ssl
.conn
) > 1) {
663 wpa_printf(MSG_INFO
, "EAP-PEAP: Locally detected fatal error "
664 "in TLS processing");
665 eap_peap_state(data
, FAILURE
);
670 static Boolean
eap_peap_isDone(struct eap_sm
*sm
, void *priv
)
672 struct eap_peap_data
*data
= priv
;
673 return data
->state
== SUCCESS
|| data
->state
== FAILURE
;
677 static u8
* eap_peap_getKey(struct eap_sm
*sm
, void *priv
, size_t *len
)
679 struct eap_peap_data
*data
= priv
;
682 if (data
->state
!= SUCCESS
)
685 /* TODO: PEAPv1 - different label in some cases */
686 eapKeyData
= eap_tls_derive_key(sm
, &data
->ssl
,
687 "client EAP encryption",
690 *len
= EAP_TLS_KEY_LEN
;
691 wpa_hexdump(MSG_DEBUG
, "EAP-PEAP: Derived key",
692 eapKeyData
, EAP_TLS_KEY_LEN
);
694 wpa_printf(MSG_DEBUG
, "EAP-PEAP: Failed to derive key");
701 static Boolean
eap_peap_isSuccess(struct eap_sm
*sm
, void *priv
)
703 struct eap_peap_data
*data
= priv
;
704 return data
->state
== SUCCESS
;
708 int eap_server_peap_register(void)
710 struct eap_method
*eap
;
713 eap
= eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION
,
714 EAP_VENDOR_IETF
, EAP_TYPE_PEAP
, "PEAP");
718 eap
->init
= eap_peap_init
;
719 eap
->reset
= eap_peap_reset
;
720 eap
->buildReq
= eap_peap_buildReq
;
721 eap
->check
= eap_peap_check
;
722 eap
->process
= eap_peap_process
;
723 eap
->isDone
= eap_peap_isDone
;
724 eap
->getKey
= eap_peap_getKey
;
725 eap
->isSuccess
= eap_peap_isSuccess
;
727 ret
= eap_server_method_register(eap
);
729 eap_server_method_free(eap
);