xref: /dflybsd-src/contrib/wpa_supplicant/src/eap_peer/eap_teap.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
1*a1157835SDaniel Fojt /*
2*a1157835SDaniel Fojt  * EAP peer method: EAP-TEAP (RFC 7170)
3*a1157835SDaniel Fojt  * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
4*a1157835SDaniel Fojt  *
5*a1157835SDaniel Fojt  * This software may be distributed under the terms of the BSD license.
6*a1157835SDaniel Fojt  * See README for more details.
7*a1157835SDaniel Fojt  */
8*a1157835SDaniel Fojt 
9*a1157835SDaniel Fojt #include "includes.h"
10*a1157835SDaniel Fojt 
11*a1157835SDaniel Fojt #include "common.h"
12*a1157835SDaniel Fojt #include "crypto/tls.h"
13*a1157835SDaniel Fojt #include "eap_common/eap_teap_common.h"
14*a1157835SDaniel Fojt #include "eap_i.h"
15*a1157835SDaniel Fojt #include "eap_tls_common.h"
16*a1157835SDaniel Fojt #include "eap_config.h"
17*a1157835SDaniel Fojt #include "eap_teap_pac.h"
18*a1157835SDaniel Fojt 
19*a1157835SDaniel Fojt #ifdef EAP_TEAP_DYNAMIC
20*a1157835SDaniel Fojt #include "eap_teap_pac.c"
21*a1157835SDaniel Fojt #endif /* EAP_TEAP_DYNAMIC */
22*a1157835SDaniel Fojt 
23*a1157835SDaniel Fojt 
24*a1157835SDaniel Fojt static void eap_teap_deinit(struct eap_sm *sm, void *priv);
25*a1157835SDaniel Fojt 
26*a1157835SDaniel Fojt 
27*a1157835SDaniel Fojt struct eap_teap_data {
28*a1157835SDaniel Fojt 	struct eap_ssl_data ssl;
29*a1157835SDaniel Fojt 
30*a1157835SDaniel Fojt 	u8 teap_version; /* Negotiated version */
31*a1157835SDaniel Fojt 	u8 received_version; /* Version number received during negotiation */
32*a1157835SDaniel Fojt 	u16 tls_cs;
33*a1157835SDaniel Fojt 
34*a1157835SDaniel Fojt 	const struct eap_method *phase2_method;
35*a1157835SDaniel Fojt 	void *phase2_priv;
36*a1157835SDaniel Fojt 	int phase2_success;
37*a1157835SDaniel Fojt 	int inner_method_done;
38*a1157835SDaniel Fojt 	int result_success_done;
39*a1157835SDaniel Fojt 	int on_tx_completion;
40*a1157835SDaniel Fojt 
41*a1157835SDaniel Fojt 	struct eap_method_type phase2_type;
42*a1157835SDaniel Fojt 	struct eap_method_type *phase2_types;
43*a1157835SDaniel Fojt 	size_t num_phase2_types;
44*a1157835SDaniel Fojt 	int resuming; /* starting a resumed session */
45*a1157835SDaniel Fojt #define EAP_TEAP_PROV_UNAUTH 1
46*a1157835SDaniel Fojt #define EAP_TEAP_PROV_AUTH 2
47*a1157835SDaniel Fojt 	int provisioning_allowed; /* Allowed PAC provisioning modes */
48*a1157835SDaniel Fojt 	int provisioning; /* doing PAC provisioning (not the normal auth) */
49*a1157835SDaniel Fojt 	int anon_provisioning; /* doing anonymous (unauthenticated)
50*a1157835SDaniel Fojt 				* provisioning */
51*a1157835SDaniel Fojt 	int session_ticket_used;
52*a1157835SDaniel Fojt 	int test_outer_tlvs;
53*a1157835SDaniel Fojt 
54*a1157835SDaniel Fojt 	u8 key_data[EAP_TEAP_KEY_LEN];
55*a1157835SDaniel Fojt 	u8 *session_id;
56*a1157835SDaniel Fojt 	size_t id_len;
57*a1157835SDaniel Fojt 	u8 emsk[EAP_EMSK_LEN];
58*a1157835SDaniel Fojt 	int success;
59*a1157835SDaniel Fojt 
60*a1157835SDaniel Fojt 	struct eap_teap_pac *pac;
61*a1157835SDaniel Fojt 	struct eap_teap_pac *current_pac;
62*a1157835SDaniel Fojt 	size_t max_pac_list_len;
63*a1157835SDaniel Fojt 	int use_pac_binary_format;
64*a1157835SDaniel Fojt 
65*a1157835SDaniel Fojt 	u8 simck_msk[EAP_TEAP_SIMCK_LEN];
66*a1157835SDaniel Fojt 	u8 simck_emsk[EAP_TEAP_SIMCK_LEN];
67*a1157835SDaniel Fojt 	int simck_idx;
68*a1157835SDaniel Fojt 	int cmk_emsk_available;
69*a1157835SDaniel Fojt 
70*a1157835SDaniel Fojt 	struct wpabuf *pending_phase2_req;
71*a1157835SDaniel Fojt 	struct wpabuf *pending_resp;
72*a1157835SDaniel Fojt 	struct wpabuf *server_outer_tlvs;
73*a1157835SDaniel Fojt 	struct wpabuf *peer_outer_tlvs;
74*a1157835SDaniel Fojt };
75*a1157835SDaniel Fojt 
76*a1157835SDaniel Fojt 
eap_teap_session_ticket_cb(void * ctx,const u8 * ticket,size_t len,const u8 * client_random,const u8 * server_random,u8 * master_secret)77*a1157835SDaniel Fojt static int eap_teap_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,
78*a1157835SDaniel Fojt 				      const u8 *client_random,
79*a1157835SDaniel Fojt 				      const u8 *server_random,
80*a1157835SDaniel Fojt 				      u8 *master_secret)
81*a1157835SDaniel Fojt {
82*a1157835SDaniel Fojt 	struct eap_teap_data *data = ctx;
83*a1157835SDaniel Fojt 
84*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "EAP-TEAP: SessionTicket callback");
85*a1157835SDaniel Fojt 
86*a1157835SDaniel Fojt 	if (!master_secret) {
87*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
88*a1157835SDaniel Fojt 			   "EAP-TEAP: SessionTicket failed - fall back to full TLS handshake");
89*a1157835SDaniel Fojt 		data->session_ticket_used = 0;
90*a1157835SDaniel Fojt 		if (data->provisioning_allowed) {
91*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
92*a1157835SDaniel Fojt 				   "EAP-TEAP: Try to provision a new PAC-Key");
93*a1157835SDaniel Fojt 			data->provisioning = 1;
94*a1157835SDaniel Fojt 			data->current_pac = NULL;
95*a1157835SDaniel Fojt 		}
96*a1157835SDaniel Fojt 		return 0;
97*a1157835SDaniel Fojt 	}
98*a1157835SDaniel Fojt 
99*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "EAP-TEAP: SessionTicket", ticket, len);
100*a1157835SDaniel Fojt 
101*a1157835SDaniel Fojt 	if (!data->current_pac) {
102*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
103*a1157835SDaniel Fojt 			   "EAP-TEAP: No PAC-Key available for using SessionTicket");
104*a1157835SDaniel Fojt 		data->session_ticket_used = 0;
105*a1157835SDaniel Fojt 		return 0;
106*a1157835SDaniel Fojt 	}
107*a1157835SDaniel Fojt 
108*a1157835SDaniel Fojt 	/* EAP-TEAP uses PAC-Key as the TLS master_secret */
109*a1157835SDaniel Fojt 	os_memcpy(master_secret, data->current_pac->pac_key,
110*a1157835SDaniel Fojt 		  EAP_TEAP_PAC_KEY_LEN);
111*a1157835SDaniel Fojt 
112*a1157835SDaniel Fojt 	data->session_ticket_used = 1;
113*a1157835SDaniel Fojt 
114*a1157835SDaniel Fojt 	return 1;
115*a1157835SDaniel Fojt }
116*a1157835SDaniel Fojt 
117*a1157835SDaniel Fojt 
eap_teap_parse_phase1(struct eap_teap_data * data,const char * phase1)118*a1157835SDaniel Fojt static void eap_teap_parse_phase1(struct eap_teap_data *data,
119*a1157835SDaniel Fojt 				  const char *phase1)
120*a1157835SDaniel Fojt {
121*a1157835SDaniel Fojt 	const char *pos;
122*a1157835SDaniel Fojt 
123*a1157835SDaniel Fojt 	pos = os_strstr(phase1, "teap_provisioning=");
124*a1157835SDaniel Fojt 	if (pos) {
125*a1157835SDaniel Fojt 		data->provisioning_allowed = atoi(pos + 18);
126*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
127*a1157835SDaniel Fojt 			   "EAP-TEAP: Automatic PAC provisioning mode: %d",
128*a1157835SDaniel Fojt 			   data->provisioning_allowed);
129*a1157835SDaniel Fojt 	}
130*a1157835SDaniel Fojt 
131*a1157835SDaniel Fojt 	pos = os_strstr(phase1, "teap_max_pac_list_len=");
132*a1157835SDaniel Fojt 	if (pos) {
133*a1157835SDaniel Fojt 		data->max_pac_list_len = atoi(pos + 22);
134*a1157835SDaniel Fojt 		if (data->max_pac_list_len == 0)
135*a1157835SDaniel Fojt 			data->max_pac_list_len = 1;
136*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "EAP-TEAP: Maximum PAC list length: %lu",
137*a1157835SDaniel Fojt 			   (unsigned long) data->max_pac_list_len);
138*a1157835SDaniel Fojt 	}
139*a1157835SDaniel Fojt 
140*a1157835SDaniel Fojt 	if (os_strstr(phase1, "teap_pac_format=binary")) {
141*a1157835SDaniel Fojt 		data->use_pac_binary_format = 1;
142*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
143*a1157835SDaniel Fojt 			   "EAP-TEAP: Using binary format for PAC list");
144*a1157835SDaniel Fojt 	}
145*a1157835SDaniel Fojt 
146*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
147*a1157835SDaniel Fojt 	if (os_strstr(phase1, "teap_test_outer_tlvs=1"))
148*a1157835SDaniel Fojt 		data->test_outer_tlvs = 1;
149*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
150*a1157835SDaniel Fojt }
151*a1157835SDaniel Fojt 
152*a1157835SDaniel Fojt 
eap_teap_init(struct eap_sm * sm)153*a1157835SDaniel Fojt static void * eap_teap_init(struct eap_sm *sm)
154*a1157835SDaniel Fojt {
155*a1157835SDaniel Fojt 	struct eap_teap_data *data;
156*a1157835SDaniel Fojt 	struct eap_peer_config *config = eap_get_config(sm);
157*a1157835SDaniel Fojt 
158*a1157835SDaniel Fojt 	if (!config)
159*a1157835SDaniel Fojt 		return NULL;
160*a1157835SDaniel Fojt 
161*a1157835SDaniel Fojt 	data = os_zalloc(sizeof(*data));
162*a1157835SDaniel Fojt 	if (!data)
163*a1157835SDaniel Fojt 		return NULL;
164*a1157835SDaniel Fojt 	data->teap_version = EAP_TEAP_VERSION;
165*a1157835SDaniel Fojt 	data->max_pac_list_len = 10;
166*a1157835SDaniel Fojt 
167*a1157835SDaniel Fojt 	if (config->phase1)
168*a1157835SDaniel Fojt 		eap_teap_parse_phase1(data, config->phase1);
169*a1157835SDaniel Fojt 
170*a1157835SDaniel Fojt 	if ((data->provisioning_allowed & EAP_TEAP_PROV_AUTH) &&
171*a1157835SDaniel Fojt 	    !config->ca_cert && !config->ca_path) {
172*a1157835SDaniel Fojt 		/* Prevent PAC provisioning without mutual authentication
173*a1157835SDaniel Fojt 		 * (either by validating server certificate or by suitable
174*a1157835SDaniel Fojt 		 * inner EAP method). */
175*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
176*a1157835SDaniel Fojt 			   "EAP-TEAP: Disable authenticated provisioning due to no ca_cert/ca_path");
177*a1157835SDaniel Fojt 		data->provisioning_allowed &= ~EAP_TEAP_PROV_AUTH;
178*a1157835SDaniel Fojt 	}
179*a1157835SDaniel Fojt 
180*a1157835SDaniel Fojt 	if (eap_peer_select_phase2_methods(config, "auth=",
181*a1157835SDaniel Fojt 					   &data->phase2_types,
182*a1157835SDaniel Fojt 					   &data->num_phase2_types) < 0) {
183*a1157835SDaniel Fojt 		eap_teap_deinit(sm, data);
184*a1157835SDaniel Fojt 		return NULL;
185*a1157835SDaniel Fojt 	}
186*a1157835SDaniel Fojt 
187*a1157835SDaniel Fojt 	data->phase2_type.vendor = EAP_VENDOR_IETF;
188*a1157835SDaniel Fojt 	data->phase2_type.method = EAP_TYPE_NONE;
189*a1157835SDaniel Fojt 
190*a1157835SDaniel Fojt 	config->teap_anon_dh = !!(data->provisioning_allowed &
191*a1157835SDaniel Fojt 				  EAP_TEAP_PROV_UNAUTH);
192*a1157835SDaniel Fojt 	if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TEAP)) {
193*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "EAP-TEAP: Failed to initialize SSL");
194*a1157835SDaniel Fojt 		eap_teap_deinit(sm, data);
195*a1157835SDaniel Fojt 		return NULL;
196*a1157835SDaniel Fojt 	}
197*a1157835SDaniel Fojt 
198*a1157835SDaniel Fojt 	if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,
199*a1157835SDaniel Fojt 						 eap_teap_session_ticket_cb,
200*a1157835SDaniel Fojt 						 data) < 0) {
201*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
202*a1157835SDaniel Fojt 			   "EAP-TEAP: Failed to set SessionTicket callback");
203*a1157835SDaniel Fojt 		eap_teap_deinit(sm, data);
204*a1157835SDaniel Fojt 		return NULL;
205*a1157835SDaniel Fojt 	}
206*a1157835SDaniel Fojt 
207*a1157835SDaniel Fojt 	if (!config->pac_file) {
208*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "EAP-TEAP: No PAC file configured");
209*a1157835SDaniel Fojt 		eap_teap_deinit(sm, data);
210*a1157835SDaniel Fojt 		return NULL;
211*a1157835SDaniel Fojt 	}
212*a1157835SDaniel Fojt 
213*a1157835SDaniel Fojt 	if (data->use_pac_binary_format &&
214*a1157835SDaniel Fojt 	    eap_teap_load_pac_bin(sm, &data->pac, config->pac_file) < 0) {
215*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "EAP-TEAP: Failed to load PAC file");
216*a1157835SDaniel Fojt 		eap_teap_deinit(sm, data);
217*a1157835SDaniel Fojt 		return NULL;
218*a1157835SDaniel Fojt 	}
219*a1157835SDaniel Fojt 
220*a1157835SDaniel Fojt 	if (!data->use_pac_binary_format &&
221*a1157835SDaniel Fojt 	    eap_teap_load_pac(sm, &data->pac, config->pac_file) < 0) {
222*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "EAP-TEAP: Failed to load PAC file");
223*a1157835SDaniel Fojt 		eap_teap_deinit(sm, data);
224*a1157835SDaniel Fojt 		return NULL;
225*a1157835SDaniel Fojt 	}
226*a1157835SDaniel Fojt 	eap_teap_pac_list_truncate(data->pac, data->max_pac_list_len);
227*a1157835SDaniel Fojt 
228*a1157835SDaniel Fojt 	return data;
229*a1157835SDaniel Fojt }
230*a1157835SDaniel Fojt 
231*a1157835SDaniel Fojt 
eap_teap_clear(struct eap_teap_data * data)232*a1157835SDaniel Fojt static void eap_teap_clear(struct eap_teap_data *data)
233*a1157835SDaniel Fojt {
234*a1157835SDaniel Fojt 	forced_memzero(data->key_data, EAP_TEAP_KEY_LEN);
235*a1157835SDaniel Fojt 	forced_memzero(data->emsk, EAP_EMSK_LEN);
236*a1157835SDaniel Fojt 	os_free(data->session_id);
237*a1157835SDaniel Fojt 	data->session_id = NULL;
238*a1157835SDaniel Fojt 	wpabuf_free(data->pending_phase2_req);
239*a1157835SDaniel Fojt 	data->pending_phase2_req = NULL;
240*a1157835SDaniel Fojt 	wpabuf_free(data->pending_resp);
241*a1157835SDaniel Fojt 	data->pending_resp = NULL;
242*a1157835SDaniel Fojt 	wpabuf_free(data->server_outer_tlvs);
243*a1157835SDaniel Fojt 	data->server_outer_tlvs = NULL;
244*a1157835SDaniel Fojt 	wpabuf_free(data->peer_outer_tlvs);
245*a1157835SDaniel Fojt 	data->peer_outer_tlvs = NULL;
246*a1157835SDaniel Fojt 	forced_memzero(data->simck_msk, EAP_TEAP_SIMCK_LEN);
247*a1157835SDaniel Fojt 	forced_memzero(data->simck_emsk, EAP_TEAP_SIMCK_LEN);
248*a1157835SDaniel Fojt }
249*a1157835SDaniel Fojt 
250*a1157835SDaniel Fojt 
eap_teap_deinit(struct eap_sm * sm,void * priv)251*a1157835SDaniel Fojt static void eap_teap_deinit(struct eap_sm *sm, void *priv)
252*a1157835SDaniel Fojt {
253*a1157835SDaniel Fojt 	struct eap_teap_data *data = priv;
254*a1157835SDaniel Fojt 	struct eap_teap_pac *pac, *prev;
255*a1157835SDaniel Fojt 
256*a1157835SDaniel Fojt 	if (!data)
257*a1157835SDaniel Fojt 		return;
258*a1157835SDaniel Fojt 	if (data->phase2_priv && data->phase2_method)
259*a1157835SDaniel Fojt 		data->phase2_method->deinit(sm, data->phase2_priv);
260*a1157835SDaniel Fojt 	eap_teap_clear(data);
261*a1157835SDaniel Fojt 	os_free(data->phase2_types);
262*a1157835SDaniel Fojt 	eap_peer_tls_ssl_deinit(sm, &data->ssl);
263*a1157835SDaniel Fojt 
264*a1157835SDaniel Fojt 	pac = data->pac;
265*a1157835SDaniel Fojt 	prev = NULL;
266*a1157835SDaniel Fojt 	while (pac) {
267*a1157835SDaniel Fojt 		prev = pac;
268*a1157835SDaniel Fojt 		pac = pac->next;
269*a1157835SDaniel Fojt 		eap_teap_free_pac(prev);
270*a1157835SDaniel Fojt 	}
271*a1157835SDaniel Fojt 
272*a1157835SDaniel Fojt 	os_free(data);
273*a1157835SDaniel Fojt }
274*a1157835SDaniel Fojt 
275*a1157835SDaniel Fojt 
eap_teap_derive_msk(struct eap_teap_data * data)276*a1157835SDaniel Fojt static int eap_teap_derive_msk(struct eap_teap_data *data)
277*a1157835SDaniel Fojt {
278*a1157835SDaniel Fojt 	/* FIX: RFC 7170 does not describe whether MSK or EMSK based S-IMCK[j]
279*a1157835SDaniel Fojt 	 * is used in this derivation */
280*a1157835SDaniel Fojt 	if (eap_teap_derive_eap_msk(data->simck_msk, data->key_data) < 0 ||
281*a1157835SDaniel Fojt 	    eap_teap_derive_eap_emsk(data->simck_msk, data->emsk) < 0)
282*a1157835SDaniel Fojt 		return -1;
283*a1157835SDaniel Fojt 	data->success = 1;
284*a1157835SDaniel Fojt 	return 0;
285*a1157835SDaniel Fojt }
286*a1157835SDaniel Fojt 
287*a1157835SDaniel Fojt 
eap_teap_derive_key_auth(struct eap_sm * sm,struct eap_teap_data * data)288*a1157835SDaniel Fojt static int eap_teap_derive_key_auth(struct eap_sm *sm,
289*a1157835SDaniel Fojt 				    struct eap_teap_data *data)
290*a1157835SDaniel Fojt {
291*a1157835SDaniel Fojt 	int res;
292*a1157835SDaniel Fojt 
293*a1157835SDaniel Fojt 	/* RFC 7170, Section 5.1 */
294*a1157835SDaniel Fojt 	res = tls_connection_export_key(sm->ssl_ctx, data->ssl.conn,
295*a1157835SDaniel Fojt 					TEAP_TLS_EXPORTER_LABEL_SKS, NULL, 0,
296*a1157835SDaniel Fojt 					data->simck_msk, EAP_TEAP_SIMCK_LEN);
297*a1157835SDaniel Fojt 	if (res)
298*a1157835SDaniel Fojt 		return res;
299*a1157835SDaniel Fojt 	wpa_hexdump_key(MSG_DEBUG,
300*a1157835SDaniel Fojt 			"EAP-TEAP: session_key_seed (S-IMCK[0])",
301*a1157835SDaniel Fojt 			data->simck_msk, EAP_TEAP_SIMCK_LEN);
302*a1157835SDaniel Fojt 	os_memcpy(data->simck_emsk, data->simck_msk, EAP_TEAP_SIMCK_LEN);
303*a1157835SDaniel Fojt 	data->simck_idx = 0;
304*a1157835SDaniel Fojt 	return 0;
305*a1157835SDaniel Fojt }
306*a1157835SDaniel Fojt 
307*a1157835SDaniel Fojt 
eap_teap_init_phase2_method(struct eap_sm * sm,struct eap_teap_data * data)308*a1157835SDaniel Fojt static int eap_teap_init_phase2_method(struct eap_sm *sm,
309*a1157835SDaniel Fojt 				       struct eap_teap_data *data)
310*a1157835SDaniel Fojt {
311*a1157835SDaniel Fojt 	data->inner_method_done = 0;
312*a1157835SDaniel Fojt 	data->phase2_method =
313*a1157835SDaniel Fojt 		eap_peer_get_eap_method(data->phase2_type.vendor,
314*a1157835SDaniel Fojt 					data->phase2_type.method);
315*a1157835SDaniel Fojt 	if (!data->phase2_method)
316*a1157835SDaniel Fojt 		return -1;
317*a1157835SDaniel Fojt 
318*a1157835SDaniel Fojt 	sm->init_phase2 = 1;
319*a1157835SDaniel Fojt 	data->phase2_priv = data->phase2_method->init(sm);
320*a1157835SDaniel Fojt 	sm->init_phase2 = 0;
321*a1157835SDaniel Fojt 
322*a1157835SDaniel Fojt 	return data->phase2_priv == NULL ? -1 : 0;
323*a1157835SDaniel Fojt }
324*a1157835SDaniel Fojt 
325*a1157835SDaniel Fojt 
eap_teap_select_phase2_method(struct eap_teap_data * data,u8 type)326*a1157835SDaniel Fojt static int eap_teap_select_phase2_method(struct eap_teap_data *data, u8 type)
327*a1157835SDaniel Fojt {
328*a1157835SDaniel Fojt 	size_t i;
329*a1157835SDaniel Fojt 
330*a1157835SDaniel Fojt 	/* TODO: TNC with anonymous provisioning; need to require both
331*a1157835SDaniel Fojt 	 * completed inner EAP authentication (EAP-pwd or EAP-EKE) and TNC */
332*a1157835SDaniel Fojt 
333*a1157835SDaniel Fojt 	if (data->anon_provisioning &&
334*a1157835SDaniel Fojt 	    !eap_teap_allowed_anon_prov_phase2_method(type)) {
335*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
336*a1157835SDaniel Fojt 			   "EAP-TEAP: EAP type %u not allowed during unauthenticated provisioning",
337*a1157835SDaniel Fojt 			   type);
338*a1157835SDaniel Fojt 		return -1;
339*a1157835SDaniel Fojt 	}
340*a1157835SDaniel Fojt 
341*a1157835SDaniel Fojt #ifdef EAP_TNC
342*a1157835SDaniel Fojt 	if (type == EAP_TYPE_TNC) {
343*a1157835SDaniel Fojt 		data->phase2_type.vendor = EAP_VENDOR_IETF;
344*a1157835SDaniel Fojt 		data->phase2_type.method = EAP_TYPE_TNC;
345*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
346*a1157835SDaniel Fojt 			   "EAP-TEAP: Selected Phase 2 EAP vendor %d method %d for TNC",
347*a1157835SDaniel Fojt 			   data->phase2_type.vendor,
348*a1157835SDaniel Fojt 			   data->phase2_type.method);
349*a1157835SDaniel Fojt 		return 0;
350*a1157835SDaniel Fojt 	}
351*a1157835SDaniel Fojt #endif /* EAP_TNC */
352*a1157835SDaniel Fojt 
353*a1157835SDaniel Fojt 	for (i = 0; i < data->num_phase2_types; i++) {
354*a1157835SDaniel Fojt 		if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
355*a1157835SDaniel Fojt 		    data->phase2_types[i].method != type)
356*a1157835SDaniel Fojt 			continue;
357*a1157835SDaniel Fojt 
358*a1157835SDaniel Fojt 		data->phase2_type.vendor = data->phase2_types[i].vendor;
359*a1157835SDaniel Fojt 		data->phase2_type.method = data->phase2_types[i].method;
360*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
361*a1157835SDaniel Fojt 			   "EAP-TEAP: Selected Phase 2 EAP vendor %d method %d",
362*a1157835SDaniel Fojt 			   data->phase2_type.vendor,
363*a1157835SDaniel Fojt 			   data->phase2_type.method);
364*a1157835SDaniel Fojt 		break;
365*a1157835SDaniel Fojt 	}
366*a1157835SDaniel Fojt 
367*a1157835SDaniel Fojt 	if (type != data->phase2_type.method || type == EAP_TYPE_NONE)
368*a1157835SDaniel Fojt 		return -1;
369*a1157835SDaniel Fojt 
370*a1157835SDaniel Fojt 	return 0;
371*a1157835SDaniel Fojt }
372*a1157835SDaniel Fojt 
373*a1157835SDaniel Fojt 
eap_teap_phase2_request(struct eap_sm * sm,struct eap_teap_data * data,struct eap_method_ret * ret,struct eap_hdr * hdr,struct wpabuf ** resp)374*a1157835SDaniel Fojt static int eap_teap_phase2_request(struct eap_sm *sm,
375*a1157835SDaniel Fojt 				   struct eap_teap_data *data,
376*a1157835SDaniel Fojt 				   struct eap_method_ret *ret,
377*a1157835SDaniel Fojt 				   struct eap_hdr *hdr,
378*a1157835SDaniel Fojt 				   struct wpabuf **resp)
379*a1157835SDaniel Fojt {
380*a1157835SDaniel Fojt 	size_t len = be_to_host16(hdr->length);
381*a1157835SDaniel Fojt 	u8 *pos;
382*a1157835SDaniel Fojt 	struct eap_method_ret iret;
383*a1157835SDaniel Fojt 	struct eap_peer_config *config = eap_get_config(sm);
384*a1157835SDaniel Fojt 	struct wpabuf msg;
385*a1157835SDaniel Fojt 
386*a1157835SDaniel Fojt 	if (len <= sizeof(struct eap_hdr)) {
387*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
388*a1157835SDaniel Fojt 			   "EAP-TEAP: too short Phase 2 request (len=%lu)",
389*a1157835SDaniel Fojt 			   (unsigned long) len);
390*a1157835SDaniel Fojt 		return -1;
391*a1157835SDaniel Fojt 	}
392*a1157835SDaniel Fojt 	pos = (u8 *) (hdr + 1);
393*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "EAP-TEAP: Phase 2 Request: type=%d", *pos);
394*a1157835SDaniel Fojt 	if (*pos == EAP_TYPE_IDENTITY) {
395*a1157835SDaniel Fojt 		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
396*a1157835SDaniel Fojt 		return 0;
397*a1157835SDaniel Fojt 	}
398*a1157835SDaniel Fojt 
399*a1157835SDaniel Fojt 	if (data->phase2_priv && data->phase2_method &&
400*a1157835SDaniel Fojt 	    *pos != data->phase2_type.method) {
401*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
402*a1157835SDaniel Fojt 			   "EAP-TEAP: Phase 2 EAP sequence - deinitialize previous method");
403*a1157835SDaniel Fojt 		data->phase2_method->deinit(sm, data->phase2_priv);
404*a1157835SDaniel Fojt 		data->phase2_method = NULL;
405*a1157835SDaniel Fojt 		data->phase2_priv = NULL;
406*a1157835SDaniel Fojt 		data->phase2_type.vendor = EAP_VENDOR_IETF;
407*a1157835SDaniel Fojt 		data->phase2_type.method = EAP_TYPE_NONE;
408*a1157835SDaniel Fojt 	}
409*a1157835SDaniel Fojt 
410*a1157835SDaniel Fojt 	if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
411*a1157835SDaniel Fojt 	    data->phase2_type.method == EAP_TYPE_NONE &&
412*a1157835SDaniel Fojt 	    eap_teap_select_phase2_method(data, *pos) < 0) {
413*a1157835SDaniel Fojt 		if (eap_peer_tls_phase2_nak(data->phase2_types,
414*a1157835SDaniel Fojt 					    data->num_phase2_types,
415*a1157835SDaniel Fojt 					    hdr, resp))
416*a1157835SDaniel Fojt 			return -1;
417*a1157835SDaniel Fojt 		return 0;
418*a1157835SDaniel Fojt 	}
419*a1157835SDaniel Fojt 
420*a1157835SDaniel Fojt 	if ((!data->phase2_priv && eap_teap_init_phase2_method(sm, data) < 0) ||
421*a1157835SDaniel Fojt 	    !data->phase2_method) {
422*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
423*a1157835SDaniel Fojt 			   "EAP-TEAP: Failed to initialize Phase 2 EAP method %d",
424*a1157835SDaniel Fojt 			   *pos);
425*a1157835SDaniel Fojt 		ret->methodState = METHOD_DONE;
426*a1157835SDaniel Fojt 		ret->decision = DECISION_FAIL;
427*a1157835SDaniel Fojt 		return -1;
428*a1157835SDaniel Fojt 	}
429*a1157835SDaniel Fojt 
430*a1157835SDaniel Fojt 	os_memset(&iret, 0, sizeof(iret));
431*a1157835SDaniel Fojt 	wpabuf_set(&msg, hdr, len);
432*a1157835SDaniel Fojt 	*resp = data->phase2_method->process(sm, data->phase2_priv, &iret,
433*a1157835SDaniel Fojt 					     &msg);
434*a1157835SDaniel Fojt 	if (iret.methodState == METHOD_DONE)
435*a1157835SDaniel Fojt 		data->inner_method_done = 1;
436*a1157835SDaniel Fojt 	if (!(*resp) ||
437*a1157835SDaniel Fojt 	    (iret.methodState == METHOD_DONE &&
438*a1157835SDaniel Fojt 	     iret.decision == DECISION_FAIL)) {
439*a1157835SDaniel Fojt 		ret->methodState = METHOD_DONE;
440*a1157835SDaniel Fojt 		ret->decision = DECISION_FAIL;
441*a1157835SDaniel Fojt 	} else if ((iret.methodState == METHOD_DONE ||
442*a1157835SDaniel Fojt 		    iret.methodState == METHOD_MAY_CONT) &&
443*a1157835SDaniel Fojt 		   (iret.decision == DECISION_UNCOND_SUCC ||
444*a1157835SDaniel Fojt 		    iret.decision == DECISION_COND_SUCC)) {
445*a1157835SDaniel Fojt 		data->phase2_success = 1;
446*a1157835SDaniel Fojt 	}
447*a1157835SDaniel Fojt 
448*a1157835SDaniel Fojt 	if (!(*resp) && config &&
449*a1157835SDaniel Fojt 	    (config->pending_req_identity || config->pending_req_password ||
450*a1157835SDaniel Fojt 	     config->pending_req_otp || config->pending_req_new_password ||
451*a1157835SDaniel Fojt 	     config->pending_req_sim)) {
452*a1157835SDaniel Fojt 		wpabuf_free(data->pending_phase2_req);
453*a1157835SDaniel Fojt 		data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
454*a1157835SDaniel Fojt 	} else if (!(*resp))
455*a1157835SDaniel Fojt 		return -1;
456*a1157835SDaniel Fojt 
457*a1157835SDaniel Fojt 	return 0;
458*a1157835SDaniel Fojt }
459*a1157835SDaniel Fojt 
460*a1157835SDaniel Fojt 
eap_teap_tlv_nak(int vendor_id,int tlv_type)461*a1157835SDaniel Fojt static struct wpabuf * eap_teap_tlv_nak(int vendor_id, int tlv_type)
462*a1157835SDaniel Fojt {
463*a1157835SDaniel Fojt 	struct wpabuf *buf;
464*a1157835SDaniel Fojt 	struct teap_tlv_nak *nak;
465*a1157835SDaniel Fojt 
466*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
467*a1157835SDaniel Fojt 		   "EAP-TEAP: Add NAK TLV (Vendor-Id %u NAK-Type %u)",
468*a1157835SDaniel Fojt 		   vendor_id, tlv_type);
469*a1157835SDaniel Fojt 	buf = wpabuf_alloc(sizeof(*nak));
470*a1157835SDaniel Fojt 	if (!buf)
471*a1157835SDaniel Fojt 		return NULL;
472*a1157835SDaniel Fojt 	nak = wpabuf_put(buf, sizeof(*nak));
473*a1157835SDaniel Fojt 	nak->tlv_type = host_to_be16(TEAP_TLV_MANDATORY | TEAP_TLV_NAK);
474*a1157835SDaniel Fojt 	nak->length = host_to_be16(6);
475*a1157835SDaniel Fojt 	nak->vendor_id = host_to_be32(vendor_id);
476*a1157835SDaniel Fojt 	nak->nak_type = host_to_be16(tlv_type);
477*a1157835SDaniel Fojt 	return buf;
478*a1157835SDaniel Fojt }
479*a1157835SDaniel Fojt 
480*a1157835SDaniel Fojt 
eap_teap_tlv_pac_ack(void)481*a1157835SDaniel Fojt static struct wpabuf * eap_teap_tlv_pac_ack(void)
482*a1157835SDaniel Fojt {
483*a1157835SDaniel Fojt 	struct wpabuf *buf;
484*a1157835SDaniel Fojt 	struct teap_tlv_result *res;
485*a1157835SDaniel Fojt 	struct teap_tlv_pac_ack *ack;
486*a1157835SDaniel Fojt 
487*a1157835SDaniel Fojt 	buf = wpabuf_alloc(sizeof(*res) + sizeof(*ack));
488*a1157835SDaniel Fojt 	if (!buf)
489*a1157835SDaniel Fojt 		return NULL;
490*a1157835SDaniel Fojt 
491*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC TLV (ack)");
492*a1157835SDaniel Fojt 	ack = wpabuf_put(buf, sizeof(*ack));
493*a1157835SDaniel Fojt 	ack->tlv_type = host_to_be16(TEAP_TLV_PAC | TEAP_TLV_MANDATORY);
494*a1157835SDaniel Fojt 	ack->length = host_to_be16(sizeof(*ack) - sizeof(struct teap_tlv_hdr));
495*a1157835SDaniel Fojt 	ack->pac_type = host_to_be16(PAC_TYPE_PAC_ACKNOWLEDGEMENT);
496*a1157835SDaniel Fojt 	ack->pac_len = host_to_be16(2);
497*a1157835SDaniel Fojt 	ack->result = host_to_be16(TEAP_STATUS_SUCCESS);
498*a1157835SDaniel Fojt 
499*a1157835SDaniel Fojt 	return buf;
500*a1157835SDaniel Fojt }
501*a1157835SDaniel Fojt 
502*a1157835SDaniel Fojt 
eap_teap_process_eap_payload_tlv(struct eap_sm * sm,struct eap_teap_data * data,struct eap_method_ret * ret,u8 * eap_payload_tlv,size_t eap_payload_tlv_len)503*a1157835SDaniel Fojt static struct wpabuf * eap_teap_process_eap_payload_tlv(
504*a1157835SDaniel Fojt 	struct eap_sm *sm, struct eap_teap_data *data,
505*a1157835SDaniel Fojt 	struct eap_method_ret *ret,
506*a1157835SDaniel Fojt 	u8 *eap_payload_tlv, size_t eap_payload_tlv_len)
507*a1157835SDaniel Fojt {
508*a1157835SDaniel Fojt 	struct eap_hdr *hdr;
509*a1157835SDaniel Fojt 	struct wpabuf *resp = NULL;
510*a1157835SDaniel Fojt 
511*a1157835SDaniel Fojt 	if (eap_payload_tlv_len < sizeof(*hdr)) {
512*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
513*a1157835SDaniel Fojt 			   "EAP-TEAP: too short EAP Payload TLV (len=%lu)",
514*a1157835SDaniel Fojt 			   (unsigned long) eap_payload_tlv_len);
515*a1157835SDaniel Fojt 		return NULL;
516*a1157835SDaniel Fojt 	}
517*a1157835SDaniel Fojt 
518*a1157835SDaniel Fojt 	hdr = (struct eap_hdr *) eap_payload_tlv;
519*a1157835SDaniel Fojt 	if (be_to_host16(hdr->length) > eap_payload_tlv_len) {
520*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
521*a1157835SDaniel Fojt 			   "EAP-TEAP: EAP packet overflow in EAP Payload TLV");
522*a1157835SDaniel Fojt 		return NULL;
523*a1157835SDaniel Fojt 	}
524*a1157835SDaniel Fojt 
525*a1157835SDaniel Fojt 	if (hdr->code != EAP_CODE_REQUEST) {
526*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
527*a1157835SDaniel Fojt 			   "EAP-TEAP: Unexpected code=%d in Phase 2 EAP header",
528*a1157835SDaniel Fojt 			   hdr->code);
529*a1157835SDaniel Fojt 		return NULL;
530*a1157835SDaniel Fojt 	}
531*a1157835SDaniel Fojt 
532*a1157835SDaniel Fojt 	if (eap_teap_phase2_request(sm, data, ret, hdr, &resp)) {
533*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
534*a1157835SDaniel Fojt 			   "EAP-TEAP: Phase 2 Request processing failed");
535*a1157835SDaniel Fojt 		return NULL;
536*a1157835SDaniel Fojt 	}
537*a1157835SDaniel Fojt 
538*a1157835SDaniel Fojt 	return eap_teap_tlv_eap_payload(resp);
539*a1157835SDaniel Fojt }
540*a1157835SDaniel Fojt 
541*a1157835SDaniel Fojt 
eap_teap_process_basic_auth_req(struct eap_sm * sm,struct eap_teap_data * data,u8 * basic_auth_req,size_t basic_auth_req_len)542*a1157835SDaniel Fojt static struct wpabuf * eap_teap_process_basic_auth_req(
543*a1157835SDaniel Fojt 	struct eap_sm *sm, struct eap_teap_data *data,
544*a1157835SDaniel Fojt 	u8 *basic_auth_req, size_t basic_auth_req_len)
545*a1157835SDaniel Fojt {
546*a1157835SDaniel Fojt 	const u8 *identity, *password;
547*a1157835SDaniel Fojt 	size_t identity_len, password_len, plen;
548*a1157835SDaniel Fojt 	struct wpabuf *resp;
549*a1157835SDaniel Fojt 
550*a1157835SDaniel Fojt 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: Basic-Password-Auth-Req prompt",
551*a1157835SDaniel Fojt 			  basic_auth_req, basic_auth_req_len);
552*a1157835SDaniel Fojt 	/* TODO: send over control interface */
553*a1157835SDaniel Fojt 
554*a1157835SDaniel Fojt 	identity = eap_get_config_identity(sm, &identity_len);
555*a1157835SDaniel Fojt 	password = eap_get_config_password(sm, &password_len);
556*a1157835SDaniel Fojt 	if (!identity || !password ||
557*a1157835SDaniel Fojt 	    identity_len > 255 || password_len > 255) {
558*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
559*a1157835SDaniel Fojt 			   "EAP-TEAP: No username/password suitable for Basic-Password-Auth");
560*a1157835SDaniel Fojt 		return eap_teap_tlv_nak(0, TEAP_TLV_BASIC_PASSWORD_AUTH_REQ);
561*a1157835SDaniel Fojt 	}
562*a1157835SDaniel Fojt 
563*a1157835SDaniel Fojt 	plen = 1 + identity_len + 1 + password_len;
564*a1157835SDaniel Fojt 	resp = wpabuf_alloc(sizeof(struct teap_tlv_hdr) + plen);
565*a1157835SDaniel Fojt 	if (!resp)
566*a1157835SDaniel Fojt 		return NULL;
567*a1157835SDaniel Fojt 	eap_teap_put_tlv_hdr(resp, TEAP_TLV_BASIC_PASSWORD_AUTH_RESP, plen);
568*a1157835SDaniel Fojt 	wpabuf_put_u8(resp, identity_len);
569*a1157835SDaniel Fojt 	wpabuf_put_data(resp, identity, identity_len);
570*a1157835SDaniel Fojt 	wpabuf_put_u8(resp, password_len);
571*a1157835SDaniel Fojt 	wpabuf_put_data(resp, password, password_len);
572*a1157835SDaniel Fojt 	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TEAP: Basic-Password-Auth-Resp",
573*a1157835SDaniel Fojt 			    resp);
574*a1157835SDaniel Fojt 
575*a1157835SDaniel Fojt 	/* Assume this succeeds so that Result TLV(Success) from the server can
576*a1157835SDaniel Fojt 	 * be used to terminate TEAP. */
577*a1157835SDaniel Fojt 	data->phase2_success = 1;
578*a1157835SDaniel Fojt 
579*a1157835SDaniel Fojt 	return resp;
580*a1157835SDaniel Fojt }
581*a1157835SDaniel Fojt 
582*a1157835SDaniel Fojt 
583*a1157835SDaniel Fojt static int
eap_teap_validate_crypto_binding(struct eap_teap_data * data,const struct teap_tlv_crypto_binding * cb)584*a1157835SDaniel Fojt eap_teap_validate_crypto_binding(struct eap_teap_data *data,
585*a1157835SDaniel Fojt 				 const struct teap_tlv_crypto_binding *cb)
586*a1157835SDaniel Fojt {
587*a1157835SDaniel Fojt 	u8 flags, subtype;
588*a1157835SDaniel Fojt 
589*a1157835SDaniel Fojt 	subtype = cb->subtype & 0x0f;
590*a1157835SDaniel Fojt 	flags = cb->subtype >> 4;
591*a1157835SDaniel Fojt 
592*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
593*a1157835SDaniel Fojt 		   "EAP-TEAP: Crypto-Binding TLV: Version %u Received Version %u Flags %u Sub-Type %u",
594*a1157835SDaniel Fojt 		   cb->version, cb->received_version, flags, subtype);
595*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Nonce",
596*a1157835SDaniel Fojt 		    cb->nonce, sizeof(cb->nonce));
597*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EMSK Compound MAC",
598*a1157835SDaniel Fojt 		    cb->emsk_compound_mac, sizeof(cb->emsk_compound_mac));
599*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: MSK Compound MAC",
600*a1157835SDaniel Fojt 		    cb->msk_compound_mac, sizeof(cb->msk_compound_mac));
601*a1157835SDaniel Fojt 
602*a1157835SDaniel Fojt 	if (cb->version != EAP_TEAP_VERSION ||
603*a1157835SDaniel Fojt 	    cb->received_version != data->received_version ||
604*a1157835SDaniel Fojt 	    subtype != TEAP_CRYPTO_BINDING_SUBTYPE_REQUEST ||
605*a1157835SDaniel Fojt 	    flags < 1 || flags > 3) {
606*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
607*a1157835SDaniel Fojt 			   "EAP-TEAP: Invalid Version/Flags/Sub-Type in Crypto-Binding TLV: Version %u Received Version %u Flags %u Sub-Type %u",
608*a1157835SDaniel Fojt 			   cb->version, cb->received_version, flags, subtype);
609*a1157835SDaniel Fojt 		return -1;
610*a1157835SDaniel Fojt 	}
611*a1157835SDaniel Fojt 
612*a1157835SDaniel Fojt 	if (cb->nonce[EAP_TEAP_NONCE_LEN - 1] & 0x01) {
613*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
614*a1157835SDaniel Fojt 			   "EAP-TEAP: Invalid Crypto-Binding TLV Nonce in request");
615*a1157835SDaniel Fojt 		return -1;
616*a1157835SDaniel Fojt 	}
617*a1157835SDaniel Fojt 
618*a1157835SDaniel Fojt 	return 0;
619*a1157835SDaniel Fojt }
620*a1157835SDaniel Fojt 
621*a1157835SDaniel Fojt 
eap_teap_write_crypto_binding(struct eap_teap_data * data,struct teap_tlv_crypto_binding * rbind,const struct teap_tlv_crypto_binding * cb,const u8 * cmk_msk,const u8 * cmk_emsk)622*a1157835SDaniel Fojt static int eap_teap_write_crypto_binding(
623*a1157835SDaniel Fojt 	struct eap_teap_data *data,
624*a1157835SDaniel Fojt 	struct teap_tlv_crypto_binding *rbind,
625*a1157835SDaniel Fojt 	const struct teap_tlv_crypto_binding *cb,
626*a1157835SDaniel Fojt 	const u8 *cmk_msk, const u8 *cmk_emsk)
627*a1157835SDaniel Fojt {
628*a1157835SDaniel Fojt 	u8 subtype, flags;
629*a1157835SDaniel Fojt 
630*a1157835SDaniel Fojt 	rbind->tlv_type = host_to_be16(TEAP_TLV_MANDATORY |
631*a1157835SDaniel Fojt 				       TEAP_TLV_CRYPTO_BINDING);
632*a1157835SDaniel Fojt 	rbind->length = host_to_be16(sizeof(*rbind) -
633*a1157835SDaniel Fojt 				     sizeof(struct teap_tlv_hdr));
634*a1157835SDaniel Fojt 	rbind->version = EAP_TEAP_VERSION;
635*a1157835SDaniel Fojt 	rbind->received_version = data->received_version;
636*a1157835SDaniel Fojt 	/* FIX: RFC 7170 is not clear on which Flags value to use when
637*a1157835SDaniel Fojt 	 * Crypto-Binding TLV is used with Basic-Password-Auth */
638*a1157835SDaniel Fojt 	flags = cmk_emsk ? TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC :
639*a1157835SDaniel Fojt 		TEAP_CRYPTO_BINDING_MSK_CMAC;
640*a1157835SDaniel Fojt 	subtype = TEAP_CRYPTO_BINDING_SUBTYPE_RESPONSE;
641*a1157835SDaniel Fojt 	rbind->subtype = (flags << 4) | subtype;
642*a1157835SDaniel Fojt 	os_memcpy(rbind->nonce, cb->nonce, sizeof(cb->nonce));
643*a1157835SDaniel Fojt 	inc_byte_array(rbind->nonce, sizeof(rbind->nonce));
644*a1157835SDaniel Fojt 	os_memset(rbind->emsk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
645*a1157835SDaniel Fojt 	os_memset(rbind->msk_compound_mac, 0, EAP_TEAP_COMPOUND_MAC_LEN);
646*a1157835SDaniel Fojt 
647*a1157835SDaniel Fojt 	if (eap_teap_compound_mac(data->tls_cs, rbind, data->server_outer_tlvs,
648*a1157835SDaniel Fojt 				  data->peer_outer_tlvs, cmk_msk,
649*a1157835SDaniel Fojt 				  rbind->msk_compound_mac) < 0)
650*a1157835SDaniel Fojt 		return -1;
651*a1157835SDaniel Fojt 	if (cmk_emsk &&
652*a1157835SDaniel Fojt 	    eap_teap_compound_mac(data->tls_cs, rbind, data->server_outer_tlvs,
653*a1157835SDaniel Fojt 				  data->peer_outer_tlvs, cmk_emsk,
654*a1157835SDaniel Fojt 				  rbind->emsk_compound_mac) < 0)
655*a1157835SDaniel Fojt 		return -1;
656*a1157835SDaniel Fojt 
657*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
658*a1157835SDaniel Fojt 		   "EAP-TEAP: Reply Crypto-Binding TLV: Version %u Received Version %u Flags %u SubType %u",
659*a1157835SDaniel Fojt 		   rbind->version, rbind->received_version, flags, subtype);
660*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Nonce",
661*a1157835SDaniel Fojt 		    rbind->nonce, sizeof(rbind->nonce));
662*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: EMSK Compound MAC",
663*a1157835SDaniel Fojt 		    rbind->emsk_compound_mac, sizeof(rbind->emsk_compound_mac));
664*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: MSK Compound MAC",
665*a1157835SDaniel Fojt 		    rbind->msk_compound_mac, sizeof(rbind->msk_compound_mac));
666*a1157835SDaniel Fojt 
667*a1157835SDaniel Fojt 	return 0;
668*a1157835SDaniel Fojt }
669*a1157835SDaniel Fojt 
670*a1157835SDaniel Fojt 
eap_teap_get_cmk(struct eap_sm * sm,struct eap_teap_data * data,u8 * cmk_msk,u8 * cmk_emsk)671*a1157835SDaniel Fojt static int eap_teap_get_cmk(struct eap_sm *sm, struct eap_teap_data *data,
672*a1157835SDaniel Fojt 			    u8 *cmk_msk, u8 *cmk_emsk)
673*a1157835SDaniel Fojt {
674*a1157835SDaniel Fojt 	u8 *msk = NULL, *emsk = NULL;
675*a1157835SDaniel Fojt 	size_t msk_len = 0, emsk_len = 0;
676*a1157835SDaniel Fojt 	int res;
677*a1157835SDaniel Fojt 
678*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
679*a1157835SDaniel Fojt 		   "EAP-TEAP: Determining CMK[%d] for Compound MAC calculation",
680*a1157835SDaniel Fojt 		   data->simck_idx + 1);
681*a1157835SDaniel Fojt 
682*a1157835SDaniel Fojt 	if (!data->phase2_method)
683*a1157835SDaniel Fojt 		return eap_teap_derive_cmk_basic_pw_auth(data->simck_msk,
684*a1157835SDaniel Fojt 							 cmk_msk);
685*a1157835SDaniel Fojt 
686*a1157835SDaniel Fojt 	if (!data->phase2_method || !data->phase2_priv) {
687*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "EAP-TEAP: Phase 2 method not available");
688*a1157835SDaniel Fojt 		return -1;
689*a1157835SDaniel Fojt 	}
690*a1157835SDaniel Fojt 
691*a1157835SDaniel Fojt 	if (data->phase2_method->isKeyAvailable &&
692*a1157835SDaniel Fojt 	    !data->phase2_method->isKeyAvailable(sm, data->phase2_priv)) {
693*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
694*a1157835SDaniel Fojt 			   "EAP-TEAP: Phase 2 key material not available");
695*a1157835SDaniel Fojt 		return -1;
696*a1157835SDaniel Fojt 	}
697*a1157835SDaniel Fojt 
698*a1157835SDaniel Fojt 	if (data->phase2_method->isKeyAvailable &&
699*a1157835SDaniel Fojt 	    data->phase2_method->getKey) {
700*a1157835SDaniel Fojt 		msk = data->phase2_method->getKey(sm, data->phase2_priv,
701*a1157835SDaniel Fojt 						  &msk_len);
702*a1157835SDaniel Fojt 		if (!msk) {
703*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
704*a1157835SDaniel Fojt 				   "EAP-TEAP: Could not fetch Phase 2 MSK");
705*a1157835SDaniel Fojt 			return -1;
706*a1157835SDaniel Fojt 		}
707*a1157835SDaniel Fojt 	}
708*a1157835SDaniel Fojt 
709*a1157835SDaniel Fojt 	if (data->phase2_method->isKeyAvailable &&
710*a1157835SDaniel Fojt 	    data->phase2_method->get_emsk) {
711*a1157835SDaniel Fojt 		emsk = data->phase2_method->get_emsk(sm, data->phase2_priv,
712*a1157835SDaniel Fojt 						     &emsk_len);
713*a1157835SDaniel Fojt 	}
714*a1157835SDaniel Fojt 
715*a1157835SDaniel Fojt 	res = eap_teap_derive_imck(data->simck_msk, data->simck_emsk,
716*a1157835SDaniel Fojt 				   msk, msk_len, emsk, emsk_len,
717*a1157835SDaniel Fojt 				   data->simck_msk, cmk_msk,
718*a1157835SDaniel Fojt 				   data->simck_emsk, cmk_emsk);
719*a1157835SDaniel Fojt 	bin_clear_free(msk, msk_len);
720*a1157835SDaniel Fojt 	bin_clear_free(emsk, emsk_len);
721*a1157835SDaniel Fojt 	if (res == 0) {
722*a1157835SDaniel Fojt 		data->simck_idx++;
723*a1157835SDaniel Fojt 		if (emsk)
724*a1157835SDaniel Fojt 			data->cmk_emsk_available = 1;
725*a1157835SDaniel Fojt 	}
726*a1157835SDaniel Fojt 	return res;
727*a1157835SDaniel Fojt }
728*a1157835SDaniel Fojt 
729*a1157835SDaniel Fojt 
eap_teap_session_id(struct eap_teap_data * data)730*a1157835SDaniel Fojt static int eap_teap_session_id(struct eap_teap_data *data)
731*a1157835SDaniel Fojt {
732*a1157835SDaniel Fojt 	const size_t max_id_len = 100;
733*a1157835SDaniel Fojt 	int res;
734*a1157835SDaniel Fojt 
735*a1157835SDaniel Fojt 	os_free(data->session_id);
736*a1157835SDaniel Fojt 	data->session_id = os_malloc(max_id_len);
737*a1157835SDaniel Fojt 	if (!data->session_id)
738*a1157835SDaniel Fojt 		return -1;
739*a1157835SDaniel Fojt 
740*a1157835SDaniel Fojt 	data->session_id[0] = EAP_TYPE_TEAP;
741*a1157835SDaniel Fojt 	res = tls_get_tls_unique(data->ssl.conn, data->session_id + 1,
742*a1157835SDaniel Fojt 				 max_id_len - 1);
743*a1157835SDaniel Fojt 	if (res < 0) {
744*a1157835SDaniel Fojt 		os_free(data->session_id);
745*a1157835SDaniel Fojt 		data->session_id = NULL;
746*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "EAP-TEAP: Failed to derive Session-Id");
747*a1157835SDaniel Fojt 		return -1;
748*a1157835SDaniel Fojt 	}
749*a1157835SDaniel Fojt 
750*a1157835SDaniel Fojt 	data->id_len = 1 + res;
751*a1157835SDaniel Fojt 	wpa_hexdump(MSG_DEBUG, "EAP-TEAP: Derived Session-Id",
752*a1157835SDaniel Fojt 		    data->session_id, data->id_len);
753*a1157835SDaniel Fojt 	return 0;
754*a1157835SDaniel Fojt }
755*a1157835SDaniel Fojt 
756*a1157835SDaniel Fojt 
eap_teap_process_crypto_binding(struct eap_sm * sm,struct eap_teap_data * data,struct eap_method_ret * ret,const struct teap_tlv_crypto_binding * cb,size_t bind_len)757*a1157835SDaniel Fojt static struct wpabuf * eap_teap_process_crypto_binding(
758*a1157835SDaniel Fojt 	struct eap_sm *sm, struct eap_teap_data *data,
759*a1157835SDaniel Fojt 	struct eap_method_ret *ret,
760*a1157835SDaniel Fojt 	const struct teap_tlv_crypto_binding *cb, size_t bind_len)
761*a1157835SDaniel Fojt {
762*a1157835SDaniel Fojt 	struct wpabuf *resp;
763*a1157835SDaniel Fojt 	u8 *pos;
764*a1157835SDaniel Fojt 	u8 cmk_msk[EAP_TEAP_CMK_LEN];
765*a1157835SDaniel Fojt 	u8 cmk_emsk[EAP_TEAP_CMK_LEN];
766*a1157835SDaniel Fojt 	const u8 *cmk_emsk_ptr = NULL;
767*a1157835SDaniel Fojt 	int res;
768*a1157835SDaniel Fojt 	size_t len;
769*a1157835SDaniel Fojt 	u8 flags;
770*a1157835SDaniel Fojt 
771*a1157835SDaniel Fojt 	if (eap_teap_validate_crypto_binding(data, cb) < 0 ||
772*a1157835SDaniel Fojt 	    eap_teap_get_cmk(sm, data, cmk_msk, cmk_emsk) < 0)
773*a1157835SDaniel Fojt 		return NULL;
774*a1157835SDaniel Fojt 
775*a1157835SDaniel Fojt 	/* Validate received MSK/EMSK Compound MAC */
776*a1157835SDaniel Fojt 	flags = cb->subtype >> 4;
777*a1157835SDaniel Fojt 
778*a1157835SDaniel Fojt 	if (flags == TEAP_CRYPTO_BINDING_MSK_CMAC ||
779*a1157835SDaniel Fojt 	    flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) {
780*a1157835SDaniel Fojt 		u8 msk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
781*a1157835SDaniel Fojt 
782*a1157835SDaniel Fojt 		if (eap_teap_compound_mac(data->tls_cs, cb,
783*a1157835SDaniel Fojt 					  data->server_outer_tlvs,
784*a1157835SDaniel Fojt 					  data->peer_outer_tlvs, cmk_msk,
785*a1157835SDaniel Fojt 					  msk_compound_mac) < 0)
786*a1157835SDaniel Fojt 			return NULL;
787*a1157835SDaniel Fojt 		res = os_memcmp_const(msk_compound_mac, cb->msk_compound_mac,
788*a1157835SDaniel Fojt 				      EAP_TEAP_COMPOUND_MAC_LEN);
789*a1157835SDaniel Fojt 		wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Received MSK Compound MAC",
790*a1157835SDaniel Fojt 			    cb->msk_compound_mac, EAP_TEAP_COMPOUND_MAC_LEN);
791*a1157835SDaniel Fojt 		wpa_hexdump(MSG_MSGDUMP,
792*a1157835SDaniel Fojt 			    "EAP-TEAP: Calculated MSK Compound MAC",
793*a1157835SDaniel Fojt 			    msk_compound_mac, EAP_TEAP_COMPOUND_MAC_LEN);
794*a1157835SDaniel Fojt 		if (res != 0) {
795*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
796*a1157835SDaniel Fojt 				   "EAP-TEAP: MSK Compound MAC did not match");
797*a1157835SDaniel Fojt 			return NULL;
798*a1157835SDaniel Fojt 		}
799*a1157835SDaniel Fojt 	}
800*a1157835SDaniel Fojt 
801*a1157835SDaniel Fojt 	if ((flags == TEAP_CRYPTO_BINDING_EMSK_CMAC ||
802*a1157835SDaniel Fojt 	     flags == TEAP_CRYPTO_BINDING_EMSK_AND_MSK_CMAC) &&
803*a1157835SDaniel Fojt 	    data->cmk_emsk_available) {
804*a1157835SDaniel Fojt 		u8 emsk_compound_mac[EAP_TEAP_COMPOUND_MAC_LEN];
805*a1157835SDaniel Fojt 
806*a1157835SDaniel Fojt 		if (eap_teap_compound_mac(data->tls_cs, cb,
807*a1157835SDaniel Fojt 					  data->server_outer_tlvs,
808*a1157835SDaniel Fojt 					  data->peer_outer_tlvs, cmk_emsk,
809*a1157835SDaniel Fojt 					  emsk_compound_mac) < 0)
810*a1157835SDaniel Fojt 			return NULL;
811*a1157835SDaniel Fojt 		res = os_memcmp_const(emsk_compound_mac, cb->emsk_compound_mac,
812*a1157835SDaniel Fojt 				      EAP_TEAP_COMPOUND_MAC_LEN);
813*a1157835SDaniel Fojt 		wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Received EMSK Compound MAC",
814*a1157835SDaniel Fojt 			    cb->emsk_compound_mac, EAP_TEAP_COMPOUND_MAC_LEN);
815*a1157835SDaniel Fojt 		wpa_hexdump(MSG_MSGDUMP,
816*a1157835SDaniel Fojt 			    "EAP-TEAP: Calculated EMSK Compound MAC",
817*a1157835SDaniel Fojt 			    emsk_compound_mac, EAP_TEAP_COMPOUND_MAC_LEN);
818*a1157835SDaniel Fojt 		if (res != 0) {
819*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
820*a1157835SDaniel Fojt 				   "EAP-TEAP: EMSK Compound MAC did not match");
821*a1157835SDaniel Fojt 			return NULL;
822*a1157835SDaniel Fojt 		}
823*a1157835SDaniel Fojt 
824*a1157835SDaniel Fojt 		cmk_emsk_ptr = cmk_emsk;
825*a1157835SDaniel Fojt 	}
826*a1157835SDaniel Fojt 
827*a1157835SDaniel Fojt 	if (flags == TEAP_CRYPTO_BINDING_EMSK_CMAC &&
828*a1157835SDaniel Fojt 	    !data->cmk_emsk_available) {
829*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
830*a1157835SDaniel Fojt 			   "EAP-TEAP: Server included only EMSK Compound MAC, but no locally generated inner EAP EMSK to validate this");
831*a1157835SDaniel Fojt 		return NULL;
832*a1157835SDaniel Fojt 	}
833*a1157835SDaniel Fojt 
834*a1157835SDaniel Fojt 	/*
835*a1157835SDaniel Fojt 	 * Compound MAC was valid, so authentication succeeded. Reply with
836*a1157835SDaniel Fojt 	 * crypto binding to allow server to complete authentication.
837*a1157835SDaniel Fojt 	 */
838*a1157835SDaniel Fojt 
839*a1157835SDaniel Fojt 	len = sizeof(struct teap_tlv_crypto_binding);
840*a1157835SDaniel Fojt 	resp = wpabuf_alloc(len);
841*a1157835SDaniel Fojt 	if (!resp)
842*a1157835SDaniel Fojt 		return NULL;
843*a1157835SDaniel Fojt 
844*a1157835SDaniel Fojt 	if (data->phase2_success && eap_teap_derive_msk(data) < 0) {
845*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "EAP-TEAP: Failed to generate MSK");
846*a1157835SDaniel Fojt 		ret->methodState = METHOD_DONE;
847*a1157835SDaniel Fojt 		ret->decision = DECISION_FAIL;
848*a1157835SDaniel Fojt 		data->phase2_success = 0;
849*a1157835SDaniel Fojt 		wpabuf_free(resp);
850*a1157835SDaniel Fojt 		return NULL;
851*a1157835SDaniel Fojt 	}
852*a1157835SDaniel Fojt 
853*a1157835SDaniel Fojt 	if (data->phase2_success && eap_teap_session_id(data) < 0) {
854*a1157835SDaniel Fojt 		wpabuf_free(resp);
855*a1157835SDaniel Fojt 		return NULL;
856*a1157835SDaniel Fojt 	}
857*a1157835SDaniel Fojt 
858*a1157835SDaniel Fojt 	pos = wpabuf_put(resp, sizeof(struct teap_tlv_crypto_binding));
859*a1157835SDaniel Fojt 	if (eap_teap_write_crypto_binding(
860*a1157835SDaniel Fojt 		    data, (struct teap_tlv_crypto_binding *) pos,
861*a1157835SDaniel Fojt 		    cb, cmk_msk, cmk_emsk_ptr) < 0) {
862*a1157835SDaniel Fojt 		wpabuf_free(resp);
863*a1157835SDaniel Fojt 		return NULL;
864*a1157835SDaniel Fojt 	}
865*a1157835SDaniel Fojt 
866*a1157835SDaniel Fojt 	return resp;
867*a1157835SDaniel Fojt }
868*a1157835SDaniel Fojt 
869*a1157835SDaniel Fojt 
eap_teap_parse_pac_tlv(struct eap_teap_pac * entry,int type,u8 * pos,size_t len,int * pac_key_found)870*a1157835SDaniel Fojt static void eap_teap_parse_pac_tlv(struct eap_teap_pac *entry, int type,
871*a1157835SDaniel Fojt 				   u8 *pos, size_t len, int *pac_key_found)
872*a1157835SDaniel Fojt {
873*a1157835SDaniel Fojt 	switch (type & 0x7fff) {
874*a1157835SDaniel Fojt 	case PAC_TYPE_PAC_KEY:
875*a1157835SDaniel Fojt 		wpa_hexdump_key(MSG_DEBUG, "EAP-TEAP: PAC-Key", pos, len);
876*a1157835SDaniel Fojt 		if (len != EAP_TEAP_PAC_KEY_LEN) {
877*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
878*a1157835SDaniel Fojt 				   "EAP-TEAP: Invalid PAC-Key length %lu",
879*a1157835SDaniel Fojt 				   (unsigned long) len);
880*a1157835SDaniel Fojt 			break;
881*a1157835SDaniel Fojt 		}
882*a1157835SDaniel Fojt 		*pac_key_found = 1;
883*a1157835SDaniel Fojt 		os_memcpy(entry->pac_key, pos, len);
884*a1157835SDaniel Fojt 		break;
885*a1157835SDaniel Fojt 	case PAC_TYPE_PAC_OPAQUE:
886*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "EAP-TEAP: PAC-Opaque", pos, len);
887*a1157835SDaniel Fojt 		entry->pac_opaque = pos;
888*a1157835SDaniel Fojt 		entry->pac_opaque_len = len;
889*a1157835SDaniel Fojt 		break;
890*a1157835SDaniel Fojt 	case PAC_TYPE_PAC_INFO:
891*a1157835SDaniel Fojt 		wpa_hexdump(MSG_DEBUG, "EAP-TEAP: PAC-Info", pos, len);
892*a1157835SDaniel Fojt 		entry->pac_info = pos;
893*a1157835SDaniel Fojt 		entry->pac_info_len = len;
894*a1157835SDaniel Fojt 		break;
895*a1157835SDaniel Fojt 	default:
896*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "EAP-TEAP: Ignored unknown PAC type %d",
897*a1157835SDaniel Fojt 			   type);
898*a1157835SDaniel Fojt 		break;
899*a1157835SDaniel Fojt 	}
900*a1157835SDaniel Fojt }
901*a1157835SDaniel Fojt 
902*a1157835SDaniel Fojt 
eap_teap_process_pac_tlv(struct eap_teap_pac * entry,u8 * pac,size_t pac_len)903*a1157835SDaniel Fojt static int eap_teap_process_pac_tlv(struct eap_teap_pac *entry,
904*a1157835SDaniel Fojt 				    u8 *pac, size_t pac_len)
905*a1157835SDaniel Fojt {
906*a1157835SDaniel Fojt 	struct pac_attr_hdr *hdr;
907*a1157835SDaniel Fojt 	u8 *pos;
908*a1157835SDaniel Fojt 	size_t left, len;
909*a1157835SDaniel Fojt 	int type, pac_key_found = 0;
910*a1157835SDaniel Fojt 
911*a1157835SDaniel Fojt 	pos = pac;
912*a1157835SDaniel Fojt 	left = pac_len;
913*a1157835SDaniel Fojt 
914*a1157835SDaniel Fojt 	while (left > sizeof(*hdr)) {
915*a1157835SDaniel Fojt 		hdr = (struct pac_attr_hdr *) pos;
916*a1157835SDaniel Fojt 		type = be_to_host16(hdr->type);
917*a1157835SDaniel Fojt 		len = be_to_host16(hdr->len);
918*a1157835SDaniel Fojt 		pos += sizeof(*hdr);
919*a1157835SDaniel Fojt 		left -= sizeof(*hdr);
920*a1157835SDaniel Fojt 		if (len > left) {
921*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
922*a1157835SDaniel Fojt 				   "EAP-TEAP: PAC TLV overrun (type=%d len=%lu left=%lu)",
923*a1157835SDaniel Fojt 				   type, (unsigned long) len,
924*a1157835SDaniel Fojt 				   (unsigned long) left);
925*a1157835SDaniel Fojt 			return -1;
926*a1157835SDaniel Fojt 		}
927*a1157835SDaniel Fojt 
928*a1157835SDaniel Fojt 		eap_teap_parse_pac_tlv(entry, type, pos, len, &pac_key_found);
929*a1157835SDaniel Fojt 
930*a1157835SDaniel Fojt 		pos += len;
931*a1157835SDaniel Fojt 		left -= len;
932*a1157835SDaniel Fojt 	}
933*a1157835SDaniel Fojt 
934*a1157835SDaniel Fojt 	if (!pac_key_found || !entry->pac_opaque || !entry->pac_info) {
935*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
936*a1157835SDaniel Fojt 			   "EAP-TEAP: PAC TLV does not include all the required fields");
937*a1157835SDaniel Fojt 		return -1;
938*a1157835SDaniel Fojt 	}
939*a1157835SDaniel Fojt 
940*a1157835SDaniel Fojt 	return 0;
941*a1157835SDaniel Fojt }
942*a1157835SDaniel Fojt 
943*a1157835SDaniel Fojt 
eap_teap_parse_pac_info(struct eap_teap_pac * entry,int type,u8 * pos,size_t len)944*a1157835SDaniel Fojt static int eap_teap_parse_pac_info(struct eap_teap_pac *entry, int type,
945*a1157835SDaniel Fojt 				   u8 *pos, size_t len)
946*a1157835SDaniel Fojt {
947*a1157835SDaniel Fojt 	u16 pac_type;
948*a1157835SDaniel Fojt 	u32 lifetime;
949*a1157835SDaniel Fojt 	struct os_time now;
950*a1157835SDaniel Fojt 
951*a1157835SDaniel Fojt 	switch (type & 0x7fff) {
952*a1157835SDaniel Fojt 	case PAC_TYPE_CRED_LIFETIME:
953*a1157835SDaniel Fojt 		if (len != 4) {
954*a1157835SDaniel Fojt 			wpa_hexdump(MSG_DEBUG,
955*a1157835SDaniel Fojt 				    "EAP-TEAP: PAC-Info - Invalid CRED_LIFETIME length - ignored",
956*a1157835SDaniel Fojt 				    pos, len);
957*a1157835SDaniel Fojt 			return 0;
958*a1157835SDaniel Fojt 		}
959*a1157835SDaniel Fojt 
960*a1157835SDaniel Fojt 		/*
961*a1157835SDaniel Fojt 		 * This is not currently saved separately in PAC files since
962*a1157835SDaniel Fojt 		 * the server can automatically initiate PAC update when
963*a1157835SDaniel Fojt 		 * needed. Anyway, the information is available from PAC-Info
964*a1157835SDaniel Fojt 		 * dump if it is needed for something in the future.
965*a1157835SDaniel Fojt 		 */
966*a1157835SDaniel Fojt 		lifetime = WPA_GET_BE32(pos);
967*a1157835SDaniel Fojt 		os_get_time(&now);
968*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
969*a1157835SDaniel Fojt 			   "EAP-TEAP: PAC-Info - CRED_LIFETIME %d (%d days)",
970*a1157835SDaniel Fojt 			   lifetime, (lifetime - (u32) now.sec) / 86400);
971*a1157835SDaniel Fojt 		break;
972*a1157835SDaniel Fojt 	case PAC_TYPE_A_ID:
973*a1157835SDaniel Fojt 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Info - A-ID",
974*a1157835SDaniel Fojt 				  pos, len);
975*a1157835SDaniel Fojt 		entry->a_id = pos;
976*a1157835SDaniel Fojt 		entry->a_id_len = len;
977*a1157835SDaniel Fojt 		break;
978*a1157835SDaniel Fojt 	case PAC_TYPE_I_ID:
979*a1157835SDaniel Fojt 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Info - I-ID",
980*a1157835SDaniel Fojt 				  pos, len);
981*a1157835SDaniel Fojt 		entry->i_id = pos;
982*a1157835SDaniel Fojt 		entry->i_id_len = len;
983*a1157835SDaniel Fojt 		break;
984*a1157835SDaniel Fojt 	case PAC_TYPE_A_ID_INFO:
985*a1157835SDaniel Fojt 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-TEAP: PAC-Info - A-ID-Info",
986*a1157835SDaniel Fojt 				  pos, len);
987*a1157835SDaniel Fojt 		entry->a_id_info = pos;
988*a1157835SDaniel Fojt 		entry->a_id_info_len = len;
989*a1157835SDaniel Fojt 		break;
990*a1157835SDaniel Fojt 	case PAC_TYPE_PAC_TYPE:
991*a1157835SDaniel Fojt 		/* RFC 7170, Section 4.2.12.6 - PAC-Type TLV */
992*a1157835SDaniel Fojt 		if (len != 2) {
993*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
994*a1157835SDaniel Fojt 				   "EAP-TEAP: Invalid PAC-Type length %lu (expected 2)",
995*a1157835SDaniel Fojt 				   (unsigned long) len);
996*a1157835SDaniel Fojt 			wpa_hexdump_ascii(MSG_DEBUG,
997*a1157835SDaniel Fojt 					  "EAP-TEAP: PAC-Info - PAC-Type",
998*a1157835SDaniel Fojt 					  pos, len);
999*a1157835SDaniel Fojt 			return -1;
1000*a1157835SDaniel Fojt 		}
1001*a1157835SDaniel Fojt 		pac_type = WPA_GET_BE16(pos);
1002*a1157835SDaniel Fojt 		if (pac_type != PAC_TYPE_TUNNEL_PAC) {
1003*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
1004*a1157835SDaniel Fojt 				   "EAP-TEAP: Unsupported PAC Type %d",
1005*a1157835SDaniel Fojt 				   pac_type);
1006*a1157835SDaniel Fojt 			return -1;
1007*a1157835SDaniel Fojt 		}
1008*a1157835SDaniel Fojt 
1009*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "EAP-TEAP: PAC-Info - PAC-Type %d",
1010*a1157835SDaniel Fojt 			   pac_type);
1011*a1157835SDaniel Fojt 		entry->pac_type = pac_type;
1012*a1157835SDaniel Fojt 		break;
1013*a1157835SDaniel Fojt 	default:
1014*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1015*a1157835SDaniel Fojt 			   "EAP-TEAP: Ignored unknown PAC-Info type %d", type);
1016*a1157835SDaniel Fojt 		break;
1017*a1157835SDaniel Fojt 	}
1018*a1157835SDaniel Fojt 
1019*a1157835SDaniel Fojt 	return 0;
1020*a1157835SDaniel Fojt }
1021*a1157835SDaniel Fojt 
1022*a1157835SDaniel Fojt 
eap_teap_process_pac_info(struct eap_teap_pac * entry)1023*a1157835SDaniel Fojt static int eap_teap_process_pac_info(struct eap_teap_pac *entry)
1024*a1157835SDaniel Fojt {
1025*a1157835SDaniel Fojt 	struct pac_attr_hdr *hdr;
1026*a1157835SDaniel Fojt 	u8 *pos;
1027*a1157835SDaniel Fojt 	size_t left, len;
1028*a1157835SDaniel Fojt 	int type;
1029*a1157835SDaniel Fojt 
1030*a1157835SDaniel Fojt 	/* RFC 7170, Section 4.2.12.4 */
1031*a1157835SDaniel Fojt 
1032*a1157835SDaniel Fojt 	/* PAC-Type defaults to Tunnel PAC (Type 1) */
1033*a1157835SDaniel Fojt 	entry->pac_type = PAC_TYPE_TUNNEL_PAC;
1034*a1157835SDaniel Fojt 
1035*a1157835SDaniel Fojt 	pos = entry->pac_info;
1036*a1157835SDaniel Fojt 	left = entry->pac_info_len;
1037*a1157835SDaniel Fojt 	while (left > sizeof(*hdr)) {
1038*a1157835SDaniel Fojt 		hdr = (struct pac_attr_hdr *) pos;
1039*a1157835SDaniel Fojt 		type = be_to_host16(hdr->type);
1040*a1157835SDaniel Fojt 		len = be_to_host16(hdr->len);
1041*a1157835SDaniel Fojt 		pos += sizeof(*hdr);
1042*a1157835SDaniel Fojt 		left -= sizeof(*hdr);
1043*a1157835SDaniel Fojt 		if (len > left) {
1044*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1045*a1157835SDaniel Fojt 				   "EAP-TEAP: PAC-Info overrun (type=%d len=%lu left=%lu)",
1046*a1157835SDaniel Fojt 				   type, (unsigned long) len,
1047*a1157835SDaniel Fojt 				   (unsigned long) left);
1048*a1157835SDaniel Fojt 			return -1;
1049*a1157835SDaniel Fojt 		}
1050*a1157835SDaniel Fojt 
1051*a1157835SDaniel Fojt 		if (eap_teap_parse_pac_info(entry, type, pos, len) < 0)
1052*a1157835SDaniel Fojt 			return -1;
1053*a1157835SDaniel Fojt 
1054*a1157835SDaniel Fojt 		pos += len;
1055*a1157835SDaniel Fojt 		left -= len;
1056*a1157835SDaniel Fojt 	}
1057*a1157835SDaniel Fojt 
1058*a1157835SDaniel Fojt 	if (!entry->a_id || !entry->a_id_info) {
1059*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1060*a1157835SDaniel Fojt 			   "EAP-TEAP: PAC-Info does not include all the required fields");
1061*a1157835SDaniel Fojt 		return -1;
1062*a1157835SDaniel Fojt 	}
1063*a1157835SDaniel Fojt 
1064*a1157835SDaniel Fojt 	return 0;
1065*a1157835SDaniel Fojt }
1066*a1157835SDaniel Fojt 
1067*a1157835SDaniel Fojt 
eap_teap_process_pac(struct eap_sm * sm,struct eap_teap_data * data,struct eap_method_ret * ret,u8 * pac,size_t pac_len)1068*a1157835SDaniel Fojt static struct wpabuf * eap_teap_process_pac(struct eap_sm *sm,
1069*a1157835SDaniel Fojt 					    struct eap_teap_data *data,
1070*a1157835SDaniel Fojt 					    struct eap_method_ret *ret,
1071*a1157835SDaniel Fojt 					    u8 *pac, size_t pac_len)
1072*a1157835SDaniel Fojt {
1073*a1157835SDaniel Fojt 	struct eap_peer_config *config = eap_get_config(sm);
1074*a1157835SDaniel Fojt 	struct eap_teap_pac entry;
1075*a1157835SDaniel Fojt 
1076*a1157835SDaniel Fojt 	os_memset(&entry, 0, sizeof(entry));
1077*a1157835SDaniel Fojt 	if (eap_teap_process_pac_tlv(&entry, pac, pac_len) ||
1078*a1157835SDaniel Fojt 	    eap_teap_process_pac_info(&entry))
1079*a1157835SDaniel Fojt 		return NULL;
1080*a1157835SDaniel Fojt 
1081*a1157835SDaniel Fojt 	eap_teap_add_pac(&data->pac, &data->current_pac, &entry);
1082*a1157835SDaniel Fojt 	eap_teap_pac_list_truncate(data->pac, data->max_pac_list_len);
1083*a1157835SDaniel Fojt 	if (data->use_pac_binary_format)
1084*a1157835SDaniel Fojt 		eap_teap_save_pac_bin(sm, data->pac, config->pac_file);
1085*a1157835SDaniel Fojt 	else
1086*a1157835SDaniel Fojt 		eap_teap_save_pac(sm, data->pac, config->pac_file);
1087*a1157835SDaniel Fojt 
1088*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
1089*a1157835SDaniel Fojt 		   "EAP-TEAP: Send PAC-Acknowledgement - %s initiated provisioning completed successfully",
1090*a1157835SDaniel Fojt 		   data->provisioning ? "peer" : "server");
1091*a1157835SDaniel Fojt 	return eap_teap_tlv_pac_ack();
1092*a1157835SDaniel Fojt }
1093*a1157835SDaniel Fojt 
1094*a1157835SDaniel Fojt 
eap_teap_parse_decrypted(struct wpabuf * decrypted,struct eap_teap_tlv_parse * tlv,struct wpabuf ** resp)1095*a1157835SDaniel Fojt static int eap_teap_parse_decrypted(struct wpabuf *decrypted,
1096*a1157835SDaniel Fojt 				    struct eap_teap_tlv_parse *tlv,
1097*a1157835SDaniel Fojt 				    struct wpabuf **resp)
1098*a1157835SDaniel Fojt {
1099*a1157835SDaniel Fojt 	u16 tlv_type;
1100*a1157835SDaniel Fojt 	int mandatory, res;
1101*a1157835SDaniel Fojt 	size_t len;
1102*a1157835SDaniel Fojt 	u8 *pos, *end;
1103*a1157835SDaniel Fojt 
1104*a1157835SDaniel Fojt 	os_memset(tlv, 0, sizeof(*tlv));
1105*a1157835SDaniel Fojt 
1106*a1157835SDaniel Fojt 	/* Parse TLVs from the decrypted Phase 2 data */
1107*a1157835SDaniel Fojt 	pos = wpabuf_mhead(decrypted);
1108*a1157835SDaniel Fojt 	end = pos + wpabuf_len(decrypted);
1109*a1157835SDaniel Fojt 	while (end - pos >= 4) {
1110*a1157835SDaniel Fojt 		mandatory = pos[0] & 0x80;
1111*a1157835SDaniel Fojt 		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
1112*a1157835SDaniel Fojt 		pos += 2;
1113*a1157835SDaniel Fojt 		len = WPA_GET_BE16(pos);
1114*a1157835SDaniel Fojt 		pos += 2;
1115*a1157835SDaniel Fojt 		if (len > (size_t) (end - pos)) {
1116*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO, "EAP-TEAP: TLV overflow");
1117*a1157835SDaniel Fojt 			return -1;
1118*a1157835SDaniel Fojt 		}
1119*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1120*a1157835SDaniel Fojt 			   "EAP-TEAP: Received Phase 2: TLV type %u (%s) length %u%s",
1121*a1157835SDaniel Fojt 			   tlv_type, eap_teap_tlv_type_str(tlv_type),
1122*a1157835SDaniel Fojt 			   (unsigned int) len,
1123*a1157835SDaniel Fojt 			   mandatory ? " (mandatory)" : "");
1124*a1157835SDaniel Fojt 
1125*a1157835SDaniel Fojt 		res = eap_teap_parse_tlv(tlv, tlv_type, pos, len);
1126*a1157835SDaniel Fojt 		if (res == -2)
1127*a1157835SDaniel Fojt 			break;
1128*a1157835SDaniel Fojt 		if (res < 0) {
1129*a1157835SDaniel Fojt 			if (mandatory) {
1130*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
1131*a1157835SDaniel Fojt 					   "EAP-TEAP: NAK unknown mandatory TLV type %u",
1132*a1157835SDaniel Fojt 					   tlv_type);
1133*a1157835SDaniel Fojt 				*resp = eap_teap_tlv_nak(0, tlv_type);
1134*a1157835SDaniel Fojt 				break;
1135*a1157835SDaniel Fojt 			}
1136*a1157835SDaniel Fojt 
1137*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1138*a1157835SDaniel Fojt 				   "EAP-TEAP: Ignore unknown optional TLV type %u",
1139*a1157835SDaniel Fojt 				   tlv_type);
1140*a1157835SDaniel Fojt 		}
1141*a1157835SDaniel Fojt 
1142*a1157835SDaniel Fojt 		pos += len;
1143*a1157835SDaniel Fojt 	}
1144*a1157835SDaniel Fojt 
1145*a1157835SDaniel Fojt 	return 0;
1146*a1157835SDaniel Fojt }
1147*a1157835SDaniel Fojt 
1148*a1157835SDaniel Fojt 
eap_teap_pac_request(void)1149*a1157835SDaniel Fojt static struct wpabuf * eap_teap_pac_request(void)
1150*a1157835SDaniel Fojt {
1151*a1157835SDaniel Fojt 	struct wpabuf *req;
1152*a1157835SDaniel Fojt 	struct teap_tlv_request_action *act;
1153*a1157835SDaniel Fojt 	struct teap_tlv_hdr *pac;
1154*a1157835SDaniel Fojt 	struct teap_attr_pac_type *type;
1155*a1157835SDaniel Fojt 
1156*a1157835SDaniel Fojt 	req = wpabuf_alloc(sizeof(*act) + sizeof(*pac) + sizeof(*type));
1157*a1157835SDaniel Fojt 	if (!req)
1158*a1157835SDaniel Fojt 		return NULL;
1159*a1157835SDaniel Fojt 
1160*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "EAP-TEAP: Add Request Action TLV (Process TLV)");
1161*a1157835SDaniel Fojt 	act = wpabuf_put(req, sizeof(*act));
1162*a1157835SDaniel Fojt 	act->tlv_type = host_to_be16(TEAP_TLV_REQUEST_ACTION);
1163*a1157835SDaniel Fojt 	act->length = host_to_be16(2);
1164*a1157835SDaniel Fojt 	act->status = TEAP_STATUS_SUCCESS;
1165*a1157835SDaniel Fojt 	act->action = TEAP_REQUEST_ACTION_PROCESS_TLV;
1166*a1157835SDaniel Fojt 
1167*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC TLV (PAC-Type = Tunnel)");
1168*a1157835SDaniel Fojt 	pac = wpabuf_put(req, sizeof(*pac));
1169*a1157835SDaniel Fojt 	pac->tlv_type = host_to_be16(TEAP_TLV_PAC);
1170*a1157835SDaniel Fojt 	pac->length = host_to_be16(sizeof(*type));
1171*a1157835SDaniel Fojt 
1172*a1157835SDaniel Fojt 	type = wpabuf_put(req, sizeof(*type));
1173*a1157835SDaniel Fojt 	type->type = host_to_be16(PAC_TYPE_PAC_TYPE);
1174*a1157835SDaniel Fojt 	type->length = host_to_be16(2);
1175*a1157835SDaniel Fojt 	type->pac_type = host_to_be16(PAC_TYPE_TUNNEL_PAC);
1176*a1157835SDaniel Fojt 
1177*a1157835SDaniel Fojt 	return req;
1178*a1157835SDaniel Fojt }
1179*a1157835SDaniel Fojt 
1180*a1157835SDaniel Fojt 
eap_teap_process_decrypted(struct eap_sm * sm,struct eap_teap_data * data,struct eap_method_ret * ret,u8 identifier,struct wpabuf * decrypted,struct wpabuf ** out_data)1181*a1157835SDaniel Fojt static int eap_teap_process_decrypted(struct eap_sm *sm,
1182*a1157835SDaniel Fojt 				      struct eap_teap_data *data,
1183*a1157835SDaniel Fojt 				      struct eap_method_ret *ret,
1184*a1157835SDaniel Fojt 				      u8 identifier,
1185*a1157835SDaniel Fojt 				      struct wpabuf *decrypted,
1186*a1157835SDaniel Fojt 				      struct wpabuf **out_data)
1187*a1157835SDaniel Fojt {
1188*a1157835SDaniel Fojt 	struct wpabuf *resp = NULL, *tmp;
1189*a1157835SDaniel Fojt 	struct eap_teap_tlv_parse tlv;
1190*a1157835SDaniel Fojt 	int failed = 0;
1191*a1157835SDaniel Fojt 	enum teap_error_codes error = 0;
1192*a1157835SDaniel Fojt 
1193*a1157835SDaniel Fojt 	if (eap_teap_parse_decrypted(decrypted, &tlv, &resp) < 0) {
1194*a1157835SDaniel Fojt 		/* Parsing failed - no response available */
1195*a1157835SDaniel Fojt 		return 0;
1196*a1157835SDaniel Fojt 	}
1197*a1157835SDaniel Fojt 
1198*a1157835SDaniel Fojt 	if (resp) {
1199*a1157835SDaniel Fojt 		/* Parsing rejected the message - send out an error response */
1200*a1157835SDaniel Fojt 		goto send_resp;
1201*a1157835SDaniel Fojt 	}
1202*a1157835SDaniel Fojt 
1203*a1157835SDaniel Fojt 	if (tlv.result == TEAP_STATUS_FAILURE) {
1204*a1157835SDaniel Fojt 		/* Server indicated failure - respond similarly per
1205*a1157835SDaniel Fojt 		 * RFC 7170, 3.6.3. This authentication exchange cannot succeed
1206*a1157835SDaniel Fojt 		 * and will be terminated with a cleartext EAP Failure. */
1207*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1208*a1157835SDaniel Fojt 			   "EAP-TEAP: Server rejected authentication");
1209*a1157835SDaniel Fojt 		resp = eap_teap_tlv_result(TEAP_STATUS_FAILURE, 0);
1210*a1157835SDaniel Fojt 		ret->methodState = METHOD_DONE;
1211*a1157835SDaniel Fojt 		ret->decision = DECISION_FAIL;
1212*a1157835SDaniel Fojt 		goto send_resp;
1213*a1157835SDaniel Fojt 	}
1214*a1157835SDaniel Fojt 
1215*a1157835SDaniel Fojt 	if ((tlv.iresult == TEAP_STATUS_SUCCESS ||
1216*a1157835SDaniel Fojt 	     (!data->result_success_done &&
1217*a1157835SDaniel Fojt 	      tlv.result == TEAP_STATUS_SUCCESS)) &&
1218*a1157835SDaniel Fojt 	    !tlv.crypto_binding) {
1219*a1157835SDaniel Fojt 		/* Result TLV or Intermediate-Result TLV indicating success,
1220*a1157835SDaniel Fojt 		 * but no Crypto-Binding TLV */
1221*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1222*a1157835SDaniel Fojt 			   "EAP-TEAP: Result TLV or Intermediate-Result TLV indicating success, but no Crypto-Binding TLV");
1223*a1157835SDaniel Fojt 		failed = 1;
1224*a1157835SDaniel Fojt 		error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR;
1225*a1157835SDaniel Fojt 		goto done;
1226*a1157835SDaniel Fojt 	}
1227*a1157835SDaniel Fojt 
1228*a1157835SDaniel Fojt 	if (tlv.iresult != TEAP_STATUS_SUCCESS &&
1229*a1157835SDaniel Fojt 	    tlv.iresult != TEAP_STATUS_FAILURE &&
1230*a1157835SDaniel Fojt 	    data->inner_method_done) {
1231*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1232*a1157835SDaniel Fojt 			   "EAP-TEAP: Inner EAP method exchange completed, but no Intermediate-Result TLV included");
1233*a1157835SDaniel Fojt 		failed = 1;
1234*a1157835SDaniel Fojt 		error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR;
1235*a1157835SDaniel Fojt 		goto done;
1236*a1157835SDaniel Fojt 	}
1237*a1157835SDaniel Fojt 
1238*a1157835SDaniel Fojt 	if (tlv.basic_auth_req) {
1239*a1157835SDaniel Fojt 		tmp = eap_teap_process_basic_auth_req(sm, data,
1240*a1157835SDaniel Fojt 						      tlv.basic_auth_req,
1241*a1157835SDaniel Fojt 						      tlv.basic_auth_req_len);
1242*a1157835SDaniel Fojt 		if (!tmp)
1243*a1157835SDaniel Fojt 			failed = 1;
1244*a1157835SDaniel Fojt 		resp = wpabuf_concat(resp, tmp);
1245*a1157835SDaniel Fojt 	} else if (tlv.eap_payload_tlv) {
1246*a1157835SDaniel Fojt 		tmp = eap_teap_process_eap_payload_tlv(sm, data, ret,
1247*a1157835SDaniel Fojt 						       tlv.eap_payload_tlv,
1248*a1157835SDaniel Fojt 						       tlv.eap_payload_tlv_len);
1249*a1157835SDaniel Fojt 		if (!tmp)
1250*a1157835SDaniel Fojt 			failed = 1;
1251*a1157835SDaniel Fojt 		resp = wpabuf_concat(resp, tmp);
1252*a1157835SDaniel Fojt 
1253*a1157835SDaniel Fojt 		if (tlv.iresult == TEAP_STATUS_SUCCESS ||
1254*a1157835SDaniel Fojt 		    tlv.iresult == TEAP_STATUS_FAILURE) {
1255*a1157835SDaniel Fojt 			tmp = eap_teap_tlv_result(failed ?
1256*a1157835SDaniel Fojt 						  TEAP_STATUS_FAILURE :
1257*a1157835SDaniel Fojt 						  TEAP_STATUS_SUCCESS, 1);
1258*a1157835SDaniel Fojt 			resp = wpabuf_concat(resp, tmp);
1259*a1157835SDaniel Fojt 			if (tlv.iresult == TEAP_STATUS_FAILURE)
1260*a1157835SDaniel Fojt 				failed = 1;
1261*a1157835SDaniel Fojt 		}
1262*a1157835SDaniel Fojt 	}
1263*a1157835SDaniel Fojt 
1264*a1157835SDaniel Fojt 	if (tlv.crypto_binding) {
1265*a1157835SDaniel Fojt 		if (tlv.iresult != TEAP_STATUS_SUCCESS &&
1266*a1157835SDaniel Fojt 		    tlv.result != TEAP_STATUS_SUCCESS) {
1267*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1268*a1157835SDaniel Fojt 				   "EAP-TEAP: Unexpected Crypto-Binding TLV without Result TLV or Intermediate-Result TLV indicating success");
1269*a1157835SDaniel Fojt 			failed = 1;
1270*a1157835SDaniel Fojt 			error = TEAP_ERROR_UNEXPECTED_TLVS_EXCHANGED;
1271*a1157835SDaniel Fojt 			goto done;
1272*a1157835SDaniel Fojt 		}
1273*a1157835SDaniel Fojt 
1274*a1157835SDaniel Fojt 		tmp = eap_teap_process_crypto_binding(sm, data, ret,
1275*a1157835SDaniel Fojt 						      tlv.crypto_binding,
1276*a1157835SDaniel Fojt 						      tlv.crypto_binding_len);
1277*a1157835SDaniel Fojt 		if (!tmp) {
1278*a1157835SDaniel Fojt 			failed = 1;
1279*a1157835SDaniel Fojt 			error = TEAP_ERROR_TUNNEL_COMPROMISE_ERROR;
1280*a1157835SDaniel Fojt 		} else {
1281*a1157835SDaniel Fojt 			resp = wpabuf_concat(resp, tmp);
1282*a1157835SDaniel Fojt 			if (tlv.result == TEAP_STATUS_SUCCESS && !failed)
1283*a1157835SDaniel Fojt 				data->result_success_done = 1;
1284*a1157835SDaniel Fojt 			if (tlv.iresult == TEAP_STATUS_SUCCESS && !failed)
1285*a1157835SDaniel Fojt 				data->inner_method_done = 0;
1286*a1157835SDaniel Fojt 		}
1287*a1157835SDaniel Fojt 	}
1288*a1157835SDaniel Fojt 
1289*a1157835SDaniel Fojt 	if (data->result_success_done && data->session_ticket_used &&
1290*a1157835SDaniel Fojt 	    eap_teap_derive_msk(data) == 0) {
1291*a1157835SDaniel Fojt 		/* Assume the server might accept authentication without going
1292*a1157835SDaniel Fojt 		 * through inner authentication. */
1293*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1294*a1157835SDaniel Fojt 			   "EAP-TEAP: PAC used - server may decide to skip inner authentication");
1295*a1157835SDaniel Fojt 		ret->methodState = METHOD_MAY_CONT;
1296*a1157835SDaniel Fojt 		ret->decision = DECISION_COND_SUCC;
1297*a1157835SDaniel Fojt 	}
1298*a1157835SDaniel Fojt 
1299*a1157835SDaniel Fojt 	if (tlv.pac) {
1300*a1157835SDaniel Fojt 		if (tlv.result == TEAP_STATUS_SUCCESS) {
1301*a1157835SDaniel Fojt 			tmp = eap_teap_process_pac(sm, data, ret,
1302*a1157835SDaniel Fojt 						   tlv.pac, tlv.pac_len);
1303*a1157835SDaniel Fojt 			resp = wpabuf_concat(resp, tmp);
1304*a1157835SDaniel Fojt 		} else {
1305*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1306*a1157835SDaniel Fojt 				   "EAP-TEAP: PAC TLV without Result TLV acknowledging success");
1307*a1157835SDaniel Fojt 			failed = 1;
1308*a1157835SDaniel Fojt 			error = TEAP_ERROR_UNEXPECTED_TLVS_EXCHANGED;
1309*a1157835SDaniel Fojt 		}
1310*a1157835SDaniel Fojt 	}
1311*a1157835SDaniel Fojt 
1312*a1157835SDaniel Fojt 	if (!data->current_pac && data->provisioning && !failed && !tlv.pac &&
1313*a1157835SDaniel Fojt 	    tlv.crypto_binding &&
1314*a1157835SDaniel Fojt 	    (!data->anon_provisioning ||
1315*a1157835SDaniel Fojt 	     (data->phase2_success && data->phase2_method &&
1316*a1157835SDaniel Fojt 	      data->phase2_method->vendor == 0 &&
1317*a1157835SDaniel Fojt 	      eap_teap_allowed_anon_prov_cipher_suite(data->tls_cs) &&
1318*a1157835SDaniel Fojt 	      eap_teap_allowed_anon_prov_phase2_method(
1319*a1157835SDaniel Fojt 		      data->phase2_method->method))) &&
1320*a1157835SDaniel Fojt 	    (tlv.iresult == TEAP_STATUS_SUCCESS ||
1321*a1157835SDaniel Fojt 	     tlv.result == TEAP_STATUS_SUCCESS)) {
1322*a1157835SDaniel Fojt 		/*
1323*a1157835SDaniel Fojt 		 * Need to request Tunnel PAC when using authenticated
1324*a1157835SDaniel Fojt 		 * provisioning.
1325*a1157835SDaniel Fojt 		 */
1326*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "EAP-TEAP: Request Tunnel PAC");
1327*a1157835SDaniel Fojt 		tmp = eap_teap_pac_request();
1328*a1157835SDaniel Fojt 		resp = wpabuf_concat(resp, tmp);
1329*a1157835SDaniel Fojt 	}
1330*a1157835SDaniel Fojt 
1331*a1157835SDaniel Fojt done:
1332*a1157835SDaniel Fojt 	if (failed) {
1333*a1157835SDaniel Fojt 		tmp = eap_teap_tlv_result(TEAP_STATUS_FAILURE, 0);
1334*a1157835SDaniel Fojt 		resp = wpabuf_concat(tmp, resp);
1335*a1157835SDaniel Fojt 
1336*a1157835SDaniel Fojt 		if (error != 0) {
1337*a1157835SDaniel Fojt 			tmp = eap_teap_tlv_error(error);
1338*a1157835SDaniel Fojt 			resp = wpabuf_concat(tmp, resp);
1339*a1157835SDaniel Fojt 		}
1340*a1157835SDaniel Fojt 
1341*a1157835SDaniel Fojt 		ret->methodState = METHOD_DONE;
1342*a1157835SDaniel Fojt 		ret->decision = DECISION_FAIL;
1343*a1157835SDaniel Fojt 	} else if (tlv.result == TEAP_STATUS_SUCCESS) {
1344*a1157835SDaniel Fojt 		tmp = eap_teap_tlv_result(TEAP_STATUS_SUCCESS, 0);
1345*a1157835SDaniel Fojt 		resp = wpabuf_concat(tmp, resp);
1346*a1157835SDaniel Fojt 	}
1347*a1157835SDaniel Fojt 
1348*a1157835SDaniel Fojt 	if (resp && tlv.result == TEAP_STATUS_SUCCESS && !failed &&
1349*a1157835SDaniel Fojt 	    tlv.crypto_binding && data->phase2_success) {
1350*a1157835SDaniel Fojt 		/* Successfully completed Phase 2 */
1351*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1352*a1157835SDaniel Fojt 			   "EAP-TEAP: Authentication completed successfully");
1353*a1157835SDaniel Fojt 		ret->methodState = METHOD_MAY_CONT;
1354*a1157835SDaniel Fojt 		data->on_tx_completion = data->provisioning ?
1355*a1157835SDaniel Fojt 			METHOD_MAY_CONT : METHOD_DONE;
1356*a1157835SDaniel Fojt 		ret->decision = DECISION_UNCOND_SUCC;
1357*a1157835SDaniel Fojt 	}
1358*a1157835SDaniel Fojt 
1359*a1157835SDaniel Fojt 	if (!resp) {
1360*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1361*a1157835SDaniel Fojt 			   "EAP-TEAP: No recognized TLVs - send empty response packet");
1362*a1157835SDaniel Fojt 		resp = wpabuf_alloc(1);
1363*a1157835SDaniel Fojt 	}
1364*a1157835SDaniel Fojt 
1365*a1157835SDaniel Fojt send_resp:
1366*a1157835SDaniel Fojt 	if (!resp)
1367*a1157835SDaniel Fojt 		return 0;
1368*a1157835SDaniel Fojt 
1369*a1157835SDaniel Fojt 	wpa_hexdump_buf(MSG_DEBUG, "EAP-TEAP: Encrypting Phase 2 data", resp);
1370*a1157835SDaniel Fojt 	if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TEAP,
1371*a1157835SDaniel Fojt 				 data->teap_version, identifier,
1372*a1157835SDaniel Fojt 				 resp, out_data)) {
1373*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
1374*a1157835SDaniel Fojt 			   "EAP-TEAP: Failed to encrypt a Phase 2 frame");
1375*a1157835SDaniel Fojt 	}
1376*a1157835SDaniel Fojt 	wpabuf_free(resp);
1377*a1157835SDaniel Fojt 
1378*a1157835SDaniel Fojt 	return 0;
1379*a1157835SDaniel Fojt }
1380*a1157835SDaniel Fojt 
1381*a1157835SDaniel Fojt 
eap_teap_decrypt(struct eap_sm * sm,struct eap_teap_data * data,struct eap_method_ret * ret,u8 identifier,const struct wpabuf * in_data,struct wpabuf ** out_data)1382*a1157835SDaniel Fojt static int eap_teap_decrypt(struct eap_sm *sm, struct eap_teap_data *data,
1383*a1157835SDaniel Fojt 			    struct eap_method_ret *ret, u8 identifier,
1384*a1157835SDaniel Fojt 			    const struct wpabuf *in_data,
1385*a1157835SDaniel Fojt 			    struct wpabuf **out_data)
1386*a1157835SDaniel Fojt {
1387*a1157835SDaniel Fojt 	struct wpabuf *in_decrypted;
1388*a1157835SDaniel Fojt 	int res;
1389*a1157835SDaniel Fojt 
1390*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
1391*a1157835SDaniel Fojt 		   "EAP-TEAP: Received %lu bytes encrypted data for Phase 2",
1392*a1157835SDaniel Fojt 		   (unsigned long) wpabuf_len(in_data));
1393*a1157835SDaniel Fojt 
1394*a1157835SDaniel Fojt 	if (data->pending_phase2_req) {
1395*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1396*a1157835SDaniel Fojt 			   "EAP-TEAP: Pending Phase 2 request - skip decryption and use old data");
1397*a1157835SDaniel Fojt 		/* Clear TLS reassembly state. */
1398*a1157835SDaniel Fojt 		eap_peer_tls_reset_input(&data->ssl);
1399*a1157835SDaniel Fojt 
1400*a1157835SDaniel Fojt 		in_decrypted = data->pending_phase2_req;
1401*a1157835SDaniel Fojt 		data->pending_phase2_req = NULL;
1402*a1157835SDaniel Fojt 		goto continue_req;
1403*a1157835SDaniel Fojt 	}
1404*a1157835SDaniel Fojt 
1405*a1157835SDaniel Fojt 	if (wpabuf_len(in_data) == 0) {
1406*a1157835SDaniel Fojt 		/* Received TLS ACK - requesting more fragments */
1407*a1157835SDaniel Fojt 		res = eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TEAP,
1408*a1157835SDaniel Fojt 					   data->teap_version,
1409*a1157835SDaniel Fojt 					   identifier, NULL, out_data);
1410*a1157835SDaniel Fojt 		if (res == 0 && !data->ssl.tls_out &&
1411*a1157835SDaniel Fojt 		    data->on_tx_completion) {
1412*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1413*a1157835SDaniel Fojt 				   "EAP-TEAP: Mark authentication completed at full TX of fragments");
1414*a1157835SDaniel Fojt 			ret->methodState = data->on_tx_completion;
1415*a1157835SDaniel Fojt 			data->on_tx_completion = 0;
1416*a1157835SDaniel Fojt 			ret->decision = DECISION_UNCOND_SUCC;
1417*a1157835SDaniel Fojt 		}
1418*a1157835SDaniel Fojt 		return res;
1419*a1157835SDaniel Fojt 	}
1420*a1157835SDaniel Fojt 
1421*a1157835SDaniel Fojt 	res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
1422*a1157835SDaniel Fojt 	if (res)
1423*a1157835SDaniel Fojt 		return res;
1424*a1157835SDaniel Fojt 
1425*a1157835SDaniel Fojt continue_req:
1426*a1157835SDaniel Fojt 	wpa_hexdump_buf(MSG_MSGDUMP, "EAP-TEAP: Decrypted Phase 2 TLV(s)",
1427*a1157835SDaniel Fojt 			in_decrypted);
1428*a1157835SDaniel Fojt 
1429*a1157835SDaniel Fojt 	if (wpabuf_len(in_decrypted) < 4) {
1430*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
1431*a1157835SDaniel Fojt 			   "EAP-TEAP: Too short Phase 2 TLV frame (len=%lu)",
1432*a1157835SDaniel Fojt 			   (unsigned long) wpabuf_len(in_decrypted));
1433*a1157835SDaniel Fojt 		wpabuf_free(in_decrypted);
1434*a1157835SDaniel Fojt 		return -1;
1435*a1157835SDaniel Fojt 	}
1436*a1157835SDaniel Fojt 
1437*a1157835SDaniel Fojt 	res = eap_teap_process_decrypted(sm, data, ret, identifier,
1438*a1157835SDaniel Fojt 					 in_decrypted, out_data);
1439*a1157835SDaniel Fojt 
1440*a1157835SDaniel Fojt 	wpabuf_free(in_decrypted);
1441*a1157835SDaniel Fojt 
1442*a1157835SDaniel Fojt 	return res;
1443*a1157835SDaniel Fojt }
1444*a1157835SDaniel Fojt 
1445*a1157835SDaniel Fojt 
eap_teap_select_pac(struct eap_teap_data * data,const u8 * a_id,size_t a_id_len)1446*a1157835SDaniel Fojt static void eap_teap_select_pac(struct eap_teap_data *data,
1447*a1157835SDaniel Fojt 				const u8 *a_id, size_t a_id_len)
1448*a1157835SDaniel Fojt {
1449*a1157835SDaniel Fojt 	if (!a_id)
1450*a1157835SDaniel Fojt 		return;
1451*a1157835SDaniel Fojt 	data->current_pac = eap_teap_get_pac(data->pac, a_id, a_id_len,
1452*a1157835SDaniel Fojt 					     PAC_TYPE_TUNNEL_PAC);
1453*a1157835SDaniel Fojt 	if (data->current_pac) {
1454*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1455*a1157835SDaniel Fojt 			   "EAP-TEAP: PAC found for this A-ID (PAC-Type %d)",
1456*a1157835SDaniel Fojt 			   data->current_pac->pac_type);
1457*a1157835SDaniel Fojt 		wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TEAP: A-ID-Info",
1458*a1157835SDaniel Fojt 				  data->current_pac->a_id_info,
1459*a1157835SDaniel Fojt 				  data->current_pac->a_id_info_len);
1460*a1157835SDaniel Fojt 	}
1461*a1157835SDaniel Fojt }
1462*a1157835SDaniel Fojt 
1463*a1157835SDaniel Fojt 
eap_teap_use_pac_opaque(struct eap_sm * sm,struct eap_teap_data * data,struct eap_teap_pac * pac)1464*a1157835SDaniel Fojt static int eap_teap_use_pac_opaque(struct eap_sm *sm,
1465*a1157835SDaniel Fojt 				   struct eap_teap_data *data,
1466*a1157835SDaniel Fojt 				   struct eap_teap_pac *pac)
1467*a1157835SDaniel Fojt {
1468*a1157835SDaniel Fojt 	u8 *tlv;
1469*a1157835SDaniel Fojt 	size_t tlv_len, olen;
1470*a1157835SDaniel Fojt 	struct teap_tlv_hdr *ehdr;
1471*a1157835SDaniel Fojt 
1472*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "EAP-TEAP: Add PAC-Opaque TLS extension");
1473*a1157835SDaniel Fojt 	olen = pac->pac_opaque_len;
1474*a1157835SDaniel Fojt 	tlv_len = sizeof(*ehdr) + olen;
1475*a1157835SDaniel Fojt 	tlv = os_malloc(tlv_len);
1476*a1157835SDaniel Fojt 	if (tlv) {
1477*a1157835SDaniel Fojt 		ehdr = (struct teap_tlv_hdr *) tlv;
1478*a1157835SDaniel Fojt 		ehdr->tlv_type = host_to_be16(PAC_TYPE_PAC_OPAQUE);
1479*a1157835SDaniel Fojt 		ehdr->length = host_to_be16(olen);
1480*a1157835SDaniel Fojt 		os_memcpy(ehdr + 1, pac->pac_opaque, olen);
1481*a1157835SDaniel Fojt 	}
1482*a1157835SDaniel Fojt 	if (!tlv ||
1483*a1157835SDaniel Fojt 	    tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn,
1484*a1157835SDaniel Fojt 					    TLS_EXT_PAC_OPAQUE,
1485*a1157835SDaniel Fojt 					    tlv, tlv_len) < 0) {
1486*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1487*a1157835SDaniel Fojt 			   "EAP-TEAP: Failed to add PAC-Opaque TLS extension");
1488*a1157835SDaniel Fojt 		os_free(tlv);
1489*a1157835SDaniel Fojt 		return -1;
1490*a1157835SDaniel Fojt 	}
1491*a1157835SDaniel Fojt 	os_free(tlv);
1492*a1157835SDaniel Fojt 
1493*a1157835SDaniel Fojt 	return 0;
1494*a1157835SDaniel Fojt }
1495*a1157835SDaniel Fojt 
1496*a1157835SDaniel Fojt 
eap_teap_clear_pac_opaque_ext(struct eap_sm * sm,struct eap_teap_data * data)1497*a1157835SDaniel Fojt static int eap_teap_clear_pac_opaque_ext(struct eap_sm *sm,
1498*a1157835SDaniel Fojt 					 struct eap_teap_data *data)
1499*a1157835SDaniel Fojt {
1500*a1157835SDaniel Fojt 	if (tls_connection_client_hello_ext(sm->ssl_ctx, data->ssl.conn,
1501*a1157835SDaniel Fojt 					    TLS_EXT_PAC_OPAQUE, NULL, 0) < 0) {
1502*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1503*a1157835SDaniel Fojt 			   "EAP-TEAP: Failed to remove PAC-Opaque TLS extension");
1504*a1157835SDaniel Fojt 		return -1;
1505*a1157835SDaniel Fojt 	}
1506*a1157835SDaniel Fojt 	return 0;
1507*a1157835SDaniel Fojt }
1508*a1157835SDaniel Fojt 
1509*a1157835SDaniel Fojt 
eap_teap_process_start(struct eap_sm * sm,struct eap_teap_data * data,u8 flags,const u8 * pos,size_t left)1510*a1157835SDaniel Fojt static int eap_teap_process_start(struct eap_sm *sm,
1511*a1157835SDaniel Fojt 				  struct eap_teap_data *data, u8 flags,
1512*a1157835SDaniel Fojt 				  const u8 *pos, size_t left)
1513*a1157835SDaniel Fojt {
1514*a1157835SDaniel Fojt 	const u8 *a_id = NULL;
1515*a1157835SDaniel Fojt 	size_t a_id_len = 0;
1516*a1157835SDaniel Fojt 
1517*a1157835SDaniel Fojt 	/* TODO: Support (mostly theoretical) case of TEAP/Start request being
1518*a1157835SDaniel Fojt 	 * fragmented */
1519*a1157835SDaniel Fojt 
1520*a1157835SDaniel Fojt 	/* EAP-TEAP version negotiation (RFC 7170, Section 3.2) */
1521*a1157835SDaniel Fojt 	data->received_version = flags & EAP_TLS_VERSION_MASK;
1522*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "EAP-TEAP: Start (server ver=%u, own ver=%u)",
1523*a1157835SDaniel Fojt 		   data->received_version, data->teap_version);
1524*a1157835SDaniel Fojt 	if (data->received_version < 1) {
1525*a1157835SDaniel Fojt 		/* Version 1 was the first defined version, so reject 0 */
1526*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
1527*a1157835SDaniel Fojt 			   "EAP-TEAP: Server used unknown TEAP version %u",
1528*a1157835SDaniel Fojt 			   data->received_version);
1529*a1157835SDaniel Fojt 		return -1;
1530*a1157835SDaniel Fojt 	}
1531*a1157835SDaniel Fojt 	if (data->received_version < data->teap_version)
1532*a1157835SDaniel Fojt 		data->teap_version = data->received_version;
1533*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "EAP-TEAP: Using TEAP version %d",
1534*a1157835SDaniel Fojt 		   data->teap_version);
1535*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Start message payload", pos, left);
1536*a1157835SDaniel Fojt 
1537*a1157835SDaniel Fojt 	/* Parse Authority-ID TLV from Outer TLVs, if present */
1538*a1157835SDaniel Fojt 	if (flags & EAP_TEAP_FLAGS_OUTER_TLV_LEN) {
1539*a1157835SDaniel Fojt 		const u8 *outer_pos, *outer_end;
1540*a1157835SDaniel Fojt 		u32 outer_tlv_len;
1541*a1157835SDaniel Fojt 
1542*a1157835SDaniel Fojt 		if (left < 4) {
1543*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
1544*a1157835SDaniel Fojt 				   "EAP-TEAP: Not enough room for the Outer TLV Length field");
1545*a1157835SDaniel Fojt 			return -1;
1546*a1157835SDaniel Fojt 		}
1547*a1157835SDaniel Fojt 
1548*a1157835SDaniel Fojt 		outer_tlv_len = WPA_GET_BE32(pos);
1549*a1157835SDaniel Fojt 		pos += 4;
1550*a1157835SDaniel Fojt 		left -= 4;
1551*a1157835SDaniel Fojt 
1552*a1157835SDaniel Fojt 		if (outer_tlv_len > left) {
1553*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
1554*a1157835SDaniel Fojt 				   "EAP-TEAP: Truncated Outer TLVs field (Outer TLV Length: %u; remaining buffer: %u)",
1555*a1157835SDaniel Fojt 				   outer_tlv_len, (unsigned int) left);
1556*a1157835SDaniel Fojt 			return -1;
1557*a1157835SDaniel Fojt 		}
1558*a1157835SDaniel Fojt 
1559*a1157835SDaniel Fojt 		outer_pos = pos + left - outer_tlv_len;
1560*a1157835SDaniel Fojt 		outer_end = outer_pos + outer_tlv_len;
1561*a1157835SDaniel Fojt 		wpa_hexdump(MSG_MSGDUMP, "EAP-TEAP: Start message Outer TLVs",
1562*a1157835SDaniel Fojt 			    outer_pos, outer_tlv_len);
1563*a1157835SDaniel Fojt 		wpabuf_free(data->server_outer_tlvs);
1564*a1157835SDaniel Fojt 		data->server_outer_tlvs = wpabuf_alloc_copy(outer_pos,
1565*a1157835SDaniel Fojt 							    outer_tlv_len);
1566*a1157835SDaniel Fojt 		if (!data->server_outer_tlvs)
1567*a1157835SDaniel Fojt 			return -1;
1568*a1157835SDaniel Fojt 		left -= outer_tlv_len;
1569*a1157835SDaniel Fojt 		if (left > 0) {
1570*a1157835SDaniel Fojt 			wpa_hexdump(MSG_INFO,
1571*a1157835SDaniel Fojt 				    "EAP-TEAP: Unexpected TLS Data in Start message",
1572*a1157835SDaniel Fojt 				    pos, left);
1573*a1157835SDaniel Fojt 			return -1;
1574*a1157835SDaniel Fojt 		}
1575*a1157835SDaniel Fojt 
1576*a1157835SDaniel Fojt 		while (outer_pos < outer_end) {
1577*a1157835SDaniel Fojt 			u16 tlv_type, tlv_len;
1578*a1157835SDaniel Fojt 
1579*a1157835SDaniel Fojt 			if (outer_end - outer_pos < 4) {
1580*a1157835SDaniel Fojt 				wpa_printf(MSG_INFO,
1581*a1157835SDaniel Fojt 					   "EAP-TEAP: Truncated Outer TLV header");
1582*a1157835SDaniel Fojt 				return -1;
1583*a1157835SDaniel Fojt 			}
1584*a1157835SDaniel Fojt 			tlv_type = WPA_GET_BE16(outer_pos);
1585*a1157835SDaniel Fojt 			outer_pos += 2;
1586*a1157835SDaniel Fojt 			tlv_len = WPA_GET_BE16(outer_pos);
1587*a1157835SDaniel Fojt 			outer_pos += 2;
1588*a1157835SDaniel Fojt 			/* Outer TLVs are required to be optional, so no need to
1589*a1157835SDaniel Fojt 			 * check the M flag */
1590*a1157835SDaniel Fojt 			tlv_type &= TEAP_TLV_TYPE_MASK;
1591*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1592*a1157835SDaniel Fojt 				   "EAP-TEAP: Outer TLV: Type=%u Length=%u",
1593*a1157835SDaniel Fojt 				   tlv_type, tlv_len);
1594*a1157835SDaniel Fojt 			if (outer_end - outer_pos < tlv_len) {
1595*a1157835SDaniel Fojt 				wpa_printf(MSG_INFO,
1596*a1157835SDaniel Fojt 					   "EAP-TEAP: Truncated Outer TLV (Type %u)",
1597*a1157835SDaniel Fojt 					   tlv_type);
1598*a1157835SDaniel Fojt 				return -1;
1599*a1157835SDaniel Fojt 			}
1600*a1157835SDaniel Fojt 			if (tlv_type == TEAP_TLV_AUTHORITY_ID) {
1601*a1157835SDaniel Fojt 				wpa_hexdump(MSG_DEBUG, "EAP-TEAP: Authority-ID",
1602*a1157835SDaniel Fojt 					    outer_pos, tlv_len);
1603*a1157835SDaniel Fojt 				if (a_id) {
1604*a1157835SDaniel Fojt 					wpa_printf(MSG_INFO,
1605*a1157835SDaniel Fojt 						   "EAP-TEAP: Multiple Authority-ID TLVs in TEAP/Start");
1606*a1157835SDaniel Fojt 					return -1;
1607*a1157835SDaniel Fojt 				}
1608*a1157835SDaniel Fojt 				a_id = outer_pos;
1609*a1157835SDaniel Fojt 				a_id_len = tlv_len;
1610*a1157835SDaniel Fojt 			} else {
1611*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
1612*a1157835SDaniel Fojt 					   "EAP-TEAP: Ignore unknown Outer TLV (Type %u)",
1613*a1157835SDaniel Fojt 					   tlv_type);
1614*a1157835SDaniel Fojt 			}
1615*a1157835SDaniel Fojt 			outer_pos += tlv_len;
1616*a1157835SDaniel Fojt 		}
1617*a1157835SDaniel Fojt 	} else if (left > 0) {
1618*a1157835SDaniel Fojt 		wpa_hexdump(MSG_INFO,
1619*a1157835SDaniel Fojt 			    "EAP-TEAP: Unexpected TLS Data in Start message",
1620*a1157835SDaniel Fojt 			    pos, left);
1621*a1157835SDaniel Fojt 		return -1;
1622*a1157835SDaniel Fojt 	}
1623*a1157835SDaniel Fojt 
1624*a1157835SDaniel Fojt 	eap_teap_select_pac(data, a_id, a_id_len);
1625*a1157835SDaniel Fojt 
1626*a1157835SDaniel Fojt 	if (data->resuming && data->current_pac) {
1627*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1628*a1157835SDaniel Fojt 			   "EAP-TEAP: Trying to resume session - do not add PAC-Opaque to TLS ClientHello");
1629*a1157835SDaniel Fojt 		if (eap_teap_clear_pac_opaque_ext(sm, data) < 0)
1630*a1157835SDaniel Fojt 			return -1;
1631*a1157835SDaniel Fojt 	} else if (data->current_pac) {
1632*a1157835SDaniel Fojt 		/*
1633*a1157835SDaniel Fojt 		 * PAC found for the A-ID and we are not resuming an old
1634*a1157835SDaniel Fojt 		 * session, so add PAC-Opaque extension to ClientHello.
1635*a1157835SDaniel Fojt 		 */
1636*a1157835SDaniel Fojt 		if (eap_teap_use_pac_opaque(sm, data, data->current_pac) < 0)
1637*a1157835SDaniel Fojt 			return -1;
1638*a1157835SDaniel Fojt 	} else if (data->provisioning_allowed) {
1639*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1640*a1157835SDaniel Fojt 			   "EAP-TEAP: No PAC found - starting provisioning");
1641*a1157835SDaniel Fojt 		if (eap_teap_clear_pac_opaque_ext(sm, data) < 0)
1642*a1157835SDaniel Fojt 			return -1;
1643*a1157835SDaniel Fojt 		data->provisioning = 1;
1644*a1157835SDaniel Fojt 	}
1645*a1157835SDaniel Fojt 
1646*a1157835SDaniel Fojt 	return 0;
1647*a1157835SDaniel Fojt }
1648*a1157835SDaniel Fojt 
1649*a1157835SDaniel Fojt 
1650*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
eap_teap_add_dummy_outer_tlvs(struct eap_teap_data * data,struct wpabuf * resp)1651*a1157835SDaniel Fojt static struct wpabuf * eap_teap_add_dummy_outer_tlvs(struct eap_teap_data *data,
1652*a1157835SDaniel Fojt 						     struct wpabuf *resp)
1653*a1157835SDaniel Fojt {
1654*a1157835SDaniel Fojt 	struct wpabuf *resp2;
1655*a1157835SDaniel Fojt 	u16 len;
1656*a1157835SDaniel Fojt 	const u8 *pos;
1657*a1157835SDaniel Fojt 	u8 flags;
1658*a1157835SDaniel Fojt 
1659*a1157835SDaniel Fojt 	wpabuf_free(data->peer_outer_tlvs);
1660*a1157835SDaniel Fojt 	data->peer_outer_tlvs = wpabuf_alloc(4 + 4);
1661*a1157835SDaniel Fojt 	if (!data->peer_outer_tlvs) {
1662*a1157835SDaniel Fojt 		wpabuf_free(resp);
1663*a1157835SDaniel Fojt 		return NULL;
1664*a1157835SDaniel Fojt 	}
1665*a1157835SDaniel Fojt 
1666*a1157835SDaniel Fojt 	/* Outer TLVs (dummy Vendor-Specific TLV for testing) */
1667*a1157835SDaniel Fojt 	wpabuf_put_be16(data->peer_outer_tlvs, TEAP_TLV_VENDOR_SPECIFIC);
1668*a1157835SDaniel Fojt 	wpabuf_put_be16(data->peer_outer_tlvs, 4);
1669*a1157835SDaniel Fojt 	wpabuf_put_be32(data->peer_outer_tlvs, EAP_VENDOR_HOSTAP);
1670*a1157835SDaniel Fojt 	wpa_hexdump_buf(MSG_DEBUG, "EAP-TEAP: TESTING - Add dummy Outer TLVs",
1671*a1157835SDaniel Fojt 			data->peer_outer_tlvs);
1672*a1157835SDaniel Fojt 
1673*a1157835SDaniel Fojt 	wpa_hexdump_buf(MSG_DEBUG,
1674*a1157835SDaniel Fojt 			"EAP-TEAP: TEAP/Start response before modification",
1675*a1157835SDaniel Fojt 			resp);
1676*a1157835SDaniel Fojt 	resp2 = wpabuf_alloc(wpabuf_len(resp) + 4 +
1677*a1157835SDaniel Fojt 			     wpabuf_len(data->peer_outer_tlvs));
1678*a1157835SDaniel Fojt 	if (!resp2) {
1679*a1157835SDaniel Fojt 		wpabuf_free(resp);
1680*a1157835SDaniel Fojt 		return NULL;
1681*a1157835SDaniel Fojt 	}
1682*a1157835SDaniel Fojt 
1683*a1157835SDaniel Fojt 	pos = wpabuf_head(resp);
1684*a1157835SDaniel Fojt 	wpabuf_put_u8(resp2, *pos++); /* Code */
1685*a1157835SDaniel Fojt 	wpabuf_put_u8(resp2, *pos++); /* Identifier */
1686*a1157835SDaniel Fojt 	len = WPA_GET_BE16(pos);
1687*a1157835SDaniel Fojt 	pos += 2;
1688*a1157835SDaniel Fojt 	wpabuf_put_be16(resp2, len + 4 + wpabuf_len(data->peer_outer_tlvs));
1689*a1157835SDaniel Fojt 	wpabuf_put_u8(resp2, *pos++); /* Type */
1690*a1157835SDaniel Fojt 	/* Flags | Ver (with Outer TLV length included flag set to 1) */
1691*a1157835SDaniel Fojt 	flags = *pos++;
1692*a1157835SDaniel Fojt 	if (flags & (EAP_TEAP_FLAGS_OUTER_TLV_LEN |
1693*a1157835SDaniel Fojt 		     EAP_TLS_FLAGS_LENGTH_INCLUDED)) {
1694*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
1695*a1157835SDaniel Fojt 			   "EAP-TEAP: Cannot add Outer TLVs for testing");
1696*a1157835SDaniel Fojt 		wpabuf_free(resp);
1697*a1157835SDaniel Fojt 		wpabuf_free(resp2);
1698*a1157835SDaniel Fojt 		return NULL;
1699*a1157835SDaniel Fojt 	}
1700*a1157835SDaniel Fojt 	flags |= EAP_TEAP_FLAGS_OUTER_TLV_LEN;
1701*a1157835SDaniel Fojt 	wpabuf_put_u8(resp2, flags);
1702*a1157835SDaniel Fojt 	/* Outer TLV Length */
1703*a1157835SDaniel Fojt 	wpabuf_put_be32(resp2, wpabuf_len(data->peer_outer_tlvs));
1704*a1157835SDaniel Fojt 	/* TLS Data */
1705*a1157835SDaniel Fojt 	wpabuf_put_data(resp2, pos, wpabuf_len(resp) - 6);
1706*a1157835SDaniel Fojt 	wpabuf_put_buf(resp2, data->peer_outer_tlvs); /* Outer TLVs */
1707*a1157835SDaniel Fojt 
1708*a1157835SDaniel Fojt 	wpabuf_free(resp);
1709*a1157835SDaniel Fojt 	wpa_hexdump_buf(MSG_DEBUG,
1710*a1157835SDaniel Fojt 			"EAP-TEAP: TEAP/Start response after modification",
1711*a1157835SDaniel Fojt 			resp2);
1712*a1157835SDaniel Fojt 	return resp2;
1713*a1157835SDaniel Fojt }
1714*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
1715*a1157835SDaniel Fojt 
1716*a1157835SDaniel Fojt 
eap_teap_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)1717*a1157835SDaniel Fojt static struct wpabuf * eap_teap_process(struct eap_sm *sm, void *priv,
1718*a1157835SDaniel Fojt 					struct eap_method_ret *ret,
1719*a1157835SDaniel Fojt 					const struct wpabuf *reqData)
1720*a1157835SDaniel Fojt {
1721*a1157835SDaniel Fojt 	const struct eap_hdr *req;
1722*a1157835SDaniel Fojt 	size_t left;
1723*a1157835SDaniel Fojt 	int res;
1724*a1157835SDaniel Fojt 	u8 flags, id;
1725*a1157835SDaniel Fojt 	struct wpabuf *resp;
1726*a1157835SDaniel Fojt 	const u8 *pos;
1727*a1157835SDaniel Fojt 	struct eap_teap_data *data = priv;
1728*a1157835SDaniel Fojt 	struct wpabuf msg;
1729*a1157835SDaniel Fojt 
1730*a1157835SDaniel Fojt 	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TEAP, ret,
1731*a1157835SDaniel Fojt 					reqData, &left, &flags);
1732*a1157835SDaniel Fojt 	if (!pos)
1733*a1157835SDaniel Fojt 		return NULL;
1734*a1157835SDaniel Fojt 
1735*a1157835SDaniel Fojt 	req = wpabuf_head(reqData);
1736*a1157835SDaniel Fojt 	id = req->identifier;
1737*a1157835SDaniel Fojt 
1738*a1157835SDaniel Fojt 	if (flags & EAP_TLS_FLAGS_START) {
1739*a1157835SDaniel Fojt 		if (eap_teap_process_start(sm, data, flags, pos, left) < 0)
1740*a1157835SDaniel Fojt 			return NULL;
1741*a1157835SDaniel Fojt 
1742*a1157835SDaniel Fojt 		/* Outer TLVs are not used in further packet processing and
1743*a1157835SDaniel Fojt 		 * there cannot be TLS Data in this TEAP/Start message, so
1744*a1157835SDaniel Fojt 		 * enforce that by ignoring whatever data might remain in the
1745*a1157835SDaniel Fojt 		 * buffer. */
1746*a1157835SDaniel Fojt 		left = 0;
1747*a1157835SDaniel Fojt 	} else if (flags & EAP_TEAP_FLAGS_OUTER_TLV_LEN) {
1748*a1157835SDaniel Fojt 		/* TODO: RFC 7170, Section 4.3.1 indicates that the unexpected
1749*a1157835SDaniel Fojt 		 * Outer TLVs MUST be ignored instead of ignoring the full
1750*a1157835SDaniel Fojt 		 * message. */
1751*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
1752*a1157835SDaniel Fojt 			   "EAP-TEAP: Outer TLVs present in non-Start message -> ignore message");
1753*a1157835SDaniel Fojt 		return NULL;
1754*a1157835SDaniel Fojt 	}
1755*a1157835SDaniel Fojt 
1756*a1157835SDaniel Fojt 	wpabuf_set(&msg, pos, left);
1757*a1157835SDaniel Fojt 
1758*a1157835SDaniel Fojt 	resp = NULL;
1759*a1157835SDaniel Fojt 	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
1760*a1157835SDaniel Fojt 	    !data->resuming) {
1761*a1157835SDaniel Fojt 		/* Process tunneled (encrypted) phase 2 data. */
1762*a1157835SDaniel Fojt 		res = eap_teap_decrypt(sm, data, ret, id, &msg, &resp);
1763*a1157835SDaniel Fojt 		if (res < 0) {
1764*a1157835SDaniel Fojt 			ret->methodState = METHOD_DONE;
1765*a1157835SDaniel Fojt 			ret->decision = DECISION_FAIL;
1766*a1157835SDaniel Fojt 			/*
1767*a1157835SDaniel Fojt 			 * Ack possible Alert that may have caused failure in
1768*a1157835SDaniel Fojt 			 * decryption.
1769*a1157835SDaniel Fojt 			 */
1770*a1157835SDaniel Fojt 			res = 1;
1771*a1157835SDaniel Fojt 		}
1772*a1157835SDaniel Fojt 	} else {
1773*a1157835SDaniel Fojt 		if (sm->waiting_ext_cert_check && data->pending_resp) {
1774*a1157835SDaniel Fojt 			struct eap_peer_config *config = eap_get_config(sm);
1775*a1157835SDaniel Fojt 
1776*a1157835SDaniel Fojt 			if (config->pending_ext_cert_check ==
1777*a1157835SDaniel Fojt 			    EXT_CERT_CHECK_GOOD) {
1778*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
1779*a1157835SDaniel Fojt 					   "EAP-TEAP: External certificate check succeeded - continue handshake");
1780*a1157835SDaniel Fojt 				resp = data->pending_resp;
1781*a1157835SDaniel Fojt 				data->pending_resp = NULL;
1782*a1157835SDaniel Fojt 				sm->waiting_ext_cert_check = 0;
1783*a1157835SDaniel Fojt 				return resp;
1784*a1157835SDaniel Fojt 			}
1785*a1157835SDaniel Fojt 
1786*a1157835SDaniel Fojt 			if (config->pending_ext_cert_check ==
1787*a1157835SDaniel Fojt 			    EXT_CERT_CHECK_BAD) {
1788*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
1789*a1157835SDaniel Fojt 					   "EAP-TEAP: External certificate check failed - force authentication failure");
1790*a1157835SDaniel Fojt 				ret->methodState = METHOD_DONE;
1791*a1157835SDaniel Fojt 				ret->decision = DECISION_FAIL;
1792*a1157835SDaniel Fojt 				sm->waiting_ext_cert_check = 0;
1793*a1157835SDaniel Fojt 				return NULL;
1794*a1157835SDaniel Fojt 			}
1795*a1157835SDaniel Fojt 
1796*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1797*a1157835SDaniel Fojt 				   "EAP-TEAP: Continuing to wait external server certificate validation");
1798*a1157835SDaniel Fojt 			return NULL;
1799*a1157835SDaniel Fojt 		}
1800*a1157835SDaniel Fojt 
1801*a1157835SDaniel Fojt 		/* Continue processing TLS handshake (phase 1). */
1802*a1157835SDaniel Fojt 		res = eap_peer_tls_process_helper(sm, &data->ssl,
1803*a1157835SDaniel Fojt 						  EAP_TYPE_TEAP,
1804*a1157835SDaniel Fojt 						  data->teap_version, id, &msg,
1805*a1157835SDaniel Fojt 						  &resp);
1806*a1157835SDaniel Fojt 		if (res < 0) {
1807*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1808*a1157835SDaniel Fojt 				   "EAP-TEAP: TLS processing failed");
1809*a1157835SDaniel Fojt 			ret->methodState = METHOD_DONE;
1810*a1157835SDaniel Fojt 			ret->decision = DECISION_FAIL;
1811*a1157835SDaniel Fojt 			return resp;
1812*a1157835SDaniel Fojt 		}
1813*a1157835SDaniel Fojt 
1814*a1157835SDaniel Fojt 		if (sm->waiting_ext_cert_check) {
1815*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1816*a1157835SDaniel Fojt 				   "EAP-TEAP: Waiting external server certificate validation");
1817*a1157835SDaniel Fojt 			wpabuf_free(data->pending_resp);
1818*a1157835SDaniel Fojt 			data->pending_resp = resp;
1819*a1157835SDaniel Fojt 			return NULL;
1820*a1157835SDaniel Fojt 		}
1821*a1157835SDaniel Fojt 
1822*a1157835SDaniel Fojt 		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
1823*a1157835SDaniel Fojt 			char cipher[80];
1824*a1157835SDaniel Fojt 
1825*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1826*a1157835SDaniel Fojt 				   "EAP-TEAP: TLS done, proceed to Phase 2");
1827*a1157835SDaniel Fojt 			data->tls_cs =
1828*a1157835SDaniel Fojt 				tls_connection_get_cipher_suite(data->ssl.conn);
1829*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1830*a1157835SDaniel Fojt 				   "EAP-TEAP: TLS cipher suite 0x%04x",
1831*a1157835SDaniel Fojt 				   data->tls_cs);
1832*a1157835SDaniel Fojt 
1833*a1157835SDaniel Fojt 			if (data->provisioning &&
1834*a1157835SDaniel Fojt 			    (!(data->provisioning_allowed &
1835*a1157835SDaniel Fojt 			       EAP_TEAP_PROV_AUTH) ||
1836*a1157835SDaniel Fojt 			     tls_get_cipher(sm->ssl_ctx, data->ssl.conn,
1837*a1157835SDaniel Fojt 					    cipher, sizeof(cipher)) < 0 ||
1838*a1157835SDaniel Fojt 			     os_strstr(cipher, "ADH-") ||
1839*a1157835SDaniel Fojt 			     os_strstr(cipher, "anon"))) {
1840*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
1841*a1157835SDaniel Fojt 					   "EAP-TEAP: Using anonymous (unauthenticated) provisioning");
1842*a1157835SDaniel Fojt 				data->anon_provisioning = 1;
1843*a1157835SDaniel Fojt 			} else {
1844*a1157835SDaniel Fojt 				data->anon_provisioning = 0;
1845*a1157835SDaniel Fojt 			}
1846*a1157835SDaniel Fojt 			data->resuming = 0;
1847*a1157835SDaniel Fojt 			if (eap_teap_derive_key_auth(sm, data) < 0) {
1848*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
1849*a1157835SDaniel Fojt 					   "EAP-TEAP: Could not derive keys");
1850*a1157835SDaniel Fojt 				ret->methodState = METHOD_DONE;
1851*a1157835SDaniel Fojt 				ret->decision = DECISION_FAIL;
1852*a1157835SDaniel Fojt 				wpabuf_free(resp);
1853*a1157835SDaniel Fojt 				return NULL;
1854*a1157835SDaniel Fojt 			}
1855*a1157835SDaniel Fojt 		}
1856*a1157835SDaniel Fojt 
1857*a1157835SDaniel Fojt 		if (res == 2) {
1858*a1157835SDaniel Fojt 			/*
1859*a1157835SDaniel Fojt 			 * Application data included in the handshake message.
1860*a1157835SDaniel Fojt 			 */
1861*a1157835SDaniel Fojt 			wpabuf_free(data->pending_phase2_req);
1862*a1157835SDaniel Fojt 			data->pending_phase2_req = resp;
1863*a1157835SDaniel Fojt 			resp = NULL;
1864*a1157835SDaniel Fojt 			res = eap_teap_decrypt(sm, data, ret, id, &msg, &resp);
1865*a1157835SDaniel Fojt 		}
1866*a1157835SDaniel Fojt 	}
1867*a1157835SDaniel Fojt 
1868*a1157835SDaniel Fojt 	if (res == 1) {
1869*a1157835SDaniel Fojt 		wpabuf_free(resp);
1870*a1157835SDaniel Fojt 		return eap_peer_tls_build_ack(id, EAP_TYPE_TEAP,
1871*a1157835SDaniel Fojt 					      data->teap_version);
1872*a1157835SDaniel Fojt 	}
1873*a1157835SDaniel Fojt 
1874*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
1875*a1157835SDaniel Fojt 	if (data->test_outer_tlvs && res == 0 && resp &&
1876*a1157835SDaniel Fojt 	    (flags & EAP_TLS_FLAGS_START) && wpabuf_len(resp) >= 6)
1877*a1157835SDaniel Fojt 		resp = eap_teap_add_dummy_outer_tlvs(data, resp);
1878*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
1879*a1157835SDaniel Fojt 
1880*a1157835SDaniel Fojt 	return resp;
1881*a1157835SDaniel Fojt }
1882*a1157835SDaniel Fojt 
1883*a1157835SDaniel Fojt 
1884*a1157835SDaniel Fojt #if 0 /* TODO */
1885*a1157835SDaniel Fojt static Boolean eap_teap_has_reauth_data(struct eap_sm *sm, void *priv)
1886*a1157835SDaniel Fojt {
1887*a1157835SDaniel Fojt 	struct eap_teap_data *data = priv;
1888*a1157835SDaniel Fojt 
1889*a1157835SDaniel Fojt 	return tls_connection_established(sm->ssl_ctx, data->ssl.conn);
1890*a1157835SDaniel Fojt }
1891*a1157835SDaniel Fojt 
1892*a1157835SDaniel Fojt 
1893*a1157835SDaniel Fojt static void eap_teap_deinit_for_reauth(struct eap_sm *sm, void *priv)
1894*a1157835SDaniel Fojt {
1895*a1157835SDaniel Fojt 	struct eap_teap_data *data = priv;
1896*a1157835SDaniel Fojt 
1897*a1157835SDaniel Fojt 	if (data->phase2_priv && data->phase2_method &&
1898*a1157835SDaniel Fojt 	    data->phase2_method->deinit_for_reauth)
1899*a1157835SDaniel Fojt 		data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
1900*a1157835SDaniel Fojt 	eap_teap_clear(data);
1901*a1157835SDaniel Fojt }
1902*a1157835SDaniel Fojt 
1903*a1157835SDaniel Fojt 
1904*a1157835SDaniel Fojt static void * eap_teap_init_for_reauth(struct eap_sm *sm, void *priv)
1905*a1157835SDaniel Fojt {
1906*a1157835SDaniel Fojt 	struct eap_teap_data *data = priv;
1907*a1157835SDaniel Fojt 
1908*a1157835SDaniel Fojt 	if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
1909*a1157835SDaniel Fojt 		eap_teap_deinit(sm, data);
1910*a1157835SDaniel Fojt 		return NULL;
1911*a1157835SDaniel Fojt 	}
1912*a1157835SDaniel Fojt 	if (data->phase2_priv && data->phase2_method &&
1913*a1157835SDaniel Fojt 	    data->phase2_method->init_for_reauth)
1914*a1157835SDaniel Fojt 		data->phase2_method->init_for_reauth(sm, data->phase2_priv);
1915*a1157835SDaniel Fojt 	data->phase2_success = 0;
1916*a1157835SDaniel Fojt 	data->inner_method_done = 0;
1917*a1157835SDaniel Fojt 	data->result_success_done = 0;
1918*a1157835SDaniel Fojt 	data->done_on_tx_completion = 0;
1919*a1157835SDaniel Fojt 	data->resuming = 1;
1920*a1157835SDaniel Fojt 	data->provisioning = 0;
1921*a1157835SDaniel Fojt 	data->anon_provisioning = 0;
1922*a1157835SDaniel Fojt 	data->simck_idx = 0;
1923*a1157835SDaniel Fojt 	return priv;
1924*a1157835SDaniel Fojt }
1925*a1157835SDaniel Fojt #endif
1926*a1157835SDaniel Fojt 
1927*a1157835SDaniel Fojt 
eap_teap_get_status(struct eap_sm * sm,void * priv,char * buf,size_t buflen,int verbose)1928*a1157835SDaniel Fojt static int eap_teap_get_status(struct eap_sm *sm, void *priv, char *buf,
1929*a1157835SDaniel Fojt 			       size_t buflen, int verbose)
1930*a1157835SDaniel Fojt {
1931*a1157835SDaniel Fojt 	struct eap_teap_data *data = priv;
1932*a1157835SDaniel Fojt 	int len, ret;
1933*a1157835SDaniel Fojt 
1934*a1157835SDaniel Fojt 	len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
1935*a1157835SDaniel Fojt 	if (data->phase2_method) {
1936*a1157835SDaniel Fojt 		ret = os_snprintf(buf + len, buflen - len,
1937*a1157835SDaniel Fojt 				  "EAP-TEAP Phase 2 method=%s\n",
1938*a1157835SDaniel Fojt 				  data->phase2_method->name);
1939*a1157835SDaniel Fojt 		if (os_snprintf_error(buflen - len, ret))
1940*a1157835SDaniel Fojt 			return len;
1941*a1157835SDaniel Fojt 		len += ret;
1942*a1157835SDaniel Fojt 	}
1943*a1157835SDaniel Fojt 	return len;
1944*a1157835SDaniel Fojt }
1945*a1157835SDaniel Fojt 
1946*a1157835SDaniel Fojt 
eap_teap_isKeyAvailable(struct eap_sm * sm,void * priv)1947*a1157835SDaniel Fojt static Boolean eap_teap_isKeyAvailable(struct eap_sm *sm, void *priv)
1948*a1157835SDaniel Fojt {
1949*a1157835SDaniel Fojt 	struct eap_teap_data *data = priv;
1950*a1157835SDaniel Fojt 
1951*a1157835SDaniel Fojt 	return data->success;
1952*a1157835SDaniel Fojt }
1953*a1157835SDaniel Fojt 
1954*a1157835SDaniel Fojt 
eap_teap_getKey(struct eap_sm * sm,void * priv,size_t * len)1955*a1157835SDaniel Fojt static u8 * eap_teap_getKey(struct eap_sm *sm, void *priv, size_t *len)
1956*a1157835SDaniel Fojt {
1957*a1157835SDaniel Fojt 	struct eap_teap_data *data = priv;
1958*a1157835SDaniel Fojt 	u8 *key;
1959*a1157835SDaniel Fojt 
1960*a1157835SDaniel Fojt 	if (!data->success)
1961*a1157835SDaniel Fojt 		return NULL;
1962*a1157835SDaniel Fojt 
1963*a1157835SDaniel Fojt 	key = os_memdup(data->key_data, EAP_TEAP_KEY_LEN);
1964*a1157835SDaniel Fojt 	if (!key)
1965*a1157835SDaniel Fojt 		return NULL;
1966*a1157835SDaniel Fojt 
1967*a1157835SDaniel Fojt 	*len = EAP_TEAP_KEY_LEN;
1968*a1157835SDaniel Fojt 
1969*a1157835SDaniel Fojt 	return key;
1970*a1157835SDaniel Fojt }
1971*a1157835SDaniel Fojt 
1972*a1157835SDaniel Fojt 
eap_teap_get_session_id(struct eap_sm * sm,void * priv,size_t * len)1973*a1157835SDaniel Fojt static u8 * eap_teap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
1974*a1157835SDaniel Fojt {
1975*a1157835SDaniel Fojt 	struct eap_teap_data *data = priv;
1976*a1157835SDaniel Fojt 	u8 *id;
1977*a1157835SDaniel Fojt 
1978*a1157835SDaniel Fojt 	if (!data->success || !data->session_id)
1979*a1157835SDaniel Fojt 		return NULL;
1980*a1157835SDaniel Fojt 
1981*a1157835SDaniel Fojt 	id = os_memdup(data->session_id, data->id_len);
1982*a1157835SDaniel Fojt 	if (!id)
1983*a1157835SDaniel Fojt 		return NULL;
1984*a1157835SDaniel Fojt 
1985*a1157835SDaniel Fojt 	*len = data->id_len;
1986*a1157835SDaniel Fojt 
1987*a1157835SDaniel Fojt 	return id;
1988*a1157835SDaniel Fojt }
1989*a1157835SDaniel Fojt 
1990*a1157835SDaniel Fojt 
eap_teap_get_emsk(struct eap_sm * sm,void * priv,size_t * len)1991*a1157835SDaniel Fojt static u8 * eap_teap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1992*a1157835SDaniel Fojt {
1993*a1157835SDaniel Fojt 	struct eap_teap_data *data = priv;
1994*a1157835SDaniel Fojt 	u8 *key;
1995*a1157835SDaniel Fojt 
1996*a1157835SDaniel Fojt 	if (!data->success)
1997*a1157835SDaniel Fojt 		return NULL;
1998*a1157835SDaniel Fojt 
1999*a1157835SDaniel Fojt 	key = os_memdup(data->emsk, EAP_EMSK_LEN);
2000*a1157835SDaniel Fojt 	if (!key)
2001*a1157835SDaniel Fojt 		return NULL;
2002*a1157835SDaniel Fojt 
2003*a1157835SDaniel Fojt 	*len = EAP_EMSK_LEN;
2004*a1157835SDaniel Fojt 
2005*a1157835SDaniel Fojt 	return key;
2006*a1157835SDaniel Fojt }
2007*a1157835SDaniel Fojt 
2008*a1157835SDaniel Fojt 
eap_peer_teap_register(void)2009*a1157835SDaniel Fojt int eap_peer_teap_register(void)
2010*a1157835SDaniel Fojt {
2011*a1157835SDaniel Fojt 	struct eap_method *eap;
2012*a1157835SDaniel Fojt 
2013*a1157835SDaniel Fojt 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
2014*a1157835SDaniel Fojt 				    EAP_VENDOR_IETF, EAP_TYPE_TEAP, "TEAP");
2015*a1157835SDaniel Fojt 	if (!eap)
2016*a1157835SDaniel Fojt 		return -1;
2017*a1157835SDaniel Fojt 
2018*a1157835SDaniel Fojt 	eap->init = eap_teap_init;
2019*a1157835SDaniel Fojt 	eap->deinit = eap_teap_deinit;
2020*a1157835SDaniel Fojt 	eap->process = eap_teap_process;
2021*a1157835SDaniel Fojt 	eap->isKeyAvailable = eap_teap_isKeyAvailable;
2022*a1157835SDaniel Fojt 	eap->getKey = eap_teap_getKey;
2023*a1157835SDaniel Fojt 	eap->getSessionId = eap_teap_get_session_id;
2024*a1157835SDaniel Fojt 	eap->get_status = eap_teap_get_status;
2025*a1157835SDaniel Fojt #if 0 /* TODO */
2026*a1157835SDaniel Fojt 	eap->has_reauth_data = eap_teap_has_reauth_data;
2027*a1157835SDaniel Fojt 	eap->deinit_for_reauth = eap_teap_deinit_for_reauth;
2028*a1157835SDaniel Fojt 	eap->init_for_reauth = eap_teap_init_for_reauth;
2029*a1157835SDaniel Fojt #endif
2030*a1157835SDaniel Fojt 	eap->get_emsk = eap_teap_get_emsk;
2031*a1157835SDaniel Fojt 
2032*a1157835SDaniel Fojt 	return eap_peer_method_register(eap);
2033*a1157835SDaniel Fojt }
2034