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,