xref: /freebsd/contrib/wpa/src/eap_peer/eap_ttls.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * EAP peer method: EAP-TTLS (RFC 5281)
3780fb4a2SCy Schubert  * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui 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 
23f05cddf9SRui 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 
32f05cddf9SRui 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;
38780fb4a2SCy Schubert 	EapDecision decision_succ;
3939beb93cSSam Leffler 
4039beb93cSSam Leffler 	enum phase2_types {
4139beb93cSSam Leffler 		EAP_TTLS_PHASE2_EAP,
4239beb93cSSam Leffler 		EAP_TTLS_PHASE2_MSCHAPV2,
4339beb93cSSam Leffler 		EAP_TTLS_PHASE2_MSCHAP,
4439beb93cSSam Leffler 		EAP_TTLS_PHASE2_PAP,
4539beb93cSSam Leffler 		EAP_TTLS_PHASE2_CHAP
4639beb93cSSam Leffler 	} phase2_type;
4739beb93cSSam Leffler 	struct eap_method_type phase2_eap_type;
4839beb93cSSam Leffler 	struct eap_method_type *phase2_eap_types;
4939beb93cSSam Leffler 	size_t num_phase2_eap_types;
5039beb93cSSam Leffler 
5139beb93cSSam Leffler 	u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];
5239beb93cSSam Leffler 	int auth_response_valid;
5339beb93cSSam Leffler 	u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */
5439beb93cSSam Leffler 	u8 ident;
5539beb93cSSam Leffler 	int resuming; /* starting a resumed session */
5639beb93cSSam Leffler 	int reauth; /* reauthentication */
5739beb93cSSam Leffler 	u8 *key_data;
585b9c547cSRui Paulo 	u8 *session_id;
595b9c547cSRui Paulo 	size_t id_len;
6039beb93cSSam Leffler 
6139beb93cSSam Leffler 	struct wpabuf *pending_phase2_req;
62780fb4a2SCy Schubert 	struct wpabuf *pending_resp;
6339beb93cSSam Leffler 
6439beb93cSSam Leffler #ifdef EAP_TNC
6539beb93cSSam Leffler 	int ready_for_tnc;
6639beb93cSSam Leffler 	int tnc_started;
6739beb93cSSam Leffler #endif /* EAP_TNC */
68*a90b9d01SCy Schubert 
69*a90b9d01SCy Schubert 	enum { NO_AUTH, FOR_INITIAL, ALWAYS } phase2_auth;
7039beb93cSSam Leffler };
7139beb93cSSam Leffler 
7239beb93cSSam Leffler 
eap_ttls_parse_phase1(struct eap_ttls_data * data,const char * phase1)73*a90b9d01SCy Schubert static void eap_ttls_parse_phase1(struct eap_ttls_data *data,
74*a90b9d01SCy Schubert 				  const char *phase1)
75*a90b9d01SCy Schubert {
76*a90b9d01SCy Schubert 	if (os_strstr(phase1, "phase2_auth=0")) {
77*a90b9d01SCy Schubert 		data->phase2_auth = NO_AUTH;
78*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
79*a90b9d01SCy Schubert 			   "EAP-TTLS: Do not require Phase 2 authentication");
80*a90b9d01SCy Schubert 	} else if (os_strstr(phase1, "phase2_auth=1")) {
81*a90b9d01SCy Schubert 		data->phase2_auth = FOR_INITIAL;
82*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
83*a90b9d01SCy Schubert 			   "EAP-TTLS: Require Phase 2 authentication for initial connection");
84*a90b9d01SCy Schubert 	} else if (os_strstr(phase1, "phase2_auth=2")) {
85*a90b9d01SCy Schubert 		data->phase2_auth = ALWAYS;
86*a90b9d01SCy Schubert 		wpa_printf(MSG_DEBUG,
87*a90b9d01SCy Schubert 			   "EAP-TTLS: Require Phase 2 authentication for all cases");
88*a90b9d01SCy Schubert 	}
89*a90b9d01SCy Schubert }
90*a90b9d01SCy Schubert 
91*a90b9d01SCy Schubert 
eap_ttls_init(struct eap_sm * sm)9239beb93cSSam Leffler static void * eap_ttls_init(struct eap_sm *sm)
9339beb93cSSam Leffler {
9439beb93cSSam Leffler 	struct eap_ttls_data *data;
9539beb93cSSam Leffler 	struct eap_peer_config *config = eap_get_config(sm);
96780fb4a2SCy Schubert 	int selected_non_eap;
9739beb93cSSam Leffler 	char *selected;
9839beb93cSSam Leffler 
9939beb93cSSam Leffler 	data = os_zalloc(sizeof(*data));
10039beb93cSSam Leffler 	if (data == NULL)
10139beb93cSSam Leffler 		return NULL;
10239beb93cSSam Leffler 	data->ttls_version = EAP_TTLS_VERSION;
10339beb93cSSam Leffler 	selected = "EAP";
104780fb4a2SCy Schubert 	selected_non_eap = 0;
10539beb93cSSam Leffler 	data->phase2_type = EAP_TTLS_PHASE2_EAP;
106*a90b9d01SCy Schubert 	data->phase2_auth = FOR_INITIAL;
107*a90b9d01SCy Schubert 
108*a90b9d01SCy Schubert 	if (config && config->phase1)
109*a90b9d01SCy Schubert 		eap_ttls_parse_phase1(data, config->phase1);
11039beb93cSSam Leffler 
111780fb4a2SCy Schubert 	/*
112780fb4a2SCy Schubert 	 * Either one auth= type or one or more autheap= methods can be
113780fb4a2SCy Schubert 	 * specified.
114780fb4a2SCy Schubert 	 */
11539beb93cSSam Leffler 	if (config && config->phase2) {
116780fb4a2SCy Schubert 		const char *token, *last = NULL;
117780fb4a2SCy Schubert 
118780fb4a2SCy Schubert 		while ((token = cstr_token(config->phase2, " \t", &last))) {
119780fb4a2SCy Schubert 			if (os_strncmp(token, "auth=", 5) != 0)
120780fb4a2SCy Schubert 				continue;
121780fb4a2SCy Schubert 			token += 5;
122780fb4a2SCy Schubert 
123780fb4a2SCy Schubert 			if (last - token == 8 &&
124780fb4a2SCy Schubert 			    os_strncmp(token, "MSCHAPV2", 8) == 0) {
12539beb93cSSam Leffler 				selected = "MSCHAPV2";
12639beb93cSSam Leffler 				data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
127780fb4a2SCy Schubert 			} else if (last - token == 6 &&
128780fb4a2SCy Schubert 				   os_strncmp(token, "MSCHAP", 6) == 0) {
12939beb93cSSam Leffler 				selected = "MSCHAP";
13039beb93cSSam Leffler 				data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
131780fb4a2SCy Schubert 			} else if (last - token == 3 &&
132780fb4a2SCy Schubert 				   os_strncmp(token, "PAP", 3) == 0) {
13339beb93cSSam Leffler 				selected = "PAP";
13439beb93cSSam Leffler 				data->phase2_type = EAP_TTLS_PHASE2_PAP;
135780fb4a2SCy Schubert 			} else if (last - token == 4 &&
136780fb4a2SCy Schubert 				   os_strncmp(token, "CHAP", 4) == 0) {
13739beb93cSSam Leffler 				selected = "CHAP";
13839beb93cSSam Leffler 				data->phase2_type = EAP_TTLS_PHASE2_CHAP;
139780fb4a2SCy Schubert 			} else {
140780fb4a2SCy Schubert 				wpa_printf(MSG_ERROR,
141780fb4a2SCy Schubert 					   "EAP-TTLS: Unsupported Phase2 type '%s'",
142780fb4a2SCy Schubert 					   token);
143780fb4a2SCy Schubert 				eap_ttls_deinit(sm, data);
144780fb4a2SCy Schubert 				return NULL;
145780fb4a2SCy Schubert 			}
146780fb4a2SCy Schubert 
147780fb4a2SCy Schubert 			if (selected_non_eap) {
148780fb4a2SCy Schubert 				wpa_printf(MSG_ERROR,
149780fb4a2SCy Schubert 					   "EAP-TTLS: Only one Phase2 type can be specified");
150780fb4a2SCy Schubert 				eap_ttls_deinit(sm, data);
151780fb4a2SCy Schubert 				return NULL;
152780fb4a2SCy Schubert 			}
153780fb4a2SCy Schubert 
154780fb4a2SCy Schubert 			selected_non_eap = 1;
155780fb4a2SCy Schubert 		}
156780fb4a2SCy Schubert 
157780fb4a2SCy Schubert 		if (os_strstr(config->phase2, "autheap=")) {
158780fb4a2SCy Schubert 			if (selected_non_eap) {
159780fb4a2SCy Schubert 				wpa_printf(MSG_ERROR,
160780fb4a2SCy Schubert 					   "EAP-TTLS: Both auth= and autheap= params cannot be specified");
161780fb4a2SCy Schubert 				eap_ttls_deinit(sm, data);
162780fb4a2SCy Schubert 				return NULL;
163780fb4a2SCy Schubert 			}
164780fb4a2SCy Schubert 			selected = "EAP";
165780fb4a2SCy Schubert 			data->phase2_type = EAP_TTLS_PHASE2_EAP;
16639beb93cSSam Leffler 		}
16739beb93cSSam Leffler 	}
168780fb4a2SCy Schubert 
16939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected);
17039beb93cSSam Leffler 
17139beb93cSSam Leffler 	if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
17239beb93cSSam Leffler 		if (eap_peer_select_phase2_methods(config, "autheap=",
17339beb93cSSam Leffler 						   &data->phase2_eap_types,
174c1d255d3SCy Schubert 						   &data->num_phase2_eap_types,
175c1d255d3SCy Schubert 						   0) < 0) {
17639beb93cSSam Leffler 			eap_ttls_deinit(sm, data);
17739beb93cSSam Leffler 			return NULL;
17839beb93cSSam Leffler 		}
17939beb93cSSam Leffler 
18039beb93cSSam Leffler 		data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
18139beb93cSSam Leffler 		data->phase2_eap_type.method = EAP_TYPE_NONE;
18239beb93cSSam Leffler 	}
18339beb93cSSam Leffler 
184f05cddf9SRui Paulo 	if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) {
185f05cddf9SRui Paulo 		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
18639beb93cSSam Leffler 		eap_ttls_deinit(sm, data);
18739beb93cSSam Leffler 		return NULL;
18839beb93cSSam Leffler 	}
18939beb93cSSam Leffler 
19039beb93cSSam Leffler 	return data;
19139beb93cSSam Leffler }
19239beb93cSSam Leffler 
19339beb93cSSam Leffler 
eap_ttls_phase2_eap_deinit(struct eap_sm * sm,struct eap_ttls_data * data)19439beb93cSSam Leffler static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm,
19539beb93cSSam Leffler 				       struct eap_ttls_data *data)
19639beb93cSSam Leffler {
19739beb93cSSam Leffler 	if (data->phase2_priv && data->phase2_method) {
19839beb93cSSam Leffler 		data->phase2_method->deinit(sm, data->phase2_priv);
19939beb93cSSam Leffler 		data->phase2_method = NULL;
20039beb93cSSam Leffler 		data->phase2_priv = NULL;
20139beb93cSSam Leffler 	}
20239beb93cSSam Leffler }
20339beb93cSSam Leffler 
20439beb93cSSam Leffler 
eap_ttls_free_key(struct eap_ttls_data * data)2055b9c547cSRui Paulo static void eap_ttls_free_key(struct eap_ttls_data *data)
2065b9c547cSRui Paulo {
2075b9c547cSRui Paulo 	if (data->key_data) {
2085b9c547cSRui Paulo 		bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
2095b9c547cSRui Paulo 		data->key_data = NULL;
2105b9c547cSRui Paulo 	}
2115b9c547cSRui Paulo }
2125b9c547cSRui Paulo 
2135b9c547cSRui Paulo 
eap_ttls_deinit(struct eap_sm * sm,void * priv)21439beb93cSSam Leffler static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
21539beb93cSSam Leffler {
21639beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
21739beb93cSSam Leffler 	if (data == NULL)
21839beb93cSSam Leffler 		return;
21939beb93cSSam Leffler 	eap_ttls_phase2_eap_deinit(sm, data);
22039beb93cSSam Leffler 	os_free(data->phase2_eap_types);
22139beb93cSSam Leffler 	eap_peer_tls_ssl_deinit(sm, &data->ssl);
2225b9c547cSRui Paulo 	eap_ttls_free_key(data);
2235b9c547cSRui Paulo 	os_free(data->session_id);
2244bc52338SCy Schubert 	wpabuf_clear_free(data->pending_phase2_req);
2254bc52338SCy Schubert 	wpabuf_clear_free(data->pending_resp);
22639beb93cSSam Leffler 	os_free(data);
22739beb93cSSam Leffler }
22839beb93cSSam Leffler 
22939beb93cSSam Leffler 
eap_ttls_avp_hdr(u8 * avphdr,u32 avp_code,u32 vendor_id,int mandatory,size_t len)23039beb93cSSam Leffler static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,
23139beb93cSSam Leffler 			     int mandatory, size_t len)
23239beb93cSSam Leffler {
23339beb93cSSam Leffler 	struct ttls_avp_vendor *avp;
23439beb93cSSam Leffler 	u8 flags;
23539beb93cSSam Leffler 	size_t hdrlen;
23639beb93cSSam Leffler 
23739beb93cSSam Leffler 	avp = (struct ttls_avp_vendor *) avphdr;
23839beb93cSSam Leffler 	flags = mandatory ? AVP_FLAGS_MANDATORY : 0;
23939beb93cSSam Leffler 	if (vendor_id) {
24039beb93cSSam Leffler 		flags |= AVP_FLAGS_VENDOR;
24139beb93cSSam Leffler 		hdrlen = sizeof(*avp);
24239beb93cSSam Leffler 		avp->vendor_id = host_to_be32(vendor_id);
24339beb93cSSam Leffler 	} else {
24439beb93cSSam Leffler 		hdrlen = sizeof(struct ttls_avp);
24539beb93cSSam Leffler 	}
24639beb93cSSam Leffler 
24739beb93cSSam Leffler 	avp->avp_code = host_to_be32(avp_code);
248325151a3SRui Paulo 	avp->avp_length = host_to_be32(((u32) flags << 24) |
249325151a3SRui Paulo 				       (u32) (hdrlen + len));
25039beb93cSSam Leffler 
25139beb93cSSam Leffler 	return avphdr + hdrlen;
25239beb93cSSam Leffler }
25339beb93cSSam Leffler 
25439beb93cSSam Leffler 
eap_ttls_avp_add(u8 * start,u8 * avphdr,u32 avp_code,u32 vendor_id,int mandatory,const u8 * data,size_t len)25539beb93cSSam Leffler static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code,
25639beb93cSSam Leffler 			     u32 vendor_id, int mandatory,
25739beb93cSSam Leffler 			     const u8 *data, size_t len)
25839beb93cSSam Leffler {
25939beb93cSSam Leffler 	u8 *pos;
26039beb93cSSam Leffler 	pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len);
26139beb93cSSam Leffler 	os_memcpy(pos, data, len);
26239beb93cSSam Leffler 	pos += len;
26339beb93cSSam Leffler 	AVP_PAD(start, pos);
26439beb93cSSam Leffler 	return pos;
26539beb93cSSam Leffler }
26639beb93cSSam Leffler 
26739beb93cSSam Leffler 
eap_ttls_avp_encapsulate(struct wpabuf ** resp,u32 avp_code,int mandatory)26839beb93cSSam Leffler static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
26939beb93cSSam Leffler 				    int mandatory)
27039beb93cSSam Leffler {
27139beb93cSSam Leffler 	struct wpabuf *msg;
27239beb93cSSam Leffler 	u8 *avp, *pos;
27339beb93cSSam Leffler 
27439beb93cSSam Leffler 	msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4);
27539beb93cSSam Leffler 	if (msg == NULL) {
2764bc52338SCy Schubert 		wpabuf_clear_free(*resp);
27739beb93cSSam Leffler 		*resp = NULL;
27839beb93cSSam Leffler 		return -1;
27939beb93cSSam Leffler 	}
28039beb93cSSam Leffler 
28139beb93cSSam Leffler 	avp = wpabuf_mhead(msg);
28239beb93cSSam Leffler 	pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp));
28339beb93cSSam Leffler 	os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp));
28439beb93cSSam Leffler 	pos += wpabuf_len(*resp);
28539beb93cSSam Leffler 	AVP_PAD(avp, pos);
2864bc52338SCy Schubert 	wpabuf_clear_free(*resp);
28739beb93cSSam Leffler 	wpabuf_put(msg, pos - avp);
28839beb93cSSam Leffler 	*resp = msg;
28939beb93cSSam Leffler 	return 0;
29039beb93cSSam Leffler }
29139beb93cSSam Leffler 
29239beb93cSSam Leffler 
eap_ttls_v0_derive_key(struct eap_sm * sm,struct eap_ttls_data * data)29339beb93cSSam Leffler static int eap_ttls_v0_derive_key(struct eap_sm *sm,
29439beb93cSSam Leffler 				  struct eap_ttls_data *data)
29539beb93cSSam Leffler {
296c1d255d3SCy Schubert 	const char *label;
297c1d255d3SCy Schubert 	const u8 eap_tls13_context[1] = { EAP_TYPE_TTLS };
298c1d255d3SCy Schubert 	const u8 *context = NULL;
299c1d255d3SCy Schubert 	size_t context_len = 0;
300c1d255d3SCy Schubert 
301c1d255d3SCy Schubert 	if (data->ssl.tls_v13) {
302c1d255d3SCy Schubert 		label = "EXPORTER_EAP_TLS_Key_Material";
303c1d255d3SCy Schubert 		context = eap_tls13_context;
304c1d255d3SCy Schubert 		context_len = sizeof(eap_tls13_context);
305c1d255d3SCy Schubert 	} else {
306c1d255d3SCy Schubert 		label = "ttls keying material";
307c1d255d3SCy Schubert 	}
308c1d255d3SCy Schubert 
3095b9c547cSRui Paulo 	eap_ttls_free_key(data);
310c1d255d3SCy Schubert 	data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, label,
311c1d255d3SCy Schubert 						 context, context_len,
3125b9c547cSRui Paulo 						 EAP_TLS_KEY_LEN +
3135b9c547cSRui Paulo 						 EAP_EMSK_LEN);
31439beb93cSSam Leffler 	if (!data->key_data) {
31539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key");
31639beb93cSSam Leffler 		return -1;
31739beb93cSSam Leffler 	}
31839beb93cSSam Leffler 
31939beb93cSSam Leffler 	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
32039beb93cSSam Leffler 			data->key_data, EAP_TLS_KEY_LEN);
3215b9c547cSRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK",
3225b9c547cSRui Paulo 			data->key_data + EAP_TLS_KEY_LEN,
3235b9c547cSRui Paulo 			EAP_EMSK_LEN);
3245b9c547cSRui Paulo 
3255b9c547cSRui Paulo 	os_free(data->session_id);
3265b9c547cSRui Paulo 	data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
3275b9c547cSRui Paulo 							  EAP_TYPE_TTLS,
3285b9c547cSRui Paulo 	                                                  &data->id_len);
3295b9c547cSRui Paulo 	if (data->session_id) {
3305b9c547cSRui Paulo 		wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id",
3315b9c547cSRui Paulo 			    data->session_id, data->id_len);
3325b9c547cSRui Paulo 	} else {
3335b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id");
3345b9c547cSRui Paulo 	}
33539beb93cSSam Leffler 
33639beb93cSSam Leffler 	return 0;
33739beb93cSSam Leffler }
33839beb93cSSam Leffler 
33939beb93cSSam Leffler 
340325151a3SRui Paulo #ifndef CONFIG_FIPS
eap_ttls_implicit_challenge(struct eap_sm * sm,struct eap_ttls_data * data,size_t len)34139beb93cSSam Leffler static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
34239beb93cSSam Leffler 					struct eap_ttls_data *data, size_t len)
34339beb93cSSam Leffler {
3444bc52338SCy Schubert 	return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge",
3454bc52338SCy Schubert 				       NULL, 0, len);
34639beb93cSSam Leffler }
347325151a3SRui Paulo #endif /* CONFIG_FIPS */
34839beb93cSSam Leffler 
34939beb93cSSam Leffler 
eap_ttls_phase2_select_eap_method(struct eap_ttls_data * data,int vendor,enum eap_type method)35039beb93cSSam Leffler static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data,
351c1d255d3SCy Schubert 					      int vendor, enum eap_type method)
35239beb93cSSam Leffler {
35339beb93cSSam Leffler 	size_t i;
35439beb93cSSam Leffler 	for (i = 0; i < data->num_phase2_eap_types; i++) {
355c1d255d3SCy Schubert 		if (data->phase2_eap_types[i].vendor != vendor ||
35639beb93cSSam Leffler 		    data->phase2_eap_types[i].method != method)
35739beb93cSSam Leffler 			continue;
35839beb93cSSam Leffler 
35939beb93cSSam Leffler 		data->phase2_eap_type.vendor =
36039beb93cSSam Leffler 			data->phase2_eap_types[i].vendor;
36139beb93cSSam Leffler 		data->phase2_eap_type.method =
36239beb93cSSam Leffler 			data->phase2_eap_types[i].method;
36339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
36439beb93cSSam Leffler 			   "Phase 2 EAP vendor %d method %d",
36539beb93cSSam Leffler 			   data->phase2_eap_type.vendor,
36639beb93cSSam Leffler 			   data->phase2_eap_type.method);
36739beb93cSSam Leffler 		break;
36839beb93cSSam Leffler 	}
36939beb93cSSam Leffler }
37039beb93cSSam Leffler 
37139beb93cSSam Leffler 
eap_ttls_phase2_eap_process(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,struct eap_hdr * hdr,size_t len,struct wpabuf ** resp)37239beb93cSSam Leffler static int eap_ttls_phase2_eap_process(struct eap_sm *sm,
37339beb93cSSam Leffler 				       struct eap_ttls_data *data,
37439beb93cSSam Leffler 				       struct eap_method_ret *ret,
37539beb93cSSam Leffler 				       struct eap_hdr *hdr, size_t len,
37639beb93cSSam Leffler 				       struct wpabuf **resp)
37739beb93cSSam Leffler {
37839beb93cSSam Leffler 	struct wpabuf msg;
37939beb93cSSam Leffler 	struct eap_method_ret iret;
38039beb93cSSam Leffler 
38139beb93cSSam Leffler 	os_memset(&iret, 0, sizeof(iret));
38239beb93cSSam Leffler 	wpabuf_set(&msg, hdr, len);
38339beb93cSSam Leffler 	*resp = data->phase2_method->process(sm, data->phase2_priv, &iret,
38439beb93cSSam Leffler 					     &msg);
38539beb93cSSam Leffler 	if ((iret.methodState == METHOD_DONE ||
38639beb93cSSam Leffler 	     iret.methodState == METHOD_MAY_CONT) &&
38739beb93cSSam Leffler 	    (iret.decision == DECISION_UNCOND_SUCC ||
38839beb93cSSam Leffler 	     iret.decision == DECISION_COND_SUCC ||
38939beb93cSSam Leffler 	     iret.decision == DECISION_FAIL)) {
39039beb93cSSam Leffler 		ret->methodState = iret.methodState;
39139beb93cSSam Leffler 		ret->decision = iret.decision;
39239beb93cSSam Leffler 	}
39339beb93cSSam Leffler 
39439beb93cSSam Leffler 	return 0;
39539beb93cSSam Leffler }
39639beb93cSSam Leffler 
39739beb93cSSam Leffler 
eap_ttls_phase2_request_eap_method(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,struct eap_hdr * hdr,size_t len,int vendor,enum eap_type method,struct wpabuf ** resp)39839beb93cSSam Leffler static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm,
39939beb93cSSam Leffler 					      struct eap_ttls_data *data,
40039beb93cSSam Leffler 					      struct eap_method_ret *ret,
40139beb93cSSam Leffler 					      struct eap_hdr *hdr, size_t len,
402c1d255d3SCy Schubert 					      int vendor, enum eap_type method,
403c1d255d3SCy Schubert 					      struct wpabuf **resp)
40439beb93cSSam Leffler {
40539beb93cSSam Leffler #ifdef EAP_TNC
40639beb93cSSam Leffler 	if (data->tnc_started && data->phase2_method &&
407c1d255d3SCy Schubert 	    data->phase2_priv &&
408c1d255d3SCy Schubert 	    vendor == EAP_VENDOR_IETF && method == EAP_TYPE_TNC &&
40939beb93cSSam Leffler 	    data->phase2_eap_type.method == EAP_TYPE_TNC)
41039beb93cSSam Leffler 		return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len,
41139beb93cSSam Leffler 						   resp);
41239beb93cSSam Leffler 
41339beb93cSSam Leffler 	if (data->ready_for_tnc && !data->tnc_started &&
414c1d255d3SCy Schubert 	    vendor == EAP_VENDOR_IETF && method == EAP_TYPE_TNC) {
41539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
41639beb93cSSam Leffler 			   "EAP method");
41739beb93cSSam Leffler 		data->tnc_started = 1;
41839beb93cSSam Leffler 	}
41939beb93cSSam Leffler 
42039beb93cSSam Leffler 	if (data->tnc_started) {
42139beb93cSSam Leffler 		if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF ||
42239beb93cSSam Leffler 		    data->phase2_eap_type.method == EAP_TYPE_TNC) {
42339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP "
42439beb93cSSam Leffler 				   "type %d for TNC", method);
42539beb93cSSam Leffler 			return -1;
42639beb93cSSam Leffler 		}
42739beb93cSSam Leffler 
428c1d255d3SCy Schubert 		data->phase2_eap_type.vendor = vendor;
42939beb93cSSam Leffler 		data->phase2_eap_type.method = method;
43039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
43139beb93cSSam Leffler 			   "Phase 2 EAP vendor %d method %d (TNC)",
43239beb93cSSam Leffler 			   data->phase2_eap_type.vendor,
43339beb93cSSam Leffler 			   data->phase2_eap_type.method);
43439beb93cSSam Leffler 
43539beb93cSSam Leffler 		if (data->phase2_type == EAP_TTLS_PHASE2_EAP)
43639beb93cSSam Leffler 			eap_ttls_phase2_eap_deinit(sm, data);
43739beb93cSSam Leffler 	}
43839beb93cSSam Leffler #endif /* EAP_TNC */
43939beb93cSSam Leffler 
44039beb93cSSam Leffler 	if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF &&
44139beb93cSSam Leffler 	    data->phase2_eap_type.method == EAP_TYPE_NONE)
442c1d255d3SCy Schubert 		eap_ttls_phase2_select_eap_method(data, vendor, method);
44339beb93cSSam Leffler 
444c1d255d3SCy Schubert 	if (vendor != data->phase2_eap_type.vendor ||
445c1d255d3SCy Schubert 	    method != data->phase2_eap_type.method ||
446c1d255d3SCy Schubert 	    (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE)) {
44739beb93cSSam Leffler 		if (eap_peer_tls_phase2_nak(data->phase2_eap_types,
44839beb93cSSam Leffler 					    data->num_phase2_eap_types,
44939beb93cSSam Leffler 					    hdr, resp))
45039beb93cSSam Leffler 			return -1;
45139beb93cSSam Leffler 		return 0;
45239beb93cSSam Leffler 	}
45339beb93cSSam Leffler 
45439beb93cSSam Leffler 	if (data->phase2_priv == NULL) {
455c1d255d3SCy Schubert 		data->phase2_method = eap_peer_get_eap_method(vendor, method);
45639beb93cSSam Leffler 		if (data->phase2_method) {
45739beb93cSSam Leffler 			sm->init_phase2 = 1;
45839beb93cSSam Leffler 			data->phase2_priv = data->phase2_method->init(sm);
45939beb93cSSam Leffler 			sm->init_phase2 = 0;
46039beb93cSSam Leffler 		}
46139beb93cSSam Leffler 	}
46239beb93cSSam Leffler 	if (data->phase2_priv == NULL || data->phase2_method == NULL) {
463c1d255d3SCy Schubert 		wpa_printf(MSG_INFO,
464c1d255d3SCy Schubert 			   "EAP-TTLS: failed to initialize Phase 2 EAP method %u:%u",
465c1d255d3SCy Schubert 			   vendor, method);
46639beb93cSSam Leffler 		return -1;
46739beb93cSSam Leffler 	}
46839beb93cSSam Leffler 
46939beb93cSSam Leffler 	return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp);
47039beb93cSSam Leffler }
47139beb93cSSam Leffler 
47239beb93cSSam Leffler 
eap_ttls_phase2_request_eap(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,struct eap_hdr * hdr,struct wpabuf ** resp)47339beb93cSSam Leffler static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
47439beb93cSSam Leffler 				       struct eap_ttls_data *data,
47539beb93cSSam Leffler 				       struct eap_method_ret *ret,
47639beb93cSSam Leffler 				       struct eap_hdr *hdr,
47739beb93cSSam Leffler 				       struct wpabuf **resp)
47839beb93cSSam Leffler {
47939beb93cSSam Leffler 	size_t len = be_to_host16(hdr->length);
48039beb93cSSam Leffler 	u8 *pos;
48139beb93cSSam Leffler 	struct eap_peer_config *config = eap_get_config(sm);
48239beb93cSSam Leffler 
48339beb93cSSam Leffler 	if (len <= sizeof(struct eap_hdr)) {
48439beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: too short "
48539beb93cSSam Leffler 			   "Phase 2 request (len=%lu)", (unsigned long) len);
48639beb93cSSam Leffler 		return -1;
48739beb93cSSam Leffler 	}
48839beb93cSSam Leffler 	pos = (u8 *) (hdr + 1);
48939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos);
49039beb93cSSam Leffler 	switch (*pos) {
49139beb93cSSam Leffler 	case EAP_TYPE_IDENTITY:
49239beb93cSSam Leffler 		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
49339beb93cSSam Leffler 		break;
494c1d255d3SCy Schubert 	case EAP_TYPE_EXPANDED:
495c1d255d3SCy Schubert 		if (len < sizeof(struct eap_hdr) + 8) {
496c1d255d3SCy Schubert 			wpa_printf(MSG_INFO,
497c1d255d3SCy Schubert 				   "EAP-TTLS: Too short Phase 2 request (expanded header) (len=%lu)",
498c1d255d3SCy Schubert 				   (unsigned long) len);
499c1d255d3SCy Schubert 			return -1;
500c1d255d3SCy Schubert 		}
501c1d255d3SCy Schubert 		if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
502c1d255d3SCy Schubert 						       WPA_GET_BE24(pos + 1),
503c1d255d3SCy Schubert 						       WPA_GET_BE32(pos + 4),
504c1d255d3SCy Schubert 						       resp) < 0)
505c1d255d3SCy Schubert 			return -1;
506c1d255d3SCy Schubert 		break;
50739beb93cSSam Leffler 	default:
50839beb93cSSam Leffler 		if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
509c1d255d3SCy Schubert 						       EAP_VENDOR_IETF, *pos,
510c1d255d3SCy Schubert 						       resp) < 0)
51139beb93cSSam Leffler 			return -1;
51239beb93cSSam Leffler 		break;
51339beb93cSSam Leffler 	}
51439beb93cSSam Leffler 
51539beb93cSSam Leffler 	if (*resp == NULL &&
51639beb93cSSam Leffler 	    (config->pending_req_identity || config->pending_req_password ||
51785732ac8SCy Schubert 	     config->pending_req_otp || config->pending_req_sim)) {
51839beb93cSSam Leffler 		return 0;
51939beb93cSSam Leffler 	}
52039beb93cSSam Leffler 
52139beb93cSSam Leffler 	if (*resp == NULL)
52239beb93cSSam Leffler 		return -1;
52339beb93cSSam Leffler 
52439beb93cSSam Leffler 	wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response",
52539beb93cSSam Leffler 			*resp);
52639beb93cSSam Leffler 	return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1);
52739beb93cSSam Leffler }
52839beb93cSSam Leffler 
52939beb93cSSam Leffler 
eap_ttls_phase2_request_mschapv2(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,struct wpabuf ** resp)53039beb93cSSam Leffler static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
53139beb93cSSam Leffler 					    struct eap_ttls_data *data,
53239beb93cSSam Leffler 					    struct eap_method_ret *ret,
53339beb93cSSam Leffler 					    struct wpabuf **resp)
53439beb93cSSam Leffler {
535325151a3SRui Paulo #ifdef CONFIG_FIPS
536325151a3SRui Paulo 	wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPV2 not supported in FIPS build");
537325151a3SRui Paulo 	return -1;
538325151a3SRui Paulo #else /* CONFIG_FIPS */
539f05cddf9SRui Paulo #ifdef EAP_MSCHAPv2
54039beb93cSSam Leffler 	struct wpabuf *msg;
54139beb93cSSam Leffler 	u8 *buf, *pos, *challenge, *peer_challenge;
54239beb93cSSam Leffler 	const u8 *identity, *password;
54339beb93cSSam Leffler 	size_t identity_len, password_len;
54439beb93cSSam Leffler 	int pwhash;
54539beb93cSSam Leffler 
54639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request");
54739beb93cSSam Leffler 
54839beb93cSSam Leffler 	identity = eap_get_config_identity(sm, &identity_len);
54939beb93cSSam Leffler 	password = eap_get_config_password2(sm, &password_len, &pwhash);
55039beb93cSSam Leffler 	if (identity == NULL || password == NULL)
55139beb93cSSam Leffler 		return -1;
55239beb93cSSam Leffler 
55339beb93cSSam Leffler 	msg = wpabuf_alloc(identity_len + 1000);
55439beb93cSSam Leffler 	if (msg == NULL) {
55539beb93cSSam Leffler 		wpa_printf(MSG_ERROR,
55639beb93cSSam Leffler 			   "EAP-TTLS/MSCHAPV2: Failed to allocate memory");
55739beb93cSSam Leffler 		return -1;
55839beb93cSSam Leffler 	}
55939beb93cSSam Leffler 	pos = buf = wpabuf_mhead(msg);
56039beb93cSSam Leffler 
56139beb93cSSam Leffler 	/* User-Name */
56239beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
56339beb93cSSam Leffler 			       identity, identity_len);
56439beb93cSSam Leffler 
56539beb93cSSam Leffler 	/* MS-CHAP-Challenge */
56639beb93cSSam Leffler 	challenge = eap_ttls_implicit_challenge(
56739beb93cSSam Leffler 		sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
56839beb93cSSam Leffler 	if (challenge == NULL) {
5694bc52338SCy Schubert 		wpabuf_clear_free(msg);
57039beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
57139beb93cSSam Leffler 			   "implicit challenge");
57239beb93cSSam Leffler 		return -1;
57339beb93cSSam Leffler 	}
57439beb93cSSam Leffler 
57539beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
57639beb93cSSam Leffler 			       RADIUS_VENDOR_ID_MICROSOFT, 1,
57739beb93cSSam Leffler 			       challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
57839beb93cSSam Leffler 
57939beb93cSSam Leffler 	/* MS-CHAP2-Response */
58039beb93cSSam Leffler 	pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE,
58139beb93cSSam Leffler 			       RADIUS_VENDOR_ID_MICROSOFT, 1,
58239beb93cSSam Leffler 			       EAP_TTLS_MSCHAPV2_RESPONSE_LEN);
58339beb93cSSam Leffler 	data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN];
58439beb93cSSam Leffler 	*pos++ = data->ident;
58539beb93cSSam Leffler 	*pos++ = 0; /* Flags */
586f05cddf9SRui Paulo 	if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) {
587f05cddf9SRui Paulo 		os_free(challenge);
5884bc52338SCy Schubert 		wpabuf_clear_free(msg);
589f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get "
590f05cddf9SRui Paulo 			   "random data for peer challenge");
591f05cddf9SRui Paulo 		return -1;
592f05cddf9SRui Paulo 	}
593f05cddf9SRui Paulo 	peer_challenge = pos;
59439beb93cSSam Leffler 	pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
59539beb93cSSam Leffler 	os_memset(pos, 0, 8); /* Reserved, must be zero */
59639beb93cSSam Leffler 	pos += 8;
597e28a4053SRui Paulo 	if (mschapv2_derive_response(identity, identity_len, password,
59839beb93cSSam Leffler 				     password_len, pwhash, challenge,
59939beb93cSSam Leffler 				     peer_challenge, pos, data->auth_response,
600e28a4053SRui Paulo 				     data->master_key)) {
601f05cddf9SRui Paulo 		os_free(challenge);
6024bc52338SCy Schubert 		wpabuf_clear_free(msg);
603e28a4053SRui Paulo 		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
604e28a4053SRui Paulo 			   "response");
605e28a4053SRui Paulo 		return -1;
606e28a4053SRui Paulo 	}
60739beb93cSSam Leffler 	data->auth_response_valid = 1;
60839beb93cSSam Leffler 
60939beb93cSSam Leffler 	pos += 24;
61039beb93cSSam Leffler 	os_free(challenge);
61139beb93cSSam Leffler 	AVP_PAD(buf, pos);
61239beb93cSSam Leffler 
61339beb93cSSam Leffler 	wpabuf_put(msg, pos - buf);
61439beb93cSSam Leffler 	*resp = msg;
61539beb93cSSam Leffler 
61639beb93cSSam Leffler 	return 0;
617f05cddf9SRui Paulo #else /* EAP_MSCHAPv2 */
618f05cddf9SRui Paulo 	wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
619f05cddf9SRui Paulo 	return -1;
620f05cddf9SRui Paulo #endif /* EAP_MSCHAPv2 */
621325151a3SRui Paulo #endif /* CONFIG_FIPS */
62239beb93cSSam Leffler }
62339beb93cSSam Leffler 
62439beb93cSSam Leffler 
eap_ttls_phase2_request_mschap(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,struct wpabuf ** resp)62539beb93cSSam Leffler static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
62639beb93cSSam Leffler 					  struct eap_ttls_data *data,
62739beb93cSSam Leffler 					  struct eap_method_ret *ret,
62839beb93cSSam Leffler 					  struct wpabuf **resp)
62939beb93cSSam Leffler {
630325151a3SRui Paulo #ifdef CONFIG_FIPS
631325151a3SRui Paulo 	wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAP not supported in FIPS build");
632325151a3SRui Paulo 	return -1;
633325151a3SRui Paulo #else /* CONFIG_FIPS */
63439beb93cSSam Leffler 	struct wpabuf *msg;
63539beb93cSSam Leffler 	u8 *buf, *pos, *challenge;
63639beb93cSSam Leffler 	const u8 *identity, *password;
63739beb93cSSam Leffler 	size_t identity_len, password_len;
63839beb93cSSam Leffler 	int pwhash;
63939beb93cSSam Leffler 
64039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request");
64139beb93cSSam Leffler 
64239beb93cSSam Leffler 	identity = eap_get_config_identity(sm, &identity_len);
64339beb93cSSam Leffler 	password = eap_get_config_password2(sm, &password_len, &pwhash);
64439beb93cSSam Leffler 	if (identity == NULL || password == NULL)
64539beb93cSSam Leffler 		return -1;
64639beb93cSSam Leffler 
64739beb93cSSam Leffler 	msg = wpabuf_alloc(identity_len + 1000);
64839beb93cSSam Leffler 	if (msg == NULL) {
64939beb93cSSam Leffler 		wpa_printf(MSG_ERROR,
65039beb93cSSam Leffler 			   "EAP-TTLS/MSCHAP: Failed to allocate memory");
65139beb93cSSam Leffler 		return -1;
65239beb93cSSam Leffler 	}
65339beb93cSSam Leffler 	pos = buf = wpabuf_mhead(msg);
65439beb93cSSam Leffler 
65539beb93cSSam Leffler 	/* User-Name */
65639beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
65739beb93cSSam Leffler 			       identity, identity_len);
65839beb93cSSam Leffler 
65939beb93cSSam Leffler 	/* MS-CHAP-Challenge */
66039beb93cSSam Leffler 	challenge = eap_ttls_implicit_challenge(
66139beb93cSSam Leffler 		sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
66239beb93cSSam Leffler 	if (challenge == NULL) {
6634bc52338SCy Schubert 		wpabuf_clear_free(msg);
66439beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive "
66539beb93cSSam Leffler 			   "implicit challenge");
66639beb93cSSam Leffler 		return -1;
66739beb93cSSam Leffler 	}
66839beb93cSSam Leffler 
66939beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
67039beb93cSSam Leffler 			       RADIUS_VENDOR_ID_MICROSOFT, 1,
67139beb93cSSam Leffler 			       challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
67239beb93cSSam Leffler 
67339beb93cSSam Leffler 	/* MS-CHAP-Response */
67439beb93cSSam Leffler 	pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE,
67539beb93cSSam Leffler 			       RADIUS_VENDOR_ID_MICROSOFT, 1,
67639beb93cSSam Leffler 			       EAP_TTLS_MSCHAP_RESPONSE_LEN);
67739beb93cSSam Leffler 	data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN];
67839beb93cSSam Leffler 	*pos++ = data->ident;
67939beb93cSSam Leffler 	*pos++ = 1; /* Flags: Use NT style passwords */
68039beb93cSSam Leffler 	os_memset(pos, 0, 24); /* LM-Response */
68139beb93cSSam Leffler 	pos += 24;
68239beb93cSSam Leffler 	if (pwhash) {
68385732ac8SCy Schubert 		/* NT-Response */
68485732ac8SCy Schubert 		if (challenge_response(challenge, password, pos)) {
68585732ac8SCy Schubert 			wpa_printf(MSG_ERROR,
68685732ac8SCy Schubert 				   "EAP-TTLS/MSCHAP: Failed derive password hash");
6874bc52338SCy Schubert 			wpabuf_clear_free(msg);
68885732ac8SCy Schubert 			os_free(challenge);
68985732ac8SCy Schubert 			return -1;
69085732ac8SCy Schubert 		}
69185732ac8SCy Schubert 
69239beb93cSSam Leffler 		wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash",
69339beb93cSSam Leffler 				password, 16);
69439beb93cSSam Leffler 	} else {
69585732ac8SCy Schubert 		/* NT-Response */
69685732ac8SCy Schubert 		if (nt_challenge_response(challenge, password, password_len,
69785732ac8SCy Schubert 					  pos)) {
69885732ac8SCy Schubert 			wpa_printf(MSG_ERROR,
69985732ac8SCy Schubert 				   "EAP-TTLS/MSCHAP: Failed derive password");
7004bc52338SCy Schubert 			wpabuf_clear_free(msg);
70185732ac8SCy Schubert 			os_free(challenge);
70285732ac8SCy Schubert 			return -1;
70385732ac8SCy Schubert 		}
70485732ac8SCy Schubert 
70539beb93cSSam Leffler 		wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password",
70639beb93cSSam Leffler 				      password, password_len);
70739beb93cSSam Leffler 	}
70839beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge",
70939beb93cSSam Leffler 		    challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
71039beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24);
71139beb93cSSam Leffler 	pos += 24;
71239beb93cSSam Leffler 	os_free(challenge);
71339beb93cSSam Leffler 	AVP_PAD(buf, pos);
71439beb93cSSam Leffler 
71539beb93cSSam Leffler 	wpabuf_put(msg, pos - buf);
71639beb93cSSam Leffler 	*resp = msg;
71739beb93cSSam Leffler 
71839beb93cSSam Leffler 	/* EAP-TTLS/MSCHAP does not provide tunneled success
71939beb93cSSam Leffler 	 * notification, so assume that Phase2 succeeds. */
72039beb93cSSam Leffler 	ret->methodState = METHOD_DONE;
72139beb93cSSam Leffler 	ret->decision = DECISION_COND_SUCC;
72239beb93cSSam Leffler 
72339beb93cSSam Leffler 	return 0;
724325151a3SRui Paulo #endif /* CONFIG_FIPS */
72539beb93cSSam Leffler }
72639beb93cSSam Leffler 
72739beb93cSSam Leffler 
eap_ttls_phase2_request_pap(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,struct wpabuf ** resp)72839beb93cSSam Leffler static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
72939beb93cSSam Leffler 				       struct eap_ttls_data *data,
73039beb93cSSam Leffler 				       struct eap_method_ret *ret,
73139beb93cSSam Leffler 				       struct wpabuf **resp)
73239beb93cSSam Leffler {
73339beb93cSSam Leffler 	struct wpabuf *msg;
73439beb93cSSam Leffler 	u8 *buf, *pos;
73539beb93cSSam Leffler 	size_t pad;
73639beb93cSSam Leffler 	const u8 *identity, *password;
73739beb93cSSam Leffler 	size_t identity_len, password_len;
73839beb93cSSam Leffler 
73939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request");
74039beb93cSSam Leffler 
74139beb93cSSam Leffler 	identity = eap_get_config_identity(sm, &identity_len);
74239beb93cSSam Leffler 	password = eap_get_config_password(sm, &password_len);
74339beb93cSSam Leffler 	if (identity == NULL || password == NULL)
74439beb93cSSam Leffler 		return -1;
74539beb93cSSam Leffler 
74639beb93cSSam Leffler 	msg = wpabuf_alloc(identity_len + password_len + 100);
74739beb93cSSam Leffler 	if (msg == NULL) {
74839beb93cSSam Leffler 		wpa_printf(MSG_ERROR,
74939beb93cSSam Leffler 			   "EAP-TTLS/PAP: Failed to allocate memory");
75039beb93cSSam Leffler 		return -1;
75139beb93cSSam Leffler 	}
75239beb93cSSam Leffler 	pos = buf = wpabuf_mhead(msg);
75339beb93cSSam Leffler 
75439beb93cSSam Leffler 	/* User-Name */
75539beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
75639beb93cSSam Leffler 			       identity, identity_len);
75739beb93cSSam Leffler 
75839beb93cSSam Leffler 	/* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts
75939beb93cSSam Leffler 	 * the data, so no separate encryption is used in the AVP itself.
76039beb93cSSam Leffler 	 * However, the password is padded to obfuscate its length. */
7613157ba21SRui Paulo 	pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15;
76239beb93cSSam Leffler 	pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1,
76339beb93cSSam Leffler 			       password_len + pad);
76439beb93cSSam Leffler 	os_memcpy(pos, password, password_len);
76539beb93cSSam Leffler 	pos += password_len;
76639beb93cSSam Leffler 	os_memset(pos, 0, pad);
76739beb93cSSam Leffler 	pos += pad;
76839beb93cSSam Leffler 	AVP_PAD(buf, pos);
76939beb93cSSam Leffler 
77039beb93cSSam Leffler 	wpabuf_put(msg, pos - buf);
77139beb93cSSam Leffler 	*resp = msg;
77239beb93cSSam Leffler 
77339beb93cSSam Leffler 	/* EAP-TTLS/PAP does not provide tunneled success notification,
77439beb93cSSam Leffler 	 * so assume that Phase2 succeeds. */
77539beb93cSSam Leffler 	ret->methodState = METHOD_DONE;
77639beb93cSSam Leffler 	ret->decision = DECISION_COND_SUCC;
77739beb93cSSam Leffler 
77839beb93cSSam Leffler 	return 0;
77939beb93cSSam Leffler }
78039beb93cSSam Leffler 
78139beb93cSSam Leffler 
eap_ttls_phase2_request_chap(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,struct wpabuf ** resp)78239beb93cSSam Leffler static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
78339beb93cSSam Leffler 					struct eap_ttls_data *data,
78439beb93cSSam Leffler 					struct eap_method_ret *ret,
78539beb93cSSam Leffler 					struct wpabuf **resp)
78639beb93cSSam Leffler {
787325151a3SRui Paulo #ifdef CONFIG_FIPS
788325151a3SRui Paulo 	wpa_printf(MSG_ERROR, "EAP-TTLS: CHAP not supported in FIPS build");
789325151a3SRui Paulo 	return -1;
790325151a3SRui Paulo #else /* CONFIG_FIPS */
79139beb93cSSam Leffler 	struct wpabuf *msg;
79239beb93cSSam Leffler 	u8 *buf, *pos, *challenge;
79339beb93cSSam Leffler 	const u8 *identity, *password;
79439beb93cSSam Leffler 	size_t identity_len, password_len;
79539beb93cSSam Leffler 
79639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request");
79739beb93cSSam Leffler 
79839beb93cSSam Leffler 	identity = eap_get_config_identity(sm, &identity_len);
79939beb93cSSam Leffler 	password = eap_get_config_password(sm, &password_len);
80039beb93cSSam Leffler 	if (identity == NULL || password == NULL)
80139beb93cSSam Leffler 		return -1;
80239beb93cSSam Leffler 
80339beb93cSSam Leffler 	msg = wpabuf_alloc(identity_len + 1000);
80439beb93cSSam Leffler 	if (msg == NULL) {
80539beb93cSSam Leffler 		wpa_printf(MSG_ERROR,
80639beb93cSSam Leffler 			   "EAP-TTLS/CHAP: Failed to allocate memory");
80739beb93cSSam Leffler 		return -1;
80839beb93cSSam Leffler 	}
80939beb93cSSam Leffler 	pos = buf = wpabuf_mhead(msg);
81039beb93cSSam Leffler 
81139beb93cSSam Leffler 	/* User-Name */
81239beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
81339beb93cSSam Leffler 			       identity, identity_len);
81439beb93cSSam Leffler 
81539beb93cSSam Leffler 	/* CHAP-Challenge */
81639beb93cSSam Leffler 	challenge = eap_ttls_implicit_challenge(
81739beb93cSSam Leffler 		sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
81839beb93cSSam Leffler 	if (challenge == NULL) {
8194bc52338SCy Schubert 		wpabuf_clear_free(msg);
82039beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive "
82139beb93cSSam Leffler 			   "implicit challenge");
82239beb93cSSam Leffler 		return -1;
82339beb93cSSam Leffler 	}
82439beb93cSSam Leffler 
82539beb93cSSam Leffler 	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1,
82639beb93cSSam Leffler 			       challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
82739beb93cSSam Leffler 
82839beb93cSSam Leffler 	/* CHAP-Password */
82939beb93cSSam Leffler 	pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1,
83039beb93cSSam Leffler 			       1 + EAP_TTLS_CHAP_PASSWORD_LEN);
83139beb93cSSam Leffler 	data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN];
83239beb93cSSam Leffler 	*pos++ = data->ident;
83339beb93cSSam Leffler 
83439beb93cSSam Leffler 	/* MD5(Ident + Password + Challenge) */
83539beb93cSSam Leffler 	chap_md5(data->ident, password, password_len, challenge,
83639beb93cSSam Leffler 		 EAP_TTLS_CHAP_CHALLENGE_LEN, pos);
83739beb93cSSam Leffler 
83839beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username",
83939beb93cSSam Leffler 			  identity, identity_len);
84039beb93cSSam Leffler 	wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password",
84139beb93cSSam Leffler 			      password, password_len);
84239beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge",
84339beb93cSSam Leffler 		    challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
84439beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password",
84539beb93cSSam Leffler 		    pos, EAP_TTLS_CHAP_PASSWORD_LEN);
84639beb93cSSam Leffler 	pos += EAP_TTLS_CHAP_PASSWORD_LEN;
84739beb93cSSam Leffler 	os_free(challenge);
84839beb93cSSam Leffler 	AVP_PAD(buf, pos);
84939beb93cSSam Leffler 
85039beb93cSSam Leffler 	wpabuf_put(msg, pos - buf);
85139beb93cSSam Leffler 	*resp = msg;
85239beb93cSSam Leffler 
85339beb93cSSam Leffler 	/* EAP-TTLS/CHAP does not provide tunneled success
85439beb93cSSam Leffler 	 * notification, so assume that Phase2 succeeds. */
85539beb93cSSam Leffler 	ret->methodState = METHOD_DONE;
85639beb93cSSam Leffler 	ret->decision = DECISION_COND_SUCC;
85739beb93cSSam Leffler 
85839beb93cSSam Leffler 	return 0;
859325151a3SRui Paulo #endif /* CONFIG_FIPS */
86039beb93cSSam Leffler }
86139beb93cSSam Leffler 
86239beb93cSSam Leffler 
eap_ttls_phase2_request(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,struct eap_hdr * hdr,struct wpabuf ** resp)86339beb93cSSam Leffler static int eap_ttls_phase2_request(struct eap_sm *sm,
86439beb93cSSam Leffler 				   struct eap_ttls_data *data,
86539beb93cSSam Leffler 				   struct eap_method_ret *ret,
86639beb93cSSam Leffler 				   struct eap_hdr *hdr,
86739beb93cSSam Leffler 				   struct wpabuf **resp)
86839beb93cSSam Leffler {
86939beb93cSSam Leffler 	int res = 0;
87039beb93cSSam Leffler 	size_t len;
87139beb93cSSam Leffler 	enum phase2_types phase2_type = data->phase2_type;
87239beb93cSSam Leffler 
87339beb93cSSam Leffler #ifdef EAP_TNC
87439beb93cSSam Leffler 	if (data->tnc_started) {
87539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC");
87639beb93cSSam Leffler 		phase2_type = EAP_TTLS_PHASE2_EAP;
87739beb93cSSam Leffler 	}
87839beb93cSSam Leffler #endif /* EAP_TNC */
87939beb93cSSam Leffler 
88039beb93cSSam Leffler 	if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 ||
88139beb93cSSam Leffler 	    phase2_type == EAP_TTLS_PHASE2_MSCHAP ||
88239beb93cSSam Leffler 	    phase2_type == EAP_TTLS_PHASE2_PAP ||
88339beb93cSSam Leffler 	    phase2_type == EAP_TTLS_PHASE2_CHAP) {
88439beb93cSSam Leffler 		if (eap_get_config_identity(sm, &len) == NULL) {
88539beb93cSSam Leffler 			wpa_printf(MSG_INFO,
88639beb93cSSam Leffler 				   "EAP-TTLS: Identity not configured");
88739beb93cSSam Leffler 			eap_sm_request_identity(sm);
88839beb93cSSam Leffler 			if (eap_get_config_password(sm, &len) == NULL)
88939beb93cSSam Leffler 				eap_sm_request_password(sm);
89039beb93cSSam Leffler 			return 0;
89139beb93cSSam Leffler 		}
89239beb93cSSam Leffler 
89339beb93cSSam Leffler 		if (eap_get_config_password(sm, &len) == NULL) {
89439beb93cSSam Leffler 			wpa_printf(MSG_INFO,
89539beb93cSSam Leffler 				   "EAP-TTLS: Password not configured");
89639beb93cSSam Leffler 			eap_sm_request_password(sm);
89739beb93cSSam Leffler 			return 0;
89839beb93cSSam Leffler 		}
89939beb93cSSam Leffler 	}
90039beb93cSSam Leffler 
90139beb93cSSam Leffler 	switch (phase2_type) {
90239beb93cSSam Leffler 	case EAP_TTLS_PHASE2_EAP:
90339beb93cSSam Leffler 		res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp);
90439beb93cSSam Leffler 		break;
90539beb93cSSam Leffler 	case EAP_TTLS_PHASE2_MSCHAPV2:
90639beb93cSSam Leffler 		res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp);
90739beb93cSSam Leffler 		break;
90839beb93cSSam Leffler 	case EAP_TTLS_PHASE2_MSCHAP:
90939beb93cSSam Leffler 		res = eap_ttls_phase2_request_mschap(sm, data, ret, resp);
91039beb93cSSam Leffler 		break;
91139beb93cSSam Leffler 	case EAP_TTLS_PHASE2_PAP:
91239beb93cSSam Leffler 		res = eap_ttls_phase2_request_pap(sm, data, ret, resp);
91339beb93cSSam Leffler 		break;
91439beb93cSSam Leffler 	case EAP_TTLS_PHASE2_CHAP:
91539beb93cSSam Leffler 		res = eap_ttls_phase2_request_chap(sm, data, ret, resp);
91639beb93cSSam Leffler 		break;
91739beb93cSSam Leffler 	default:
91839beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown");
91939beb93cSSam Leffler 		res = -1;
92039beb93cSSam Leffler 		break;
92139beb93cSSam Leffler 	}
92239beb93cSSam Leffler 
92339beb93cSSam Leffler 	if (res < 0) {
92439beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
92539beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
92639beb93cSSam Leffler 	}
92739beb93cSSam Leffler 
92839beb93cSSam Leffler 	return res;
92939beb93cSSam Leffler }
93039beb93cSSam Leffler 
93139beb93cSSam Leffler 
93239beb93cSSam Leffler struct ttls_parse_avp {
93339beb93cSSam Leffler 	u8 *mschapv2;
93439beb93cSSam Leffler 	u8 *eapdata;
93539beb93cSSam Leffler 	size_t eap_len;
93639beb93cSSam Leffler 	int mschapv2_error;
93739beb93cSSam Leffler };
93839beb93cSSam Leffler 
93939beb93cSSam Leffler 
eap_ttls_parse_attr_eap(const u8 * dpos,size_t dlen,struct ttls_parse_avp * parse)94039beb93cSSam Leffler static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen,
94139beb93cSSam Leffler 				   struct ttls_parse_avp *parse)
94239beb93cSSam Leffler {
94339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message");
94439beb93cSSam Leffler 	if (parse->eapdata == NULL) {
94585732ac8SCy Schubert 		parse->eapdata = os_memdup(dpos, dlen);
94639beb93cSSam Leffler 		if (parse->eapdata == NULL) {
94739beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
94839beb93cSSam Leffler 				   "memory for Phase 2 EAP data");
94939beb93cSSam Leffler 			return -1;
95039beb93cSSam Leffler 		}
95139beb93cSSam Leffler 		parse->eap_len = dlen;
95239beb93cSSam Leffler 	} else {
95339beb93cSSam Leffler 		u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen);
95439beb93cSSam Leffler 		if (neweap == NULL) {
95539beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
95639beb93cSSam Leffler 				   "memory for Phase 2 EAP data");
95739beb93cSSam Leffler 			return -1;
95839beb93cSSam Leffler 		}
95939beb93cSSam Leffler 		os_memcpy(neweap + parse->eap_len, dpos, dlen);
96039beb93cSSam Leffler 		parse->eapdata = neweap;
96139beb93cSSam Leffler 		parse->eap_len += dlen;
96239beb93cSSam Leffler 	}
96339beb93cSSam Leffler 
96439beb93cSSam Leffler 	return 0;
96539beb93cSSam Leffler }
96639beb93cSSam Leffler 
96739beb93cSSam Leffler 
eap_ttls_parse_avp(u8 * pos,size_t left,struct ttls_parse_avp * parse)96839beb93cSSam Leffler static int eap_ttls_parse_avp(u8 *pos, size_t left,
96939beb93cSSam Leffler 			      struct ttls_parse_avp *parse)
97039beb93cSSam Leffler {
97139beb93cSSam Leffler 	struct ttls_avp *avp;
97239beb93cSSam Leffler 	u32 avp_code, avp_length, vendor_id = 0;
97339beb93cSSam Leffler 	u8 avp_flags, *dpos;
97439beb93cSSam Leffler 	size_t dlen;
97539beb93cSSam Leffler 
97639beb93cSSam Leffler 	avp = (struct ttls_avp *) pos;
97739beb93cSSam Leffler 	avp_code = be_to_host32(avp->avp_code);
97839beb93cSSam Leffler 	avp_length = be_to_host32(avp->avp_length);
97939beb93cSSam Leffler 	avp_flags = (avp_length >> 24) & 0xff;
98039beb93cSSam Leffler 	avp_length &= 0xffffff;
98139beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x "
98239beb93cSSam Leffler 		   "length=%d", (int) avp_code, avp_flags,
98339beb93cSSam Leffler 		   (int) avp_length);
98439beb93cSSam Leffler 
98539beb93cSSam Leffler 	if (avp_length > left) {
98639beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow "
98739beb93cSSam Leffler 			   "(len=%d, left=%lu) - dropped",
98839beb93cSSam Leffler 			   (int) avp_length, (unsigned long) left);
98939beb93cSSam Leffler 		return -1;
99039beb93cSSam Leffler 	}
99139beb93cSSam Leffler 
99239beb93cSSam Leffler 	if (avp_length < sizeof(*avp)) {
99339beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d",
99439beb93cSSam Leffler 			   avp_length);
99539beb93cSSam Leffler 		return -1;
99639beb93cSSam Leffler 	}
99739beb93cSSam Leffler 
99839beb93cSSam Leffler 	dpos = (u8 *) (avp + 1);
99939beb93cSSam Leffler 	dlen = avp_length - sizeof(*avp);
100039beb93cSSam Leffler 	if (avp_flags & AVP_FLAGS_VENDOR) {
100139beb93cSSam Leffler 		if (dlen < 4) {
100239beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "EAP-TTLS: Vendor AVP "
100339beb93cSSam Leffler 				   "underflow");
100439beb93cSSam Leffler 			return -1;
100539beb93cSSam Leffler 		}
100639beb93cSSam Leffler 		vendor_id = WPA_GET_BE32(dpos);
100739beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d",
100839beb93cSSam Leffler 			   (int) vendor_id);
100939beb93cSSam Leffler 		dpos += 4;
101039beb93cSSam Leffler 		dlen -= 4;
101139beb93cSSam Leffler 	}
101239beb93cSSam Leffler 
101339beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen);
101439beb93cSSam Leffler 
101539beb93cSSam Leffler 	if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) {
101639beb93cSSam Leffler 		if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0)
101739beb93cSSam Leffler 			return -1;
101839beb93cSSam Leffler 	} else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) {
101939beb93cSSam Leffler 		/* This is an optional message that can be displayed to
102039beb93cSSam Leffler 		 * the user. */
102139beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message",
102239beb93cSSam Leffler 				  dpos, dlen);
102339beb93cSSam Leffler 	} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
102439beb93cSSam Leffler 		   avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) {
102539beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success",
102639beb93cSSam Leffler 				  dpos, dlen);
102739beb93cSSam Leffler 		if (dlen != 43) {
102839beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected "
102939beb93cSSam Leffler 				   "MS-CHAP2-Success length "
103039beb93cSSam Leffler 				   "(len=%lu, expected 43)",
103139beb93cSSam Leffler 				   (unsigned long) dlen);
103239beb93cSSam Leffler 			return -1;
103339beb93cSSam Leffler 		}
103439beb93cSSam Leffler 		parse->mschapv2 = dpos;
103539beb93cSSam Leffler 	} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
103639beb93cSSam Leffler 		   avp_code == RADIUS_ATTR_MS_CHAP_ERROR) {
103739beb93cSSam Leffler 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error",
103839beb93cSSam Leffler 				  dpos, dlen);
103939beb93cSSam Leffler 		parse->mschapv2_error = 1;
104039beb93cSSam Leffler 	} else if (avp_flags & AVP_FLAGS_MANDATORY) {
104139beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported mandatory AVP "
104239beb93cSSam Leffler 			   "code %d vendor_id %d - dropped",
104339beb93cSSam Leffler 			   (int) avp_code, (int) vendor_id);
104439beb93cSSam Leffler 		return -1;
104539beb93cSSam Leffler 	} else {
104639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP "
104739beb93cSSam Leffler 			   "code %d vendor_id %d",
104839beb93cSSam Leffler 			   (int) avp_code, (int) vendor_id);
104939beb93cSSam Leffler 	}
105039beb93cSSam Leffler 
105139beb93cSSam Leffler 	return avp_length;
105239beb93cSSam Leffler }
105339beb93cSSam Leffler 
105439beb93cSSam Leffler 
eap_ttls_parse_avps(struct wpabuf * in_decrypted,struct ttls_parse_avp * parse)105539beb93cSSam Leffler static int eap_ttls_parse_avps(struct wpabuf *in_decrypted,
105639beb93cSSam Leffler 			       struct ttls_parse_avp *parse)
105739beb93cSSam Leffler {
105839beb93cSSam Leffler 	u8 *pos;
105939beb93cSSam Leffler 	size_t left, pad;
106039beb93cSSam Leffler 	int avp_length;
106139beb93cSSam Leffler 
106239beb93cSSam Leffler 	pos = wpabuf_mhead(in_decrypted);
106339beb93cSSam Leffler 	left = wpabuf_len(in_decrypted);
106439beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left);
106539beb93cSSam Leffler 	if (left < sizeof(struct ttls_avp)) {
106639beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame"
106739beb93cSSam Leffler 			   " len=%lu expected %lu or more - dropped",
106839beb93cSSam Leffler 			   (unsigned long) left,
106939beb93cSSam Leffler 			   (unsigned long) sizeof(struct ttls_avp));
107039beb93cSSam Leffler 		return -1;
107139beb93cSSam Leffler 	}
107239beb93cSSam Leffler 
107339beb93cSSam Leffler 	/* Parse AVPs */
107439beb93cSSam Leffler 	os_memset(parse, 0, sizeof(*parse));
107539beb93cSSam Leffler 
107639beb93cSSam Leffler 	while (left > 0) {
107739beb93cSSam Leffler 		avp_length = eap_ttls_parse_avp(pos, left, parse);
107839beb93cSSam Leffler 		if (avp_length < 0)
107939beb93cSSam Leffler 			return -1;
108039beb93cSSam Leffler 
108139beb93cSSam Leffler 		pad = (4 - (avp_length & 3)) & 3;
108239beb93cSSam Leffler 		pos += avp_length + pad;
108339beb93cSSam Leffler 		if (left < avp_length + pad)
108439beb93cSSam Leffler 			left = 0;
108539beb93cSSam Leffler 		else
108639beb93cSSam Leffler 			left -= avp_length + pad;
108739beb93cSSam Leffler 	}
108839beb93cSSam Leffler 
108939beb93cSSam Leffler 	return 0;
109039beb93cSSam Leffler }
109139beb93cSSam Leffler 
109239beb93cSSam Leffler 
eap_ttls_fake_identity_request(void)109339beb93cSSam Leffler static u8 * eap_ttls_fake_identity_request(void)
109439beb93cSSam Leffler {
109539beb93cSSam Leffler 	struct eap_hdr *hdr;
109639beb93cSSam Leffler 	u8 *buf;
109739beb93cSSam Leffler 
109839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of "
109939beb93cSSam Leffler 		   "Phase 2 - use fake EAP-Request Identity");
110039beb93cSSam Leffler 	buf = os_malloc(sizeof(*hdr) + 1);
110139beb93cSSam Leffler 	if (buf == NULL) {
110239beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate "
110339beb93cSSam Leffler 			   "memory for fake EAP-Identity Request");
110439beb93cSSam Leffler 		return NULL;
110539beb93cSSam Leffler 	}
110639beb93cSSam Leffler 
110739beb93cSSam Leffler 	hdr = (struct eap_hdr *) buf;
110839beb93cSSam Leffler 	hdr->code = EAP_CODE_REQUEST;
110939beb93cSSam Leffler 	hdr->identifier = 0;
111039beb93cSSam Leffler 	hdr->length = host_to_be16(sizeof(*hdr) + 1);
111139beb93cSSam Leffler 	buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY;
111239beb93cSSam Leffler 
111339beb93cSSam Leffler 	return buf;
111439beb93cSSam Leffler }
111539beb93cSSam Leffler 
111639beb93cSSam Leffler 
eap_ttls_encrypt_response(struct eap_sm * sm,struct eap_ttls_data * data,struct wpabuf * resp,u8 identifier,struct wpabuf ** out_data)111739beb93cSSam Leffler static int eap_ttls_encrypt_response(struct eap_sm *sm,
111839beb93cSSam Leffler 				     struct eap_ttls_data *data,
111939beb93cSSam Leffler 				     struct wpabuf *resp, u8 identifier,
112039beb93cSSam Leffler 				     struct wpabuf **out_data)
112139beb93cSSam Leffler {
112239beb93cSSam Leffler 	if (resp == NULL)
112339beb93cSSam Leffler 		return 0;
112439beb93cSSam Leffler 
112539beb93cSSam Leffler 	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data",
112639beb93cSSam Leffler 			    resp);
112739beb93cSSam Leffler 	if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS,
112839beb93cSSam Leffler 				 data->ttls_version, identifier,
112939beb93cSSam Leffler 				 resp, out_data)) {
113039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 "
113139beb93cSSam Leffler 			   "frame");
11324bc52338SCy Schubert 		wpabuf_clear_free(resp);
113339beb93cSSam Leffler 		return -1;
113439beb93cSSam Leffler 	}
11354bc52338SCy Schubert 	wpabuf_clear_free(resp);
113639beb93cSSam Leffler 
113739beb93cSSam Leffler 	return 0;
113839beb93cSSam Leffler }
113939beb93cSSam Leffler 
114039beb93cSSam Leffler 
eap_ttls_process_phase2_eap(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,struct ttls_parse_avp * parse,struct wpabuf ** resp)114139beb93cSSam Leffler static int eap_ttls_process_phase2_eap(struct eap_sm *sm,
114239beb93cSSam Leffler 				       struct eap_ttls_data *data,
114339beb93cSSam Leffler 				       struct eap_method_ret *ret,
114439beb93cSSam Leffler 				       struct ttls_parse_avp *parse,
114539beb93cSSam Leffler 				       struct wpabuf **resp)
114639beb93cSSam Leffler {
114739beb93cSSam Leffler 	struct eap_hdr *hdr;
114839beb93cSSam Leffler 	size_t len;
114939beb93cSSam Leffler 
115039beb93cSSam Leffler 	if (parse->eapdata == NULL) {
115139beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the "
115239beb93cSSam Leffler 			   "packet - dropped");
115339beb93cSSam Leffler 		return -1;
115439beb93cSSam Leffler 	}
115539beb93cSSam Leffler 
115639beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP",
115739beb93cSSam Leffler 		    parse->eapdata, parse->eap_len);
115839beb93cSSam Leffler 	hdr = (struct eap_hdr *) parse->eapdata;
115939beb93cSSam Leffler 
116039beb93cSSam Leffler 	if (parse->eap_len < sizeof(*hdr)) {
116139beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP "
116239beb93cSSam Leffler 			   "frame (len=%lu, expected %lu or more) - dropped",
116339beb93cSSam Leffler 			   (unsigned long) parse->eap_len,
116439beb93cSSam Leffler 			   (unsigned long) sizeof(*hdr));
116539beb93cSSam Leffler 		return -1;
116639beb93cSSam Leffler 	}
116739beb93cSSam Leffler 	len = be_to_host16(hdr->length);
116839beb93cSSam Leffler 	if (len > parse->eap_len) {
116939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 "
117039beb93cSSam Leffler 			   "EAP frame (EAP hdr len=%lu, EAP data len in "
117139beb93cSSam Leffler 			   "AVP=%lu)",
117239beb93cSSam Leffler 			   (unsigned long) len,
117339beb93cSSam Leffler 			   (unsigned long) parse->eap_len);
117439beb93cSSam Leffler 		return -1;
117539beb93cSSam Leffler 	}
117639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d "
117739beb93cSSam Leffler 		   "identifier=%d length=%lu",
117839beb93cSSam Leffler 		   hdr->code, hdr->identifier, (unsigned long) len);
117939beb93cSSam Leffler 	switch (hdr->code) {
118039beb93cSSam Leffler 	case EAP_CODE_REQUEST:
118139beb93cSSam Leffler 		if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) {
118239beb93cSSam Leffler 			wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request "
118339beb93cSSam Leffler 				   "processing failed");
118439beb93cSSam Leffler 			return -1;
118539beb93cSSam Leffler 		}
118639beb93cSSam Leffler 		break;
118739beb93cSSam Leffler 	default:
118839beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in "
118939beb93cSSam Leffler 			   "Phase 2 EAP header", hdr->code);
119039beb93cSSam Leffler 		return -1;
119139beb93cSSam Leffler 	}
119239beb93cSSam Leffler 
119339beb93cSSam Leffler 	return 0;
119439beb93cSSam Leffler }
119539beb93cSSam Leffler 
119639beb93cSSam Leffler 
eap_ttls_process_phase2_mschapv2(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,struct ttls_parse_avp * parse)119739beb93cSSam Leffler static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
119839beb93cSSam Leffler 					    struct eap_ttls_data *data,
119939beb93cSSam Leffler 					    struct eap_method_ret *ret,
120039beb93cSSam Leffler 					    struct ttls_parse_avp *parse)
120139beb93cSSam Leffler {
1202f05cddf9SRui Paulo #ifdef EAP_MSCHAPv2
120339beb93cSSam Leffler 	if (parse->mschapv2_error) {
120439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received "
120539beb93cSSam Leffler 			   "MS-CHAP-Error - failed");
120639beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
120739beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
120839beb93cSSam Leffler 		/* Reply with empty data to ACK error */
120939beb93cSSam Leffler 		return 1;
121039beb93cSSam Leffler 	}
121139beb93cSSam Leffler 
121239beb93cSSam Leffler 	if (parse->mschapv2 == NULL) {
121339beb93cSSam Leffler #ifdef EAP_TNC
121439beb93cSSam Leffler 		if (data->phase2_success && parse->eapdata) {
121539beb93cSSam Leffler 			/*
121639beb93cSSam Leffler 			 * Allow EAP-TNC to be started after successfully
121739beb93cSSam Leffler 			 * completed MSCHAPV2.
121839beb93cSSam Leffler 			 */
121939beb93cSSam Leffler 			return 1;
122039beb93cSSam Leffler 		}
122139beb93cSSam Leffler #endif /* EAP_TNC */
122239beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP "
122339beb93cSSam Leffler 			   "received for Phase2 MSCHAPV2");
122439beb93cSSam Leffler 		return -1;
122539beb93cSSam Leffler 	}
122639beb93cSSam Leffler 	if (parse->mschapv2[0] != data->ident) {
122739beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 "
122839beb93cSSam Leffler 			   "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)",
122939beb93cSSam Leffler 			   parse->mschapv2[0], data->ident);
123039beb93cSSam Leffler 		return -1;
123139beb93cSSam Leffler 	}
123239beb93cSSam Leffler 	if (!data->auth_response_valid ||
123339beb93cSSam Leffler 	    mschapv2_verify_auth_response(data->auth_response,
123439beb93cSSam Leffler 					  parse->mschapv2 + 1, 42)) {
123539beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator "
123639beb93cSSam Leffler 			   "response in Phase 2 MSCHAPV2 success request");
123739beb93cSSam Leffler 		return -1;
123839beb93cSSam Leffler 	}
123939beb93cSSam Leffler 
124039beb93cSSam Leffler 	wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 "
124139beb93cSSam Leffler 		   "authentication succeeded");
124239beb93cSSam Leffler 	ret->methodState = METHOD_DONE;
124339beb93cSSam Leffler 	ret->decision = DECISION_UNCOND_SUCC;
124439beb93cSSam Leffler 	data->phase2_success = 1;
124539beb93cSSam Leffler 
124639beb93cSSam Leffler 	/*
124739beb93cSSam Leffler 	 * Reply with empty data; authentication server will reply
124839beb93cSSam Leffler 	 * with EAP-Success after this.
124939beb93cSSam Leffler 	 */
125039beb93cSSam Leffler 	return 1;
1251f05cddf9SRui Paulo #else /* EAP_MSCHAPv2 */
1252f05cddf9SRui Paulo 	wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
1253f05cddf9SRui Paulo 	return -1;
1254f05cddf9SRui Paulo #endif /* EAP_MSCHAPv2 */
125539beb93cSSam Leffler }
125639beb93cSSam Leffler 
125739beb93cSSam Leffler 
125839beb93cSSam Leffler #ifdef EAP_TNC
eap_ttls_process_tnc_start(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,struct ttls_parse_avp * parse,struct wpabuf ** resp)125939beb93cSSam Leffler static int eap_ttls_process_tnc_start(struct eap_sm *sm,
126039beb93cSSam Leffler 				      struct eap_ttls_data *data,
126139beb93cSSam Leffler 				      struct eap_method_ret *ret,
126239beb93cSSam Leffler 				      struct ttls_parse_avp *parse,
126339beb93cSSam Leffler 				      struct wpabuf **resp)
126439beb93cSSam Leffler {
126539beb93cSSam Leffler 	/* TNC uses inner EAP method after non-EAP TTLS phase 2. */
126639beb93cSSam Leffler 	if (parse->eapdata == NULL) {
126739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received "
126839beb93cSSam Leffler 			   "unexpected tunneled data (no EAP)");
126939beb93cSSam Leffler 		return -1;
127039beb93cSSam Leffler 	}
127139beb93cSSam Leffler 
127239beb93cSSam Leffler 	if (!data->ready_for_tnc) {
127339beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received "
127439beb93cSSam Leffler 			   "EAP after non-EAP, but not ready for TNC");
127539beb93cSSam Leffler 		return -1;
127639beb93cSSam Leffler 	}
127739beb93cSSam Leffler 
127839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
127939beb93cSSam Leffler 		   "non-EAP method");
128039beb93cSSam Leffler 	data->tnc_started = 1;
128139beb93cSSam Leffler 
128239beb93cSSam Leffler 	if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0)
128339beb93cSSam Leffler 		return -1;
128439beb93cSSam Leffler 
128539beb93cSSam Leffler 	return 0;
128639beb93cSSam Leffler }
128739beb93cSSam Leffler #endif /* EAP_TNC */
128839beb93cSSam Leffler 
128939beb93cSSam Leffler 
eap_ttls_process_decrypted(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,u8 identifier,struct ttls_parse_avp * parse,struct wpabuf * in_decrypted,struct wpabuf ** out_data)129039beb93cSSam Leffler static int eap_ttls_process_decrypted(struct eap_sm *sm,
129139beb93cSSam Leffler 				      struct eap_ttls_data *data,
129239beb93cSSam Leffler 				      struct eap_method_ret *ret,
129339beb93cSSam Leffler 				      u8 identifier,
129439beb93cSSam Leffler 				      struct ttls_parse_avp *parse,
129539beb93cSSam Leffler 				      struct wpabuf *in_decrypted,
129639beb93cSSam Leffler 				      struct wpabuf **out_data)
129739beb93cSSam Leffler {
129839beb93cSSam Leffler 	struct wpabuf *resp = NULL;
129939beb93cSSam Leffler 	struct eap_peer_config *config = eap_get_config(sm);
130039beb93cSSam Leffler 	int res;
130139beb93cSSam Leffler 	enum phase2_types phase2_type = data->phase2_type;
130239beb93cSSam Leffler 
130339beb93cSSam Leffler #ifdef EAP_TNC
130439beb93cSSam Leffler 	if (data->tnc_started)
130539beb93cSSam Leffler 		phase2_type = EAP_TTLS_PHASE2_EAP;
130639beb93cSSam Leffler #endif /* EAP_TNC */
130739beb93cSSam Leffler 
130839beb93cSSam Leffler 	switch (phase2_type) {
130939beb93cSSam Leffler 	case EAP_TTLS_PHASE2_EAP:
131039beb93cSSam Leffler 		if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) <
131139beb93cSSam Leffler 		    0)
131239beb93cSSam Leffler 			return -1;
131339beb93cSSam Leffler 		break;
131439beb93cSSam Leffler 	case EAP_TTLS_PHASE2_MSCHAPV2:
131539beb93cSSam Leffler 		res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse);
131639beb93cSSam Leffler #ifdef EAP_TNC
131739beb93cSSam Leffler 		if (res == 1 && parse->eapdata && data->phase2_success) {
131839beb93cSSam Leffler 			/*
131939beb93cSSam Leffler 			 * TNC may be required as the next
132039beb93cSSam Leffler 			 * authentication method within the tunnel.
132139beb93cSSam Leffler 			 */
132239beb93cSSam Leffler 			ret->methodState = METHOD_MAY_CONT;
132339beb93cSSam Leffler 			data->ready_for_tnc = 1;
132439beb93cSSam Leffler 			if (eap_ttls_process_tnc_start(sm, data, ret, parse,
132539beb93cSSam Leffler 						       &resp) == 0)
132639beb93cSSam Leffler 				break;
132739beb93cSSam Leffler 		}
132839beb93cSSam Leffler #endif /* EAP_TNC */
132939beb93cSSam Leffler 		return res;
133039beb93cSSam Leffler 	case EAP_TTLS_PHASE2_MSCHAP:
133139beb93cSSam Leffler 	case EAP_TTLS_PHASE2_PAP:
133239beb93cSSam Leffler 	case EAP_TTLS_PHASE2_CHAP:
133339beb93cSSam Leffler #ifdef EAP_TNC
133439beb93cSSam Leffler 		if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) <
133539beb93cSSam Leffler 		    0)
133639beb93cSSam Leffler 			return -1;
133739beb93cSSam Leffler 		break;
133839beb93cSSam Leffler #else /* EAP_TNC */
133939beb93cSSam Leffler 		/* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled
134039beb93cSSam Leffler 		 * requests to the supplicant */
134139beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected "
134239beb93cSSam Leffler 			   "tunneled data");
134339beb93cSSam Leffler 		return -1;
134439beb93cSSam Leffler #endif /* EAP_TNC */
134539beb93cSSam Leffler 	}
134639beb93cSSam Leffler 
134739beb93cSSam Leffler 	if (resp) {
134839beb93cSSam Leffler 		if (eap_ttls_encrypt_response(sm, data, resp, identifier,
134939beb93cSSam Leffler 					      out_data) < 0)
135039beb93cSSam Leffler 			return -1;
135139beb93cSSam Leffler 	} else if (config->pending_req_identity ||
135239beb93cSSam Leffler 		   config->pending_req_password ||
135339beb93cSSam Leffler 		   config->pending_req_otp ||
135485732ac8SCy Schubert 		   config->pending_req_new_password ||
135585732ac8SCy Schubert 		   config->pending_req_sim) {
13564bc52338SCy Schubert 		wpabuf_clear_free(data->pending_phase2_req);
135739beb93cSSam Leffler 		data->pending_phase2_req = wpabuf_dup(in_decrypted);
135839beb93cSSam Leffler 	}
135939beb93cSSam Leffler 
136039beb93cSSam Leffler 	return 0;
136139beb93cSSam Leffler }
136239beb93cSSam Leffler 
136339beb93cSSam Leffler 
eap_ttls_implicit_identity_request(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,u8 identifier,struct wpabuf ** out_data)136439beb93cSSam Leffler static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
136539beb93cSSam Leffler 					      struct eap_ttls_data *data,
136639beb93cSSam Leffler 					      struct eap_method_ret *ret,
136739beb93cSSam Leffler 					      u8 identifier,
136839beb93cSSam Leffler 					      struct wpabuf **out_data)
136939beb93cSSam Leffler {
137039beb93cSSam Leffler 	int retval = 0;
137139beb93cSSam Leffler 	struct eap_hdr *hdr;
137239beb93cSSam Leffler 	struct wpabuf *resp;
137339beb93cSSam Leffler 
137439beb93cSSam Leffler 	hdr = (struct eap_hdr *) eap_ttls_fake_identity_request();
137539beb93cSSam Leffler 	if (hdr == NULL) {
137639beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
137739beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
137839beb93cSSam Leffler 		return -1;
137939beb93cSSam Leffler 	}
138039beb93cSSam Leffler 
138139beb93cSSam Leffler 	resp = NULL;
138239beb93cSSam Leffler 	if (eap_ttls_phase2_request(sm, data, ret, hdr, &resp)) {
138339beb93cSSam Leffler 		wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request "
138439beb93cSSam Leffler 			   "processing failed");
138539beb93cSSam Leffler 		retval = -1;
138639beb93cSSam Leffler 	} else {
1387f05cddf9SRui Paulo 		struct eap_peer_config *config = eap_get_config(sm);
1388f05cddf9SRui Paulo 		if (resp == NULL &&
1389f05cddf9SRui Paulo 		    (config->pending_req_identity ||
1390f05cddf9SRui Paulo 		     config->pending_req_password ||
1391f05cddf9SRui Paulo 		     config->pending_req_otp ||
139285732ac8SCy Schubert 		     config->pending_req_new_password ||
139385732ac8SCy Schubert 		     config->pending_req_sim)) {
1394f05cddf9SRui Paulo 			/*
1395f05cddf9SRui Paulo 			 * Use empty buffer to force implicit request
1396f05cddf9SRui Paulo 			 * processing when EAP request is re-processed after
1397f05cddf9SRui Paulo 			 * user input.
1398f05cddf9SRui Paulo 			 */
13994bc52338SCy Schubert 			wpabuf_clear_free(data->pending_phase2_req);
1400f05cddf9SRui Paulo 			data->pending_phase2_req = wpabuf_alloc(0);
1401f05cddf9SRui Paulo 		}
1402f05cddf9SRui Paulo 
140339beb93cSSam Leffler 		retval = eap_ttls_encrypt_response(sm, data, resp, identifier,
140439beb93cSSam Leffler 						   out_data);
140539beb93cSSam Leffler 	}
140639beb93cSSam Leffler 
140739beb93cSSam Leffler 	os_free(hdr);
140839beb93cSSam Leffler 
140939beb93cSSam Leffler 	if (retval < 0) {
141039beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
141139beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
141239beb93cSSam Leffler 	}
141339beb93cSSam Leffler 
141439beb93cSSam Leffler 	return retval;
141539beb93cSSam Leffler }
141639beb93cSSam Leffler 
141739beb93cSSam Leffler 
eap_ttls_phase2_start(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,u8 identifier,struct wpabuf ** out_data)141839beb93cSSam Leffler static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data,
141939beb93cSSam Leffler 				 struct eap_method_ret *ret, u8 identifier,
142039beb93cSSam Leffler 				 struct wpabuf **out_data)
142139beb93cSSam Leffler {
142239beb93cSSam Leffler 	data->phase2_start = 0;
142339beb93cSSam Leffler 
142439beb93cSSam Leffler 	/*
142539beb93cSSam Leffler 	 * EAP-TTLS does not use Phase2 on fast re-auth; this must be done only
142639beb93cSSam Leffler 	 * if TLS part was indeed resuming a previous session. Most
142739beb93cSSam Leffler 	 * Authentication Servers terminate EAP-TTLS before reaching this
142839beb93cSSam Leffler 	 * point, but some do not. Make wpa_supplicant stop phase 2 here, if
142939beb93cSSam Leffler 	 * needed.
143039beb93cSSam Leffler 	 */
143139beb93cSSam Leffler 	if (data->reauth &&
143239beb93cSSam Leffler 	    tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
143339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - "
143439beb93cSSam Leffler 			   "skip phase 2");
143539beb93cSSam Leffler 		*out_data = eap_peer_tls_build_ack(identifier, EAP_TYPE_TTLS,
143639beb93cSSam Leffler 						   data->ttls_version);
143739beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
143839beb93cSSam Leffler 		ret->decision = DECISION_UNCOND_SUCC;
143939beb93cSSam Leffler 		data->phase2_success = 1;
144039beb93cSSam Leffler 		return 0;
144139beb93cSSam Leffler 	}
144239beb93cSSam Leffler 
144339beb93cSSam Leffler 	return eap_ttls_implicit_identity_request(sm, data, ret, identifier,
144439beb93cSSam Leffler 						  out_data);
144539beb93cSSam Leffler }
144639beb93cSSam Leffler 
144739beb93cSSam Leffler 
eap_ttls_decrypt(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,u8 identifier,const struct wpabuf * in_data,struct wpabuf ** out_data)144839beb93cSSam Leffler static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
144939beb93cSSam Leffler 			    struct eap_method_ret *ret, u8 identifier,
145039beb93cSSam Leffler 			    const struct wpabuf *in_data,
145139beb93cSSam Leffler 			    struct wpabuf **out_data)
145239beb93cSSam Leffler {
145339beb93cSSam Leffler 	struct wpabuf *in_decrypted = NULL;
145439beb93cSSam Leffler 	int retval = 0;
145539beb93cSSam Leffler 	struct ttls_parse_avp parse;
145639beb93cSSam Leffler 
145739beb93cSSam Leffler 	os_memset(&parse, 0, sizeof(parse));
145839beb93cSSam Leffler 
145939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
146039beb93cSSam Leffler 		   " Phase 2",
146139beb93cSSam Leffler 		   in_data ? (unsigned long) wpabuf_len(in_data) : 0);
146239beb93cSSam Leffler 
146339beb93cSSam Leffler 	if (data->pending_phase2_req) {
146439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - "
146539beb93cSSam Leffler 			   "skip decryption and use old data");
146639beb93cSSam Leffler 		/* Clear TLS reassembly state. */
146739beb93cSSam Leffler 		eap_peer_tls_reset_input(&data->ssl);
146839beb93cSSam Leffler 
146939beb93cSSam Leffler 		in_decrypted = data->pending_phase2_req;
147039beb93cSSam Leffler 		data->pending_phase2_req = NULL;
147139beb93cSSam Leffler 		if (wpabuf_len(in_decrypted) == 0) {
14724bc52338SCy Schubert 			wpabuf_clear_free(in_decrypted);
147339beb93cSSam Leffler 			return eap_ttls_implicit_identity_request(
147439beb93cSSam Leffler 				sm, data, ret, identifier, out_data);
147539beb93cSSam Leffler 		}
147639beb93cSSam Leffler 		goto continue_req;
147739beb93cSSam Leffler 	}
147839beb93cSSam Leffler 
147939beb93cSSam Leffler 	if ((in_data == NULL || wpabuf_len(in_data) == 0) &&
148039beb93cSSam Leffler 	    data->phase2_start) {
1481c1d255d3SCy Schubert start:
148239beb93cSSam Leffler 		return eap_ttls_phase2_start(sm, data, ret, identifier,
148339beb93cSSam Leffler 					     out_data);
148439beb93cSSam Leffler 	}
148539beb93cSSam Leffler 
148639beb93cSSam Leffler 	if (in_data == NULL || wpabuf_len(in_data) == 0) {
148739beb93cSSam Leffler 		/* Received TLS ACK - requesting more fragments */
148839beb93cSSam Leffler 		return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS,
148939beb93cSSam Leffler 					    data->ttls_version,
149039beb93cSSam Leffler 					    identifier, NULL, out_data);
149139beb93cSSam Leffler 	}
149239beb93cSSam Leffler 
149339beb93cSSam Leffler 	retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
149439beb93cSSam Leffler 	if (retval)
149539beb93cSSam Leffler 		goto done;
1496c1d255d3SCy Schubert 	if (wpabuf_len(in_decrypted) == 0) {
1497c1d255d3SCy Schubert 		wpabuf_free(in_decrypted);
1498c1d255d3SCy Schubert 		goto start;
1499c1d255d3SCy Schubert 	}
1500c1d255d3SCy Schubert 
1501*a90b9d01SCy Schubert 	/* RFC 9190 Section 2.5 */
1502c1d255d3SCy Schubert 	if (data->ssl.tls_v13 && wpabuf_len(in_decrypted) == 1 &&
1503c1d255d3SCy Schubert 	    *wpabuf_head_u8(in_decrypted) == 0) {
1504c1d255d3SCy Schubert 		wpa_printf(MSG_DEBUG,
1505*a90b9d01SCy Schubert 			   "EAP-TLS: ACKing protected success indication (appl data 0x00)");
1506c1d255d3SCy Schubert 		eap_peer_tls_reset_output(&data->ssl);
1507c1d255d3SCy Schubert 		wpabuf_free(in_decrypted);
1508c1d255d3SCy Schubert 		return 1;
1509c1d255d3SCy Schubert 	}
151039beb93cSSam Leffler 
151139beb93cSSam Leffler continue_req:
151239beb93cSSam Leffler 	data->phase2_start = 0;
151339beb93cSSam Leffler 
151439beb93cSSam Leffler 	if (eap_ttls_parse_avps(in_decrypted, &parse) < 0) {
151539beb93cSSam Leffler 		retval = -1;
151639beb93cSSam Leffler 		goto done;
151739beb93cSSam Leffler 	}
151839beb93cSSam Leffler 
151939beb93cSSam Leffler 	retval = eap_ttls_process_decrypted(sm, data, ret, identifier,
152039beb93cSSam Leffler 					    &parse, in_decrypted, out_data);
152139beb93cSSam Leffler 
152239beb93cSSam Leffler done:
15234bc52338SCy Schubert 	wpabuf_clear_free(in_decrypted);
152439beb93cSSam Leffler 	os_free(parse.eapdata);
152539beb93cSSam Leffler 
152639beb93cSSam Leffler 	if (retval < 0) {
152739beb93cSSam Leffler 		ret->methodState = METHOD_DONE;
152839beb93cSSam Leffler 		ret->decision = DECISION_FAIL;
152939beb93cSSam Leffler 	}
153039beb93cSSam Leffler 
153139beb93cSSam Leffler 	return retval;
153239beb93cSSam Leffler }
153339beb93cSSam Leffler 
153439beb93cSSam Leffler 
eap_ttls_process_handshake(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret,u8 identifier,const struct wpabuf * in_data,struct wpabuf ** out_data)153539beb93cSSam Leffler static int eap_ttls_process_handshake(struct eap_sm *sm,
153639beb93cSSam Leffler 				      struct eap_ttls_data *data,
153739beb93cSSam Leffler 				      struct eap_method_ret *ret,
153839beb93cSSam Leffler 				      u8 identifier,
1539325151a3SRui Paulo 				      const struct wpabuf *in_data,
154039beb93cSSam Leffler 				      struct wpabuf **out_data)
154139beb93cSSam Leffler {
154239beb93cSSam Leffler 	int res;
154339beb93cSSam Leffler 
1544780fb4a2SCy Schubert 	if (sm->waiting_ext_cert_check && data->pending_resp) {
1545780fb4a2SCy Schubert 		struct eap_peer_config *config = eap_get_config(sm);
1546780fb4a2SCy Schubert 
1547780fb4a2SCy Schubert 		if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
1548780fb4a2SCy Schubert 			wpa_printf(MSG_DEBUG,
1549780fb4a2SCy Schubert 				   "EAP-TTLS: External certificate check succeeded - continue handshake");
1550780fb4a2SCy Schubert 			*out_data = data->pending_resp;
1551780fb4a2SCy Schubert 			data->pending_resp = NULL;
1552780fb4a2SCy Schubert 			sm->waiting_ext_cert_check = 0;
1553780fb4a2SCy Schubert 			return 0;
1554780fb4a2SCy Schubert 		}
1555780fb4a2SCy Schubert 
1556780fb4a2SCy Schubert 		if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
1557780fb4a2SCy Schubert 			wpa_printf(MSG_DEBUG,
1558780fb4a2SCy Schubert 				   "EAP-TTLS: External certificate check failed - force authentication failure");
1559780fb4a2SCy Schubert 			ret->methodState = METHOD_DONE;
1560780fb4a2SCy Schubert 			ret->decision = DECISION_FAIL;
1561780fb4a2SCy Schubert 			sm->waiting_ext_cert_check = 0;
1562780fb4a2SCy Schubert 			return 0;
1563780fb4a2SCy Schubert 		}
1564780fb4a2SCy Schubert 
1565780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG,
1566780fb4a2SCy Schubert 			   "EAP-TTLS: Continuing to wait external server certificate validation");
1567780fb4a2SCy Schubert 		return 0;
1568780fb4a2SCy Schubert 	}
1569780fb4a2SCy Schubert 
157039beb93cSSam Leffler 	res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
157139beb93cSSam Leffler 					  data->ttls_version, identifier,
1572325151a3SRui Paulo 					  in_data, out_data);
1573325151a3SRui Paulo 	if (res < 0) {
1574325151a3SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS processing failed");
1575325151a3SRui Paulo 		ret->methodState = METHOD_DONE;
1576325151a3SRui Paulo 		ret->decision = DECISION_FAIL;
1577325151a3SRui Paulo 		return -1;
1578325151a3SRui Paulo 	}
157939beb93cSSam Leffler 
1580780fb4a2SCy Schubert 	if (sm->waiting_ext_cert_check) {
1581780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG,
1582780fb4a2SCy Schubert 			   "EAP-TTLS: Waiting external server certificate validation");
15834bc52338SCy Schubert 		wpabuf_clear_free(data->pending_resp);
1584780fb4a2SCy Schubert 		data->pending_resp = *out_data;
1585780fb4a2SCy Schubert 		*out_data = NULL;
1586780fb4a2SCy Schubert 		return 0;
1587780fb4a2SCy Schubert 	}
1588780fb4a2SCy Schubert 
158939beb93cSSam Leffler 	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
159039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to "
159139beb93cSSam Leffler 			   "Phase 2");
159239beb93cSSam Leffler 		if (data->resuming) {
159339beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth - may "
159439beb93cSSam Leffler 				   "skip Phase 2");
159539beb93cSSam Leffler 			ret->decision = DECISION_COND_SUCC;
159639beb93cSSam Leffler 			ret->methodState = METHOD_MAY_CONT;
159739beb93cSSam Leffler 		}
159839beb93cSSam Leffler 		data->phase2_start = 1;
159939beb93cSSam Leffler 		eap_ttls_v0_derive_key(sm, data);
160039beb93cSSam Leffler 
160139beb93cSSam Leffler 		if (*out_data == NULL || wpabuf_len(*out_data) == 0) {
160239beb93cSSam Leffler 			if (eap_ttls_decrypt(sm, data, ret, identifier,
160339beb93cSSam Leffler 					     NULL, out_data)) {
160439beb93cSSam Leffler 				wpa_printf(MSG_WARNING, "EAP-TTLS: "
160539beb93cSSam Leffler 					   "failed to process early "
160639beb93cSSam Leffler 					   "start for Phase 2");
160739beb93cSSam Leffler 			}
160839beb93cSSam Leffler 			res = 0;
160939beb93cSSam Leffler 		}
161039beb93cSSam Leffler 		data->resuming = 0;
161139beb93cSSam Leffler 	}
161239beb93cSSam Leffler 
161339beb93cSSam Leffler 	if (res == 2) {
161439beb93cSSam Leffler 		/*
161539beb93cSSam Leffler 		 * Application data included in the handshake message.
161639beb93cSSam Leffler 		 */
16174bc52338SCy Schubert 		wpabuf_clear_free(data->pending_phase2_req);
161839beb93cSSam Leffler 		data->pending_phase2_req = *out_data;
161939beb93cSSam Leffler 		*out_data = NULL;
1620325151a3SRui Paulo 		res = eap_ttls_decrypt(sm, data, ret, identifier, in_data,
162139beb93cSSam Leffler 				       out_data);
162239beb93cSSam Leffler 	}
162339beb93cSSam Leffler 
162439beb93cSSam Leffler 	return res;
162539beb93cSSam Leffler }
162639beb93cSSam Leffler 
162739beb93cSSam Leffler 
eap_ttls_check_auth_status(struct eap_sm * sm,struct eap_ttls_data * data,struct eap_method_ret * ret)162839beb93cSSam Leffler static void eap_ttls_check_auth_status(struct eap_sm *sm,
162939beb93cSSam Leffler 				       struct eap_ttls_data *data,
163039beb93cSSam Leffler 				       struct eap_method_ret *ret)
163139beb93cSSam Leffler {
1632f05cddf9SRui Paulo 	if (ret->methodState == METHOD_DONE) {
1633c1d255d3SCy Schubert 		ret->allowNotifications = false;
163439beb93cSSam Leffler 		if (ret->decision == DECISION_UNCOND_SUCC ||
163539beb93cSSam Leffler 		    ret->decision == DECISION_COND_SUCC) {
163639beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
163739beb93cSSam Leffler 				   "completed successfully");
163839beb93cSSam Leffler 			data->phase2_success = 1;
1639780fb4a2SCy Schubert 			data->decision_succ = ret->decision;
164039beb93cSSam Leffler #ifdef EAP_TNC
164139beb93cSSam Leffler 			if (!data->ready_for_tnc && !data->tnc_started) {
164239beb93cSSam Leffler 				/*
164339beb93cSSam Leffler 				 * TNC may be required as the next
164439beb93cSSam Leffler 				 * authentication method within the tunnel.
164539beb93cSSam Leffler 				 */
164639beb93cSSam Leffler 				ret->methodState = METHOD_MAY_CONT;
164739beb93cSSam Leffler 				data->ready_for_tnc = 1;
164839beb93cSSam Leffler 			}
164939beb93cSSam Leffler #endif /* EAP_TNC */
165039beb93cSSam Leffler 		}
1651f05cddf9SRui Paulo 	} else if (ret->methodState == METHOD_MAY_CONT &&
165239beb93cSSam Leffler 		   (ret->decision == DECISION_UNCOND_SUCC ||
165339beb93cSSam Leffler 		    ret->decision == DECISION_COND_SUCC)) {
165439beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
165539beb93cSSam Leffler 				   "completed successfully (MAY_CONT)");
165639beb93cSSam Leffler 			data->phase2_success = 1;
1657780fb4a2SCy Schubert 			data->decision_succ = ret->decision;
1658780fb4a2SCy Schubert 	} else if (data->decision_succ != DECISION_FAIL &&
1659780fb4a2SCy Schubert 		   data->phase2_success &&
1660780fb4a2SCy Schubert 		   !data->ssl.tls_out) {
1661780fb4a2SCy Schubert 		/*
1662780fb4a2SCy Schubert 		 * This is needed to cover the case where the final Phase 2
1663780fb4a2SCy Schubert 		 * message gets fragmented since fragmentation clears
1664780fb4a2SCy Schubert 		 * decision back to FAIL.
1665780fb4a2SCy Schubert 		 */
1666780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG,
1667780fb4a2SCy Schubert 			   "EAP-TTLS: Restore success decision after fragmented frame sent completely");
1668780fb4a2SCy Schubert 		ret->decision = data->decision_succ;
166939beb93cSSam Leffler 	}
167039beb93cSSam Leffler }
167139beb93cSSam Leffler 
167239beb93cSSam Leffler 
eap_ttls_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)167339beb93cSSam Leffler static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv,
167439beb93cSSam Leffler 					struct eap_method_ret *ret,
167539beb93cSSam Leffler 					const struct wpabuf *reqData)
167639beb93cSSam Leffler {
167739beb93cSSam Leffler 	size_t left;
167839beb93cSSam Leffler 	int res;
167939beb93cSSam Leffler 	u8 flags, id;
168039beb93cSSam Leffler 	struct wpabuf *resp;
168139beb93cSSam Leffler 	const u8 *pos;
168239beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
1683325151a3SRui Paulo 	struct wpabuf msg;
168439beb93cSSam Leffler 
168539beb93cSSam Leffler 	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret,
168639beb93cSSam Leffler 					reqData, &left, &flags);
168739beb93cSSam Leffler 	if (pos == NULL)
168839beb93cSSam Leffler 		return NULL;
168939beb93cSSam Leffler 	id = eap_get_id(reqData);
169039beb93cSSam Leffler 
169139beb93cSSam Leffler 	if (flags & EAP_TLS_FLAGS_START) {
1692f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own "
1693f05cddf9SRui Paulo 			   "ver=%d)", flags & EAP_TLS_VERSION_MASK,
1694f05cddf9SRui Paulo 			   data->ttls_version);
169539beb93cSSam Leffler 
169639beb93cSSam Leffler 		/* RFC 5281, Ch. 9.2:
169739beb93cSSam Leffler 		 * "This packet MAY contain additional information in the form
169839beb93cSSam Leffler 		 * of AVPs, which may provide useful hints to the client"
169939beb93cSSam Leffler 		 * For now, ignore any potential extra data.
170039beb93cSSam Leffler 		 */
170139beb93cSSam Leffler 		left = 0;
170239beb93cSSam Leffler 	}
170339beb93cSSam Leffler 
1704325151a3SRui Paulo 	wpabuf_set(&msg, pos, left);
1705325151a3SRui Paulo 
170639beb93cSSam Leffler 	resp = NULL;
170739beb93cSSam Leffler 	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
170839beb93cSSam Leffler 	    !data->resuming) {
170939beb93cSSam Leffler 		res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp);
171039beb93cSSam Leffler 	} else {
171139beb93cSSam Leffler 		res = eap_ttls_process_handshake(sm, data, ret, id,
1712325151a3SRui Paulo 						 &msg, &resp);
171339beb93cSSam Leffler 	}
171439beb93cSSam Leffler 
171539beb93cSSam Leffler 	eap_ttls_check_auth_status(sm, data, ret);
171639beb93cSSam Leffler 
171739beb93cSSam Leffler 	/* FIX: what about res == -1? Could just move all error processing into
171839beb93cSSam Leffler 	 * the other functions and get rid of this res==1 case here. */
171939beb93cSSam Leffler 	if (res == 1) {
17204bc52338SCy Schubert 		wpabuf_clear_free(resp);
172139beb93cSSam Leffler 		return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS,
172239beb93cSSam Leffler 					      data->ttls_version);
172339beb93cSSam Leffler 	}
172439beb93cSSam Leffler 	return resp;
172539beb93cSSam Leffler }
172639beb93cSSam Leffler 
172739beb93cSSam Leffler 
eap_ttls_has_reauth_data(struct eap_sm * sm,void * priv)1728c1d255d3SCy Schubert static bool eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)
172939beb93cSSam Leffler {
173039beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
1731*a90b9d01SCy Schubert 
173239beb93cSSam Leffler 	return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
1733*a90b9d01SCy Schubert 		data->phase2_success && data->phase2_auth != ALWAYS;
173439beb93cSSam Leffler }
173539beb93cSSam Leffler 
173639beb93cSSam Leffler 
eap_ttls_deinit_for_reauth(struct eap_sm * sm,void * priv)173739beb93cSSam Leffler static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
173839beb93cSSam Leffler {
173939beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
174085732ac8SCy Schubert 
174185732ac8SCy Schubert 	if (data->phase2_priv && data->phase2_method &&
174285732ac8SCy Schubert 	    data->phase2_method->deinit_for_reauth)
174385732ac8SCy Schubert 		data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
17444bc52338SCy Schubert 	wpabuf_clear_free(data->pending_phase2_req);
174539beb93cSSam Leffler 	data->pending_phase2_req = NULL;
17464bc52338SCy Schubert 	wpabuf_clear_free(data->pending_resp);
1747780fb4a2SCy Schubert 	data->pending_resp = NULL;
1748780fb4a2SCy Schubert 	data->decision_succ = DECISION_FAIL;
174939beb93cSSam Leffler #ifdef EAP_TNC
175039beb93cSSam Leffler 	data->ready_for_tnc = 0;
175139beb93cSSam Leffler 	data->tnc_started = 0;
175239beb93cSSam Leffler #endif /* EAP_TNC */
175339beb93cSSam Leffler }
175439beb93cSSam Leffler 
175539beb93cSSam Leffler 
eap_ttls_init_for_reauth(struct eap_sm * sm,void * priv)175639beb93cSSam Leffler static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)
175739beb93cSSam Leffler {
175839beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
17595b9c547cSRui Paulo 	eap_ttls_free_key(data);
17605b9c547cSRui Paulo 	os_free(data->session_id);
17615b9c547cSRui Paulo 	data->session_id = NULL;
176239beb93cSSam Leffler 	if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
176339beb93cSSam Leffler 		os_free(data);
176439beb93cSSam Leffler 		return NULL;
176539beb93cSSam Leffler 	}
176639beb93cSSam Leffler 	if (data->phase2_priv && data->phase2_method &&
176739beb93cSSam Leffler 	    data->phase2_method->init_for_reauth)
176839beb93cSSam Leffler 		data->phase2_method->init_for_reauth(sm, data->phase2_priv);
176939beb93cSSam Leffler 	data->phase2_start = 0;
177039beb93cSSam Leffler 	data->phase2_success = 0;
177139beb93cSSam Leffler 	data->resuming = 1;
177239beb93cSSam Leffler 	data->reauth = 1;
177339beb93cSSam Leffler 	return priv;
177439beb93cSSam Leffler }
177539beb93cSSam Leffler 
177639beb93cSSam Leffler 
eap_ttls_get_status(struct eap_sm * sm,void * priv,char * buf,size_t buflen,int verbose)177739beb93cSSam Leffler static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf,
177839beb93cSSam Leffler 			       size_t buflen, int verbose)
177939beb93cSSam Leffler {
178039beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
178139beb93cSSam Leffler 	int len, ret;
178239beb93cSSam Leffler 
178339beb93cSSam Leffler 	len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
178439beb93cSSam Leffler 	ret = os_snprintf(buf + len, buflen - len,
178539beb93cSSam Leffler 			  "EAP-TTLSv%d Phase2 method=",
178639beb93cSSam Leffler 			  data->ttls_version);
17875b9c547cSRui Paulo 	if (os_snprintf_error(buflen - len, ret))
178839beb93cSSam Leffler 		return len;
178939beb93cSSam Leffler 	len += ret;
179039beb93cSSam Leffler 	switch (data->phase2_type) {
179139beb93cSSam Leffler 	case EAP_TTLS_PHASE2_EAP:
179239beb93cSSam Leffler 		ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n",
179339beb93cSSam Leffler 				  data->phase2_method ?
179439beb93cSSam Leffler 				  data->phase2_method->name : "?");
179539beb93cSSam Leffler 		break;
179639beb93cSSam Leffler 	case EAP_TTLS_PHASE2_MSCHAPV2:
179739beb93cSSam Leffler 		ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n");
179839beb93cSSam Leffler 		break;
179939beb93cSSam Leffler 	case EAP_TTLS_PHASE2_MSCHAP:
180039beb93cSSam Leffler 		ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n");
180139beb93cSSam Leffler 		break;
180239beb93cSSam Leffler 	case EAP_TTLS_PHASE2_PAP:
180339beb93cSSam Leffler 		ret = os_snprintf(buf + len, buflen - len, "PAP\n");
180439beb93cSSam Leffler 		break;
180539beb93cSSam Leffler 	case EAP_TTLS_PHASE2_CHAP:
180639beb93cSSam Leffler 		ret = os_snprintf(buf + len, buflen - len, "CHAP\n");
180739beb93cSSam Leffler 		break;
180839beb93cSSam Leffler 	default:
180939beb93cSSam Leffler 		ret = 0;
181039beb93cSSam Leffler 		break;
181139beb93cSSam Leffler 	}
18125b9c547cSRui Paulo 	if (os_snprintf_error(buflen - len, ret))
181339beb93cSSam Leffler 		return len;
181439beb93cSSam Leffler 	len += ret;
181539beb93cSSam Leffler 
181639beb93cSSam Leffler 	return len;
181739beb93cSSam Leffler }
181839beb93cSSam Leffler 
181939beb93cSSam Leffler 
eap_ttls_isKeyAvailable(struct eap_sm * sm,void * priv)1820c1d255d3SCy Schubert static bool eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv)
182139beb93cSSam Leffler {
182239beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
182339beb93cSSam Leffler 	return data->key_data != NULL && data->phase2_success;
182439beb93cSSam Leffler }
182539beb93cSSam Leffler 
182639beb93cSSam Leffler 
eap_ttls_getKey(struct eap_sm * sm,void * priv,size_t * len)182739beb93cSSam Leffler static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
182839beb93cSSam Leffler {
182939beb93cSSam Leffler 	struct eap_ttls_data *data = priv;
183039beb93cSSam Leffler 	u8 *key;
183139beb93cSSam Leffler 
183239beb93cSSam Leffler 	if (data->key_data == NULL || !data->phase2_success)
183339beb93cSSam Leffler 		return NULL;
183439beb93cSSam Leffler 
183585732ac8SCy Schubert 	key = os_memdup(data->key_data, EAP_TLS_KEY_LEN);
183639beb93cSSam Leffler 	if (key == NULL)
183739beb93cSSam Leffler 		return NULL;
183839beb93cSSam Leffler 
183939beb93cSSam Leffler 	*len = EAP_TLS_KEY_LEN;
184039beb93cSSam Leffler 
184139beb93cSSam Leffler 	return key;
184239beb93cSSam Leffler }
184339beb93cSSam Leffler 
184439beb93cSSam Leffler 
eap_ttls_get_session_id(struct eap_sm * sm,void * priv,size_t * len)18455b9c547cSRui Paulo static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
18465b9c547cSRui Paulo {
18475b9c547cSRui Paulo 	struct eap_ttls_data *data = priv;
18485b9c547cSRui Paulo 	u8 *id;
18495b9c547cSRui Paulo 
18505b9c547cSRui Paulo 	if (data->session_id == NULL || !data->phase2_success)
18515b9c547cSRui Paulo 		return NULL;
18525b9c547cSRui Paulo 
185385732ac8SCy Schubert 	id = os_memdup(data->session_id, data->id_len);
18545b9c547cSRui Paulo 	if (id == NULL)
18555b9c547cSRui Paulo 		return NULL;
18565b9c547cSRui Paulo 
18575b9c547cSRui Paulo 	*len = data->id_len;
18585b9c547cSRui Paulo 
18595b9c547cSRui Paulo 	return id;
18605b9c547cSRui Paulo }
18615b9c547cSRui Paulo 
18625b9c547cSRui Paulo 
eap_ttls_get_emsk(struct eap_sm * sm,void * priv,size_t * len)18635b9c547cSRui Paulo static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
18645b9c547cSRui Paulo {
18655b9c547cSRui Paulo 	struct eap_ttls_data *data = priv;
18665b9c547cSRui Paulo 	u8 *key;
18675b9c547cSRui Paulo 
18685b9c547cSRui Paulo 	if (data->key_data == NULL)
18695b9c547cSRui Paulo 		return NULL;
18705b9c547cSRui Paulo 
187185732ac8SCy Schubert 	key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
18725b9c547cSRui Paulo 	if (key == NULL)
18735b9c547cSRui Paulo 		return NULL;
18745b9c547cSRui Paulo 
18755b9c547cSRui Paulo 	*len = EAP_EMSK_LEN;
18765b9c547cSRui Paulo 
18775b9c547cSRui Paulo 	return key;
18785b9c547cSRui Paulo }
18795b9c547cSRui Paulo 
18805b9c547cSRui Paulo 
eap_peer_ttls_register(void)188139beb93cSSam Leffler int eap_peer_ttls_register(void)
188239beb93cSSam Leffler {
188339beb93cSSam Leffler 	struct eap_method *eap;
188439beb93cSSam Leffler 
188539beb93cSSam Leffler 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
188639beb93cSSam Leffler 				    EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
188739beb93cSSam Leffler 	if (eap == NULL)
188839beb93cSSam Leffler 		return -1;
188939beb93cSSam Leffler 
189039beb93cSSam Leffler 	eap->init = eap_ttls_init;
189139beb93cSSam Leffler 	eap->deinit = eap_ttls_deinit;
189239beb93cSSam Leffler 	eap->process = eap_ttls_process;
189339beb93cSSam Leffler 	eap->isKeyAvailable = eap_ttls_isKeyAvailable;
189439beb93cSSam Leffler 	eap->getKey = eap_ttls_getKey;
18955b9c547cSRui Paulo 	eap->getSessionId = eap_ttls_get_session_id;
189639beb93cSSam Leffler 	eap->get_status = eap_ttls_get_status;
189739beb93cSSam Leffler 	eap->has_reauth_data = eap_ttls_has_reauth_data;
189839beb93cSSam Leffler 	eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;
189939beb93cSSam Leffler 	eap->init_for_reauth = eap_ttls_init_for_reauth;
19005b9c547cSRui Paulo 	eap->get_emsk = eap_ttls_get_emsk;
190139beb93cSSam Leffler 
1902780fb4a2SCy Schubert 	return eap_peer_method_register(eap);
190339beb93cSSam Leffler }
1904