13ff40c12SJohn Marino /*
23ff40c12SJohn Marino * hostapd / EAP-TLS (RFC 2716)
33ff40c12SJohn Marino * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
73ff40c12SJohn Marino */
83ff40c12SJohn Marino
93ff40c12SJohn Marino #include "includes.h"
103ff40c12SJohn Marino
113ff40c12SJohn Marino #include "common.h"
123ff40c12SJohn Marino #include "eap_i.h"
133ff40c12SJohn Marino #include "eap_tls_common.h"
143ff40c12SJohn Marino #include "crypto/tls.h"
153ff40c12SJohn Marino
163ff40c12SJohn Marino
173ff40c12SJohn Marino static void eap_tls_reset(struct eap_sm *sm, void *priv);
183ff40c12SJohn Marino
193ff40c12SJohn Marino
203ff40c12SJohn Marino struct eap_tls_data {
213ff40c12SJohn Marino struct eap_ssl_data ssl;
223ff40c12SJohn Marino enum { START, CONTINUE, SUCCESS, FAILURE } state;
233ff40c12SJohn Marino int established;
243ff40c12SJohn Marino u8 eap_type;
25*a1157835SDaniel Fojt int phase2;
263ff40c12SJohn Marino };
273ff40c12SJohn Marino
283ff40c12SJohn Marino
eap_tls_state_txt(int state)293ff40c12SJohn Marino static const char * eap_tls_state_txt(int state)
303ff40c12SJohn Marino {
313ff40c12SJohn Marino switch (state) {
323ff40c12SJohn Marino case START:
333ff40c12SJohn Marino return "START";
343ff40c12SJohn Marino case CONTINUE:
353ff40c12SJohn Marino return "CONTINUE";
363ff40c12SJohn Marino case SUCCESS:
373ff40c12SJohn Marino return "SUCCESS";
383ff40c12SJohn Marino case FAILURE:
393ff40c12SJohn Marino return "FAILURE";
403ff40c12SJohn Marino default:
413ff40c12SJohn Marino return "Unknown?!";
423ff40c12SJohn Marino }
433ff40c12SJohn Marino }
443ff40c12SJohn Marino
453ff40c12SJohn Marino
eap_tls_state(struct eap_tls_data * data,int state)463ff40c12SJohn Marino static void eap_tls_state(struct eap_tls_data *data, int state)
473ff40c12SJohn Marino {
483ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
493ff40c12SJohn Marino eap_tls_state_txt(data->state),
503ff40c12SJohn Marino eap_tls_state_txt(state));
513ff40c12SJohn Marino data->state = state;
52*a1157835SDaniel Fojt if (state == FAILURE)
53*a1157835SDaniel Fojt tls_connection_remove_session(data->ssl.conn);
54*a1157835SDaniel Fojt }
55*a1157835SDaniel Fojt
56*a1157835SDaniel Fojt
eap_tls_valid_session(struct eap_sm * sm,struct eap_tls_data * data)57*a1157835SDaniel Fojt static void eap_tls_valid_session(struct eap_sm *sm, struct eap_tls_data *data)
58*a1157835SDaniel Fojt {
59*a1157835SDaniel Fojt struct wpabuf *buf;
60*a1157835SDaniel Fojt
61*a1157835SDaniel Fojt if (!sm->tls_session_lifetime)
62*a1157835SDaniel Fojt return;
63*a1157835SDaniel Fojt
64*a1157835SDaniel Fojt buf = wpabuf_alloc(1);
65*a1157835SDaniel Fojt if (!buf)
66*a1157835SDaniel Fojt return;
67*a1157835SDaniel Fojt wpabuf_put_u8(buf, data->eap_type);
68*a1157835SDaniel Fojt tls_connection_set_success_data(data->ssl.conn, buf);
693ff40c12SJohn Marino }
703ff40c12SJohn Marino
713ff40c12SJohn Marino
eap_tls_init(struct eap_sm * sm)723ff40c12SJohn Marino static void * eap_tls_init(struct eap_sm *sm)
733ff40c12SJohn Marino {
743ff40c12SJohn Marino struct eap_tls_data *data;
753ff40c12SJohn Marino
763ff40c12SJohn Marino data = os_zalloc(sizeof(*data));
773ff40c12SJohn Marino if (data == NULL)
783ff40c12SJohn Marino return NULL;
793ff40c12SJohn Marino data->state = START;
803ff40c12SJohn Marino
81*a1157835SDaniel Fojt if (eap_server_tls_ssl_init(sm, &data->ssl, 1, EAP_TYPE_TLS)) {
823ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
833ff40c12SJohn Marino eap_tls_reset(sm, data);
843ff40c12SJohn Marino return NULL;
853ff40c12SJohn Marino }
863ff40c12SJohn Marino
873ff40c12SJohn Marino data->eap_type = EAP_TYPE_TLS;
883ff40c12SJohn Marino
89*a1157835SDaniel Fojt data->phase2 = sm->init_phase2;
90*a1157835SDaniel Fojt
913ff40c12SJohn Marino return data;
923ff40c12SJohn Marino }
933ff40c12SJohn Marino
943ff40c12SJohn Marino
953ff40c12SJohn Marino #ifdef EAP_SERVER_UNAUTH_TLS
eap_unauth_tls_init(struct eap_sm * sm)963ff40c12SJohn Marino static void * eap_unauth_tls_init(struct eap_sm *sm)
973ff40c12SJohn Marino {
983ff40c12SJohn Marino struct eap_tls_data *data;
993ff40c12SJohn Marino
1003ff40c12SJohn Marino data = os_zalloc(sizeof(*data));
1013ff40c12SJohn Marino if (data == NULL)
1023ff40c12SJohn Marino return NULL;
1033ff40c12SJohn Marino data->state = START;
1043ff40c12SJohn Marino
105*a1157835SDaniel Fojt if (eap_server_tls_ssl_init(sm, &data->ssl, 0, EAP_UNAUTH_TLS_TYPE)) {
1063ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
1073ff40c12SJohn Marino eap_tls_reset(sm, data);
1083ff40c12SJohn Marino return NULL;
1093ff40c12SJohn Marino }
1103ff40c12SJohn Marino
1113ff40c12SJohn Marino data->eap_type = EAP_UNAUTH_TLS_TYPE;
1123ff40c12SJohn Marino return data;
1133ff40c12SJohn Marino }
1143ff40c12SJohn Marino #endif /* EAP_SERVER_UNAUTH_TLS */
1153ff40c12SJohn Marino
1163ff40c12SJohn Marino
117*a1157835SDaniel Fojt #ifdef CONFIG_HS20
eap_wfa_unauth_tls_init(struct eap_sm * sm)118*a1157835SDaniel Fojt static void * eap_wfa_unauth_tls_init(struct eap_sm *sm)
119*a1157835SDaniel Fojt {
120*a1157835SDaniel Fojt struct eap_tls_data *data;
121*a1157835SDaniel Fojt
122*a1157835SDaniel Fojt data = os_zalloc(sizeof(*data));
123*a1157835SDaniel Fojt if (data == NULL)
124*a1157835SDaniel Fojt return NULL;
125*a1157835SDaniel Fojt data->state = START;
126*a1157835SDaniel Fojt
127*a1157835SDaniel Fojt if (eap_server_tls_ssl_init(sm, &data->ssl, 0,
128*a1157835SDaniel Fojt EAP_WFA_UNAUTH_TLS_TYPE)) {
129*a1157835SDaniel Fojt wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
130*a1157835SDaniel Fojt eap_tls_reset(sm, data);
131*a1157835SDaniel Fojt return NULL;
132*a1157835SDaniel Fojt }
133*a1157835SDaniel Fojt
134*a1157835SDaniel Fojt data->eap_type = EAP_WFA_UNAUTH_TLS_TYPE;
135*a1157835SDaniel Fojt return data;
136*a1157835SDaniel Fojt }
137*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
138*a1157835SDaniel Fojt
139*a1157835SDaniel Fojt
eap_tls_reset(struct eap_sm * sm,void * priv)1403ff40c12SJohn Marino static void eap_tls_reset(struct eap_sm *sm, void *priv)
1413ff40c12SJohn Marino {
1423ff40c12SJohn Marino struct eap_tls_data *data = priv;
1433ff40c12SJohn Marino if (data == NULL)
1443ff40c12SJohn Marino return;
1453ff40c12SJohn Marino eap_server_tls_ssl_deinit(sm, &data->ssl);
1463ff40c12SJohn Marino os_free(data);
1473ff40c12SJohn Marino }
1483ff40c12SJohn Marino
1493ff40c12SJohn Marino
eap_tls_build_start(struct eap_sm * sm,struct eap_tls_data * data,u8 id)1503ff40c12SJohn Marino static struct wpabuf * eap_tls_build_start(struct eap_sm *sm,
1513ff40c12SJohn Marino struct eap_tls_data *data, u8 id)
1523ff40c12SJohn Marino {
1533ff40c12SJohn Marino struct wpabuf *req;
1543ff40c12SJohn Marino
1553ff40c12SJohn Marino req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id);
1563ff40c12SJohn Marino if (req == NULL) {
1573ff40c12SJohn Marino wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
1583ff40c12SJohn Marino "request");
1593ff40c12SJohn Marino eap_tls_state(data, FAILURE);
1603ff40c12SJohn Marino return NULL;
1613ff40c12SJohn Marino }
1623ff40c12SJohn Marino
1633ff40c12SJohn Marino wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
1643ff40c12SJohn Marino
1653ff40c12SJohn Marino eap_tls_state(data, CONTINUE);
1663ff40c12SJohn Marino
1673ff40c12SJohn Marino return req;
1683ff40c12SJohn Marino }
1693ff40c12SJohn Marino
1703ff40c12SJohn Marino
eap_tls_buildReq(struct eap_sm * sm,void * priv,u8 id)1713ff40c12SJohn Marino static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
1723ff40c12SJohn Marino {
1733ff40c12SJohn Marino struct eap_tls_data *data = priv;
1743ff40c12SJohn Marino struct wpabuf *res;
1753ff40c12SJohn Marino
1763ff40c12SJohn Marino if (data->ssl.state == FRAG_ACK) {
1773ff40c12SJohn Marino return eap_server_tls_build_ack(id, data->eap_type, 0);
1783ff40c12SJohn Marino }
1793ff40c12SJohn Marino
1803ff40c12SJohn Marino if (data->ssl.state == WAIT_FRAG_ACK) {
1813ff40c12SJohn Marino res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0,
1823ff40c12SJohn Marino id);
1833ff40c12SJohn Marino goto check_established;
1843ff40c12SJohn Marino }
1853ff40c12SJohn Marino
1863ff40c12SJohn Marino switch (data->state) {
1873ff40c12SJohn Marino case START:
1883ff40c12SJohn Marino return eap_tls_build_start(sm, data, id);
1893ff40c12SJohn Marino case CONTINUE:
1903ff40c12SJohn Marino if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
1913ff40c12SJohn Marino data->established = 1;
1923ff40c12SJohn Marino break;
1933ff40c12SJohn Marino default:
1943ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
1953ff40c12SJohn Marino __func__, data->state);
1963ff40c12SJohn Marino return NULL;
1973ff40c12SJohn Marino }
1983ff40c12SJohn Marino
1993ff40c12SJohn Marino res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id);
2003ff40c12SJohn Marino
2013ff40c12SJohn Marino check_established:
2023ff40c12SJohn Marino if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
2033ff40c12SJohn Marino /* TLS handshake has been completed and there are no more
2043ff40c12SJohn Marino * fragments waiting to be sent out. */
2053ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
2063ff40c12SJohn Marino eap_tls_state(data, SUCCESS);
207*a1157835SDaniel Fojt eap_tls_valid_session(sm, data);
208*a1157835SDaniel Fojt if (sm->serial_num) {
209*a1157835SDaniel Fojt char user[128];
210*a1157835SDaniel Fojt int user_len;
211*a1157835SDaniel Fojt
212*a1157835SDaniel Fojt user_len = os_snprintf(user, sizeof(user), "cert-%s",
213*a1157835SDaniel Fojt sm->serial_num);
214*a1157835SDaniel Fojt if (eap_user_get(sm, (const u8 *) user, user_len,
215*a1157835SDaniel Fojt data->phase2) < 0)
216*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
217*a1157835SDaniel Fojt "EAP-TLS: No user entry found based on the serial number of the client certificate ");
218*a1157835SDaniel Fojt else
219*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
220*a1157835SDaniel Fojt "EAP-TLS: Updated user entry based on the serial number of the client certificate ");
221*a1157835SDaniel Fojt }
2223ff40c12SJohn Marino }
2233ff40c12SJohn Marino
2243ff40c12SJohn Marino return res;
2253ff40c12SJohn Marino }
2263ff40c12SJohn Marino
2273ff40c12SJohn Marino
eap_tls_check(struct eap_sm * sm,void * priv,struct wpabuf * respData)2283ff40c12SJohn Marino static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
2293ff40c12SJohn Marino struct wpabuf *respData)
2303ff40c12SJohn Marino {
2313ff40c12SJohn Marino struct eap_tls_data *data = priv;
2323ff40c12SJohn Marino const u8 *pos;
2333ff40c12SJohn Marino size_t len;
2343ff40c12SJohn Marino
2353ff40c12SJohn Marino if (data->eap_type == EAP_UNAUTH_TLS_TYPE)
2363ff40c12SJohn Marino pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
2373ff40c12SJohn Marino EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
2383ff40c12SJohn Marino &len);
239*a1157835SDaniel Fojt else if (data->eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
240*a1157835SDaniel Fojt pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
241*a1157835SDaniel Fojt EAP_VENDOR_WFA_UNAUTH_TLS, respData,
242*a1157835SDaniel Fojt &len);
2433ff40c12SJohn Marino else
2443ff40c12SJohn Marino pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type,
2453ff40c12SJohn Marino respData, &len);
2463ff40c12SJohn Marino if (pos == NULL || len < 1) {
2473ff40c12SJohn Marino wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
2483ff40c12SJohn Marino return TRUE;
2493ff40c12SJohn Marino }
2503ff40c12SJohn Marino
2513ff40c12SJohn Marino return FALSE;
2523ff40c12SJohn Marino }
2533ff40c12SJohn Marino
2543ff40c12SJohn Marino
eap_tls_process_msg(struct eap_sm * sm,void * priv,const struct wpabuf * respData)2553ff40c12SJohn Marino static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
2563ff40c12SJohn Marino const struct wpabuf *respData)
2573ff40c12SJohn Marino {
2583ff40c12SJohn Marino struct eap_tls_data *data = priv;
2593ff40c12SJohn Marino if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) {
2603ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
2613ff40c12SJohn Marino "handshake message");
2623ff40c12SJohn Marino return;
2633ff40c12SJohn Marino }
264*a1157835SDaniel Fojt if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
2653ff40c12SJohn Marino eap_tls_state(data, FAILURE);
266*a1157835SDaniel Fojt return;
267*a1157835SDaniel Fojt }
268*a1157835SDaniel Fojt
269*a1157835SDaniel Fojt if (data->ssl.tls_v13 &&
270*a1157835SDaniel Fojt tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
271*a1157835SDaniel Fojt struct wpabuf *plain, *encr;
272*a1157835SDaniel Fojt
273*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
274*a1157835SDaniel Fojt "EAP-TLS: Send empty application data to indicate end of exchange");
275*a1157835SDaniel Fojt /* FIX: This should be an empty application data based on
276*a1157835SDaniel Fojt * draft-ietf-emu-eap-tls13-05, but OpenSSL does not allow zero
277*a1157835SDaniel Fojt * length payload (SSL_write() documentation explicitly
278*a1157835SDaniel Fojt * describes this as not allowed), so work around that for now
279*a1157835SDaniel Fojt * by sending out a payload of one octet. Hopefully the draft
280*a1157835SDaniel Fojt * specification will change to allow this so that no crypto
281*a1157835SDaniel Fojt * library changes are needed. */
282*a1157835SDaniel Fojt plain = wpabuf_alloc(1);
283*a1157835SDaniel Fojt if (!plain)
284*a1157835SDaniel Fojt return;
285*a1157835SDaniel Fojt wpabuf_put_u8(plain, 0);
286*a1157835SDaniel Fojt encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
287*a1157835SDaniel Fojt wpabuf_free(plain);
288*a1157835SDaniel Fojt if (!encr)
289*a1157835SDaniel Fojt return;
290*a1157835SDaniel Fojt if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) {
291*a1157835SDaniel Fojt wpa_printf(MSG_INFO,
292*a1157835SDaniel Fojt "EAP-TLS: Failed to resize output buffer");
293*a1157835SDaniel Fojt wpabuf_free(encr);
294*a1157835SDaniel Fojt return;
295*a1157835SDaniel Fojt }
296*a1157835SDaniel Fojt wpabuf_put_buf(data->ssl.tls_out, encr);
297*a1157835SDaniel Fojt wpa_hexdump_buf(MSG_DEBUG,
298*a1157835SDaniel Fojt "EAP-TLS: Data appended to the message", encr);
299*a1157835SDaniel Fojt wpabuf_free(encr);
300*a1157835SDaniel Fojt }
3013ff40c12SJohn Marino }
3023ff40c12SJohn Marino
3033ff40c12SJohn Marino
eap_tls_process(struct eap_sm * sm,void * priv,struct wpabuf * respData)3043ff40c12SJohn Marino static void eap_tls_process(struct eap_sm *sm, void *priv,
3053ff40c12SJohn Marino struct wpabuf *respData)
3063ff40c12SJohn Marino {
3073ff40c12SJohn Marino struct eap_tls_data *data = priv;
308*a1157835SDaniel Fojt const struct wpabuf *buf;
309*a1157835SDaniel Fojt const u8 *pos;
310*a1157835SDaniel Fojt
3113ff40c12SJohn Marino if (eap_server_tls_process(sm, &data->ssl, respData, data,
3123ff40c12SJohn Marino data->eap_type, NULL, eap_tls_process_msg) <
313*a1157835SDaniel Fojt 0) {
3143ff40c12SJohn Marino eap_tls_state(data, FAILURE);
315*a1157835SDaniel Fojt return;
316*a1157835SDaniel Fojt }
317*a1157835SDaniel Fojt
318*a1157835SDaniel Fojt if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
319*a1157835SDaniel Fojt !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn))
320*a1157835SDaniel Fojt return;
321*a1157835SDaniel Fojt
322*a1157835SDaniel Fojt buf = tls_connection_get_success_data(data->ssl.conn);
323*a1157835SDaniel Fojt if (!buf || wpabuf_len(buf) < 1) {
324*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
325*a1157835SDaniel Fojt "EAP-TLS: No success data in resumed session - reject attempt");
326*a1157835SDaniel Fojt eap_tls_state(data, FAILURE);
327*a1157835SDaniel Fojt return;
328*a1157835SDaniel Fojt }
329*a1157835SDaniel Fojt
330*a1157835SDaniel Fojt pos = wpabuf_head(buf);
331*a1157835SDaniel Fojt if (*pos != data->eap_type) {
332*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
333*a1157835SDaniel Fojt "EAP-TLS: Resumed session for another EAP type (%u) - reject attempt",
334*a1157835SDaniel Fojt *pos);
335*a1157835SDaniel Fojt eap_tls_state(data, FAILURE);
336*a1157835SDaniel Fojt return;
337*a1157835SDaniel Fojt }
338*a1157835SDaniel Fojt
339*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
340*a1157835SDaniel Fojt "EAP-TLS: Resuming previous session");
341*a1157835SDaniel Fojt eap_tls_state(data, SUCCESS);
342*a1157835SDaniel Fojt tls_connection_set_success_data_resumed(data->ssl.conn);
343*a1157835SDaniel Fojt /* TODO: Cache serial number with session and update EAP user
344*a1157835SDaniel Fojt * information based on the cached serial number */
3453ff40c12SJohn Marino }
3463ff40c12SJohn Marino
3473ff40c12SJohn Marino
eap_tls_isDone(struct eap_sm * sm,void * priv)3483ff40c12SJohn Marino static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv)
3493ff40c12SJohn Marino {
3503ff40c12SJohn Marino struct eap_tls_data *data = priv;
3513ff40c12SJohn Marino return data->state == SUCCESS || data->state == FAILURE;
3523ff40c12SJohn Marino }
3533ff40c12SJohn Marino
3543ff40c12SJohn Marino
eap_tls_getKey(struct eap_sm * sm,void * priv,size_t * len)3553ff40c12SJohn Marino static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
3563ff40c12SJohn Marino {
3573ff40c12SJohn Marino struct eap_tls_data *data = priv;
3583ff40c12SJohn Marino u8 *eapKeyData;
359*a1157835SDaniel Fojt const char *label;
360*a1157835SDaniel Fojt const u8 eap_tls13_context[] = { EAP_TYPE_TLS };
361*a1157835SDaniel Fojt const u8 *context = NULL;
362*a1157835SDaniel Fojt size_t context_len = 0;
3633ff40c12SJohn Marino
3643ff40c12SJohn Marino if (data->state != SUCCESS)
3653ff40c12SJohn Marino return NULL;
3663ff40c12SJohn Marino
367*a1157835SDaniel Fojt if (data->ssl.tls_v13) {
368*a1157835SDaniel Fojt label = "EXPORTER_EAP_TLS_Key_Material";
369*a1157835SDaniel Fojt context = eap_tls13_context;
370*a1157835SDaniel Fojt context_len = 1;
371*a1157835SDaniel Fojt } else {
372*a1157835SDaniel Fojt label = "client EAP encryption";
373*a1157835SDaniel Fojt }
374*a1157835SDaniel Fojt eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
375*a1157835SDaniel Fojt context, context_len,
376*a1157835SDaniel Fojt EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
3773ff40c12SJohn Marino if (eapKeyData) {
3783ff40c12SJohn Marino *len = EAP_TLS_KEY_LEN;
3793ff40c12SJohn Marino wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key",
3803ff40c12SJohn Marino eapKeyData, EAP_TLS_KEY_LEN);
381*a1157835SDaniel Fojt os_memset(eapKeyData + EAP_TLS_KEY_LEN, 0, EAP_EMSK_LEN);
3823ff40c12SJohn Marino } else {
3833ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
3843ff40c12SJohn Marino }
3853ff40c12SJohn Marino
3863ff40c12SJohn Marino return eapKeyData;
3873ff40c12SJohn Marino }
3883ff40c12SJohn Marino
3893ff40c12SJohn Marino
eap_tls_get_emsk(struct eap_sm * sm,void * priv,size_t * len)3903ff40c12SJohn Marino static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
3913ff40c12SJohn Marino {
3923ff40c12SJohn Marino struct eap_tls_data *data = priv;
3933ff40c12SJohn Marino u8 *eapKeyData, *emsk;
394*a1157835SDaniel Fojt const char *label;
395*a1157835SDaniel Fojt const u8 eap_tls13_context[] = { EAP_TYPE_TLS };
396*a1157835SDaniel Fojt const u8 *context = NULL;
397*a1157835SDaniel Fojt size_t context_len = 0;
3983ff40c12SJohn Marino
3993ff40c12SJohn Marino if (data->state != SUCCESS)
4003ff40c12SJohn Marino return NULL;
4013ff40c12SJohn Marino
402*a1157835SDaniel Fojt if (data->ssl.tls_v13) {
403*a1157835SDaniel Fojt label = "EXPORTER_EAP_TLS_Key_Material";
404*a1157835SDaniel Fojt context = eap_tls13_context;
405*a1157835SDaniel Fojt context_len = 1;
406*a1157835SDaniel Fojt } else {
407*a1157835SDaniel Fojt label = "client EAP encryption";
408*a1157835SDaniel Fojt }
409*a1157835SDaniel Fojt eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, label,
410*a1157835SDaniel Fojt context, context_len,
4113ff40c12SJohn Marino EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
4123ff40c12SJohn Marino if (eapKeyData) {
4133ff40c12SJohn Marino emsk = os_malloc(EAP_EMSK_LEN);
4143ff40c12SJohn Marino if (emsk)
4153ff40c12SJohn Marino os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
4163ff40c12SJohn Marino EAP_EMSK_LEN);
417*a1157835SDaniel Fojt bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
4183ff40c12SJohn Marino } else
4193ff40c12SJohn Marino emsk = NULL;
4203ff40c12SJohn Marino
4213ff40c12SJohn Marino if (emsk) {
4223ff40c12SJohn Marino *len = EAP_EMSK_LEN;
4233ff40c12SJohn Marino wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
4243ff40c12SJohn Marino emsk, EAP_EMSK_LEN);
4253ff40c12SJohn Marino } else {
4263ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
4273ff40c12SJohn Marino }
4283ff40c12SJohn Marino
4293ff40c12SJohn Marino return emsk;
4303ff40c12SJohn Marino }
4313ff40c12SJohn Marino
4323ff40c12SJohn Marino
eap_tls_isSuccess(struct eap_sm * sm,void * priv)4333ff40c12SJohn Marino static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
4343ff40c12SJohn Marino {
4353ff40c12SJohn Marino struct eap_tls_data *data = priv;
4363ff40c12SJohn Marino return data->state == SUCCESS;
4373ff40c12SJohn Marino }
4383ff40c12SJohn Marino
4393ff40c12SJohn Marino
eap_tls_get_session_id(struct eap_sm * sm,void * priv,size_t * len)440*a1157835SDaniel Fojt static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
441*a1157835SDaniel Fojt {
442*a1157835SDaniel Fojt struct eap_tls_data *data = priv;
443*a1157835SDaniel Fojt
444*a1157835SDaniel Fojt if (data->state != SUCCESS)
445*a1157835SDaniel Fojt return NULL;
446*a1157835SDaniel Fojt
447*a1157835SDaniel Fojt return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TLS,
448*a1157835SDaniel Fojt len);
449*a1157835SDaniel Fojt }
450*a1157835SDaniel Fojt
451*a1157835SDaniel Fojt
eap_server_tls_register(void)4523ff40c12SJohn Marino int eap_server_tls_register(void)
4533ff40c12SJohn Marino {
4543ff40c12SJohn Marino struct eap_method *eap;
4553ff40c12SJohn Marino
4563ff40c12SJohn Marino eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
4573ff40c12SJohn Marino EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
4583ff40c12SJohn Marino if (eap == NULL)
4593ff40c12SJohn Marino return -1;
4603ff40c12SJohn Marino
4613ff40c12SJohn Marino eap->init = eap_tls_init;
4623ff40c12SJohn Marino eap->reset = eap_tls_reset;
4633ff40c12SJohn Marino eap->buildReq = eap_tls_buildReq;
4643ff40c12SJohn Marino eap->check = eap_tls_check;
4653ff40c12SJohn Marino eap->process = eap_tls_process;
4663ff40c12SJohn Marino eap->isDone = eap_tls_isDone;
4673ff40c12SJohn Marino eap->getKey = eap_tls_getKey;
4683ff40c12SJohn Marino eap->isSuccess = eap_tls_isSuccess;
4693ff40c12SJohn Marino eap->get_emsk = eap_tls_get_emsk;
470*a1157835SDaniel Fojt eap->getSessionId = eap_tls_get_session_id;
4713ff40c12SJohn Marino
472*a1157835SDaniel Fojt return eap_server_method_register(eap);
4733ff40c12SJohn Marino }
4743ff40c12SJohn Marino
4753ff40c12SJohn Marino
4763ff40c12SJohn Marino #ifdef EAP_SERVER_UNAUTH_TLS
eap_server_unauth_tls_register(void)4773ff40c12SJohn Marino int eap_server_unauth_tls_register(void)
4783ff40c12SJohn Marino {
4793ff40c12SJohn Marino struct eap_method *eap;
4803ff40c12SJohn Marino
4813ff40c12SJohn Marino eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
4823ff40c12SJohn Marino EAP_VENDOR_UNAUTH_TLS,
4833ff40c12SJohn Marino EAP_VENDOR_TYPE_UNAUTH_TLS,
4843ff40c12SJohn Marino "UNAUTH-TLS");
4853ff40c12SJohn Marino if (eap == NULL)
4863ff40c12SJohn Marino return -1;
4873ff40c12SJohn Marino
4883ff40c12SJohn Marino eap->init = eap_unauth_tls_init;
4893ff40c12SJohn Marino eap->reset = eap_tls_reset;
4903ff40c12SJohn Marino eap->buildReq = eap_tls_buildReq;
4913ff40c12SJohn Marino eap->check = eap_tls_check;
4923ff40c12SJohn Marino eap->process = eap_tls_process;
4933ff40c12SJohn Marino eap->isDone = eap_tls_isDone;
4943ff40c12SJohn Marino eap->getKey = eap_tls_getKey;
4953ff40c12SJohn Marino eap->isSuccess = eap_tls_isSuccess;
4963ff40c12SJohn Marino eap->get_emsk = eap_tls_get_emsk;
4973ff40c12SJohn Marino
498*a1157835SDaniel Fojt return eap_server_method_register(eap);
4993ff40c12SJohn Marino }
5003ff40c12SJohn Marino #endif /* EAP_SERVER_UNAUTH_TLS */
501*a1157835SDaniel Fojt
502*a1157835SDaniel Fojt
503*a1157835SDaniel Fojt #ifdef CONFIG_HS20
eap_server_wfa_unauth_tls_register(void)504*a1157835SDaniel Fojt int eap_server_wfa_unauth_tls_register(void)
505*a1157835SDaniel Fojt {
506*a1157835SDaniel Fojt struct eap_method *eap;
507*a1157835SDaniel Fojt
508*a1157835SDaniel Fojt eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
509*a1157835SDaniel Fojt EAP_VENDOR_WFA_NEW,
510*a1157835SDaniel Fojt EAP_VENDOR_WFA_UNAUTH_TLS,
511*a1157835SDaniel Fojt "WFA-UNAUTH-TLS");
512*a1157835SDaniel Fojt if (eap == NULL)
513*a1157835SDaniel Fojt return -1;
514*a1157835SDaniel Fojt
515*a1157835SDaniel Fojt eap->init = eap_wfa_unauth_tls_init;
516*a1157835SDaniel Fojt eap->reset = eap_tls_reset;
517*a1157835SDaniel Fojt eap->buildReq = eap_tls_buildReq;
518*a1157835SDaniel Fojt eap->check = eap_tls_check;
519*a1157835SDaniel Fojt eap->process = eap_tls_process;
520*a1157835SDaniel Fojt eap->isDone = eap_tls_isDone;
521*a1157835SDaniel Fojt eap->getKey = eap_tls_getKey;
522*a1157835SDaniel Fojt eap->isSuccess = eap_tls_isSuccess;
523*a1157835SDaniel Fojt eap->get_emsk = eap_tls_get_emsk;
524*a1157835SDaniel Fojt
525*a1157835SDaniel Fojt return eap_server_method_register(eap);
526*a1157835SDaniel Fojt }
527*a1157835SDaniel Fojt #endif /* CONFIG_HS20 */
528