xref: /freebsd/contrib/wpa/src/eap_peer/eap_ttls.c (revision f05cddf940dbfc5b657f5e9beb9de2c31e509e5b)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * EAP peer method: EAP-TTLS (RFC 5281)
3*f05cddf9SRui Paulo  * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5*f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6*f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler 
1139beb93cSSam Leffler #include "common.h"
12e28a4053SRui Paulo #include "crypto/ms_funcs.h"
13e28a4053SRui Paulo #include "crypto/sha1.h"
14e28a4053SRui Paulo #include "crypto/tls.h"
1539beb93cSSam Leffler #include "eap_common/chap.h"
1639beb93cSSam Leffler #include "eap_common/eap_ttls.h"
17e28a4053SRui Paulo #include "mschapv2.h"
18e28a4053SRui Paulo #include "eap_i.h"
19e28a4053SRui Paulo #include "eap_tls_common.h"
20e28a4053SRui Paulo #include "eap_config.h"
2139beb93cSSam Leffler 
2239beb93cSSam Leffler 
23*f05cddf9SRui Paulo #define EAP_TTLS_VERSION 0
2439beb93cSSam Leffler 
2539beb93cSSam Leffler 
2639beb93cSSam Leffler static void eap_ttls_deinit(struct eap_sm *sm, void *priv);
2739beb93cSSam Leffler 
2839beb93cSSam Leffler 
2939beb93cSSam Leffler struct eap_ttls_data {
3039beb93cSSam Leffler 	struct eap_ssl_data ssl;
3139beb93cSSam Leffler 
32*f05cddf9SRui Paulo 	int ttls_version;
3339beb93cSSam Leffler 
3439beb93cSSam Leffler 	const struct eap_method *phase2_method;
3539beb93cSSam Leffler 	void *phase2_priv;
3639beb93cSSam Leffler 	int phase2_success;
3739beb93cSSam Leffler 	int phase2_start;
3839beb93cSSam Leffler 
3939beb93cSSam Leffler 	enum phase2_types {
4039beb93cSSam Leffler 		EAP_TTLS_PHASE2_EAP,
4139beb93cSSam Leffler 		EAP_TTLS_PHASE2_MSCHAPV2,
4239beb93cSSam Leffler 		EAP_TTLS_PHASE2_MSCHAP,
4339beb93cSSam Leffler 		EAP_TTLS_PHASE2_PAP,
4439beb93cSSam Leffler 		EAP_TTLS_PHASE2_CHAP
4539beb93cSSam Leffler 	} phase2_type;
4639beb93cSSam Leffler 	struct eap_method_type phase2_eap_type;
4739beb93cSSam Leffler 	struct eap_method_type *phase2_eap_types;
4839beb93cSSam Leffler 	size_t num_phase2_eap_types;
4939beb93cSSam Leffler 
5039beb93cSSam Leffler 	u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];
5139beb93cSSam Leffler 	int auth_response_valid;
5239beb93cSSam Leffler 	u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */
5339beb93cSSam Leffler 	u8 ident;
5439beb93cSSam Leffler 	int resuming; /* starting a resumed session */
5539beb93cSSam Leffler 	int reauth; /* reauthentication */
5639beb93cSSam Leffler 	u8 *key_data;
5739beb93cSSam Leffler 
5839beb93cSSam Leffler 	struct wpabuf *pending_phase2_req;
5939beb93cSSam Leffler 
6039beb93cSSam Leffler #ifdef EAP_TNC
6139beb93cSSam Leffler 	int ready_for_tnc;
6239beb93cSSam Leffler 	int tnc_started;
6339beb93cSSam Leffler #endif /* EAP_TNC */
6439beb93cSSam Leffler };
6539beb93cSSam Leffler 
6639beb93cSSam Leffler 
6739beb93cSSam Leffler static void * eap_ttls_init(struct eap_sm *sm)
6839beb93cSSam Leffler {
6939beb93cSSam Leffler 	struct eap_ttls_data *data;
7039beb93cSSam Leffler 	struct eap_peer_config *config = eap_get_config(sm);
7139beb93cSSam Leffler 	char *selected;
7239beb93cSSam Leffler 
7339beb93cSSam Leffler 	data = os_zalloc(sizeof(*data));
7439beb93cSSam Leffler 	if (data == NULL)
7539beb93cSSam Leffler 		return NULL;
7639beb93cSSam Leffler 	data->ttls_version = EAP_TTLS_VERSION;
7739beb93cSSam Leffler 	selected = "EAP";
7839beb93cSSam Leffler 	data->phase2_type = EAP_TTLS_PHASE2_EAP;
7939beb93cSSam Leffler 
8039beb93cSSam Leffler 	if (config && config->phase2) {
8139beb93cSSam Leffler 		if (os_strstr(config->phase2, "autheap=")) {
8239beb93cSSam Leffler 			selected = "EAP";
8339beb93cSSam Leffler 			data->phase2_type = EAP_TTLS_PHASE2_EAP;
8439beb93cSSam Leffler 		} else if (os_strstr(config->phase2, "auth=MSCHAPV2")) {
8539beb93cSSam Leffler 			selected = "MSCHAPV2";
8639beb93cSSam Leffler 			data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
8739beb93cSSam Leffler 		} else if (os_strstr(config->phase2, "auth=MSCHAP")) {
8839beb93cSSam Leffler 			selected = "MSCHAP";
8939beb93cSSam Leffler 			data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
9039beb93cSSam Leffler 		} else if (os_strstr(config->phase2, "auth=PAP")) {
9139beb93cSSam Leffler 			selected = "PAP";
9239beb93cSSam Leffler 			data->phase2_type = EAP_TTLS_PHASE2_PAP;
9339beb93cSSam Leffler 		} else if (os_strstr(config->phase2, "auth=CHAP")) {
9439beb93cSSam Leffler 			selected = "CHAP";
9539beb93cSSam Leffler 			data->phase2_type = EAP_TTLS_PHASE2_CHAP;
9639beb93cSSam Leffler 		}
9739beb93cSSam Leffler 	}
9839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected);
9939beb93cSSam Leffler 
10039beb93cSSam Leffler 	if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
10139beb93cSSam Leffler 		if (eap_peer_select_phase2_methods(config, "autheap=",
10239beb93cSSam Leffler 						   &data->phase2_eap_types,
10339beb93cSSam Leffler 						   &data->num_phase2_eap_types)
10439beb93cSSam Leffler 		    < 0) {
10539beb93cSSam Leffler 			eap_ttls_deinit(sm, data);
10639beb93cSSam Leffler 			return NULL;
10739beb93cSSam Leffler 		}
10839beb93cSSam Leffler 
10939beb93cSSam Leffler 		data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
11039beb93cSSam Leffler 		data->phase2_eap_type.method = EAP_TYPE_NONE;
11139beb93cSSam Leffler 	}
11239beb93cSSam Leffler 
113*f05cddf9SRui Paulo 	if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) {
114*f05cddf9SRui Paulo 		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
11539beb93cSSam Leffler 		eap_ttls_deinit(sm, data);
11639beb93cSSam Leffler 		return NULL;
11739beb93cSSam Leffler 	}
11839beb93cSSam Leffler 
11939beb93cSSam Leffler 	return data;
12039beb93cSSam Leffler }
12139beb93cSSam Leffler 
12239beb93cSSam Leffler 
12339beb93cSSam Leffler static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm,
12439beb93cSSam Leffler 				       struct eap_ttls_data *data)
12539beb93cSSam Leffler {
12639beb93cSSam Leffler 	if (data->phase2_priv && data->phase2_method) {
12739beb93cSSam Leffler 		data->phase2_method->deinit(sm, data->phase2_priv);
12839beb93cSSam Leffler 		data->phase2_method = NULL;
12939beb93cSSam Leffler 		data->phase2_priv = NULL;
13039beb93cSSam Leffler 	}
13139beb93cSSam Leffler }
13239beb93cSSam Leffler 
13339beb93cSSam Leffler 
13439beb93cSSam Leffler static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
13539beb93cSSam Leffler {
13639beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
13739beb93cSSam Leffler 	if (data == NULL)
13839beb93cSSam Leffler 		return;
13939beb93cSSam Leffler 	eap_ttls_phase2_eap_deinit(sm, data);
14039beb93cSSam Leffler 	os_free(data->phase2_eap_types);
14139beb93cSSam Leffler 	eap_peer_tls_ssl_deinit(sm, &data->ssl);
14239beb93cSSam Leffler 	os_free(data->key_data);
14339beb93cSSam Leffler 	wpabuf_free(data->pending_phase2_req);
14439beb93cSSam Leffler 	os_free(data);
14539beb93cSSam Leffler }
14639beb93cSSam Leffler 
14739beb93cSSam Leffler 
14839beb93cSSam Leffler static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,
14939beb93cSSam Leffler 			     int mandatory, size_t len)
15039beb93cSSam Leffler {
15139beb93cSSam Leffler 	struct ttls_avp_vendor *avp;
15239beb93cSSam Leffler 	u8 flags;
15339beb93cSSam Leffler 	size_t hdrlen;
15439beb93cSSam Leffler 
15539beb93cSSam Leffler 	avp = (struct ttls_avp_vendor *) avphdr;
15639beb93cSSam Leffler 	flags = mandatory ? AVP_FLAGS_MANDATORY : 0;
15739beb93cSSam Leffler 	if (vendor_id) {
15839beb93cSSam Leffler 		flags |= AVP_FLAGS_VENDOR;
15939beb93cSSam Leffler 		hdrlen = sizeof(*avp);
16039beb93cSSam Leffler 		avp->vendor_id = host_to_be32(vendor_id);
16139beb93cSSam Leffler 	} else {
16239beb93cSSam Leffler 		hdrlen = sizeof(struct ttls_avp);
16339beb93cSSam Leffler 	}
16439beb93cSSam Leffler 
16539beb93cSSam Leffler 	avp->avp_code = host_to_be32(avp_code);
166*f05cddf9SRui Paulo 	avp->avp_length = host_to_be32((flags << 24) | (u32) (hdrlen + len));
16739beb93cSSam Leffler 
16839beb93cSSam Leffler 	return avphdr + hdrlen;
16939beb93cSSam Leffler }
17039beb93cSSam Leffler 
17139beb93cSSam Leffler 
17239beb93cSSam Leffler static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code,
17339beb93cSSam Leffler 			     u32 vendor_id, int mandatory,
17439beb93cSSam Leffler 			     const u8 *data, size_t len)
17539beb93cSSam Leffler {
17639beb93cSSam Leffler 	u8 *pos;
17739beb93cSSam Leffler 	pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len);
17839beb93cSSam Leffler 	os_memcpy(pos, data, len);
17939beb93cSSam Leffler 	pos += len;
18039beb93cSSam Leffler 	AVP_PAD(start, pos);
18139beb93cSSam Leffler 	return pos;
18239beb93cSSam Leffler }
18339beb93cSSam Leffler 
18439beb93cSSam Leffler 
18539beb93cSSam Leffler static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
18639beb93cSSam Leffler 				    int mandatory)
18739beb93cSSam Leffler {
18839beb93cSSam Leffler 	struct wpabuf *msg;
18939beb93cSSam Leffler 	u8 *avp, *pos;
19039beb93cSSam Leffler 
19139beb93cSSam Leffler 	msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4);
19239beb93cSSam Leffler 	if (msg == NULL) {
19339beb93cSSam Leffler 		wpabuf_free(*resp);
19439beb93cSSam Leffler 		*resp = NULL;
19539beb93cSSam Leffler 		return -1;
19639beb93cSSam Leffler 	}
19739beb93cSSam Leffler 
19839beb93cSSam Leffler 	avp = wpabuf_mhead(msg);
19939beb93cSSam Leffler 	pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp));
20039beb93cSSam Leffler 	os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp));
20139beb93cSSam Leffler 	pos += wpabuf_len(*resp);
20239beb93cSSam Leffler 	AVP_PAD(avp, pos);
20339beb93cSSam Leffler 	wpabuf_free(*resp);
20439beb93cSSam Leffler 	wpabuf_put(msg, pos - avp);
20539beb93cSSam Leffler 	*resp = msg;
20639beb93cSSam Leffler 	return 0;
20739beb93cSSam Leffler }
20839beb93cSSam Leffler 
20939beb93cSSam Leffler 
21039beb93cSSam Leffler static int eap_ttls_v0_derive_key(struct eap_sm *sm,
21139beb93cSSam Leffler 				  struct eap_ttls_data *data)
21239beb93cSSam Leffler {
21339beb93cSSam Leffler 	os_free(data->key_data);
21439beb93cSSam Leffler 	data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
21539beb93cSSam Leffler 						 "ttls keying material",
21639beb93cSSam Leffler 						 EAP_TLS_KEY_LEN);
21739beb93cSSam Leffler 	if (!data->key_data) {
21839beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key");
21939beb93cSSam Leffler 		return -1;
22039beb93cSSam Leffler 	}
22139beb93cSSam Leffler 
22239beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
22339beb93cSSam Leffler 			data->key_data, EAP_TLS_KEY_LEN);
22439beb93cSSam Leffler 
22539beb93cSSam Leffler 	return 0;
22639beb93cSSam Leffler }
22739beb93cSSam Leffler 
22839beb93cSSam Leffler 
22939beb93cSSam Leffler static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
23039beb93cSSam Leffler 					struct eap_ttls_data *data, size_t len)
23139beb93cSSam Leffler {
232*f05cddf9SRui Paulo 	return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len);
23339beb93cSSam Leffler }
23439beb93cSSam Leffler 
23539beb93cSSam Leffler 
23639beb93cSSam Leffler static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data,
23739beb93cSSam Leffler 					      u8 method)
23839beb93cSSam Leffler {
23939beb93cSSam Leffler 	size_t i;
24039beb93cSSam Leffler 	for (i = 0; i < data->num_phase2_eap_types; i++) {
24139beb93cSSam Leffler 		if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF ||
24239beb93cSSam Leffler 		    data->phase2_eap_types[i].method != method)
24339beb93cSSam Leffler 			continue;
24439beb93cSSam Leffler 
24539beb93cSSam Leffler 		data->phase2_eap_type.vendor =
24639beb93cSSam Leffler 			data->phase2_eap_types[i].vendor;
24739beb93cSSam Leffler 		data->phase2_eap_type.method =
24839beb93cSSam Leffler 			data->phase2_eap_types[i].method;
24939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
25039beb93cSSam Leffler 			   "Phase 2 EAP vendor %d method %d",
25139beb93cSSam Leffler 			   data->phase2_eap_type.vendor,
25239beb93cSSam Leffler 			   data->phase2_eap_type.method);
25339beb93cSSam Leffler 		break;
25439beb93cSSam Leffler 	}
25539beb93cSSam Leffler }
25639beb93cSSam Leffler 
25739beb93cSSam Leffler 
25839beb93cSSam Leffler static int eap_ttls_phase2_eap_process(struct eap_sm *sm,
25939beb93cSSam Leffler 				       struct eap_ttls_data *data,
26039beb93cSSam Leffler 				       struct eap_method_ret *ret,
26139beb93cSSam Leffler 				       struct eap_hdr *hdr, size_t len,
26239beb93cSSam Leffler 				       struct wpabuf **resp)
26339beb93cSSam Leffler {
26439beb93cSSam Leffler 	struct wpabuf msg;
26539beb93cSSam Leffler 	struct eap_method_ret iret;
26639beb93cSSam Leffler 
26739beb93cSSam Leffler 	os_memset(&iret, 0, sizeof(iret));
26839beb93cSSam Leffler 	wpabuf_set(&msg, hdr, len);
26939beb93cSSam Leffler 	*resp = data->phase2_method->process(sm, data->phase2_priv, &iret,
27039beb93cSSam Leffler 					     &msg);
27139beb93cSSam Leffler 	if ((iret.methodState == METHOD_DONE ||
27239beb93cSSam Leffler 	     iret.methodState == METHOD_MAY_CONT) &&
27339beb93cSSam Leffler 	    (iret.decision == DECISION_UNCOND_SUCC ||
27439beb93cSSam Leffler 	     iret.decision == DECISION_COND_SUCC ||
27539beb93cSSam Leffler 	     iret.decision == DECISION_FAIL)) {
27639beb93cSSam Leffler 		ret->methodState = iret.methodState;
27739beb93cSSam Leffler 		ret->decision = iret.decision;
27839beb93cSSam Leffler 	}
27939beb93cSSam Leffler 
28039beb93cSSam Leffler 	return 0;
28139beb93cSSam Leffler }
28239beb93cSSam Leffler 
28339beb93cSSam Leffler 
28439beb93cSSam Leffler static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm,
28539beb93cSSam Leffler 					      struct eap_ttls_data *data,
28639beb93cSSam Leffler 					      struct eap_method_ret *ret,
28739beb93cSSam Leffler 					      struct eap_hdr *hdr, size_t len,
28839beb93cSSam Leffler 					      u8 method, struct wpabuf **resp)
28939beb93cSSam Leffler {
29039beb93cSSam Leffler #ifdef EAP_TNC
29139beb93cSSam Leffler 	if (data->tnc_started && data->phase2_method &&
29239beb93cSSam Leffler 	    data->phase2_priv && method == EAP_TYPE_TNC &&
29339beb93cSSam Leffler 	    data->phase2_eap_type.method == EAP_TYPE_TNC)
29439beb93cSSam Leffler 		return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len,
29539beb93cSSam Leffler 						   resp);
29639beb93cSSam Leffler 
29739beb93cSSam Leffler 	if (data->ready_for_tnc && !data->tnc_started &&
29839beb93cSSam Leffler 	    method == EAP_TYPE_TNC) {
29939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
30039beb93cSSam Leffler 			   "EAP method");
30139beb93cSSam Leffler 		data->tnc_started = 1;
30239beb93cSSam Leffler 	}
30339beb93cSSam Leffler 
30439beb93cSSam Leffler 	if (data->tnc_started) {
30539beb93cSSam Leffler 		if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF ||
30639beb93cSSam Leffler 		    data->phase2_eap_type.method == EAP_TYPE_TNC) {
30739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP "
30839beb93cSSam Leffler 				   "type %d for TNC", method);
30939beb93cSSam Leffler 			return -1;
31039beb93cSSam Leffler 		}
31139beb93cSSam Leffler 
31239beb93cSSam Leffler 		data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
31339beb93cSSam Leffler 		data->phase2_eap_type.method = method;
31439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
31539beb93cSSam Leffler 			   "Phase 2 EAP vendor %d method %d (TNC)",
31639beb93cSSam Leffler 			   data->phase2_eap_type.vendor,
31739beb93cSSam Leffler 			   data->phase2_eap_type.method);
31839beb93cSSam Leffler 
31939beb93cSSam Leffler 		if (data->phase2_type == EAP_TTLS_PHASE2_EAP)
32039beb93cSSam Leffler 			eap_ttls_phase2_eap_deinit(sm, data);
32139beb93cSSam Leffler 	}
32239beb93cSSam Leffler #endif /* EAP_TNC */
32339beb93cSSam Leffler 
32439beb93cSSam Leffler 	if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF &&
32539beb93cSSam Leffler 	    data->phase2_eap_type.method == EAP_TYPE_NONE)
32639beb93cSSam Leffler 		eap_ttls_phase2_select_eap_method(data, method);
32739beb93cSSam Leffler 
32839beb93cSSam Leffler 	if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE)
32939beb93cSSam Leffler 	{
33039beb93cSSam Leffler 		if (eap_peer_tls_phase2_nak(data->phase2_eap_types,
33139beb93cSSam Leffler 					    data->num_phase2_eap_types,
33239beb93cSSam Leffler 					    hdr, resp))
33339beb93cSSam Leffler 			return -1;
33439beb93cSSam Leffler 		return 0;
33539beb93cSSam Leffler 	}
33639beb93cSSam Leffler 
33739beb93cSSam Leffler 	if (data->phase2_priv == NULL) {
33839beb93cSSam Leffler 		data->phase2_method = eap_peer_get_eap_method(
33939beb93cSSam Leffler 			EAP_VENDOR_IETF, method);
34039beb93cSSam Leffler 		if (data->phase2_method) {
34139beb93cSSam Leffler 			sm->init_phase2 = 1;
34239beb93cSSam Leffler 			data->phase2_priv = data->phase2_method->init(sm);
34339beb93cSSam Leffler 			sm->init_phase2 = 0;
34439beb93cSSam Leffler 		}
34539beb93cSSam Leffler 	}
34639beb93cSSam Leffler 	if (data->phase2_priv == NULL || data->phase2_method == NULL) {
34739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize "
34839beb93cSSam Leffler 			   "Phase 2 EAP method %d", method);
34939beb93cSSam Leffler 		return -1;
35039beb93cSSam Leffler 	}
35139beb93cSSam Leffler 
35239beb93cSSam Leffler 	return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp);
35339beb93cSSam Leffler }
35439beb93cSSam Leffler 
35539beb93cSSam Leffler 
35639beb93cSSam Leffler static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
35739beb93cSSam Leffler 				       struct eap_ttls_data *data,
35839beb93cSSam Leffler 				       struct eap_method_ret *ret,
35939beb93cSSam Leffler 				       struct eap_hdr *hdr,
36039beb93cSSam Leffler 				       struct wpabuf **resp)
36139beb93cSSam Leffler {
36239beb93cSSam Leffler 	size_t len = be_to_host16(hdr->length);
36339beb93cSSam Leffler 	u8 *pos;
36439beb93cSSam Leffler 	struct eap_peer_config *config = eap_get_config(sm);
36539beb93cSSam Leffler 
36639beb93cSSam Leffler 	if (len <= sizeof(struct eap_hdr)) {
36739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: too short "
36839beb93cSSam Leffler 			   "Phase 2 request (len=%lu)", (unsigned long) len);
36939beb93cSSam Leffler 		return -1;
37039beb93cSSam Leffler 	}
37139beb93cSSam Leffler 	pos = (u8 *) (hdr + 1);
37239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos);
37339beb93cSSam Leffler 	switch (*pos) {
37439beb93cSSam Leffler 	case EAP_TYPE_IDENTITY:
37539beb93cSSam Leffler 		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
37639beb93cSSam Leffler 		break;
37739beb93cSSam Leffler 	default:
37839beb93cSSam Leffler 		if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
37939beb93cSSam Leffler 						       *pos, resp) < 0)
38039beb93cSSam Leffler 			return -1;
38139beb93cSSam Leffler 		break;
38239beb93cSSam Leffler 	}
38339beb93cSSam Leffler 
38439beb93cSSam Leffler 	if (*resp == NULL &&
38539beb93cSSam Leffler 	    (config->pending_req_identity || config->pending_req_password ||
38639beb93cSSam Leffler 	     config->pending_req_otp)) {
38739beb93cSSam Leffler 		return 0;
38839beb93cSSam Leffler 	}
38939beb93cSSam Leffler 
39039beb93cSSam Leffler 	if (*resp == NULL)
39139beb93cSSam Leffler 		return -1;
39239beb93cSSam Leffler 
39339beb93cSSam Leffler 	wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response",
39439beb93cSSam Leffler 			*resp);
39539beb93cSSam Leffler 	return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1);
39639beb93cSSam Leffler }
39739beb93cSSam Leffler 
39839beb93cSSam Leffler 
39939beb93cSSam Leffler static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
40039beb93cSSam Leffler 					    struct eap_ttls_data *data,
40139beb93cSSam Leffler 					    struct eap_method_ret *ret,
40239beb93cSSam Leffler 					    struct wpabuf **resp)
40339beb93cSSam Leffler {
404*f05cddf9SRui Paulo #ifdef EAP_MSCHAPv2
40539beb93cSSam Leffler 	struct wpabuf *msg;
40639beb93cSSam Leffler 	u8 *buf, *pos, *challenge, *peer_challenge;
40739beb93cSSam Leffler 	const u8 *identity, *password;
40839beb93cSSam Leffler 	size_t identity_len, password_len;
40939beb93cSSam Leffler 	int pwhash;
41039beb93cSSam Leffler 
41139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request");
41239beb93cSSam Leffler 
41339beb93cSSam Leffler 	identity = eap_get_config_identity(sm, &identity_len);
41439beb93cSSam Leffler 	password = eap_get_config_password2(sm, &password_len, &pwhash);
41539beb93cSSam Leffler 	if (identity == NULL || password == NULL)
41639beb93cSSam Leffler 		return -1;
41739beb93cSSam Leffler 
41839beb93cSSam Leffler 	msg = wpabuf_alloc(identity_len + 1000);
41939beb93cSSam Leffler 	if (msg == NULL) {
42039beb93cSSam Leffler 		wpa_printf(MSG_ERROR,
42139beb93cSSam Leffler 			   "EAP-TTLS/MSCHAPV2: Failed to allocate memory");
42239beb93cSSam Leffler 		return -1;
42339beb93cSSam Leffler 	}
42439beb93cSSam Leffler 	pos = buf = wpabuf_mhead(msg);
42539beb93cSSam Leffler 
42639beb93cSSam Leffler 	/* User-Name */
42739beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
42839beb93cSSam Leffler 			       identity, identity_len);
42939beb93cSSam Leffler 
43039beb93cSSam Leffler 	/* MS-CHAP-Challenge */
43139beb93cSSam Leffler 	challenge = eap_ttls_implicit_challenge(
43239beb93cSSam Leffler 		sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
43339beb93cSSam Leffler 	if (challenge == NULL) {
43439beb93cSSam Leffler 		wpabuf_free(msg);
43539beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
43639beb93cSSam Leffler 			   "implicit challenge");
43739beb93cSSam Leffler 		return -1;
43839beb93cSSam Leffler 	}
43939beb93cSSam Leffler 
44039beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
44139beb93cSSam Leffler 			       RADIUS_VENDOR_ID_MICROSOFT, 1,
44239beb93cSSam Leffler 			       challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
44339beb93cSSam Leffler 
44439beb93cSSam Leffler 	/* MS-CHAP2-Response */
44539beb93cSSam Leffler 	pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE,
44639beb93cSSam Leffler 			       RADIUS_VENDOR_ID_MICROSOFT, 1,
44739beb93cSSam Leffler 			       EAP_TTLS_MSCHAPV2_RESPONSE_LEN);
44839beb93cSSam Leffler 	data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN];
44939beb93cSSam Leffler 	*pos++ = data->ident;
45039beb93cSSam Leffler 	*pos++ = 0; /* Flags */
451*f05cddf9SRui Paulo 	if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) {
452*f05cddf9SRui Paulo 		os_free(challenge);
453*f05cddf9SRui Paulo 		wpabuf_free(msg);
454*f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get "
455*f05cddf9SRui Paulo 			   "random data for peer challenge");
456*f05cddf9SRui Paulo 		return -1;
457*f05cddf9SRui Paulo 	}
458*f05cddf9SRui Paulo 	peer_challenge = pos;
45939beb93cSSam Leffler 	pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
46039beb93cSSam Leffler 	os_memset(pos, 0, 8); /* Reserved, must be zero */
46139beb93cSSam Leffler 	pos += 8;
462e28a4053SRui Paulo 	if (mschapv2_derive_response(identity, identity_len, password,
46339beb93cSSam Leffler 				     password_len, pwhash, challenge,
46439beb93cSSam Leffler 				     peer_challenge, pos, data->auth_response,
465e28a4053SRui Paulo 				     data->master_key)) {
466*f05cddf9SRui Paulo 		os_free(challenge);
467e28a4053SRui Paulo 		wpabuf_free(msg);
468e28a4053SRui Paulo 		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
469e28a4053SRui Paulo 			   "response");
470e28a4053SRui Paulo 		return -1;
471e28a4053SRui Paulo 	}
47239beb93cSSam Leffler 	data->auth_response_valid = 1;
47339beb93cSSam Leffler 
47439beb93cSSam Leffler 	pos += 24;
47539beb93cSSam Leffler 	os_free(challenge);
47639beb93cSSam Leffler 	AVP_PAD(buf, pos);
47739beb93cSSam Leffler 
47839beb93cSSam Leffler 	wpabuf_put(msg, pos - buf);
47939beb93cSSam Leffler 	*resp = msg;
48039beb93cSSam Leffler 
481*f05cddf9SRui Paulo 	if (sm->workaround) {
48239beb93cSSam Leffler 		/* At least FreeRADIUS seems to be terminating
48339beb93cSSam Leffler 		 * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success
48439beb93cSSam Leffler 		 * packet. */
48539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - "
48639beb93cSSam Leffler 			   "allow success without tunneled response");
48739beb93cSSam Leffler 		ret->methodState = METHOD_MAY_CONT;
48839beb93cSSam Leffler 		ret->decision = DECISION_COND_SUCC;
48939beb93cSSam Leffler 	}
49039beb93cSSam Leffler 
49139beb93cSSam Leffler 	return 0;
492*f05cddf9SRui Paulo #else /* EAP_MSCHAPv2 */
493*f05cddf9SRui Paulo 	wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
494*f05cddf9SRui Paulo 	return -1;
495*f05cddf9SRui Paulo #endif /* EAP_MSCHAPv2 */
49639beb93cSSam Leffler }
49739beb93cSSam Leffler 
49839beb93cSSam Leffler 
49939beb93cSSam Leffler static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
50039beb93cSSam Leffler 					  struct eap_ttls_data *data,
50139beb93cSSam Leffler 					  struct eap_method_ret *ret,
50239beb93cSSam Leffler 					  struct wpabuf **resp)
50339beb93cSSam Leffler {
50439beb93cSSam Leffler 	struct wpabuf *msg;
50539beb93cSSam Leffler 	u8 *buf, *pos, *challenge;
50639beb93cSSam Leffler 	const u8 *identity, *password;
50739beb93cSSam Leffler 	size_t identity_len, password_len;
50839beb93cSSam Leffler 	int pwhash;
50939beb93cSSam Leffler 
51039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request");
51139beb93cSSam Leffler 
51239beb93cSSam Leffler 	identity = eap_get_config_identity(sm, &identity_len);
51339beb93cSSam Leffler 	password = eap_get_config_password2(sm, &password_len, &pwhash);
51439beb93cSSam Leffler 	if (identity == NULL || password == NULL)
51539beb93cSSam Leffler 		return -1;
51639beb93cSSam Leffler 
51739beb93cSSam Leffler 	msg = wpabuf_alloc(identity_len + 1000);
51839beb93cSSam Leffler 	if (msg == NULL) {
51939beb93cSSam Leffler 		wpa_printf(MSG_ERROR,
52039beb93cSSam Leffler 			   "EAP-TTLS/MSCHAP: Failed to allocate memory");
52139beb93cSSam Leffler 		return -1;
52239beb93cSSam Leffler 	}
52339beb93cSSam Leffler 	pos = buf = wpabuf_mhead(msg);
52439beb93cSSam Leffler 
52539beb93cSSam Leffler 	/* User-Name */
52639beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
52739beb93cSSam Leffler 			       identity, identity_len);
52839beb93cSSam Leffler 
52939beb93cSSam Leffler 	/* MS-CHAP-Challenge */
53039beb93cSSam Leffler 	challenge = eap_ttls_implicit_challenge(
53139beb93cSSam Leffler 		sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
53239beb93cSSam Leffler 	if (challenge == NULL) {
53339beb93cSSam Leffler 		wpabuf_free(msg);
53439beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive "
53539beb93cSSam Leffler 			   "implicit challenge");
53639beb93cSSam Leffler 		return -1;
53739beb93cSSam Leffler 	}
53839beb93cSSam Leffler 
53939beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
54039beb93cSSam Leffler 			       RADIUS_VENDOR_ID_MICROSOFT, 1,
54139beb93cSSam Leffler 			       challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
54239beb93cSSam Leffler 
54339beb93cSSam Leffler 	/* MS-CHAP-Response */
54439beb93cSSam Leffler 	pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE,
54539beb93cSSam Leffler 			       RADIUS_VENDOR_ID_MICROSOFT, 1,
54639beb93cSSam Leffler 			       EAP_TTLS_MSCHAP_RESPONSE_LEN);
54739beb93cSSam Leffler 	data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN];
54839beb93cSSam Leffler 	*pos++ = data->ident;
54939beb93cSSam Leffler 	*pos++ = 1; /* Flags: Use NT style passwords */
55039beb93cSSam Leffler 	os_memset(pos, 0, 24); /* LM-Response */
55139beb93cSSam Leffler 	pos += 24;
55239beb93cSSam Leffler 	if (pwhash) {
55339beb93cSSam Leffler 		challenge_response(challenge, password, pos); /* NT-Response */
55439beb93cSSam Leffler 		wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash",
55539beb93cSSam Leffler 				password, 16);
55639beb93cSSam Leffler 	} else {
55739beb93cSSam Leffler 		nt_challenge_response(challenge, password, password_len,
55839beb93cSSam Leffler 				      pos); /* NT-Response */
55939beb93cSSam Leffler 		wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password",
56039beb93cSSam Leffler 				      password, password_len);
56139beb93cSSam Leffler 	}
56239beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge",
56339beb93cSSam Leffler 		    challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
56439beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24);
56539beb93cSSam Leffler 	pos += 24;
56639beb93cSSam Leffler 	os_free(challenge);
56739beb93cSSam Leffler 	AVP_PAD(buf, pos);
56839beb93cSSam Leffler 
56939beb93cSSam Leffler 	wpabuf_put(msg, pos - buf);
57039beb93cSSam Leffler 	*resp = msg;
57139beb93cSSam Leffler 
57239beb93cSSam Leffler 	/* EAP-TTLS/MSCHAP does not provide tunneled success
57339beb93cSSam Leffler 	 * notification, so assume that Phase2 succeeds. */
57439beb93cSSam Leffler 	ret->methodState = METHOD_DONE;
57539beb93cSSam Leffler 	ret->decision = DECISION_COND_SUCC;
57639beb93cSSam Leffler 
57739beb93cSSam Leffler 	return 0;
57839beb93cSSam Leffler }
57939beb93cSSam Leffler 
58039beb93cSSam Leffler 
58139beb93cSSam Leffler static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
58239beb93cSSam Leffler 				       struct eap_ttls_data *data,
58339beb93cSSam Leffler 				       struct eap_method_ret *ret,
58439beb93cSSam Leffler 				       struct wpabuf **resp)
58539beb93cSSam Leffler {
58639beb93cSSam Leffler 	struct wpabuf *msg;
58739beb93cSSam Leffler 	u8 *buf, *pos;
58839beb93cSSam Leffler 	size_t pad;
58939beb93cSSam Leffler 	const u8 *identity, *password;
59039beb93cSSam Leffler 	size_t identity_len, password_len;
59139beb93cSSam Leffler 
59239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request");
59339beb93cSSam Leffler 
59439beb93cSSam Leffler 	identity = eap_get_config_identity(sm, &identity_len);
59539beb93cSSam Leffler 	password = eap_get_config_password(sm, &password_len);
59639beb93cSSam Leffler 	if (identity == NULL || password == NULL)
59739beb93cSSam Leffler 		return -1;
59839beb93cSSam Leffler 
59939beb93cSSam Leffler 	msg = wpabuf_alloc(identity_len + password_len + 100);
60039beb93cSSam Leffler 	if (msg == NULL) {
60139beb93cSSam Leffler 		wpa_printf(MSG_ERROR,
60239beb93cSSam Leffler 			   "EAP-TTLS/PAP: Failed to allocate memory");
60339beb93cSSam Leffler 		return -1;
60439beb93cSSam Leffler 	}
60539beb93cSSam Leffler 	pos = buf = wpabuf_mhead(msg);
60639beb93cSSam Leffler 
60739beb93cSSam Leffler 	/* User-Name */
60839beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
60939beb93cSSam Leffler 			       identity, identity_len);
61039beb93cSSam Leffler 
61139beb93cSSam Leffler 	/* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts
61239beb93cSSam Leffler 	 * the data, so no separate encryption is used in the AVP itself.
61339beb93cSSam Leffler 	 * However, the password is padded to obfuscate its length. */
6143157ba21SRui Paulo 	pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15;
61539beb93cSSam Leffler 	pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1,
61639beb93cSSam Leffler 			       password_len + pad);
61739beb93cSSam Leffler 	os_memcpy(pos, password, password_len);
61839beb93cSSam Leffler 	pos += password_len;
61939beb93cSSam Leffler 	os_memset(pos, 0, pad);
62039beb93cSSam Leffler 	pos += pad;
62139beb93cSSam Leffler 	AVP_PAD(buf, pos);
62239beb93cSSam Leffler 
62339beb93cSSam Leffler 	wpabuf_put(msg, pos - buf);
62439beb93cSSam Leffler 	*resp = msg;
62539beb93cSSam Leffler 
62639beb93cSSam Leffler 	/* EAP-TTLS/PAP does not provide tunneled success notification,
62739beb93cSSam Leffler 	 * so assume that Phase2 succeeds. */
62839beb93cSSam Leffler 	ret->methodState = METHOD_DONE;
62939beb93cSSam Leffler 	ret->decision = DECISION_COND_SUCC;
63039beb93cSSam Leffler 
63139beb93cSSam Leffler 	return 0;
63239beb93cSSam Leffler }
63339beb93cSSam Leffler 
63439beb93cSSam Leffler 
63539beb93cSSam Leffler static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
63639beb93cSSam Leffler 					struct eap_ttls_data *data,
63739beb93cSSam Leffler 					struct eap_method_ret *ret,
63839beb93cSSam Leffler 					struct wpabuf **resp)
63939beb93cSSam Leffler {
64039beb93cSSam Leffler 	struct wpabuf *msg;
64139beb93cSSam Leffler 	u8 *buf, *pos, *challenge;
64239beb93cSSam Leffler 	const u8 *identity, *password;
64339beb93cSSam Leffler 	size_t identity_len, password_len;
64439beb93cSSam Leffler 
64539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request");
64639beb93cSSam Leffler 
64739beb93cSSam Leffler 	identity = eap_get_config_identity(sm, &identity_len);
64839beb93cSSam Leffler 	password = eap_get_config_password(sm, &password_len);
64939beb93cSSam Leffler 	if (identity == NULL || password == NULL)
65039beb93cSSam Leffler 		return -1;
65139beb93cSSam Leffler 
65239beb93cSSam Leffler 	msg = wpabuf_alloc(identity_len + 1000);
65339beb93cSSam Leffler 	if (msg == NULL) {
65439beb93cSSam Leffler 		wpa_printf(MSG_ERROR,
65539beb93cSSam Leffler 			   "EAP-TTLS/CHAP: Failed to allocate memory");
65639beb93cSSam Leffler 		return -1;
65739beb93cSSam Leffler 	}
65839beb93cSSam Leffler 	pos = buf = wpabuf_mhead(msg);
65939beb93cSSam Leffler 
66039beb93cSSam Leffler 	/* User-Name */
66139beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
66239beb93cSSam Leffler 			       identity, identity_len);
66339beb93cSSam Leffler 
66439beb93cSSam Leffler 	/* CHAP-Challenge */
66539beb93cSSam Leffler 	challenge = eap_ttls_implicit_challenge(
66639beb93cSSam Leffler 		sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
66739beb93cSSam Leffler 	if (challenge == NULL) {
66839beb93cSSam Leffler 		wpabuf_free(msg);
66939beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive "
67039beb93cSSam Leffler 			   "implicit challenge");
67139beb93cSSam Leffler 		return -1;
67239beb93cSSam Leffler 	}
67339beb93cSSam Leffler 
67439beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1,
67539beb93cSSam Leffler 			       challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
67639beb93cSSam Leffler 
67739beb93cSSam Leffler 	/* CHAP-Password */
67839beb93cSSam Leffler 	pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1,
67939beb93cSSam Leffler 			       1 + EAP_TTLS_CHAP_PASSWORD_LEN);
68039beb93cSSam Leffler 	data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN];
68139beb93cSSam Leffler 	*pos++ = data->ident;
68239beb93cSSam Leffler 
68339beb93cSSam Leffler 	/* MD5(Ident + Password + Challenge) */
68439beb93cSSam Leffler 	chap_md5(data->ident, password, password_len, challenge,
68539beb93cSSam Leffler 		 EAP_TTLS_CHAP_CHALLENGE_LEN, pos);
68639beb93cSSam Leffler 
68739beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username",
68839beb93cSSam Leffler 			  identity, identity_len);
68939beb93cSSam Leffler 	wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password",
69039beb93cSSam Leffler 			      password, password_len);
69139beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge",
69239beb93cSSam Leffler 		    challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
69339beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password",
69439beb93cSSam Leffler 		    pos, EAP_TTLS_CHAP_PASSWORD_LEN);
69539beb93cSSam Leffler 	pos += EAP_TTLS_CHAP_PASSWORD_LEN;
69639beb93cSSam Leffler 	os_free(challenge);
69739beb93cSSam Leffler 	AVP_PAD(buf, pos);
69839beb93cSSam Leffler 
69939beb93cSSam Leffler 	wpabuf_put(msg, pos - buf);
70039beb93cSSam Leffler 	*resp = msg;
70139beb93cSSam Leffler 
70239beb93cSSam Leffler 	/* EAP-TTLS/CHAP does not provide tunneled success
70339beb93cSSam Leffler 	 * notification, so assume that Phase2 succeeds. */
70439beb93cSSam Leffler 	ret->methodState = METHOD_DONE;
70539beb93cSSam Leffler 	ret->decision = DECISION_COND_SUCC;
70639beb93cSSam Leffler 
70739beb93cSSam Leffler 	return 0;
70839beb93cSSam Leffler }
70939beb93cSSam Leffler 
71039beb93cSSam Leffler 
71139beb93cSSam Leffler static int eap_ttls_phase2_request(struct eap_sm *sm,
71239beb93cSSam Leffler 				   struct eap_ttls_data *data,
71339beb93cSSam Leffler 				   struct eap_method_ret *ret,
71439beb93cSSam Leffler 				   struct eap_hdr *hdr,
71539beb93cSSam Leffler 				   struct wpabuf **resp)
71639beb93cSSam Leffler {
71739beb93cSSam Leffler 	int res = 0;
71839beb93cSSam Leffler 	size_t len;
71939beb93cSSam Leffler 	enum phase2_types phase2_type = data->phase2_type;
72039beb93cSSam Leffler 
72139beb93cSSam Leffler #ifdef EAP_TNC
72239beb93cSSam Leffler 	if (data->tnc_started) {
72339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC");
72439beb93cSSam Leffler 		phase2_type = EAP_TTLS_PHASE2_EAP;
72539beb93cSSam Leffler 	}
72639beb93cSSam Leffler #endif /* EAP_TNC */
72739beb93cSSam Leffler 
72839beb93cSSam Leffler 	if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 ||
72939beb93cSSam Leffler 	    phase2_type == EAP_TTLS_PHASE2_MSCHAP ||
73039beb93cSSam Leffler 	    phase2_type == EAP_TTLS_PHASE2_PAP ||
73139beb93cSSam Leffler 	    phase2_type == EAP_TTLS_PHASE2_CHAP) {
73239beb93cSSam Leffler 		if (eap_get_config_identity(sm, &len) == NULL) {
73339beb93cSSam Leffler 			wpa_printf(MSG_INFO,
73439beb93cSSam Leffler 				   "EAP-TTLS: Identity not configured");
73539beb93cSSam Leffler 			eap_sm_request_identity(sm);
73639beb93cSSam Leffler 			if (eap_get_config_password(sm, &len) == NULL)
73739beb93cSSam Leffler 				eap_sm_request_password(sm);
73839beb93cSSam Leffler 			return 0;
73939beb93cSSam Leffler 		}
74039beb93cSSam Leffler 
74139beb93cSSam Leffler 		if (eap_get_config_password(sm, &len) == NULL) {
74239beb93cSSam Leffler 			wpa_printf(MSG_INFO,
74339beb93cSSam Leffler 				   "EAP-TTLS: Password not configured");
74439beb93cSSam Leffler 			eap_sm_request_password(sm);
74539beb93cSSam Leffler 			return 0;
74639beb93cSSam Leffler 		}
74739beb93cSSam Leffler 	}
74839beb93cSSam Leffler 
74939beb93cSSam Leffler 	switch (phase2_type) {
75039beb93cSSam Leffler 	case EAP_TTLS_PHASE2_EAP:
75139beb93cSSam Leffler 		res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp);
75239beb93cSSam Leffler 		break;
75339beb93cSSam Leffler 	case EAP_TTLS_PHASE2_MSCHAPV2:
75439beb93cSSam Leffler 		res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp);
75539beb93cSSam Leffler 		break;
75639beb93cSSam Leffler 	case EAP_TTLS_PHASE2_MSCHAP:
75739beb93cSSam Leffler 		res = eap_ttls_phase2_request_mschap(sm, data, ret, resp);
75839beb93cSSam Leffler 		break;
75939beb93cSSam Leffler 	case EAP_TTLS_PHASE2_PAP:
76039beb93cSSam Leffler 		res = eap_ttls_phase2_request_pap(sm, data, ret, resp);
76139beb93cSSam Leffler 		break;
76239beb93cSSam Leffler 	case EAP_TTLS_PHASE2_CHAP:
76339beb93cSSam Leffler 		res = eap_ttls_phase2_request_chap(sm, data, ret, resp);
76439beb93cSSam Leffler 		break;
76539beb93cSSam Leffler 	default:
76639beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown");
76739beb93cSSam Leffler 		res = -1;
76839beb93cSSam Leffler 		break;
76939beb93cSSam Leffler 	}
77039beb93cSSam Leffler 
77139beb93cSSam Leffler 	if (res < 0) {
77239beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
77339beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
77439beb93cSSam Leffler 	}
77539beb93cSSam Leffler 
77639beb93cSSam Leffler 	return res;
77739beb93cSSam Leffler }
77839beb93cSSam Leffler 
77939beb93cSSam Leffler 
78039beb93cSSam Leffler struct ttls_parse_avp {
78139beb93cSSam Leffler 	u8 *mschapv2;
78239beb93cSSam Leffler 	u8 *eapdata;
78339beb93cSSam Leffler 	size_t eap_len;
78439beb93cSSam Leffler 	int mschapv2_error;
78539beb93cSSam Leffler };
78639beb93cSSam Leffler 
78739beb93cSSam Leffler 
78839beb93cSSam Leffler static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen,
78939beb93cSSam Leffler 				   struct ttls_parse_avp *parse)
79039beb93cSSam Leffler {
79139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message");
79239beb93cSSam Leffler 	if (parse->eapdata == NULL) {
79339beb93cSSam Leffler 		parse->eapdata = os_malloc(dlen);
79439beb93cSSam Leffler 		if (parse->eapdata == NULL) {
79539beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
79639beb93cSSam Leffler 				   "memory for Phase 2 EAP data");
79739beb93cSSam Leffler 			return -1;
79839beb93cSSam Leffler 		}
79939beb93cSSam Leffler 		os_memcpy(parse->eapdata, dpos, dlen);
80039beb93cSSam Leffler 		parse->eap_len = dlen;
80139beb93cSSam Leffler 	} else {
80239beb93cSSam Leffler 		u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen);
80339beb93cSSam Leffler 		if (neweap == NULL) {
80439beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
80539beb93cSSam Leffler 				   "memory for Phase 2 EAP data");
80639beb93cSSam Leffler 			return -1;
80739beb93cSSam Leffler 		}
80839beb93cSSam Leffler 		os_memcpy(neweap + parse->eap_len, dpos, dlen);
80939beb93cSSam Leffler 		parse->eapdata = neweap;
81039beb93cSSam Leffler 		parse->eap_len += dlen;
81139beb93cSSam Leffler 	}
81239beb93cSSam Leffler 
81339beb93cSSam Leffler 	return 0;
81439beb93cSSam Leffler }
81539beb93cSSam Leffler 
81639beb93cSSam Leffler 
81739beb93cSSam Leffler static int eap_ttls_parse_avp(u8 *pos, size_t left,
81839beb93cSSam Leffler 			      struct ttls_parse_avp *parse)
81939beb93cSSam Leffler {
82039beb93cSSam Leffler 	struct ttls_avp *avp;
82139beb93cSSam Leffler 	u32 avp_code, avp_length, vendor_id = 0;
82239beb93cSSam Leffler 	u8 avp_flags, *dpos;
82339beb93cSSam Leffler 	size_t dlen;
82439beb93cSSam Leffler 
82539beb93cSSam Leffler 	avp = (struct ttls_avp *) pos;
82639beb93cSSam Leffler 	avp_code = be_to_host32(avp->avp_code);
82739beb93cSSam Leffler 	avp_length = be_to_host32(avp->avp_length);
82839beb93cSSam Leffler 	avp_flags = (avp_length >> 24) & 0xff;
82939beb93cSSam Leffler 	avp_length &= 0xffffff;
83039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x "
83139beb93cSSam Leffler 		   "length=%d", (int) avp_code, avp_flags,
83239beb93cSSam Leffler 		   (int) avp_length);
83339beb93cSSam Leffler 
83439beb93cSSam Leffler 	if (avp_length > left) {
83539beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow "
83639beb93cSSam Leffler 			   "(len=%d, left=%lu) - dropped",
83739beb93cSSam Leffler 			   (int) avp_length, (unsigned long) left);
83839beb93cSSam Leffler 		return -1;
83939beb93cSSam Leffler 	}
84039beb93cSSam Leffler 
84139beb93cSSam Leffler 	if (avp_length < sizeof(*avp)) {
84239beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d",
84339beb93cSSam Leffler 			   avp_length);
84439beb93cSSam Leffler 		return -1;
84539beb93cSSam Leffler 	}
84639beb93cSSam Leffler 
84739beb93cSSam Leffler 	dpos = (u8 *) (avp + 1);
84839beb93cSSam Leffler 	dlen = avp_length - sizeof(*avp);
84939beb93cSSam Leffler 	if (avp_flags & AVP_FLAGS_VENDOR) {
85039beb93cSSam Leffler 		if (dlen < 4) {
85139beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "EAP-TTLS: Vendor AVP "
85239beb93cSSam Leffler 				   "underflow");
85339beb93cSSam Leffler 			return -1;
85439beb93cSSam Leffler 		}
85539beb93cSSam Leffler 		vendor_id = WPA_GET_BE32(dpos);
85639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d",
85739beb93cSSam Leffler 			   (int) vendor_id);
85839beb93cSSam Leffler 		dpos += 4;
85939beb93cSSam Leffler 		dlen -= 4;
86039beb93cSSam Leffler 	}
86139beb93cSSam Leffler 
86239beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen);
86339beb93cSSam Leffler 
86439beb93cSSam Leffler 	if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) {
86539beb93cSSam Leffler 		if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0)
86639beb93cSSam Leffler 			return -1;
86739beb93cSSam Leffler 	} else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) {
86839beb93cSSam Leffler 		/* This is an optional message that can be displayed to
86939beb93cSSam Leffler 		 * the user. */
87039beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message",
87139beb93cSSam Leffler 				  dpos, dlen);
87239beb93cSSam Leffler 	} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
87339beb93cSSam Leffler 		   avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) {
87439beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success",
87539beb93cSSam Leffler 				  dpos, dlen);
87639beb93cSSam Leffler 		if (dlen != 43) {
87739beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected "
87839beb93cSSam Leffler 				   "MS-CHAP2-Success length "
87939beb93cSSam Leffler 				   "(len=%lu, expected 43)",
88039beb93cSSam Leffler 				   (unsigned long) dlen);
88139beb93cSSam Leffler 			return -1;
88239beb93cSSam Leffler 		}
88339beb93cSSam Leffler 		parse->mschapv2 = dpos;
88439beb93cSSam Leffler 	} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
88539beb93cSSam Leffler 		   avp_code == RADIUS_ATTR_MS_CHAP_ERROR) {
88639beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error",
88739beb93cSSam Leffler 				  dpos, dlen);
88839beb93cSSam Leffler 		parse->mschapv2_error = 1;
88939beb93cSSam Leffler 	} else if (avp_flags & AVP_FLAGS_MANDATORY) {
89039beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported mandatory AVP "
89139beb93cSSam Leffler 			   "code %d vendor_id %d - dropped",
89239beb93cSSam Leffler 			   (int) avp_code, (int) vendor_id);
89339beb93cSSam Leffler 		return -1;
89439beb93cSSam Leffler 	} else {
89539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP "
89639beb93cSSam Leffler 			   "code %d vendor_id %d",
89739beb93cSSam Leffler 			   (int) avp_code, (int) vendor_id);
89839beb93cSSam Leffler 	}
89939beb93cSSam Leffler 
90039beb93cSSam Leffler 	return avp_length;
90139beb93cSSam Leffler }
90239beb93cSSam Leffler 
90339beb93cSSam Leffler 
90439beb93cSSam Leffler static int eap_ttls_parse_avps(struct wpabuf *in_decrypted,
90539beb93cSSam Leffler 			       struct ttls_parse_avp *parse)
90639beb93cSSam Leffler {
90739beb93cSSam Leffler 	u8 *pos;
90839beb93cSSam Leffler 	size_t left, pad;
90939beb93cSSam Leffler 	int avp_length;
91039beb93cSSam Leffler 
91139beb93cSSam Leffler 	pos = wpabuf_mhead(in_decrypted);
91239beb93cSSam Leffler 	left = wpabuf_len(in_decrypted);
91339beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left);
91439beb93cSSam Leffler 	if (left < sizeof(struct ttls_avp)) {
91539beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame"
91639beb93cSSam Leffler 			   " len=%lu expected %lu or more - dropped",
91739beb93cSSam Leffler 			   (unsigned long) left,
91839beb93cSSam Leffler 			   (unsigned long) sizeof(struct ttls_avp));
91939beb93cSSam Leffler 		return -1;
92039beb93cSSam Leffler 	}
92139beb93cSSam Leffler 
92239beb93cSSam Leffler 	/* Parse AVPs */
92339beb93cSSam Leffler 	os_memset(parse, 0, sizeof(*parse));
92439beb93cSSam Leffler 
92539beb93cSSam Leffler 	while (left > 0) {
92639beb93cSSam Leffler 		avp_length = eap_ttls_parse_avp(pos, left, parse);
92739beb93cSSam Leffler 		if (avp_length < 0)
92839beb93cSSam Leffler 			return -1;
92939beb93cSSam Leffler 
93039beb93cSSam Leffler 		pad = (4 - (avp_length & 3)) & 3;
93139beb93cSSam Leffler 		pos += avp_length + pad;
93239beb93cSSam Leffler 		if (left < avp_length + pad)
93339beb93cSSam Leffler 			left = 0;
93439beb93cSSam Leffler 		else
93539beb93cSSam Leffler 			left -= avp_length + pad;
93639beb93cSSam Leffler 	}
93739beb93cSSam Leffler 
93839beb93cSSam Leffler 	return 0;
93939beb93cSSam Leffler }
94039beb93cSSam Leffler 
94139beb93cSSam Leffler 
94239beb93cSSam Leffler static u8 * eap_ttls_fake_identity_request(void)
94339beb93cSSam Leffler {
94439beb93cSSam Leffler 	struct eap_hdr *hdr;
94539beb93cSSam Leffler 	u8 *buf;
94639beb93cSSam Leffler 
94739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of "
94839beb93cSSam Leffler 		   "Phase 2 - use fake EAP-Request Identity");
94939beb93cSSam Leffler 	buf = os_malloc(sizeof(*hdr) + 1);
95039beb93cSSam Leffler 	if (buf == NULL) {
95139beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate "
95239beb93cSSam Leffler 			   "memory for fake EAP-Identity Request");
95339beb93cSSam Leffler 		return NULL;
95439beb93cSSam Leffler 	}
95539beb93cSSam Leffler 
95639beb93cSSam Leffler 	hdr = (struct eap_hdr *) buf;
95739beb93cSSam Leffler 	hdr->code = EAP_CODE_REQUEST;
95839beb93cSSam Leffler 	hdr->identifier = 0;
95939beb93cSSam Leffler 	hdr->length = host_to_be16(sizeof(*hdr) + 1);
96039beb93cSSam Leffler 	buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY;
96139beb93cSSam Leffler 
96239beb93cSSam Leffler 	return buf;
96339beb93cSSam Leffler }
96439beb93cSSam Leffler 
96539beb93cSSam Leffler 
96639beb93cSSam Leffler static int eap_ttls_encrypt_response(struct eap_sm *sm,
96739beb93cSSam Leffler 				     struct eap_ttls_data *data,
96839beb93cSSam Leffler 				     struct wpabuf *resp, u8 identifier,
96939beb93cSSam Leffler 				     struct wpabuf **out_data)
97039beb93cSSam Leffler {
97139beb93cSSam Leffler 	if (resp == NULL)
97239beb93cSSam Leffler 		return 0;
97339beb93cSSam Leffler 
97439beb93cSSam Leffler 	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data",
97539beb93cSSam Leffler 			    resp);
97639beb93cSSam Leffler 	if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS,
97739beb93cSSam Leffler 				 data->ttls_version, identifier,
97839beb93cSSam Leffler 				 resp, out_data)) {
97939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 "
98039beb93cSSam Leffler 			   "frame");
98139beb93cSSam Leffler 		return -1;
98239beb93cSSam Leffler 	}
98339beb93cSSam Leffler 	wpabuf_free(resp);
98439beb93cSSam Leffler 
98539beb93cSSam Leffler 	return 0;
98639beb93cSSam Leffler }
98739beb93cSSam Leffler 
98839beb93cSSam Leffler 
98939beb93cSSam Leffler static int eap_ttls_process_phase2_eap(struct eap_sm *sm,
99039beb93cSSam Leffler 				       struct eap_ttls_data *data,
99139beb93cSSam Leffler 				       struct eap_method_ret *ret,
99239beb93cSSam Leffler 				       struct ttls_parse_avp *parse,
99339beb93cSSam Leffler 				       struct wpabuf **resp)
99439beb93cSSam Leffler {
99539beb93cSSam Leffler 	struct eap_hdr *hdr;
99639beb93cSSam Leffler 	size_t len;
99739beb93cSSam Leffler 
99839beb93cSSam Leffler 	if (parse->eapdata == NULL) {
99939beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the "
100039beb93cSSam Leffler 			   "packet - dropped");
100139beb93cSSam Leffler 		return -1;
100239beb93cSSam Leffler 	}
100339beb93cSSam Leffler 
100439beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP",
100539beb93cSSam Leffler 		    parse->eapdata, parse->eap_len);
100639beb93cSSam Leffler 	hdr = (struct eap_hdr *) parse->eapdata;
100739beb93cSSam Leffler 
100839beb93cSSam Leffler 	if (parse->eap_len < sizeof(*hdr)) {
100939beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP "
101039beb93cSSam Leffler 			   "frame (len=%lu, expected %lu or more) - dropped",
101139beb93cSSam Leffler 			   (unsigned long) parse->eap_len,
101239beb93cSSam Leffler 			   (unsigned long) sizeof(*hdr));
101339beb93cSSam Leffler 		return -1;
101439beb93cSSam Leffler 	}
101539beb93cSSam Leffler 	len = be_to_host16(hdr->length);
101639beb93cSSam Leffler 	if (len > parse->eap_len) {
101739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 "
101839beb93cSSam Leffler 			   "EAP frame (EAP hdr len=%lu, EAP data len in "
101939beb93cSSam Leffler 			   "AVP=%lu)",
102039beb93cSSam Leffler 			   (unsigned long) len,
102139beb93cSSam Leffler 			   (unsigned long) parse->eap_len);
102239beb93cSSam Leffler 		return -1;
102339beb93cSSam Leffler 	}
102439beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d "
102539beb93cSSam Leffler 		   "identifier=%d length=%lu",
102639beb93cSSam Leffler 		   hdr->code, hdr->identifier, (unsigned long) len);
102739beb93cSSam Leffler 	switch (hdr->code) {
102839beb93cSSam Leffler 	case EAP_CODE_REQUEST:
102939beb93cSSam Leffler 		if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) {
103039beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request "
103139beb93cSSam Leffler 				   "processing failed");
103239beb93cSSam Leffler 			return -1;
103339beb93cSSam Leffler 		}
103439beb93cSSam Leffler 		break;
103539beb93cSSam Leffler 	default:
103639beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in "
103739beb93cSSam Leffler 			   "Phase 2 EAP header", hdr->code);
103839beb93cSSam Leffler 		return -1;
103939beb93cSSam Leffler 	}
104039beb93cSSam Leffler 
104139beb93cSSam Leffler 	return 0;
104239beb93cSSam Leffler }
104339beb93cSSam Leffler 
104439beb93cSSam Leffler 
104539beb93cSSam Leffler static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
104639beb93cSSam Leffler 					    struct eap_ttls_data *data,
104739beb93cSSam Leffler 					    struct eap_method_ret *ret,
104839beb93cSSam Leffler 					    struct ttls_parse_avp *parse)
104939beb93cSSam Leffler {
1050*f05cddf9SRui Paulo #ifdef EAP_MSCHAPv2
105139beb93cSSam Leffler 	if (parse->mschapv2_error) {
105239beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received "
105339beb93cSSam Leffler 			   "MS-CHAP-Error - failed");
105439beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
105539beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
105639beb93cSSam Leffler 		/* Reply with empty data to ACK error */
105739beb93cSSam Leffler 		return 1;
105839beb93cSSam Leffler 	}
105939beb93cSSam Leffler 
106039beb93cSSam Leffler 	if (parse->mschapv2 == NULL) {
106139beb93cSSam Leffler #ifdef EAP_TNC
106239beb93cSSam Leffler 		if (data->phase2_success && parse->eapdata) {
106339beb93cSSam Leffler 			/*
106439beb93cSSam Leffler 			 * Allow EAP-TNC to be started after successfully
106539beb93cSSam Leffler 			 * completed MSCHAPV2.
106639beb93cSSam Leffler 			 */
106739beb93cSSam Leffler 			return 1;
106839beb93cSSam Leffler 		}
106939beb93cSSam Leffler #endif /* EAP_TNC */
107039beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP "
107139beb93cSSam Leffler 			   "received for Phase2 MSCHAPV2");
107239beb93cSSam Leffler 		return -1;
107339beb93cSSam Leffler 	}
107439beb93cSSam Leffler 	if (parse->mschapv2[0] != data->ident) {
107539beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 "
107639beb93cSSam Leffler 			   "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)",
107739beb93cSSam Leffler 			   parse->mschapv2[0], data->ident);
107839beb93cSSam Leffler 		return -1;
107939beb93cSSam Leffler 	}
108039beb93cSSam Leffler 	if (!data->auth_response_valid ||
108139beb93cSSam Leffler 	    mschapv2_verify_auth_response(data->auth_response,
108239beb93cSSam Leffler 					  parse->mschapv2 + 1, 42)) {
108339beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator "
108439beb93cSSam Leffler 			   "response in Phase 2 MSCHAPV2 success request");
108539beb93cSSam Leffler 		return -1;
108639beb93cSSam Leffler 	}
108739beb93cSSam Leffler 
108839beb93cSSam Leffler 	wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 "
108939beb93cSSam Leffler 		   "authentication succeeded");
109039beb93cSSam Leffler 	ret->methodState = METHOD_DONE;
109139beb93cSSam Leffler 	ret->decision = DECISION_UNCOND_SUCC;
109239beb93cSSam Leffler 	data->phase2_success = 1;
109339beb93cSSam Leffler 
109439beb93cSSam Leffler 	/*
109539beb93cSSam Leffler 	 * Reply with empty data; authentication server will reply
109639beb93cSSam Leffler 	 * with EAP-Success after this.
109739beb93cSSam Leffler 	 */
109839beb93cSSam Leffler 	return 1;
1099*f05cddf9SRui Paulo #else /* EAP_MSCHAPv2 */
1100*f05cddf9SRui Paulo 	wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
1101*f05cddf9SRui Paulo 	return -1;
1102*f05cddf9SRui Paulo #endif /* EAP_MSCHAPv2 */
110339beb93cSSam Leffler }
110439beb93cSSam Leffler 
110539beb93cSSam Leffler 
110639beb93cSSam Leffler #ifdef EAP_TNC
110739beb93cSSam Leffler static int eap_ttls_process_tnc_start(struct eap_sm *sm,
110839beb93cSSam Leffler 				      struct eap_ttls_data *data,
110939beb93cSSam Leffler 				      struct eap_method_ret *ret,
111039beb93cSSam Leffler 				      struct ttls_parse_avp *parse,
111139beb93cSSam Leffler 				      struct wpabuf **resp)
111239beb93cSSam Leffler {
111339beb93cSSam Leffler 	/* TNC uses inner EAP method after non-EAP TTLS phase 2. */
111439beb93cSSam Leffler 	if (parse->eapdata == NULL) {
111539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received "
111639beb93cSSam Leffler 			   "unexpected tunneled data (no EAP)");
111739beb93cSSam Leffler 		return -1;
111839beb93cSSam Leffler 	}
111939beb93cSSam Leffler 
112039beb93cSSam Leffler 	if (!data->ready_for_tnc) {
112139beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received "
112239beb93cSSam Leffler 			   "EAP after non-EAP, but not ready for TNC");
112339beb93cSSam Leffler 		return -1;
112439beb93cSSam Leffler 	}
112539beb93cSSam Leffler 
112639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
112739beb93cSSam Leffler 		   "non-EAP method");
112839beb93cSSam Leffler 	data->tnc_started = 1;
112939beb93cSSam Leffler 
113039beb93cSSam Leffler 	if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0)
113139beb93cSSam Leffler 		return -1;
113239beb93cSSam Leffler 
113339beb93cSSam Leffler 	return 0;
113439beb93cSSam Leffler }
113539beb93cSSam Leffler #endif /* EAP_TNC */
113639beb93cSSam Leffler 
113739beb93cSSam Leffler 
113839beb93cSSam Leffler static int eap_ttls_process_decrypted(struct eap_sm *sm,
113939beb93cSSam Leffler 				      struct eap_ttls_data *data,
114039beb93cSSam Leffler 				      struct eap_method_ret *ret,
114139beb93cSSam Leffler 				      u8 identifier,
114239beb93cSSam Leffler 				      struct ttls_parse_avp *parse,
114339beb93cSSam Leffler 				      struct wpabuf *in_decrypted,
114439beb93cSSam Leffler 				      struct wpabuf **out_data)
114539beb93cSSam Leffler {
114639beb93cSSam Leffler 	struct wpabuf *resp = NULL;
114739beb93cSSam Leffler 	struct eap_peer_config *config = eap_get_config(sm);
114839beb93cSSam Leffler 	int res;
114939beb93cSSam Leffler 	enum phase2_types phase2_type = data->phase2_type;
115039beb93cSSam Leffler 
115139beb93cSSam Leffler #ifdef EAP_TNC
115239beb93cSSam Leffler 	if (data->tnc_started)
115339beb93cSSam Leffler 		phase2_type = EAP_TTLS_PHASE2_EAP;
115439beb93cSSam Leffler #endif /* EAP_TNC */
115539beb93cSSam Leffler 
115639beb93cSSam Leffler 	switch (phase2_type) {
115739beb93cSSam Leffler 	case EAP_TTLS_PHASE2_EAP:
115839beb93cSSam Leffler 		if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) <
115939beb93cSSam Leffler 		    0)
116039beb93cSSam Leffler 			return -1;
116139beb93cSSam Leffler 		break;
116239beb93cSSam Leffler 	case EAP_TTLS_PHASE2_MSCHAPV2:
116339beb93cSSam Leffler 		res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse);
116439beb93cSSam Leffler #ifdef EAP_TNC
116539beb93cSSam Leffler 		if (res == 1 && parse->eapdata && data->phase2_success) {
116639beb93cSSam Leffler 			/*
116739beb93cSSam Leffler 			 * TNC may be required as the next
116839beb93cSSam Leffler 			 * authentication method within the tunnel.
116939beb93cSSam Leffler 			 */
117039beb93cSSam Leffler 			ret->methodState = METHOD_MAY_CONT;
117139beb93cSSam Leffler 			data->ready_for_tnc = 1;
117239beb93cSSam Leffler 			if (eap_ttls_process_tnc_start(sm, data, ret, parse,
117339beb93cSSam Leffler 						       &resp) == 0)
117439beb93cSSam Leffler 				break;
117539beb93cSSam Leffler 		}
117639beb93cSSam Leffler #endif /* EAP_TNC */
117739beb93cSSam Leffler 		return res;
117839beb93cSSam Leffler 	case EAP_TTLS_PHASE2_MSCHAP:
117939beb93cSSam Leffler 	case EAP_TTLS_PHASE2_PAP:
118039beb93cSSam Leffler 	case EAP_TTLS_PHASE2_CHAP:
118139beb93cSSam Leffler #ifdef EAP_TNC
118239beb93cSSam Leffler 		if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) <
118339beb93cSSam Leffler 		    0)
118439beb93cSSam Leffler 			return -1;
118539beb93cSSam Leffler 		break;
118639beb93cSSam Leffler #else /* EAP_TNC */
118739beb93cSSam Leffler 		/* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled
118839beb93cSSam Leffler 		 * requests to the supplicant */
118939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected "
119039beb93cSSam Leffler 			   "tunneled data");
119139beb93cSSam Leffler 		return -1;
119239beb93cSSam Leffler #endif /* EAP_TNC */
119339beb93cSSam Leffler 	}
119439beb93cSSam Leffler 
119539beb93cSSam Leffler 	if (resp) {
119639beb93cSSam Leffler 		if (eap_ttls_encrypt_response(sm, data, resp, identifier,
119739beb93cSSam Leffler 					      out_data) < 0)
119839beb93cSSam Leffler 			return -1;
119939beb93cSSam Leffler 	} else if (config->pending_req_identity ||
120039beb93cSSam Leffler 		   config->pending_req_password ||
120139beb93cSSam Leffler 		   config->pending_req_otp ||
120239beb93cSSam Leffler 		   config->pending_req_new_password) {
120339beb93cSSam Leffler 		wpabuf_free(data->pending_phase2_req);
120439beb93cSSam Leffler 		data->pending_phase2_req = wpabuf_dup(in_decrypted);
120539beb93cSSam Leffler 	}
120639beb93cSSam Leffler 
120739beb93cSSam Leffler 	return 0;
120839beb93cSSam Leffler }
120939beb93cSSam Leffler 
121039beb93cSSam Leffler 
121139beb93cSSam Leffler static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
121239beb93cSSam Leffler 					      struct eap_ttls_data *data,
121339beb93cSSam Leffler 					      struct eap_method_ret *ret,
121439beb93cSSam Leffler 					      u8 identifier,
121539beb93cSSam Leffler 					      struct wpabuf **out_data)
121639beb93cSSam Leffler {
121739beb93cSSam Leffler 	int retval = 0;
121839beb93cSSam Leffler 	struct eap_hdr *hdr;
121939beb93cSSam Leffler 	struct wpabuf *resp;
122039beb93cSSam Leffler 
122139beb93cSSam Leffler 	hdr = (struct eap_hdr *) eap_ttls_fake_identity_request();
122239beb93cSSam Leffler 	if (hdr == NULL) {
122339beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
122439beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
122539beb93cSSam Leffler 		return -1;
122639beb93cSSam Leffler 	}
122739beb93cSSam Leffler 
122839beb93cSSam Leffler 	resp = NULL;
122939beb93cSSam Leffler 	if (eap_ttls_phase2_request(sm, data, ret, hdr, &resp)) {
123039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request "
123139beb93cSSam Leffler 			   "processing failed");
123239beb93cSSam Leffler 		retval = -1;
123339beb93cSSam Leffler 	} else {
1234*f05cddf9SRui Paulo 		struct eap_peer_config *config = eap_get_config(sm);
1235*f05cddf9SRui Paulo 		if (resp == NULL &&
1236*f05cddf9SRui Paulo 		    (config->pending_req_identity ||
1237*f05cddf9SRui Paulo 		     config->pending_req_password ||
1238*f05cddf9SRui Paulo 		     config->pending_req_otp ||
1239*f05cddf9SRui Paulo 		     config->pending_req_new_password)) {
1240*f05cddf9SRui Paulo 			/*
1241*f05cddf9SRui Paulo 			 * Use empty buffer to force implicit request
1242*f05cddf9SRui Paulo 			 * processing when EAP request is re-processed after
1243*f05cddf9SRui Paulo 			 * user input.
1244*f05cddf9SRui Paulo 			 */
1245*f05cddf9SRui Paulo 			wpabuf_free(data->pending_phase2_req);
1246*f05cddf9SRui Paulo 			data->pending_phase2_req = wpabuf_alloc(0);
1247*f05cddf9SRui Paulo 		}
1248*f05cddf9SRui Paulo 
124939beb93cSSam Leffler 		retval = eap_ttls_encrypt_response(sm, data, resp, identifier,
125039beb93cSSam Leffler 						   out_data);
125139beb93cSSam Leffler 	}
125239beb93cSSam Leffler 
125339beb93cSSam Leffler 	os_free(hdr);
125439beb93cSSam Leffler 
125539beb93cSSam Leffler 	if (retval < 0) {
125639beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
125739beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
125839beb93cSSam Leffler 	}
125939beb93cSSam Leffler 
126039beb93cSSam Leffler 	return retval;
126139beb93cSSam Leffler }
126239beb93cSSam Leffler 
126339beb93cSSam Leffler 
126439beb93cSSam Leffler static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data,
126539beb93cSSam Leffler 				 struct eap_method_ret *ret, u8 identifier,
126639beb93cSSam Leffler 				 struct wpabuf **out_data)
126739beb93cSSam Leffler {
126839beb93cSSam Leffler 	data->phase2_start = 0;
126939beb93cSSam Leffler 
127039beb93cSSam Leffler 	/*
127139beb93cSSam Leffler 	 * EAP-TTLS does not use Phase2 on fast re-auth; this must be done only
127239beb93cSSam Leffler 	 * if TLS part was indeed resuming a previous session. Most
127339beb93cSSam Leffler 	 * Authentication Servers terminate EAP-TTLS before reaching this
127439beb93cSSam Leffler 	 * point, but some do not. Make wpa_supplicant stop phase 2 here, if
127539beb93cSSam Leffler 	 * needed.
127639beb93cSSam Leffler 	 */
127739beb93cSSam Leffler 	if (data->reauth &&
127839beb93cSSam Leffler 	    tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
127939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - "
128039beb93cSSam Leffler 			   "skip phase 2");
128139beb93cSSam Leffler 		*out_data = eap_peer_tls_build_ack(identifier, EAP_TYPE_TTLS,
128239beb93cSSam Leffler 						   data->ttls_version);
128339beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
128439beb93cSSam Leffler 		ret->decision = DECISION_UNCOND_SUCC;
128539beb93cSSam Leffler 		data->phase2_success = 1;
128639beb93cSSam Leffler 		return 0;
128739beb93cSSam Leffler 	}
128839beb93cSSam Leffler 
128939beb93cSSam Leffler 	return eap_ttls_implicit_identity_request(sm, data, ret, identifier,
129039beb93cSSam Leffler 						  out_data);
129139beb93cSSam Leffler }
129239beb93cSSam Leffler 
129339beb93cSSam Leffler 
129439beb93cSSam Leffler static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
129539beb93cSSam Leffler 			    struct eap_method_ret *ret, u8 identifier,
129639beb93cSSam Leffler 			    const struct wpabuf *in_data,
129739beb93cSSam Leffler 			    struct wpabuf **out_data)
129839beb93cSSam Leffler {
129939beb93cSSam Leffler 	struct wpabuf *in_decrypted = NULL;
130039beb93cSSam Leffler 	int retval = 0;
130139beb93cSSam Leffler 	struct ttls_parse_avp parse;
130239beb93cSSam Leffler 
130339beb93cSSam Leffler 	os_memset(&parse, 0, sizeof(parse));
130439beb93cSSam Leffler 
130539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
130639beb93cSSam Leffler 		   " Phase 2",
130739beb93cSSam Leffler 		   in_data ? (unsigned long) wpabuf_len(in_data) : 0);
130839beb93cSSam Leffler 
130939beb93cSSam Leffler 	if (data->pending_phase2_req) {
131039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - "
131139beb93cSSam Leffler 			   "skip decryption and use old data");
131239beb93cSSam Leffler 		/* Clear TLS reassembly state. */
131339beb93cSSam Leffler 		eap_peer_tls_reset_input(&data->ssl);
131439beb93cSSam Leffler 
131539beb93cSSam Leffler 		in_decrypted = data->pending_phase2_req;
131639beb93cSSam Leffler 		data->pending_phase2_req = NULL;
131739beb93cSSam Leffler 		if (wpabuf_len(in_decrypted) == 0) {
131839beb93cSSam Leffler 			wpabuf_free(in_decrypted);
131939beb93cSSam Leffler 			return eap_ttls_implicit_identity_request(
132039beb93cSSam Leffler 				sm, data, ret, identifier, out_data);
132139beb93cSSam Leffler 		}
132239beb93cSSam Leffler 		goto continue_req;
132339beb93cSSam Leffler 	}
132439beb93cSSam Leffler 
132539beb93cSSam Leffler 	if ((in_data == NULL || wpabuf_len(in_data) == 0) &&
132639beb93cSSam Leffler 	    data->phase2_start) {
132739beb93cSSam Leffler 		return eap_ttls_phase2_start(sm, data, ret, identifier,
132839beb93cSSam Leffler 					     out_data);
132939beb93cSSam Leffler 	}
133039beb93cSSam Leffler 
133139beb93cSSam Leffler 	if (in_data == NULL || wpabuf_len(in_data) == 0) {
133239beb93cSSam Leffler 		/* Received TLS ACK - requesting more fragments */
133339beb93cSSam Leffler 		return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS,
133439beb93cSSam Leffler 					    data->ttls_version,
133539beb93cSSam Leffler 					    identifier, NULL, out_data);
133639beb93cSSam Leffler 	}
133739beb93cSSam Leffler 
133839beb93cSSam Leffler 	retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
133939beb93cSSam Leffler 	if (retval)
134039beb93cSSam Leffler 		goto done;
134139beb93cSSam Leffler 
134239beb93cSSam Leffler continue_req:
134339beb93cSSam Leffler 	data->phase2_start = 0;
134439beb93cSSam Leffler 
134539beb93cSSam Leffler 	if (eap_ttls_parse_avps(in_decrypted, &parse) < 0) {
134639beb93cSSam Leffler 		retval = -1;
134739beb93cSSam Leffler 		goto done;
134839beb93cSSam Leffler 	}
134939beb93cSSam Leffler 
135039beb93cSSam Leffler 	retval = eap_ttls_process_decrypted(sm, data, ret, identifier,
135139beb93cSSam Leffler 					    &parse, in_decrypted, out_data);
135239beb93cSSam Leffler 
135339beb93cSSam Leffler done:
135439beb93cSSam Leffler 	wpabuf_free(in_decrypted);
135539beb93cSSam Leffler 	os_free(parse.eapdata);
135639beb93cSSam Leffler 
135739beb93cSSam Leffler 	if (retval < 0) {
135839beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
135939beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
136039beb93cSSam Leffler 	}
136139beb93cSSam Leffler 
136239beb93cSSam Leffler 	return retval;
136339beb93cSSam Leffler }
136439beb93cSSam Leffler 
136539beb93cSSam Leffler 
136639beb93cSSam Leffler static int eap_ttls_process_handshake(struct eap_sm *sm,
136739beb93cSSam Leffler 				      struct eap_ttls_data *data,
136839beb93cSSam Leffler 				      struct eap_method_ret *ret,
136939beb93cSSam Leffler 				      u8 identifier,
137039beb93cSSam Leffler 				      const u8 *in_data, size_t in_len,
137139beb93cSSam Leffler 				      struct wpabuf **out_data)
137239beb93cSSam Leffler {
137339beb93cSSam Leffler 	int res;
137439beb93cSSam Leffler 
137539beb93cSSam Leffler 	res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
137639beb93cSSam Leffler 					  data->ttls_version, identifier,
137739beb93cSSam Leffler 					  in_data, in_len, out_data);
137839beb93cSSam Leffler 
137939beb93cSSam Leffler 	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
138039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to "
138139beb93cSSam Leffler 			   "Phase 2");
138239beb93cSSam Leffler 		if (data->resuming) {
138339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth - may "
138439beb93cSSam Leffler 				   "skip Phase 2");
138539beb93cSSam Leffler 			ret->decision = DECISION_COND_SUCC;
138639beb93cSSam Leffler 			ret->methodState = METHOD_MAY_CONT;
138739beb93cSSam Leffler 		}
138839beb93cSSam Leffler 		data->phase2_start = 1;
138939beb93cSSam Leffler 		eap_ttls_v0_derive_key(sm, data);
139039beb93cSSam Leffler 
139139beb93cSSam Leffler 		if (*out_data == NULL || wpabuf_len(*out_data) == 0) {
139239beb93cSSam Leffler 			if (eap_ttls_decrypt(sm, data, ret, identifier,
139339beb93cSSam Leffler 					     NULL, out_data)) {
139439beb93cSSam Leffler 				wpa_printf(MSG_WARNING, "EAP-TTLS: "
139539beb93cSSam Leffler 					   "failed to process early "
139639beb93cSSam Leffler 					   "start for Phase 2");
139739beb93cSSam Leffler 			}
139839beb93cSSam Leffler 			res = 0;
139939beb93cSSam Leffler 		}
140039beb93cSSam Leffler 		data->resuming = 0;
140139beb93cSSam Leffler 	}
140239beb93cSSam Leffler 
140339beb93cSSam Leffler 	if (res == 2) {
140439beb93cSSam Leffler 		struct wpabuf msg;
140539beb93cSSam Leffler 		/*
140639beb93cSSam Leffler 		 * Application data included in the handshake message.
140739beb93cSSam Leffler 		 */
140839beb93cSSam Leffler 		wpabuf_free(data->pending_phase2_req);
140939beb93cSSam Leffler 		data->pending_phase2_req = *out_data;
141039beb93cSSam Leffler 		*out_data = NULL;
141139beb93cSSam Leffler 		wpabuf_set(&msg, in_data, in_len);
141239beb93cSSam Leffler 		res = eap_ttls_decrypt(sm, data, ret, identifier, &msg,
141339beb93cSSam Leffler 				       out_data);
141439beb93cSSam Leffler 	}
141539beb93cSSam Leffler 
141639beb93cSSam Leffler 	return res;
141739beb93cSSam Leffler }
141839beb93cSSam Leffler 
141939beb93cSSam Leffler 
142039beb93cSSam Leffler static void eap_ttls_check_auth_status(struct eap_sm *sm,
142139beb93cSSam Leffler 				       struct eap_ttls_data *data,
142239beb93cSSam Leffler 				       struct eap_method_ret *ret)
142339beb93cSSam Leffler {
1424*f05cddf9SRui Paulo 	if (ret->methodState == METHOD_DONE) {
142539beb93cSSam Leffler 		ret->allowNotifications = FALSE;
142639beb93cSSam Leffler 		if (ret->decision == DECISION_UNCOND_SUCC ||
142739beb93cSSam Leffler 		    ret->decision == DECISION_COND_SUCC) {
142839beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
142939beb93cSSam Leffler 				   "completed successfully");
143039beb93cSSam Leffler 			data->phase2_success = 1;
143139beb93cSSam Leffler #ifdef EAP_TNC
143239beb93cSSam Leffler 			if (!data->ready_for_tnc && !data->tnc_started) {
143339beb93cSSam Leffler 				/*
143439beb93cSSam Leffler 				 * TNC may be required as the next
143539beb93cSSam Leffler 				 * authentication method within the tunnel.
143639beb93cSSam Leffler 				 */
143739beb93cSSam Leffler 				ret->methodState = METHOD_MAY_CONT;
143839beb93cSSam Leffler 				data->ready_for_tnc = 1;
143939beb93cSSam Leffler 			}
144039beb93cSSam Leffler #endif /* EAP_TNC */
144139beb93cSSam Leffler 		}
1442*f05cddf9SRui Paulo 	} else if (ret->methodState == METHOD_MAY_CONT &&
144339beb93cSSam Leffler 		   (ret->decision == DECISION_UNCOND_SUCC ||
144439beb93cSSam Leffler 		    ret->decision == DECISION_COND_SUCC)) {
144539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
144639beb93cSSam Leffler 				   "completed successfully (MAY_CONT)");
144739beb93cSSam Leffler 			data->phase2_success = 1;
144839beb93cSSam Leffler 	}
144939beb93cSSam Leffler }
145039beb93cSSam Leffler 
145139beb93cSSam Leffler 
145239beb93cSSam Leffler static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv,
145339beb93cSSam Leffler 					struct eap_method_ret *ret,
145439beb93cSSam Leffler 					const struct wpabuf *reqData)
145539beb93cSSam Leffler {
145639beb93cSSam Leffler 	size_t left;
145739beb93cSSam Leffler 	int res;
145839beb93cSSam Leffler 	u8 flags, id;
145939beb93cSSam Leffler 	struct wpabuf *resp;
146039beb93cSSam Leffler 	const u8 *pos;
146139beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
146239beb93cSSam Leffler 
146339beb93cSSam Leffler 	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret,
146439beb93cSSam Leffler 					reqData, &left, &flags);
146539beb93cSSam Leffler 	if (pos == NULL)
146639beb93cSSam Leffler 		return NULL;
146739beb93cSSam Leffler 	id = eap_get_id(reqData);
146839beb93cSSam Leffler 
146939beb93cSSam Leffler 	if (flags & EAP_TLS_FLAGS_START) {
1470*f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own "
1471*f05cddf9SRui Paulo 			   "ver=%d)", flags & EAP_TLS_VERSION_MASK,
1472*f05cddf9SRui Paulo 			   data->ttls_version);
147339beb93cSSam Leffler 
147439beb93cSSam Leffler 		/* RFC 5281, Ch. 9.2:
147539beb93cSSam Leffler 		 * "This packet MAY contain additional information in the form
147639beb93cSSam Leffler 		 * of AVPs, which may provide useful hints to the client"
147739beb93cSSam Leffler 		 * For now, ignore any potential extra data.
147839beb93cSSam Leffler 		 */
147939beb93cSSam Leffler 		left = 0;
148039beb93cSSam Leffler 	}
148139beb93cSSam Leffler 
148239beb93cSSam Leffler 	resp = NULL;
148339beb93cSSam Leffler 	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
148439beb93cSSam Leffler 	    !data->resuming) {
148539beb93cSSam Leffler 		struct wpabuf msg;
148639beb93cSSam Leffler 		wpabuf_set(&msg, pos, left);
148739beb93cSSam Leffler 		res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp);
148839beb93cSSam Leffler 	} else {
148939beb93cSSam Leffler 		res = eap_ttls_process_handshake(sm, data, ret, id,
149039beb93cSSam Leffler 						 pos, left, &resp);
149139beb93cSSam Leffler 	}
149239beb93cSSam Leffler 
149339beb93cSSam Leffler 	eap_ttls_check_auth_status(sm, data, ret);
149439beb93cSSam Leffler 
149539beb93cSSam Leffler 	/* FIX: what about res == -1? Could just move all error processing into
149639beb93cSSam Leffler 	 * the other functions and get rid of this res==1 case here. */
149739beb93cSSam Leffler 	if (res == 1) {
149839beb93cSSam Leffler 		wpabuf_free(resp);
149939beb93cSSam Leffler 		return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS,
150039beb93cSSam Leffler 					      data->ttls_version);
150139beb93cSSam Leffler 	}
150239beb93cSSam Leffler 	return resp;
150339beb93cSSam Leffler }
150439beb93cSSam Leffler 
150539beb93cSSam Leffler 
150639beb93cSSam Leffler static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)
150739beb93cSSam Leffler {
150839beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
150939beb93cSSam Leffler 	return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
151039beb93cSSam Leffler 		data->phase2_success;
151139beb93cSSam Leffler }
151239beb93cSSam Leffler 
151339beb93cSSam Leffler 
151439beb93cSSam Leffler static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
151539beb93cSSam Leffler {
151639beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
151739beb93cSSam Leffler 	wpabuf_free(data->pending_phase2_req);
151839beb93cSSam Leffler 	data->pending_phase2_req = NULL;
151939beb93cSSam Leffler #ifdef EAP_TNC
152039beb93cSSam Leffler 	data->ready_for_tnc = 0;
152139beb93cSSam Leffler 	data->tnc_started = 0;
152239beb93cSSam Leffler #endif /* EAP_TNC */
152339beb93cSSam Leffler }
152439beb93cSSam Leffler 
152539beb93cSSam Leffler 
152639beb93cSSam Leffler static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)
152739beb93cSSam Leffler {
152839beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
152939beb93cSSam Leffler 	os_free(data->key_data);
153039beb93cSSam Leffler 	data->key_data = NULL;
153139beb93cSSam Leffler 	if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
153239beb93cSSam Leffler 		os_free(data);
153339beb93cSSam Leffler 		return NULL;
153439beb93cSSam Leffler 	}
153539beb93cSSam Leffler 	if (data->phase2_priv && data->phase2_method &&
153639beb93cSSam Leffler 	    data->phase2_method->init_for_reauth)
153739beb93cSSam Leffler 		data->phase2_method->init_for_reauth(sm, data->phase2_priv);
153839beb93cSSam Leffler 	data->phase2_start = 0;
153939beb93cSSam Leffler 	data->phase2_success = 0;
154039beb93cSSam Leffler 	data->resuming = 1;
154139beb93cSSam Leffler 	data->reauth = 1;
154239beb93cSSam Leffler 	return priv;
154339beb93cSSam Leffler }
154439beb93cSSam Leffler 
154539beb93cSSam Leffler 
154639beb93cSSam Leffler static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf,
154739beb93cSSam Leffler 			       size_t buflen, int verbose)
154839beb93cSSam Leffler {
154939beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
155039beb93cSSam Leffler 	int len, ret;
155139beb93cSSam Leffler 
155239beb93cSSam Leffler 	len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
155339beb93cSSam Leffler 	ret = os_snprintf(buf + len, buflen - len,
155439beb93cSSam Leffler 			  "EAP-TTLSv%d Phase2 method=",
155539beb93cSSam Leffler 			  data->ttls_version);
155639beb93cSSam Leffler 	if (ret < 0 || (size_t) ret >= buflen - len)
155739beb93cSSam Leffler 		return len;
155839beb93cSSam Leffler 	len += ret;
155939beb93cSSam Leffler 	switch (data->phase2_type) {
156039beb93cSSam Leffler 	case EAP_TTLS_PHASE2_EAP:
156139beb93cSSam Leffler 		ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n",
156239beb93cSSam Leffler 				  data->phase2_method ?
156339beb93cSSam Leffler 				  data->phase2_method->name : "?");
156439beb93cSSam Leffler 		break;
156539beb93cSSam Leffler 	case EAP_TTLS_PHASE2_MSCHAPV2:
156639beb93cSSam Leffler 		ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n");
156739beb93cSSam Leffler 		break;
156839beb93cSSam Leffler 	case EAP_TTLS_PHASE2_MSCHAP:
156939beb93cSSam Leffler 		ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n");
157039beb93cSSam Leffler 		break;
157139beb93cSSam Leffler 	case EAP_TTLS_PHASE2_PAP:
157239beb93cSSam Leffler 		ret = os_snprintf(buf + len, buflen - len, "PAP\n");
157339beb93cSSam Leffler 		break;
157439beb93cSSam Leffler 	case EAP_TTLS_PHASE2_CHAP:
157539beb93cSSam Leffler 		ret = os_snprintf(buf + len, buflen - len, "CHAP\n");
157639beb93cSSam Leffler 		break;
157739beb93cSSam Leffler 	default:
157839beb93cSSam Leffler 		ret = 0;
157939beb93cSSam Leffler 		break;
158039beb93cSSam Leffler 	}
158139beb93cSSam Leffler 	if (ret < 0 || (size_t) ret >= buflen - len)
158239beb93cSSam Leffler 		return len;
158339beb93cSSam Leffler 	len += ret;
158439beb93cSSam Leffler 
158539beb93cSSam Leffler 	return len;
158639beb93cSSam Leffler }
158739beb93cSSam Leffler 
158839beb93cSSam Leffler 
158939beb93cSSam Leffler static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv)
159039beb93cSSam Leffler {
159139beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
159239beb93cSSam Leffler 	return data->key_data != NULL && data->phase2_success;
159339beb93cSSam Leffler }
159439beb93cSSam Leffler 
159539beb93cSSam Leffler 
159639beb93cSSam Leffler static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
159739beb93cSSam Leffler {
159839beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
159939beb93cSSam Leffler 	u8 *key;
160039beb93cSSam Leffler 
160139beb93cSSam Leffler 	if (data->key_data == NULL || !data->phase2_success)
160239beb93cSSam Leffler 		return NULL;
160339beb93cSSam Leffler 
160439beb93cSSam Leffler 	key = os_malloc(EAP_TLS_KEY_LEN);
160539beb93cSSam Leffler 	if (key == NULL)
160639beb93cSSam Leffler 		return NULL;
160739beb93cSSam Leffler 
160839beb93cSSam Leffler 	*len = EAP_TLS_KEY_LEN;
160939beb93cSSam Leffler 	os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
161039beb93cSSam Leffler 
161139beb93cSSam Leffler 	return key;
161239beb93cSSam Leffler }
161339beb93cSSam Leffler 
161439beb93cSSam Leffler 
161539beb93cSSam Leffler int eap_peer_ttls_register(void)
161639beb93cSSam Leffler {
161739beb93cSSam Leffler 	struct eap_method *eap;
161839beb93cSSam Leffler 	int ret;
161939beb93cSSam Leffler 
162039beb93cSSam Leffler 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
162139beb93cSSam Leffler 				    EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
162239beb93cSSam Leffler 	if (eap == NULL)
162339beb93cSSam Leffler 		return -1;
162439beb93cSSam Leffler 
162539beb93cSSam Leffler 	eap->init = eap_ttls_init;
162639beb93cSSam Leffler 	eap->deinit = eap_ttls_deinit;
162739beb93cSSam Leffler 	eap->process = eap_ttls_process;
162839beb93cSSam Leffler 	eap->isKeyAvailable = eap_ttls_isKeyAvailable;
162939beb93cSSam Leffler 	eap->getKey = eap_ttls_getKey;
163039beb93cSSam Leffler 	eap->get_status = eap_ttls_get_status;
163139beb93cSSam Leffler 	eap->has_reauth_data = eap_ttls_has_reauth_data;
163239beb93cSSam Leffler 	eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;
163339beb93cSSam Leffler 	eap->init_for_reauth = eap_ttls_init_for_reauth;
163439beb93cSSam Leffler 
163539beb93cSSam Leffler 	ret = eap_peer_method_register(eap);
163639beb93cSSam Leffler 	if (ret)
163739beb93cSSam Leffler 		eap_peer_method_free(eap);
163839beb93cSSam Leffler 	return ret;
163939beb93cSSam Leffler }
1640