xref: /dflybsd-src/contrib/wpa_supplicant/src/crypto/tls_gnutls.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
16d49e1aeSJan Lentfer /*
23ff40c12SJohn Marino  * SSL/TLS interface functions for GnuTLS
3*a1157835SDaniel Fojt  * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
76d49e1aeSJan Lentfer  */
86d49e1aeSJan Lentfer 
96d49e1aeSJan Lentfer #include "includes.h"
106d49e1aeSJan Lentfer #include <gnutls/gnutls.h>
116d49e1aeSJan Lentfer #include <gnutls/x509.h>
126d49e1aeSJan Lentfer #ifdef PKCS12_FUNCS
136d49e1aeSJan Lentfer #include <gnutls/pkcs12.h>
146d49e1aeSJan Lentfer #endif /* PKCS12_FUNCS */
15*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x030103
16*a1157835SDaniel Fojt #include <gnutls/ocsp.h>
17*a1157835SDaniel Fojt #endif /* 3.1.3 */
186d49e1aeSJan Lentfer 
196d49e1aeSJan Lentfer #include "common.h"
20*a1157835SDaniel Fojt #include "crypto/crypto.h"
216d49e1aeSJan Lentfer #include "tls.h"
226d49e1aeSJan Lentfer 
236d49e1aeSJan Lentfer 
246d49e1aeSJan Lentfer static int tls_gnutls_ref_count = 0;
256d49e1aeSJan Lentfer 
266d49e1aeSJan Lentfer struct tls_global {
276d49e1aeSJan Lentfer 	/* Data for session resumption */
286d49e1aeSJan Lentfer 	void *session_data;
296d49e1aeSJan Lentfer 	size_t session_data_size;
306d49e1aeSJan Lentfer 
316d49e1aeSJan Lentfer 	int server;
326d49e1aeSJan Lentfer 
336d49e1aeSJan Lentfer 	int params_set;
346d49e1aeSJan Lentfer 	gnutls_certificate_credentials_t xcred;
35*a1157835SDaniel Fojt 
36*a1157835SDaniel Fojt 	void (*event_cb)(void *ctx, enum tls_event ev,
37*a1157835SDaniel Fojt 			 union tls_event_data *data);
38*a1157835SDaniel Fojt 	void *cb_ctx;
39*a1157835SDaniel Fojt 	int cert_in_cb;
40*a1157835SDaniel Fojt 
41*a1157835SDaniel Fojt 	char *ocsp_stapling_response;
426d49e1aeSJan Lentfer };
436d49e1aeSJan Lentfer 
446d49e1aeSJan Lentfer struct tls_connection {
45*a1157835SDaniel Fojt 	struct tls_global *global;
46*a1157835SDaniel Fojt 	gnutls_session_t session;
476d49e1aeSJan Lentfer 	int read_alerts, write_alerts, failed;
486d49e1aeSJan Lentfer 
496d49e1aeSJan Lentfer 	u8 *pre_shared_secret;
506d49e1aeSJan Lentfer 	size_t pre_shared_secret_len;
516d49e1aeSJan Lentfer 	int established;
526d49e1aeSJan Lentfer 	int verify_peer;
53*a1157835SDaniel Fojt 	unsigned int disable_time_checks:1;
546d49e1aeSJan Lentfer 
553ff40c12SJohn Marino 	struct wpabuf *push_buf;
563ff40c12SJohn Marino 	struct wpabuf *pull_buf;
573ff40c12SJohn Marino 	const u8 *pull_buf_offset;
586d49e1aeSJan Lentfer 
596d49e1aeSJan Lentfer 	int params_set;
606d49e1aeSJan Lentfer 	gnutls_certificate_credentials_t xcred;
61*a1157835SDaniel Fojt 
62*a1157835SDaniel Fojt 	char *suffix_match;
63*a1157835SDaniel Fojt 	char *domain_match;
64*a1157835SDaniel Fojt 	unsigned int flags;
656d49e1aeSJan Lentfer };
666d49e1aeSJan Lentfer 
676d49e1aeSJan Lentfer 
68*a1157835SDaniel Fojt static int tls_connection_verify_peer(gnutls_session_t session);
69*a1157835SDaniel Fojt 
70*a1157835SDaniel Fojt 
tls_log_func(int level,const char * msg)716d49e1aeSJan Lentfer static void tls_log_func(int level, const char *msg)
726d49e1aeSJan Lentfer {
736d49e1aeSJan Lentfer 	char *s, *pos;
746d49e1aeSJan Lentfer 	if (level == 6 || level == 7) {
756d49e1aeSJan Lentfer 		/* These levels seem to be mostly I/O debug and msg dumps */
766d49e1aeSJan Lentfer 		return;
776d49e1aeSJan Lentfer 	}
786d49e1aeSJan Lentfer 
796d49e1aeSJan Lentfer 	s = os_strdup(msg);
806d49e1aeSJan Lentfer 	if (s == NULL)
816d49e1aeSJan Lentfer 		return;
826d49e1aeSJan Lentfer 
836d49e1aeSJan Lentfer 	pos = s;
846d49e1aeSJan Lentfer 	while (*pos != '\0') {
856d49e1aeSJan Lentfer 		if (*pos == '\n') {
866d49e1aeSJan Lentfer 			*pos = '\0';
876d49e1aeSJan Lentfer 			break;
886d49e1aeSJan Lentfer 		}
896d49e1aeSJan Lentfer 		pos++;
906d49e1aeSJan Lentfer 	}
916d49e1aeSJan Lentfer 	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
926d49e1aeSJan Lentfer 		   "gnutls<%d> %s", level, s);
936d49e1aeSJan Lentfer 	os_free(s);
946d49e1aeSJan Lentfer }
956d49e1aeSJan Lentfer 
966d49e1aeSJan Lentfer 
tls_init(const struct tls_config * conf)976d49e1aeSJan Lentfer void * tls_init(const struct tls_config *conf)
986d49e1aeSJan Lentfer {
996d49e1aeSJan Lentfer 	struct tls_global *global;
1006d49e1aeSJan Lentfer 
101*a1157835SDaniel Fojt 	if (tls_gnutls_ref_count == 0) {
102*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
103*a1157835SDaniel Fojt 			   "GnuTLS: Library version %s (runtime) - %s (build)",
104*a1157835SDaniel Fojt 			   gnutls_check_version(NULL), GNUTLS_VERSION);
105*a1157835SDaniel Fojt 	}
1066d49e1aeSJan Lentfer 
1076d49e1aeSJan Lentfer 	global = os_zalloc(sizeof(*global));
1086d49e1aeSJan Lentfer 	if (global == NULL)
1096d49e1aeSJan Lentfer 		return NULL;
1106d49e1aeSJan Lentfer 
1116d49e1aeSJan Lentfer 	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
1126d49e1aeSJan Lentfer 		os_free(global);
1136d49e1aeSJan Lentfer 		return NULL;
1146d49e1aeSJan Lentfer 	}
1156d49e1aeSJan Lentfer 	tls_gnutls_ref_count++;
1166d49e1aeSJan Lentfer 
1176d49e1aeSJan Lentfer 	gnutls_global_set_log_function(tls_log_func);
1186d49e1aeSJan Lentfer 	if (wpa_debug_show_keys)
1196d49e1aeSJan Lentfer 		gnutls_global_set_log_level(11);
120*a1157835SDaniel Fojt 
121*a1157835SDaniel Fojt 	if (conf) {
122*a1157835SDaniel Fojt 		global->event_cb = conf->event_cb;
123*a1157835SDaniel Fojt 		global->cb_ctx = conf->cb_ctx;
124*a1157835SDaniel Fojt 		global->cert_in_cb = conf->cert_in_cb;
125*a1157835SDaniel Fojt 	}
126*a1157835SDaniel Fojt 
1276d49e1aeSJan Lentfer 	return global;
1286d49e1aeSJan Lentfer }
1296d49e1aeSJan Lentfer 
1306d49e1aeSJan Lentfer 
tls_deinit(void * ssl_ctx)1316d49e1aeSJan Lentfer void tls_deinit(void *ssl_ctx)
1326d49e1aeSJan Lentfer {
1336d49e1aeSJan Lentfer 	struct tls_global *global = ssl_ctx;
1346d49e1aeSJan Lentfer 	if (global) {
1356d49e1aeSJan Lentfer 		if (global->params_set)
1366d49e1aeSJan Lentfer 			gnutls_certificate_free_credentials(global->xcred);
1376d49e1aeSJan Lentfer 		os_free(global->session_data);
138*a1157835SDaniel Fojt 		os_free(global->ocsp_stapling_response);
1396d49e1aeSJan Lentfer 		os_free(global);
1406d49e1aeSJan Lentfer 	}
1416d49e1aeSJan Lentfer 
1426d49e1aeSJan Lentfer 	tls_gnutls_ref_count--;
1436d49e1aeSJan Lentfer 	if (tls_gnutls_ref_count == 0)
1446d49e1aeSJan Lentfer 		gnutls_global_deinit();
1456d49e1aeSJan Lentfer }
1466d49e1aeSJan Lentfer 
1476d49e1aeSJan Lentfer 
tls_get_errors(void * ssl_ctx)1486d49e1aeSJan Lentfer int tls_get_errors(void *ssl_ctx)
1496d49e1aeSJan Lentfer {
1506d49e1aeSJan Lentfer 	return 0;
1516d49e1aeSJan Lentfer }
1526d49e1aeSJan Lentfer 
1536d49e1aeSJan Lentfer 
tls_pull_func(gnutls_transport_ptr_t ptr,void * buf,size_t len)154*a1157835SDaniel Fojt static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
1556d49e1aeSJan Lentfer 			     size_t len)
1566d49e1aeSJan Lentfer {
1576d49e1aeSJan Lentfer 	struct tls_connection *conn = (struct tls_connection *) ptr;
1583ff40c12SJohn Marino 	const u8 *end;
1596d49e1aeSJan Lentfer 	if (conn->pull_buf == NULL) {
1606d49e1aeSJan Lentfer 		errno = EWOULDBLOCK;
1616d49e1aeSJan Lentfer 		return -1;
1626d49e1aeSJan Lentfer 	}
1636d49e1aeSJan Lentfer 
1643ff40c12SJohn Marino 	end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
1656d49e1aeSJan Lentfer 	if ((size_t) (end - conn->pull_buf_offset) < len)
1666d49e1aeSJan Lentfer 		len = end - conn->pull_buf_offset;
1676d49e1aeSJan Lentfer 	os_memcpy(buf, conn->pull_buf_offset, len);
1686d49e1aeSJan Lentfer 	conn->pull_buf_offset += len;
1696d49e1aeSJan Lentfer 	if (conn->pull_buf_offset == end) {
1706d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
1713ff40c12SJohn Marino 		wpabuf_free(conn->pull_buf);
1723ff40c12SJohn Marino 		conn->pull_buf = NULL;
1733ff40c12SJohn Marino 		conn->pull_buf_offset = NULL;
1746d49e1aeSJan Lentfer 	} else {
1756d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
1766d49e1aeSJan Lentfer 			   __func__,
1776d49e1aeSJan Lentfer 			   (unsigned long) (end - conn->pull_buf_offset));
1786d49e1aeSJan Lentfer 	}
1796d49e1aeSJan Lentfer 	return len;
1806d49e1aeSJan Lentfer }
1816d49e1aeSJan Lentfer 
1826d49e1aeSJan Lentfer 
tls_push_func(gnutls_transport_ptr_t ptr,const void * buf,size_t len)183*a1157835SDaniel Fojt static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
1846d49e1aeSJan Lentfer 			     size_t len)
1856d49e1aeSJan Lentfer {
1866d49e1aeSJan Lentfer 	struct tls_connection *conn = (struct tls_connection *) ptr;
1876d49e1aeSJan Lentfer 
1883ff40c12SJohn Marino 	if (wpabuf_resize(&conn->push_buf, len) < 0) {
1896d49e1aeSJan Lentfer 		errno = ENOMEM;
1906d49e1aeSJan Lentfer 		return -1;
1916d49e1aeSJan Lentfer 	}
1923ff40c12SJohn Marino 	wpabuf_put_data(conn->push_buf, buf, len);
1936d49e1aeSJan Lentfer 
1946d49e1aeSJan Lentfer 	return len;
1956d49e1aeSJan Lentfer }
1966d49e1aeSJan Lentfer 
1976d49e1aeSJan Lentfer 
tls_gnutls_init_session(struct tls_global * global,struct tls_connection * conn)1986d49e1aeSJan Lentfer static int tls_gnutls_init_session(struct tls_global *global,
1996d49e1aeSJan Lentfer 				   struct tls_connection *conn)
2006d49e1aeSJan Lentfer {
2013ff40c12SJohn Marino 	const char *err;
2026d49e1aeSJan Lentfer 	int ret;
2036d49e1aeSJan Lentfer 
2046d49e1aeSJan Lentfer 	ret = gnutls_init(&conn->session,
2056d49e1aeSJan Lentfer 			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
2066d49e1aeSJan Lentfer 	if (ret < 0) {
2076d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
2086d49e1aeSJan Lentfer 			   "connection: %s", gnutls_strerror(ret));
2096d49e1aeSJan Lentfer 		return -1;
2106d49e1aeSJan Lentfer 	}
2116d49e1aeSJan Lentfer 
2126d49e1aeSJan Lentfer 	ret = gnutls_set_default_priority(conn->session);
2136d49e1aeSJan Lentfer 	if (ret < 0)
2146d49e1aeSJan Lentfer 		goto fail;
2156d49e1aeSJan Lentfer 
2163ff40c12SJohn Marino 	ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
2173ff40c12SJohn Marino 					 &err);
2183ff40c12SJohn Marino 	if (ret < 0) {
2193ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
2203ff40c12SJohn Marino 			   "'%s'", err);
2213ff40c12SJohn Marino 		goto fail;
2223ff40c12SJohn Marino 	}
2236d49e1aeSJan Lentfer 
2246d49e1aeSJan Lentfer 	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
2256d49e1aeSJan Lentfer 	gnutls_transport_set_push_function(conn->session, tls_push_func);
226*a1157835SDaniel Fojt 	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
227*a1157835SDaniel Fojt 	gnutls_session_set_ptr(conn->session, conn);
2286d49e1aeSJan Lentfer 
2296d49e1aeSJan Lentfer 	return 0;
2306d49e1aeSJan Lentfer 
2316d49e1aeSJan Lentfer fail:
2326d49e1aeSJan Lentfer 	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
2336d49e1aeSJan Lentfer 		   gnutls_strerror(ret));
2346d49e1aeSJan Lentfer 	gnutls_deinit(conn->session);
2356d49e1aeSJan Lentfer 	return -1;
2366d49e1aeSJan Lentfer }
2376d49e1aeSJan Lentfer 
2386d49e1aeSJan Lentfer 
tls_connection_init(void * ssl_ctx)2396d49e1aeSJan Lentfer struct tls_connection * tls_connection_init(void *ssl_ctx)
2406d49e1aeSJan Lentfer {
2416d49e1aeSJan Lentfer 	struct tls_global *global = ssl_ctx;
2426d49e1aeSJan Lentfer 	struct tls_connection *conn;
2436d49e1aeSJan Lentfer 	int ret;
2446d49e1aeSJan Lentfer 
2456d49e1aeSJan Lentfer 	conn = os_zalloc(sizeof(*conn));
2466d49e1aeSJan Lentfer 	if (conn == NULL)
2476d49e1aeSJan Lentfer 		return NULL;
248*a1157835SDaniel Fojt 	conn->global = global;
2496d49e1aeSJan Lentfer 
2506d49e1aeSJan Lentfer 	if (tls_gnutls_init_session(global, conn)) {
2516d49e1aeSJan Lentfer 		os_free(conn);
2526d49e1aeSJan Lentfer 		return NULL;
2536d49e1aeSJan Lentfer 	}
2546d49e1aeSJan Lentfer 
2556d49e1aeSJan Lentfer 	if (global->params_set) {
2566d49e1aeSJan Lentfer 		ret = gnutls_credentials_set(conn->session,
2576d49e1aeSJan Lentfer 					     GNUTLS_CRD_CERTIFICATE,
2586d49e1aeSJan Lentfer 					     global->xcred);
2596d49e1aeSJan Lentfer 		if (ret < 0) {
2606d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "Failed to configure "
2616d49e1aeSJan Lentfer 				   "credentials: %s", gnutls_strerror(ret));
2626d49e1aeSJan Lentfer 			os_free(conn);
2636d49e1aeSJan Lentfer 			return NULL;
2646d49e1aeSJan Lentfer 		}
2656d49e1aeSJan Lentfer 	}
2666d49e1aeSJan Lentfer 
2676d49e1aeSJan Lentfer 	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
2686d49e1aeSJan Lentfer 		os_free(conn);
2696d49e1aeSJan Lentfer 		return NULL;
2706d49e1aeSJan Lentfer 	}
2716d49e1aeSJan Lentfer 
2726d49e1aeSJan Lentfer 	return conn;
2736d49e1aeSJan Lentfer }
2746d49e1aeSJan Lentfer 
2756d49e1aeSJan Lentfer 
tls_connection_deinit(void * ssl_ctx,struct tls_connection * conn)2766d49e1aeSJan Lentfer void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
2776d49e1aeSJan Lentfer {
2786d49e1aeSJan Lentfer 	if (conn == NULL)
2796d49e1aeSJan Lentfer 		return;
2806d49e1aeSJan Lentfer 
2816d49e1aeSJan Lentfer 	gnutls_certificate_free_credentials(conn->xcred);
2826d49e1aeSJan Lentfer 	gnutls_deinit(conn->session);
2836d49e1aeSJan Lentfer 	os_free(conn->pre_shared_secret);
2843ff40c12SJohn Marino 	wpabuf_free(conn->push_buf);
2853ff40c12SJohn Marino 	wpabuf_free(conn->pull_buf);
286*a1157835SDaniel Fojt 	os_free(conn->suffix_match);
287*a1157835SDaniel Fojt 	os_free(conn->domain_match);
2886d49e1aeSJan Lentfer 	os_free(conn);
2896d49e1aeSJan Lentfer }
2906d49e1aeSJan Lentfer 
2916d49e1aeSJan Lentfer 
tls_connection_established(void * ssl_ctx,struct tls_connection * conn)2926d49e1aeSJan Lentfer int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
2936d49e1aeSJan Lentfer {
2946d49e1aeSJan Lentfer 	return conn ? conn->established : 0;
2956d49e1aeSJan Lentfer }
2966d49e1aeSJan Lentfer 
2976d49e1aeSJan Lentfer 
tls_connection_peer_serial_num(void * tls_ctx,struct tls_connection * conn)298*a1157835SDaniel Fojt char * tls_connection_peer_serial_num(void *tls_ctx,
299*a1157835SDaniel Fojt 				      struct tls_connection *conn)
300*a1157835SDaniel Fojt {
301*a1157835SDaniel Fojt 	/* TODO */
302*a1157835SDaniel Fojt 	return NULL;
303*a1157835SDaniel Fojt }
304*a1157835SDaniel Fojt 
305*a1157835SDaniel Fojt 
tls_connection_shutdown(void * ssl_ctx,struct tls_connection * conn)3066d49e1aeSJan Lentfer int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
3076d49e1aeSJan Lentfer {
3086d49e1aeSJan Lentfer 	struct tls_global *global = ssl_ctx;
3096d49e1aeSJan Lentfer 	int ret;
3106d49e1aeSJan Lentfer 
3116d49e1aeSJan Lentfer 	if (conn == NULL)
3126d49e1aeSJan Lentfer 		return -1;
3136d49e1aeSJan Lentfer 
3146d49e1aeSJan Lentfer 	/* Shutdown previous TLS connection without notifying the peer
3156d49e1aeSJan Lentfer 	 * because the connection was already terminated in practice
3166d49e1aeSJan Lentfer 	 * and "close notify" shutdown alert would confuse AS. */
3176d49e1aeSJan Lentfer 	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
3183ff40c12SJohn Marino 	wpabuf_free(conn->push_buf);
3196d49e1aeSJan Lentfer 	conn->push_buf = NULL;
3206d49e1aeSJan Lentfer 	conn->established = 0;
3216d49e1aeSJan Lentfer 
3226d49e1aeSJan Lentfer 	gnutls_deinit(conn->session);
3236d49e1aeSJan Lentfer 	if (tls_gnutls_init_session(global, conn)) {
3246d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
3256d49e1aeSJan Lentfer 			   "for session resumption use");
3266d49e1aeSJan Lentfer 		return -1;
3276d49e1aeSJan Lentfer 	}
3286d49e1aeSJan Lentfer 
3296d49e1aeSJan Lentfer 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
3306d49e1aeSJan Lentfer 				     conn->params_set ? conn->xcred :
3316d49e1aeSJan Lentfer 				     global->xcred);
3326d49e1aeSJan Lentfer 	if (ret < 0) {
3336d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
3346d49e1aeSJan Lentfer 			   "for session resumption: %s", gnutls_strerror(ret));
3356d49e1aeSJan Lentfer 		return -1;
3366d49e1aeSJan Lentfer 	}
3376d49e1aeSJan Lentfer 
3386d49e1aeSJan Lentfer 	if (global->session_data) {
3396d49e1aeSJan Lentfer 		ret = gnutls_session_set_data(conn->session,
3406d49e1aeSJan Lentfer 					      global->session_data,
3416d49e1aeSJan Lentfer 					      global->session_data_size);
3426d49e1aeSJan Lentfer 		if (ret < 0) {
3436d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
3446d49e1aeSJan Lentfer 				   "data: %s", gnutls_strerror(ret));
3456d49e1aeSJan Lentfer 			return -1;
3466d49e1aeSJan Lentfer 		}
3476d49e1aeSJan Lentfer 	}
3486d49e1aeSJan Lentfer 
3496d49e1aeSJan Lentfer 	return 0;
3506d49e1aeSJan Lentfer }
3516d49e1aeSJan Lentfer 
3526d49e1aeSJan Lentfer 
tls_connection_set_params(void * tls_ctx,struct tls_connection * conn,const struct tls_connection_params * params)3536d49e1aeSJan Lentfer int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
3546d49e1aeSJan Lentfer 			      const struct tls_connection_params *params)
3556d49e1aeSJan Lentfer {
3566d49e1aeSJan Lentfer 	int ret;
357*a1157835SDaniel Fojt 	const char *err;
358*a1157835SDaniel Fojt 	char prio_buf[100];
359*a1157835SDaniel Fojt 	const char *prio = NULL;
3606d49e1aeSJan Lentfer 
3616d49e1aeSJan Lentfer 	if (conn == NULL || params == NULL)
3626d49e1aeSJan Lentfer 		return -1;
3636d49e1aeSJan Lentfer 
364*a1157835SDaniel Fojt 	if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
365*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
366*a1157835SDaniel Fojt 			   "GnuTLS: ocsp=3 not supported");
3676d49e1aeSJan Lentfer 		return -1;
3686d49e1aeSJan Lentfer 	}
3696d49e1aeSJan Lentfer 
370*a1157835SDaniel Fojt 	if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
371*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
372*a1157835SDaniel Fojt 			   "GnuTLS: tls_ext_cert_check=1 not supported");
373*a1157835SDaniel Fojt 		return -1;
374*a1157835SDaniel Fojt 	}
375*a1157835SDaniel Fojt 
376*a1157835SDaniel Fojt 	if (params->subject_match) {
377*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
378*a1157835SDaniel Fojt 		return -1;
379*a1157835SDaniel Fojt 	}
380*a1157835SDaniel Fojt 
3816d49e1aeSJan Lentfer 	if (params->altsubject_match) {
382*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
383*a1157835SDaniel Fojt 		return -1;
384*a1157835SDaniel Fojt 	}
385*a1157835SDaniel Fojt 
386*a1157835SDaniel Fojt 	os_free(conn->suffix_match);
387*a1157835SDaniel Fojt 	conn->suffix_match = NULL;
388*a1157835SDaniel Fojt 	if (params->suffix_match) {
389*a1157835SDaniel Fojt 		conn->suffix_match = os_strdup(params->suffix_match);
390*a1157835SDaniel Fojt 		if (conn->suffix_match == NULL)
391*a1157835SDaniel Fojt 			return -1;
392*a1157835SDaniel Fojt 	}
393*a1157835SDaniel Fojt 
394*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x030300
395*a1157835SDaniel Fojt 	os_free(conn->domain_match);
396*a1157835SDaniel Fojt 	conn->domain_match = NULL;
397*a1157835SDaniel Fojt 	if (params->domain_match) {
398*a1157835SDaniel Fojt 		conn->domain_match = os_strdup(params->domain_match);
399*a1157835SDaniel Fojt 		if (conn->domain_match == NULL)
400*a1157835SDaniel Fojt 			return -1;
401*a1157835SDaniel Fojt 	}
402*a1157835SDaniel Fojt #else /* < 3.3.0 */
403*a1157835SDaniel Fojt 	if (params->domain_match) {
404*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
405*a1157835SDaniel Fojt 		return -1;
406*a1157835SDaniel Fojt 	}
407*a1157835SDaniel Fojt #endif /* >= 3.3.0 */
408*a1157835SDaniel Fojt 
409*a1157835SDaniel Fojt 	conn->flags = params->flags;
410*a1157835SDaniel Fojt 
411*a1157835SDaniel Fojt 	if (params->flags & (TLS_CONN_DISABLE_TLSv1_0 |
412*a1157835SDaniel Fojt 			     TLS_CONN_DISABLE_TLSv1_1 |
413*a1157835SDaniel Fojt 			     TLS_CONN_DISABLE_TLSv1_2)) {
414*a1157835SDaniel Fojt 		os_snprintf(prio_buf, sizeof(prio_buf),
415*a1157835SDaniel Fojt 			    "NORMAL:-VERS-SSL3.0%s%s%s",
416*a1157835SDaniel Fojt 			    params->flags & TLS_CONN_DISABLE_TLSv1_0 ?
417*a1157835SDaniel Fojt 			    ":-VERS-TLS1.0" : "",
418*a1157835SDaniel Fojt 			    params->flags & TLS_CONN_DISABLE_TLSv1_1 ?
419*a1157835SDaniel Fojt 			    ":-VERS-TLS1.1" : "",
420*a1157835SDaniel Fojt 			    params->flags & TLS_CONN_DISABLE_TLSv1_2 ?
421*a1157835SDaniel Fojt 			    ":-VERS-TLS1.2" : "");
422*a1157835SDaniel Fojt 		prio = prio_buf;
423*a1157835SDaniel Fojt 	}
424*a1157835SDaniel Fojt 
425*a1157835SDaniel Fojt 	if (params->openssl_ciphers) {
426*a1157835SDaniel Fojt 		if (os_strcmp(params->openssl_ciphers, "SUITEB128") == 0) {
427*a1157835SDaniel Fojt 			prio = "SUITEB128";
428*a1157835SDaniel Fojt 		} else if (os_strcmp(params->openssl_ciphers,
429*a1157835SDaniel Fojt 				     "SUITEB192") == 0) {
430*a1157835SDaniel Fojt 			prio = "SUITEB192";
431*a1157835SDaniel Fojt 		} else if ((params->flags & TLS_CONN_SUITEB) &&
432*a1157835SDaniel Fojt 			   os_strcmp(params->openssl_ciphers,
433*a1157835SDaniel Fojt 				     "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
434*a1157835SDaniel Fojt 			prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
435*a1157835SDaniel Fojt 		} else if (os_strcmp(params->openssl_ciphers,
436*a1157835SDaniel Fojt 				     "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
437*a1157835SDaniel Fojt 			prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
438*a1157835SDaniel Fojt 		} else if (os_strcmp(params->openssl_ciphers,
439*a1157835SDaniel Fojt 				     "DHE-RSA-AES256-GCM-SHA384") == 0) {
440*a1157835SDaniel Fojt 			prio = "NONE:+VERS-TLS1.2:+AEAD:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
441*a1157835SDaniel Fojt 		} else if (os_strcmp(params->openssl_ciphers,
442*a1157835SDaniel Fojt 				     "ECDHE-ECDSA-AES256-GCM-SHA384") == 0) {
443*a1157835SDaniel Fojt 			prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
444*a1157835SDaniel Fojt 		} else {
445*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
446*a1157835SDaniel Fojt 				   "GnuTLS: openssl_ciphers not supported");
447*a1157835SDaniel Fojt 			return -1;
448*a1157835SDaniel Fojt 		}
449*a1157835SDaniel Fojt 	} else if (params->flags & TLS_CONN_SUITEB) {
450*a1157835SDaniel Fojt 		prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
451*a1157835SDaniel Fojt 	}
452*a1157835SDaniel Fojt 
453*a1157835SDaniel Fojt 	if (prio) {
454*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "GnuTLS: Set priority string: %s", prio);
455*a1157835SDaniel Fojt 		ret = gnutls_priority_set_direct(conn->session, prio, &err);
456*a1157835SDaniel Fojt 		if (ret < 0) {
457*a1157835SDaniel Fojt 			wpa_printf(MSG_ERROR,
458*a1157835SDaniel Fojt 				   "GnuTLS: Priority string failure at '%s'",
459*a1157835SDaniel Fojt 				   err);
460*a1157835SDaniel Fojt 			return -1;
461*a1157835SDaniel Fojt 		}
462*a1157835SDaniel Fojt 	}
463*a1157835SDaniel Fojt 
464*a1157835SDaniel Fojt 	if (params->openssl_ecdh_curves) {
465*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
466*a1157835SDaniel Fojt 			   "GnuTLS: openssl_ecdh_curves not supported");
4676d49e1aeSJan Lentfer 		return -1;
4686d49e1aeSJan Lentfer 	}
4696d49e1aeSJan Lentfer 
4706d49e1aeSJan Lentfer 	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
4716d49e1aeSJan Lentfer 	 * to force peer validation(?) */
4726d49e1aeSJan Lentfer 
4736d49e1aeSJan Lentfer 	if (params->ca_cert) {
474*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
475*a1157835SDaniel Fojt 			   params->ca_cert);
4766d49e1aeSJan Lentfer 		ret = gnutls_certificate_set_x509_trust_file(
477*a1157835SDaniel Fojt 			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
4786d49e1aeSJan Lentfer 		if (ret < 0) {
479*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
480*a1157835SDaniel Fojt 				   "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
481*a1157835SDaniel Fojt 				   params->ca_cert,
4826d49e1aeSJan Lentfer 				   gnutls_strerror(ret));
4836d49e1aeSJan Lentfer 			ret = gnutls_certificate_set_x509_trust_file(
4846d49e1aeSJan Lentfer 				conn->xcred, params->ca_cert,
485*a1157835SDaniel Fojt 				GNUTLS_X509_FMT_PEM);
4866d49e1aeSJan Lentfer 			if (ret < 0) {
487*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
488*a1157835SDaniel Fojt 					   "Failed to read CA cert '%s' in PEM format: %s",
4896d49e1aeSJan Lentfer 					   params->ca_cert,
4906d49e1aeSJan Lentfer 					   gnutls_strerror(ret));
4916d49e1aeSJan Lentfer 				return -1;
4926d49e1aeSJan Lentfer 			}
493*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
494*a1157835SDaniel Fojt 				   "GnuTLS: Successfully read CA cert '%s' in PEM format",
495*a1157835SDaniel Fojt 				   params->ca_cert);
496*a1157835SDaniel Fojt 		} else {
497*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
498*a1157835SDaniel Fojt 				   "GnuTLS: Successfully read CA cert '%s' in DER format",
499*a1157835SDaniel Fojt 				   params->ca_cert);
5006d49e1aeSJan Lentfer 		}
501*a1157835SDaniel Fojt 	} else if (params->ca_cert_blob) {
502*a1157835SDaniel Fojt 		gnutls_datum_t ca;
503*a1157835SDaniel Fojt 
504*a1157835SDaniel Fojt 		ca.data = (unsigned char *) params->ca_cert_blob;
505*a1157835SDaniel Fojt 		ca.size = params->ca_cert_blob_len;
506*a1157835SDaniel Fojt 
507*a1157835SDaniel Fojt 		ret = gnutls_certificate_set_x509_trust_mem(
508*a1157835SDaniel Fojt 			conn->xcred, &ca, GNUTLS_X509_FMT_DER);
509*a1157835SDaniel Fojt 		if (ret < 0) {
510*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
511*a1157835SDaniel Fojt 				   "Failed to parse CA cert in DER format: %s",
512*a1157835SDaniel Fojt 				   gnutls_strerror(ret));
513*a1157835SDaniel Fojt 			ret = gnutls_certificate_set_x509_trust_mem(
514*a1157835SDaniel Fojt 				conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
515*a1157835SDaniel Fojt 			if (ret < 0) {
516*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG,
517*a1157835SDaniel Fojt 					   "Failed to parse CA cert in PEM format: %s",
518*a1157835SDaniel Fojt 					   gnutls_strerror(ret));
519*a1157835SDaniel Fojt 				return -1;
520*a1157835SDaniel Fojt 			}
521*a1157835SDaniel Fojt 		}
522*a1157835SDaniel Fojt 	} else if (params->ca_path) {
523*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
524*a1157835SDaniel Fojt 		return -1;
525*a1157835SDaniel Fojt 	}
526*a1157835SDaniel Fojt 
527*a1157835SDaniel Fojt 	conn->disable_time_checks = 0;
528*a1157835SDaniel Fojt 	if (params->ca_cert || params->ca_cert_blob) {
529*a1157835SDaniel Fojt 		conn->verify_peer = 1;
530*a1157835SDaniel Fojt 		gnutls_certificate_set_verify_function(
531*a1157835SDaniel Fojt 			conn->xcred, tls_connection_verify_peer);
5326d49e1aeSJan Lentfer 
5336d49e1aeSJan Lentfer 		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
5346d49e1aeSJan Lentfer 			gnutls_certificate_set_verify_flags(
5356d49e1aeSJan Lentfer 				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
5366d49e1aeSJan Lentfer 		}
5376d49e1aeSJan Lentfer 
5386d49e1aeSJan Lentfer 		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
539*a1157835SDaniel Fojt 			conn->disable_time_checks = 1;
5406d49e1aeSJan Lentfer 			gnutls_certificate_set_verify_flags(
5416d49e1aeSJan Lentfer 				conn->xcred,
5426d49e1aeSJan Lentfer 				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
5436d49e1aeSJan Lentfer 		}
5446d49e1aeSJan Lentfer 	}
5456d49e1aeSJan Lentfer 
5466d49e1aeSJan Lentfer 	if (params->client_cert && params->private_key) {
547*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
548*a1157835SDaniel Fojt 			   "GnuTLS: Try to parse client cert '%s' and key '%s' in DER format",
549*a1157835SDaniel Fojt 			   params->client_cert, params->private_key);
550*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x03010b
551*a1157835SDaniel Fojt 		ret = gnutls_certificate_set_x509_key_file2(
552*a1157835SDaniel Fojt 			conn->xcred, params->client_cert, params->private_key,
553*a1157835SDaniel Fojt 			GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
554*a1157835SDaniel Fojt #else
555*a1157835SDaniel Fojt 		/* private_key_passwd not (easily) supported here */
5566d49e1aeSJan Lentfer 		ret = gnutls_certificate_set_x509_key_file(
5576d49e1aeSJan Lentfer 			conn->xcred, params->client_cert, params->private_key,
558*a1157835SDaniel Fojt 			GNUTLS_X509_FMT_DER);
559*a1157835SDaniel Fojt #endif
5606d49e1aeSJan Lentfer 		if (ret < 0) {
561*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
562*a1157835SDaniel Fojt 				   "GnuTLS: Failed to read client cert/key in DER format (%s) - try in PEM format",
563*a1157835SDaniel Fojt 				   gnutls_strerror(ret));
564*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x03010b
565*a1157835SDaniel Fojt 			ret = gnutls_certificate_set_x509_key_file2(
566*a1157835SDaniel Fojt 				conn->xcred, params->client_cert,
567*a1157835SDaniel Fojt 				params->private_key, GNUTLS_X509_FMT_PEM,
568*a1157835SDaniel Fojt 				params->private_key_passwd, 0);
569*a1157835SDaniel Fojt #else
5706d49e1aeSJan Lentfer 			ret = gnutls_certificate_set_x509_key_file(
5716d49e1aeSJan Lentfer 				conn->xcred, params->client_cert,
572*a1157835SDaniel Fojt 				params->private_key, GNUTLS_X509_FMT_PEM);
573*a1157835SDaniel Fojt #endif
5746d49e1aeSJan Lentfer 			if (ret < 0) {
5756d49e1aeSJan Lentfer 				wpa_printf(MSG_DEBUG, "Failed to read client "
576*a1157835SDaniel Fojt 					   "cert/key in PEM format: %s",
5776d49e1aeSJan Lentfer 					   gnutls_strerror(ret));
5786d49e1aeSJan Lentfer 				return ret;
5796d49e1aeSJan Lentfer 			}
580*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
581*a1157835SDaniel Fojt 				   "GnuTLS: Successfully read client cert/key in PEM format");
582*a1157835SDaniel Fojt 		} else {
583*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
584*a1157835SDaniel Fojt 				   "GnuTLS: Successfully read client cert/key in DER format");
5856d49e1aeSJan Lentfer 		}
5866d49e1aeSJan Lentfer 	} else if (params->private_key) {
5876d49e1aeSJan Lentfer 		int pkcs12_ok = 0;
5886d49e1aeSJan Lentfer #ifdef PKCS12_FUNCS
5896d49e1aeSJan Lentfer 		/* Try to load in PKCS#12 format */
590*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
591*a1157835SDaniel Fojt 			   "GnuTLS: Try to parse client cert/key '%s'in PKCS#12 DER format",
592*a1157835SDaniel Fojt 			   params->private_key);
5936d49e1aeSJan Lentfer 		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
5946d49e1aeSJan Lentfer 			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
5956d49e1aeSJan Lentfer 			params->private_key_passwd);
5966d49e1aeSJan Lentfer 		if (ret != 0) {
5976d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
5986d49e1aeSJan Lentfer 				   "PKCS#12 format: %s", gnutls_strerror(ret));
5996d49e1aeSJan Lentfer 			return -1;
6006d49e1aeSJan Lentfer 		} else
6016d49e1aeSJan Lentfer 			pkcs12_ok = 1;
6026d49e1aeSJan Lentfer #endif /* PKCS12_FUNCS */
6036d49e1aeSJan Lentfer 
6046d49e1aeSJan Lentfer 		if (!pkcs12_ok) {
6056d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
6066d49e1aeSJan Lentfer 				   "included");
6076d49e1aeSJan Lentfer 			return -1;
6086d49e1aeSJan Lentfer 		}
609*a1157835SDaniel Fojt 	} else if (params->client_cert_blob && params->private_key_blob) {
610*a1157835SDaniel Fojt 		gnutls_datum_t cert, key;
611*a1157835SDaniel Fojt 
612*a1157835SDaniel Fojt 		cert.data = (unsigned char *) params->client_cert_blob;
613*a1157835SDaniel Fojt 		cert.size = params->client_cert_blob_len;
614*a1157835SDaniel Fojt 		key.data = (unsigned char *) params->private_key_blob;
615*a1157835SDaniel Fojt 		key.size = params->private_key_blob_len;
616*a1157835SDaniel Fojt 
617*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x03010b
618*a1157835SDaniel Fojt 		ret = gnutls_certificate_set_x509_key_mem2(
619*a1157835SDaniel Fojt 			conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
620*a1157835SDaniel Fojt 			params->private_key_passwd, 0);
621*a1157835SDaniel Fojt #else
622*a1157835SDaniel Fojt 		/* private_key_passwd not (easily) supported here */
623*a1157835SDaniel Fojt 		ret = gnutls_certificate_set_x509_key_mem(
624*a1157835SDaniel Fojt 			conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
625*a1157835SDaniel Fojt #endif
626*a1157835SDaniel Fojt 		if (ret < 0) {
627*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
628*a1157835SDaniel Fojt 				   "in DER format: %s", gnutls_strerror(ret));
629*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x03010b
630*a1157835SDaniel Fojt 			ret = gnutls_certificate_set_x509_key_mem2(
631*a1157835SDaniel Fojt 				conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
632*a1157835SDaniel Fojt 				params->private_key_passwd, 0);
633*a1157835SDaniel Fojt #else
634*a1157835SDaniel Fojt 			/* private_key_passwd not (easily) supported here */
635*a1157835SDaniel Fojt 			ret = gnutls_certificate_set_x509_key_mem(
636*a1157835SDaniel Fojt 				conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
637*a1157835SDaniel Fojt #endif
638*a1157835SDaniel Fojt 			if (ret < 0) {
639*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG, "Failed to read client "
640*a1157835SDaniel Fojt 					   "cert/key in PEM format: %s",
641*a1157835SDaniel Fojt 					   gnutls_strerror(ret));
642*a1157835SDaniel Fojt 				return ret;
6436d49e1aeSJan Lentfer 			}
644*a1157835SDaniel Fojt 		}
645*a1157835SDaniel Fojt 	} else if (params->private_key_blob) {
646*a1157835SDaniel Fojt #ifdef PKCS12_FUNCS
647*a1157835SDaniel Fojt 		gnutls_datum_t key;
648*a1157835SDaniel Fojt 
649*a1157835SDaniel Fojt 		key.data = (unsigned char *) params->private_key_blob;
650*a1157835SDaniel Fojt 		key.size = params->private_key_blob_len;
651*a1157835SDaniel Fojt 
652*a1157835SDaniel Fojt 		/* Try to load in PKCS#12 format */
653*a1157835SDaniel Fojt 		ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
654*a1157835SDaniel Fojt 			conn->xcred, &key, GNUTLS_X509_FMT_DER,
655*a1157835SDaniel Fojt 			params->private_key_passwd);
656*a1157835SDaniel Fojt 		if (ret != 0) {
657*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
658*a1157835SDaniel Fojt 				   "PKCS#12 format: %s", gnutls_strerror(ret));
659*a1157835SDaniel Fojt 			return -1;
660*a1157835SDaniel Fojt 		}
661*a1157835SDaniel Fojt #else /* PKCS12_FUNCS */
662*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
663*a1157835SDaniel Fojt 		return -1;
664*a1157835SDaniel Fojt #endif /* PKCS12_FUNCS */
665*a1157835SDaniel Fojt 	}
666*a1157835SDaniel Fojt 
667*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x030103
668*a1157835SDaniel Fojt 	if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
669*a1157835SDaniel Fojt 		ret = gnutls_ocsp_status_request_enable_client(conn->session,
670*a1157835SDaniel Fojt 							       NULL, 0, NULL);
671*a1157835SDaniel Fojt 		if (ret != GNUTLS_E_SUCCESS) {
672*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
673*a1157835SDaniel Fojt 				   "GnuTLS: Failed to enable OCSP client");
674*a1157835SDaniel Fojt 			return -1;
675*a1157835SDaniel Fojt 		}
676*a1157835SDaniel Fojt 	}
677*a1157835SDaniel Fojt #else /* 3.1.3 */
678*a1157835SDaniel Fojt 	if (params->flags & TLS_CONN_REQUIRE_OCSP) {
679*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
680*a1157835SDaniel Fojt 			   "GnuTLS: OCSP not supported by this version of GnuTLS");
681*a1157835SDaniel Fojt 		return -1;
682*a1157835SDaniel Fojt 	}
683*a1157835SDaniel Fojt #endif /* 3.1.3 */
6846d49e1aeSJan Lentfer 
6856d49e1aeSJan Lentfer 	conn->params_set = 1;
6866d49e1aeSJan Lentfer 
6876d49e1aeSJan Lentfer 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
6886d49e1aeSJan Lentfer 				     conn->xcred);
6896d49e1aeSJan Lentfer 	if (ret < 0) {
6906d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
6916d49e1aeSJan Lentfer 			   gnutls_strerror(ret));
6926d49e1aeSJan Lentfer 	}
6936d49e1aeSJan Lentfer 
6946d49e1aeSJan Lentfer 	return ret;
6956d49e1aeSJan Lentfer }
6966d49e1aeSJan Lentfer 
6976d49e1aeSJan Lentfer 
698*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x030103
server_ocsp_status_req(gnutls_session_t session,void * ptr,gnutls_datum_t * resp)699*a1157835SDaniel Fojt static int server_ocsp_status_req(gnutls_session_t session, void *ptr,
700*a1157835SDaniel Fojt 				  gnutls_datum_t *resp)
701*a1157835SDaniel Fojt {
702*a1157835SDaniel Fojt 	struct tls_global *global = ptr;
703*a1157835SDaniel Fojt 	char *cached;
704*a1157835SDaniel Fojt 	size_t len;
705*a1157835SDaniel Fojt 
706*a1157835SDaniel Fojt 	if (!global->ocsp_stapling_response) {
707*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
708*a1157835SDaniel Fojt 		return GNUTLS_E_NO_CERTIFICATE_STATUS;
709*a1157835SDaniel Fojt 	}
710*a1157835SDaniel Fojt 
711*a1157835SDaniel Fojt 	cached = os_readfile(global->ocsp_stapling_response, &len);
712*a1157835SDaniel Fojt 	if (!cached) {
713*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
714*a1157835SDaniel Fojt 			   "GnuTLS: OCSP status callback - could not read response file (%s)",
715*a1157835SDaniel Fojt 			   global->ocsp_stapling_response);
716*a1157835SDaniel Fojt 		return GNUTLS_E_NO_CERTIFICATE_STATUS;
717*a1157835SDaniel Fojt 	}
718*a1157835SDaniel Fojt 
719*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG,
720*a1157835SDaniel Fojt 		   "GnuTLS: OCSP status callback - send cached response");
721*a1157835SDaniel Fojt 	resp->data = gnutls_malloc(len);
722*a1157835SDaniel Fojt 	if (!resp->data) {
723*a1157835SDaniel Fojt 		os_free(resp);
724*a1157835SDaniel Fojt 		return GNUTLS_E_MEMORY_ERROR;
725*a1157835SDaniel Fojt 	}
726*a1157835SDaniel Fojt 
727*a1157835SDaniel Fojt 	os_memcpy(resp->data, cached, len);
728*a1157835SDaniel Fojt 	resp->size = len;
729*a1157835SDaniel Fojt 	os_free(cached);
730*a1157835SDaniel Fojt 
731*a1157835SDaniel Fojt 	return GNUTLS_E_SUCCESS;
732*a1157835SDaniel Fojt }
733*a1157835SDaniel Fojt #endif /* 3.1.3 */
734*a1157835SDaniel Fojt 
735*a1157835SDaniel Fojt 
tls_global_set_params(void * tls_ctx,const struct tls_connection_params * params)7366d49e1aeSJan Lentfer int tls_global_set_params(void *tls_ctx,
7376d49e1aeSJan Lentfer 			  const struct tls_connection_params *params)
7386d49e1aeSJan Lentfer {
7396d49e1aeSJan Lentfer 	struct tls_global *global = tls_ctx;
7406d49e1aeSJan Lentfer 	int ret;
7416d49e1aeSJan Lentfer 
742*a1157835SDaniel Fojt 	if (params->check_cert_subject)
743*a1157835SDaniel Fojt 		return -1; /* not yet supported */
744*a1157835SDaniel Fojt 
7456d49e1aeSJan Lentfer 	/* Currently, global parameters are only set when running in server
7466d49e1aeSJan Lentfer 	 * mode. */
7476d49e1aeSJan Lentfer 	global->server = 1;
7486d49e1aeSJan Lentfer 
7496d49e1aeSJan Lentfer 	if (global->params_set) {
7506d49e1aeSJan Lentfer 		gnutls_certificate_free_credentials(global->xcred);
7516d49e1aeSJan Lentfer 		global->params_set = 0;
7526d49e1aeSJan Lentfer 	}
7536d49e1aeSJan Lentfer 
7546d49e1aeSJan Lentfer 	ret = gnutls_certificate_allocate_credentials(&global->xcred);
7556d49e1aeSJan Lentfer 	if (ret) {
7566d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
7576d49e1aeSJan Lentfer 			   "%s", gnutls_strerror(ret));
7586d49e1aeSJan Lentfer 		return -1;
7596d49e1aeSJan Lentfer 	}
7606d49e1aeSJan Lentfer 
7616d49e1aeSJan Lentfer 	if (params->ca_cert) {
7626d49e1aeSJan Lentfer 		ret = gnutls_certificate_set_x509_trust_file(
763*a1157835SDaniel Fojt 			global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
7646d49e1aeSJan Lentfer 		if (ret < 0) {
7656d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
766*a1157835SDaniel Fojt 				   "in DER format: %s", params->ca_cert,
7676d49e1aeSJan Lentfer 				   gnutls_strerror(ret));
7686d49e1aeSJan Lentfer 			ret = gnutls_certificate_set_x509_trust_file(
7696d49e1aeSJan Lentfer 				global->xcred, params->ca_cert,
770*a1157835SDaniel Fojt 				GNUTLS_X509_FMT_PEM);
7716d49e1aeSJan Lentfer 			if (ret < 0) {
7726d49e1aeSJan Lentfer 				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
773*a1157835SDaniel Fojt 					   "'%s' in PEM format: %s",
7746d49e1aeSJan Lentfer 					   params->ca_cert,
7756d49e1aeSJan Lentfer 					   gnutls_strerror(ret));
7766d49e1aeSJan Lentfer 				goto fail;
7776d49e1aeSJan Lentfer 			}
7786d49e1aeSJan Lentfer 		}
7796d49e1aeSJan Lentfer 
7806d49e1aeSJan Lentfer 		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
7816d49e1aeSJan Lentfer 			gnutls_certificate_set_verify_flags(
7826d49e1aeSJan Lentfer 				global->xcred,
7836d49e1aeSJan Lentfer 				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
7846d49e1aeSJan Lentfer 		}
7856d49e1aeSJan Lentfer 
7866d49e1aeSJan Lentfer 		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
7876d49e1aeSJan Lentfer 			gnutls_certificate_set_verify_flags(
7886d49e1aeSJan Lentfer 				global->xcred,
7896d49e1aeSJan Lentfer 				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
7906d49e1aeSJan Lentfer 		}
7916d49e1aeSJan Lentfer 	}
7926d49e1aeSJan Lentfer 
7936d49e1aeSJan Lentfer 	if (params->client_cert && params->private_key) {
7946d49e1aeSJan Lentfer 		/* TODO: private_key_passwd? */
7956d49e1aeSJan Lentfer 		ret = gnutls_certificate_set_x509_key_file(
7966d49e1aeSJan Lentfer 			global->xcred, params->client_cert,
7976d49e1aeSJan Lentfer 			params->private_key, GNUTLS_X509_FMT_DER);
7986d49e1aeSJan Lentfer 		if (ret < 0) {
799*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
800*a1157835SDaniel Fojt 				   "in DER format: %s", gnutls_strerror(ret));
801*a1157835SDaniel Fojt 			ret = gnutls_certificate_set_x509_key_file(
802*a1157835SDaniel Fojt 				global->xcred, params->client_cert,
803*a1157835SDaniel Fojt 				params->private_key, GNUTLS_X509_FMT_PEM);
804*a1157835SDaniel Fojt 			if (ret < 0) {
8056d49e1aeSJan Lentfer 				wpa_printf(MSG_DEBUG, "Failed to read client "
806*a1157835SDaniel Fojt 					   "cert/key in PEM format: %s",
8076d49e1aeSJan Lentfer 					   gnutls_strerror(ret));
8086d49e1aeSJan Lentfer 				goto fail;
8096d49e1aeSJan Lentfer 			}
8106d49e1aeSJan Lentfer 		}
8116d49e1aeSJan Lentfer 	} else if (params->private_key) {
8126d49e1aeSJan Lentfer 		int pkcs12_ok = 0;
8136d49e1aeSJan Lentfer #ifdef PKCS12_FUNCS
8146d49e1aeSJan Lentfer 		/* Try to load in PKCS#12 format */
8156d49e1aeSJan Lentfer 		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
8166d49e1aeSJan Lentfer 			global->xcred, params->private_key,
8176d49e1aeSJan Lentfer 			GNUTLS_X509_FMT_DER, params->private_key_passwd);
8186d49e1aeSJan Lentfer 		if (ret != 0) {
8196d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
8206d49e1aeSJan Lentfer 				   "PKCS#12 format: %s", gnutls_strerror(ret));
8216d49e1aeSJan Lentfer 			goto fail;
8226d49e1aeSJan Lentfer 		} else
8236d49e1aeSJan Lentfer 			pkcs12_ok = 1;
8246d49e1aeSJan Lentfer #endif /* PKCS12_FUNCS */
8256d49e1aeSJan Lentfer 
8266d49e1aeSJan Lentfer 		if (!pkcs12_ok) {
8276d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
8286d49e1aeSJan Lentfer 				   "included");
8296d49e1aeSJan Lentfer 			goto fail;
8306d49e1aeSJan Lentfer 		}
8316d49e1aeSJan Lentfer 	}
8326d49e1aeSJan Lentfer 
833*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x030103
834*a1157835SDaniel Fojt 	os_free(global->ocsp_stapling_response);
835*a1157835SDaniel Fojt 	if (params->ocsp_stapling_response)
836*a1157835SDaniel Fojt 		global->ocsp_stapling_response =
837*a1157835SDaniel Fojt 			os_strdup(params->ocsp_stapling_response);
838*a1157835SDaniel Fojt 	else
839*a1157835SDaniel Fojt 		global->ocsp_stapling_response = NULL;
840*a1157835SDaniel Fojt 	gnutls_certificate_set_ocsp_status_request_function(
841*a1157835SDaniel Fojt 		global->xcred, server_ocsp_status_req, global);
842*a1157835SDaniel Fojt #endif /* 3.1.3 */
843*a1157835SDaniel Fojt 
8446d49e1aeSJan Lentfer 	global->params_set = 1;
8456d49e1aeSJan Lentfer 
8466d49e1aeSJan Lentfer 	return 0;
8476d49e1aeSJan Lentfer 
8486d49e1aeSJan Lentfer fail:
8496d49e1aeSJan Lentfer 	gnutls_certificate_free_credentials(global->xcred);
8506d49e1aeSJan Lentfer 	return -1;
8516d49e1aeSJan Lentfer }
8526d49e1aeSJan Lentfer 
8536d49e1aeSJan Lentfer 
tls_global_set_verify(void * ssl_ctx,int check_crl,int strict)854*a1157835SDaniel Fojt int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
8556d49e1aeSJan Lentfer {
8566d49e1aeSJan Lentfer 	/* TODO */
8576d49e1aeSJan Lentfer 	return 0;
8586d49e1aeSJan Lentfer }
8596d49e1aeSJan Lentfer 
8606d49e1aeSJan Lentfer 
tls_connection_set_verify(void * ssl_ctx,struct tls_connection * conn,int verify_peer,unsigned int flags,const u8 * session_ctx,size_t session_ctx_len)8616d49e1aeSJan Lentfer int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
862*a1157835SDaniel Fojt 			      int verify_peer, unsigned int flags,
863*a1157835SDaniel Fojt 			      const u8 *session_ctx, size_t session_ctx_len)
8646d49e1aeSJan Lentfer {
8656d49e1aeSJan Lentfer 	if (conn == NULL || conn->session == NULL)
8666d49e1aeSJan Lentfer 		return -1;
8676d49e1aeSJan Lentfer 
8686d49e1aeSJan Lentfer 	conn->verify_peer = verify_peer;
8696d49e1aeSJan Lentfer 	gnutls_certificate_server_set_request(conn->session,
8706d49e1aeSJan Lentfer 					      verify_peer ? GNUTLS_CERT_REQUIRE
8716d49e1aeSJan Lentfer 					      : GNUTLS_CERT_REQUEST);
8726d49e1aeSJan Lentfer 
8736d49e1aeSJan Lentfer 	return 0;
8746d49e1aeSJan Lentfer }
8756d49e1aeSJan Lentfer 
8766d49e1aeSJan Lentfer 
tls_connection_get_random(void * ssl_ctx,struct tls_connection * conn,struct tls_random * keys)877*a1157835SDaniel Fojt int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
878*a1157835SDaniel Fojt 			    struct tls_random *keys)
8796d49e1aeSJan Lentfer {
880*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x030012
881*a1157835SDaniel Fojt 	gnutls_datum_t client, server;
8826d49e1aeSJan Lentfer 
8836d49e1aeSJan Lentfer 	if (conn == NULL || conn->session == NULL || keys == NULL)
8846d49e1aeSJan Lentfer 		return -1;
8856d49e1aeSJan Lentfer 
8866d49e1aeSJan Lentfer 	os_memset(keys, 0, sizeof(*keys));
887*a1157835SDaniel Fojt 	gnutls_session_get_random(conn->session, &client, &server);
888*a1157835SDaniel Fojt 	keys->client_random = client.data;
889*a1157835SDaniel Fojt 	keys->server_random = server.data;
890*a1157835SDaniel Fojt 	keys->client_random_len = client.size;
891*a1157835SDaniel Fojt 	keys->server_random_len = client.size;
8926d49e1aeSJan Lentfer 
8936d49e1aeSJan Lentfer 	return 0;
894*a1157835SDaniel Fojt #else /* 3.0.18 */
895*a1157835SDaniel Fojt 	return -1;
896*a1157835SDaniel Fojt #endif /* 3.0.18 */
8976d49e1aeSJan Lentfer }
8986d49e1aeSJan Lentfer 
8996d49e1aeSJan Lentfer 
tls_connection_export_key(void * tls_ctx,struct tls_connection * conn,const char * label,const u8 * context,size_t context_len,u8 * out,size_t out_len)900*a1157835SDaniel Fojt int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
901*a1157835SDaniel Fojt 			      const char *label, const u8 *context,
902*a1157835SDaniel Fojt 			      size_t context_len, u8 *out, size_t out_len)
9036d49e1aeSJan Lentfer {
9046d49e1aeSJan Lentfer 	if (conn == NULL || conn->session == NULL)
9056d49e1aeSJan Lentfer 		return -1;
9066d49e1aeSJan Lentfer 
907*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x030404
908*a1157835SDaniel Fojt 	return gnutls_prf_rfc5705(conn->session, os_strlen(label), label,
909*a1157835SDaniel Fojt 				  context_len, (const char *) context,
910*a1157835SDaniel Fojt 				  out_len, (char *) out);
911*a1157835SDaniel Fojt #else /* 3.4.4 */
912*a1157835SDaniel Fojt 	if (context)
9136d49e1aeSJan Lentfer 		return -1;
914*a1157835SDaniel Fojt 	return gnutls_prf(conn->session, os_strlen(label), label,
915*a1157835SDaniel Fojt 			  0 /* client_random first */, 0, NULL, out_len,
916*a1157835SDaniel Fojt 			  (char *) out);
917*a1157835SDaniel Fojt #endif /* 3.4.4 */
9186d49e1aeSJan Lentfer }
9196d49e1aeSJan Lentfer 
9206d49e1aeSJan Lentfer 
tls_connection_get_eap_fast_key(void * tls_ctx,struct tls_connection * conn,u8 * out,size_t out_len)921*a1157835SDaniel Fojt int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
922*a1157835SDaniel Fojt 				    u8 *out, size_t out_len)
923*a1157835SDaniel Fojt {
924*a1157835SDaniel Fojt 	return -1;
925*a1157835SDaniel Fojt }
926*a1157835SDaniel Fojt 
927*a1157835SDaniel Fojt 
gnutls_tls_fail_event(struct tls_connection * conn,const gnutls_datum_t * cert,int depth,const char * subject,const char * err_str,enum tls_fail_reason reason)928*a1157835SDaniel Fojt static void gnutls_tls_fail_event(struct tls_connection *conn,
929*a1157835SDaniel Fojt 				  const gnutls_datum_t *cert, int depth,
930*a1157835SDaniel Fojt 				  const char *subject, const char *err_str,
931*a1157835SDaniel Fojt 				  enum tls_fail_reason reason)
932*a1157835SDaniel Fojt {
933*a1157835SDaniel Fojt 	union tls_event_data ev;
934*a1157835SDaniel Fojt 	struct tls_global *global = conn->global;
935*a1157835SDaniel Fojt 	struct wpabuf *cert_buf = NULL;
936*a1157835SDaniel Fojt 
937*a1157835SDaniel Fojt 	if (global->event_cb == NULL)
938*a1157835SDaniel Fojt 		return;
939*a1157835SDaniel Fojt 
940*a1157835SDaniel Fojt 	os_memset(&ev, 0, sizeof(ev));
941*a1157835SDaniel Fojt 	ev.cert_fail.depth = depth;
942*a1157835SDaniel Fojt 	ev.cert_fail.subject = subject ? subject : "";
943*a1157835SDaniel Fojt 	ev.cert_fail.reason = reason;
944*a1157835SDaniel Fojt 	ev.cert_fail.reason_txt = err_str;
945*a1157835SDaniel Fojt 	if (cert) {
946*a1157835SDaniel Fojt 		cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
947*a1157835SDaniel Fojt 		ev.cert_fail.cert = cert_buf;
948*a1157835SDaniel Fojt 	}
949*a1157835SDaniel Fojt 	global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
950*a1157835SDaniel Fojt 	wpabuf_free(cert_buf);
951*a1157835SDaniel Fojt }
952*a1157835SDaniel Fojt 
953*a1157835SDaniel Fojt 
954*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER < 0x030300
server_eku_purpose(gnutls_x509_crt_t cert)955*a1157835SDaniel Fojt static int server_eku_purpose(gnutls_x509_crt_t cert)
956*a1157835SDaniel Fojt {
957*a1157835SDaniel Fojt 	unsigned int i;
958*a1157835SDaniel Fojt 
959*a1157835SDaniel Fojt 	for (i = 0; ; i++) {
960*a1157835SDaniel Fojt 		char oid[128];
961*a1157835SDaniel Fojt 		size_t oid_size = sizeof(oid);
962*a1157835SDaniel Fojt 		int res;
963*a1157835SDaniel Fojt 
964*a1157835SDaniel Fojt 		res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
965*a1157835SDaniel Fojt 							  &oid_size, NULL);
966*a1157835SDaniel Fojt 		if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
967*a1157835SDaniel Fojt 			if (i == 0) {
968*a1157835SDaniel Fojt 				/* No EKU - assume any use allowed */
969*a1157835SDaniel Fojt 				return 1;
970*a1157835SDaniel Fojt 			}
971*a1157835SDaniel Fojt 			break;
972*a1157835SDaniel Fojt 		}
973*a1157835SDaniel Fojt 
974*a1157835SDaniel Fojt 		if (res < 0) {
975*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
976*a1157835SDaniel Fojt 			return 0;
977*a1157835SDaniel Fojt 		}
978*a1157835SDaniel Fojt 
979*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
980*a1157835SDaniel Fojt 		if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
981*a1157835SDaniel Fojt 		    os_strcmp(oid, GNUTLS_KP_ANY) == 0)
982*a1157835SDaniel Fojt 			return 1;
983*a1157835SDaniel Fojt 	}
984*a1157835SDaniel Fojt 
985*a1157835SDaniel Fojt 	return 0;
986*a1157835SDaniel Fojt }
987*a1157835SDaniel Fojt #endif /* < 3.3.0 */
988*a1157835SDaniel Fojt 
989*a1157835SDaniel Fojt 
check_ocsp(struct tls_connection * conn,gnutls_session_t session,gnutls_alert_description_t * err)990*a1157835SDaniel Fojt static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
9916d49e1aeSJan Lentfer 		      gnutls_alert_description_t *err)
9926d49e1aeSJan Lentfer {
993*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x030103
994*a1157835SDaniel Fojt 	gnutls_datum_t response, buf;
995*a1157835SDaniel Fojt 	gnutls_ocsp_resp_t resp;
996*a1157835SDaniel Fojt 	unsigned int cert_status;
997*a1157835SDaniel Fojt 	int res;
998*a1157835SDaniel Fojt 
999*a1157835SDaniel Fojt 	if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
1000*a1157835SDaniel Fojt 		return 0;
1001*a1157835SDaniel Fojt 
1002*a1157835SDaniel Fojt 	if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
1003*a1157835SDaniel Fojt 		if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
1004*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO,
1005*a1157835SDaniel Fojt 				   "GnuTLS: No valid OCSP response received");
1006*a1157835SDaniel Fojt 			goto ocsp_error;
1007*a1157835SDaniel Fojt 		}
1008*a1157835SDaniel Fojt 
1009*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1010*a1157835SDaniel Fojt 			   "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
1011*a1157835SDaniel Fojt 		return 0;
1012*a1157835SDaniel Fojt 	}
1013*a1157835SDaniel Fojt 
1014*a1157835SDaniel Fojt 	/*
1015*a1157835SDaniel Fojt 	 * GnuTLS has already verified the OCSP response in
1016*a1157835SDaniel Fojt 	 * check_ocsp_response() and rejected handshake if the certificate was
1017*a1157835SDaniel Fojt 	 * found to be revoked. However, if the response indicates that the
1018*a1157835SDaniel Fojt 	 * status is unknown, handshake continues and reaches here. We need to
1019*a1157835SDaniel Fojt 	 * re-import the OCSP response to check for unknown certificate status,
1020*a1157835SDaniel Fojt 	 * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
1021*a1157835SDaniel Fojt 	 * gnutls_ocsp_resp_verify_direct() calls.
1022*a1157835SDaniel Fojt 	 */
1023*a1157835SDaniel Fojt 
1024*a1157835SDaniel Fojt 	res = gnutls_ocsp_status_request_get(session, &response);
1025*a1157835SDaniel Fojt 	if (res != GNUTLS_E_SUCCESS) {
1026*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
1027*a1157835SDaniel Fojt 			   "GnuTLS: OCSP response was received, but it was not valid");
1028*a1157835SDaniel Fojt 		goto ocsp_error;
1029*a1157835SDaniel Fojt 	}
1030*a1157835SDaniel Fojt 
1031*a1157835SDaniel Fojt 	if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
1032*a1157835SDaniel Fojt 		goto ocsp_error;
1033*a1157835SDaniel Fojt 
1034*a1157835SDaniel Fojt 	res = gnutls_ocsp_resp_import(resp, &response);
1035*a1157835SDaniel Fojt 	if (res != GNUTLS_E_SUCCESS) {
1036*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
1037*a1157835SDaniel Fojt 			   "GnuTLS: Could not parse received OCSP response: %s",
1038*a1157835SDaniel Fojt 			   gnutls_strerror(res));
1039*a1157835SDaniel Fojt 		gnutls_ocsp_resp_deinit(resp);
1040*a1157835SDaniel Fojt 		goto ocsp_error;
1041*a1157835SDaniel Fojt 	}
1042*a1157835SDaniel Fojt 
1043*a1157835SDaniel Fojt 	res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
1044*a1157835SDaniel Fojt 	if (res == GNUTLS_E_SUCCESS) {
1045*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
1046*a1157835SDaniel Fojt 		gnutls_free(buf.data);
1047*a1157835SDaniel Fojt 	}
1048*a1157835SDaniel Fojt 
1049*a1157835SDaniel Fojt 	res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
1050*a1157835SDaniel Fojt 					  NULL, &cert_status, NULL,
1051*a1157835SDaniel Fojt 					  NULL, NULL, NULL);
1052*a1157835SDaniel Fojt 	gnutls_ocsp_resp_deinit(resp);
1053*a1157835SDaniel Fojt 	if (res != GNUTLS_E_SUCCESS) {
1054*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO,
1055*a1157835SDaniel Fojt 			   "GnuTLS: Failed to extract OCSP information: %s",
1056*a1157835SDaniel Fojt 			   gnutls_strerror(res));
1057*a1157835SDaniel Fojt 		goto ocsp_error;
1058*a1157835SDaniel Fojt 	}
1059*a1157835SDaniel Fojt 
1060*a1157835SDaniel Fojt 	if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
1061*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
1062*a1157835SDaniel Fojt 	} else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
1063*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1064*a1157835SDaniel Fojt 			   "GnuTLS: OCSP cert status: revoked");
1065*a1157835SDaniel Fojt 		goto ocsp_error;
1066*a1157835SDaniel Fojt 	} else {
1067*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1068*a1157835SDaniel Fojt 			   "GnuTLS: OCSP cert status: unknown");
1069*a1157835SDaniel Fojt 		if (conn->flags & TLS_CONN_REQUIRE_OCSP)
1070*a1157835SDaniel Fojt 			goto ocsp_error;
1071*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1072*a1157835SDaniel Fojt 			   "GnuTLS: OCSP was not required, so allow connection to continue");
1073*a1157835SDaniel Fojt 	}
1074*a1157835SDaniel Fojt 
1075*a1157835SDaniel Fojt 	return 0;
1076*a1157835SDaniel Fojt 
1077*a1157835SDaniel Fojt ocsp_error:
1078*a1157835SDaniel Fojt 	gnutls_tls_fail_event(conn, NULL, 0, NULL,
1079*a1157835SDaniel Fojt 			      "bad certificate status response",
1080*a1157835SDaniel Fojt 			      TLS_FAIL_REVOKED);
1081*a1157835SDaniel Fojt 	*err = GNUTLS_A_CERTIFICATE_REVOKED;
1082*a1157835SDaniel Fojt 	return -1;
1083*a1157835SDaniel Fojt #else /* GnuTLS 3.1.3 or newer */
1084*a1157835SDaniel Fojt 	return 0;
1085*a1157835SDaniel Fojt #endif /* GnuTLS 3.1.3 or newer */
1086*a1157835SDaniel Fojt }
1087*a1157835SDaniel Fojt 
1088*a1157835SDaniel Fojt 
tls_match_suffix_helper(gnutls_x509_crt_t cert,const char * match,int full)1089*a1157835SDaniel Fojt static int tls_match_suffix_helper(gnutls_x509_crt_t cert, const char *match,
1090*a1157835SDaniel Fojt 				   int full)
1091*a1157835SDaniel Fojt {
1092*a1157835SDaniel Fojt 	int res = -1;
1093*a1157835SDaniel Fojt 
1094*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x030300
1095*a1157835SDaniel Fojt 	if (full)
1096*a1157835SDaniel Fojt 		res = gnutls_x509_crt_check_hostname2(
1097*a1157835SDaniel Fojt 			cert, match,
1098*a1157835SDaniel Fojt 			GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
1099*a1157835SDaniel Fojt #endif /* >= 3.3.0 */
1100*a1157835SDaniel Fojt 	if (res == -1)
1101*a1157835SDaniel Fojt 		res = gnutls_x509_crt_check_hostname(cert, match);
1102*a1157835SDaniel Fojt 
1103*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s --> res=%d",
1104*a1157835SDaniel Fojt 		   full ? "": "suffix ", match, res);
1105*a1157835SDaniel Fojt 	return res;
1106*a1157835SDaniel Fojt }
1107*a1157835SDaniel Fojt 
1108*a1157835SDaniel Fojt 
tls_match_suffix(gnutls_x509_crt_t cert,const char * match,int full)1109*a1157835SDaniel Fojt static int tls_match_suffix(gnutls_x509_crt_t cert, const char *match,
1110*a1157835SDaniel Fojt 			    int full)
1111*a1157835SDaniel Fojt {
1112*a1157835SDaniel Fojt 	char *values, *token, *context = NULL;
1113*a1157835SDaniel Fojt 	int ret = 0;
1114*a1157835SDaniel Fojt 
1115*a1157835SDaniel Fojt 	if (!os_strchr(match, ';'))
1116*a1157835SDaniel Fojt 		return tls_match_suffix_helper(cert, match, full);
1117*a1157835SDaniel Fojt 
1118*a1157835SDaniel Fojt 	values = os_strdup(match);
1119*a1157835SDaniel Fojt 	if (!values)
1120*a1157835SDaniel Fojt 		return 0;
1121*a1157835SDaniel Fojt 
1122*a1157835SDaniel Fojt 	/* Process each match alternative separately until a match is found */
1123*a1157835SDaniel Fojt 	while ((token = str_token(values, ";", &context))) {
1124*a1157835SDaniel Fojt 		if (tls_match_suffix_helper(cert, token, full)) {
1125*a1157835SDaniel Fojt 			ret = 1;
1126*a1157835SDaniel Fojt 			break;
1127*a1157835SDaniel Fojt 		}
1128*a1157835SDaniel Fojt 	}
1129*a1157835SDaniel Fojt 
1130*a1157835SDaniel Fojt 	os_free(values);
1131*a1157835SDaniel Fojt 	return ret;
1132*a1157835SDaniel Fojt }
1133*a1157835SDaniel Fojt 
1134*a1157835SDaniel Fojt 
tls_connection_verify_peer(gnutls_session_t session)1135*a1157835SDaniel Fojt static int tls_connection_verify_peer(gnutls_session_t session)
1136*a1157835SDaniel Fojt {
1137*a1157835SDaniel Fojt 	struct tls_connection *conn;
11386d49e1aeSJan Lentfer 	unsigned int status, num_certs, i;
11396d49e1aeSJan Lentfer 	struct os_time now;
11406d49e1aeSJan Lentfer 	const gnutls_datum_t *certs;
11416d49e1aeSJan Lentfer 	gnutls_x509_crt_t cert;
1142*a1157835SDaniel Fojt 	gnutls_alert_description_t err;
1143*a1157835SDaniel Fojt 	int res;
11446d49e1aeSJan Lentfer 
1145*a1157835SDaniel Fojt 	conn = gnutls_session_get_ptr(session);
1146*a1157835SDaniel Fojt 	if (!conn->verify_peer) {
1147*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG,
1148*a1157835SDaniel Fojt 			   "GnuTLS: No peer certificate verification enabled");
1149*a1157835SDaniel Fojt 		return 0;
1150*a1157835SDaniel Fojt 	}
1151*a1157835SDaniel Fojt 
1152*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
1153*a1157835SDaniel Fojt 
1154*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x030300
1155*a1157835SDaniel Fojt 	{
1156*a1157835SDaniel Fojt 		gnutls_typed_vdata_st data[1];
1157*a1157835SDaniel Fojt 		unsigned int elements = 0;
1158*a1157835SDaniel Fojt 
1159*a1157835SDaniel Fojt 		os_memset(data, 0, sizeof(data));
1160*a1157835SDaniel Fojt 		if (!conn->global->server) {
1161*a1157835SDaniel Fojt 			data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
1162*a1157835SDaniel Fojt 			data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
1163*a1157835SDaniel Fojt 			elements++;
1164*a1157835SDaniel Fojt 		}
1165*a1157835SDaniel Fojt 		res = gnutls_certificate_verify_peers(session, data, 1,
1166*a1157835SDaniel Fojt 						      &status);
1167*a1157835SDaniel Fojt 	}
1168*a1157835SDaniel Fojt #else /* < 3.3.0 */
1169*a1157835SDaniel Fojt 	res = gnutls_certificate_verify_peers2(session, &status);
1170*a1157835SDaniel Fojt #endif
1171*a1157835SDaniel Fojt 	if (res < 0) {
11726d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
11736d49e1aeSJan Lentfer 			   "certificate chain");
1174*a1157835SDaniel Fojt 		err = GNUTLS_A_INTERNAL_ERROR;
1175*a1157835SDaniel Fojt 		goto out;
1176*a1157835SDaniel Fojt 	}
1177*a1157835SDaniel Fojt 
1178*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x030104
1179*a1157835SDaniel Fojt 	{
1180*a1157835SDaniel Fojt 		gnutls_datum_t info;
1181*a1157835SDaniel Fojt 		int ret, type;
1182*a1157835SDaniel Fojt 
1183*a1157835SDaniel Fojt 		type = gnutls_certificate_type_get(session);
1184*a1157835SDaniel Fojt 		ret = gnutls_certificate_verification_status_print(status, type,
1185*a1157835SDaniel Fojt 								   &info, 0);
1186*a1157835SDaniel Fojt 		if (ret < 0) {
1187*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
1188*a1157835SDaniel Fojt 				   "GnuTLS: Failed to print verification status");
1189*a1157835SDaniel Fojt 			err = GNUTLS_A_INTERNAL_ERROR;
1190*a1157835SDaniel Fojt 			goto out;
1191*a1157835SDaniel Fojt 		}
1192*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
1193*a1157835SDaniel Fojt 		gnutls_free(info.data);
1194*a1157835SDaniel Fojt 	}
1195*a1157835SDaniel Fojt #endif /* GnuTLS 3.1.4 or newer */
1196*a1157835SDaniel Fojt 
1197*a1157835SDaniel Fojt 	certs = gnutls_certificate_get_peers(session, &num_certs);
1198*a1157835SDaniel Fojt 	if (certs == NULL || num_certs == 0) {
1199*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
1200*a1157835SDaniel Fojt 		err = GNUTLS_A_UNKNOWN_CA;
1201*a1157835SDaniel Fojt 		goto out;
12026d49e1aeSJan Lentfer 	}
12036d49e1aeSJan Lentfer 
12046d49e1aeSJan Lentfer 	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
12056d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
12066d49e1aeSJan Lentfer 		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
12076d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
12086d49e1aeSJan Lentfer 				   "algorithm");
1209*a1157835SDaniel Fojt 			gnutls_tls_fail_event(conn, NULL, 0, NULL,
1210*a1157835SDaniel Fojt 					      "certificate uses insecure algorithm",
1211*a1157835SDaniel Fojt 					      TLS_FAIL_BAD_CERTIFICATE);
1212*a1157835SDaniel Fojt 			err = GNUTLS_A_INSUFFICIENT_SECURITY;
1213*a1157835SDaniel Fojt 			goto out;
12146d49e1aeSJan Lentfer 		}
12156d49e1aeSJan Lentfer 		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
12166d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
12176d49e1aeSJan Lentfer 				   "activated");
1218*a1157835SDaniel Fojt 			gnutls_tls_fail_event(conn, NULL, 0, NULL,
1219*a1157835SDaniel Fojt 					      "certificate not yet valid",
1220*a1157835SDaniel Fojt 					      TLS_FAIL_NOT_YET_VALID);
1221*a1157835SDaniel Fojt 			err = GNUTLS_A_CERTIFICATE_EXPIRED;
1222*a1157835SDaniel Fojt 			goto out;
12236d49e1aeSJan Lentfer 		}
12246d49e1aeSJan Lentfer 		if (status & GNUTLS_CERT_EXPIRED) {
12256d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "TLS: Certificate expired");
1226*a1157835SDaniel Fojt 			gnutls_tls_fail_event(conn, NULL, 0, NULL,
1227*a1157835SDaniel Fojt 					      "certificate has expired",
1228*a1157835SDaniel Fojt 					      TLS_FAIL_EXPIRED);
1229*a1157835SDaniel Fojt 			err = GNUTLS_A_CERTIFICATE_EXPIRED;
1230*a1157835SDaniel Fojt 			goto out;
12316d49e1aeSJan Lentfer 		}
1232*a1157835SDaniel Fojt 		gnutls_tls_fail_event(conn, NULL, 0, NULL,
1233*a1157835SDaniel Fojt 				      "untrusted certificate",
1234*a1157835SDaniel Fojt 				      TLS_FAIL_UNTRUSTED);
1235*a1157835SDaniel Fojt 		err = GNUTLS_A_INTERNAL_ERROR;
1236*a1157835SDaniel Fojt 		goto out;
12376d49e1aeSJan Lentfer 	}
12386d49e1aeSJan Lentfer 
12396d49e1aeSJan Lentfer 	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
12406d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
12416d49e1aeSJan Lentfer 			   "known issuer");
1242*a1157835SDaniel Fojt 		gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
1243*a1157835SDaniel Fojt 				      TLS_FAIL_UNTRUSTED);
1244*a1157835SDaniel Fojt 		err = GNUTLS_A_UNKNOWN_CA;
1245*a1157835SDaniel Fojt 		goto out;
12466d49e1aeSJan Lentfer 	}
12476d49e1aeSJan Lentfer 
12486d49e1aeSJan Lentfer 	if (status & GNUTLS_CERT_REVOKED) {
12496d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
1250*a1157835SDaniel Fojt 		gnutls_tls_fail_event(conn, NULL, 0, NULL,
1251*a1157835SDaniel Fojt 				      "certificate revoked",
1252*a1157835SDaniel Fojt 				      TLS_FAIL_REVOKED);
1253*a1157835SDaniel Fojt 		err = GNUTLS_A_CERTIFICATE_REVOKED;
1254*a1157835SDaniel Fojt 		goto out;
12556d49e1aeSJan Lentfer 	}
12566d49e1aeSJan Lentfer 
1257*a1157835SDaniel Fojt 	if (status != 0) {
1258*a1157835SDaniel Fojt 		wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
1259*a1157835SDaniel Fojt 			   status);
1260*a1157835SDaniel Fojt 		err = GNUTLS_A_INTERNAL_ERROR;
1261*a1157835SDaniel Fojt 		goto out;
1262*a1157835SDaniel Fojt 	}
1263*a1157835SDaniel Fojt 
1264*a1157835SDaniel Fojt 	if (check_ocsp(conn, session, &err))
1265*a1157835SDaniel Fojt 		goto out;
1266*a1157835SDaniel Fojt 
12676d49e1aeSJan Lentfer 	os_get_time(&now);
12686d49e1aeSJan Lentfer 
12696d49e1aeSJan Lentfer 	for (i = 0; i < num_certs; i++) {
12706d49e1aeSJan Lentfer 		char *buf;
12716d49e1aeSJan Lentfer 		size_t len;
12726d49e1aeSJan Lentfer 		if (gnutls_x509_crt_init(&cert) < 0) {
12736d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
12746d49e1aeSJan Lentfer 				   "failed");
1275*a1157835SDaniel Fojt 			err = GNUTLS_A_BAD_CERTIFICATE;
1276*a1157835SDaniel Fojt 			goto out;
12776d49e1aeSJan Lentfer 		}
12786d49e1aeSJan Lentfer 
12796d49e1aeSJan Lentfer 		if (gnutls_x509_crt_import(cert, &certs[i],
12806d49e1aeSJan Lentfer 					   GNUTLS_X509_FMT_DER) < 0) {
12816d49e1aeSJan Lentfer 			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
12826d49e1aeSJan Lentfer 				   "certificate %d/%d", i + 1, num_certs);
12836d49e1aeSJan Lentfer 			gnutls_x509_crt_deinit(cert);
1284*a1157835SDaniel Fojt 			err = GNUTLS_A_BAD_CERTIFICATE;
1285*a1157835SDaniel Fojt 			goto out;
12866d49e1aeSJan Lentfer 		}
12876d49e1aeSJan Lentfer 
12886d49e1aeSJan Lentfer 		gnutls_x509_crt_get_dn(cert, NULL, &len);
12896d49e1aeSJan Lentfer 		len++;
12906d49e1aeSJan Lentfer 		buf = os_malloc(len + 1);
12916d49e1aeSJan Lentfer 		if (buf) {
12926d49e1aeSJan Lentfer 			buf[0] = buf[len] = '\0';
12936d49e1aeSJan Lentfer 			gnutls_x509_crt_get_dn(cert, buf, &len);
12946d49e1aeSJan Lentfer 		}
12956d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
12966d49e1aeSJan Lentfer 			   i + 1, num_certs, buf);
12976d49e1aeSJan Lentfer 
1298*a1157835SDaniel Fojt 		if (conn->global->event_cb) {
1299*a1157835SDaniel Fojt 			struct wpabuf *cert_buf = NULL;
1300*a1157835SDaniel Fojt 			union tls_event_data ev;
1301*a1157835SDaniel Fojt #ifdef CONFIG_SHA256
1302*a1157835SDaniel Fojt 			u8 hash[32];
1303*a1157835SDaniel Fojt 			const u8 *_addr[1];
1304*a1157835SDaniel Fojt 			size_t _len[1];
1305*a1157835SDaniel Fojt #endif /* CONFIG_SHA256 */
1306*a1157835SDaniel Fojt 
1307*a1157835SDaniel Fojt 			os_memset(&ev, 0, sizeof(ev));
1308*a1157835SDaniel Fojt 			if (conn->global->cert_in_cb) {
1309*a1157835SDaniel Fojt 				cert_buf = wpabuf_alloc_copy(certs[i].data,
1310*a1157835SDaniel Fojt 							     certs[i].size);
1311*a1157835SDaniel Fojt 				ev.peer_cert.cert = cert_buf;
1312*a1157835SDaniel Fojt 			}
1313*a1157835SDaniel Fojt #ifdef CONFIG_SHA256
1314*a1157835SDaniel Fojt 			_addr[0] = certs[i].data;
1315*a1157835SDaniel Fojt 			_len[0] = certs[i].size;
1316*a1157835SDaniel Fojt 			if (sha256_vector(1, _addr, _len, hash) == 0) {
1317*a1157835SDaniel Fojt 				ev.peer_cert.hash = hash;
1318*a1157835SDaniel Fojt 				ev.peer_cert.hash_len = sizeof(hash);
1319*a1157835SDaniel Fojt 			}
1320*a1157835SDaniel Fojt #endif /* CONFIG_SHA256 */
1321*a1157835SDaniel Fojt 			ev.peer_cert.depth = i;
1322*a1157835SDaniel Fojt 			ev.peer_cert.subject = buf;
1323*a1157835SDaniel Fojt 			conn->global->event_cb(conn->global->cb_ctx,
1324*a1157835SDaniel Fojt 					       TLS_PEER_CERTIFICATE, &ev);
1325*a1157835SDaniel Fojt 			wpabuf_free(cert_buf);
1326*a1157835SDaniel Fojt 		}
1327*a1157835SDaniel Fojt 
13286d49e1aeSJan Lentfer 		if (i == 0) {
1329*a1157835SDaniel Fojt 			if (conn->suffix_match &&
1330*a1157835SDaniel Fojt 			    !tls_match_suffix(cert, conn->suffix_match, 0)) {
1331*a1157835SDaniel Fojt 				wpa_printf(MSG_WARNING,
1332*a1157835SDaniel Fojt 					   "TLS: Domain suffix match '%s' not found",
1333*a1157835SDaniel Fojt 					   conn->suffix_match);
1334*a1157835SDaniel Fojt 				gnutls_tls_fail_event(
1335*a1157835SDaniel Fojt 					conn, &certs[i], i, buf,
1336*a1157835SDaniel Fojt 					"Domain suffix mismatch",
1337*a1157835SDaniel Fojt 					TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1338*a1157835SDaniel Fojt 				err = GNUTLS_A_BAD_CERTIFICATE;
1339*a1157835SDaniel Fojt 				gnutls_x509_crt_deinit(cert);
1340*a1157835SDaniel Fojt 				os_free(buf);
1341*a1157835SDaniel Fojt 				goto out;
1342*a1157835SDaniel Fojt 			}
1343*a1157835SDaniel Fojt 
1344*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x030300
1345*a1157835SDaniel Fojt 			if (conn->domain_match &&
1346*a1157835SDaniel Fojt 			    !tls_match_suffix(cert, conn->domain_match, 1)) {
1347*a1157835SDaniel Fojt 				wpa_printf(MSG_WARNING,
1348*a1157835SDaniel Fojt 					   "TLS: Domain match '%s' not found",
1349*a1157835SDaniel Fojt 					   conn->domain_match);
1350*a1157835SDaniel Fojt 				gnutls_tls_fail_event(
1351*a1157835SDaniel Fojt 					conn, &certs[i], i, buf,
1352*a1157835SDaniel Fojt 					"Domain mismatch",
1353*a1157835SDaniel Fojt 					TLS_FAIL_DOMAIN_MISMATCH);
1354*a1157835SDaniel Fojt 				err = GNUTLS_A_BAD_CERTIFICATE;
1355*a1157835SDaniel Fojt 				gnutls_x509_crt_deinit(cert);
1356*a1157835SDaniel Fojt 				os_free(buf);
1357*a1157835SDaniel Fojt 				goto out;
1358*a1157835SDaniel Fojt 			}
1359*a1157835SDaniel Fojt #endif /* >= 3.3.0 */
1360*a1157835SDaniel Fojt 
1361*a1157835SDaniel Fojt 			/* TODO: validate altsubject_match.
1362*a1157835SDaniel Fojt 			 * For now, any such configuration is rejected in
1363*a1157835SDaniel Fojt 			 * tls_connection_set_params() */
1364*a1157835SDaniel Fojt 
1365*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER < 0x030300
1366*a1157835SDaniel Fojt 			/*
1367*a1157835SDaniel Fojt 			 * gnutls_certificate_verify_peers() not available, so
1368*a1157835SDaniel Fojt 			 * need to check EKU separately.
1369*a1157835SDaniel Fojt 			 */
1370*a1157835SDaniel Fojt 			if (!conn->global->server &&
1371*a1157835SDaniel Fojt 			    !server_eku_purpose(cert)) {
1372*a1157835SDaniel Fojt 				wpa_printf(MSG_WARNING,
1373*a1157835SDaniel Fojt 					   "GnuTLS: No server EKU");
1374*a1157835SDaniel Fojt 				gnutls_tls_fail_event(
1375*a1157835SDaniel Fojt 					conn, &certs[i], i, buf,
1376*a1157835SDaniel Fojt 					"No server EKU",
1377*a1157835SDaniel Fojt 					TLS_FAIL_BAD_CERTIFICATE);
1378*a1157835SDaniel Fojt 				err = GNUTLS_A_BAD_CERTIFICATE;
1379*a1157835SDaniel Fojt 				gnutls_x509_crt_deinit(cert);
1380*a1157835SDaniel Fojt 				os_free(buf);
1381*a1157835SDaniel Fojt 				goto out;
1382*a1157835SDaniel Fojt 			}
1383*a1157835SDaniel Fojt #endif /* < 3.3.0 */
1384*a1157835SDaniel Fojt 		}
1385*a1157835SDaniel Fojt 
1386*a1157835SDaniel Fojt 		if (!conn->disable_time_checks &&
1387*a1157835SDaniel Fojt 		    (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
1388*a1157835SDaniel Fojt 		     gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
1389*a1157835SDaniel Fojt 			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
1390*a1157835SDaniel Fojt 				   "not valid at this time",
1391*a1157835SDaniel Fojt 				   i + 1, num_certs);
1392*a1157835SDaniel Fojt 			gnutls_tls_fail_event(
1393*a1157835SDaniel Fojt 				conn, &certs[i], i, buf,
1394*a1157835SDaniel Fojt 				"Certificate is not valid at this time",
1395*a1157835SDaniel Fojt 				TLS_FAIL_EXPIRED);
1396*a1157835SDaniel Fojt 			gnutls_x509_crt_deinit(cert);
1397*a1157835SDaniel Fojt 			os_free(buf);
1398*a1157835SDaniel Fojt 			err = GNUTLS_A_CERTIFICATE_EXPIRED;
1399*a1157835SDaniel Fojt 			goto out;
14006d49e1aeSJan Lentfer 		}
14016d49e1aeSJan Lentfer 
14026d49e1aeSJan Lentfer 		os_free(buf);
14036d49e1aeSJan Lentfer 
14046d49e1aeSJan Lentfer 		gnutls_x509_crt_deinit(cert);
14056d49e1aeSJan Lentfer 	}
14066d49e1aeSJan Lentfer 
1407*a1157835SDaniel Fojt 	if (conn->global->event_cb != NULL)
1408*a1157835SDaniel Fojt 		conn->global->event_cb(conn->global->cb_ctx,
1409*a1157835SDaniel Fojt 				       TLS_CERT_CHAIN_SUCCESS, NULL);
14106d49e1aeSJan Lentfer 
14116d49e1aeSJan Lentfer 	return 0;
1412*a1157835SDaniel Fojt 
1413*a1157835SDaniel Fojt out:
1414*a1157835SDaniel Fojt 	conn->failed++;
1415*a1157835SDaniel Fojt 	gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
1416*a1157835SDaniel Fojt 	return GNUTLS_E_CERTIFICATE_ERROR;
14176d49e1aeSJan Lentfer }
14186d49e1aeSJan Lentfer 
14196d49e1aeSJan Lentfer 
gnutls_get_appl_data(struct tls_connection * conn)14203ff40c12SJohn Marino static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
14216d49e1aeSJan Lentfer {
14223ff40c12SJohn Marino 	int res;
14233ff40c12SJohn Marino 	struct wpabuf *ad;
14243ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
14253ff40c12SJohn Marino 	ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
14263ff40c12SJohn Marino 	if (ad == NULL)
14273ff40c12SJohn Marino 		return NULL;
14283ff40c12SJohn Marino 
14293ff40c12SJohn Marino 	res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
14303ff40c12SJohn Marino 				 wpabuf_size(ad));
14313ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
14323ff40c12SJohn Marino 	if (res < 0) {
14333ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
14343ff40c12SJohn Marino 			   "(%s)", __func__, (int) res,
14353ff40c12SJohn Marino 			   gnutls_strerror(res));
14363ff40c12SJohn Marino 		wpabuf_free(ad);
14373ff40c12SJohn Marino 		return NULL;
14383ff40c12SJohn Marino 	}
14393ff40c12SJohn Marino 
14403ff40c12SJohn Marino 	wpabuf_put(ad, res);
14413ff40c12SJohn Marino 	wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
14423ff40c12SJohn Marino 		   res);
14433ff40c12SJohn Marino 	return ad;
14443ff40c12SJohn Marino }
14453ff40c12SJohn Marino 
14463ff40c12SJohn Marino 
tls_connection_handshake(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)14473ff40c12SJohn Marino struct wpabuf * tls_connection_handshake(void *tls_ctx,
14483ff40c12SJohn Marino 					 struct tls_connection *conn,
14493ff40c12SJohn Marino 					 const struct wpabuf *in_data,
14503ff40c12SJohn Marino 					 struct wpabuf **appl_data)
14513ff40c12SJohn Marino {
14523ff40c12SJohn Marino 	struct tls_global *global = tls_ctx;
14533ff40c12SJohn Marino 	struct wpabuf *out_data;
14546d49e1aeSJan Lentfer 	int ret;
14556d49e1aeSJan Lentfer 
14566d49e1aeSJan Lentfer 	if (appl_data)
14576d49e1aeSJan Lentfer 		*appl_data = NULL;
14586d49e1aeSJan Lentfer 
14593ff40c12SJohn Marino 	if (in_data && wpabuf_len(in_data) > 0) {
14606d49e1aeSJan Lentfer 		if (conn->pull_buf) {
14616d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
14626d49e1aeSJan Lentfer 				   "pull_buf", __func__,
14633ff40c12SJohn Marino 				   (unsigned long) wpabuf_len(conn->pull_buf));
14643ff40c12SJohn Marino 			wpabuf_free(conn->pull_buf);
14656d49e1aeSJan Lentfer 		}
14663ff40c12SJohn Marino 		conn->pull_buf = wpabuf_dup(in_data);
14676d49e1aeSJan Lentfer 		if (conn->pull_buf == NULL)
14686d49e1aeSJan Lentfer 			return NULL;
14693ff40c12SJohn Marino 		conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
14706d49e1aeSJan Lentfer 	}
14716d49e1aeSJan Lentfer 
14726d49e1aeSJan Lentfer 	ret = gnutls_handshake(conn->session);
14736d49e1aeSJan Lentfer 	if (ret < 0) {
1474*a1157835SDaniel Fojt 		gnutls_alert_description_t alert;
1475*a1157835SDaniel Fojt 		union tls_event_data ev;
1476*a1157835SDaniel Fojt 
14776d49e1aeSJan Lentfer 		switch (ret) {
14786d49e1aeSJan Lentfer 		case GNUTLS_E_AGAIN:
14796d49e1aeSJan Lentfer 			if (global->server && conn->established &&
14806d49e1aeSJan Lentfer 			    conn->push_buf == NULL) {
14816d49e1aeSJan Lentfer 				/* Need to return something to trigger
14826d49e1aeSJan Lentfer 				 * completion of EAP-TLS. */
14833ff40c12SJohn Marino 				conn->push_buf = wpabuf_alloc(0);
14846d49e1aeSJan Lentfer 			}
14856d49e1aeSJan Lentfer 			break;
1486*a1157835SDaniel Fojt 		case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
1487*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG, "GnuTLS: Unacceptable DH prime");
1488*a1157835SDaniel Fojt 			if (conn->global->event_cb) {
1489*a1157835SDaniel Fojt 				os_memset(&ev, 0, sizeof(ev));
1490*a1157835SDaniel Fojt 				ev.alert.is_local = 1;
1491*a1157835SDaniel Fojt 				ev.alert.type = "fatal";
1492*a1157835SDaniel Fojt 				ev.alert.description = "insufficient security";
1493*a1157835SDaniel Fojt 				conn->global->event_cb(conn->global->cb_ctx,
1494*a1157835SDaniel Fojt 						       TLS_ALERT, &ev);
1495*a1157835SDaniel Fojt 			}
1496*a1157835SDaniel Fojt 			/*
1497*a1157835SDaniel Fojt 			 * Could send a TLS Alert to the server, but for now,
1498*a1157835SDaniel Fojt 			 * simply terminate handshake.
1499*a1157835SDaniel Fojt 			 */
1500*a1157835SDaniel Fojt 			conn->failed++;
1501*a1157835SDaniel Fojt 			conn->write_alerts++;
1502*a1157835SDaniel Fojt 			break;
15036d49e1aeSJan Lentfer 		case GNUTLS_E_FATAL_ALERT_RECEIVED:
1504*a1157835SDaniel Fojt 			alert = gnutls_alert_get(conn->session);
15056d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
1506*a1157835SDaniel Fojt 				   __func__, gnutls_alert_get_name(alert));
15076d49e1aeSJan Lentfer 			conn->read_alerts++;
1508*a1157835SDaniel Fojt 			if (conn->global->event_cb != NULL) {
1509*a1157835SDaniel Fojt 				os_memset(&ev, 0, sizeof(ev));
1510*a1157835SDaniel Fojt 				ev.alert.is_local = 0;
1511*a1157835SDaniel Fojt 				ev.alert.type = gnutls_alert_get_name(alert);
1512*a1157835SDaniel Fojt 				ev.alert.description = ev.alert.type;
1513*a1157835SDaniel Fojt 				conn->global->event_cb(conn->global->cb_ctx,
1514*a1157835SDaniel Fojt 						       TLS_ALERT, &ev);
1515*a1157835SDaniel Fojt 			}
15166d49e1aeSJan Lentfer 			/* continue */
15176d49e1aeSJan Lentfer 		default:
15186d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
15196d49e1aeSJan Lentfer 				   "-> %s", __func__, gnutls_strerror(ret));
15206d49e1aeSJan Lentfer 			conn->failed++;
15216d49e1aeSJan Lentfer 		}
15226d49e1aeSJan Lentfer 	} else {
15236d49e1aeSJan Lentfer 		size_t size;
15246d49e1aeSJan Lentfer 
15253ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
1526*a1157835SDaniel Fojt 
1527*a1157835SDaniel Fojt #if GNUTLS_VERSION_NUMBER >= 0x03010a
1528*a1157835SDaniel Fojt 		{
1529*a1157835SDaniel Fojt 			char *desc;
1530*a1157835SDaniel Fojt 
1531*a1157835SDaniel Fojt 			desc = gnutls_session_get_desc(conn->session);
1532*a1157835SDaniel Fojt 			if (desc) {
1533*a1157835SDaniel Fojt 				wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
1534*a1157835SDaniel Fojt 				gnutls_free(desc);
1535*a1157835SDaniel Fojt 			}
1536*a1157835SDaniel Fojt 		}
1537*a1157835SDaniel Fojt #endif /* GnuTLS 3.1.10 or newer */
1538*a1157835SDaniel Fojt 
15396d49e1aeSJan Lentfer 		conn->established = 1;
15406d49e1aeSJan Lentfer 		if (conn->push_buf == NULL) {
15416d49e1aeSJan Lentfer 			/* Need to return something to get final TLS ACK. */
15423ff40c12SJohn Marino 			conn->push_buf = wpabuf_alloc(0);
15436d49e1aeSJan Lentfer 		}
15446d49e1aeSJan Lentfer 
15456d49e1aeSJan Lentfer 		gnutls_session_get_data(conn->session, NULL, &size);
15466d49e1aeSJan Lentfer 		if (global->session_data == NULL ||
15476d49e1aeSJan Lentfer 		    global->session_data_size < size) {
15486d49e1aeSJan Lentfer 			os_free(global->session_data);
15496d49e1aeSJan Lentfer 			global->session_data = os_malloc(size);
15506d49e1aeSJan Lentfer 		}
15516d49e1aeSJan Lentfer 		if (global->session_data) {
15526d49e1aeSJan Lentfer 			global->session_data_size = size;
15536d49e1aeSJan Lentfer 			gnutls_session_get_data(conn->session,
15546d49e1aeSJan Lentfer 						global->session_data,
15556d49e1aeSJan Lentfer 						&global->session_data_size);
15566d49e1aeSJan Lentfer 		}
15573ff40c12SJohn Marino 
15583ff40c12SJohn Marino 		if (conn->pull_buf && appl_data)
15593ff40c12SJohn Marino 			*appl_data = gnutls_get_appl_data(conn);
15606d49e1aeSJan Lentfer 	}
15616d49e1aeSJan Lentfer 
15626d49e1aeSJan Lentfer 	out_data = conn->push_buf;
15636d49e1aeSJan Lentfer 	conn->push_buf = NULL;
15646d49e1aeSJan Lentfer 	return out_data;
15656d49e1aeSJan Lentfer }
15666d49e1aeSJan Lentfer 
15676d49e1aeSJan Lentfer 
tls_connection_server_handshake(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)15683ff40c12SJohn Marino struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
15696d49e1aeSJan Lentfer 						struct tls_connection *conn,
15703ff40c12SJohn Marino 						const struct wpabuf *in_data,
15713ff40c12SJohn Marino 						struct wpabuf **appl_data)
15726d49e1aeSJan Lentfer {
15733ff40c12SJohn Marino 	return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
15746d49e1aeSJan Lentfer }
15756d49e1aeSJan Lentfer 
15766d49e1aeSJan Lentfer 
tls_connection_encrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)15773ff40c12SJohn Marino struct wpabuf * tls_connection_encrypt(void *tls_ctx,
15783ff40c12SJohn Marino 				       struct tls_connection *conn,
15793ff40c12SJohn Marino 				       const struct wpabuf *in_data)
15806d49e1aeSJan Lentfer {
15816d49e1aeSJan Lentfer 	ssize_t res;
15823ff40c12SJohn Marino 	struct wpabuf *buf;
15836d49e1aeSJan Lentfer 
15843ff40c12SJohn Marino 	res = gnutls_record_send(conn->session, wpabuf_head(in_data),
15853ff40c12SJohn Marino 				 wpabuf_len(in_data));
15866d49e1aeSJan Lentfer 	if (res < 0) {
15876d49e1aeSJan Lentfer 		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
15886d49e1aeSJan Lentfer 			   __func__, gnutls_strerror(res));
15893ff40c12SJohn Marino 		return NULL;
15906d49e1aeSJan Lentfer 	}
15913ff40c12SJohn Marino 
15923ff40c12SJohn Marino 	buf = conn->push_buf;
15936d49e1aeSJan Lentfer 	conn->push_buf = NULL;
15943ff40c12SJohn Marino 	return buf;
15956d49e1aeSJan Lentfer }
15966d49e1aeSJan Lentfer 
15976d49e1aeSJan Lentfer 
tls_connection_decrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)15983ff40c12SJohn Marino struct wpabuf * tls_connection_decrypt(void *tls_ctx,
15993ff40c12SJohn Marino 				       struct tls_connection *conn,
16003ff40c12SJohn Marino 				       const struct wpabuf *in_data)
16016d49e1aeSJan Lentfer {
16026d49e1aeSJan Lentfer 	ssize_t res;
16033ff40c12SJohn Marino 	struct wpabuf *out;
16046d49e1aeSJan Lentfer 
16056d49e1aeSJan Lentfer 	if (conn->pull_buf) {
16066d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
16076d49e1aeSJan Lentfer 			   "pull_buf", __func__,
16083ff40c12SJohn Marino 			   (unsigned long) wpabuf_len(conn->pull_buf));
16093ff40c12SJohn Marino 		wpabuf_free(conn->pull_buf);
16106d49e1aeSJan Lentfer 	}
16113ff40c12SJohn Marino 	conn->pull_buf = wpabuf_dup(in_data);
16126d49e1aeSJan Lentfer 	if (conn->pull_buf == NULL)
16133ff40c12SJohn Marino 		return NULL;
16143ff40c12SJohn Marino 	conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
16156d49e1aeSJan Lentfer 
16163ff40c12SJohn Marino 	/*
16173ff40c12SJohn Marino 	 * Even though we try to disable TLS compression, it is possible that
16183ff40c12SJohn Marino 	 * this cannot be done with all TLS libraries. Add extra buffer space
16193ff40c12SJohn Marino 	 * to handle the possibility of the decrypted data being longer than
16203ff40c12SJohn Marino 	 * input data.
16213ff40c12SJohn Marino 	 */
16223ff40c12SJohn Marino 	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
16233ff40c12SJohn Marino 	if (out == NULL)
16243ff40c12SJohn Marino 		return NULL;
16256d49e1aeSJan Lentfer 
16263ff40c12SJohn Marino 	res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
16273ff40c12SJohn Marino 				 wpabuf_size(out));
16286d49e1aeSJan Lentfer 	if (res < 0) {
16296d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
16306d49e1aeSJan Lentfer 			   "(%s)", __func__, (int) res, gnutls_strerror(res));
16313ff40c12SJohn Marino 		wpabuf_free(out);
16323ff40c12SJohn Marino 		return NULL;
16336d49e1aeSJan Lentfer 	}
16343ff40c12SJohn Marino 	wpabuf_put(out, res);
16356d49e1aeSJan Lentfer 
16363ff40c12SJohn Marino 	return out;
16376d49e1aeSJan Lentfer }
16386d49e1aeSJan Lentfer 
16396d49e1aeSJan Lentfer 
tls_connection_resumed(void * ssl_ctx,struct tls_connection * conn)16406d49e1aeSJan Lentfer int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
16416d49e1aeSJan Lentfer {
16426d49e1aeSJan Lentfer 	if (conn == NULL)
16436d49e1aeSJan Lentfer 		return 0;
16446d49e1aeSJan Lentfer 	return gnutls_session_is_resumed(conn->session);
16456d49e1aeSJan Lentfer }
16466d49e1aeSJan Lentfer 
16476d49e1aeSJan Lentfer 
tls_connection_set_cipher_list(void * tls_ctx,struct tls_connection * conn,u8 * ciphers)16486d49e1aeSJan Lentfer int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
16496d49e1aeSJan Lentfer 				   u8 *ciphers)
16506d49e1aeSJan Lentfer {
16516d49e1aeSJan Lentfer 	/* TODO */
16526d49e1aeSJan Lentfer 	return -1;
16536d49e1aeSJan Lentfer }
16546d49e1aeSJan Lentfer 
16556d49e1aeSJan Lentfer 
tls_get_version(void * ssl_ctx,struct tls_connection * conn,char * buf,size_t buflen)1656*a1157835SDaniel Fojt int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
1657*a1157835SDaniel Fojt 		    char *buf, size_t buflen)
1658*a1157835SDaniel Fojt {
1659*a1157835SDaniel Fojt 	gnutls_protocol_t ver;
1660*a1157835SDaniel Fojt 
1661*a1157835SDaniel Fojt 	ver = gnutls_protocol_get_version(conn->session);
1662*a1157835SDaniel Fojt 	if (ver == GNUTLS_TLS1_0)
1663*a1157835SDaniel Fojt 		os_strlcpy(buf, "TLSv1", buflen);
1664*a1157835SDaniel Fojt 	else if (ver == GNUTLS_TLS1_1)
1665*a1157835SDaniel Fojt 		os_strlcpy(buf, "TLSv1.1", buflen);
1666*a1157835SDaniel Fojt 	else if (ver == GNUTLS_TLS1_2)
1667*a1157835SDaniel Fojt 		os_strlcpy(buf, "TLSv1.2", buflen);
1668*a1157835SDaniel Fojt 	else
1669*a1157835SDaniel Fojt 		return -1;
1670*a1157835SDaniel Fojt 	return 0;
1671*a1157835SDaniel Fojt }
1672*a1157835SDaniel Fojt 
1673*a1157835SDaniel Fojt 
tls_get_cipher(void * ssl_ctx,struct tls_connection * conn,char * buf,size_t buflen)16746d49e1aeSJan Lentfer int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
16756d49e1aeSJan Lentfer 		   char *buf, size_t buflen)
16766d49e1aeSJan Lentfer {
1677*a1157835SDaniel Fojt 	gnutls_cipher_algorithm_t cipher;
1678*a1157835SDaniel Fojt 	gnutls_kx_algorithm_t kx;
1679*a1157835SDaniel Fojt 	gnutls_mac_algorithm_t mac;
1680*a1157835SDaniel Fojt 	const char *kx_str, *cipher_str, *mac_str;
1681*a1157835SDaniel Fojt 	int res;
1682*a1157835SDaniel Fojt 
1683*a1157835SDaniel Fojt 	cipher = gnutls_cipher_get(conn->session);
1684*a1157835SDaniel Fojt 	cipher_str = gnutls_cipher_get_name(cipher);
1685*a1157835SDaniel Fojt 	if (!cipher_str)
1686*a1157835SDaniel Fojt 		cipher_str = "";
1687*a1157835SDaniel Fojt 
1688*a1157835SDaniel Fojt 	kx = gnutls_kx_get(conn->session);
1689*a1157835SDaniel Fojt 	kx_str = gnutls_kx_get_name(kx);
1690*a1157835SDaniel Fojt 	if (!kx_str)
1691*a1157835SDaniel Fojt 		kx_str = "";
1692*a1157835SDaniel Fojt 
1693*a1157835SDaniel Fojt 	mac = gnutls_mac_get(conn->session);
1694*a1157835SDaniel Fojt 	mac_str = gnutls_mac_get_name(mac);
1695*a1157835SDaniel Fojt 	if (!mac_str)
1696*a1157835SDaniel Fojt 		mac_str = "";
1697*a1157835SDaniel Fojt 
1698*a1157835SDaniel Fojt 	if (kx == GNUTLS_KX_RSA)
1699*a1157835SDaniel Fojt 		res = os_snprintf(buf, buflen, "%s-%s", cipher_str, mac_str);
1700*a1157835SDaniel Fojt 	else
1701*a1157835SDaniel Fojt 		res = os_snprintf(buf, buflen, "%s-%s-%s",
1702*a1157835SDaniel Fojt 				  kx_str, cipher_str, mac_str);
1703*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen, res))
1704*a1157835SDaniel Fojt 		return -1;
1705*a1157835SDaniel Fojt 
17066d49e1aeSJan Lentfer 	return 0;
17076d49e1aeSJan Lentfer }
17086d49e1aeSJan Lentfer 
17096d49e1aeSJan Lentfer 
tls_connection_enable_workaround(void * ssl_ctx,struct tls_connection * conn)17106d49e1aeSJan Lentfer int tls_connection_enable_workaround(void *ssl_ctx,
17116d49e1aeSJan Lentfer 				     struct tls_connection *conn)
17126d49e1aeSJan Lentfer {
17133ff40c12SJohn Marino 	gnutls_record_disable_padding(conn->session);
17146d49e1aeSJan Lentfer 	return 0;
17156d49e1aeSJan Lentfer }
17166d49e1aeSJan Lentfer 
17176d49e1aeSJan Lentfer 
tls_connection_client_hello_ext(void * ssl_ctx,struct tls_connection * conn,int ext_type,const u8 * data,size_t data_len)17186d49e1aeSJan Lentfer int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
17196d49e1aeSJan Lentfer 				    int ext_type, const u8 *data,
17206d49e1aeSJan Lentfer 				    size_t data_len)
17216d49e1aeSJan Lentfer {
17226d49e1aeSJan Lentfer 	/* TODO */
17236d49e1aeSJan Lentfer 	return -1;
17246d49e1aeSJan Lentfer }
17256d49e1aeSJan Lentfer 
17266d49e1aeSJan Lentfer 
tls_connection_get_failed(void * ssl_ctx,struct tls_connection * conn)17276d49e1aeSJan Lentfer int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
17286d49e1aeSJan Lentfer {
17296d49e1aeSJan Lentfer 	if (conn == NULL)
17306d49e1aeSJan Lentfer 		return -1;
17316d49e1aeSJan Lentfer 	return conn->failed;
17326d49e1aeSJan Lentfer }
17336d49e1aeSJan Lentfer 
17346d49e1aeSJan Lentfer 
tls_connection_get_read_alerts(void * ssl_ctx,struct tls_connection * conn)17356d49e1aeSJan Lentfer int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
17366d49e1aeSJan Lentfer {
17376d49e1aeSJan Lentfer 	if (conn == NULL)
17386d49e1aeSJan Lentfer 		return -1;
17396d49e1aeSJan Lentfer 	return conn->read_alerts;
17406d49e1aeSJan Lentfer }
17416d49e1aeSJan Lentfer 
17426d49e1aeSJan Lentfer 
tls_connection_get_write_alerts(void * ssl_ctx,struct tls_connection * conn)17436d49e1aeSJan Lentfer int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
17446d49e1aeSJan Lentfer {
17456d49e1aeSJan Lentfer 	if (conn == NULL)
17466d49e1aeSJan Lentfer 		return -1;
17476d49e1aeSJan Lentfer 	return conn->write_alerts;
17486d49e1aeSJan Lentfer }
17496d49e1aeSJan Lentfer 
17506d49e1aeSJan Lentfer 
tls_connection_set_session_ticket_cb(void * tls_ctx,struct tls_connection * conn,tls_session_ticket_cb cb,void * ctx)17513ff40c12SJohn Marino int tls_connection_set_session_ticket_cb(void *tls_ctx,
17526d49e1aeSJan Lentfer 					 struct tls_connection *conn,
17533ff40c12SJohn Marino 					 tls_session_ticket_cb cb, void *ctx)
17546d49e1aeSJan Lentfer {
17556d49e1aeSJan Lentfer 	return -1;
17566d49e1aeSJan Lentfer }
1757*a1157835SDaniel Fojt 
1758*a1157835SDaniel Fojt 
tls_get_library_version(char * buf,size_t buf_len)1759*a1157835SDaniel Fojt int tls_get_library_version(char *buf, size_t buf_len)
1760*a1157835SDaniel Fojt {
1761*a1157835SDaniel Fojt 	return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
1762*a1157835SDaniel Fojt 			   GNUTLS_VERSION, gnutls_check_version(NULL));
1763*a1157835SDaniel Fojt }
1764*a1157835SDaniel Fojt 
1765*a1157835SDaniel Fojt 
tls_connection_set_success_data(struct tls_connection * conn,struct wpabuf * data)1766*a1157835SDaniel Fojt void tls_connection_set_success_data(struct tls_connection *conn,
1767*a1157835SDaniel Fojt 				     struct wpabuf *data)
1768*a1157835SDaniel Fojt {
1769*a1157835SDaniel Fojt }
1770*a1157835SDaniel Fojt 
1771*a1157835SDaniel Fojt 
tls_connection_set_success_data_resumed(struct tls_connection * conn)1772*a1157835SDaniel Fojt void tls_connection_set_success_data_resumed(struct tls_connection *conn)
1773*a1157835SDaniel Fojt {
1774*a1157835SDaniel Fojt }
1775*a1157835SDaniel Fojt 
1776*a1157835SDaniel Fojt 
1777*a1157835SDaniel Fojt const struct wpabuf *
tls_connection_get_success_data(struct tls_connection * conn)1778*a1157835SDaniel Fojt tls_connection_get_success_data(struct tls_connection *conn)
1779*a1157835SDaniel Fojt {
1780*a1157835SDaniel Fojt 	return NULL;
1781*a1157835SDaniel Fojt }
1782*a1157835SDaniel Fojt 
1783*a1157835SDaniel Fojt 
tls_connection_remove_session(struct tls_connection * conn)1784*a1157835SDaniel Fojt void tls_connection_remove_session(struct tls_connection *conn)
1785*a1157835SDaniel Fojt {
1786*a1157835SDaniel Fojt }
1787