xref: /freebsd/contrib/wpa/src/eap_server/eap_server_tls.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1e28a4053SRui Paulo /*
2*a90b9d01SCy Schubert  * hostapd / EAP-TLS (RFC 5216, RFC 9190)
3e28a4053SRui Paulo  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
4e28a4053SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
7e28a4053SRui Paulo  */
8e28a4053SRui Paulo 
9e28a4053SRui Paulo #include "includes.h"
10e28a4053SRui Paulo 
11e28a4053SRui Paulo #include "common.h"
12e28a4053SRui Paulo #include "eap_i.h"
13e28a4053SRui Paulo #include "eap_tls_common.h"
14e28a4053SRui Paulo #include "crypto/tls.h"
15e28a4053SRui Paulo 
16e28a4053SRui Paulo 
17e28a4053SRui Paulo static void eap_tls_reset(struct eap_sm *sm, void *priv);
18e28a4053SRui Paulo 
19e28a4053SRui Paulo 
20e28a4053SRui Paulo struct eap_tls_data {
21e28a4053SRui Paulo 	struct eap_ssl_data ssl;
22e28a4053SRui Paulo 	enum { START, CONTINUE, SUCCESS, FAILURE } state;
23e28a4053SRui Paulo 	int established;
24f05cddf9SRui Paulo 	u8 eap_type;
254bc52338SCy Schubert 	int phase2;
26e28a4053SRui Paulo };
27e28a4053SRui Paulo 
28e28a4053SRui Paulo 
eap_tls_state_txt(int state)29e28a4053SRui Paulo static const char * eap_tls_state_txt(int state)
30e28a4053SRui Paulo {
31e28a4053SRui Paulo 	switch (state) {
32e28a4053SRui Paulo 	case START:
33e28a4053SRui Paulo 		return "START";
34e28a4053SRui Paulo 	case CONTINUE:
35e28a4053SRui Paulo 		return "CONTINUE";
36e28a4053SRui Paulo 	case SUCCESS:
37e28a4053SRui Paulo 		return "SUCCESS";
38e28a4053SRui Paulo 	case FAILURE:
39e28a4053SRui Paulo 		return "FAILURE";
40e28a4053SRui Paulo 	default:
41e28a4053SRui Paulo 		return "Unknown?!";
42e28a4053SRui Paulo 	}
43e28a4053SRui Paulo }
44e28a4053SRui Paulo 
45e28a4053SRui Paulo 
eap_tls_state(struct eap_tls_data * data,int state)46e28a4053SRui Paulo static void eap_tls_state(struct eap_tls_data *data, int state)
47e28a4053SRui Paulo {
48e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
49e28a4053SRui Paulo 		   eap_tls_state_txt(data->state),
50e28a4053SRui Paulo 		   eap_tls_state_txt(state));
51e28a4053SRui Paulo 	data->state = state;
52325151a3SRui Paulo 	if (state == FAILURE)
53325151a3SRui Paulo 		tls_connection_remove_session(data->ssl.conn);
54325151a3SRui Paulo }
55325151a3SRui Paulo 
56325151a3SRui Paulo 
eap_tls_valid_session(struct eap_sm * sm,struct eap_tls_data * data)57325151a3SRui Paulo static void eap_tls_valid_session(struct eap_sm *sm, struct eap_tls_data *data)
58325151a3SRui Paulo {
59325151a3SRui Paulo 	struct wpabuf *buf;
60325151a3SRui Paulo 
61c1d255d3SCy Schubert 	if (!sm->cfg->tls_session_lifetime)
62325151a3SRui Paulo 		return;
63325151a3SRui Paulo 
64325151a3SRui Paulo 	buf = wpabuf_alloc(1);
65325151a3SRui Paulo 	if (!buf)
66325151a3SRui Paulo 		return;
67325151a3SRui Paulo 	wpabuf_put_u8(buf, data->eap_type);
68325151a3SRui Paulo 	tls_connection_set_success_data(data->ssl.conn, buf);
69e28a4053SRui Paulo }
70e28a4053SRui Paulo 
71e28a4053SRui Paulo 
eap_tls_init(struct eap_sm * sm)72e28a4053SRui Paulo static void * eap_tls_init(struct eap_sm *sm)
73e28a4053SRui Paulo {
74e28a4053SRui Paulo 	struct eap_tls_data *data;
75e28a4053SRui Paulo 
76e28a4053SRui Paulo 	data = os_zalloc(sizeof(*data));
77e28a4053SRui Paulo 	if (data == NULL)
78e28a4053SRui Paulo 		return NULL;
79e28a4053SRui Paulo 	data->state = START;
80e28a4053SRui Paulo 
81325151a3SRui Paulo 	if (eap_server_tls_ssl_init(sm, &data->ssl, 1, EAP_TYPE_TLS)) {
82e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
83e28a4053SRui Paulo 		eap_tls_reset(sm, data);
84e28a4053SRui Paulo 		return NULL;
85e28a4053SRui Paulo 	}
86e28a4053SRui Paulo 
87f05cddf9SRui Paulo 	data->eap_type = EAP_TYPE_TLS;
88f05cddf9SRui Paulo 
894bc52338SCy Schubert 	data->phase2 = sm->init_phase2;
904bc52338SCy Schubert 
91e28a4053SRui Paulo 	return data;
92e28a4053SRui Paulo }
93e28a4053SRui Paulo 
94e28a4053SRui Paulo 
95f05cddf9SRui Paulo #ifdef EAP_SERVER_UNAUTH_TLS
eap_unauth_tls_init(struct eap_sm * sm)96f05cddf9SRui Paulo static void * eap_unauth_tls_init(struct eap_sm *sm)
97f05cddf9SRui Paulo {
98f05cddf9SRui Paulo 	struct eap_tls_data *data;
99f05cddf9SRui Paulo 
100f05cddf9SRui Paulo 	data = os_zalloc(sizeof(*data));
101f05cddf9SRui Paulo 	if (data == NULL)
102f05cddf9SRui Paulo 		return NULL;
103f05cddf9SRui Paulo 	data->state = START;
104f05cddf9SRui Paulo 
105325151a3SRui Paulo 	if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_UNAUTH_TLS_TYPE)) {
106f05cddf9SRui Paulo 		wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
107f05cddf9SRui Paulo 		eap_tls_reset(sm, data);
108f05cddf9SRui Paulo 		return NULL;
109f05cddf9SRui Paulo 	}
110f05cddf9SRui Paulo 
111f05cddf9SRui Paulo 	data->eap_type = EAP_UNAUTH_TLS_TYPE;
112f05cddf9SRui Paulo 	return data;
113f05cddf9SRui Paulo }
114f05cddf9SRui Paulo #endif /* EAP_SERVER_UNAUTH_TLS */
115f05cddf9SRui Paulo 
116f05cddf9SRui Paulo 
1175b9c547cSRui Paulo #ifdef CONFIG_HS20
eap_wfa_unauth_tls_init(struct eap_sm * sm)1185b9c547cSRui Paulo static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
1195b9c547cSRui Paulo {
1205b9c547cSRui Paulo 	struct eap_tls_data *data;
1215b9c547cSRui Paulo 
1225b9c547cSRui Paulo 	data = os_zalloc(sizeof(*data));
1235b9c547cSRui Paulo 	if (data == NULL)
1245b9c547cSRui Paulo 		return NULL;
1255b9c547cSRui Paulo 	data->state = START;
1265b9c547cSRui Paulo 
127325151a3SRui Paulo 	if (eap_server_tls_ssl_init(sm, &data->ssl, 0,
128325151a3SRui Paulo 				    EAP_WFA_UNAUTH_TLS_TYPE)) {
1295b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
1305b9c547cSRui Paulo 		eap_tls_reset(sm, data);
1315b9c547cSRui Paulo 		return NULL;
1325b9c547cSRui Paulo 	}
1335b9c547cSRui Paulo 
1345b9c547cSRui Paulo 	data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE;
1355b9c547cSRui Paulo 	return data;
1365b9c547cSRui Paulo }
1375b9c547cSRui Paulo #endif /* CONFIG_HS20 */
1385b9c547cSRui Paulo 
1395b9c547cSRui Paulo 
eap_tls_reset(struct eap_sm * sm,void * priv)140e28a4053SRui Paulo static void eap_tls_reset(struct eap_sm *sm, void *priv)
141e28a4053SRui Paulo {
142e28a4053SRui Paulo 	struct eap_tls_data *data = priv;
143e28a4053SRui Paulo 	if (data == NULL)
144e28a4053SRui Paulo 		return;
145e28a4053SRui Paulo 	eap_server_tls_ssl_deinit(sm, &data->ssl);
146e28a4053SRui Paulo 	os_free(data);
147e28a4053SRui Paulo }
148e28a4053SRui Paulo 
149e28a4053SRui Paulo 
eap_tls_build_start(struct eap_sm * sm,struct eap_tls_data * data,u8 id)150e28a4053SRui Paulo static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
151e28a4053SRui Paulo 					   struct eap_tls_data *data, u8 id)
152e28a4053SRui Paulo {
153e28a4053SRui Paulo 	struct wpabuf *req;
154e28a4053SRui Paulo 
155f05cddf9SRui Paulo 	req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id);
156e28a4053SRui Paulo 	if (req == NULL) {
157e28a4053SRui Paulo 		wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
158e28a4053SRui Paulo 			   "request");
159e28a4053SRui Paulo 		eap_tls_state(data, FAILURE);
160e28a4053SRui Paulo 		return NULL;
161e28a4053SRui Paulo 	}
162e28a4053SRui Paulo 
163e28a4053SRui Paulo 	wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
164e28a4053SRui Paulo 
165e28a4053SRui Paulo 	eap_tls_state(data, CONTINUE);
166e28a4053SRui Paulo 
167e28a4053SRui Paulo 	return req;
168e28a4053SRui Paulo }
169e28a4053SRui Paulo 
170e28a4053SRui Paulo 
eap_tls_buildReq(struct eap_sm * sm,void * priv,u8 id)171e28a4053SRui Paulo static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
172e28a4053SRui Paulo {
173e28a4053SRui Paulo 	struct eap_tls_data *data = priv;
174e28a4053SRui Paulo 	struct wpabuf *res;
175e28a4053SRui Paulo 
176e28a4053SRui Paulo 	if (data->ssl.state == FRAG_ACK) {
177f05cddf9SRui Paulo 		return eap_server_tls_build_ack(id, data->eap_type, 0);
178e28a4053SRui Paulo 	}
179e28a4053SRui Paulo 
180e28a4053SRui Paulo 	if (data->ssl.state == WAIT_FRAG_ACK) {
181f05cddf9SRui Paulo 		res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0,
182e28a4053SRui Paulo 					       id);
183e28a4053SRui Paulo 		goto check_established;
184e28a4053SRui Paulo 	}
185e28a4053SRui Paulo 
186e28a4053SRui Paulo 	switch (data->state) {
187e28a4053SRui Paulo 	case START:
188e28a4053SRui Paulo 		return eap_tls_build_start(sm, data, id);
189e28a4053SRui Paulo 	case CONTINUE:
190c1d255d3SCy Schubert 		if (tls_connection_established(sm->cfg->ssl_ctx,
191c1d255d3SCy Schubert 					       data->ssl.conn))
192e28a4053SRui Paulo 			data->established = 1;
193e28a4053SRui Paulo 		break;
194e28a4053SRui Paulo 	default:
195e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
196e28a4053SRui Paulo 			   __func__, data->state);
197e28a4053SRui Paulo 		return NULL;
198e28a4053SRui Paulo 	}
199e28a4053SRui Paulo 
200f05cddf9SRui Paulo 	res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id);
201e28a4053SRui Paulo 
202e28a4053SRui Paulo check_established:
203e28a4053SRui Paulo 	if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
204e28a4053SRui Paulo 		/* TLS handshake has been completed and there are no more
205e28a4053SRui Paulo 		 * fragments waiting to be sent out. */
206e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
207e28a4053SRui Paulo 		eap_tls_state(data, SUCCESS);
208325151a3SRui Paulo 		eap_tls_valid_session(sm, data);
2094bc52338SCy Schubert 		if (sm->serial_num) {
2104bc52338SCy Schubert 			char user[128];
2114bc52338SCy Schubert 			int user_len;
2124bc52338SCy Schubert 
2134bc52338SCy Schubert 			user_len = os_snprintf(user, sizeof(user), "cert-%s",
2144bc52338SCy Schubert 					       sm->serial_num);
2154bc52338SCy Schubert 			if (eap_user_get(sm, (const u8 *) user, user_len,
2164bc52338SCy Schubert 					 data->phase2) < 0)
2174bc52338SCy Schubert 				wpa_printf(MSG_DEBUG,
2184bc52338SCy Schubert 					   "EAP-TLS: No user entry found based on the serial number of the client certificate ");
2194bc52338SCy Schubert 			else
2204bc52338SCy Schubert 				wpa_printf(MSG_DEBUG,
2214bc52338SCy Schubert 					   "EAP-TLS: Updated user entry based on the serial number of the client certificate ");
2224bc52338SCy Schubert 		}
223e28a4053SRui Paulo 	}
224e28a4053SRui Paulo 
225e28a4053SRui Paulo 	return res;
226e28a4053SRui Paulo }
227e28a4053SRui Paulo 
228e28a4053SRui Paulo 
eap_tls_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)229c1d255d3SCy Schubert static bool eap_tls_check(struct eap_sm *sm, void *priv,
230e28a4053SRui Paulo 			  struct wpabuf *respData)
231e28a4053SRui Paulo {
232f05cddf9SRui Paulo 	struct eap_tls_data *data = priv;
233e28a4053SRui Paulo 	const u8 *pos;
234e28a4053SRui Paulo 	size_t len;
235e28a4053SRui Paulo 
236f05cddf9SRui Paulo 	if (data->eap_type == EAP_UNAUTH_TLS_TYPE)
237f05cddf9SRui Paulo 		pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
238f05cddf9SRui Paulo 				       EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
239f05cddf9SRui Paulo 				       &len);
2405b9c547cSRui Paulo 	else if (data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
2415b9c547cSRui Paulo 		pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
2425b9c547cSRui Paulo 				       EAP_VENDOR_WFA_UNAUTH_TLS, respData,
2435b9c547cSRui Paulo 				       &len);
244f05cddf9SRui Paulo 	else
245f05cddf9SRui Paulo 		pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type,
246f05cddf9SRui Paulo 				       respData, &len);
247e28a4053SRui Paulo 	if (pos == NULL || len < 1) {
248e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
249c1d255d3SCy Schubert 		return true;
250e28a4053SRui Paulo 	}
251e28a4053SRui Paulo 
252c1d255d3SCy Schubert 	return false;
253e28a4053SRui Paulo }
254e28a4053SRui Paulo 
255e28a4053SRui Paulo 
eap_tls_process_msg(struct eap_sm * sm,void * priv,const struct wpabuf * respData)256e28a4053SRui Paulo static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
257e28a4053SRui Paulo 				const struct wpabuf *respData)
258e28a4053SRui Paulo {
259e28a4053SRui Paulo 	struct eap_tls_data *data = priv;
260e28a4053SRui Paulo 	if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) {
261e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
262e28a4053SRui Paulo 			   "handshake message");
263e28a4053SRui Paulo 		return;
264e28a4053SRui Paulo 	}
265206b73d0SCy Schubert 	if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
266e28a4053SRui Paulo 		eap_tls_state(data, FAILURE);
267206b73d0SCy Schubert 		return;
268206b73d0SCy Schubert 	}
269e28a4053SRui Paulo }
270e28a4053SRui Paulo 
271e28a4053SRui Paulo 
eap_tls_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)272e28a4053SRui Paulo static void eap_tls_process(struct eap_sm *sm, void *priv,
273e28a4053SRui Paulo 			    struct wpabuf *respData)
274e28a4053SRui Paulo {
275e28a4053SRui Paulo 	struct eap_tls_data *data = priv;
276325151a3SRui Paulo 	const struct wpabuf *buf;
277325151a3SRui Paulo 	const u8 *pos;
278325151a3SRui Paulo 
279e28a4053SRui Paulo 	if (eap_server_tls_process(sm, &data->ssl, respData, data,
280f05cddf9SRui Paulo 				   data->eap_type, NULL, eap_tls_process_msg) <
281325151a3SRui Paulo 	    0) {
282e28a4053SRui Paulo 		eap_tls_state(data, FAILURE);
283325151a3SRui Paulo 		return;
284325151a3SRui Paulo 	}
285325151a3SRui Paulo 
286c1d255d3SCy Schubert 	if (!tls_connection_established(sm->cfg->ssl_ctx, data->ssl.conn) ||
287c1d255d3SCy Schubert 	    !tls_connection_resumed(sm->cfg->ssl_ctx, data->ssl.conn))
288325151a3SRui Paulo 		return;
289325151a3SRui Paulo 
290325151a3SRui Paulo 	buf = tls_connection_get_success_data(data->ssl.conn);
291325151a3SRui Paulo 	if (!buf || wpabuf_len(buf) < 1) {
292325151a3SRui Paulo 		wpa_printf(MSG_DEBUG,
293325151a3SRui Paulo 			   "EAP-TLS: No success data in resumed session - reject attempt");
294325151a3SRui Paulo 		eap_tls_state(data, FAILURE);
295325151a3SRui Paulo 		return;
296325151a3SRui Paulo 	}
297325151a3SRui Paulo 
298325151a3SRui Paulo 	pos = wpabuf_head(buf);
299325151a3SRui Paulo 	if (*pos != data->eap_type) {
300325151a3SRui Paulo 		wpa_printf(MSG_DEBUG,
301325151a3SRui Paulo 			   "EAP-TLS: Resumed session for another EAP type (%u) - reject attempt",
302325151a3SRui Paulo 			   *pos);
303325151a3SRui Paulo 		eap_tls_state(data, FAILURE);
304325151a3SRui Paulo 		return;
305325151a3SRui Paulo 	}
306325151a3SRui Paulo 
307325151a3SRui Paulo 	wpa_printf(MSG_DEBUG,
308325151a3SRui Paulo 		   "EAP-TLS: Resuming previous session");
309*a90b9d01SCy Schubert 
310*a90b9d01SCy Schubert 	if (data->ssl.tls_v13 && data->ssl.tls_out) {
311*a90b9d01SCy Schubert 		wpa_hexdump_buf(MSG_DEBUG,
312*a90b9d01SCy Schubert 				"EAP-TLS: Additional data to be sent for TLS 1.3",
313*a90b9d01SCy Schubert 				data->ssl.tls_out);
314*a90b9d01SCy Schubert 		return;
315*a90b9d01SCy Schubert 	}
316*a90b9d01SCy Schubert 
317325151a3SRui Paulo 	eap_tls_state(data, SUCCESS);
318325151a3SRui Paulo 	tls_connection_set_success_data_resumed(data->ssl.conn);
3194bc52338SCy Schubert 	/* TODO: Cache serial number with session and update EAP user
3204bc52338SCy Schubert 	 * information based on the cached serial number */
321e28a4053SRui Paulo }
322e28a4053SRui Paulo 
323e28a4053SRui Paulo 
eap_tls_isDone(struct eap_sm * sm,void * priv)324c1d255d3SCy Schubert static bool eap_tls_isDone(struct eap_sm *sm, void *priv)
325e28a4053SRui Paulo {
326e28a4053SRui Paulo 	struct eap_tls_data *data = priv;
327e28a4053SRui Paulo 	return data->state == SUCCESS || data->state == FAILURE;
328e28a4053SRui Paulo }
329e28a4053SRui Paulo 
330e28a4053SRui Paulo 
eap_tls_getKey(struct eap_sm * sm,void * priv,size_t * len)331e28a4053SRui Paulo static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
332e28a4053SRui Paulo {
333e28a4053SRui Paulo 	struct eap_tls_data *data = priv;
334e28a4053SRui Paulo 	u8 *eapKeyData;
33585732ac8SCy Schubert 	const char *label;
336206b73d0SCy Schubert 	const u8 eap_tls13_context[] = { EAP_TYPE_TLS };
337206b73d0SCy Schubert 	const u8 *context = NULL;
338206b73d0SCy Schubert 	size_t context_len = 0;
339e28a4053SRui Paulo 
340e28a4053SRui Paulo 	if (data->state != SUCCESS)
341e28a4053SRui Paulo 		return NULL;
342e28a4053SRui Paulo 
343206b73d0SCy Schubert 	if (data->ssl.tls_v13) {
34485732ac8SCy Schubert 		label = "EXPORTER_EAP_TLS_Key_Material";
345206b73d0SCy Schubert 		context = eap_tls13_context;
346206b73d0SCy Schubert 		context_len = 1;
347206b73d0SCy Schubert 	} else {
34885732ac8SCy Schubert 		label = "client EAP encryption";
349206b73d0SCy Schubert 	}
35085732ac8SCy Schubert 	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
351206b73d0SCy Schubert 					       context, context_len,
35285732ac8SCy Schubert 					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
353e28a4053SRui Paulo 	if (eapKeyData) {
354e28a4053SRui Paulo 		*len = EAP_TLS_KEY_LEN;
355e28a4053SRui Paulo 		wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
356e28a4053SRui Paulo 			    eapKeyData, EAP_TLS_KEY_LEN);
35785732ac8SCy Schubert 		os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
358e28a4053SRui Paulo 	} else {
359e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
360e28a4053SRui Paulo 	}
361e28a4053SRui Paulo 
362e28a4053SRui Paulo 	return eapKeyData;
363e28a4053SRui Paulo }
364e28a4053SRui Paulo 
365e28a4053SRui Paulo 
eap_tls_get_emsk(struct eap_sm * sm,void * priv,size_t * len)366e28a4053SRui Paulo static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
367e28a4053SRui Paulo {
368e28a4053SRui Paulo 	struct eap_tls_data *data = priv;
369e28a4053SRui Paulo 	u8 *eapKeyData, *emsk;
37085732ac8SCy Schubert 	const char *label;
371206b73d0SCy Schubert 	const u8 eap_tls13_context[] = { EAP_TYPE_TLS };
372206b73d0SCy Schubert 	const u8 *context = NULL;
373206b73d0SCy Schubert 	size_t context_len = 0;
374e28a4053SRui Paulo 
375e28a4053SRui Paulo 	if (data->state != SUCCESS)
376e28a4053SRui Paulo 		return NULL;
377e28a4053SRui Paulo 
378206b73d0SCy Schubert 	if (data->ssl.tls_v13) {
37985732ac8SCy Schubert 		label = "EXPORTER_EAP_TLS_Key_Material";
380206b73d0SCy Schubert 		context = eap_tls13_context;
381206b73d0SCy Schubert 		context_len = 1;
382206b73d0SCy Schubert 	} else {
38385732ac8SCy Schubert 		label = "client EAP encryption";
384206b73d0SCy Schubert 	}
38585732ac8SCy Schubert 	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
386206b73d0SCy Schubert 					       context, context_len,
387e28a4053SRui Paulo 					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
388e28a4053SRui Paulo 	if (eapKeyData) {
389e28a4053SRui Paulo 		emsk = os_malloc(EAP_EMSK_LEN);
390e28a4053SRui Paulo 		if (emsk)
391e28a4053SRui Paulo 			os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
392e28a4053SRui Paulo 				  EAP_EMSK_LEN);
3935b9c547cSRui Paulo 		bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
394e28a4053SRui Paulo 	} else
395e28a4053SRui Paulo 		emsk = NULL;
396e28a4053SRui Paulo 
397e28a4053SRui Paulo 	if (emsk) {
398e28a4053SRui Paulo 		*len = EAP_EMSK_LEN;
399e28a4053SRui Paulo 		wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
400e28a4053SRui Paulo 			    emsk, EAP_EMSK_LEN);
401e28a4053SRui Paulo 	} else {
402e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
403e28a4053SRui Paulo 	}
404e28a4053SRui Paulo 
405e28a4053SRui Paulo 	return emsk;
406e28a4053SRui Paulo }
407e28a4053SRui Paulo 
408e28a4053SRui Paulo 
eap_tls_isSuccess(struct eap_sm * sm,void * priv)409c1d255d3SCy Schubert static bool eap_tls_isSuccess(struct eap_sm *sm, void *priv)
410e28a4053SRui Paulo {
411e28a4053SRui Paulo 	struct eap_tls_data *data = priv;
412e28a4053SRui Paulo 	return data->state == SUCCESS;
413e28a4053SRui Paulo }
414e28a4053SRui Paulo 
415e28a4053SRui Paulo 
eap_tls_get_session_id(struct eap_sm * sm,void * priv,size_t * len)4165b9c547cSRui Paulo static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
4175b9c547cSRui Paulo {
4185b9c547cSRui Paulo 	struct eap_tls_data *data = priv;
4195b9c547cSRui Paulo 
4205b9c547cSRui Paulo 	if (data->state != SUCCESS)
4215b9c547cSRui Paulo 		return NULL;
4225b9c547cSRui Paulo 
4235b9c547cSRui Paulo 	return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TLS,
4245b9c547cSRui Paulo 						len);
4255b9c547cSRui Paulo }
4265b9c547cSRui Paulo 
4275b9c547cSRui Paulo 
eap_server_tls_register(void)428e28a4053SRui Paulo int eap_server_tls_register(void)
429e28a4053SRui Paulo {
430e28a4053SRui Paulo 	struct eap_method *eap;
431e28a4053SRui Paulo 
432e28a4053SRui Paulo 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
433e28a4053SRui Paulo 				      EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
434e28a4053SRui Paulo 	if (eap == NULL)
435e28a4053SRui Paulo 		return -1;
436e28a4053SRui Paulo 
437e28a4053SRui Paulo 	eap->init = eap_tls_init;
438e28a4053SRui Paulo 	eap->reset = eap_tls_reset;
439e28a4053SRui Paulo 	eap->buildReq = eap_tls_buildReq;
440e28a4053SRui Paulo 	eap->check = eap_tls_check;
441e28a4053SRui Paulo 	eap->process = eap_tls_process;
442e28a4053SRui Paulo 	eap->isDone = eap_tls_isDone;
443e28a4053SRui Paulo 	eap->getKey = eap_tls_getKey;
444e28a4053SRui Paulo 	eap->isSuccess = eap_tls_isSuccess;
445e28a4053SRui Paulo 	eap->get_emsk = eap_tls_get_emsk;
4465b9c547cSRui Paulo 	eap->getSessionId = eap_tls_get_session_id;
447e28a4053SRui Paulo 
448780fb4a2SCy Schubert 	return eap_server_method_register(eap);
449e28a4053SRui Paulo }
450f05cddf9SRui Paulo 
451f05cddf9SRui Paulo 
452f05cddf9SRui Paulo #ifdef EAP_SERVER_UNAUTH_TLS
eap_server_unauth_tls_register(void)453f05cddf9SRui Paulo int eap_server_unauth_tls_register(void)
454f05cddf9SRui Paulo {
455f05cddf9SRui Paulo 	struct eap_method *eap;
456f05cddf9SRui Paulo 
457f05cddf9SRui Paulo 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
458f05cddf9SRui Paulo 				      EAP_VENDOR_UNAUTH_TLS,
459f05cddf9SRui Paulo 				      EAP_VENDOR_TYPE_UNAUTH_TLS,
460f05cddf9SRui Paulo 				      "UNAUTH-TLS");
461f05cddf9SRui Paulo 	if (eap == NULL)
462f05cddf9SRui Paulo 		return -1;
463f05cddf9SRui Paulo 
464f05cddf9SRui Paulo 	eap->init = eap_unauth_tls_init;
465f05cddf9SRui Paulo 	eap->reset = eap_tls_reset;
466f05cddf9SRui Paulo 	eap->buildReq = eap_tls_buildReq;
467f05cddf9SRui Paulo 	eap->check = eap_tls_check;
468f05cddf9SRui Paulo 	eap->process = eap_tls_process;
469f05cddf9SRui Paulo 	eap->isDone = eap_tls_isDone;
470f05cddf9SRui Paulo 	eap->getKey = eap_tls_getKey;
471f05cddf9SRui Paulo 	eap->isSuccess = eap_tls_isSuccess;
472f05cddf9SRui Paulo 	eap->get_emsk = eap_tls_get_emsk;
473f05cddf9SRui Paulo 
474780fb4a2SCy Schubert 	return eap_server_method_register(eap);
475f05cddf9SRui Paulo }
476f05cddf9SRui Paulo #endif /* EAP_SERVER_UNAUTH_TLS */
4775b9c547cSRui Paulo 
4785b9c547cSRui Paulo 
4795b9c547cSRui Paulo #ifdef CONFIG_HS20
eap_server_wfa_unauth_tls_register(void)4805b9c547cSRui Paulo int eap_server_wfa_unauth_tls_register(void)
4815b9c547cSRui Paulo {
4825b9c547cSRui Paulo 	struct eap_method *eap;
4835b9c547cSRui Paulo 
4845b9c547cSRui Paulo 	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
4855b9c547cSRui Paulo 				      EAP_VENDOR_WFA_NEW,
4865b9c547cSRui Paulo 				      EAP_VENDOR_WFA_UNAUTH_TLS,
4875b9c547cSRui Paulo 				      "WFA-UNAUTH-TLS");
4885b9c547cSRui Paulo 	if (eap == NULL)
4895b9c547cSRui Paulo 		return -1;
4905b9c547cSRui Paulo 
4915b9c547cSRui Paulo 	eap->init = eap_wfa_unauth_tls_init;
4925b9c547cSRui Paulo 	eap->reset = eap_tls_reset;
4935b9c547cSRui Paulo 	eap->buildReq = eap_tls_buildReq;
4945b9c547cSRui Paulo 	eap->check = eap_tls_check;
4955b9c547cSRui Paulo 	eap->process = eap_tls_process;
4965b9c547cSRui Paulo 	eap->isDone = eap_tls_isDone;
4975b9c547cSRui Paulo 	eap->getKey = eap_tls_getKey;
4985b9c547cSRui Paulo 	eap->isSuccess = eap_tls_isSuccess;
4995b9c547cSRui Paulo 	eap->get_emsk = eap_tls_get_emsk;
5005b9c547cSRui Paulo 
501780fb4a2SCy Schubert 	return eap_server_method_register(eap);
5025b9c547cSRui Paulo }
5035b9c547cSRui Paulo #endif /* CONFIG_HS20 */
504