xref: /freebsd/contrib/wpa/src/crypto/tls_gnutls.c (revision 39beb93c)
1*39beb93cSSam Leffler /*
2*39beb93cSSam Leffler  * WPA Supplicant / SSL/TLS interface functions for openssl
3*39beb93cSSam Leffler  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
4*39beb93cSSam Leffler  *
5*39beb93cSSam Leffler  * This program is free software; you can redistribute it and/or modify
6*39beb93cSSam Leffler  * it under the terms of the GNU General Public License version 2 as
7*39beb93cSSam Leffler  * published by the Free Software Foundation.
8*39beb93cSSam Leffler  *
9*39beb93cSSam Leffler  * Alternatively, this software may be distributed under the terms of BSD
10*39beb93cSSam Leffler  * license.
11*39beb93cSSam Leffler  *
12*39beb93cSSam Leffler  * See README and COPYING for more details.
13*39beb93cSSam Leffler  */
14*39beb93cSSam Leffler 
15*39beb93cSSam Leffler #include "includes.h"
16*39beb93cSSam Leffler #include <gnutls/gnutls.h>
17*39beb93cSSam Leffler #include <gnutls/x509.h>
18*39beb93cSSam Leffler #ifdef PKCS12_FUNCS
19*39beb93cSSam Leffler #include <gnutls/pkcs12.h>
20*39beb93cSSam Leffler #endif /* PKCS12_FUNCS */
21*39beb93cSSam Leffler 
22*39beb93cSSam Leffler #ifdef CONFIG_GNUTLS_EXTRA
23*39beb93cSSam Leffler #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
24*39beb93cSSam Leffler #define GNUTLS_IA
25*39beb93cSSam Leffler #include <gnutls/extra.h>
26*39beb93cSSam Leffler #if LIBGNUTLS_VERSION_NUMBER == 0x010302
27*39beb93cSSam Leffler /* This function is not included in the current gnutls/extra.h even though it
28*39beb93cSSam Leffler  * should be, so define it here as a workaround for the time being. */
29*39beb93cSSam Leffler int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
30*39beb93cSSam Leffler #endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */
31*39beb93cSSam Leffler #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
32*39beb93cSSam Leffler #endif /* CONFIG_GNUTLS_EXTRA */
33*39beb93cSSam Leffler 
34*39beb93cSSam Leffler #include "common.h"
35*39beb93cSSam Leffler #include "tls.h"
36*39beb93cSSam Leffler 
37*39beb93cSSam Leffler 
38*39beb93cSSam Leffler #define TLS_RANDOM_SIZE 32
39*39beb93cSSam Leffler #define TLS_MASTER_SIZE 48
40*39beb93cSSam Leffler 
41*39beb93cSSam Leffler 
42*39beb93cSSam Leffler #if LIBGNUTLS_VERSION_NUMBER < 0x010302
43*39beb93cSSam Leffler /* GnuTLS 1.3.2 added functions for using master secret. Older versions require
44*39beb93cSSam Leffler  * use of internal structures to get the master_secret and
45*39beb93cSSam Leffler  * {server,client}_random.
46*39beb93cSSam Leffler  */
47*39beb93cSSam Leffler #define GNUTLS_INTERNAL_STRUCTURE_HACK
48*39beb93cSSam Leffler #endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
49*39beb93cSSam Leffler 
50*39beb93cSSam Leffler 
51*39beb93cSSam Leffler #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
52*39beb93cSSam Leffler /*
53*39beb93cSSam Leffler  * It looks like gnutls does not provide access to client/server_random and
54*39beb93cSSam Leffler  * master_key. This is somewhat unfortunate since these are needed for key
55*39beb93cSSam Leffler  * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
56*39beb93cSSam Leffler  * hack that copies the gnutls_session_int definition from gnutls_int.h so that
57*39beb93cSSam Leffler  * we can get the needed information.
58*39beb93cSSam Leffler  */
59*39beb93cSSam Leffler 
60*39beb93cSSam Leffler typedef u8 uint8;
61*39beb93cSSam Leffler typedef unsigned char opaque;
62*39beb93cSSam Leffler typedef struct {
63*39beb93cSSam Leffler     uint8 suite[2];
64*39beb93cSSam Leffler } cipher_suite_st;
65*39beb93cSSam Leffler 
66*39beb93cSSam Leffler typedef struct {
67*39beb93cSSam Leffler 	gnutls_connection_end_t entity;
68*39beb93cSSam Leffler 	gnutls_kx_algorithm_t kx_algorithm;
69*39beb93cSSam Leffler 	gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
70*39beb93cSSam Leffler 	gnutls_mac_algorithm_t read_mac_algorithm;
71*39beb93cSSam Leffler 	gnutls_compression_method_t read_compression_algorithm;
72*39beb93cSSam Leffler 	gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
73*39beb93cSSam Leffler 	gnutls_mac_algorithm_t write_mac_algorithm;
74*39beb93cSSam Leffler 	gnutls_compression_method_t write_compression_algorithm;
75*39beb93cSSam Leffler 	cipher_suite_st current_cipher_suite;
76*39beb93cSSam Leffler 	opaque master_secret[TLS_MASTER_SIZE];
77*39beb93cSSam Leffler 	opaque client_random[TLS_RANDOM_SIZE];
78*39beb93cSSam Leffler 	opaque server_random[TLS_RANDOM_SIZE];
79*39beb93cSSam Leffler 	/* followed by stuff we are not interested in */
80*39beb93cSSam Leffler } security_parameters_st;
81*39beb93cSSam Leffler 
82*39beb93cSSam Leffler struct gnutls_session_int {
83*39beb93cSSam Leffler 	security_parameters_st security_parameters;
84*39beb93cSSam Leffler 	/* followed by things we are not interested in */
85*39beb93cSSam Leffler };
86*39beb93cSSam Leffler #endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
87*39beb93cSSam Leffler 
88*39beb93cSSam Leffler static int tls_gnutls_ref_count = 0;
89*39beb93cSSam Leffler 
90*39beb93cSSam Leffler struct tls_global {
91*39beb93cSSam Leffler 	/* Data for session resumption */
92*39beb93cSSam Leffler 	void *session_data;
93*39beb93cSSam Leffler 	size_t session_data_size;
94*39beb93cSSam Leffler 
95*39beb93cSSam Leffler 	int server;
96*39beb93cSSam Leffler 
97*39beb93cSSam Leffler 	int params_set;
98*39beb93cSSam Leffler 	gnutls_certificate_credentials_t xcred;
99*39beb93cSSam Leffler };
100*39beb93cSSam Leffler 
101*39beb93cSSam Leffler struct tls_connection {
102*39beb93cSSam Leffler 	gnutls_session session;
103*39beb93cSSam Leffler 	char *subject_match, *altsubject_match;
104*39beb93cSSam Leffler 	int read_alerts, write_alerts, failed;
105*39beb93cSSam Leffler 
106*39beb93cSSam Leffler 	u8 *pre_shared_secret;
107*39beb93cSSam Leffler 	size_t pre_shared_secret_len;
108*39beb93cSSam Leffler 	int established;
109*39beb93cSSam Leffler 	int verify_peer;
110*39beb93cSSam Leffler 
111*39beb93cSSam Leffler 	u8 *push_buf, *pull_buf, *pull_buf_offset;
112*39beb93cSSam Leffler 	size_t push_buf_len, pull_buf_len;
113*39beb93cSSam Leffler 
114*39beb93cSSam Leffler 	int params_set;
115*39beb93cSSam Leffler 	gnutls_certificate_credentials_t xcred;
116*39beb93cSSam Leffler 
117*39beb93cSSam Leffler 	int tls_ia;
118*39beb93cSSam Leffler 	int final_phase_finished;
119*39beb93cSSam Leffler 
120*39beb93cSSam Leffler #ifdef GNUTLS_IA
121*39beb93cSSam Leffler 	gnutls_ia_server_credentials_t iacred_srv;
122*39beb93cSSam Leffler 	gnutls_ia_client_credentials_t iacred_cli;
123*39beb93cSSam Leffler 
124*39beb93cSSam Leffler 	/* Session keys generated in the current phase for inner secret
125*39beb93cSSam Leffler 	 * permutation before generating/verifying PhaseFinished. */
126*39beb93cSSam Leffler 	u8 *session_keys;
127*39beb93cSSam Leffler 	size_t session_keys_len;
128*39beb93cSSam Leffler 
129*39beb93cSSam Leffler 	u8 inner_secret[TLS_MASTER_SIZE];
130*39beb93cSSam Leffler #endif /* GNUTLS_IA */
131*39beb93cSSam Leffler };
132*39beb93cSSam Leffler 
133*39beb93cSSam Leffler 
134*39beb93cSSam Leffler static void tls_log_func(int level, const char *msg)
135*39beb93cSSam Leffler {
136*39beb93cSSam Leffler 	char *s, *pos;
137*39beb93cSSam Leffler 	if (level == 6 || level == 7) {
138*39beb93cSSam Leffler 		/* These levels seem to be mostly I/O debug and msg dumps */
139*39beb93cSSam Leffler 		return;
140*39beb93cSSam Leffler 	}
141*39beb93cSSam Leffler 
142*39beb93cSSam Leffler 	s = os_strdup(msg);
143*39beb93cSSam Leffler 	if (s == NULL)
144*39beb93cSSam Leffler 		return;
145*39beb93cSSam Leffler 
146*39beb93cSSam Leffler 	pos = s;
147*39beb93cSSam Leffler 	while (*pos != '\0') {
148*39beb93cSSam Leffler 		if (*pos == '\n') {
149*39beb93cSSam Leffler 			*pos = '\0';
150*39beb93cSSam Leffler 			break;
151*39beb93cSSam Leffler 		}
152*39beb93cSSam Leffler 		pos++;
153*39beb93cSSam Leffler 	}
154*39beb93cSSam Leffler 	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
155*39beb93cSSam Leffler 		   "gnutls<%d> %s", level, s);
156*39beb93cSSam Leffler 	os_free(s);
157*39beb93cSSam Leffler }
158*39beb93cSSam Leffler 
159*39beb93cSSam Leffler 
160*39beb93cSSam Leffler extern int wpa_debug_show_keys;
161*39beb93cSSam Leffler 
162*39beb93cSSam Leffler void * tls_init(const struct tls_config *conf)
163*39beb93cSSam Leffler {
164*39beb93cSSam Leffler 	struct tls_global *global;
165*39beb93cSSam Leffler 
166*39beb93cSSam Leffler #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
167*39beb93cSSam Leffler 	/* Because of the horrible hack to get master_secret and client/server
168*39beb93cSSam Leffler 	 * random, we need to make sure that the gnutls version is something
169*39beb93cSSam Leffler 	 * that is expected to have same structure definition for the session
170*39beb93cSSam Leffler 	 * data.. */
171*39beb93cSSam Leffler 	const char *ver;
172*39beb93cSSam Leffler 	const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
173*39beb93cSSam Leffler 				 "1.3.2",
174*39beb93cSSam Leffler 				 NULL };
175*39beb93cSSam Leffler 	int i;
176*39beb93cSSam Leffler #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
177*39beb93cSSam Leffler 
178*39beb93cSSam Leffler 	global = os_zalloc(sizeof(*global));
179*39beb93cSSam Leffler 	if (global == NULL)
180*39beb93cSSam Leffler 		return NULL;
181*39beb93cSSam Leffler 
182*39beb93cSSam Leffler 	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
183*39beb93cSSam Leffler 		os_free(global);
184*39beb93cSSam Leffler 		return NULL;
185*39beb93cSSam Leffler 	}
186*39beb93cSSam Leffler 	tls_gnutls_ref_count++;
187*39beb93cSSam Leffler 
188*39beb93cSSam Leffler #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
189*39beb93cSSam Leffler 	ver = gnutls_check_version(NULL);
190*39beb93cSSam Leffler 	if (ver == NULL) {
191*39beb93cSSam Leffler 		tls_deinit(global);
192*39beb93cSSam Leffler 		return NULL;
193*39beb93cSSam Leffler 	}
194*39beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
195*39beb93cSSam Leffler 	for (i = 0; ok_ver[i]; i++) {
196*39beb93cSSam Leffler 		if (strcmp(ok_ver[i], ver) == 0)
197*39beb93cSSam Leffler 			break;
198*39beb93cSSam Leffler 	}
199*39beb93cSSam Leffler 	if (ok_ver[i] == NULL) {
200*39beb93cSSam Leffler 		wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
201*39beb93cSSam Leffler 			   "to be tested and enabled in tls_gnutls.c", ver);
202*39beb93cSSam Leffler 		tls_deinit(global);
203*39beb93cSSam Leffler 		return NULL;
204*39beb93cSSam Leffler 	}
205*39beb93cSSam Leffler #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
206*39beb93cSSam Leffler 
207*39beb93cSSam Leffler 	gnutls_global_set_log_function(tls_log_func);
208*39beb93cSSam Leffler 	if (wpa_debug_show_keys)
209*39beb93cSSam Leffler 		gnutls_global_set_log_level(11);
210*39beb93cSSam Leffler 	return global;
211*39beb93cSSam Leffler }
212*39beb93cSSam Leffler 
213*39beb93cSSam Leffler 
214*39beb93cSSam Leffler void tls_deinit(void *ssl_ctx)
215*39beb93cSSam Leffler {
216*39beb93cSSam Leffler 	struct tls_global *global = ssl_ctx;
217*39beb93cSSam Leffler 	if (global) {
218*39beb93cSSam Leffler 		if (global->params_set)
219*39beb93cSSam Leffler 			gnutls_certificate_free_credentials(global->xcred);
220*39beb93cSSam Leffler 		os_free(global->session_data);
221*39beb93cSSam Leffler 		os_free(global);
222*39beb93cSSam Leffler 	}
223*39beb93cSSam Leffler 
224*39beb93cSSam Leffler 	tls_gnutls_ref_count--;
225*39beb93cSSam Leffler 	if (tls_gnutls_ref_count == 0)
226*39beb93cSSam Leffler 		gnutls_global_deinit();
227*39beb93cSSam Leffler }
228*39beb93cSSam Leffler 
229*39beb93cSSam Leffler 
230*39beb93cSSam Leffler int tls_get_errors(void *ssl_ctx)
231*39beb93cSSam Leffler {
232*39beb93cSSam Leffler 	return 0;
233*39beb93cSSam Leffler }
234*39beb93cSSam Leffler 
235*39beb93cSSam Leffler 
236*39beb93cSSam Leffler static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
237*39beb93cSSam Leffler 			     size_t len)
238*39beb93cSSam Leffler {
239*39beb93cSSam Leffler 	struct tls_connection *conn = (struct tls_connection *) ptr;
240*39beb93cSSam Leffler 	u8 *end;
241*39beb93cSSam Leffler 	if (conn->pull_buf == NULL) {
242*39beb93cSSam Leffler 		errno = EWOULDBLOCK;
243*39beb93cSSam Leffler 		return -1;
244*39beb93cSSam Leffler 	}
245*39beb93cSSam Leffler 
246*39beb93cSSam Leffler 	end = conn->pull_buf + conn->pull_buf_len;
247*39beb93cSSam Leffler 	if ((size_t) (end - conn->pull_buf_offset) < len)
248*39beb93cSSam Leffler 		len = end - conn->pull_buf_offset;
249*39beb93cSSam Leffler 	os_memcpy(buf, conn->pull_buf_offset, len);
250*39beb93cSSam Leffler 	conn->pull_buf_offset += len;
251*39beb93cSSam Leffler 	if (conn->pull_buf_offset == end) {
252*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
253*39beb93cSSam Leffler 		os_free(conn->pull_buf);
254*39beb93cSSam Leffler 		conn->pull_buf = conn->pull_buf_offset = NULL;
255*39beb93cSSam Leffler 		conn->pull_buf_len = 0;
256*39beb93cSSam Leffler 	} else {
257*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
258*39beb93cSSam Leffler 			   __func__,
259*39beb93cSSam Leffler 			   (unsigned long) (end - conn->pull_buf_offset));
260*39beb93cSSam Leffler 	}
261*39beb93cSSam Leffler 	return len;
262*39beb93cSSam Leffler }
263*39beb93cSSam Leffler 
264*39beb93cSSam Leffler 
265*39beb93cSSam Leffler static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
266*39beb93cSSam Leffler 			     size_t len)
267*39beb93cSSam Leffler {
268*39beb93cSSam Leffler 	struct tls_connection *conn = (struct tls_connection *) ptr;
269*39beb93cSSam Leffler 	u8 *nbuf;
270*39beb93cSSam Leffler 
271*39beb93cSSam Leffler 	nbuf = os_realloc(conn->push_buf, conn->push_buf_len + len);
272*39beb93cSSam Leffler 	if (nbuf == NULL) {
273*39beb93cSSam Leffler 		errno = ENOMEM;
274*39beb93cSSam Leffler 		return -1;
275*39beb93cSSam Leffler 	}
276*39beb93cSSam Leffler 	os_memcpy(nbuf + conn->push_buf_len, buf, len);
277*39beb93cSSam Leffler 	conn->push_buf = nbuf;
278*39beb93cSSam Leffler 	conn->push_buf_len += len;
279*39beb93cSSam Leffler 
280*39beb93cSSam Leffler 	return len;
281*39beb93cSSam Leffler }
282*39beb93cSSam Leffler 
283*39beb93cSSam Leffler 
284*39beb93cSSam Leffler static int tls_gnutls_init_session(struct tls_global *global,
285*39beb93cSSam Leffler 				   struct tls_connection *conn)
286*39beb93cSSam Leffler {
287*39beb93cSSam Leffler 	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
288*39beb93cSSam Leffler 	const int protos[2] = { GNUTLS_TLS1, 0 };
289*39beb93cSSam Leffler 	int ret;
290*39beb93cSSam Leffler 
291*39beb93cSSam Leffler 	ret = gnutls_init(&conn->session,
292*39beb93cSSam Leffler 			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
293*39beb93cSSam Leffler 	if (ret < 0) {
294*39beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
295*39beb93cSSam Leffler 			   "connection: %s", gnutls_strerror(ret));
296*39beb93cSSam Leffler 		return -1;
297*39beb93cSSam Leffler 	}
298*39beb93cSSam Leffler 
299*39beb93cSSam Leffler 	ret = gnutls_set_default_priority(conn->session);
300*39beb93cSSam Leffler 	if (ret < 0)
301*39beb93cSSam Leffler 		goto fail;
302*39beb93cSSam Leffler 
303*39beb93cSSam Leffler 	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
304*39beb93cSSam Leffler 	if (ret < 0)
305*39beb93cSSam Leffler 		goto fail;
306*39beb93cSSam Leffler 
307*39beb93cSSam Leffler 	ret = gnutls_protocol_set_priority(conn->session, protos);
308*39beb93cSSam Leffler 	if (ret < 0)
309*39beb93cSSam Leffler 		goto fail;
310*39beb93cSSam Leffler 
311*39beb93cSSam Leffler 	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
312*39beb93cSSam Leffler 	gnutls_transport_set_push_function(conn->session, tls_push_func);
313*39beb93cSSam Leffler 	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
314*39beb93cSSam Leffler 
315*39beb93cSSam Leffler 	return 0;
316*39beb93cSSam Leffler 
317*39beb93cSSam Leffler fail:
318*39beb93cSSam Leffler 	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
319*39beb93cSSam Leffler 		   gnutls_strerror(ret));
320*39beb93cSSam Leffler 	gnutls_deinit(conn->session);
321*39beb93cSSam Leffler 	return -1;
322*39beb93cSSam Leffler }
323*39beb93cSSam Leffler 
324*39beb93cSSam Leffler 
325*39beb93cSSam Leffler struct tls_connection * tls_connection_init(void *ssl_ctx)
326*39beb93cSSam Leffler {
327*39beb93cSSam Leffler 	struct tls_global *global = ssl_ctx;
328*39beb93cSSam Leffler 	struct tls_connection *conn;
329*39beb93cSSam Leffler 	int ret;
330*39beb93cSSam Leffler 
331*39beb93cSSam Leffler 	conn = os_zalloc(sizeof(*conn));
332*39beb93cSSam Leffler 	if (conn == NULL)
333*39beb93cSSam Leffler 		return NULL;
334*39beb93cSSam Leffler 
335*39beb93cSSam Leffler 	if (tls_gnutls_init_session(global, conn)) {
336*39beb93cSSam Leffler 		os_free(conn);
337*39beb93cSSam Leffler 		return NULL;
338*39beb93cSSam Leffler 	}
339*39beb93cSSam Leffler 
340*39beb93cSSam Leffler 	if (global->params_set) {
341*39beb93cSSam Leffler 		ret = gnutls_credentials_set(conn->session,
342*39beb93cSSam Leffler 					     GNUTLS_CRD_CERTIFICATE,
343*39beb93cSSam Leffler 					     global->xcred);
344*39beb93cSSam Leffler 		if (ret < 0) {
345*39beb93cSSam Leffler 			wpa_printf(MSG_INFO, "Failed to configure "
346*39beb93cSSam Leffler 				   "credentials: %s", gnutls_strerror(ret));
347*39beb93cSSam Leffler 			os_free(conn);
348*39beb93cSSam Leffler 			return NULL;
349*39beb93cSSam Leffler 		}
350*39beb93cSSam Leffler 	}
351*39beb93cSSam Leffler 
352*39beb93cSSam Leffler 	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
353*39beb93cSSam Leffler 		os_free(conn);
354*39beb93cSSam Leffler 		return NULL;
355*39beb93cSSam Leffler 	}
356*39beb93cSSam Leffler 
357*39beb93cSSam Leffler 	return conn;
358*39beb93cSSam Leffler }
359*39beb93cSSam Leffler 
360*39beb93cSSam Leffler 
361*39beb93cSSam Leffler void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
362*39beb93cSSam Leffler {
363*39beb93cSSam Leffler 	if (conn == NULL)
364*39beb93cSSam Leffler 		return;
365*39beb93cSSam Leffler 
366*39beb93cSSam Leffler #ifdef GNUTLS_IA
367*39beb93cSSam Leffler 	if (conn->iacred_srv)
368*39beb93cSSam Leffler 		gnutls_ia_free_server_credentials(conn->iacred_srv);
369*39beb93cSSam Leffler 	if (conn->iacred_cli)
370*39beb93cSSam Leffler 		gnutls_ia_free_client_credentials(conn->iacred_cli);
371*39beb93cSSam Leffler 	if (conn->session_keys) {
372*39beb93cSSam Leffler 		os_memset(conn->session_keys, 0, conn->session_keys_len);
373*39beb93cSSam Leffler 		os_free(conn->session_keys);
374*39beb93cSSam Leffler 	}
375*39beb93cSSam Leffler #endif /* GNUTLS_IA */
376*39beb93cSSam Leffler 
377*39beb93cSSam Leffler 	gnutls_certificate_free_credentials(conn->xcred);
378*39beb93cSSam Leffler 	gnutls_deinit(conn->session);
379*39beb93cSSam Leffler 	os_free(conn->pre_shared_secret);
380*39beb93cSSam Leffler 	os_free(conn->subject_match);
381*39beb93cSSam Leffler 	os_free(conn->altsubject_match);
382*39beb93cSSam Leffler 	os_free(conn->push_buf);
383*39beb93cSSam Leffler 	os_free(conn->pull_buf);
384*39beb93cSSam Leffler 	os_free(conn);
385*39beb93cSSam Leffler }
386*39beb93cSSam Leffler 
387*39beb93cSSam Leffler 
388*39beb93cSSam Leffler int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
389*39beb93cSSam Leffler {
390*39beb93cSSam Leffler 	return conn ? conn->established : 0;
391*39beb93cSSam Leffler }
392*39beb93cSSam Leffler 
393*39beb93cSSam Leffler 
394*39beb93cSSam Leffler int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
395*39beb93cSSam Leffler {
396*39beb93cSSam Leffler 	struct tls_global *global = ssl_ctx;
397*39beb93cSSam Leffler 	int ret;
398*39beb93cSSam Leffler 
399*39beb93cSSam Leffler 	if (conn == NULL)
400*39beb93cSSam Leffler 		return -1;
401*39beb93cSSam Leffler 
402*39beb93cSSam Leffler 	/* Shutdown previous TLS connection without notifying the peer
403*39beb93cSSam Leffler 	 * because the connection was already terminated in practice
404*39beb93cSSam Leffler 	 * and "close notify" shutdown alert would confuse AS. */
405*39beb93cSSam Leffler 	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
406*39beb93cSSam Leffler 	os_free(conn->push_buf);
407*39beb93cSSam Leffler 	conn->push_buf = NULL;
408*39beb93cSSam Leffler 	conn->push_buf_len = 0;
409*39beb93cSSam Leffler 	conn->established = 0;
410*39beb93cSSam Leffler 	conn->final_phase_finished = 0;
411*39beb93cSSam Leffler #ifdef GNUTLS_IA
412*39beb93cSSam Leffler 	if (conn->session_keys) {
413*39beb93cSSam Leffler 		os_memset(conn->session_keys, 0, conn->session_keys_len);
414*39beb93cSSam Leffler 		os_free(conn->session_keys);
415*39beb93cSSam Leffler 	}
416*39beb93cSSam Leffler 	conn->session_keys_len = 0;
417*39beb93cSSam Leffler #endif /* GNUTLS_IA */
418*39beb93cSSam Leffler 
419*39beb93cSSam Leffler 	gnutls_deinit(conn->session);
420*39beb93cSSam Leffler 	if (tls_gnutls_init_session(global, conn)) {
421*39beb93cSSam Leffler 		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
422*39beb93cSSam Leffler 			   "for session resumption use");
423*39beb93cSSam Leffler 		return -1;
424*39beb93cSSam Leffler 	}
425*39beb93cSSam Leffler 
426*39beb93cSSam Leffler 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
427*39beb93cSSam Leffler 				     conn->params_set ? conn->xcred :
428*39beb93cSSam Leffler 				     global->xcred);
429*39beb93cSSam Leffler 	if (ret < 0) {
430*39beb93cSSam Leffler 		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
431*39beb93cSSam Leffler 			   "for session resumption: %s", gnutls_strerror(ret));
432*39beb93cSSam Leffler 		return -1;
433*39beb93cSSam Leffler 	}
434*39beb93cSSam Leffler 
435*39beb93cSSam Leffler 	if (global->session_data) {
436*39beb93cSSam Leffler 		ret = gnutls_session_set_data(conn->session,
437*39beb93cSSam Leffler 					      global->session_data,
438*39beb93cSSam Leffler 					      global->session_data_size);
439*39beb93cSSam Leffler 		if (ret < 0) {
440*39beb93cSSam Leffler 			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
441*39beb93cSSam Leffler 				   "data: %s", gnutls_strerror(ret));
442*39beb93cSSam Leffler 			return -1;
443*39beb93cSSam Leffler 		}
444*39beb93cSSam Leffler 	}
445*39beb93cSSam Leffler 
446*39beb93cSSam Leffler 	return 0;
447*39beb93cSSam Leffler }
448*39beb93cSSam Leffler 
449*39beb93cSSam Leffler 
450*39beb93cSSam Leffler #if 0
451*39beb93cSSam Leffler static int tls_match_altsubject(X509 *cert, const char *match)
452*39beb93cSSam Leffler {
453*39beb93cSSam Leffler 	GENERAL_NAME *gen;
454*39beb93cSSam Leffler 	char *field, *tmp;
455*39beb93cSSam Leffler 	void *ext;
456*39beb93cSSam Leffler 	int i, found = 0;
457*39beb93cSSam Leffler 	size_t len;
458*39beb93cSSam Leffler 
459*39beb93cSSam Leffler 	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
460*39beb93cSSam Leffler 
461*39beb93cSSam Leffler 	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
462*39beb93cSSam Leffler 		gen = sk_GENERAL_NAME_value(ext, i);
463*39beb93cSSam Leffler 		switch (gen->type) {
464*39beb93cSSam Leffler 		case GEN_EMAIL:
465*39beb93cSSam Leffler 			field = "EMAIL";
466*39beb93cSSam Leffler 			break;
467*39beb93cSSam Leffler 		case GEN_DNS:
468*39beb93cSSam Leffler 			field = "DNS";
469*39beb93cSSam Leffler 			break;
470*39beb93cSSam Leffler 		case GEN_URI:
471*39beb93cSSam Leffler 			field = "URI";
472*39beb93cSSam Leffler 			break;
473*39beb93cSSam Leffler 		default:
474*39beb93cSSam Leffler 			field = NULL;
475*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
476*39beb93cSSam Leffler 				   "unsupported type=%d", gen->type);
477*39beb93cSSam Leffler 			break;
478*39beb93cSSam Leffler 		}
479*39beb93cSSam Leffler 
480*39beb93cSSam Leffler 		if (!field)
481*39beb93cSSam Leffler 			continue;
482*39beb93cSSam Leffler 
483*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
484*39beb93cSSam Leffler 			   field, gen->d.ia5->data);
485*39beb93cSSam Leffler 		len = os_strlen(field) + 1 +
486*39beb93cSSam Leffler 			strlen((char *) gen->d.ia5->data) + 1;
487*39beb93cSSam Leffler 		tmp = os_malloc(len);
488*39beb93cSSam Leffler 		if (tmp == NULL)
489*39beb93cSSam Leffler 			continue;
490*39beb93cSSam Leffler 		snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
491*39beb93cSSam Leffler 		if (strstr(tmp, match))
492*39beb93cSSam Leffler 			found++;
493*39beb93cSSam Leffler 		os_free(tmp);
494*39beb93cSSam Leffler 	}
495*39beb93cSSam Leffler 
496*39beb93cSSam Leffler 	return found;
497*39beb93cSSam Leffler }
498*39beb93cSSam Leffler #endif
499*39beb93cSSam Leffler 
500*39beb93cSSam Leffler 
501*39beb93cSSam Leffler #if 0
502*39beb93cSSam Leffler static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
503*39beb93cSSam Leffler {
504*39beb93cSSam Leffler 	char buf[256];
505*39beb93cSSam Leffler 	X509 *err_cert;
506*39beb93cSSam Leffler 	int err, depth;
507*39beb93cSSam Leffler 	SSL *ssl;
508*39beb93cSSam Leffler 	struct tls_connection *conn;
509*39beb93cSSam Leffler 	char *match, *altmatch;
510*39beb93cSSam Leffler 
511*39beb93cSSam Leffler 	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
512*39beb93cSSam Leffler 	err = X509_STORE_CTX_get_error(x509_ctx);
513*39beb93cSSam Leffler 	depth = X509_STORE_CTX_get_error_depth(x509_ctx);
514*39beb93cSSam Leffler 	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
515*39beb93cSSam Leffler 					 SSL_get_ex_data_X509_STORE_CTX_idx());
516*39beb93cSSam Leffler 	X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
517*39beb93cSSam Leffler 
518*39beb93cSSam Leffler 	conn = SSL_get_app_data(ssl);
519*39beb93cSSam Leffler 	match = conn ? conn->subject_match : NULL;
520*39beb93cSSam Leffler 	altmatch = conn ? conn->altsubject_match : NULL;
521*39beb93cSSam Leffler 
522*39beb93cSSam Leffler 	if (!preverify_ok) {
523*39beb93cSSam Leffler 		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
524*39beb93cSSam Leffler 			   " error %d (%s) depth %d for '%s'", err,
525*39beb93cSSam Leffler 			   X509_verify_cert_error_string(err), depth, buf);
526*39beb93cSSam Leffler 	} else {
527*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
528*39beb93cSSam Leffler 			   "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
529*39beb93cSSam Leffler 			   preverify_ok, err,
530*39beb93cSSam Leffler 			   X509_verify_cert_error_string(err), depth, buf);
531*39beb93cSSam Leffler 		if (depth == 0 && match && strstr(buf, match) == NULL) {
532*39beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
533*39beb93cSSam Leffler 				   "match with '%s'", buf, match);
534*39beb93cSSam Leffler 			preverify_ok = 0;
535*39beb93cSSam Leffler 		} else if (depth == 0 && altmatch &&
536*39beb93cSSam Leffler 			   !tls_match_altsubject(err_cert, altmatch)) {
537*39beb93cSSam Leffler 			wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
538*39beb93cSSam Leffler 				   "'%s' not found", altmatch);
539*39beb93cSSam Leffler 			preverify_ok = 0;
540*39beb93cSSam Leffler 		}
541*39beb93cSSam Leffler 	}
542*39beb93cSSam Leffler 
543*39beb93cSSam Leffler 	return preverify_ok;
544*39beb93cSSam Leffler }
545*39beb93cSSam Leffler #endif
546*39beb93cSSam Leffler 
547*39beb93cSSam Leffler 
548*39beb93cSSam Leffler int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
549*39beb93cSSam Leffler 			      const struct tls_connection_params *params)
550*39beb93cSSam Leffler {
551*39beb93cSSam Leffler 	int ret;
552*39beb93cSSam Leffler 
553*39beb93cSSam Leffler 	if (conn == NULL || params == NULL)
554*39beb93cSSam Leffler 		return -1;
555*39beb93cSSam Leffler 
556*39beb93cSSam Leffler 	os_free(conn->subject_match);
557*39beb93cSSam Leffler 	conn->subject_match = NULL;
558*39beb93cSSam Leffler 	if (params->subject_match) {
559*39beb93cSSam Leffler 		conn->subject_match = os_strdup(params->subject_match);
560*39beb93cSSam Leffler 		if (conn->subject_match == NULL)
561*39beb93cSSam Leffler 			return -1;
562*39beb93cSSam Leffler 	}
563*39beb93cSSam Leffler 
564*39beb93cSSam Leffler 	os_free(conn->altsubject_match);
565*39beb93cSSam Leffler 	conn->altsubject_match = NULL;
566*39beb93cSSam Leffler 	if (params->altsubject_match) {
567*39beb93cSSam Leffler 		conn->altsubject_match = os_strdup(params->altsubject_match);
568*39beb93cSSam Leffler 		if (conn->altsubject_match == NULL)
569*39beb93cSSam Leffler 			return -1;
570*39beb93cSSam Leffler 	}
571*39beb93cSSam Leffler 
572*39beb93cSSam Leffler 	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
573*39beb93cSSam Leffler 	 * to force peer validation(?) */
574*39beb93cSSam Leffler 
575*39beb93cSSam Leffler 	if (params->ca_cert) {
576*39beb93cSSam Leffler 		conn->verify_peer = 1;
577*39beb93cSSam Leffler 		ret = gnutls_certificate_set_x509_trust_file(
578*39beb93cSSam Leffler 			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
579*39beb93cSSam Leffler 		if (ret < 0) {
580*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
581*39beb93cSSam Leffler 				   "in PEM format: %s", params->ca_cert,
582*39beb93cSSam Leffler 				   gnutls_strerror(ret));
583*39beb93cSSam Leffler 			ret = gnutls_certificate_set_x509_trust_file(
584*39beb93cSSam Leffler 				conn->xcred, params->ca_cert,
585*39beb93cSSam Leffler 				GNUTLS_X509_FMT_DER);
586*39beb93cSSam Leffler 			if (ret < 0) {
587*39beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
588*39beb93cSSam Leffler 					   "'%s' in DER format: %s",
589*39beb93cSSam Leffler 					   params->ca_cert,
590*39beb93cSSam Leffler 					   gnutls_strerror(ret));
591*39beb93cSSam Leffler 				return -1;
592*39beb93cSSam Leffler 			}
593*39beb93cSSam Leffler 		}
594*39beb93cSSam Leffler 	}
595*39beb93cSSam Leffler 
596*39beb93cSSam Leffler 	if (params->client_cert && params->private_key) {
597*39beb93cSSam Leffler 		/* TODO: private_key_passwd? */
598*39beb93cSSam Leffler 		ret = gnutls_certificate_set_x509_key_file(
599*39beb93cSSam Leffler 			conn->xcred, params->client_cert, params->private_key,
600*39beb93cSSam Leffler 			GNUTLS_X509_FMT_PEM);
601*39beb93cSSam Leffler 		if (ret < 0) {
602*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
603*39beb93cSSam Leffler 				   "in PEM format: %s", gnutls_strerror(ret));
604*39beb93cSSam Leffler 			ret = gnutls_certificate_set_x509_key_file(
605*39beb93cSSam Leffler 				conn->xcred, params->client_cert,
606*39beb93cSSam Leffler 				params->private_key, GNUTLS_X509_FMT_DER);
607*39beb93cSSam Leffler 			if (ret < 0) {
608*39beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "Failed to read client "
609*39beb93cSSam Leffler 					   "cert/key in DER format: %s",
610*39beb93cSSam Leffler 					   gnutls_strerror(ret));
611*39beb93cSSam Leffler 				return ret;
612*39beb93cSSam Leffler 			}
613*39beb93cSSam Leffler 		}
614*39beb93cSSam Leffler 	} else if (params->private_key) {
615*39beb93cSSam Leffler 		int pkcs12_ok = 0;
616*39beb93cSSam Leffler #ifdef PKCS12_FUNCS
617*39beb93cSSam Leffler 		/* Try to load in PKCS#12 format */
618*39beb93cSSam Leffler #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
619*39beb93cSSam Leffler 		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
620*39beb93cSSam Leffler 			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
621*39beb93cSSam Leffler 			params->private_key_passwd);
622*39beb93cSSam Leffler 		if (ret != 0) {
623*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
624*39beb93cSSam Leffler 				   "PKCS#12 format: %s", gnutls_strerror(ret));
625*39beb93cSSam Leffler 			return -1;
626*39beb93cSSam Leffler 		} else
627*39beb93cSSam Leffler 			pkcs12_ok = 1;
628*39beb93cSSam Leffler #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
629*39beb93cSSam Leffler #endif /* PKCS12_FUNCS */
630*39beb93cSSam Leffler 
631*39beb93cSSam Leffler 		if (!pkcs12_ok) {
632*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
633*39beb93cSSam Leffler 				   "included");
634*39beb93cSSam Leffler 			return -1;
635*39beb93cSSam Leffler 		}
636*39beb93cSSam Leffler 	}
637*39beb93cSSam Leffler 
638*39beb93cSSam Leffler 	conn->tls_ia = params->tls_ia;
639*39beb93cSSam Leffler 	conn->params_set = 1;
640*39beb93cSSam Leffler 
641*39beb93cSSam Leffler 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
642*39beb93cSSam Leffler 				     conn->xcred);
643*39beb93cSSam Leffler 	if (ret < 0) {
644*39beb93cSSam Leffler 		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
645*39beb93cSSam Leffler 			   gnutls_strerror(ret));
646*39beb93cSSam Leffler 	}
647*39beb93cSSam Leffler 
648*39beb93cSSam Leffler #ifdef GNUTLS_IA
649*39beb93cSSam Leffler 	if (conn->iacred_cli)
650*39beb93cSSam Leffler 		gnutls_ia_free_client_credentials(conn->iacred_cli);
651*39beb93cSSam Leffler 
652*39beb93cSSam Leffler 	ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli);
653*39beb93cSSam Leffler 	if (ret) {
654*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
655*39beb93cSSam Leffler 			   gnutls_strerror(ret));
656*39beb93cSSam Leffler 		return -1;
657*39beb93cSSam Leffler 	}
658*39beb93cSSam Leffler 
659*39beb93cSSam Leffler 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
660*39beb93cSSam Leffler 				     conn->iacred_cli);
661*39beb93cSSam Leffler 	if (ret) {
662*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
663*39beb93cSSam Leffler 			   gnutls_strerror(ret));
664*39beb93cSSam Leffler 		gnutls_ia_free_client_credentials(conn->iacred_cli);
665*39beb93cSSam Leffler 		conn->iacred_cli = NULL;
666*39beb93cSSam Leffler 		return -1;
667*39beb93cSSam Leffler 	}
668*39beb93cSSam Leffler #endif /* GNUTLS_IE */
669*39beb93cSSam Leffler 
670*39beb93cSSam Leffler 	return ret;
671*39beb93cSSam Leffler }
672*39beb93cSSam Leffler 
673*39beb93cSSam Leffler 
674*39beb93cSSam Leffler int tls_global_set_params(void *tls_ctx,
675*39beb93cSSam Leffler 			  const struct tls_connection_params *params)
676*39beb93cSSam Leffler {
677*39beb93cSSam Leffler 	struct tls_global *global = tls_ctx;
678*39beb93cSSam Leffler 	int ret;
679*39beb93cSSam Leffler 
680*39beb93cSSam Leffler 	/* Currently, global parameters are only set when running in server
681*39beb93cSSam Leffler 	 * mode. */
682*39beb93cSSam Leffler 	global->server = 1;
683*39beb93cSSam Leffler 
684*39beb93cSSam Leffler 	if (global->params_set) {
685*39beb93cSSam Leffler 		gnutls_certificate_free_credentials(global->xcred);
686*39beb93cSSam Leffler 		global->params_set = 0;
687*39beb93cSSam Leffler 	}
688*39beb93cSSam Leffler 
689*39beb93cSSam Leffler 	ret = gnutls_certificate_allocate_credentials(&global->xcred);
690*39beb93cSSam Leffler 	if (ret) {
691*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
692*39beb93cSSam Leffler 			   "%s", gnutls_strerror(ret));
693*39beb93cSSam Leffler 		return -1;
694*39beb93cSSam Leffler 	}
695*39beb93cSSam Leffler 
696*39beb93cSSam Leffler 	if (params->ca_cert) {
697*39beb93cSSam Leffler 		ret = gnutls_certificate_set_x509_trust_file(
698*39beb93cSSam Leffler 			global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
699*39beb93cSSam Leffler 		if (ret < 0) {
700*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
701*39beb93cSSam Leffler 				   "in PEM format: %s", params->ca_cert,
702*39beb93cSSam Leffler 				   gnutls_strerror(ret));
703*39beb93cSSam Leffler 			ret = gnutls_certificate_set_x509_trust_file(
704*39beb93cSSam Leffler 				global->xcred, params->ca_cert,
705*39beb93cSSam Leffler 				GNUTLS_X509_FMT_DER);
706*39beb93cSSam Leffler 			if (ret < 0) {
707*39beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
708*39beb93cSSam Leffler 					   "'%s' in DER format: %s",
709*39beb93cSSam Leffler 					   params->ca_cert,
710*39beb93cSSam Leffler 					   gnutls_strerror(ret));
711*39beb93cSSam Leffler 				goto fail;
712*39beb93cSSam Leffler 			}
713*39beb93cSSam Leffler 		}
714*39beb93cSSam Leffler 	}
715*39beb93cSSam Leffler 
716*39beb93cSSam Leffler 	if (params->client_cert && params->private_key) {
717*39beb93cSSam Leffler 		/* TODO: private_key_passwd? */
718*39beb93cSSam Leffler 		ret = gnutls_certificate_set_x509_key_file(
719*39beb93cSSam Leffler 			global->xcred, params->client_cert,
720*39beb93cSSam Leffler 			params->private_key, GNUTLS_X509_FMT_PEM);
721*39beb93cSSam Leffler 		if (ret < 0) {
722*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
723*39beb93cSSam Leffler 				   "in PEM format: %s", gnutls_strerror(ret));
724*39beb93cSSam Leffler 			ret = gnutls_certificate_set_x509_key_file(
725*39beb93cSSam Leffler 				global->xcred, params->client_cert,
726*39beb93cSSam Leffler 				params->private_key, GNUTLS_X509_FMT_DER);
727*39beb93cSSam Leffler 			if (ret < 0) {
728*39beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "Failed to read client "
729*39beb93cSSam Leffler 					   "cert/key in DER format: %s",
730*39beb93cSSam Leffler 					   gnutls_strerror(ret));
731*39beb93cSSam Leffler 				goto fail;
732*39beb93cSSam Leffler 			}
733*39beb93cSSam Leffler 		}
734*39beb93cSSam Leffler 	} else if (params->private_key) {
735*39beb93cSSam Leffler 		int pkcs12_ok = 0;
736*39beb93cSSam Leffler #ifdef PKCS12_FUNCS
737*39beb93cSSam Leffler 		/* Try to load in PKCS#12 format */
738*39beb93cSSam Leffler #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
739*39beb93cSSam Leffler 		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
740*39beb93cSSam Leffler 			global->xcred, params->private_key,
741*39beb93cSSam Leffler 			GNUTLS_X509_FMT_DER, params->private_key_passwd);
742*39beb93cSSam Leffler 		if (ret != 0) {
743*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
744*39beb93cSSam Leffler 				   "PKCS#12 format: %s", gnutls_strerror(ret));
745*39beb93cSSam Leffler 			goto fail;
746*39beb93cSSam Leffler 		} else
747*39beb93cSSam Leffler 			pkcs12_ok = 1;
748*39beb93cSSam Leffler #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
749*39beb93cSSam Leffler #endif /* PKCS12_FUNCS */
750*39beb93cSSam Leffler 
751*39beb93cSSam Leffler 		if (!pkcs12_ok) {
752*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
753*39beb93cSSam Leffler 				   "included");
754*39beb93cSSam Leffler 			goto fail;
755*39beb93cSSam Leffler 		}
756*39beb93cSSam Leffler 	}
757*39beb93cSSam Leffler 
758*39beb93cSSam Leffler 	global->params_set = 1;
759*39beb93cSSam Leffler 
760*39beb93cSSam Leffler 	return 0;
761*39beb93cSSam Leffler 
762*39beb93cSSam Leffler fail:
763*39beb93cSSam Leffler 	gnutls_certificate_free_credentials(global->xcred);
764*39beb93cSSam Leffler 	return -1;
765*39beb93cSSam Leffler }
766*39beb93cSSam Leffler 
767*39beb93cSSam Leffler 
768*39beb93cSSam Leffler int tls_global_set_verify(void *ssl_ctx, int check_crl)
769*39beb93cSSam Leffler {
770*39beb93cSSam Leffler 	/* TODO */
771*39beb93cSSam Leffler 	return 0;
772*39beb93cSSam Leffler }
773*39beb93cSSam Leffler 
774*39beb93cSSam Leffler 
775*39beb93cSSam Leffler int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
776*39beb93cSSam Leffler 			      int verify_peer)
777*39beb93cSSam Leffler {
778*39beb93cSSam Leffler 	if (conn == NULL || conn->session == NULL)
779*39beb93cSSam Leffler 		return -1;
780*39beb93cSSam Leffler 
781*39beb93cSSam Leffler 	conn->verify_peer = verify_peer;
782*39beb93cSSam Leffler 	gnutls_certificate_server_set_request(conn->session,
783*39beb93cSSam Leffler 					      verify_peer ? GNUTLS_CERT_REQUIRE
784*39beb93cSSam Leffler 					      : GNUTLS_CERT_REQUEST);
785*39beb93cSSam Leffler 
786*39beb93cSSam Leffler 	return 0;
787*39beb93cSSam Leffler }
788*39beb93cSSam Leffler 
789*39beb93cSSam Leffler 
790*39beb93cSSam Leffler int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
791*39beb93cSSam Leffler 			    struct tls_keys *keys)
792*39beb93cSSam Leffler {
793*39beb93cSSam Leffler #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
794*39beb93cSSam Leffler 	security_parameters_st *sec;
795*39beb93cSSam Leffler #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
796*39beb93cSSam Leffler 
797*39beb93cSSam Leffler 	if (conn == NULL || conn->session == NULL || keys == NULL)
798*39beb93cSSam Leffler 		return -1;
799*39beb93cSSam Leffler 
800*39beb93cSSam Leffler 	os_memset(keys, 0, sizeof(*keys));
801*39beb93cSSam Leffler 
802*39beb93cSSam Leffler #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
803*39beb93cSSam Leffler 	sec = &conn->session->security_parameters;
804*39beb93cSSam Leffler 	keys->master_key = sec->master_secret;
805*39beb93cSSam Leffler 	keys->master_key_len = TLS_MASTER_SIZE;
806*39beb93cSSam Leffler 	keys->client_random = sec->client_random;
807*39beb93cSSam Leffler 	keys->server_random = sec->server_random;
808*39beb93cSSam Leffler #else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
809*39beb93cSSam Leffler 	keys->client_random =
810*39beb93cSSam Leffler 		(u8 *) gnutls_session_get_client_random(conn->session);
811*39beb93cSSam Leffler 	keys->server_random =
812*39beb93cSSam Leffler 		(u8 *) gnutls_session_get_server_random(conn->session);
813*39beb93cSSam Leffler 	/* No access to master_secret */
814*39beb93cSSam Leffler #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
815*39beb93cSSam Leffler 
816*39beb93cSSam Leffler #ifdef GNUTLS_IA
817*39beb93cSSam Leffler 	gnutls_ia_extract_inner_secret(conn->session,
818*39beb93cSSam Leffler 				       (char *) conn->inner_secret);
819*39beb93cSSam Leffler 	keys->inner_secret = conn->inner_secret;
820*39beb93cSSam Leffler 	keys->inner_secret_len = TLS_MASTER_SIZE;
821*39beb93cSSam Leffler #endif /* GNUTLS_IA */
822*39beb93cSSam Leffler 
823*39beb93cSSam Leffler 	keys->client_random_len = TLS_RANDOM_SIZE;
824*39beb93cSSam Leffler 	keys->server_random_len = TLS_RANDOM_SIZE;
825*39beb93cSSam Leffler 
826*39beb93cSSam Leffler 	return 0;
827*39beb93cSSam Leffler }
828*39beb93cSSam Leffler 
829*39beb93cSSam Leffler 
830*39beb93cSSam Leffler int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
831*39beb93cSSam Leffler 		       const char *label, int server_random_first,
832*39beb93cSSam Leffler 		       u8 *out, size_t out_len)
833*39beb93cSSam Leffler {
834*39beb93cSSam Leffler #if LIBGNUTLS_VERSION_NUMBER >= 0x010302
835*39beb93cSSam Leffler 	if (conn == NULL || conn->session == NULL)
836*39beb93cSSam Leffler 		return -1;
837*39beb93cSSam Leffler 
838*39beb93cSSam Leffler 	return gnutls_prf(conn->session, os_strlen(label), label,
839*39beb93cSSam Leffler 			  server_random_first, 0, NULL, out_len, (char *) out);
840*39beb93cSSam Leffler #else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
841*39beb93cSSam Leffler 	return -1;
842*39beb93cSSam Leffler #endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
843*39beb93cSSam Leffler }
844*39beb93cSSam Leffler 
845*39beb93cSSam Leffler 
846*39beb93cSSam Leffler static int tls_connection_verify_peer(struct tls_connection *conn)
847*39beb93cSSam Leffler {
848*39beb93cSSam Leffler 	unsigned int status, num_certs, i;
849*39beb93cSSam Leffler 	struct os_time now;
850*39beb93cSSam Leffler 	const gnutls_datum_t *certs;
851*39beb93cSSam Leffler 	gnutls_x509_crt_t cert;
852*39beb93cSSam Leffler 
853*39beb93cSSam Leffler 	if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
854*39beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
855*39beb93cSSam Leffler 			   "certificate chain");
856*39beb93cSSam Leffler 		return -1;
857*39beb93cSSam Leffler 	}
858*39beb93cSSam Leffler 
859*39beb93cSSam Leffler 	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
860*39beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
861*39beb93cSSam Leffler 		return -1;
862*39beb93cSSam Leffler 	}
863*39beb93cSSam Leffler 
864*39beb93cSSam Leffler 	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
865*39beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
866*39beb93cSSam Leffler 			   "known issuer");
867*39beb93cSSam Leffler 		return -1;
868*39beb93cSSam Leffler 	}
869*39beb93cSSam Leffler 
870*39beb93cSSam Leffler 	if (status & GNUTLS_CERT_REVOKED) {
871*39beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
872*39beb93cSSam Leffler 		return -1;
873*39beb93cSSam Leffler 	}
874*39beb93cSSam Leffler 
875*39beb93cSSam Leffler 	os_get_time(&now);
876*39beb93cSSam Leffler 
877*39beb93cSSam Leffler 	certs = gnutls_certificate_get_peers(conn->session, &num_certs);
878*39beb93cSSam Leffler 	if (certs == NULL) {
879*39beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
880*39beb93cSSam Leffler 			   "received");
881*39beb93cSSam Leffler 		return -1;
882*39beb93cSSam Leffler 	}
883*39beb93cSSam Leffler 
884*39beb93cSSam Leffler 	for (i = 0; i < num_certs; i++) {
885*39beb93cSSam Leffler 		char *buf;
886*39beb93cSSam Leffler 		size_t len;
887*39beb93cSSam Leffler 		if (gnutls_x509_crt_init(&cert) < 0) {
888*39beb93cSSam Leffler 			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
889*39beb93cSSam Leffler 				   "failed");
890*39beb93cSSam Leffler 			return -1;
891*39beb93cSSam Leffler 		}
892*39beb93cSSam Leffler 
893*39beb93cSSam Leffler 		if (gnutls_x509_crt_import(cert, &certs[i],
894*39beb93cSSam Leffler 					   GNUTLS_X509_FMT_DER) < 0) {
895*39beb93cSSam Leffler 			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
896*39beb93cSSam Leffler 				   "certificate %d/%d", i + 1, num_certs);
897*39beb93cSSam Leffler 			gnutls_x509_crt_deinit(cert);
898*39beb93cSSam Leffler 			return -1;
899*39beb93cSSam Leffler 		}
900*39beb93cSSam Leffler 
901*39beb93cSSam Leffler 		gnutls_x509_crt_get_dn(cert, NULL, &len);
902*39beb93cSSam Leffler 		len++;
903*39beb93cSSam Leffler 		buf = os_malloc(len + 1);
904*39beb93cSSam Leffler 		if (buf) {
905*39beb93cSSam Leffler 			buf[0] = buf[len] = '\0';
906*39beb93cSSam Leffler 			gnutls_x509_crt_get_dn(cert, buf, &len);
907*39beb93cSSam Leffler 		}
908*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
909*39beb93cSSam Leffler 			   i + 1, num_certs, buf);
910*39beb93cSSam Leffler 
911*39beb93cSSam Leffler 		if (i == 0) {
912*39beb93cSSam Leffler 			/* TODO: validate subject_match and altsubject_match */
913*39beb93cSSam Leffler 		}
914*39beb93cSSam Leffler 
915*39beb93cSSam Leffler 		os_free(buf);
916*39beb93cSSam Leffler 
917*39beb93cSSam Leffler 		if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
918*39beb93cSSam Leffler 		    gnutls_x509_crt_get_activation_time(cert) > now.sec) {
919*39beb93cSSam Leffler 			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
920*39beb93cSSam Leffler 				   "not valid at this time",
921*39beb93cSSam Leffler 				   i + 1, num_certs);
922*39beb93cSSam Leffler 			gnutls_x509_crt_deinit(cert);
923*39beb93cSSam Leffler 			return -1;
924*39beb93cSSam Leffler 		}
925*39beb93cSSam Leffler 
926*39beb93cSSam Leffler 		gnutls_x509_crt_deinit(cert);
927*39beb93cSSam Leffler 	}
928*39beb93cSSam Leffler 
929*39beb93cSSam Leffler 	return 0;
930*39beb93cSSam Leffler }
931*39beb93cSSam Leffler 
932*39beb93cSSam Leffler 
933*39beb93cSSam Leffler u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
934*39beb93cSSam Leffler 			      const u8 *in_data, size_t in_len,
935*39beb93cSSam Leffler 			      size_t *out_len, u8 **appl_data,
936*39beb93cSSam Leffler 			      size_t *appl_data_len)
937*39beb93cSSam Leffler {
938*39beb93cSSam Leffler 	struct tls_global *global = ssl_ctx;
939*39beb93cSSam Leffler 	u8 *out_data;
940*39beb93cSSam Leffler 	int ret;
941*39beb93cSSam Leffler 
942*39beb93cSSam Leffler 	if (appl_data)
943*39beb93cSSam Leffler 		*appl_data = NULL;
944*39beb93cSSam Leffler 
945*39beb93cSSam Leffler 	if (in_data && in_len) {
946*39beb93cSSam Leffler 		if (conn->pull_buf) {
947*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
948*39beb93cSSam Leffler 				   "pull_buf", __func__,
949*39beb93cSSam Leffler 				   (unsigned long) conn->pull_buf_len);
950*39beb93cSSam Leffler 			os_free(conn->pull_buf);
951*39beb93cSSam Leffler 		}
952*39beb93cSSam Leffler 		conn->pull_buf = os_malloc(in_len);
953*39beb93cSSam Leffler 		if (conn->pull_buf == NULL)
954*39beb93cSSam Leffler 			return NULL;
955*39beb93cSSam Leffler 		os_memcpy(conn->pull_buf, in_data, in_len);
956*39beb93cSSam Leffler 		conn->pull_buf_offset = conn->pull_buf;
957*39beb93cSSam Leffler 		conn->pull_buf_len = in_len;
958*39beb93cSSam Leffler 	}
959*39beb93cSSam Leffler 
960*39beb93cSSam Leffler 	ret = gnutls_handshake(conn->session);
961*39beb93cSSam Leffler 	if (ret < 0) {
962*39beb93cSSam Leffler 		switch (ret) {
963*39beb93cSSam Leffler 		case GNUTLS_E_AGAIN:
964*39beb93cSSam Leffler 			if (global->server && conn->established &&
965*39beb93cSSam Leffler 			    conn->push_buf == NULL) {
966*39beb93cSSam Leffler 				/* Need to return something to trigger
967*39beb93cSSam Leffler 				 * completion of EAP-TLS. */
968*39beb93cSSam Leffler 				conn->push_buf = os_malloc(1);
969*39beb93cSSam Leffler 			}
970*39beb93cSSam Leffler 			break;
971*39beb93cSSam Leffler 		case GNUTLS_E_FATAL_ALERT_RECEIVED:
972*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
973*39beb93cSSam Leffler 				   __func__, gnutls_alert_get_name(
974*39beb93cSSam Leffler 					   gnutls_alert_get(conn->session)));
975*39beb93cSSam Leffler 			conn->read_alerts++;
976*39beb93cSSam Leffler 			/* continue */
977*39beb93cSSam Leffler 		default:
978*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
979*39beb93cSSam Leffler 				   "-> %s", __func__, gnutls_strerror(ret));
980*39beb93cSSam Leffler 			conn->failed++;
981*39beb93cSSam Leffler 		}
982*39beb93cSSam Leffler 	} else {
983*39beb93cSSam Leffler 		size_t size;
984*39beb93cSSam Leffler 
985*39beb93cSSam Leffler 		if (conn->verify_peer && tls_connection_verify_peer(conn)) {
986*39beb93cSSam Leffler 			wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
987*39beb93cSSam Leffler 				   "failed validation");
988*39beb93cSSam Leffler 			conn->failed++;
989*39beb93cSSam Leffler 			return NULL;
990*39beb93cSSam Leffler 		}
991*39beb93cSSam Leffler 
992*39beb93cSSam Leffler 		if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
993*39beb93cSSam Leffler 			wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
994*39beb93cSSam Leffler 			conn->failed++;
995*39beb93cSSam Leffler 			return NULL;
996*39beb93cSSam Leffler 		}
997*39beb93cSSam Leffler 
998*39beb93cSSam Leffler 		if (conn->tls_ia)
999*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
1000*39beb93cSSam Leffler 		else {
1001*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TLS: Handshake completed "
1002*39beb93cSSam Leffler 				   "successfully");
1003*39beb93cSSam Leffler 		}
1004*39beb93cSSam Leffler 		conn->established = 1;
1005*39beb93cSSam Leffler 		if (conn->push_buf == NULL) {
1006*39beb93cSSam Leffler 			/* Need to return something to get final TLS ACK. */
1007*39beb93cSSam Leffler 			conn->push_buf = os_malloc(1);
1008*39beb93cSSam Leffler 		}
1009*39beb93cSSam Leffler 
1010*39beb93cSSam Leffler 		gnutls_session_get_data(conn->session, NULL, &size);
1011*39beb93cSSam Leffler 		if (global->session_data == NULL ||
1012*39beb93cSSam Leffler 		    global->session_data_size < size) {
1013*39beb93cSSam Leffler 			os_free(global->session_data);
1014*39beb93cSSam Leffler 			global->session_data = os_malloc(size);
1015*39beb93cSSam Leffler 		}
1016*39beb93cSSam Leffler 		if (global->session_data) {
1017*39beb93cSSam Leffler 			global->session_data_size = size;
1018*39beb93cSSam Leffler 			gnutls_session_get_data(conn->session,
1019*39beb93cSSam Leffler 						global->session_data,
1020*39beb93cSSam Leffler 						&global->session_data_size);
1021*39beb93cSSam Leffler 		}
1022*39beb93cSSam Leffler 	}
1023*39beb93cSSam Leffler 
1024*39beb93cSSam Leffler 	out_data = conn->push_buf;
1025*39beb93cSSam Leffler 	*out_len = conn->push_buf_len;
1026*39beb93cSSam Leffler 	conn->push_buf = NULL;
1027*39beb93cSSam Leffler 	conn->push_buf_len = 0;
1028*39beb93cSSam Leffler 	return out_data;
1029*39beb93cSSam Leffler }
1030*39beb93cSSam Leffler 
1031*39beb93cSSam Leffler 
1032*39beb93cSSam Leffler u8 * tls_connection_server_handshake(void *ssl_ctx,
1033*39beb93cSSam Leffler 				     struct tls_connection *conn,
1034*39beb93cSSam Leffler 				     const u8 *in_data, size_t in_len,
1035*39beb93cSSam Leffler 				     size_t *out_len)
1036*39beb93cSSam Leffler {
1037*39beb93cSSam Leffler 	return tls_connection_handshake(ssl_ctx, conn, in_data, in_len,
1038*39beb93cSSam Leffler 					out_len, NULL, NULL);
1039*39beb93cSSam Leffler }
1040*39beb93cSSam Leffler 
1041*39beb93cSSam Leffler 
1042*39beb93cSSam Leffler int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
1043*39beb93cSSam Leffler 			   const u8 *in_data, size_t in_len,
1044*39beb93cSSam Leffler 			   u8 *out_data, size_t out_len)
1045*39beb93cSSam Leffler {
1046*39beb93cSSam Leffler 	ssize_t res;
1047*39beb93cSSam Leffler 
1048*39beb93cSSam Leffler #ifdef GNUTLS_IA
1049*39beb93cSSam Leffler 	if (conn->tls_ia)
1050*39beb93cSSam Leffler 		res = gnutls_ia_send(conn->session, (char *) in_data, in_len);
1051*39beb93cSSam Leffler 	else
1052*39beb93cSSam Leffler #endif /* GNUTLS_IA */
1053*39beb93cSSam Leffler 	res = gnutls_record_send(conn->session, in_data, in_len);
1054*39beb93cSSam Leffler 	if (res < 0) {
1055*39beb93cSSam Leffler 		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1056*39beb93cSSam Leffler 			   __func__, gnutls_strerror(res));
1057*39beb93cSSam Leffler 		return -1;
1058*39beb93cSSam Leffler 	}
1059*39beb93cSSam Leffler 	if (conn->push_buf == NULL)
1060*39beb93cSSam Leffler 		return -1;
1061*39beb93cSSam Leffler 	if (conn->push_buf_len < out_len)
1062*39beb93cSSam Leffler 		out_len = conn->push_buf_len;
1063*39beb93cSSam Leffler 	else if (conn->push_buf_len > out_len) {
1064*39beb93cSSam Leffler 		wpa_printf(MSG_INFO, "GnuTLS: Not enough buffer space for "
1065*39beb93cSSam Leffler 			   "encrypted message (in_len=%lu push_buf_len=%lu "
1066*39beb93cSSam Leffler 			   "out_len=%lu",
1067*39beb93cSSam Leffler 			   (unsigned long) in_len,
1068*39beb93cSSam Leffler 			   (unsigned long) conn->push_buf_len,
1069*39beb93cSSam Leffler 			   (unsigned long) out_len);
1070*39beb93cSSam Leffler 	}
1071*39beb93cSSam Leffler 	os_memcpy(out_data, conn->push_buf, out_len);
1072*39beb93cSSam Leffler 	os_free(conn->push_buf);
1073*39beb93cSSam Leffler 	conn->push_buf = NULL;
1074*39beb93cSSam Leffler 	conn->push_buf_len = 0;
1075*39beb93cSSam Leffler 	return out_len;
1076*39beb93cSSam Leffler }
1077*39beb93cSSam Leffler 
1078*39beb93cSSam Leffler 
1079*39beb93cSSam Leffler int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
1080*39beb93cSSam Leffler 			   const u8 *in_data, size_t in_len,
1081*39beb93cSSam Leffler 			   u8 *out_data, size_t out_len)
1082*39beb93cSSam Leffler {
1083*39beb93cSSam Leffler 	ssize_t res;
1084*39beb93cSSam Leffler 
1085*39beb93cSSam Leffler 	if (conn->pull_buf) {
1086*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1087*39beb93cSSam Leffler 			   "pull_buf", __func__,
1088*39beb93cSSam Leffler 			   (unsigned long) conn->pull_buf_len);
1089*39beb93cSSam Leffler 		os_free(conn->pull_buf);
1090*39beb93cSSam Leffler 	}
1091*39beb93cSSam Leffler 	conn->pull_buf = os_malloc(in_len);
1092*39beb93cSSam Leffler 	if (conn->pull_buf == NULL)
1093*39beb93cSSam Leffler 		return -1;
1094*39beb93cSSam Leffler 	os_memcpy(conn->pull_buf, in_data, in_len);
1095*39beb93cSSam Leffler 	conn->pull_buf_offset = conn->pull_buf;
1096*39beb93cSSam Leffler 	conn->pull_buf_len = in_len;
1097*39beb93cSSam Leffler 
1098*39beb93cSSam Leffler #ifdef GNUTLS_IA
1099*39beb93cSSam Leffler 	if (conn->tls_ia) {
1100*39beb93cSSam Leffler 		res = gnutls_ia_recv(conn->session, (char *) out_data,
1101*39beb93cSSam Leffler 				     out_len);
1102*39beb93cSSam Leffler 		if (out_len >= 12 &&
1103*39beb93cSSam Leffler 		    (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
1104*39beb93cSSam Leffler 		     res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)) {
1105*39beb93cSSam Leffler 			int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
1106*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished",
1107*39beb93cSSam Leffler 				   __func__, final ? "Final" : "Intermediate");
1108*39beb93cSSam Leffler 
1109*39beb93cSSam Leffler 			res = gnutls_ia_permute_inner_secret(
1110*39beb93cSSam Leffler 				conn->session, conn->session_keys_len,
1111*39beb93cSSam Leffler 				(char *) conn->session_keys);
1112*39beb93cSSam Leffler 			if (conn->session_keys) {
1113*39beb93cSSam Leffler 				os_memset(conn->session_keys, 0,
1114*39beb93cSSam Leffler 					  conn->session_keys_len);
1115*39beb93cSSam Leffler 				os_free(conn->session_keys);
1116*39beb93cSSam Leffler 			}
1117*39beb93cSSam Leffler 			conn->session_keys = NULL;
1118*39beb93cSSam Leffler 			conn->session_keys_len = 0;
1119*39beb93cSSam Leffler 			if (res) {
1120*39beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "%s: Failed to permute "
1121*39beb93cSSam Leffler 					   "inner secret: %s",
1122*39beb93cSSam Leffler 					   __func__, gnutls_strerror(res));
1123*39beb93cSSam Leffler 				return -1;
1124*39beb93cSSam Leffler 			}
1125*39beb93cSSam Leffler 
1126*39beb93cSSam Leffler 			res = gnutls_ia_verify_endphase(conn->session,
1127*39beb93cSSam Leffler 							(char *) out_data);
1128*39beb93cSSam Leffler 			if (res == 0) {
1129*39beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "%s: Correct endphase "
1130*39beb93cSSam Leffler 					   "checksum", __func__);
1131*39beb93cSSam Leffler 			} else {
1132*39beb93cSSam Leffler 				wpa_printf(MSG_INFO, "%s: Endphase "
1133*39beb93cSSam Leffler 					   "verification failed: %s",
1134*39beb93cSSam Leffler 					   __func__, gnutls_strerror(res));
1135*39beb93cSSam Leffler 				return -1;
1136*39beb93cSSam Leffler 			}
1137*39beb93cSSam Leffler 
1138*39beb93cSSam Leffler 			if (final)
1139*39beb93cSSam Leffler 				conn->final_phase_finished = 1;
1140*39beb93cSSam Leffler 
1141*39beb93cSSam Leffler 			return 0;
1142*39beb93cSSam Leffler 		}
1143*39beb93cSSam Leffler 
1144*39beb93cSSam Leffler 		if (res < 0) {
1145*39beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
1146*39beb93cSSam Leffler 				   "(%s)", __func__, (int) res,
1147*39beb93cSSam Leffler 				   gnutls_strerror(res));
1148*39beb93cSSam Leffler 		}
1149*39beb93cSSam Leffler 		return res;
1150*39beb93cSSam Leffler 	}
1151*39beb93cSSam Leffler #endif /* GNUTLS_IA */
1152*39beb93cSSam Leffler 
1153*39beb93cSSam Leffler 	res = gnutls_record_recv(conn->session, out_data, out_len);
1154*39beb93cSSam Leffler 	if (res < 0) {
1155*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1156*39beb93cSSam Leffler 			   "(%s)", __func__, (int) res, gnutls_strerror(res));
1157*39beb93cSSam Leffler 	}
1158*39beb93cSSam Leffler 
1159*39beb93cSSam Leffler 	return res;
1160*39beb93cSSam Leffler }
1161*39beb93cSSam Leffler 
1162*39beb93cSSam Leffler 
1163*39beb93cSSam Leffler int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1164*39beb93cSSam Leffler {
1165*39beb93cSSam Leffler 	if (conn == NULL)
1166*39beb93cSSam Leffler 		return 0;
1167*39beb93cSSam Leffler 	return gnutls_session_is_resumed(conn->session);
1168*39beb93cSSam Leffler }
1169*39beb93cSSam Leffler 
1170*39beb93cSSam Leffler 
1171*39beb93cSSam Leffler int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1172*39beb93cSSam Leffler 				   u8 *ciphers)
1173*39beb93cSSam Leffler {
1174*39beb93cSSam Leffler 	/* TODO */
1175*39beb93cSSam Leffler 	return -1;
1176*39beb93cSSam Leffler }
1177*39beb93cSSam Leffler 
1178*39beb93cSSam Leffler 
1179*39beb93cSSam Leffler int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1180*39beb93cSSam Leffler 		   char *buf, size_t buflen)
1181*39beb93cSSam Leffler {
1182*39beb93cSSam Leffler 	/* TODO */
1183*39beb93cSSam Leffler 	buf[0] = '\0';
1184*39beb93cSSam Leffler 	return 0;
1185*39beb93cSSam Leffler }
1186*39beb93cSSam Leffler 
1187*39beb93cSSam Leffler 
1188*39beb93cSSam Leffler int tls_connection_enable_workaround(void *ssl_ctx,
1189*39beb93cSSam Leffler 				     struct tls_connection *conn)
1190*39beb93cSSam Leffler {
1191*39beb93cSSam Leffler 	/* TODO: set SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */
1192*39beb93cSSam Leffler 	return 0;
1193*39beb93cSSam Leffler }
1194*39beb93cSSam Leffler 
1195*39beb93cSSam Leffler 
1196*39beb93cSSam Leffler int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1197*39beb93cSSam Leffler 				    int ext_type, const u8 *data,
1198*39beb93cSSam Leffler 				    size_t data_len)
1199*39beb93cSSam Leffler {
1200*39beb93cSSam Leffler 	/* TODO */
1201*39beb93cSSam Leffler 	return -1;
1202*39beb93cSSam Leffler }
1203*39beb93cSSam Leffler 
1204*39beb93cSSam Leffler 
1205*39beb93cSSam Leffler int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1206*39beb93cSSam Leffler {
1207*39beb93cSSam Leffler 	if (conn == NULL)
1208*39beb93cSSam Leffler 		return -1;
1209*39beb93cSSam Leffler 	return conn->failed;
1210*39beb93cSSam Leffler }
1211*39beb93cSSam Leffler 
1212*39beb93cSSam Leffler 
1213*39beb93cSSam Leffler int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1214*39beb93cSSam Leffler {
1215*39beb93cSSam Leffler 	if (conn == NULL)
1216*39beb93cSSam Leffler 		return -1;
1217*39beb93cSSam Leffler 	return conn->read_alerts;
1218*39beb93cSSam Leffler }
1219*39beb93cSSam Leffler 
1220*39beb93cSSam Leffler 
1221*39beb93cSSam Leffler int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1222*39beb93cSSam Leffler {
1223*39beb93cSSam Leffler 	if (conn == NULL)
1224*39beb93cSSam Leffler 		return -1;
1225*39beb93cSSam Leffler 	return conn->write_alerts;
1226*39beb93cSSam Leffler }
1227*39beb93cSSam Leffler 
1228*39beb93cSSam Leffler 
1229*39beb93cSSam Leffler int tls_connection_get_keyblock_size(void *tls_ctx,
1230*39beb93cSSam Leffler 				     struct tls_connection *conn)
1231*39beb93cSSam Leffler {
1232*39beb93cSSam Leffler 	/* TODO */
1233*39beb93cSSam Leffler 	return -1;
1234*39beb93cSSam Leffler }
1235*39beb93cSSam Leffler 
1236*39beb93cSSam Leffler 
1237*39beb93cSSam Leffler unsigned int tls_capabilities(void *tls_ctx)
1238*39beb93cSSam Leffler {
1239*39beb93cSSam Leffler 	unsigned int capa = 0;
1240*39beb93cSSam Leffler 
1241*39beb93cSSam Leffler #ifdef GNUTLS_IA
1242*39beb93cSSam Leffler 	capa |= TLS_CAPABILITY_IA;
1243*39beb93cSSam Leffler #endif /* GNUTLS_IA */
1244*39beb93cSSam Leffler 
1245*39beb93cSSam Leffler 	return capa;
1246*39beb93cSSam Leffler }
1247*39beb93cSSam Leffler 
1248*39beb93cSSam Leffler 
1249*39beb93cSSam Leffler int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
1250*39beb93cSSam Leffler 			  int tls_ia)
1251*39beb93cSSam Leffler {
1252*39beb93cSSam Leffler #ifdef GNUTLS_IA
1253*39beb93cSSam Leffler 	int ret;
1254*39beb93cSSam Leffler 
1255*39beb93cSSam Leffler 	if (conn == NULL)
1256*39beb93cSSam Leffler 		return -1;
1257*39beb93cSSam Leffler 
1258*39beb93cSSam Leffler 	conn->tls_ia = tls_ia;
1259*39beb93cSSam Leffler 	if (!tls_ia)
1260*39beb93cSSam Leffler 		return 0;
1261*39beb93cSSam Leffler 
1262*39beb93cSSam Leffler 	ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv);
1263*39beb93cSSam Leffler 	if (ret) {
1264*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
1265*39beb93cSSam Leffler 			   gnutls_strerror(ret));
1266*39beb93cSSam Leffler 		return -1;
1267*39beb93cSSam Leffler 	}
1268*39beb93cSSam Leffler 
1269*39beb93cSSam Leffler 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
1270*39beb93cSSam Leffler 				     conn->iacred_srv);
1271*39beb93cSSam Leffler 	if (ret) {
1272*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
1273*39beb93cSSam Leffler 			   gnutls_strerror(ret));
1274*39beb93cSSam Leffler 		gnutls_ia_free_server_credentials(conn->iacred_srv);
1275*39beb93cSSam Leffler 		conn->iacred_srv = NULL;
1276*39beb93cSSam Leffler 		return -1;
1277*39beb93cSSam Leffler 	}
1278*39beb93cSSam Leffler 
1279*39beb93cSSam Leffler 	return 0;
1280*39beb93cSSam Leffler #else /* GNUTLS_IA */
1281*39beb93cSSam Leffler 	return -1;
1282*39beb93cSSam Leffler #endif /* GNUTLS_IA */
1283*39beb93cSSam Leffler }
1284*39beb93cSSam Leffler 
1285*39beb93cSSam Leffler 
1286*39beb93cSSam Leffler int tls_connection_ia_send_phase_finished(void *tls_ctx,
1287*39beb93cSSam Leffler 					  struct tls_connection *conn,
1288*39beb93cSSam Leffler 					  int final,
1289*39beb93cSSam Leffler 					  u8 *out_data, size_t out_len)
1290*39beb93cSSam Leffler {
1291*39beb93cSSam Leffler #ifdef GNUTLS_IA
1292*39beb93cSSam Leffler 	int ret;
1293*39beb93cSSam Leffler 
1294*39beb93cSSam Leffler 	if (conn == NULL || conn->session == NULL || !conn->tls_ia)
1295*39beb93cSSam Leffler 		return -1;
1296*39beb93cSSam Leffler 
1297*39beb93cSSam Leffler 	ret = gnutls_ia_permute_inner_secret(conn->session,
1298*39beb93cSSam Leffler 					     conn->session_keys_len,
1299*39beb93cSSam Leffler 					     (char *) conn->session_keys);
1300*39beb93cSSam Leffler 	if (conn->session_keys) {
1301*39beb93cSSam Leffler 		os_memset(conn->session_keys, 0, conn->session_keys_len);
1302*39beb93cSSam Leffler 		os_free(conn->session_keys);
1303*39beb93cSSam Leffler 	}
1304*39beb93cSSam Leffler 	conn->session_keys = NULL;
1305*39beb93cSSam Leffler 	conn->session_keys_len = 0;
1306*39beb93cSSam Leffler 	if (ret) {
1307*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s",
1308*39beb93cSSam Leffler 			   __func__, gnutls_strerror(ret));
1309*39beb93cSSam Leffler 		return -1;
1310*39beb93cSSam Leffler 	}
1311*39beb93cSSam Leffler 
1312*39beb93cSSam Leffler 	ret = gnutls_ia_endphase_send(conn->session, final);
1313*39beb93cSSam Leffler 	if (ret) {
1314*39beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s",
1315*39beb93cSSam Leffler 			   __func__, gnutls_strerror(ret));
1316*39beb93cSSam Leffler 		return -1;
1317*39beb93cSSam Leffler 	}
1318*39beb93cSSam Leffler 
1319*39beb93cSSam Leffler 	if (conn->push_buf == NULL)
1320*39beb93cSSam Leffler 		return -1;
1321*39beb93cSSam Leffler 	if (conn->push_buf_len < out_len)
1322*39beb93cSSam Leffler 		out_len = conn->push_buf_len;
1323*39beb93cSSam Leffler 	os_memcpy(out_data, conn->push_buf, out_len);
1324*39beb93cSSam Leffler 	os_free(conn->push_buf);
1325*39beb93cSSam Leffler 	conn->push_buf = NULL;
1326*39beb93cSSam Leffler 	conn->push_buf_len = 0;
1327*39beb93cSSam Leffler 	return out_len;
1328*39beb93cSSam Leffler #else /* GNUTLS_IA */
1329*39beb93cSSam Leffler 	return -1;
1330*39beb93cSSam Leffler #endif /* GNUTLS_IA */
1331*39beb93cSSam Leffler }
1332*39beb93cSSam Leffler 
1333*39beb93cSSam Leffler 
1334*39beb93cSSam Leffler int tls_connection_ia_final_phase_finished(void *tls_ctx,
1335*39beb93cSSam Leffler 					   struct tls_connection *conn)
1336*39beb93cSSam Leffler {
1337*39beb93cSSam Leffler 	if (conn == NULL)
1338*39beb93cSSam Leffler 		return -1;
1339*39beb93cSSam Leffler 
1340*39beb93cSSam Leffler 	return conn->final_phase_finished;
1341*39beb93cSSam Leffler }
1342*39beb93cSSam Leffler 
1343*39beb93cSSam Leffler 
1344*39beb93cSSam Leffler int tls_connection_ia_permute_inner_secret(void *tls_ctx,
1345*39beb93cSSam Leffler 					   struct tls_connection *conn,
1346*39beb93cSSam Leffler 					   const u8 *key, size_t key_len)
1347*39beb93cSSam Leffler {
1348*39beb93cSSam Leffler #ifdef GNUTLS_IA
1349*39beb93cSSam Leffler 	if (conn == NULL || !conn->tls_ia)
1350*39beb93cSSam Leffler 		return -1;
1351*39beb93cSSam Leffler 
1352*39beb93cSSam Leffler 	if (conn->session_keys) {
1353*39beb93cSSam Leffler 		os_memset(conn->session_keys, 0, conn->session_keys_len);
1354*39beb93cSSam Leffler 		os_free(conn->session_keys);
1355*39beb93cSSam Leffler 	}
1356*39beb93cSSam Leffler 	conn->session_keys_len = 0;
1357*39beb93cSSam Leffler 
1358*39beb93cSSam Leffler 	if (key) {
1359*39beb93cSSam Leffler 		conn->session_keys = os_malloc(key_len);
1360*39beb93cSSam Leffler 		if (conn->session_keys == NULL)
1361*39beb93cSSam Leffler 			return -1;
1362*39beb93cSSam Leffler 		os_memcpy(conn->session_keys, key, key_len);
1363*39beb93cSSam Leffler 		conn->session_keys_len = key_len;
1364*39beb93cSSam Leffler 	} else {
1365*39beb93cSSam Leffler 		conn->session_keys = NULL;
1366*39beb93cSSam Leffler 		conn->session_keys_len = 0;
1367*39beb93cSSam Leffler 	}
1368*39beb93cSSam Leffler 
1369*39beb93cSSam Leffler 	return 0;
1370*39beb93cSSam Leffler #else /* GNUTLS_IA */
1371*39beb93cSSam Leffler 	return -1;
1372*39beb93cSSam Leffler #endif /* GNUTLS_IA */
1373*39beb93cSSam Leffler }
1374