13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * EAP-TLS/PEAP/TTLS/FAST server common functions
33ff40c12SJohn Marino  * Copyright (c) 2004-2009, 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 "crypto/sha1.h"
133ff40c12SJohn Marino #include "crypto/tls.h"
143ff40c12SJohn Marino #include "eap_i.h"
153ff40c12SJohn Marino #include "eap_tls_common.h"
163ff40c12SJohn Marino 
173ff40c12SJohn Marino 
183ff40c12SJohn Marino static void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
193ff40c12SJohn Marino 
203ff40c12SJohn Marino 
eap_tls_msg_alloc(EapType type,size_t payload_len,u8 code,u8 identifier)213ff40c12SJohn Marino struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
223ff40c12SJohn Marino 				  u8 code, u8 identifier)
233ff40c12SJohn Marino {
243ff40c12SJohn Marino 	if (type == EAP_UNAUTH_TLS_TYPE)
253ff40c12SJohn Marino 		return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
263ff40c12SJohn Marino 				     EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
273ff40c12SJohn Marino 				     code, identifier);
28*a1157835SDaniel Fojt 	else if (type == EAP_WFA_UNAUTH_TLS_TYPE)
29*a1157835SDaniel Fojt 		return eap_msg_alloc(EAP_VENDOR_WFA_NEW,
30*a1157835SDaniel Fojt 				     EAP_VENDOR_WFA_UNAUTH_TLS, payload_len,
31*a1157835SDaniel Fojt 				     code, identifier);
323ff40c12SJohn Marino 	return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
333ff40c12SJohn Marino 			     identifier);
343ff40c12SJohn Marino }
353ff40c12SJohn Marino 
363ff40c12SJohn Marino 
37*a1157835SDaniel Fojt #ifdef CONFIG_TLS_INTERNAL
eap_server_tls_log_cb(void * ctx,const char * msg)38*a1157835SDaniel Fojt static void eap_server_tls_log_cb(void *ctx, const char *msg)
393ff40c12SJohn Marino {
40*a1157835SDaniel Fojt 	struct eap_sm *sm = ctx;
41*a1157835SDaniel Fojt 	eap_log_msg(sm, "TLS: %s", msg);
42*a1157835SDaniel Fojt }
43*a1157835SDaniel Fojt #endif /* CONFIG_TLS_INTERNAL */
44*a1157835SDaniel Fojt 
45*a1157835SDaniel Fojt 
eap_server_tls_ssl_init(struct eap_sm * sm,struct eap_ssl_data * data,int verify_peer,int eap_type)46*a1157835SDaniel Fojt int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
47*a1157835SDaniel Fojt 			    int verify_peer, int eap_type)
48*a1157835SDaniel Fojt {
49*a1157835SDaniel Fojt 	u8 session_ctx[8];
50*a1157835SDaniel Fojt 	unsigned int flags = sm->tls_flags;
51*a1157835SDaniel Fojt 
523ff40c12SJohn Marino 	if (sm->ssl_ctx == NULL) {
533ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "TLS context not initialized - cannot use TLS-based EAP method");
543ff40c12SJohn Marino 		return -1;
553ff40c12SJohn Marino 	}
563ff40c12SJohn Marino 
573ff40c12SJohn Marino 	data->eap = sm;
583ff40c12SJohn Marino 	data->phase2 = sm->init_phase2;
593ff40c12SJohn Marino 
603ff40c12SJohn Marino 	data->conn = tls_connection_init(sm->ssl_ctx);
613ff40c12SJohn Marino 	if (data->conn == NULL) {
623ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
633ff40c12SJohn Marino 			   "connection");
643ff40c12SJohn Marino 		return -1;
653ff40c12SJohn Marino 	}
663ff40c12SJohn Marino 
67*a1157835SDaniel Fojt #ifdef CONFIG_TLS_INTERNAL
68*a1157835SDaniel Fojt 	tls_connection_set_log_cb(data->conn, eap_server_tls_log_cb, sm);
69*a1157835SDaniel Fojt #ifdef CONFIG_TESTING_OPTIONS
70*a1157835SDaniel Fojt 	tls_connection_set_test_flags(data->conn, sm->tls_test_flags);
71*a1157835SDaniel Fojt #endif /* CONFIG_TESTING_OPTIONS */
72*a1157835SDaniel Fojt #endif /* CONFIG_TLS_INTERNAL */
73*a1157835SDaniel Fojt 
74*a1157835SDaniel Fojt 	if (eap_type != EAP_TYPE_FAST)
75*a1157835SDaniel Fojt 		flags |= TLS_CONN_DISABLE_SESSION_TICKET;
76*a1157835SDaniel Fojt 	os_memcpy(session_ctx, "hostapd", 7);
77*a1157835SDaniel Fojt 	session_ctx[7] = (u8) eap_type;
78*a1157835SDaniel Fojt 	if (tls_connection_set_verify(sm->ssl_ctx, data->conn, verify_peer,
79*a1157835SDaniel Fojt 				      flags, session_ctx,
80*a1157835SDaniel Fojt 				      sizeof(session_ctx))) {
813ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "SSL: Failed to configure verification "
823ff40c12SJohn Marino 			   "of TLS peer certificate");
833ff40c12SJohn Marino 		tls_connection_deinit(sm->ssl_ctx, data->conn);
843ff40c12SJohn Marino 		data->conn = NULL;
853ff40c12SJohn Marino 		return -1;
863ff40c12SJohn Marino 	}
873ff40c12SJohn Marino 
883ff40c12SJohn Marino 	data->tls_out_limit = sm->fragment_size > 0 ? sm->fragment_size : 1398;
893ff40c12SJohn Marino 	if (data->phase2) {
903ff40c12SJohn Marino 		/* Limit the fragment size in the inner TLS authentication
913ff40c12SJohn Marino 		 * since the outer authentication with EAP-PEAP does not yet
923ff40c12SJohn Marino 		 * support fragmentation */
933ff40c12SJohn Marino 		if (data->tls_out_limit > 100)
943ff40c12SJohn Marino 			data->tls_out_limit -= 100;
953ff40c12SJohn Marino 	}
963ff40c12SJohn Marino 	return 0;
973ff40c12SJohn Marino }
983ff40c12SJohn Marino 
993ff40c12SJohn Marino 
eap_server_tls_ssl_deinit(struct eap_sm * sm,struct eap_ssl_data * data)1003ff40c12SJohn Marino void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
1013ff40c12SJohn Marino {
1023ff40c12SJohn Marino 	tls_connection_deinit(sm->ssl_ctx, data->conn);
1033ff40c12SJohn Marino 	eap_server_tls_free_in_buf(data);
1043ff40c12SJohn Marino 	wpabuf_free(data->tls_out);
1053ff40c12SJohn Marino 	data->tls_out = NULL;
1063ff40c12SJohn Marino }
1073ff40c12SJohn Marino 
1083ff40c12SJohn Marino 
eap_server_tls_derive_key(struct eap_sm * sm,struct eap_ssl_data * data,const char * label,const u8 * context,size_t context_len,size_t len)1093ff40c12SJohn Marino u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
110*a1157835SDaniel Fojt 			       const char *label, const u8 *context,
111*a1157835SDaniel Fojt 			       size_t context_len, size_t len)
1123ff40c12SJohn Marino {
113*a1157835SDaniel Fojt 	u8 *out;
1143ff40c12SJohn Marino 
1153ff40c12SJohn Marino 	out = os_malloc(len);
1163ff40c12SJohn Marino 	if (out == NULL)
1173ff40c12SJohn Marino 		return NULL;
1183ff40c12SJohn Marino 
119*a1157835SDaniel Fojt 	if (tls_connection_export_key(sm->ssl_ctx, data->conn, label,
120*a1157835SDaniel Fojt 				      context, context_len, out, len)) {
121*a1157835SDaniel Fojt 		os_free(out);
122*a1157835SDaniel Fojt 		return NULL;
123*a1157835SDaniel Fojt 	}
124*a1157835SDaniel Fojt 
1253ff40c12SJohn Marino 	return out;
126*a1157835SDaniel Fojt }
1273ff40c12SJohn Marino 
1283ff40c12SJohn Marino 
129*a1157835SDaniel Fojt /**
130*a1157835SDaniel Fojt  * eap_server_tls_derive_session_id - Derive a Session-Id based on TLS data
131*a1157835SDaniel Fojt  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
132*a1157835SDaniel Fojt  * @data: Data for TLS processing
133*a1157835SDaniel Fojt  * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
134*a1157835SDaniel Fojt  * @len: Pointer to length of the session ID generated
135*a1157835SDaniel Fojt  * Returns: Pointer to allocated Session-Id on success or %NULL on failure
136*a1157835SDaniel Fojt  *
137*a1157835SDaniel Fojt  * This function derive the Session-Id based on the TLS session data
138*a1157835SDaniel Fojt  * (client/server random and method type).
139*a1157835SDaniel Fojt  *
140*a1157835SDaniel Fojt  * The caller is responsible for freeing the returned buffer.
141*a1157835SDaniel Fojt  */
eap_server_tls_derive_session_id(struct eap_sm * sm,struct eap_ssl_data * data,u8 eap_type,size_t * len)142*a1157835SDaniel Fojt u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
143*a1157835SDaniel Fojt 				      struct eap_ssl_data *data, u8 eap_type,
144*a1157835SDaniel Fojt 				      size_t *len)
145*a1157835SDaniel Fojt {
146*a1157835SDaniel Fojt 	struct tls_random keys;
147*a1157835SDaniel Fojt 	u8 *out;
148*a1157835SDaniel Fojt 	const u8 context[] = { EAP_TYPE_TLS };
1493ff40c12SJohn Marino 
150*a1157835SDaniel Fojt 	if (eap_type == EAP_TYPE_TLS && data->tls_v13) {
151*a1157835SDaniel Fojt 		u8 *id, *method_id;
152*a1157835SDaniel Fojt 
153*a1157835SDaniel Fojt 		/* Session-Id = <EAP-Type> || Method-Id
154*a1157835SDaniel Fojt 		 * Method-Id = TLS-Exporter("EXPORTER_EAP_TLS_Method-Id",
155*a1157835SDaniel Fojt 		 *                          Type-Code, 64)
156*a1157835SDaniel Fojt 		 */
157*a1157835SDaniel Fojt 		*len = 1 + 64;
158*a1157835SDaniel Fojt 		id = os_malloc(*len);
159*a1157835SDaniel Fojt 		if (!id)
160*a1157835SDaniel Fojt 			return NULL;
161*a1157835SDaniel Fojt 		method_id = eap_server_tls_derive_key(
162*a1157835SDaniel Fojt 			sm, data, "EXPORTER_EAP_TLS_Method-Id", context, 1, 64);
163*a1157835SDaniel Fojt 		if (!method_id) {
164*a1157835SDaniel Fojt 			os_free(id);
165*a1157835SDaniel Fojt 			return NULL;
166*a1157835SDaniel Fojt 		}
167*a1157835SDaniel Fojt 		id[0] = eap_type;
168*a1157835SDaniel Fojt 		os_memcpy(id + 1, method_id, 64);
169*a1157835SDaniel Fojt 		os_free(method_id);
170*a1157835SDaniel Fojt 		return id;
171*a1157835SDaniel Fojt 	}
172*a1157835SDaniel Fojt 
173*a1157835SDaniel Fojt 	if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
174*a1157835SDaniel Fojt 		return NULL;
175*a1157835SDaniel Fojt 
176*a1157835SDaniel Fojt 	if (keys.client_random == NULL || keys.server_random == NULL)
177*a1157835SDaniel Fojt 		return NULL;
178*a1157835SDaniel Fojt 
179*a1157835SDaniel Fojt 	*len = 1 + keys.client_random_len + keys.server_random_len;
180*a1157835SDaniel Fojt 	out = os_malloc(*len);
181*a1157835SDaniel Fojt 	if (out == NULL)
182*a1157835SDaniel Fojt 		return NULL;
183*a1157835SDaniel Fojt 
184*a1157835SDaniel Fojt 	/* Session-Id = EAP type || client.random || server.random */
185*a1157835SDaniel Fojt 	out[0] = eap_type;
186*a1157835SDaniel Fojt 	os_memcpy(out + 1, keys.client_random, keys.client_random_len);
187*a1157835SDaniel Fojt 	os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
1883ff40c12SJohn Marino 		  keys.server_random_len);
1893ff40c12SJohn Marino 
1903ff40c12SJohn Marino 	return out;
1913ff40c12SJohn Marino }
1923ff40c12SJohn Marino 
1933ff40c12SJohn Marino 
eap_server_tls_build_msg(struct eap_ssl_data * data,int eap_type,int version,u8 id)1943ff40c12SJohn Marino struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
1953ff40c12SJohn Marino 					 int eap_type, int version, u8 id)
1963ff40c12SJohn Marino {
1973ff40c12SJohn Marino 	struct wpabuf *req;
1983ff40c12SJohn Marino 	u8 flags;
1993ff40c12SJohn Marino 	size_t send_len, plen;
2003ff40c12SJohn Marino 
2013ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "SSL: Generating Request");
2023ff40c12SJohn Marino 	if (data->tls_out == NULL) {
2033ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "SSL: tls_out NULL in %s", __func__);
2043ff40c12SJohn Marino 		return NULL;
2053ff40c12SJohn Marino 	}
2063ff40c12SJohn Marino 
2073ff40c12SJohn Marino 	flags = version;
2083ff40c12SJohn Marino 	send_len = wpabuf_len(data->tls_out) - data->tls_out_pos;
2093ff40c12SJohn Marino 	if (1 + send_len > data->tls_out_limit) {
2103ff40c12SJohn Marino 		send_len = data->tls_out_limit - 1;
2113ff40c12SJohn Marino 		flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
2123ff40c12SJohn Marino 		if (data->tls_out_pos == 0) {
2133ff40c12SJohn Marino 			flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
2143ff40c12SJohn Marino 			send_len -= 4;
2153ff40c12SJohn Marino 		}
2163ff40c12SJohn Marino 	}
2173ff40c12SJohn Marino 
2183ff40c12SJohn Marino 	plen = 1 + send_len;
2193ff40c12SJohn Marino 	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
2203ff40c12SJohn Marino 		plen += 4;
2213ff40c12SJohn Marino 
2223ff40c12SJohn Marino 	req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id);
2233ff40c12SJohn Marino 	if (req == NULL)
2243ff40c12SJohn Marino 		return NULL;
2253ff40c12SJohn Marino 
2263ff40c12SJohn Marino 	wpabuf_put_u8(req, flags); /* Flags */
2273ff40c12SJohn Marino 	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
2283ff40c12SJohn Marino 		wpabuf_put_be32(req, wpabuf_len(data->tls_out));
2293ff40c12SJohn Marino 
2303ff40c12SJohn Marino 	wpabuf_put_data(req, wpabuf_head_u8(data->tls_out) + data->tls_out_pos,
2313ff40c12SJohn Marino 			send_len);
2323ff40c12SJohn Marino 	data->tls_out_pos += send_len;
2333ff40c12SJohn Marino 
2343ff40c12SJohn Marino 	if (data->tls_out_pos == wpabuf_len(data->tls_out)) {
2353ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
2363ff40c12SJohn Marino 			   "(message sent completely)",
2373ff40c12SJohn Marino 			   (unsigned long) send_len);
2383ff40c12SJohn Marino 		wpabuf_free(data->tls_out);
2393ff40c12SJohn Marino 		data->tls_out = NULL;
2403ff40c12SJohn Marino 		data->tls_out_pos = 0;
2413ff40c12SJohn Marino 		data->state = MSG;
2423ff40c12SJohn Marino 	} else {
2433ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
2443ff40c12SJohn Marino 			   "(%lu more to send)", (unsigned long) send_len,
2453ff40c12SJohn Marino 			   (unsigned long) wpabuf_len(data->tls_out) -
2463ff40c12SJohn Marino 			   data->tls_out_pos);
2473ff40c12SJohn Marino 		data->state = WAIT_FRAG_ACK;
2483ff40c12SJohn Marino 	}
2493ff40c12SJohn Marino 
2503ff40c12SJohn Marino 	return req;
2513ff40c12SJohn Marino }
2523ff40c12SJohn Marino 
2533ff40c12SJohn Marino 
eap_server_tls_build_ack(u8 id,int eap_type,int version)2543ff40c12SJohn Marino struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version)
2553ff40c12SJohn Marino {
2563ff40c12SJohn Marino 	struct wpabuf *req;
2573ff40c12SJohn Marino 
2583ff40c12SJohn Marino 	req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id);
2593ff40c12SJohn Marino 	if (req == NULL)
2603ff40c12SJohn Marino 		return NULL;
2613ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "SSL: Building ACK");
2623ff40c12SJohn Marino 	wpabuf_put_u8(req, version); /* Flags */
2633ff40c12SJohn Marino 	return req;
2643ff40c12SJohn Marino }
2653ff40c12SJohn Marino 
2663ff40c12SJohn Marino 
eap_server_tls_process_cont(struct eap_ssl_data * data,const u8 * buf,size_t len)2673ff40c12SJohn Marino static int eap_server_tls_process_cont(struct eap_ssl_data *data,
2683ff40c12SJohn Marino 				       const u8 *buf, size_t len)
2693ff40c12SJohn Marino {
2703ff40c12SJohn Marino 	/* Process continuation of a pending message */
2713ff40c12SJohn Marino 	if (len > wpabuf_tailroom(data->tls_in)) {
2723ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "SSL: Fragment overflow");
2733ff40c12SJohn Marino 		return -1;
2743ff40c12SJohn Marino 	}
2753ff40c12SJohn Marino 
2763ff40c12SJohn Marino 	wpabuf_put_data(data->tls_in, buf, len);
2773ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu "
2783ff40c12SJohn Marino 		   "bytes more", (unsigned long) len,
2793ff40c12SJohn Marino 		   (unsigned long) wpabuf_tailroom(data->tls_in));
2803ff40c12SJohn Marino 
2813ff40c12SJohn Marino 	return 0;
2823ff40c12SJohn Marino }
2833ff40c12SJohn Marino 
2843ff40c12SJohn Marino 
eap_server_tls_process_fragment(struct eap_ssl_data * data,u8 flags,u32 message_length,const u8 * buf,size_t len)2853ff40c12SJohn Marino static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
2863ff40c12SJohn Marino 					   u8 flags, u32 message_length,
2873ff40c12SJohn Marino 					   const u8 *buf, size_t len)
2883ff40c12SJohn Marino {
2893ff40c12SJohn Marino 	/* Process a fragment that is not the last one of the message */
2903ff40c12SJohn Marino 	if (data->tls_in == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) {
2913ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a "
2923ff40c12SJohn Marino 			   "fragmented packet");
2933ff40c12SJohn Marino 		return -1;
2943ff40c12SJohn Marino 	}
2953ff40c12SJohn Marino 
2963ff40c12SJohn Marino 	if (data->tls_in == NULL) {
2973ff40c12SJohn Marino 		/* First fragment of the message */
2983ff40c12SJohn Marino 
2993ff40c12SJohn Marino 		/* Limit length to avoid rogue peers from causing large
3003ff40c12SJohn Marino 		 * memory allocations. */
3013ff40c12SJohn Marino 		if (message_length > 65536) {
3023ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
3033ff40c12SJohn Marino 				   " over 64 kB)");
3043ff40c12SJohn Marino 			return -1;
3053ff40c12SJohn Marino 		}
3063ff40c12SJohn Marino 
3073ff40c12SJohn Marino 		if (len > message_length) {
3083ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "SSL: Too much data (%d bytes) in "
3093ff40c12SJohn Marino 				   "first fragment of frame (TLS Message "
3103ff40c12SJohn Marino 				   "Length %d bytes)",
3113ff40c12SJohn Marino 				   (int) len, (int) message_length);
3123ff40c12SJohn Marino 			return -1;
3133ff40c12SJohn Marino 		}
3143ff40c12SJohn Marino 
3153ff40c12SJohn Marino 		data->tls_in = wpabuf_alloc(message_length);
3163ff40c12SJohn Marino 		if (data->tls_in == NULL) {
3173ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "SSL: No memory for message");
3183ff40c12SJohn Marino 			return -1;
3193ff40c12SJohn Marino 		}
3203ff40c12SJohn Marino 		wpabuf_put_data(data->tls_in, buf, len);
3213ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first "
3223ff40c12SJohn Marino 			   "fragment, waiting for %lu bytes more",
3233ff40c12SJohn Marino 			   (unsigned long) len,
3243ff40c12SJohn Marino 			   (unsigned long) wpabuf_tailroom(data->tls_in));
3253ff40c12SJohn Marino 	}
3263ff40c12SJohn Marino 
3273ff40c12SJohn Marino 	return 0;
3283ff40c12SJohn Marino }
3293ff40c12SJohn Marino 
3303ff40c12SJohn Marino 
eap_server_tls_phase1(struct eap_sm * sm,struct eap_ssl_data * data)3313ff40c12SJohn Marino int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
3323ff40c12SJohn Marino {
333*a1157835SDaniel Fojt 	char buf[20];
334*a1157835SDaniel Fojt 
3353ff40c12SJohn Marino 	if (data->tls_out) {
3363ff40c12SJohn Marino 		/* This should not happen.. */
3373ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
3383ff40c12SJohn Marino 			   "processing new message");
3393ff40c12SJohn Marino 		wpabuf_free(data->tls_out);
3403ff40c12SJohn Marino 		WPA_ASSERT(data->tls_out == NULL);
3413ff40c12SJohn Marino 	}
3423ff40c12SJohn Marino 
3433ff40c12SJohn Marino 	data->tls_out = tls_connection_server_handshake(sm->ssl_ctx,
3443ff40c12SJohn Marino 							data->conn,
3453ff40c12SJohn Marino 							data->tls_in, NULL);
3463ff40c12SJohn Marino 	if (data->tls_out == NULL) {
3473ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "SSL: TLS processing failed");
3483ff40c12SJohn Marino 		return -1;
3493ff40c12SJohn Marino 	}
3503ff40c12SJohn Marino 	if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
3513ff40c12SJohn Marino 		/* TLS processing has failed - return error */
3523ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
3533ff40c12SJohn Marino 			   "report error");
3543ff40c12SJohn Marino 		return -1;
3553ff40c12SJohn Marino 	}
3563ff40c12SJohn Marino 
357*a1157835SDaniel Fojt 	if (tls_get_version(sm->ssl_ctx, data->conn, buf, sizeof(buf)) == 0) {
358*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "SSL: Using TLS version %s", buf);
359*a1157835SDaniel Fojt 		data->tls_v13 = os_strcmp(buf, "TLSv1.3") == 0;
360*a1157835SDaniel Fojt 	}
361*a1157835SDaniel Fojt 
362*a1157835SDaniel Fojt 	if (!sm->serial_num &&
363*a1157835SDaniel Fojt 	    tls_connection_established(sm->ssl_ctx, data->conn))
364*a1157835SDaniel Fojt 		sm->serial_num = tls_connection_peer_serial_num(sm->ssl_ctx,
365*a1157835SDaniel Fojt 								data->conn);
366*a1157835SDaniel Fojt 
3673ff40c12SJohn Marino 	return 0;
3683ff40c12SJohn Marino }
3693ff40c12SJohn Marino 
3703ff40c12SJohn Marino 
eap_server_tls_reassemble(struct eap_ssl_data * data,u8 flags,const u8 ** pos,size_t * left)3713ff40c12SJohn Marino static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
3723ff40c12SJohn Marino 				     const u8 **pos, size_t *left)
3733ff40c12SJohn Marino {
3743ff40c12SJohn Marino 	unsigned int tls_msg_len = 0;
3753ff40c12SJohn Marino 	const u8 *end = *pos + *left;
3763ff40c12SJohn Marino 
377*a1157835SDaniel Fojt 	wpa_hexdump(MSG_MSGDUMP, "SSL: Received data", *pos, *left);
378*a1157835SDaniel Fojt 
3793ff40c12SJohn Marino 	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
3803ff40c12SJohn Marino 		if (*left < 4) {
3813ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
3823ff40c12SJohn Marino 				   "length");
3833ff40c12SJohn Marino 			return -1;
3843ff40c12SJohn Marino 		}
3853ff40c12SJohn Marino 		tls_msg_len = WPA_GET_BE32(*pos);
3863ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
3873ff40c12SJohn Marino 			   tls_msg_len);
3883ff40c12SJohn Marino 		*pos += 4;
3893ff40c12SJohn Marino 		*left -= 4;
3903ff40c12SJohn Marino 
3913ff40c12SJohn Marino 		if (*left > tls_msg_len) {
3923ff40c12SJohn Marino 			wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
3933ff40c12SJohn Marino 				   "bytes) smaller than this fragment (%d "
3943ff40c12SJohn Marino 				   "bytes)", (int) tls_msg_len, (int) *left);
3953ff40c12SJohn Marino 			return -1;
3963ff40c12SJohn Marino 		}
3973ff40c12SJohn Marino 	}
3983ff40c12SJohn Marino 
3993ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
4003ff40c12SJohn Marino 		   "Message Length %u", flags, tls_msg_len);
4013ff40c12SJohn Marino 
4023ff40c12SJohn Marino 	if (data->state == WAIT_FRAG_ACK) {
4033ff40c12SJohn Marino 		if (*left != 0) {
4043ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in "
4053ff40c12SJohn Marino 				   "WAIT_FRAG_ACK state");
4063ff40c12SJohn Marino 			return -1;
4073ff40c12SJohn Marino 		}
4083ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged");
4093ff40c12SJohn Marino 		return 1;
4103ff40c12SJohn Marino 	}
4113ff40c12SJohn Marino 
4123ff40c12SJohn Marino 	if (data->tls_in &&
4133ff40c12SJohn Marino 	    eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
4143ff40c12SJohn Marino 		return -1;
4153ff40c12SJohn Marino 
4163ff40c12SJohn Marino 	if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
4173ff40c12SJohn Marino 		if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
4183ff40c12SJohn Marino 						    *pos, end - *pos) < 0)
4193ff40c12SJohn Marino 			return -1;
4203ff40c12SJohn Marino 
4213ff40c12SJohn Marino 		data->state = FRAG_ACK;
4223ff40c12SJohn Marino 		return 1;
4233ff40c12SJohn Marino 	}
4243ff40c12SJohn Marino 
4253ff40c12SJohn Marino 	if (data->state == FRAG_ACK) {
4263ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "SSL: All fragments received");
4273ff40c12SJohn Marino 		data->state = MSG;
4283ff40c12SJohn Marino 	}
4293ff40c12SJohn Marino 
4303ff40c12SJohn Marino 	if (data->tls_in == NULL) {
4313ff40c12SJohn Marino 		/* Wrap unfragmented messages as wpabuf without extra copy */
4323ff40c12SJohn Marino 		wpabuf_set(&data->tmpbuf, *pos, end - *pos);
4333ff40c12SJohn Marino 		data->tls_in = &data->tmpbuf;
4343ff40c12SJohn Marino 	}
4353ff40c12SJohn Marino 
4363ff40c12SJohn Marino 	return 0;
4373ff40c12SJohn Marino }
4383ff40c12SJohn Marino 
4393ff40c12SJohn Marino 
eap_server_tls_free_in_buf(struct eap_ssl_data * data)4403ff40c12SJohn Marino static void eap_server_tls_free_in_buf(struct eap_ssl_data *data)
4413ff40c12SJohn Marino {
4423ff40c12SJohn Marino 	if (data->tls_in != &data->tmpbuf)
4433ff40c12SJohn Marino 		wpabuf_free(data->tls_in);
4443ff40c12SJohn Marino 	data->tls_in = NULL;
4453ff40c12SJohn Marino }
4463ff40c12SJohn Marino 
4473ff40c12SJohn Marino 
eap_server_tls_encrypt(struct eap_sm * sm,struct eap_ssl_data * data,const struct wpabuf * plain)4483ff40c12SJohn Marino struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
4493ff40c12SJohn Marino 				       struct eap_ssl_data *data,
4503ff40c12SJohn Marino 				       const struct wpabuf *plain)
4513ff40c12SJohn Marino {
4523ff40c12SJohn Marino 	struct wpabuf *buf;
4533ff40c12SJohn Marino 
4543ff40c12SJohn Marino 	buf = tls_connection_encrypt(sm->ssl_ctx, data->conn,
4553ff40c12SJohn Marino 				     plain);
4563ff40c12SJohn Marino 	if (buf == NULL) {
4573ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
4583ff40c12SJohn Marino 		return NULL;
4593ff40c12SJohn Marino 	}
4603ff40c12SJohn Marino 
4613ff40c12SJohn Marino 	return buf;
4623ff40c12SJohn Marino }
4633ff40c12SJohn Marino 
4643ff40c12SJohn Marino 
eap_server_tls_process(struct eap_sm * sm,struct eap_ssl_data * data,struct wpabuf * respData,void * priv,int eap_type,int (* proc_version)(struct eap_sm * sm,void * priv,int peer_version),void (* proc_msg)(struct eap_sm * sm,void * priv,const struct wpabuf * respData))4653ff40c12SJohn Marino int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
4663ff40c12SJohn Marino 			   struct wpabuf *respData, void *priv, int eap_type,
4673ff40c12SJohn Marino 			   int (*proc_version)(struct eap_sm *sm, void *priv,
4683ff40c12SJohn Marino 					       int peer_version),
4693ff40c12SJohn Marino 			   void (*proc_msg)(struct eap_sm *sm, void *priv,
4703ff40c12SJohn Marino 					    const struct wpabuf *respData))
4713ff40c12SJohn Marino {
4723ff40c12SJohn Marino 	const u8 *pos;
4733ff40c12SJohn Marino 	u8 flags;
4743ff40c12SJohn Marino 	size_t left;
4753ff40c12SJohn Marino 	int ret, res = 0;
4763ff40c12SJohn Marino 
4773ff40c12SJohn Marino 	if (eap_type == EAP_UNAUTH_TLS_TYPE)
4783ff40c12SJohn Marino 		pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
4793ff40c12SJohn Marino 				       EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
4803ff40c12SJohn Marino 				       &left);
481*a1157835SDaniel Fojt 	else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
482*a1157835SDaniel Fojt 		pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
483*a1157835SDaniel Fojt 				       EAP_VENDOR_WFA_UNAUTH_TLS, respData,
484*a1157835SDaniel Fojt 				       &left);
4853ff40c12SJohn Marino 	else
4863ff40c12SJohn Marino 		pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData,
4873ff40c12SJohn Marino 				       &left);
4883ff40c12SJohn Marino 	if (pos == NULL || left < 1)
4893ff40c12SJohn Marino 		return 0; /* Should not happen - frame already validated */
4903ff40c12SJohn Marino 	flags = *pos++;
4913ff40c12SJohn Marino 	left--;
4923ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x",
4933ff40c12SJohn Marino 		   (unsigned long) wpabuf_len(respData), flags);
4943ff40c12SJohn Marino 
4953ff40c12SJohn Marino 	if (proc_version &&
4963ff40c12SJohn Marino 	    proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0)
4973ff40c12SJohn Marino 		return -1;
4983ff40c12SJohn Marino 
4993ff40c12SJohn Marino 	ret = eap_server_tls_reassemble(data, flags, &pos, &left);
5003ff40c12SJohn Marino 	if (ret < 0) {
5013ff40c12SJohn Marino 		res = -1;
5023ff40c12SJohn Marino 		goto done;
5033ff40c12SJohn Marino 	} else if (ret == 1)
5043ff40c12SJohn Marino 		return 0;
5053ff40c12SJohn Marino 
5063ff40c12SJohn Marino 	if (proc_msg)
5073ff40c12SJohn Marino 		proc_msg(sm, priv, respData);
5083ff40c12SJohn Marino 
5093ff40c12SJohn Marino 	if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) {
5103ff40c12SJohn Marino 		wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in "
5113ff40c12SJohn Marino 			   "TLS processing");
5123ff40c12SJohn Marino 		res = -1;
5133ff40c12SJohn Marino 	}
5143ff40c12SJohn Marino 
5153ff40c12SJohn Marino done:
5163ff40c12SJohn Marino 	eap_server_tls_free_in_buf(data);
5173ff40c12SJohn Marino 
5183ff40c12SJohn Marino 	return res;
5193ff40c12SJohn Marino }
520