xref: /freebsd/contrib/wpa/src/crypto/tls_gnutls.c (revision 4bc52338)
139beb93cSSam Leffler /*
2e28a4053SRui Paulo  * SSL/TLS interface functions for GnuTLS
385732ac8SCy Schubert  * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler #include <gnutls/gnutls.h>
1139beb93cSSam Leffler #include <gnutls/x509.h>
1239beb93cSSam Leffler #ifdef PKCS12_FUNCS
1339beb93cSSam Leffler #include <gnutls/pkcs12.h>
1439beb93cSSam Leffler #endif /* PKCS12_FUNCS */
155b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030103
165b9c547cSRui Paulo #include <gnutls/ocsp.h>
175b9c547cSRui Paulo #endif /* 3.1.3 */
1839beb93cSSam Leffler 
1939beb93cSSam Leffler #include "common.h"
205b9c547cSRui Paulo #include "crypto/crypto.h"
2139beb93cSSam Leffler #include "tls.h"
2239beb93cSSam Leffler 
2339beb93cSSam Leffler 
2439beb93cSSam Leffler static int tls_gnutls_ref_count = 0;
2539beb93cSSam Leffler 
2639beb93cSSam Leffler struct tls_global {
2739beb93cSSam Leffler 	/* Data for session resumption */
2839beb93cSSam Leffler 	void *session_data;
2939beb93cSSam Leffler 	size_t session_data_size;
3039beb93cSSam Leffler 
3139beb93cSSam Leffler 	int server;
3239beb93cSSam Leffler 
3339beb93cSSam Leffler 	int params_set;
3439beb93cSSam Leffler 	gnutls_certificate_credentials_t xcred;
355b9c547cSRui Paulo 
365b9c547cSRui Paulo 	void (*event_cb)(void *ctx, enum tls_event ev,
375b9c547cSRui Paulo 			 union tls_event_data *data);
385b9c547cSRui Paulo 	void *cb_ctx;
395b9c547cSRui Paulo 	int cert_in_cb;
40780fb4a2SCy Schubert 
41780fb4a2SCy Schubert 	char *ocsp_stapling_response;
4239beb93cSSam Leffler };
4339beb93cSSam Leffler 
4439beb93cSSam Leffler struct tls_connection {
455b9c547cSRui Paulo 	struct tls_global *global;
465b9c547cSRui Paulo 	gnutls_session_t session;
4739beb93cSSam Leffler 	int read_alerts, write_alerts, failed;
4839beb93cSSam Leffler 
4939beb93cSSam Leffler 	u8 *pre_shared_secret;
5039beb93cSSam Leffler 	size_t pre_shared_secret_len;
5139beb93cSSam Leffler 	int established;
5239beb93cSSam Leffler 	int verify_peer;
535b9c547cSRui Paulo 	unsigned int disable_time_checks:1;
5439beb93cSSam Leffler 
55e28a4053SRui Paulo 	struct wpabuf *push_buf;
56e28a4053SRui Paulo 	struct wpabuf *pull_buf;
57e28a4053SRui Paulo 	const u8 *pull_buf_offset;
5839beb93cSSam Leffler 
5939beb93cSSam Leffler 	int params_set;
6039beb93cSSam Leffler 	gnutls_certificate_credentials_t xcred;
615b9c547cSRui Paulo 
625b9c547cSRui Paulo 	char *suffix_match;
635b9c547cSRui Paulo 	char *domain_match;
645b9c547cSRui Paulo 	unsigned int flags;
6539beb93cSSam Leffler };
6639beb93cSSam Leffler 
6739beb93cSSam Leffler 
685b9c547cSRui Paulo static int tls_connection_verify_peer(gnutls_session_t session);
695b9c547cSRui Paulo 
705b9c547cSRui Paulo 
tls_log_func(int level,const char * msg)7139beb93cSSam Leffler static void tls_log_func(int level, const char *msg)
7239beb93cSSam Leffler {
7339beb93cSSam Leffler 	char *s, *pos;
7439beb93cSSam Leffler 	if (level == 6 || level == 7) {
7539beb93cSSam Leffler 		/* These levels seem to be mostly I/O debug and msg dumps */
7639beb93cSSam Leffler 		return;
7739beb93cSSam Leffler 	}
7839beb93cSSam Leffler 
7939beb93cSSam Leffler 	s = os_strdup(msg);
8039beb93cSSam Leffler 	if (s == NULL)
8139beb93cSSam Leffler 		return;
8239beb93cSSam Leffler 
8339beb93cSSam Leffler 	pos = s;
8439beb93cSSam Leffler 	while (*pos != '\0') {
8539beb93cSSam Leffler 		if (*pos == '\n') {
8639beb93cSSam Leffler 			*pos = '\0';
8739beb93cSSam Leffler 			break;
8839beb93cSSam Leffler 		}
8939beb93cSSam Leffler 		pos++;
9039beb93cSSam Leffler 	}
9139beb93cSSam Leffler 	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
9239beb93cSSam Leffler 		   "gnutls<%d> %s", level, s);
9339beb93cSSam Leffler 	os_free(s);
9439beb93cSSam Leffler }
9539beb93cSSam Leffler 
9639beb93cSSam Leffler 
tls_init(const struct tls_config * conf)9739beb93cSSam Leffler void * tls_init(const struct tls_config *conf)
9839beb93cSSam Leffler {
9939beb93cSSam Leffler 	struct tls_global *global;
10039beb93cSSam Leffler 
1015b9c547cSRui Paulo 	if (tls_gnutls_ref_count == 0) {
1025b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG,
1035b9c547cSRui Paulo 			   "GnuTLS: Library version %s (runtime) - %s (build)",
1045b9c547cSRui Paulo 			   gnutls_check_version(NULL), GNUTLS_VERSION);
1055b9c547cSRui Paulo 	}
10639beb93cSSam Leffler 
10739beb93cSSam Leffler 	global = os_zalloc(sizeof(*global));
10839beb93cSSam Leffler 	if (global == NULL)
10939beb93cSSam Leffler 		return NULL;
11039beb93cSSam Leffler 
11139beb93cSSam Leffler 	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
11239beb93cSSam Leffler 		os_free(global);
11339beb93cSSam Leffler 		return NULL;
11439beb93cSSam Leffler 	}
11539beb93cSSam Leffler 	tls_gnutls_ref_count++;
11639beb93cSSam Leffler 
11739beb93cSSam Leffler 	gnutls_global_set_log_function(tls_log_func);
11839beb93cSSam Leffler 	if (wpa_debug_show_keys)
11939beb93cSSam Leffler 		gnutls_global_set_log_level(11);
1205b9c547cSRui Paulo 
1215b9c547cSRui Paulo 	if (conf) {
1225b9c547cSRui Paulo 		global->event_cb = conf->event_cb;
1235b9c547cSRui Paulo 		global->cb_ctx = conf->cb_ctx;
1245b9c547cSRui Paulo 		global->cert_in_cb = conf->cert_in_cb;
1255b9c547cSRui Paulo 	}
1265b9c547cSRui Paulo 
12739beb93cSSam Leffler 	return global;
12839beb93cSSam Leffler }
12939beb93cSSam Leffler 
13039beb93cSSam Leffler 
tls_deinit(void * ssl_ctx)13139beb93cSSam Leffler void tls_deinit(void *ssl_ctx)
13239beb93cSSam Leffler {
13339beb93cSSam Leffler 	struct tls_global *global = ssl_ctx;
13439beb93cSSam Leffler 	if (global) {
13539beb93cSSam Leffler 		if (global->params_set)
13639beb93cSSam Leffler 			gnutls_certificate_free_credentials(global->xcred);
13739beb93cSSam Leffler 		os_free(global->session_data);
138780fb4a2SCy Schubert 		os_free(global->ocsp_stapling_response);
13939beb93cSSam Leffler 		os_free(global);
14039beb93cSSam Leffler 	}
14139beb93cSSam Leffler 
14239beb93cSSam Leffler 	tls_gnutls_ref_count--;
14339beb93cSSam Leffler 	if (tls_gnutls_ref_count == 0)
14439beb93cSSam Leffler 		gnutls_global_deinit();
14539beb93cSSam Leffler }
14639beb93cSSam Leffler 
14739beb93cSSam Leffler 
tls_get_errors(void * ssl_ctx)14839beb93cSSam Leffler int tls_get_errors(void *ssl_ctx)
14939beb93cSSam Leffler {
15039beb93cSSam Leffler 	return 0;
15139beb93cSSam Leffler }
15239beb93cSSam Leffler 
15339beb93cSSam Leffler 
tls_pull_func(gnutls_transport_ptr_t ptr,void * buf,size_t len)1545b9c547cSRui Paulo static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
15539beb93cSSam Leffler 			     size_t len)
15639beb93cSSam Leffler {
15739beb93cSSam Leffler 	struct tls_connection *conn = (struct tls_connection *) ptr;
158e28a4053SRui Paulo 	const u8 *end;
15939beb93cSSam Leffler 	if (conn->pull_buf == NULL) {
16039beb93cSSam Leffler 		errno = EWOULDBLOCK;
16139beb93cSSam Leffler 		return -1;
16239beb93cSSam Leffler 	}
16339beb93cSSam Leffler 
164e28a4053SRui Paulo 	end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
16539beb93cSSam Leffler 	if ((size_t) (end - conn->pull_buf_offset) < len)
16639beb93cSSam Leffler 		len = end - conn->pull_buf_offset;
16739beb93cSSam Leffler 	os_memcpy(buf, conn->pull_buf_offset, len);
16839beb93cSSam Leffler 	conn->pull_buf_offset += len;
16939beb93cSSam Leffler 	if (conn->pull_buf_offset == end) {
17039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
171e28a4053SRui Paulo 		wpabuf_free(conn->pull_buf);
172e28a4053SRui Paulo 		conn->pull_buf = NULL;
173e28a4053SRui Paulo 		conn->pull_buf_offset = NULL;
17439beb93cSSam Leffler 	} else {
17539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
17639beb93cSSam Leffler 			   __func__,
17739beb93cSSam Leffler 			   (unsigned long) (end - conn->pull_buf_offset));
17839beb93cSSam Leffler 	}
17939beb93cSSam Leffler 	return len;
18039beb93cSSam Leffler }
18139beb93cSSam Leffler 
18239beb93cSSam Leffler 
tls_push_func(gnutls_transport_ptr_t ptr,const void * buf,size_t len)1835b9c547cSRui Paulo static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
18439beb93cSSam Leffler 			     size_t len)
18539beb93cSSam Leffler {
18639beb93cSSam Leffler 	struct tls_connection *conn = (struct tls_connection *) ptr;
18739beb93cSSam Leffler 
188e28a4053SRui Paulo 	if (wpabuf_resize(&conn->push_buf, len) < 0) {
18939beb93cSSam Leffler 		errno = ENOMEM;
19039beb93cSSam Leffler 		return -1;
19139beb93cSSam Leffler 	}
192e28a4053SRui Paulo 	wpabuf_put_data(conn->push_buf, buf, len);
19339beb93cSSam Leffler 
19439beb93cSSam Leffler 	return len;
19539beb93cSSam Leffler }
19639beb93cSSam Leffler 
19739beb93cSSam Leffler 
tls_gnutls_init_session(struct tls_global * global,struct tls_connection * conn)19839beb93cSSam Leffler static int tls_gnutls_init_session(struct tls_global *global,
19939beb93cSSam Leffler 				   struct tls_connection *conn)
20039beb93cSSam Leffler {
201f05cddf9SRui Paulo 	const char *err;
20239beb93cSSam Leffler 	int ret;
20339beb93cSSam Leffler 
20439beb93cSSam Leffler 	ret = gnutls_init(&conn->session,
20539beb93cSSam Leffler 			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
20639beb93cSSam Leffler 	if (ret < 0) {
20739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
20839beb93cSSam Leffler 			   "connection: %s", gnutls_strerror(ret));
20939beb93cSSam Leffler 		return -1;
21039beb93cSSam Leffler 	}
21139beb93cSSam Leffler 
21239beb93cSSam Leffler 	ret = gnutls_set_default_priority(conn->session);
21339beb93cSSam Leffler 	if (ret < 0)
21439beb93cSSam Leffler 		goto fail;
21539beb93cSSam Leffler 
216f05cddf9SRui Paulo 	ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
217f05cddf9SRui Paulo 					 &err);
218f05cddf9SRui Paulo 	if (ret < 0) {
219f05cddf9SRui Paulo 		wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
220f05cddf9SRui Paulo 			   "'%s'", err);
221f05cddf9SRui Paulo 		goto fail;
222f05cddf9SRui Paulo 	}
22339beb93cSSam Leffler 
22439beb93cSSam Leffler 	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
22539beb93cSSam Leffler 	gnutls_transport_set_push_function(conn->session, tls_push_func);
2265b9c547cSRui Paulo 	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
2275b9c547cSRui Paulo 	gnutls_session_set_ptr(conn->session, conn);
22839beb93cSSam Leffler 
22939beb93cSSam Leffler 	return 0;
23039beb93cSSam Leffler 
23139beb93cSSam Leffler fail:
23239beb93cSSam Leffler 	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
23339beb93cSSam Leffler 		   gnutls_strerror(ret));
23439beb93cSSam Leffler 	gnutls_deinit(conn->session);
23539beb93cSSam Leffler 	return -1;
23639beb93cSSam Leffler }
23739beb93cSSam Leffler 
23839beb93cSSam Leffler 
tls_connection_init(void * ssl_ctx)23939beb93cSSam Leffler struct tls_connection * tls_connection_init(void *ssl_ctx)
24039beb93cSSam Leffler {
24139beb93cSSam Leffler 	struct tls_global *global = ssl_ctx;
24239beb93cSSam Leffler 	struct tls_connection *conn;
24339beb93cSSam Leffler 	int ret;
24439beb93cSSam Leffler 
24539beb93cSSam Leffler 	conn = os_zalloc(sizeof(*conn));
24639beb93cSSam Leffler 	if (conn == NULL)
24739beb93cSSam Leffler 		return NULL;
2485b9c547cSRui Paulo 	conn->global = global;
24939beb93cSSam Leffler 
25039beb93cSSam Leffler 	if (tls_gnutls_init_session(global, conn)) {
25139beb93cSSam Leffler 		os_free(conn);
25239beb93cSSam Leffler 		return NULL;
25339beb93cSSam Leffler 	}
25439beb93cSSam Leffler 
25539beb93cSSam Leffler 	if (global->params_set) {
25639beb93cSSam Leffler 		ret = gnutls_credentials_set(conn->session,
25739beb93cSSam Leffler 					     GNUTLS_CRD_CERTIFICATE,
25839beb93cSSam Leffler 					     global->xcred);
25939beb93cSSam Leffler 		if (ret < 0) {
26039beb93cSSam Leffler 			wpa_printf(MSG_INFO, "Failed to configure "
26139beb93cSSam Leffler 				   "credentials: %s", gnutls_strerror(ret));
26239beb93cSSam Leffler 			os_free(conn);
26339beb93cSSam Leffler 			return NULL;
26439beb93cSSam Leffler 		}
26539beb93cSSam Leffler 	}
26639beb93cSSam Leffler 
26739beb93cSSam Leffler 	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
26839beb93cSSam Leffler 		os_free(conn);
26939beb93cSSam Leffler 		return NULL;
27039beb93cSSam Leffler 	}
27139beb93cSSam Leffler 
27239beb93cSSam Leffler 	return conn;
27339beb93cSSam Leffler }
27439beb93cSSam Leffler 
27539beb93cSSam Leffler 
tls_connection_deinit(void * ssl_ctx,struct tls_connection * conn)27639beb93cSSam Leffler void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
27739beb93cSSam Leffler {
27839beb93cSSam Leffler 	if (conn == NULL)
27939beb93cSSam Leffler 		return;
28039beb93cSSam Leffler 
28139beb93cSSam Leffler 	gnutls_certificate_free_credentials(conn->xcred);
28239beb93cSSam Leffler 	gnutls_deinit(conn->session);
28339beb93cSSam Leffler 	os_free(conn->pre_shared_secret);
284e28a4053SRui Paulo 	wpabuf_free(conn->push_buf);
285e28a4053SRui Paulo 	wpabuf_free(conn->pull_buf);
2865b9c547cSRui Paulo 	os_free(conn->suffix_match);
2875b9c547cSRui Paulo 	os_free(conn->domain_match);
28839beb93cSSam Leffler 	os_free(conn);
28939beb93cSSam Leffler }
29039beb93cSSam Leffler 
29139beb93cSSam Leffler 
tls_connection_established(void * ssl_ctx,struct tls_connection * conn)29239beb93cSSam Leffler int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
29339beb93cSSam Leffler {
29439beb93cSSam Leffler 	return conn ? conn->established : 0;
29539beb93cSSam Leffler }
29639beb93cSSam Leffler 
29739beb93cSSam Leffler 
tls_connection_peer_serial_num(void * tls_ctx,struct tls_connection * conn)29885732ac8SCy Schubert char * tls_connection_peer_serial_num(void *tls_ctx,
29985732ac8SCy Schubert 				      struct tls_connection *conn)
30085732ac8SCy Schubert {
30185732ac8SCy Schubert 	/* TODO */
30285732ac8SCy Schubert 	return NULL;
30385732ac8SCy Schubert }
30485732ac8SCy Schubert 
30585732ac8SCy Schubert 
tls_connection_shutdown(void * ssl_ctx,struct tls_connection * conn)30639beb93cSSam Leffler int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
30739beb93cSSam Leffler {
30839beb93cSSam Leffler 	struct tls_global *global = ssl_ctx;
30939beb93cSSam Leffler 	int ret;
31039beb93cSSam Leffler 
31139beb93cSSam Leffler 	if (conn == NULL)
31239beb93cSSam Leffler 		return -1;
31339beb93cSSam Leffler 
31439beb93cSSam Leffler 	/* Shutdown previous TLS connection without notifying the peer
31539beb93cSSam Leffler 	 * because the connection was already terminated in practice
31639beb93cSSam Leffler 	 * and "close notify" shutdown alert would confuse AS. */
31739beb93cSSam Leffler 	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
318e28a4053SRui Paulo 	wpabuf_free(conn->push_buf);
31939beb93cSSam Leffler 	conn->push_buf = NULL;
32039beb93cSSam Leffler 	conn->established = 0;
32139beb93cSSam Leffler 
32239beb93cSSam Leffler 	gnutls_deinit(conn->session);
32339beb93cSSam Leffler 	if (tls_gnutls_init_session(global, conn)) {
32439beb93cSSam Leffler 		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
32539beb93cSSam Leffler 			   "for session resumption use");
32639beb93cSSam Leffler 		return -1;
32739beb93cSSam Leffler 	}
32839beb93cSSam Leffler 
32939beb93cSSam Leffler 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
33039beb93cSSam Leffler 				     conn->params_set ? conn->xcred :
33139beb93cSSam Leffler 				     global->xcred);
33239beb93cSSam Leffler 	if (ret < 0) {
33339beb93cSSam Leffler 		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
33439beb93cSSam Leffler 			   "for session resumption: %s", gnutls_strerror(ret));
33539beb93cSSam Leffler 		return -1;
33639beb93cSSam Leffler 	}
33739beb93cSSam Leffler 
33839beb93cSSam Leffler 	if (global->session_data) {
33939beb93cSSam Leffler 		ret = gnutls_session_set_data(conn->session,
34039beb93cSSam Leffler 					      global->session_data,
34139beb93cSSam Leffler 					      global->session_data_size);
34239beb93cSSam Leffler 		if (ret < 0) {
34339beb93cSSam Leffler 			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
34439beb93cSSam Leffler 				   "data: %s", gnutls_strerror(ret));
34539beb93cSSam Leffler 			return -1;
34639beb93cSSam Leffler 		}
34739beb93cSSam Leffler 	}
34839beb93cSSam Leffler 
34939beb93cSSam Leffler 	return 0;
35039beb93cSSam Leffler }
35139beb93cSSam Leffler 
35239beb93cSSam Leffler 
tls_connection_set_params(void * tls_ctx,struct tls_connection * conn,const struct tls_connection_params * params)35339beb93cSSam Leffler int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
35439beb93cSSam Leffler 			      const struct tls_connection_params *params)
35539beb93cSSam Leffler {
35639beb93cSSam Leffler 	int ret;
35785732ac8SCy Schubert 	const char *err;
35885732ac8SCy Schubert 	char prio_buf[100];
35985732ac8SCy Schubert 	const char *prio = NULL;
36039beb93cSSam Leffler 
36139beb93cSSam Leffler 	if (conn == NULL || params == NULL)
36239beb93cSSam Leffler 		return -1;
36339beb93cSSam Leffler 
364780fb4a2SCy Schubert 	if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
365780fb4a2SCy Schubert 		wpa_printf(MSG_INFO,
366780fb4a2SCy Schubert 			   "GnuTLS: ocsp=3 not supported");
367780fb4a2SCy Schubert 		return -1;
368780fb4a2SCy Schubert 	}
369780fb4a2SCy Schubert 
370780fb4a2SCy Schubert 	if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
371780fb4a2SCy Schubert 		wpa_printf(MSG_INFO,
372780fb4a2SCy Schubert 			   "GnuTLS: tls_ext_cert_check=1 not supported");
373780fb4a2SCy Schubert 		return -1;
374780fb4a2SCy Schubert 	}
375780fb4a2SCy Schubert 
37639beb93cSSam Leffler 	if (params->subject_match) {
3775b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
37839beb93cSSam Leffler 		return -1;
37939beb93cSSam Leffler 	}
38039beb93cSSam Leffler 
38139beb93cSSam Leffler 	if (params->altsubject_match) {
3825b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
3835b9c547cSRui Paulo 		return -1;
3845b9c547cSRui Paulo 	}
3855b9c547cSRui Paulo 
3865b9c547cSRui Paulo 	os_free(conn->suffix_match);
3875b9c547cSRui Paulo 	conn->suffix_match = NULL;
3885b9c547cSRui Paulo 	if (params->suffix_match) {
3895b9c547cSRui Paulo 		conn->suffix_match = os_strdup(params->suffix_match);
3905b9c547cSRui Paulo 		if (conn->suffix_match == NULL)
3915b9c547cSRui Paulo 			return -1;
3925b9c547cSRui Paulo 	}
3935b9c547cSRui Paulo 
3945b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030300
3955b9c547cSRui Paulo 	os_free(conn->domain_match);
3965b9c547cSRui Paulo 	conn->domain_match = NULL;
3975b9c547cSRui Paulo 	if (params->domain_match) {
3985b9c547cSRui Paulo 		conn->domain_match = os_strdup(params->domain_match);
3995b9c547cSRui Paulo 		if (conn->domain_match == NULL)
4005b9c547cSRui Paulo 			return -1;
4015b9c547cSRui Paulo 	}
4025b9c547cSRui Paulo #else /* < 3.3.0 */
4035b9c547cSRui Paulo 	if (params->domain_match) {
4045b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
4055b9c547cSRui Paulo 		return -1;
4065b9c547cSRui Paulo 	}
4075b9c547cSRui Paulo #endif /* >= 3.3.0 */
4085b9c547cSRui Paulo 
4095b9c547cSRui Paulo 	conn->flags = params->flags;
4105b9c547cSRui Paulo 
41185732ac8SCy Schubert 	if (params->flags & (TLS_CONN_DISABLE_TLSv1_0 |
41285732ac8SCy Schubert 			     TLS_CONN_DISABLE_TLSv1_1 |
41385732ac8SCy Schubert 			     TLS_CONN_DISABLE_TLSv1_2)) {
41485732ac8SCy Schubert 		os_snprintf(prio_buf, sizeof(prio_buf),
41585732ac8SCy Schubert 			    "NORMAL:-VERS-SSL3.0%s%s%s",
41685732ac8SCy Schubert 			    params->flags & TLS_CONN_DISABLE_TLSv1_0 ?
41785732ac8SCy Schubert 			    ":-VERS-TLS1.0" : "",
41885732ac8SCy Schubert 			    params->flags & TLS_CONN_DISABLE_TLSv1_1 ?
41985732ac8SCy Schubert 			    ":-VERS-TLS1.1" : "",
42085732ac8SCy Schubert 			    params->flags & TLS_CONN_DISABLE_TLSv1_2 ?
42185732ac8SCy Schubert 			    ":-VERS-TLS1.2" : "");
42285732ac8SCy Schubert 		prio = prio_buf;
42385732ac8SCy Schubert 	}
42485732ac8SCy Schubert 
4255b9c547cSRui Paulo 	if (params->openssl_ciphers) {
42685732ac8SCy Schubert 		if (os_strcmp(params->openssl_ciphers, "SUITEB128") == 0) {
42785732ac8SCy Schubert 			prio = "SUITEB128";
42885732ac8SCy Schubert 		} else if (os_strcmp(params->openssl_ciphers,
42985732ac8SCy Schubert 				     "SUITEB192") == 0) {
43085732ac8SCy Schubert 			prio = "SUITEB192";
43185732ac8SCy Schubert 		} else if ((params->flags & TLS_CONN_SUITEB) &&
43285732ac8SCy Schubert 			   os_strcmp(params->openssl_ciphers,
43385732ac8SCy Schubert 				     "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
43485732ac8SCy Schubert 			prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
43585732ac8SCy Schubert 		} else if (os_strcmp(params->openssl_ciphers,
43685732ac8SCy Schubert 				     "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
43785732ac8SCy Schubert 			prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
43885732ac8SCy Schubert 		} else if (os_strcmp(params->openssl_ciphers,
43985732ac8SCy Schubert 				     "DHE-RSA-AES256-GCM-SHA384") == 0) {
44085732ac8SCy Schubert 			prio = "NONE:+VERS-TLS1.2:+AEAD:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
44185732ac8SCy Schubert 		} else if (os_strcmp(params->openssl_ciphers,
44285732ac8SCy Schubert 				     "ECDHE-ECDSA-AES256-GCM-SHA384") == 0) {
44385732ac8SCy Schubert 			prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
44485732ac8SCy Schubert 		} else {
44585732ac8SCy Schubert 			wpa_printf(MSG_INFO,
44685732ac8SCy Schubert 				   "GnuTLS: openssl_ciphers not supported");
44739beb93cSSam Leffler 			return -1;
44839beb93cSSam Leffler 		}
44985732ac8SCy Schubert 	} else if (params->flags & TLS_CONN_SUITEB) {
45085732ac8SCy Schubert 		prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
45185732ac8SCy Schubert 	}
45285732ac8SCy Schubert 
45385732ac8SCy Schubert 	if (prio) {
45485732ac8SCy Schubert 		wpa_printf(MSG_DEBUG, "GnuTLS: Set priority string: %s", prio);
45585732ac8SCy Schubert 		ret = gnutls_priority_set_direct(conn->session, prio, &err);
45685732ac8SCy Schubert 		if (ret < 0) {
45785732ac8SCy Schubert 			wpa_printf(MSG_ERROR,
45885732ac8SCy Schubert 				   "GnuTLS: Priority string failure at '%s'",
45985732ac8SCy Schubert 				   err);
46085732ac8SCy Schubert 			return -1;
46185732ac8SCy Schubert 		}
46285732ac8SCy Schubert 	}
46339beb93cSSam Leffler 
464*4bc52338SCy Schubert 	if (params->openssl_ecdh_curves) {
465*4bc52338SCy Schubert 		wpa_printf(MSG_INFO,
466*4bc52338SCy Schubert 			   "GnuTLS: openssl_ecdh_curves not supported");
467*4bc52338SCy Schubert 		return -1;
468*4bc52338SCy Schubert 	}
469*4bc52338SCy Schubert 
47039beb93cSSam Leffler 	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
47139beb93cSSam Leffler 	 * to force peer validation(?) */
47239beb93cSSam Leffler 
47339beb93cSSam Leffler 	if (params->ca_cert) {
4745b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
4755b9c547cSRui Paulo 			   params->ca_cert);
47639beb93cSSam Leffler 		ret = gnutls_certificate_set_x509_trust_file(
4775b9c547cSRui Paulo 			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
47839beb93cSSam Leffler 		if (ret < 0) {
4795b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG,
4805b9c547cSRui Paulo 				   "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
4815b9c547cSRui Paulo 				   params->ca_cert,
48239beb93cSSam Leffler 				   gnutls_strerror(ret));
48339beb93cSSam Leffler 			ret = gnutls_certificate_set_x509_trust_file(
48439beb93cSSam Leffler 				conn->xcred, params->ca_cert,
4855b9c547cSRui Paulo 				GNUTLS_X509_FMT_PEM);
48639beb93cSSam Leffler 			if (ret < 0) {
4875b9c547cSRui Paulo 				wpa_printf(MSG_DEBUG,
4885b9c547cSRui Paulo 					   "Failed to read CA cert '%s' in PEM format: %s",
48939beb93cSSam Leffler 					   params->ca_cert,
49039beb93cSSam Leffler 					   gnutls_strerror(ret));
49139beb93cSSam Leffler 				return -1;
49239beb93cSSam Leffler 			}
49385732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
49485732ac8SCy Schubert 				   "GnuTLS: Successfully read CA cert '%s' in PEM format",
49585732ac8SCy Schubert 				   params->ca_cert);
49685732ac8SCy Schubert 		} else {
49785732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
49885732ac8SCy Schubert 				   "GnuTLS: Successfully read CA cert '%s' in DER format",
49985732ac8SCy Schubert 				   params->ca_cert);
50039beb93cSSam Leffler 		}
5015b9c547cSRui Paulo 	} else if (params->ca_cert_blob) {
5025b9c547cSRui Paulo 		gnutls_datum_t ca;
5035b9c547cSRui Paulo 
5045b9c547cSRui Paulo 		ca.data = (unsigned char *) params->ca_cert_blob;
5055b9c547cSRui Paulo 		ca.size = params->ca_cert_blob_len;
5065b9c547cSRui Paulo 
5075b9c547cSRui Paulo 		ret = gnutls_certificate_set_x509_trust_mem(
5085b9c547cSRui Paulo 			conn->xcred, &ca, GNUTLS_X509_FMT_DER);
5095b9c547cSRui Paulo 		if (ret < 0) {
5105b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG,
5115b9c547cSRui Paulo 				   "Failed to parse CA cert in DER format: %s",
5125b9c547cSRui Paulo 				   gnutls_strerror(ret));
5135b9c547cSRui Paulo 			ret = gnutls_certificate_set_x509_trust_mem(
5145b9c547cSRui Paulo 				conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
5155b9c547cSRui Paulo 			if (ret < 0) {
5165b9c547cSRui Paulo 				wpa_printf(MSG_DEBUG,
5175b9c547cSRui Paulo 					   "Failed to parse CA cert in PEM format: %s",
5185b9c547cSRui Paulo 					   gnutls_strerror(ret));
5195b9c547cSRui Paulo 				return -1;
5205b9c547cSRui Paulo 			}
5215b9c547cSRui Paulo 		}
5225b9c547cSRui Paulo 	} else if (params->ca_path) {
5235b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
5245b9c547cSRui Paulo 		return -1;
5255b9c547cSRui Paulo 	}
5265b9c547cSRui Paulo 
5275b9c547cSRui Paulo 	conn->disable_time_checks = 0;
5285b9c547cSRui Paulo 	if (params->ca_cert || params->ca_cert_blob) {
5295b9c547cSRui Paulo 		conn->verify_peer = 1;
5305b9c547cSRui Paulo 		gnutls_certificate_set_verify_function(
5315b9c547cSRui Paulo 			conn->xcred, tls_connection_verify_peer);
5323157ba21SRui Paulo 
5333157ba21SRui Paulo 		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
5343157ba21SRui Paulo 			gnutls_certificate_set_verify_flags(
5353157ba21SRui Paulo 				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
5363157ba21SRui Paulo 		}
5373157ba21SRui Paulo 
5383157ba21SRui Paulo 		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
5395b9c547cSRui Paulo 			conn->disable_time_checks = 1;
5403157ba21SRui Paulo 			gnutls_certificate_set_verify_flags(
5413157ba21SRui Paulo 				conn->xcred,
5423157ba21SRui Paulo 				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
5433157ba21SRui Paulo 		}
54439beb93cSSam Leffler 	}
54539beb93cSSam Leffler 
54639beb93cSSam Leffler 	if (params->client_cert && params->private_key) {
54785732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
54885732ac8SCy Schubert 			   "GnuTLS: Try to parse client cert '%s' and key '%s' in DER format",
54985732ac8SCy Schubert 			   params->client_cert, params->private_key);
5505b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x03010b
5515b9c547cSRui Paulo 		ret = gnutls_certificate_set_x509_key_file2(
5525b9c547cSRui Paulo 			conn->xcred, params->client_cert, params->private_key,
5535b9c547cSRui Paulo 			GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
5545b9c547cSRui Paulo #else
5555b9c547cSRui Paulo 		/* private_key_passwd not (easily) supported here */
55639beb93cSSam Leffler 		ret = gnutls_certificate_set_x509_key_file(
55739beb93cSSam Leffler 			conn->xcred, params->client_cert, params->private_key,
5585b9c547cSRui Paulo 			GNUTLS_X509_FMT_DER);
5595b9c547cSRui Paulo #endif
56039beb93cSSam Leffler 		if (ret < 0) {
56185732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
56285732ac8SCy Schubert 				   "GnuTLS: Failed to read client cert/key in DER format (%s) - try in PEM format",
56385732ac8SCy Schubert 				   gnutls_strerror(ret));
5645b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x03010b
5655b9c547cSRui Paulo 			ret = gnutls_certificate_set_x509_key_file2(
5665b9c547cSRui Paulo 				conn->xcred, params->client_cert,
5675b9c547cSRui Paulo 				params->private_key, GNUTLS_X509_FMT_PEM,
5685b9c547cSRui Paulo 				params->private_key_passwd, 0);
5695b9c547cSRui Paulo #else
57039beb93cSSam Leffler 			ret = gnutls_certificate_set_x509_key_file(
57139beb93cSSam Leffler 				conn->xcred, params->client_cert,
5725b9c547cSRui Paulo 				params->private_key, GNUTLS_X509_FMT_PEM);
5735b9c547cSRui Paulo #endif
57439beb93cSSam Leffler 			if (ret < 0) {
57539beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "Failed to read client "
5765b9c547cSRui Paulo 					   "cert/key in PEM format: %s",
57739beb93cSSam Leffler 					   gnutls_strerror(ret));
57839beb93cSSam Leffler 				return ret;
57939beb93cSSam Leffler 			}
58085732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
58185732ac8SCy Schubert 				   "GnuTLS: Successfully read client cert/key in PEM format");
58285732ac8SCy Schubert 		} else {
58385732ac8SCy Schubert 			wpa_printf(MSG_DEBUG,
58485732ac8SCy Schubert 				   "GnuTLS: Successfully read client cert/key in DER format");
58539beb93cSSam Leffler 		}
58639beb93cSSam Leffler 	} else if (params->private_key) {
58739beb93cSSam Leffler 		int pkcs12_ok = 0;
58839beb93cSSam Leffler #ifdef PKCS12_FUNCS
58939beb93cSSam Leffler 		/* Try to load in PKCS#12 format */
59085732ac8SCy Schubert 		wpa_printf(MSG_DEBUG,
59185732ac8SCy Schubert 			   "GnuTLS: Try to parse client cert/key '%s'in PKCS#12 DER format",
59285732ac8SCy Schubert 			   params->private_key);
59339beb93cSSam Leffler 		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
59439beb93cSSam Leffler 			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
59539beb93cSSam Leffler 			params->private_key_passwd);
59639beb93cSSam Leffler 		if (ret != 0) {
59739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
59839beb93cSSam Leffler 				   "PKCS#12 format: %s", gnutls_strerror(ret));
59939beb93cSSam Leffler 			return -1;
60039beb93cSSam Leffler 		} else
60139beb93cSSam Leffler 			pkcs12_ok = 1;
60239beb93cSSam Leffler #endif /* PKCS12_FUNCS */
60339beb93cSSam Leffler 
60439beb93cSSam Leffler 		if (!pkcs12_ok) {
60539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
60639beb93cSSam Leffler 				   "included");
60739beb93cSSam Leffler 			return -1;
60839beb93cSSam Leffler 		}
6095b9c547cSRui Paulo 	} else if (params->client_cert_blob && params->private_key_blob) {
6105b9c547cSRui Paulo 		gnutls_datum_t cert, key;
6115b9c547cSRui Paulo 
6125b9c547cSRui Paulo 		cert.data = (unsigned char *) params->client_cert_blob;
6135b9c547cSRui Paulo 		cert.size = params->client_cert_blob_len;
6145b9c547cSRui Paulo 		key.data = (unsigned char *) params->private_key_blob;
6155b9c547cSRui Paulo 		key.size = params->private_key_blob_len;
6165b9c547cSRui Paulo 
6175b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x03010b
6185b9c547cSRui Paulo 		ret = gnutls_certificate_set_x509_key_mem2(
6195b9c547cSRui Paulo 			conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
6205b9c547cSRui Paulo 			params->private_key_passwd, 0);
6215b9c547cSRui Paulo #else
6225b9c547cSRui Paulo 		/* private_key_passwd not (easily) supported here */
6235b9c547cSRui Paulo 		ret = gnutls_certificate_set_x509_key_mem(
6245b9c547cSRui Paulo 			conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
6255b9c547cSRui Paulo #endif
6265b9c547cSRui Paulo 		if (ret < 0) {
6275b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
6285b9c547cSRui Paulo 				   "in DER format: %s", gnutls_strerror(ret));
6295b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x03010b
6305b9c547cSRui Paulo 			ret = gnutls_certificate_set_x509_key_mem2(
6315b9c547cSRui Paulo 				conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
6325b9c547cSRui Paulo 				params->private_key_passwd, 0);
6335b9c547cSRui Paulo #else
6345b9c547cSRui Paulo 			/* private_key_passwd not (easily) supported here */
6355b9c547cSRui Paulo 			ret = gnutls_certificate_set_x509_key_mem(
6365b9c547cSRui Paulo 				conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
6375b9c547cSRui Paulo #endif
6385b9c547cSRui Paulo 			if (ret < 0) {
6395b9c547cSRui Paulo 				wpa_printf(MSG_DEBUG, "Failed to read client "
6405b9c547cSRui Paulo 					   "cert/key in PEM format: %s",
6415b9c547cSRui Paulo 					   gnutls_strerror(ret));
6425b9c547cSRui Paulo 				return ret;
64339beb93cSSam Leffler 			}
6445b9c547cSRui Paulo 		}
6455b9c547cSRui Paulo 	} else if (params->private_key_blob) {
6465b9c547cSRui Paulo #ifdef PKCS12_FUNCS
6475b9c547cSRui Paulo 		gnutls_datum_t key;
6485b9c547cSRui Paulo 
6495b9c547cSRui Paulo 		key.data = (unsigned char *) params->private_key_blob;
6505b9c547cSRui Paulo 		key.size = params->private_key_blob_len;
6515b9c547cSRui Paulo 
6525b9c547cSRui Paulo 		/* Try to load in PKCS#12 format */
6535b9c547cSRui Paulo 		ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
6545b9c547cSRui Paulo 			conn->xcred, &key, GNUTLS_X509_FMT_DER,
6555b9c547cSRui Paulo 			params->private_key_passwd);
6565b9c547cSRui Paulo 		if (ret != 0) {
6575b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
6585b9c547cSRui Paulo 				   "PKCS#12 format: %s", gnutls_strerror(ret));
6595b9c547cSRui Paulo 			return -1;
6605b9c547cSRui Paulo 		}
6615b9c547cSRui Paulo #else /* PKCS12_FUNCS */
6625b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
6635b9c547cSRui Paulo 		return -1;
6645b9c547cSRui Paulo #endif /* PKCS12_FUNCS */
6655b9c547cSRui Paulo 	}
6665b9c547cSRui Paulo 
6675b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030103
6685b9c547cSRui Paulo 	if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
6695b9c547cSRui Paulo 		ret = gnutls_ocsp_status_request_enable_client(conn->session,
6705b9c547cSRui Paulo 							       NULL, 0, NULL);
6715b9c547cSRui Paulo 		if (ret != GNUTLS_E_SUCCESS) {
6725b9c547cSRui Paulo 			wpa_printf(MSG_INFO,
6735b9c547cSRui Paulo 				   "GnuTLS: Failed to enable OCSP client");
6745b9c547cSRui Paulo 			return -1;
6755b9c547cSRui Paulo 		}
6765b9c547cSRui Paulo 	}
6775b9c547cSRui Paulo #else /* 3.1.3 */
6785b9c547cSRui Paulo 	if (params->flags & TLS_CONN_REQUIRE_OCSP) {
6795b9c547cSRui Paulo 		wpa_printf(MSG_INFO,
6805b9c547cSRui Paulo 			   "GnuTLS: OCSP not supported by this version of GnuTLS");
6815b9c547cSRui Paulo 		return -1;
6825b9c547cSRui Paulo 	}
6835b9c547cSRui Paulo #endif /* 3.1.3 */
68439beb93cSSam Leffler 
68539beb93cSSam Leffler 	conn->params_set = 1;
68639beb93cSSam Leffler 
68739beb93cSSam Leffler 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
68839beb93cSSam Leffler 				     conn->xcred);
68939beb93cSSam Leffler 	if (ret < 0) {
69039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
69139beb93cSSam Leffler 			   gnutls_strerror(ret));
69239beb93cSSam Leffler 	}
69339beb93cSSam Leffler 
69439beb93cSSam Leffler 	return ret;
69539beb93cSSam Leffler }
69639beb93cSSam Leffler 
69739beb93cSSam Leffler 
698780fb4a2SCy Schubert #if GNUTLS_VERSION_NUMBER >= 0x030103
server_ocsp_status_req(gnutls_session_t session,void * ptr,gnutls_datum_t * resp)699780fb4a2SCy Schubert static int server_ocsp_status_req(gnutls_session_t session, void *ptr,
700780fb4a2SCy Schubert 				  gnutls_datum_t *resp)
701780fb4a2SCy Schubert {
702780fb4a2SCy Schubert 	struct tls_global *global = ptr;
703780fb4a2SCy Schubert 	char *cached;
704780fb4a2SCy Schubert 	size_t len;
705780fb4a2SCy Schubert 
706780fb4a2SCy Schubert 	if (!global->ocsp_stapling_response) {
707780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
708780fb4a2SCy Schubert 		return GNUTLS_E_NO_CERTIFICATE_STATUS;
709780fb4a2SCy Schubert 	}
710780fb4a2SCy Schubert 
711780fb4a2SCy Schubert 	cached = os_readfile(global->ocsp_stapling_response, &len);
712780fb4a2SCy Schubert 	if (!cached) {
713780fb4a2SCy Schubert 		wpa_printf(MSG_DEBUG,
714780fb4a2SCy Schubert 			   "GnuTLS: OCSP status callback - could not read response file (%s)",
715780fb4a2SCy Schubert 			   global->ocsp_stapling_response);
716780fb4a2SCy Schubert 		return GNUTLS_E_NO_CERTIFICATE_STATUS;
717780fb4a2SCy Schubert 	}
718780fb4a2SCy Schubert 
719780fb4a2SCy Schubert 	wpa_printf(MSG_DEBUG,
720780fb4a2SCy Schubert 		   "GnuTLS: OCSP status callback - send cached response");
721780fb4a2SCy Schubert 	resp->data = gnutls_malloc(len);
722780fb4a2SCy Schubert 	if (!resp->data) {
723780fb4a2SCy Schubert 		os_free(resp);
724780fb4a2SCy Schubert 		return GNUTLS_E_MEMORY_ERROR;
725780fb4a2SCy Schubert 	}
726780fb4a2SCy Schubert 
727780fb4a2SCy Schubert 	os_memcpy(resp->data, cached, len);
728780fb4a2SCy Schubert 	resp->size = len;
729780fb4a2SCy Schubert 	os_free(cached);
730780fb4a2SCy Schubert 
731780fb4a2SCy Schubert 	return GNUTLS_E_SUCCESS;
732780fb4a2SCy Schubert }
733780fb4a2SCy Schubert #endif /* 3.1.3 */
734780fb4a2SCy Schubert 
735780fb4a2SCy Schubert 
tls_global_set_params(void * tls_ctx,const struct tls_connection_params * params)73639beb93cSSam Leffler int tls_global_set_params(void *tls_ctx,
73739beb93cSSam Leffler 			  const struct tls_connection_params *params)
73839beb93cSSam Leffler {
73939beb93cSSam Leffler 	struct tls_global *global = tls_ctx;
74039beb93cSSam Leffler 	int ret;
74139beb93cSSam Leffler 
742*4bc52338SCy Schubert 	if (params->check_cert_subject)
743*4bc52338SCy Schubert 		return -1; /* not yet supported */
744*4bc52338SCy Schubert 
74539beb93cSSam Leffler 	/* Currently, global parameters are only set when running in server
74639beb93cSSam Leffler 	 * mode. */
74739beb93cSSam Leffler 	global->server = 1;
74839beb93cSSam Leffler 
74939beb93cSSam Leffler 	if (global->params_set) {
75039beb93cSSam Leffler 		gnutls_certificate_free_credentials(global->xcred);
75139beb93cSSam Leffler 		global->params_set = 0;
75239beb93cSSam Leffler 	}
75339beb93cSSam Leffler 
75439beb93cSSam Leffler 	ret = gnutls_certificate_allocate_credentials(&global->xcred);
75539beb93cSSam Leffler 	if (ret) {
75639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
75739beb93cSSam Leffler 			   "%s", gnutls_strerror(ret));
75839beb93cSSam Leffler 		return -1;
75939beb93cSSam Leffler 	}
76039beb93cSSam Leffler 
76139beb93cSSam Leffler 	if (params->ca_cert) {
76239beb93cSSam Leffler 		ret = gnutls_certificate_set_x509_trust_file(
7635b9c547cSRui Paulo 			global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
76439beb93cSSam Leffler 		if (ret < 0) {
76539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
7665b9c547cSRui Paulo 				   "in DER format: %s", params->ca_cert,
76739beb93cSSam Leffler 				   gnutls_strerror(ret));
76839beb93cSSam Leffler 			ret = gnutls_certificate_set_x509_trust_file(
76939beb93cSSam Leffler 				global->xcred, params->ca_cert,
7705b9c547cSRui Paulo 				GNUTLS_X509_FMT_PEM);
77139beb93cSSam Leffler 			if (ret < 0) {
77239beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
7735b9c547cSRui Paulo 					   "'%s' in PEM format: %s",
77439beb93cSSam Leffler 					   params->ca_cert,
77539beb93cSSam Leffler 					   gnutls_strerror(ret));
77639beb93cSSam Leffler 				goto fail;
77739beb93cSSam Leffler 			}
77839beb93cSSam Leffler 		}
7793157ba21SRui Paulo 
7803157ba21SRui Paulo 		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
7813157ba21SRui Paulo 			gnutls_certificate_set_verify_flags(
7823157ba21SRui Paulo 				global->xcred,
7833157ba21SRui Paulo 				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
7843157ba21SRui Paulo 		}
7853157ba21SRui Paulo 
7863157ba21SRui Paulo 		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
7873157ba21SRui Paulo 			gnutls_certificate_set_verify_flags(
7883157ba21SRui Paulo 				global->xcred,
7893157ba21SRui Paulo 				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
7903157ba21SRui Paulo 		}
79139beb93cSSam Leffler 	}
79239beb93cSSam Leffler 
79339beb93cSSam Leffler 	if (params->client_cert && params->private_key) {
79439beb93cSSam Leffler 		/* TODO: private_key_passwd? */
79539beb93cSSam Leffler 		ret = gnutls_certificate_set_x509_key_file(
79639beb93cSSam Leffler 			global->xcred, params->client_cert,
79739beb93cSSam Leffler 			params->private_key, GNUTLS_X509_FMT_DER);
79839beb93cSSam Leffler 		if (ret < 0) {
7995b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
8005b9c547cSRui Paulo 				   "in DER format: %s", gnutls_strerror(ret));
8015b9c547cSRui Paulo 			ret = gnutls_certificate_set_x509_key_file(
8025b9c547cSRui Paulo 				global->xcred, params->client_cert,
8035b9c547cSRui Paulo 				params->private_key, GNUTLS_X509_FMT_PEM);
8045b9c547cSRui Paulo 			if (ret < 0) {
80539beb93cSSam Leffler 				wpa_printf(MSG_DEBUG, "Failed to read client "
8065b9c547cSRui Paulo 					   "cert/key in PEM format: %s",
80739beb93cSSam Leffler 					   gnutls_strerror(ret));
80839beb93cSSam Leffler 				goto fail;
80939beb93cSSam Leffler 			}
81039beb93cSSam Leffler 		}
81139beb93cSSam Leffler 	} else if (params->private_key) {
81239beb93cSSam Leffler 		int pkcs12_ok = 0;
81339beb93cSSam Leffler #ifdef PKCS12_FUNCS
81439beb93cSSam Leffler 		/* Try to load in PKCS#12 format */
81539beb93cSSam Leffler 		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
81639beb93cSSam Leffler 			global->xcred, params->private_key,
81739beb93cSSam Leffler 			GNUTLS_X509_FMT_DER, params->private_key_passwd);
81839beb93cSSam Leffler 		if (ret != 0) {
81939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
82039beb93cSSam Leffler 				   "PKCS#12 format: %s", gnutls_strerror(ret));
82139beb93cSSam Leffler 			goto fail;
82239beb93cSSam Leffler 		} else
82339beb93cSSam Leffler 			pkcs12_ok = 1;
82439beb93cSSam Leffler #endif /* PKCS12_FUNCS */
82539beb93cSSam Leffler 
82639beb93cSSam Leffler 		if (!pkcs12_ok) {
82739beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
82839beb93cSSam Leffler 				   "included");
82939beb93cSSam Leffler 			goto fail;
83039beb93cSSam Leffler 		}
83139beb93cSSam Leffler 	}
83239beb93cSSam Leffler 
833780fb4a2SCy Schubert #if GNUTLS_VERSION_NUMBER >= 0x030103
834780fb4a2SCy Schubert 	os_free(global->ocsp_stapling_response);
835780fb4a2SCy Schubert 	if (params->ocsp_stapling_response)
836780fb4a2SCy Schubert 		global->ocsp_stapling_response =
837780fb4a2SCy Schubert 			os_strdup(params->ocsp_stapling_response);
838780fb4a2SCy Schubert 	else
839780fb4a2SCy Schubert 		global->ocsp_stapling_response = NULL;
840780fb4a2SCy Schubert 	gnutls_certificate_set_ocsp_status_request_function(
841780fb4a2SCy Schubert 		global->xcred, server_ocsp_status_req, global);
842780fb4a2SCy Schubert #endif /* 3.1.3 */
843780fb4a2SCy Schubert 
84439beb93cSSam Leffler 	global->params_set = 1;
84539beb93cSSam Leffler 
84639beb93cSSam Leffler 	return 0;
84739beb93cSSam Leffler 
84839beb93cSSam Leffler fail:
84939beb93cSSam Leffler 	gnutls_certificate_free_credentials(global->xcred);
85039beb93cSSam Leffler 	return -1;
85139beb93cSSam Leffler }
85239beb93cSSam Leffler 
85339beb93cSSam Leffler 
tls_global_set_verify(void * ssl_ctx,int check_crl,int strict)854*4bc52338SCy Schubert int tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
85539beb93cSSam Leffler {
85639beb93cSSam Leffler 	/* TODO */
85739beb93cSSam Leffler 	return 0;
85839beb93cSSam Leffler }
85939beb93cSSam Leffler 
86039beb93cSSam Leffler 
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)86139beb93cSSam Leffler int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
862325151a3SRui Paulo 			      int verify_peer, unsigned int flags,
863325151a3SRui Paulo 			      const u8 *session_ctx, size_t session_ctx_len)
86439beb93cSSam Leffler {
86539beb93cSSam Leffler 	if (conn == NULL || conn->session == NULL)
86639beb93cSSam Leffler 		return -1;
86739beb93cSSam Leffler 
86839beb93cSSam Leffler 	conn->verify_peer = verify_peer;
86939beb93cSSam Leffler 	gnutls_certificate_server_set_request(conn->session,
87039beb93cSSam Leffler 					      verify_peer ? GNUTLS_CERT_REQUIRE
87139beb93cSSam Leffler 					      : GNUTLS_CERT_REQUEST);
87239beb93cSSam Leffler 
87339beb93cSSam Leffler 	return 0;
87439beb93cSSam Leffler }
87539beb93cSSam Leffler 
87639beb93cSSam Leffler 
tls_connection_get_random(void * ssl_ctx,struct tls_connection * conn,struct tls_random * keys)877325151a3SRui Paulo int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
878325151a3SRui Paulo 			    struct tls_random *keys)
87939beb93cSSam Leffler {
8805b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030012
8815b9c547cSRui Paulo 	gnutls_datum_t client, server;
88239beb93cSSam Leffler 
88339beb93cSSam Leffler 	if (conn == NULL || conn->session == NULL || keys == NULL)
88439beb93cSSam Leffler 		return -1;
88539beb93cSSam Leffler 
88639beb93cSSam Leffler 	os_memset(keys, 0, sizeof(*keys));
8875b9c547cSRui Paulo 	gnutls_session_get_random(conn->session, &client, &server);
8885b9c547cSRui Paulo 	keys->client_random = client.data;
8895b9c547cSRui Paulo 	keys->server_random = server.data;
8905b9c547cSRui Paulo 	keys->client_random_len = client.size;
8915b9c547cSRui Paulo 	keys->server_random_len = client.size;
89239beb93cSSam Leffler 
89339beb93cSSam Leffler 	return 0;
8945b9c547cSRui Paulo #else /* 3.0.18 */
8955b9c547cSRui Paulo 	return -1;
8965b9c547cSRui Paulo #endif /* 3.0.18 */
89739beb93cSSam Leffler }
89839beb93cSSam Leffler 
89939beb93cSSam Leffler 
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)900780fb4a2SCy Schubert int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
901*4bc52338SCy Schubert 			      const char *label, const u8 *context,
902*4bc52338SCy Schubert 			      size_t context_len, u8 *out, size_t out_len)
90339beb93cSSam Leffler {
904780fb4a2SCy Schubert 	if (conn == NULL || conn->session == NULL)
90539beb93cSSam Leffler 		return -1;
90639beb93cSSam Leffler 
907*4bc52338SCy Schubert #if GNUTLS_VERSION_NUMBER >= 0x030404
908*4bc52338SCy Schubert 	return gnutls_prf_rfc5705(conn->session, os_strlen(label), label,
909*4bc52338SCy Schubert 				  context_len, (const char *) context,
910*4bc52338SCy Schubert 				  out_len, (char *) out);
911*4bc52338SCy Schubert #else /* 3.4.4 */
912*4bc52338SCy Schubert 	if (context)
913*4bc52338SCy Schubert 		return -1;
91439beb93cSSam Leffler 	return gnutls_prf(conn->session, os_strlen(label), label,
915780fb4a2SCy Schubert 			  0 /* client_random first */, 0, NULL, out_len,
916780fb4a2SCy Schubert 			  (char *) out);
917*4bc52338SCy Schubert #endif /* 3.4.4 */
918780fb4a2SCy Schubert }
919780fb4a2SCy Schubert 
920780fb4a2SCy Schubert 
tls_connection_get_eap_fast_key(void * tls_ctx,struct tls_connection * conn,u8 * out,size_t out_len)921780fb4a2SCy Schubert int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
922780fb4a2SCy Schubert 				    u8 *out, size_t out_len)
923780fb4a2SCy Schubert {
924780fb4a2SCy Schubert 	return -1;
92539beb93cSSam Leffler }
92639beb93cSSam Leffler 
92739beb93cSSam Leffler 
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)9285b9c547cSRui Paulo static void gnutls_tls_fail_event(struct tls_connection *conn,
9295b9c547cSRui Paulo 				  const gnutls_datum_t *cert, int depth,
9305b9c547cSRui Paulo 				  const char *subject, const char *err_str,
9315b9c547cSRui Paulo 				  enum tls_fail_reason reason)
9325b9c547cSRui Paulo {
9335b9c547cSRui Paulo 	union tls_event_data ev;
9345b9c547cSRui Paulo 	struct tls_global *global = conn->global;
9355b9c547cSRui Paulo 	struct wpabuf *cert_buf = NULL;
9365b9c547cSRui Paulo 
9375b9c547cSRui Paulo 	if (global->event_cb == NULL)
9385b9c547cSRui Paulo 		return;
9395b9c547cSRui Paulo 
9405b9c547cSRui Paulo 	os_memset(&ev, 0, sizeof(ev));
9415b9c547cSRui Paulo 	ev.cert_fail.depth = depth;
9425b9c547cSRui Paulo 	ev.cert_fail.subject = subject ? subject : "";
9435b9c547cSRui Paulo 	ev.cert_fail.reason = reason;
9445b9c547cSRui Paulo 	ev.cert_fail.reason_txt = err_str;
9455b9c547cSRui Paulo 	if (cert) {
9465b9c547cSRui Paulo 		cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
9475b9c547cSRui Paulo 		ev.cert_fail.cert = cert_buf;
9485b9c547cSRui Paulo 	}
9495b9c547cSRui Paulo 	global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
9505b9c547cSRui Paulo 	wpabuf_free(cert_buf);
9515b9c547cSRui Paulo }
9525b9c547cSRui Paulo 
9535b9c547cSRui Paulo 
9545b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER < 0x030300
server_eku_purpose(gnutls_x509_crt_t cert)9555b9c547cSRui Paulo static int server_eku_purpose(gnutls_x509_crt_t cert)
9565b9c547cSRui Paulo {
9575b9c547cSRui Paulo 	unsigned int i;
9585b9c547cSRui Paulo 
9595b9c547cSRui Paulo 	for (i = 0; ; i++) {
9605b9c547cSRui Paulo 		char oid[128];
9615b9c547cSRui Paulo 		size_t oid_size = sizeof(oid);
9625b9c547cSRui Paulo 		int res;
9635b9c547cSRui Paulo 
9645b9c547cSRui Paulo 		res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
9655b9c547cSRui Paulo 							  &oid_size, NULL);
9665b9c547cSRui Paulo 		if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
9675b9c547cSRui Paulo 			if (i == 0) {
9685b9c547cSRui Paulo 				/* No EKU - assume any use allowed */
9695b9c547cSRui Paulo 				return 1;
9705b9c547cSRui Paulo 			}
9715b9c547cSRui Paulo 			break;
9725b9c547cSRui Paulo 		}
9735b9c547cSRui Paulo 
9745b9c547cSRui Paulo 		if (res < 0) {
9755b9c547cSRui Paulo 			wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
9765b9c547cSRui Paulo 			return 0;
9775b9c547cSRui Paulo 		}
9785b9c547cSRui Paulo 
9795b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
9805b9c547cSRui Paulo 		if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
9815b9c547cSRui Paulo 		    os_strcmp(oid, GNUTLS_KP_ANY) == 0)
9825b9c547cSRui Paulo 			return 1;
9835b9c547cSRui Paulo 	}
9845b9c547cSRui Paulo 
9855b9c547cSRui Paulo 	return 0;
9865b9c547cSRui Paulo }
9875b9c547cSRui Paulo #endif /* < 3.3.0 */
9885b9c547cSRui Paulo 
9895b9c547cSRui Paulo 
check_ocsp(struct tls_connection * conn,gnutls_session_t session,gnutls_alert_description_t * err)9905b9c547cSRui Paulo static int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
9913157ba21SRui Paulo 		      gnutls_alert_description_t *err)
99239beb93cSSam Leffler {
9935b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030103
9945b9c547cSRui Paulo 	gnutls_datum_t response, buf;
9955b9c547cSRui Paulo 	gnutls_ocsp_resp_t resp;
9965b9c547cSRui Paulo 	unsigned int cert_status;
9975b9c547cSRui Paulo 	int res;
9985b9c547cSRui Paulo 
9995b9c547cSRui Paulo 	if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
10005b9c547cSRui Paulo 		return 0;
10015b9c547cSRui Paulo 
10025b9c547cSRui Paulo 	if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
10035b9c547cSRui Paulo 		if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
10045b9c547cSRui Paulo 			wpa_printf(MSG_INFO,
10055b9c547cSRui Paulo 				   "GnuTLS: No valid OCSP response received");
10065b9c547cSRui Paulo 			goto ocsp_error;
10075b9c547cSRui Paulo 		}
10085b9c547cSRui Paulo 
10095b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG,
10105b9c547cSRui Paulo 			   "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
10115b9c547cSRui Paulo 		return 0;
10125b9c547cSRui Paulo 	}
10135b9c547cSRui Paulo 
10145b9c547cSRui Paulo 	/*
10155b9c547cSRui Paulo 	 * GnuTLS has already verified the OCSP response in
10165b9c547cSRui Paulo 	 * check_ocsp_response() and rejected handshake if the certificate was
10175b9c547cSRui Paulo 	 * found to be revoked. However, if the response indicates that the
10185b9c547cSRui Paulo 	 * status is unknown, handshake continues and reaches here. We need to
10195b9c547cSRui Paulo 	 * re-import the OCSP response to check for unknown certificate status,
10205b9c547cSRui Paulo 	 * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
10215b9c547cSRui Paulo 	 * gnutls_ocsp_resp_verify_direct() calls.
10225b9c547cSRui Paulo 	 */
10235b9c547cSRui Paulo 
10245b9c547cSRui Paulo 	res = gnutls_ocsp_status_request_get(session, &response);
10255b9c547cSRui Paulo 	if (res != GNUTLS_E_SUCCESS) {
10265b9c547cSRui Paulo 		wpa_printf(MSG_INFO,
10275b9c547cSRui Paulo 			   "GnuTLS: OCSP response was received, but it was not valid");
10285b9c547cSRui Paulo 		goto ocsp_error;
10295b9c547cSRui Paulo 	}
10305b9c547cSRui Paulo 
10315b9c547cSRui Paulo 	if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
10325b9c547cSRui Paulo 		goto ocsp_error;
10335b9c547cSRui Paulo 
10345b9c547cSRui Paulo 	res = gnutls_ocsp_resp_import(resp, &response);
10355b9c547cSRui Paulo 	if (res != GNUTLS_E_SUCCESS) {
10365b9c547cSRui Paulo 		wpa_printf(MSG_INFO,
10375b9c547cSRui Paulo 			   "GnuTLS: Could not parse received OCSP response: %s",
10385b9c547cSRui Paulo 			   gnutls_strerror(res));
10395b9c547cSRui Paulo 		gnutls_ocsp_resp_deinit(resp);
10405b9c547cSRui Paulo 		goto ocsp_error;
10415b9c547cSRui Paulo 	}
10425b9c547cSRui Paulo 
10435b9c547cSRui Paulo 	res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
10445b9c547cSRui Paulo 	if (res == GNUTLS_E_SUCCESS) {
10455b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
10465b9c547cSRui Paulo 		gnutls_free(buf.data);
10475b9c547cSRui Paulo 	}
10485b9c547cSRui Paulo 
10495b9c547cSRui Paulo 	res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
10505b9c547cSRui Paulo 					  NULL, &cert_status, NULL,
10515b9c547cSRui Paulo 					  NULL, NULL, NULL);
10525b9c547cSRui Paulo 	gnutls_ocsp_resp_deinit(resp);
10535b9c547cSRui Paulo 	if (res != GNUTLS_E_SUCCESS) {
10545b9c547cSRui Paulo 		wpa_printf(MSG_INFO,
10555b9c547cSRui Paulo 			   "GnuTLS: Failed to extract OCSP information: %s",
10565b9c547cSRui Paulo 			   gnutls_strerror(res));
10575b9c547cSRui Paulo 		goto ocsp_error;
10585b9c547cSRui Paulo 	}
10595b9c547cSRui Paulo 
10605b9c547cSRui Paulo 	if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
10615b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
10625b9c547cSRui Paulo 	} else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
10635b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG,
10645b9c547cSRui Paulo 			   "GnuTLS: OCSP cert status: revoked");
10655b9c547cSRui Paulo 		goto ocsp_error;
10665b9c547cSRui Paulo 	} else {
10675b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG,
10685b9c547cSRui Paulo 			   "GnuTLS: OCSP cert status: unknown");
10695b9c547cSRui Paulo 		if (conn->flags & TLS_CONN_REQUIRE_OCSP)
10705b9c547cSRui Paulo 			goto ocsp_error;
10715b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG,
10725b9c547cSRui Paulo 			   "GnuTLS: OCSP was not required, so allow connection to continue");
10735b9c547cSRui Paulo 	}
10745b9c547cSRui Paulo 
10755b9c547cSRui Paulo 	return 0;
10765b9c547cSRui Paulo 
10775b9c547cSRui Paulo ocsp_error:
10785b9c547cSRui Paulo 	gnutls_tls_fail_event(conn, NULL, 0, NULL,
10795b9c547cSRui Paulo 			      "bad certificate status response",
10805b9c547cSRui Paulo 			      TLS_FAIL_REVOKED);
10815b9c547cSRui Paulo 	*err = GNUTLS_A_CERTIFICATE_REVOKED;
10825b9c547cSRui Paulo 	return -1;
10835b9c547cSRui Paulo #else /* GnuTLS 3.1.3 or newer */
10845b9c547cSRui Paulo 	return 0;
10855b9c547cSRui Paulo #endif /* GnuTLS 3.1.3 or newer */
10865b9c547cSRui Paulo }
10875b9c547cSRui Paulo 
10885b9c547cSRui Paulo 
tls_match_suffix_helper(gnutls_x509_crt_t cert,const char * match,int full)1089*4bc52338SCy Schubert static int tls_match_suffix_helper(gnutls_x509_crt_t cert, const char *match,
1090*4bc52338SCy Schubert 				   int full)
1091*4bc52338SCy Schubert {
1092*4bc52338SCy Schubert 	int res = -1;
1093*4bc52338SCy Schubert 
1094*4bc52338SCy Schubert #if GNUTLS_VERSION_NUMBER >= 0x030300
1095*4bc52338SCy Schubert 	if (full)
1096*4bc52338SCy Schubert 		res = gnutls_x509_crt_check_hostname2(
1097*4bc52338SCy Schubert 			cert, match,
1098*4bc52338SCy Schubert 			GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
1099*4bc52338SCy Schubert #endif /* >= 3.3.0 */
1100*4bc52338SCy Schubert 	if (res == -1)
1101*4bc52338SCy Schubert 		res = gnutls_x509_crt_check_hostname(cert, match);
1102*4bc52338SCy Schubert 
1103*4bc52338SCy Schubert 	wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s --> res=%d",
1104*4bc52338SCy Schubert 		   full ? "": "suffix ", match, res);
1105*4bc52338SCy Schubert 	return res;
1106*4bc52338SCy Schubert }
1107*4bc52338SCy Schubert 
1108*4bc52338SCy Schubert 
tls_match_suffix(gnutls_x509_crt_t cert,const char * match,int full)1109*4bc52338SCy Schubert static int tls_match_suffix(gnutls_x509_crt_t cert, const char *match,
1110*4bc52338SCy Schubert 			    int full)
1111*4bc52338SCy Schubert {
1112*4bc52338SCy Schubert 	char *values, *token, *context = NULL;
1113*4bc52338SCy Schubert 	int ret = 0;
1114*4bc52338SCy Schubert 
1115*4bc52338SCy Schubert 	if (!os_strchr(match, ';'))
1116*4bc52338SCy Schubert 		return tls_match_suffix_helper(cert, match, full);
1117*4bc52338SCy Schubert 
1118*4bc52338SCy Schubert 	values = os_strdup(match);
1119*4bc52338SCy Schubert 	if (!values)
1120*4bc52338SCy Schubert 		return 0;
1121*4bc52338SCy Schubert 
1122*4bc52338SCy Schubert 	/* Process each match alternative separately until a match is found */
1123*4bc52338SCy Schubert 	while ((token = str_token(values, ";", &context))) {
1124*4bc52338SCy Schubert 		if (tls_match_suffix_helper(cert, token, full)) {
1125*4bc52338SCy Schubert 			ret = 1;
1126*4bc52338SCy Schubert 			break;
1127*4bc52338SCy Schubert 		}
1128*4bc52338SCy Schubert 	}
1129*4bc52338SCy Schubert 
1130*4bc52338SCy Schubert 	os_free(values);
1131*4bc52338SCy Schubert 	return ret;
1132*4bc52338SCy Schubert }
1133*4bc52338SCy Schubert 
1134*4bc52338SCy Schubert 
tls_connection_verify_peer(gnutls_session_t session)11355b9c547cSRui Paulo static int tls_connection_verify_peer(gnutls_session_t session)
11365b9c547cSRui Paulo {
11375b9c547cSRui Paulo 	struct tls_connection *conn;
113839beb93cSSam Leffler 	unsigned int status, num_certs, i;
113939beb93cSSam Leffler 	struct os_time now;
114039beb93cSSam Leffler 	const gnutls_datum_t *certs;
114139beb93cSSam Leffler 	gnutls_x509_crt_t cert;
11425b9c547cSRui Paulo 	gnutls_alert_description_t err;
11435b9c547cSRui Paulo 	int res;
114439beb93cSSam Leffler 
11455b9c547cSRui Paulo 	conn = gnutls_session_get_ptr(session);
11465b9c547cSRui Paulo 	if (!conn->verify_peer) {
11475b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG,
11485b9c547cSRui Paulo 			   "GnuTLS: No peer certificate verification enabled");
11495b9c547cSRui Paulo 		return 0;
11505b9c547cSRui Paulo 	}
11515b9c547cSRui Paulo 
11525b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
11535b9c547cSRui Paulo 
11545b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030300
11555b9c547cSRui Paulo 	{
11565b9c547cSRui Paulo 		gnutls_typed_vdata_st data[1];
11575b9c547cSRui Paulo 		unsigned int elements = 0;
11585b9c547cSRui Paulo 
11595b9c547cSRui Paulo 		os_memset(data, 0, sizeof(data));
11605b9c547cSRui Paulo 		if (!conn->global->server) {
11615b9c547cSRui Paulo 			data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
11625b9c547cSRui Paulo 			data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
11635b9c547cSRui Paulo 			elements++;
11645b9c547cSRui Paulo 		}
11655b9c547cSRui Paulo 		res = gnutls_certificate_verify_peers(session, data, 1,
11665b9c547cSRui Paulo 						      &status);
11675b9c547cSRui Paulo 	}
11685b9c547cSRui Paulo #else /* < 3.3.0 */
11695b9c547cSRui Paulo 	res = gnutls_certificate_verify_peers2(session, &status);
11705b9c547cSRui Paulo #endif
11715b9c547cSRui Paulo 	if (res < 0) {
117239beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
117339beb93cSSam Leffler 			   "certificate chain");
11745b9c547cSRui Paulo 		err = GNUTLS_A_INTERNAL_ERROR;
11755b9c547cSRui Paulo 		goto out;
11765b9c547cSRui Paulo 	}
11775b9c547cSRui Paulo 
11785b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030104
11795b9c547cSRui Paulo 	{
11805b9c547cSRui Paulo 		gnutls_datum_t info;
11815b9c547cSRui Paulo 		int ret, type;
11825b9c547cSRui Paulo 
11835b9c547cSRui Paulo 		type = gnutls_certificate_type_get(session);
11845b9c547cSRui Paulo 		ret = gnutls_certificate_verification_status_print(status, type,
11855b9c547cSRui Paulo 								   &info, 0);
11865b9c547cSRui Paulo 		if (ret < 0) {
11875b9c547cSRui Paulo 			wpa_printf(MSG_DEBUG,
11885b9c547cSRui Paulo 				   "GnuTLS: Failed to print verification status");
11895b9c547cSRui Paulo 			err = GNUTLS_A_INTERNAL_ERROR;
11905b9c547cSRui Paulo 			goto out;
11915b9c547cSRui Paulo 		}
11925b9c547cSRui Paulo 		wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
11935b9c547cSRui Paulo 		gnutls_free(info.data);
11945b9c547cSRui Paulo 	}
11955b9c547cSRui Paulo #endif /* GnuTLS 3.1.4 or newer */
11965b9c547cSRui Paulo 
11975b9c547cSRui Paulo 	certs = gnutls_certificate_get_peers(session, &num_certs);
11985b9c547cSRui Paulo 	if (certs == NULL || num_certs == 0) {
11995b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
12005b9c547cSRui Paulo 		err = GNUTLS_A_UNKNOWN_CA;
12015b9c547cSRui Paulo 		goto out;
120239beb93cSSam Leffler 	}
120339beb93cSSam Leffler 
120439beb93cSSam Leffler 	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
120539beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
12063157ba21SRui Paulo 		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
12073157ba21SRui Paulo 			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
12083157ba21SRui Paulo 				   "algorithm");
12095b9c547cSRui Paulo 			gnutls_tls_fail_event(conn, NULL, 0, NULL,
12105b9c547cSRui Paulo 					      "certificate uses insecure algorithm",
12115b9c547cSRui Paulo 					      TLS_FAIL_BAD_CERTIFICATE);
12125b9c547cSRui Paulo 			err = GNUTLS_A_INSUFFICIENT_SECURITY;
12135b9c547cSRui Paulo 			goto out;
12143157ba21SRui Paulo 		}
12153157ba21SRui Paulo 		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
12163157ba21SRui Paulo 			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
12173157ba21SRui Paulo 				   "activated");
12185b9c547cSRui Paulo 			gnutls_tls_fail_event(conn, NULL, 0, NULL,
12195b9c547cSRui Paulo 					      "certificate not yet valid",
12205b9c547cSRui Paulo 					      TLS_FAIL_NOT_YET_VALID);
12215b9c547cSRui Paulo 			err = GNUTLS_A_CERTIFICATE_EXPIRED;
12225b9c547cSRui Paulo 			goto out;
12233157ba21SRui Paulo 		}
12243157ba21SRui Paulo 		if (status & GNUTLS_CERT_EXPIRED) {
12253157ba21SRui Paulo 			wpa_printf(MSG_INFO, "TLS: Certificate expired");
12265b9c547cSRui Paulo 			gnutls_tls_fail_event(conn, NULL, 0, NULL,
12275b9c547cSRui Paulo 					      "certificate has expired",
12285b9c547cSRui Paulo 					      TLS_FAIL_EXPIRED);
12295b9c547cSRui Paulo 			err = GNUTLS_A_CERTIFICATE_EXPIRED;
12305b9c547cSRui Paulo 			goto out;
12313157ba21SRui Paulo 		}
12325b9c547cSRui Paulo 		gnutls_tls_fail_event(conn, NULL, 0, NULL,
12335b9c547cSRui Paulo 				      "untrusted certificate",
12345b9c547cSRui Paulo 				      TLS_FAIL_UNTRUSTED);
12355b9c547cSRui Paulo 		err = GNUTLS_A_INTERNAL_ERROR;
12365b9c547cSRui Paulo 		goto out;
123739beb93cSSam Leffler 	}
123839beb93cSSam Leffler 
123939beb93cSSam Leffler 	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
124039beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
124139beb93cSSam Leffler 			   "known issuer");
12425b9c547cSRui Paulo 		gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
12435b9c547cSRui Paulo 				      TLS_FAIL_UNTRUSTED);
12445b9c547cSRui Paulo 		err = GNUTLS_A_UNKNOWN_CA;
12455b9c547cSRui Paulo 		goto out;
124639beb93cSSam Leffler 	}
124739beb93cSSam Leffler 
124839beb93cSSam Leffler 	if (status & GNUTLS_CERT_REVOKED) {
124939beb93cSSam Leffler 		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
12505b9c547cSRui Paulo 		gnutls_tls_fail_event(conn, NULL, 0, NULL,
12515b9c547cSRui Paulo 				      "certificate revoked",
12525b9c547cSRui Paulo 				      TLS_FAIL_REVOKED);
12535b9c547cSRui Paulo 		err = GNUTLS_A_CERTIFICATE_REVOKED;
12545b9c547cSRui Paulo 		goto out;
125539beb93cSSam Leffler 	}
125639beb93cSSam Leffler 
12575b9c547cSRui Paulo 	if (status != 0) {
12585b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
12595b9c547cSRui Paulo 			   status);
12605b9c547cSRui Paulo 		err = GNUTLS_A_INTERNAL_ERROR;
12615b9c547cSRui Paulo 		goto out;
12625b9c547cSRui Paulo 	}
12635b9c547cSRui Paulo 
12645b9c547cSRui Paulo 	if (check_ocsp(conn, session, &err))
12655b9c547cSRui Paulo 		goto out;
12665b9c547cSRui Paulo 
126739beb93cSSam Leffler 	os_get_time(&now);
126839beb93cSSam Leffler 
126939beb93cSSam Leffler 	for (i = 0; i < num_certs; i++) {
127039beb93cSSam Leffler 		char *buf;
127139beb93cSSam Leffler 		size_t len;
127239beb93cSSam Leffler 		if (gnutls_x509_crt_init(&cert) < 0) {
127339beb93cSSam Leffler 			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
127439beb93cSSam Leffler 				   "failed");
12755b9c547cSRui Paulo 			err = GNUTLS_A_BAD_CERTIFICATE;
12765b9c547cSRui Paulo 			goto out;
127739beb93cSSam Leffler 		}
127839beb93cSSam Leffler 
127939beb93cSSam Leffler 		if (gnutls_x509_crt_import(cert, &certs[i],
128039beb93cSSam Leffler 					   GNUTLS_X509_FMT_DER) < 0) {
128139beb93cSSam Leffler 			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
128239beb93cSSam Leffler 				   "certificate %d/%d", i + 1, num_certs);
128339beb93cSSam Leffler 			gnutls_x509_crt_deinit(cert);
12845b9c547cSRui Paulo 			err = GNUTLS_A_BAD_CERTIFICATE;
12855b9c547cSRui Paulo 			goto out;
128639beb93cSSam Leffler 		}
128739beb93cSSam Leffler 
128839beb93cSSam Leffler 		gnutls_x509_crt_get_dn(cert, NULL, &len);
128939beb93cSSam Leffler 		len++;
129039beb93cSSam Leffler 		buf = os_malloc(len + 1);
129139beb93cSSam Leffler 		if (buf) {
129239beb93cSSam Leffler 			buf[0] = buf[len] = '\0';
129339beb93cSSam Leffler 			gnutls_x509_crt_get_dn(cert, buf, &len);
129439beb93cSSam Leffler 		}
129539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
129639beb93cSSam Leffler 			   i + 1, num_certs, buf);
129739beb93cSSam Leffler 
12985b9c547cSRui Paulo 		if (conn->global->event_cb) {
12995b9c547cSRui Paulo 			struct wpabuf *cert_buf = NULL;
13005b9c547cSRui Paulo 			union tls_event_data ev;
13015b9c547cSRui Paulo #ifdef CONFIG_SHA256
13025b9c547cSRui Paulo 			u8 hash[32];
13035b9c547cSRui Paulo 			const u8 *_addr[1];
13045b9c547cSRui Paulo 			size_t _len[1];
13055b9c547cSRui Paulo #endif /* CONFIG_SHA256 */
13065b9c547cSRui Paulo 
13075b9c547cSRui Paulo 			os_memset(&ev, 0, sizeof(ev));
13085b9c547cSRui Paulo 			if (conn->global->cert_in_cb) {
13095b9c547cSRui Paulo 				cert_buf = wpabuf_alloc_copy(certs[i].data,
13105b9c547cSRui Paulo 							     certs[i].size);
13115b9c547cSRui Paulo 				ev.peer_cert.cert = cert_buf;
13125b9c547cSRui Paulo 			}
13135b9c547cSRui Paulo #ifdef CONFIG_SHA256
13145b9c547cSRui Paulo 			_addr[0] = certs[i].data;
13155b9c547cSRui Paulo 			_len[0] = certs[i].size;
13165b9c547cSRui Paulo 			if (sha256_vector(1, _addr, _len, hash) == 0) {
13175b9c547cSRui Paulo 				ev.peer_cert.hash = hash;
13185b9c547cSRui Paulo 				ev.peer_cert.hash_len = sizeof(hash);
13195b9c547cSRui Paulo 			}
13205b9c547cSRui Paulo #endif /* CONFIG_SHA256 */
13215b9c547cSRui Paulo 			ev.peer_cert.depth = i;
13225b9c547cSRui Paulo 			ev.peer_cert.subject = buf;
13235b9c547cSRui Paulo 			conn->global->event_cb(conn->global->cb_ctx,
13245b9c547cSRui Paulo 					       TLS_PEER_CERTIFICATE, &ev);
13255b9c547cSRui Paulo 			wpabuf_free(cert_buf);
13265b9c547cSRui Paulo 		}
13275b9c547cSRui Paulo 
132839beb93cSSam Leffler 		if (i == 0) {
13295b9c547cSRui Paulo 			if (conn->suffix_match &&
1330*4bc52338SCy Schubert 			    !tls_match_suffix(cert, conn->suffix_match, 0)) {
13315b9c547cSRui Paulo 				wpa_printf(MSG_WARNING,
13325b9c547cSRui Paulo 					   "TLS: Domain suffix match '%s' not found",
13335b9c547cSRui Paulo 					   conn->suffix_match);
13345b9c547cSRui Paulo 				gnutls_tls_fail_event(
13355b9c547cSRui Paulo 					conn, &certs[i], i, buf,
13365b9c547cSRui Paulo 					"Domain suffix mismatch",
13375b9c547cSRui Paulo 					TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
13385b9c547cSRui Paulo 				err = GNUTLS_A_BAD_CERTIFICATE;
13395b9c547cSRui Paulo 				gnutls_x509_crt_deinit(cert);
13405b9c547cSRui Paulo 				os_free(buf);
13415b9c547cSRui Paulo 				goto out;
13425b9c547cSRui Paulo 			}
13435b9c547cSRui Paulo 
13445b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x030300
13455b9c547cSRui Paulo 			if (conn->domain_match &&
1346*4bc52338SCy Schubert 			    !tls_match_suffix(cert, conn->domain_match, 1)) {
13475b9c547cSRui Paulo 				wpa_printf(MSG_WARNING,
13485b9c547cSRui Paulo 					   "TLS: Domain match '%s' not found",
13495b9c547cSRui Paulo 					   conn->domain_match);
13505b9c547cSRui Paulo 				gnutls_tls_fail_event(
13515b9c547cSRui Paulo 					conn, &certs[i], i, buf,
13525b9c547cSRui Paulo 					"Domain mismatch",
13535b9c547cSRui Paulo 					TLS_FAIL_DOMAIN_MISMATCH);
13545b9c547cSRui Paulo 				err = GNUTLS_A_BAD_CERTIFICATE;
13555b9c547cSRui Paulo 				gnutls_x509_crt_deinit(cert);
13565b9c547cSRui Paulo 				os_free(buf);
13575b9c547cSRui Paulo 				goto out;
13585b9c547cSRui Paulo 			}
13595b9c547cSRui Paulo #endif /* >= 3.3.0 */
13605b9c547cSRui Paulo 
13615b9c547cSRui Paulo 			/* TODO: validate altsubject_match.
13625b9c547cSRui Paulo 			 * For now, any such configuration is rejected in
13635b9c547cSRui Paulo 			 * tls_connection_set_params() */
13645b9c547cSRui Paulo 
13655b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER < 0x030300
13665b9c547cSRui Paulo 			/*
13675b9c547cSRui Paulo 			 * gnutls_certificate_verify_peers() not available, so
13685b9c547cSRui Paulo 			 * need to check EKU separately.
13695b9c547cSRui Paulo 			 */
13705b9c547cSRui Paulo 			if (!conn->global->server &&
13715b9c547cSRui Paulo 			    !server_eku_purpose(cert)) {
13725b9c547cSRui Paulo 				wpa_printf(MSG_WARNING,
13735b9c547cSRui Paulo 					   "GnuTLS: No server EKU");
13745b9c547cSRui Paulo 				gnutls_tls_fail_event(
13755b9c547cSRui Paulo 					conn, &certs[i], i, buf,
13765b9c547cSRui Paulo 					"No server EKU",
13775b9c547cSRui Paulo 					TLS_FAIL_BAD_CERTIFICATE);
13785b9c547cSRui Paulo 				err = GNUTLS_A_BAD_CERTIFICATE;
13795b9c547cSRui Paulo 				gnutls_x509_crt_deinit(cert);
13805b9c547cSRui Paulo 				os_free(buf);
13815b9c547cSRui Paulo 				goto out;
13825b9c547cSRui Paulo 			}
13835b9c547cSRui Paulo #endif /* < 3.3.0 */
13845b9c547cSRui Paulo 		}
13855b9c547cSRui Paulo 
13865b9c547cSRui Paulo 		if (!conn->disable_time_checks &&
13875b9c547cSRui Paulo 		    (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
13885b9c547cSRui Paulo 		     gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
13895b9c547cSRui Paulo 			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
13905b9c547cSRui Paulo 				   "not valid at this time",
13915b9c547cSRui Paulo 				   i + 1, num_certs);
13925b9c547cSRui Paulo 			gnutls_tls_fail_event(
13935b9c547cSRui Paulo 				conn, &certs[i], i, buf,
13945b9c547cSRui Paulo 				"Certificate is not valid at this time",
13955b9c547cSRui Paulo 				TLS_FAIL_EXPIRED);
13965b9c547cSRui Paulo 			gnutls_x509_crt_deinit(cert);
13975b9c547cSRui Paulo 			os_free(buf);
13985b9c547cSRui Paulo 			err = GNUTLS_A_CERTIFICATE_EXPIRED;
13995b9c547cSRui Paulo 			goto out;
140039beb93cSSam Leffler 		}
140139beb93cSSam Leffler 
140239beb93cSSam Leffler 		os_free(buf);
140339beb93cSSam Leffler 
140439beb93cSSam Leffler 		gnutls_x509_crt_deinit(cert);
140539beb93cSSam Leffler 	}
140639beb93cSSam Leffler 
14075b9c547cSRui Paulo 	if (conn->global->event_cb != NULL)
14085b9c547cSRui Paulo 		conn->global->event_cb(conn->global->cb_ctx,
14095b9c547cSRui Paulo 				       TLS_CERT_CHAIN_SUCCESS, NULL);
141039beb93cSSam Leffler 
141139beb93cSSam Leffler 	return 0;
14125b9c547cSRui Paulo 
14135b9c547cSRui Paulo out:
14145b9c547cSRui Paulo 	conn->failed++;
14155b9c547cSRui Paulo 	gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
14165b9c547cSRui Paulo 	return GNUTLS_E_CERTIFICATE_ERROR;
141739beb93cSSam Leffler }
141839beb93cSSam Leffler 
141939beb93cSSam Leffler 
gnutls_get_appl_data(struct tls_connection * conn)1420e28a4053SRui Paulo static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
142139beb93cSSam Leffler {
1422e28a4053SRui Paulo 	int res;
1423e28a4053SRui Paulo 	struct wpabuf *ad;
1424e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
1425e28a4053SRui Paulo 	ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
1426e28a4053SRui Paulo 	if (ad == NULL)
1427e28a4053SRui Paulo 		return NULL;
1428e28a4053SRui Paulo 
1429e28a4053SRui Paulo 	res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
1430e28a4053SRui Paulo 				 wpabuf_size(ad));
1431e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
1432e28a4053SRui Paulo 	if (res < 0) {
1433f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1434e28a4053SRui Paulo 			   "(%s)", __func__, (int) res,
1435e28a4053SRui Paulo 			   gnutls_strerror(res));
1436e28a4053SRui Paulo 		wpabuf_free(ad);
1437e28a4053SRui Paulo 		return NULL;
1438e28a4053SRui Paulo 	}
1439e28a4053SRui Paulo 
1440e28a4053SRui Paulo 	wpabuf_put(ad, res);
1441e28a4053SRui Paulo 	wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
1442e28a4053SRui Paulo 		   res);
1443e28a4053SRui Paulo 	return ad;
1444e28a4053SRui Paulo }
1445e28a4053SRui Paulo 
1446e28a4053SRui Paulo 
tls_connection_handshake(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)1447e28a4053SRui Paulo struct wpabuf * tls_connection_handshake(void *tls_ctx,
1448e28a4053SRui Paulo 					 struct tls_connection *conn,
1449e28a4053SRui Paulo 					 const struct wpabuf *in_data,
1450e28a4053SRui Paulo 					 struct wpabuf **appl_data)
1451e28a4053SRui Paulo {
1452e28a4053SRui Paulo 	struct tls_global *global = tls_ctx;
1453e28a4053SRui Paulo 	struct wpabuf *out_data;
145439beb93cSSam Leffler 	int ret;
145539beb93cSSam Leffler 
145639beb93cSSam Leffler 	if (appl_data)
145739beb93cSSam Leffler 		*appl_data = NULL;
145839beb93cSSam Leffler 
1459e28a4053SRui Paulo 	if (in_data && wpabuf_len(in_data) > 0) {
146039beb93cSSam Leffler 		if (conn->pull_buf) {
146139beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
146239beb93cSSam Leffler 				   "pull_buf", __func__,
1463e28a4053SRui Paulo 				   (unsigned long) wpabuf_len(conn->pull_buf));
1464e28a4053SRui Paulo 			wpabuf_free(conn->pull_buf);
146539beb93cSSam Leffler 		}
1466e28a4053SRui Paulo 		conn->pull_buf = wpabuf_dup(in_data);
146739beb93cSSam Leffler 		if (conn->pull_buf == NULL)
146839beb93cSSam Leffler 			return NULL;
1469e28a4053SRui Paulo 		conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
147039beb93cSSam Leffler 	}
147139beb93cSSam Leffler 
147239beb93cSSam Leffler 	ret = gnutls_handshake(conn->session);
147339beb93cSSam Leffler 	if (ret < 0) {
14745b9c547cSRui Paulo 		gnutls_alert_description_t alert;
147585732ac8SCy Schubert 		union tls_event_data ev;
14765b9c547cSRui Paulo 
147739beb93cSSam Leffler 		switch (ret) {
147839beb93cSSam Leffler 		case GNUTLS_E_AGAIN:
147939beb93cSSam Leffler 			if (global->server && conn->established &&
148039beb93cSSam Leffler 			    conn->push_buf == NULL) {
148139beb93cSSam Leffler 				/* Need to return something to trigger
148239beb93cSSam Leffler 				 * completion of EAP-TLS. */
1483e28a4053SRui Paulo 				conn->push_buf = wpabuf_alloc(0);
148439beb93cSSam Leffler 			}
148539beb93cSSam Leffler 			break;
148685732ac8SCy Schubert 		case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
148785732ac8SCy Schubert 			wpa_printf(MSG_DEBUG, "GnuTLS: Unacceptable DH prime");
148885732ac8SCy Schubert 			if (conn->global->event_cb) {
148985732ac8SCy Schubert 				os_memset(&ev, 0, sizeof(ev));
149085732ac8SCy Schubert 				ev.alert.is_local = 1;
149185732ac8SCy Schubert 				ev.alert.type = "fatal";
149285732ac8SCy Schubert 				ev.alert.description = "insufficient security";
149385732ac8SCy Schubert 				conn->global->event_cb(conn->global->cb_ctx,
149485732ac8SCy Schubert 						       TLS_ALERT, &ev);
149585732ac8SCy Schubert 			}
149685732ac8SCy Schubert 			/*
149785732ac8SCy Schubert 			 * Could send a TLS Alert to the server, but for now,
149885732ac8SCy Schubert 			 * simply terminate handshake.
149985732ac8SCy Schubert 			 */
150085732ac8SCy Schubert 			conn->failed++;
150185732ac8SCy Schubert 			conn->write_alerts++;
150285732ac8SCy Schubert 			break;
150339beb93cSSam Leffler 		case GNUTLS_E_FATAL_ALERT_RECEIVED:
15045b9c547cSRui Paulo 			alert = gnutls_alert_get(conn->session);
150539beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
15065b9c547cSRui Paulo 				   __func__, gnutls_alert_get_name(alert));
150739beb93cSSam Leffler 			conn->read_alerts++;
15085b9c547cSRui Paulo 			if (conn->global->event_cb != NULL) {
15095b9c547cSRui Paulo 				os_memset(&ev, 0, sizeof(ev));
15105b9c547cSRui Paulo 				ev.alert.is_local = 0;
15115b9c547cSRui Paulo 				ev.alert.type = gnutls_alert_get_name(alert);
15125b9c547cSRui Paulo 				ev.alert.description = ev.alert.type;
15135b9c547cSRui Paulo 				conn->global->event_cb(conn->global->cb_ctx,
15145b9c547cSRui Paulo 						       TLS_ALERT, &ev);
15155b9c547cSRui Paulo 			}
151639beb93cSSam Leffler 			/* continue */
151739beb93cSSam Leffler 		default:
151839beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
151939beb93cSSam Leffler 				   "-> %s", __func__, gnutls_strerror(ret));
152039beb93cSSam Leffler 			conn->failed++;
152139beb93cSSam Leffler 		}
152239beb93cSSam Leffler 	} else {
152339beb93cSSam Leffler 		size_t size;
152439beb93cSSam Leffler 
1525f05cddf9SRui Paulo 		wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
15265b9c547cSRui Paulo 
15275b9c547cSRui Paulo #if GNUTLS_VERSION_NUMBER >= 0x03010a
15285b9c547cSRui Paulo 		{
15295b9c547cSRui Paulo 			char *desc;
15305b9c547cSRui Paulo 
15315b9c547cSRui Paulo 			desc = gnutls_session_get_desc(conn->session);
15325b9c547cSRui Paulo 			if (desc) {
15335b9c547cSRui Paulo 				wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
15345b9c547cSRui Paulo 				gnutls_free(desc);
15355b9c547cSRui Paulo 			}
15365b9c547cSRui Paulo 		}
15375b9c547cSRui Paulo #endif /* GnuTLS 3.1.10 or newer */
15385b9c547cSRui Paulo 
153939beb93cSSam Leffler 		conn->established = 1;
154039beb93cSSam Leffler 		if (conn->push_buf == NULL) {
154139beb93cSSam Leffler 			/* Need to return something to get final TLS ACK. */
1542e28a4053SRui Paulo 			conn->push_buf = wpabuf_alloc(0);
154339beb93cSSam Leffler 		}
154439beb93cSSam Leffler 
154539beb93cSSam Leffler 		gnutls_session_get_data(conn->session, NULL, &size);
154639beb93cSSam Leffler 		if (global->session_data == NULL ||
154739beb93cSSam Leffler 		    global->session_data_size < size) {
154839beb93cSSam Leffler 			os_free(global->session_data);
154939beb93cSSam Leffler 			global->session_data = os_malloc(size);
155039beb93cSSam Leffler 		}
155139beb93cSSam Leffler 		if (global->session_data) {
155239beb93cSSam Leffler 			global->session_data_size = size;
155339beb93cSSam Leffler 			gnutls_session_get_data(conn->session,
155439beb93cSSam Leffler 						global->session_data,
155539beb93cSSam Leffler 						&global->session_data_size);
155639beb93cSSam Leffler 		}
1557e28a4053SRui Paulo 
1558e28a4053SRui Paulo 		if (conn->pull_buf && appl_data)
1559e28a4053SRui Paulo 			*appl_data = gnutls_get_appl_data(conn);
156039beb93cSSam Leffler 	}
156139beb93cSSam Leffler 
156239beb93cSSam Leffler 	out_data = conn->push_buf;
156339beb93cSSam Leffler 	conn->push_buf = NULL;
156439beb93cSSam Leffler 	return out_data;
156539beb93cSSam Leffler }
156639beb93cSSam Leffler 
156739beb93cSSam Leffler 
tls_connection_server_handshake(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data,struct wpabuf ** appl_data)1568e28a4053SRui Paulo struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
156939beb93cSSam Leffler 						struct tls_connection *conn,
1570e28a4053SRui Paulo 						const struct wpabuf *in_data,
1571e28a4053SRui Paulo 						struct wpabuf **appl_data)
157239beb93cSSam Leffler {
1573e28a4053SRui Paulo 	return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
157439beb93cSSam Leffler }
157539beb93cSSam Leffler 
157639beb93cSSam Leffler 
tls_connection_encrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)1577e28a4053SRui Paulo struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1578e28a4053SRui Paulo 				       struct tls_connection *conn,
1579e28a4053SRui Paulo 				       const struct wpabuf *in_data)
158039beb93cSSam Leffler {
158139beb93cSSam Leffler 	ssize_t res;
1582e28a4053SRui Paulo 	struct wpabuf *buf;
158339beb93cSSam Leffler 
1584e28a4053SRui Paulo 	res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1585e28a4053SRui Paulo 				 wpabuf_len(in_data));
158639beb93cSSam Leffler 	if (res < 0) {
158739beb93cSSam Leffler 		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
158839beb93cSSam Leffler 			   __func__, gnutls_strerror(res));
1589e28a4053SRui Paulo 		return NULL;
159039beb93cSSam Leffler 	}
1591e28a4053SRui Paulo 
1592e28a4053SRui Paulo 	buf = conn->push_buf;
159339beb93cSSam Leffler 	conn->push_buf = NULL;
1594e28a4053SRui Paulo 	return buf;
159539beb93cSSam Leffler }
159639beb93cSSam Leffler 
159739beb93cSSam Leffler 
tls_connection_decrypt(void * tls_ctx,struct tls_connection * conn,const struct wpabuf * in_data)1598e28a4053SRui Paulo struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1599e28a4053SRui Paulo 				       struct tls_connection *conn,
1600e28a4053SRui Paulo 				       const struct wpabuf *in_data)
160139beb93cSSam Leffler {
160239beb93cSSam Leffler 	ssize_t res;
1603e28a4053SRui Paulo 	struct wpabuf *out;
160439beb93cSSam Leffler 
160539beb93cSSam Leffler 	if (conn->pull_buf) {
160639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
160739beb93cSSam Leffler 			   "pull_buf", __func__,
1608e28a4053SRui Paulo 			   (unsigned long) wpabuf_len(conn->pull_buf));
1609e28a4053SRui Paulo 		wpabuf_free(conn->pull_buf);
161039beb93cSSam Leffler 	}
1611e28a4053SRui Paulo 	conn->pull_buf = wpabuf_dup(in_data);
161239beb93cSSam Leffler 	if (conn->pull_buf == NULL)
1613e28a4053SRui Paulo 		return NULL;
1614e28a4053SRui Paulo 	conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1615e28a4053SRui Paulo 
1616e28a4053SRui Paulo 	/*
1617e28a4053SRui Paulo 	 * Even though we try to disable TLS compression, it is possible that
1618e28a4053SRui Paulo 	 * this cannot be done with all TLS libraries. Add extra buffer space
1619e28a4053SRui Paulo 	 * to handle the possibility of the decrypted data being longer than
1620e28a4053SRui Paulo 	 * input data.
1621e28a4053SRui Paulo 	 */
1622e28a4053SRui Paulo 	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1623e28a4053SRui Paulo 	if (out == NULL)
1624e28a4053SRui Paulo 		return NULL;
162539beb93cSSam Leffler 
1626e28a4053SRui Paulo 	res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1627e28a4053SRui Paulo 				 wpabuf_size(out));
162839beb93cSSam Leffler 	if (res < 0) {
162939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
163039beb93cSSam Leffler 			   "(%s)", __func__, (int) res, gnutls_strerror(res));
1631e28a4053SRui Paulo 		wpabuf_free(out);
1632e28a4053SRui Paulo 		return NULL;
163339beb93cSSam Leffler 	}
1634e28a4053SRui Paulo 	wpabuf_put(out, res);
163539beb93cSSam Leffler 
1636e28a4053SRui Paulo 	return out;
163739beb93cSSam Leffler }
163839beb93cSSam Leffler 
163939beb93cSSam Leffler 
tls_connection_resumed(void * ssl_ctx,struct tls_connection * conn)164039beb93cSSam Leffler int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
164139beb93cSSam Leffler {
164239beb93cSSam Leffler 	if (conn == NULL)
164339beb93cSSam Leffler 		return 0;
164439beb93cSSam Leffler 	return gnutls_session_is_resumed(conn->session);
164539beb93cSSam Leffler }
164639beb93cSSam Leffler 
164739beb93cSSam Leffler 
tls_connection_set_cipher_list(void * tls_ctx,struct tls_connection * conn,u8 * ciphers)164839beb93cSSam Leffler int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
164939beb93cSSam Leffler 				   u8 *ciphers)
165039beb93cSSam Leffler {
165139beb93cSSam Leffler 	/* TODO */
165239beb93cSSam Leffler 	return -1;
165339beb93cSSam Leffler }
165439beb93cSSam Leffler 
165539beb93cSSam Leffler 
tls_get_version(void * ssl_ctx,struct tls_connection * conn,char * buf,size_t buflen)1656325151a3SRui Paulo int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
1657325151a3SRui Paulo 		    char *buf, size_t buflen)
1658325151a3SRui Paulo {
165985732ac8SCy Schubert 	gnutls_protocol_t ver;
166085732ac8SCy Schubert 
166185732ac8SCy Schubert 	ver = gnutls_protocol_get_version(conn->session);
166285732ac8SCy Schubert 	if (ver == GNUTLS_TLS1_0)
166385732ac8SCy Schubert 		os_strlcpy(buf, "TLSv1", buflen);
166485732ac8SCy Schubert 	else if (ver == GNUTLS_TLS1_1)
166585732ac8SCy Schubert 		os_strlcpy(buf, "TLSv1.1", buflen);
166685732ac8SCy Schubert 	else if (ver == GNUTLS_TLS1_2)
166785732ac8SCy Schubert 		os_strlcpy(buf, "TLSv1.2", buflen);
166885732ac8SCy Schubert 	else
1669325151a3SRui Paulo 		return -1;
167085732ac8SCy Schubert 	return 0;
1671325151a3SRui Paulo }
1672325151a3SRui Paulo 
1673325151a3SRui Paulo 
tls_get_cipher(void * ssl_ctx,struct tls_connection * conn,char * buf,size_t buflen)167439beb93cSSam Leffler int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
167539beb93cSSam Leffler 		   char *buf, size_t buflen)
167639beb93cSSam Leffler {
167785732ac8SCy Schubert 	gnutls_cipher_algorithm_t cipher;
167885732ac8SCy Schubert 	gnutls_kx_algorithm_t kx;
167985732ac8SCy Schubert 	gnutls_mac_algorithm_t mac;
168085732ac8SCy Schubert 	const char *kx_str, *cipher_str, *mac_str;
168185732ac8SCy Schubert 	int res;
168285732ac8SCy Schubert 
168385732ac8SCy Schubert 	cipher = gnutls_cipher_get(conn->session);
168485732ac8SCy Schubert 	cipher_str = gnutls_cipher_get_name(cipher);
168585732ac8SCy Schubert 	if (!cipher_str)
168685732ac8SCy Schubert 		cipher_str = "";
168785732ac8SCy Schubert 
168885732ac8SCy Schubert 	kx = gnutls_kx_get(conn->session);
168985732ac8SCy Schubert 	kx_str = gnutls_kx_get_name(kx);
169085732ac8SCy Schubert 	if (!kx_str)
169185732ac8SCy Schubert 		kx_str = "";
169285732ac8SCy Schubert 
169385732ac8SCy Schubert 	mac = gnutls_mac_get(conn->session);
169485732ac8SCy Schubert 	mac_str = gnutls_mac_get_name(mac);
169585732ac8SCy Schubert 	if (!mac_str)
169685732ac8SCy Schubert 		mac_str = "";
169785732ac8SCy Schubert 
169885732ac8SCy Schubert 	if (kx == GNUTLS_KX_RSA)
169985732ac8SCy Schubert 		res = os_snprintf(buf, buflen, "%s-%s", cipher_str, mac_str);
170085732ac8SCy Schubert 	else
170185732ac8SCy Schubert 		res = os_snprintf(buf, buflen, "%s-%s-%s",
170285732ac8SCy Schubert 				  kx_str, cipher_str, mac_str);
170385732ac8SCy Schubert 	if (os_snprintf_error(buflen, res))
170485732ac8SCy Schubert 		return -1;
170585732ac8SCy Schubert 
170639beb93cSSam Leffler 	return 0;
170739beb93cSSam Leffler }
170839beb93cSSam Leffler 
170939beb93cSSam Leffler 
tls_connection_enable_workaround(void * ssl_ctx,struct tls_connection * conn)171039beb93cSSam Leffler int tls_connection_enable_workaround(void *ssl_ctx,
171139beb93cSSam Leffler 				     struct tls_connection *conn)
171239beb93cSSam Leffler {
1713e28a4053SRui Paulo 	gnutls_record_disable_padding(conn->session);
171439beb93cSSam Leffler 	return 0;
171539beb93cSSam Leffler }
171639beb93cSSam Leffler 
171739beb93cSSam Leffler 
tls_connection_client_hello_ext(void * ssl_ctx,struct tls_connection * conn,int ext_type,const u8 * data,size_t data_len)171839beb93cSSam Leffler int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
171939beb93cSSam Leffler 				    int ext_type, const u8 *data,
172039beb93cSSam Leffler 				    size_t data_len)
172139beb93cSSam Leffler {
172239beb93cSSam Leffler 	/* TODO */
172339beb93cSSam Leffler 	return -1;
172439beb93cSSam Leffler }
172539beb93cSSam Leffler 
172639beb93cSSam Leffler 
tls_connection_get_failed(void * ssl_ctx,struct tls_connection * conn)172739beb93cSSam Leffler int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
172839beb93cSSam Leffler {
172939beb93cSSam Leffler 	if (conn == NULL)
173039beb93cSSam Leffler 		return -1;
173139beb93cSSam Leffler 	return conn->failed;
173239beb93cSSam Leffler }
173339beb93cSSam Leffler 
173439beb93cSSam Leffler 
tls_connection_get_read_alerts(void * ssl_ctx,struct tls_connection * conn)173539beb93cSSam Leffler int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
173639beb93cSSam Leffler {
173739beb93cSSam Leffler 	if (conn == NULL)
173839beb93cSSam Leffler 		return -1;
173939beb93cSSam Leffler 	return conn->read_alerts;
174039beb93cSSam Leffler }
174139beb93cSSam Leffler 
174239beb93cSSam Leffler 
tls_connection_get_write_alerts(void * ssl_ctx,struct tls_connection * conn)174339beb93cSSam Leffler int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
174439beb93cSSam Leffler {
174539beb93cSSam Leffler 	if (conn == NULL)
174639beb93cSSam Leffler 		return -1;
174739beb93cSSam Leffler 	return conn->write_alerts;
174839beb93cSSam Leffler }
174939beb93cSSam Leffler 
175039beb93cSSam Leffler 
tls_connection_set_session_ticket_cb(void * tls_ctx,struct tls_connection * conn,tls_session_ticket_cb cb,void * ctx)1751e28a4053SRui Paulo int tls_connection_set_session_ticket_cb(void *tls_ctx,
1752e28a4053SRui Paulo 					 struct tls_connection *conn,
1753e28a4053SRui Paulo 					 tls_session_ticket_cb cb, void *ctx)
1754e28a4053SRui Paulo {
1755e28a4053SRui Paulo 	return -1;
1756e28a4053SRui Paulo }
17575b9c547cSRui Paulo 
17585b9c547cSRui Paulo 
tls_get_library_version(char * buf,size_t buf_len)17595b9c547cSRui Paulo int tls_get_library_version(char *buf, size_t buf_len)
17605b9c547cSRui Paulo {
17615b9c547cSRui Paulo 	return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
17625b9c547cSRui Paulo 			   GNUTLS_VERSION, gnutls_check_version(NULL));
17635b9c547cSRui Paulo }
1764325151a3SRui Paulo 
1765325151a3SRui Paulo 
tls_connection_set_success_data(struct tls_connection * conn,struct wpabuf * data)1766325151a3SRui Paulo void tls_connection_set_success_data(struct tls_connection *conn,
1767325151a3SRui Paulo 				     struct wpabuf *data)
1768325151a3SRui Paulo {
1769325151a3SRui Paulo }
1770325151a3SRui Paulo 
1771325151a3SRui Paulo 
tls_connection_set_success_data_resumed(struct tls_connection * conn)1772325151a3SRui Paulo void tls_connection_set_success_data_resumed(struct tls_connection *conn)
1773325151a3SRui Paulo {
1774325151a3SRui Paulo }
1775325151a3SRui Paulo 
1776325151a3SRui Paulo 
1777325151a3SRui Paulo const struct wpabuf *
tls_connection_get_success_data(struct tls_connection * conn)1778325151a3SRui Paulo tls_connection_get_success_data(struct tls_connection *conn)
1779325151a3SRui Paulo {
1780325151a3SRui Paulo 	return NULL;
1781325151a3SRui Paulo }
1782325151a3SRui Paulo 
1783325151a3SRui Paulo 
tls_connection_remove_session(struct tls_connection * conn)1784325151a3SRui Paulo void tls_connection_remove_session(struct tls_connection *conn)
1785325151a3SRui Paulo {
1786325151a3SRui Paulo }
1787