2 * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
12 #include "crypto/sha1.h"
13 #include "crypto/tls.h"
14 #include "crypto/random.h"
16 #include "eap_tls_common.h"
17 #include "eap_common/eap_tlv_common.h"
18 #include "eap_common/eap_peap_common.h"
22 /* Maximum supported PEAP version
23 * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
24 * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
25 * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
27 #define EAP_PEAP_VERSION 1
30 static void eap_peap_reset(struct eap_sm *sm, void *priv);
33 struct eap_peap_data {
34 struct eap_ssl_data ssl;
36 START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID,
37 PHASE2_METHOD, PHASE2_SOH,
38 PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE
43 const struct eap_method *phase2_method;
46 struct wpabuf *pending_phase2_resp;
47 enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
48 int crypto_binding_sent;
49 int crypto_binding_used;
50 enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
55 size_t phase2_key_len;
56 struct wpabuf *soh_response;
60 static const char * eap_peap_state_txt(int state)
70 return "PHASE2_START";
74 return "PHASE2_METHOD";
93 static void eap_peap_state(struct eap_peap_data *data, int state)
95 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s",
96 eap_peap_state_txt(data->state),
97 eap_peap_state_txt(state));
102 static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
105 struct eap_tlv_hdr *tlv;
110 /* Encapsulate EAP packet in EAP-Payload TLV */
111 wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
112 e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
114 wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
115 "for TLV encapsulation");
119 tlv = wpabuf_put(e, sizeof(*tlv));
120 tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
121 EAP_TLV_EAP_PAYLOAD_TLV);
122 tlv->length = host_to_be16(wpabuf_len(buf));
123 wpabuf_put_buf(e, buf);
129 static void eap_peap_req_success(struct eap_sm *sm,
130 struct eap_peap_data *data)
132 if (data->state == FAILURE || data->state == FAILURE_REQ) {
133 eap_peap_state(data, FAILURE);
137 if (data->peap_version == 0) {
138 data->tlv_request = TLV_REQ_SUCCESS;
139 eap_peap_state(data, PHASE2_TLV);
141 eap_peap_state(data, SUCCESS_REQ);
146 static void eap_peap_req_failure(struct eap_sm *sm,
147 struct eap_peap_data *data)
149 if (data->state == FAILURE || data->state == FAILURE_REQ ||
150 data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) {
151 eap_peap_state(data, FAILURE);
155 if (data->peap_version == 0) {
156 data->tlv_request = TLV_REQ_FAILURE;
157 eap_peap_state(data, PHASE2_TLV);
159 eap_peap_state(data, FAILURE_REQ);
164 static void * eap_peap_init(struct eap_sm *sm)
166 struct eap_peap_data *data;
168 data = os_zalloc(sizeof(*data));
171 data->peap_version = EAP_PEAP_VERSION;
172 data->force_version = -1;
173 if (sm->user && sm->user->force_version >= 0) {
174 data->force_version = sm->user->force_version;
175 wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d",
176 data->force_version);
177 data->peap_version = data->force_version;
180 data->crypto_binding = OPTIONAL_BINDING;
182 if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
183 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
184 eap_peap_reset(sm, data);
192 static void eap_peap_reset(struct eap_sm *sm, void *priv)
194 struct eap_peap_data *data = priv;
197 if (data->phase2_priv && data->phase2_method)
198 data->phase2_method->reset(sm, data->phase2_priv);
199 eap_server_tls_ssl_deinit(sm, &data->ssl);
200 wpabuf_free(data->pending_phase2_resp);
201 os_free(data->phase2_key);
202 wpabuf_free(data->soh_response);
207 static struct wpabuf * eap_peap_build_start(struct eap_sm *sm,
208 struct eap_peap_data *data, u8 id)
212 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1,
213 EAP_CODE_REQUEST, id);
215 wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for"
217 eap_peap_state(data, FAILURE);
221 wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version);
223 eap_peap_state(data, PHASE1);
229 static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
230 struct eap_peap_data *data,
233 struct wpabuf *buf, *encr_req, msgbuf;
237 if (data->phase2_method == NULL || data->phase2_priv == NULL) {
238 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready");
241 buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
242 if (data->peap_version >= 2 && buf)
243 buf = eap_peapv2_tlv_eap_payload(buf);
247 req = wpabuf_head(buf);
248 req_len = wpabuf_len(buf);
249 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
252 if (data->peap_version == 0 &&
253 data->phase2_method->method != EAP_TYPE_TLV) {
254 req += sizeof(struct eap_hdr);
255 req_len -= sizeof(struct eap_hdr);
258 wpabuf_set(&msgbuf, req, req_len);
259 encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
266 #ifdef EAP_SERVER_TNC
267 static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm,
268 struct eap_peap_data *data,
271 struct wpabuf *buf1, *buf, *encr_req, msgbuf;
275 buf1 = tncs_build_soh_request();
279 buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1),
280 EAP_CODE_REQUEST, id);
285 wpabuf_put_buf(buf, buf1);
288 req = wpabuf_head(buf);
289 req_len = wpabuf_len(buf);
291 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data",
294 req += sizeof(struct eap_hdr);
295 req_len -= sizeof(struct eap_hdr);
296 wpabuf_set(&msgbuf, req, req_len);
298 encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
303 #endif /* EAP_SERVER_TNC */
306 static void eap_peap_get_isk(struct eap_peap_data *data,
307 u8 *isk, size_t isk_len)
311 os_memset(isk, 0, isk_len);
312 if (data->phase2_key == NULL)
315 key_len = data->phase2_key_len;
316 if (key_len > isk_len)
318 os_memcpy(isk, data->phase2_key, key_len);
322 static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
325 u8 isk[32], imck[60];
328 * Tunnel key (TK) is the first 60 octets of the key generated by
329 * phase 1 of PEAP (based on TLS).
331 tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
335 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
337 eap_peap_get_isk(data, isk, sizeof(isk));
338 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
341 * IPMK Seed = "Inner Methods Compound Keys" | ISK
342 * TempKey = First 40 octets of TK
343 * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
344 * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
345 * in the end of the label just before ISK; is that just a typo?)
347 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
348 if (peap_prfplus(data->peap_version, tk, 40,
349 "Inner Methods Compound Keys",
350 isk, sizeof(isk), imck, sizeof(imck)) < 0) {
354 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
359 /* TODO: fast-connect: IPMK|CMK = TK */
360 os_memcpy(data->ipmk, imck, 40);
361 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
362 os_memcpy(data->cmk, imck + 40, 20);
363 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
369 static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
370 struct eap_peap_data *data,
373 struct wpabuf *buf, *encr_req;
376 mlen = 6; /* Result TLV */
377 if (data->crypto_binding != NO_BINDING)
378 mlen += 60; /* Cryptobinding TLV */
379 #ifdef EAP_SERVER_TNC
380 if (data->soh_response)
381 mlen += wpabuf_len(data->soh_response);
382 #endif /* EAP_SERVER_TNC */
384 buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen,
385 EAP_CODE_REQUEST, id);
389 wpabuf_put_u8(buf, 0x80); /* Mandatory */
390 wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV);
392 wpabuf_put_be16(buf, 2);
394 wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?
395 EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);
397 if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
398 data->crypto_binding != NO_BINDING) {
400 u8 eap_type = EAP_TYPE_PEAP;
405 #ifdef EAP_SERVER_TNC
406 if (data->soh_response) {
407 wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH "
409 wpabuf_put_buf(buf, data->soh_response);
410 wpabuf_free(data->soh_response);
411 data->soh_response = NULL;
413 #endif /* EAP_SERVER_TNC */
415 if (eap_peap_derive_cmk(sm, data) < 0 ||
416 random_get_bytes(data->binding_nonce, 32)) {
421 /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
422 addr[0] = wpabuf_put(buf, 0);
427 tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
428 if (data->peap_version >= 2)
429 tlv_type |= EAP_TLV_TYPE_MANDATORY;
430 wpabuf_put_be16(buf, tlv_type);
431 wpabuf_put_be16(buf, 56);
433 wpabuf_put_u8(buf, 0); /* Reserved */
434 wpabuf_put_u8(buf, data->peap_version); /* Version */
435 wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */
436 wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */
437 wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
438 mac = wpabuf_put(buf, 20); /* Compound_MAC */
439 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK",
441 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
443 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
445 hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
446 wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",
448 data->crypto_binding_sent = 1;
451 wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
454 encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf);
461 static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,
462 struct eap_peap_data *data,
465 struct wpabuf *encr_req, msgbuf;
469 req_len = sizeof(*hdr);
470 hdr = os_zalloc(req_len);
474 hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
475 hdr->identifier = id;
476 hdr->length = host_to_be16(req_len);
478 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
479 (u8 *) hdr, req_len);
481 wpabuf_set(&msgbuf, hdr, req_len);
482 encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf);
489 static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
491 struct eap_peap_data *data = priv;
493 if (data->ssl.state == FRAG_ACK) {
494 return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
498 if (data->ssl.state == WAIT_FRAG_ACK) {
499 return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
500 data->peap_version, id);
503 switch (data->state) {
505 return eap_peap_build_start(sm, data, id);
508 if (data->peap_version < 2 &&
509 tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
510 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
512 eap_peap_state(data, PHASE2_START);
517 wpabuf_free(data->ssl.tls_out);
518 data->ssl.tls_out_pos = 0;
519 data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id);
521 #ifdef EAP_SERVER_TNC
523 wpabuf_free(data->ssl.tls_out);
524 data->ssl.tls_out_pos = 0;
525 data->ssl.tls_out = eap_peap_build_phase2_soh(sm, data, id);
527 #endif /* EAP_SERVER_TNC */
529 wpabuf_free(data->ssl.tls_out);
530 data->ssl.tls_out_pos = 0;
531 data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id);
534 wpabuf_free(data->ssl.tls_out);
535 data->ssl.tls_out_pos = 0;
536 data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
540 wpabuf_free(data->ssl.tls_out);
541 data->ssl.tls_out_pos = 0;
542 data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id,
546 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
547 __func__, data->state);
551 return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
552 data->peap_version, id);
556 static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
557 struct wpabuf *respData)
562 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len);
563 if (pos == NULL || len < 1) {
564 wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
572 static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
575 if (data->phase2_priv && data->phase2_method) {
576 data->phase2_method->reset(sm, data->phase2_priv);
577 data->phase2_method = NULL;
578 data->phase2_priv = NULL;
580 data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF,
582 if (!data->phase2_method)
586 data->phase2_priv = data->phase2_method->init(sm);
592 static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
593 struct eap_peap_data *data,
594 const u8 *crypto_tlv,
595 size_t crypto_tlv_len)
597 u8 buf[61], mac[SHA1_MAC_LEN];
600 if (crypto_tlv_len != 4 + 56) {
601 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
602 "length %d", (int) crypto_tlv_len);
607 pos += 4; /* TLV header */
608 if (pos[1] != data->peap_version) {
609 wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
610 "mismatch (was %d; expected %d)",
611 pos[1], data->peap_version);
616 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
617 "SubType %d", pos[3]);
621 pos += 32; /* Nonce */
623 /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
624 os_memcpy(buf, crypto_tlv, 60);
625 os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
626 buf[60] = EAP_TYPE_PEAP;
627 hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
629 if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
630 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
631 "cryptobinding TLV");
632 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
633 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data",
638 wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
644 static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
645 struct eap_peap_data *data,
646 struct wpabuf *in_data)
650 const u8 *result_tlv = NULL, *crypto_tlv = NULL;
651 size_t result_tlv_len = 0, crypto_tlv_len = 0;
652 int tlv_type, mandatory, tlv_len;
654 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left);
656 wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header");
661 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left);
663 mandatory = !!(pos[0] & 0x80);
664 tlv_type = pos[0] & 0x3f;
665 tlv_type = (tlv_type << 8) | pos[1];
666 tlv_len = ((int) pos[2] << 8) | pos[3];
669 if ((size_t) tlv_len > left) {
670 wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
671 "(tlv_len=%d left=%lu)", tlv_len,
672 (unsigned long) left);
673 eap_peap_state(data, FAILURE);
677 case EAP_TLV_RESULT_TLV:
679 result_tlv_len = tlv_len;
681 case EAP_TLV_CRYPTO_BINDING_TLV:
683 crypto_tlv_len = tlv_len;
686 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
688 mandatory ? " (mandatory)" : "");
690 eap_peap_state(data, FAILURE);
693 /* Ignore this TLV, but process other TLVs */
701 wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
702 "Request (left=%lu)", (unsigned long) left);
703 eap_peap_state(data, FAILURE);
707 /* Process supported TLVs */
708 if (crypto_tlv && data->crypto_binding_sent) {
709 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
710 crypto_tlv, crypto_tlv_len);
711 if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
712 crypto_tlv_len + 4) < 0) {
713 eap_peap_state(data, FAILURE);
716 data->crypto_binding_used = 1;
717 } else if (!crypto_tlv && data->crypto_binding_sent &&
718 data->crypto_binding == REQUIRE_BINDING) {
719 wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
720 eap_peap_state(data, FAILURE);
726 const char *requested;
728 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV",
729 result_tlv, result_tlv_len);
730 if (result_tlv_len < 2) {
731 wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV "
733 (unsigned long) result_tlv_len);
734 eap_peap_state(data, FAILURE);
737 requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" :
739 status = WPA_GET_BE16(result_tlv);
740 if (status == EAP_TLV_RESULT_SUCCESS) {
741 wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
742 "- requested %s", requested);
743 if (data->tlv_request == TLV_REQ_SUCCESS)
744 eap_peap_state(data, SUCCESS);
746 eap_peap_state(data, FAILURE);
748 } else if (status == EAP_TLV_RESULT_FAILURE) {
749 wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
750 "- requested %s", requested);
751 eap_peap_state(data, FAILURE);
753 wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result "
754 "Status %d", status);
755 eap_peap_state(data, FAILURE);
761 #ifdef EAP_SERVER_TNC
762 static void eap_peap_process_phase2_soh(struct eap_sm *sm,
763 struct eap_peap_data *data,
764 struct wpabuf *in_data)
766 const u8 *pos, *vpos;
768 const u8 *soh_tlv = NULL;
769 size_t soh_tlv_len = 0;
770 int tlv_type, mandatory, tlv_len, vtlv_len;
774 pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
776 wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP "
777 "Extensions Method header - skip TNC");
782 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left);
784 mandatory = !!(pos[0] & 0x80);
785 tlv_type = pos[0] & 0x3f;
786 tlv_type = (tlv_type << 8) | pos[1];
787 tlv_len = ((int) pos[2] << 8) | pos[3];
790 if ((size_t) tlv_len > left) {
791 wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
792 "(tlv_len=%d left=%lu)", tlv_len,
793 (unsigned long) left);
794 eap_peap_state(data, FAILURE);
798 case EAP_TLV_VENDOR_SPECIFIC_TLV:
800 wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short "
801 "vendor specific TLV (len=%d)",
803 eap_peap_state(data, FAILURE);
807 vendor_id = WPA_GET_BE32(pos);
808 if (vendor_id != EAP_VENDOR_MICROSOFT) {
810 eap_peap_state(data, FAILURE);
817 mandatory = !!(vpos[0] & 0x80);
818 tlv_type = vpos[0] & 0x3f;
819 tlv_type = (tlv_type << 8) | vpos[1];
820 vtlv_len = ((int) vpos[2] << 8) | vpos[3];
822 if (vpos + vtlv_len > pos + left) {
823 wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV "
825 eap_peap_state(data, FAILURE);
831 soh_tlv_len = vtlv_len;
835 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV "
836 "Type %d%s", tlv_type,
837 mandatory ? " (mandatory)" : "");
839 eap_peap_state(data, FAILURE);
842 /* Ignore this TLV, but process other TLVs */
845 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
847 mandatory ? " (mandatory)" : "");
849 eap_peap_state(data, FAILURE);
852 /* Ignore this TLV, but process other TLVs */
860 wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
861 "Request (left=%lu)", (unsigned long) left);
862 eap_peap_state(data, FAILURE);
866 /* Process supported TLVs */
869 wpabuf_free(data->soh_response);
870 data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len,
873 eap_peap_state(data, FAILURE);
877 wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received");
878 eap_peap_state(data, FAILURE);
883 eap_peap_state(data, PHASE2_METHOD);
884 next_type = sm->user->methods[0].method;
885 sm->user_eap_method_index = 1;
886 wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
887 eap_peap_phase2_init(sm, data, next_type);
889 #endif /* EAP_SERVER_TNC */
892 static void eap_peap_process_phase2_response(struct eap_sm *sm,
893 struct eap_peap_data *data,
894 struct wpabuf *in_data)
896 u8 next_type = EAP_TYPE_NONE;
897 const struct eap_hdr *hdr;
901 if (data->state == PHASE2_TLV) {
902 eap_peap_process_phase2_tlv(sm, data, in_data);
906 #ifdef EAP_SERVER_TNC
907 if (data->state == PHASE2_SOH) {
908 eap_peap_process_phase2_soh(sm, data, in_data);
911 #endif /* EAP_SERVER_TNC */
913 if (data->phase2_priv == NULL) {
914 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not "
915 "initialized?!", __func__);
919 hdr = wpabuf_head(in_data);
920 pos = (const u8 *) (hdr + 1);
922 if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
923 left = wpabuf_len(in_data) - sizeof(*hdr);
924 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
925 "allowed types", pos + 1, left - 1);
926 eap_sm_process_nak(sm, pos + 1, left - 1);
927 if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
928 sm->user->methods[sm->user_eap_method_index].method !=
930 next_type = sm->user->methods[
931 sm->user_eap_method_index++].method;
932 wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
935 eap_peap_req_failure(sm, data);
936 next_type = EAP_TYPE_NONE;
938 eap_peap_phase2_init(sm, data, next_type);
942 if (data->phase2_method->check(sm, data->phase2_priv, in_data)) {
943 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to "
944 "ignore the packet");
948 data->phase2_method->process(sm, data->phase2_priv, in_data);
950 if (sm->method_pending == METHOD_PENDING_WAIT) {
951 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in "
952 "pending wait state - save decrypted response");
953 wpabuf_free(data->pending_phase2_resp);
954 data->pending_phase2_resp = wpabuf_dup(in_data);
957 if (!data->phase2_method->isDone(sm, data->phase2_priv))
960 if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
961 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
962 eap_peap_req_failure(sm, data);
963 next_type = EAP_TYPE_NONE;
964 eap_peap_phase2_init(sm, data, next_type);
968 os_free(data->phase2_key);
969 if (data->phase2_method->getKey) {
970 data->phase2_key = data->phase2_method->getKey(
971 sm, data->phase2_priv, &data->phase2_key_len);
972 if (data->phase2_key == NULL) {
973 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
975 eap_peap_req_failure(sm, data);
976 eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
981 switch (data->state) {
985 if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
986 wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 "
987 "Identity not found in the user "
989 sm->identity, sm->identity_len);
990 eap_peap_req_failure(sm, data);
991 next_type = EAP_TYPE_NONE;
995 #ifdef EAP_SERVER_TNC
996 if (data->state != PHASE2_SOH && sm->tnc &&
997 data->peap_version == 0) {
998 eap_peap_state(data, PHASE2_SOH);
999 wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
1001 next_type = EAP_TYPE_NONE;
1004 #endif /* EAP_SERVER_TNC */
1006 eap_peap_state(data, PHASE2_METHOD);
1007 next_type = sm->user->methods[0].method;
1008 sm->user_eap_method_index = 1;
1009 wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
1012 eap_peap_req_success(sm, data);
1013 next_type = EAP_TYPE_NONE;
1018 wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
1019 __func__, data->state);
1023 eap_peap_phase2_init(sm, data, next_type);
1027 static void eap_peap_process_phase2(struct eap_sm *sm,
1028 struct eap_peap_data *data,
1029 const struct wpabuf *respData,
1030 struct wpabuf *in_buf)
1032 struct wpabuf *in_decrypted;
1033 const struct eap_hdr *hdr;
1036 wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
1037 " Phase 2", (unsigned long) wpabuf_len(in_buf));
1039 if (data->pending_phase2_resp) {
1040 wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - "
1041 "skip decryption and use old data");
1042 eap_peap_process_phase2_response(sm, data,
1043 data->pending_phase2_resp);
1044 wpabuf_free(data->pending_phase2_resp);
1045 data->pending_phase2_resp = NULL;
1049 in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
1051 if (in_decrypted == NULL) {
1052 wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
1054 eap_peap_state(data, FAILURE);
1058 wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
1061 if (data->peap_version == 0 && data->state != PHASE2_TLV) {
1062 const struct eap_hdr *resp;
1063 struct eap_hdr *nhdr;
1064 struct wpabuf *nbuf =
1065 wpabuf_alloc(sizeof(struct eap_hdr) +
1066 wpabuf_len(in_decrypted));
1068 wpabuf_free(in_decrypted);
1072 resp = wpabuf_head(respData);
1073 nhdr = wpabuf_put(nbuf, sizeof(*nhdr));
1074 nhdr->code = resp->code;
1075 nhdr->identifier = resp->identifier;
1076 nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
1077 wpabuf_len(in_decrypted));
1078 wpabuf_put_buf(nbuf, in_decrypted);
1079 wpabuf_free(in_decrypted);
1081 in_decrypted = nbuf;
1082 } else if (data->peap_version >= 2) {
1083 struct eap_tlv_hdr *tlv;
1084 struct wpabuf *nmsg;
1086 if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
1087 wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
1089 wpabuf_free(in_decrypted);
1092 tlv = wpabuf_mhead(in_decrypted);
1093 if ((be_to_host16(tlv->tlv_type) & EAP_TLV_TYPE_MASK) !=
1094 EAP_TLV_EAP_PAYLOAD_TLV) {
1095 wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
1096 wpabuf_free(in_decrypted);
1099 if (sizeof(*tlv) + be_to_host16(tlv->length) >
1100 wpabuf_len(in_decrypted)) {
1101 wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
1103 wpabuf_free(in_decrypted);
1106 hdr = (struct eap_hdr *) (tlv + 1);
1107 if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
1108 wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
1109 "EAP packet in EAP TLV");
1110 wpabuf_free(in_decrypted);
1114 nmsg = wpabuf_alloc(be_to_host16(hdr->length));
1116 wpabuf_free(in_decrypted);
1120 wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
1121 wpabuf_free(in_decrypted);
1122 in_decrypted = nmsg;
1125 hdr = wpabuf_head(in_decrypted);
1126 if (wpabuf_len(in_decrypted) < (int) sizeof(*hdr)) {
1127 wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
1128 "EAP frame (len=%lu)",
1129 (unsigned long) wpabuf_len(in_decrypted));
1130 wpabuf_free(in_decrypted);
1131 eap_peap_req_failure(sm, data);
1134 len = be_to_host16(hdr->length);
1135 if (len > wpabuf_len(in_decrypted)) {
1136 wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
1137 "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
1138 (unsigned long) wpabuf_len(in_decrypted),
1139 (unsigned long) len);
1140 wpabuf_free(in_decrypted);
1141 eap_peap_req_failure(sm, data);
1144 wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
1145 "identifier=%d length=%lu", hdr->code, hdr->identifier,
1146 (unsigned long) len);
1147 switch (hdr->code) {
1148 case EAP_CODE_RESPONSE:
1149 eap_peap_process_phase2_response(sm, data, in_decrypted);
1151 case EAP_CODE_SUCCESS:
1152 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
1153 if (data->state == SUCCESS_REQ) {
1154 eap_peap_state(data, SUCCESS);
1157 case EAP_CODE_FAILURE:
1158 wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
1159 eap_peap_state(data, FAILURE);
1162 wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
1163 "Phase 2 EAP header", hdr->code);
1167 wpabuf_free(in_decrypted);
1171 static int eap_peapv2_start_phase2(struct eap_sm *sm,
1172 struct eap_peap_data *data)
1174 struct wpabuf *buf, *buf2;
1176 wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 "
1177 "payload in the same message");
1178 eap_peap_state(data, PHASE1_ID2);
1179 if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY))
1182 /* TODO: which Id to use here? */
1183 buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6);
1187 buf2 = eap_peapv2_tlv_eap_payload(buf);
1191 wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2);
1193 buf = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
1198 wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 "
1203 wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request",
1206 /* Append TLS data into the pending buffer after the Server Finished */
1207 if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(buf)) < 0) {
1211 wpabuf_put_buf(data->ssl.tls_out, buf);
1218 static int eap_peap_process_version(struct eap_sm *sm, void *priv,
1221 struct eap_peap_data *data = priv;
1223 data->recv_version = peer_version;
1224 if (data->force_version >= 0 && peer_version != data->force_version) {
1225 wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
1226 " version (forced=%d peer=%d) - reject",
1227 data->force_version, peer_version);
1230 if (peer_version < data->peap_version) {
1231 wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; "
1233 peer_version, data->peap_version, peer_version);
1234 data->peap_version = peer_version;
1241 static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
1242 const struct wpabuf *respData)
1244 struct eap_peap_data *data = priv;
1246 switch (data->state) {
1248 if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
1249 eap_peap_state(data, FAILURE);
1253 if (data->peap_version >= 2 &&
1254 tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
1255 if (eap_peapv2_start_phase2(sm, data)) {
1256 eap_peap_state(data, FAILURE);
1262 eap_peap_state(data, PHASE2_ID);
1263 eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY);
1270 eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in);
1273 eap_peap_state(data, SUCCESS);
1276 eap_peap_state(data, FAILURE);
1279 wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s",
1280 data->state, __func__);
1286 static void eap_peap_process(struct eap_sm *sm, void *priv,
1287 struct wpabuf *respData)
1289 struct eap_peap_data *data = priv;
1290 if (eap_server_tls_process(sm, &data->ssl, respData, data,
1291 EAP_TYPE_PEAP, eap_peap_process_version,
1292 eap_peap_process_msg) < 0)
1293 eap_peap_state(data, FAILURE);
1297 static Boolean eap_peap_isDone(struct eap_sm *sm, void *priv)
1299 struct eap_peap_data *data = priv;
1300 return data->state == SUCCESS || data->state == FAILURE;
1304 static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
1306 struct eap_peap_data *data = priv;
1309 if (data->state != SUCCESS)
1312 if (data->crypto_binding_used) {
1315 * Note: It looks like Microsoft implementation requires null
1316 * termination for this label while the one used for deriving
1317 * IPMK|CMK did not use null termination.
1319 if (peap_prfplus(data->peap_version, data->ipmk, 40,
1320 "Session Key Generating Function",
1321 (u8 *) "\00", 1, csk, sizeof(csk)) < 0)
1323 wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
1324 eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
1326 os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN);
1327 *len = EAP_TLS_KEY_LEN;
1328 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
1329 eapKeyData, EAP_TLS_KEY_LEN);
1331 wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive "
1338 /* TODO: PEAPv1 - different label in some cases */
1339 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
1340 "client EAP encryption",
1343 *len = EAP_TLS_KEY_LEN;
1344 wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
1345 eapKeyData, EAP_TLS_KEY_LEN);
1347 wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key");
1354 static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
1356 struct eap_peap_data *data = priv;
1357 return data->state == SUCCESS;
1361 int eap_server_peap_register(void)
1363 struct eap_method *eap;
1366 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
1367 EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
1371 eap->init = eap_peap_init;
1372 eap->reset = eap_peap_reset;
1373 eap->buildReq = eap_peap_buildReq;
1374 eap->check = eap_peap_check;
1375 eap->process = eap_peap_process;
1376 eap->isDone = eap_peap_isDone;
1377 eap->getKey = eap_peap_getKey;
1378 eap->isSuccess = eap_peap_isSuccess;
1380 ret = eap_server_method_register(eap);
1382 eap_server_method_free(eap);