18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * SSL/TLS interface functions for GnuTLS
31f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <gnutls/gnutls.h>
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <gnutls/x509.h>
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef PKCS12_FUNCS
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <gnutls/pkcs12.h>
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* PKCS12_FUNCS */
15ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030103
16ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#include <gnutls/ocsp.h>
17ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* 3.1.3 */
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
20ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#include "crypto/crypto.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "tls.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tls_gnutls_ref_count = 0;
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct tls_global {
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Data for session resumption */
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *session_data;
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t session_data_size;
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int server;
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int params_set;
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_credentials_t xcred;
35ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
36ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	void (*event_cb)(void *ctx, enum tls_event ev,
37ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			 union tls_event_data *data);
38ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	void *cb_ctx;
39ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	int cert_in_cb;
40d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt
41d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	char *ocsp_stapling_response;
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct tls_connection {
45ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	struct tls_global *global;
466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	gnutls_session_t session;
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int read_alerts, write_alerts, failed;
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pre_shared_secret;
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t pre_shared_secret_len;
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int established;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int verify_peer;
53ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	unsigned int disable_time_checks:1;
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *push_buf;
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *pull_buf;
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pull_buf_offset;
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int params_set;
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_credentials_t xcred;
61ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
62ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	char *suffix_match;
632f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	char *domain_match;
64ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	unsigned int flags;
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstatic int tls_connection_verify_peer(gnutls_session_t session);
69ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
70ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void tls_log_func(int level, const char *msg)
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *s, *pos;
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (level == 6 || level == 7) {
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* These levels seem to be mostly I/O debug and msg dumps */
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	s = os_strdup(msg);
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (s == NULL)
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = s;
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (*pos != '\0') {
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (*pos == '\n') {
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*pos = '\0';
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos++;
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "gnutls<%d> %s", level, s);
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(s);
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid * tls_init(const struct tls_config *conf)
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global;
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
101ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (tls_gnutls_ref_count == 0) {
102ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG,
103ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: Library version %s (runtime) - %s (build)",
104ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   gnutls_check_version(NULL), GNUTLS_VERSION);
105ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	global = os_zalloc(sizeof(*global));
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global == NULL)
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(global);
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tls_gnutls_ref_count++;
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_global_set_log_function(tls_log_func);
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_debug_show_keys)
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_global_set_log_level(11);
120ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
121ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (conf) {
122ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		global->event_cb = conf->event_cb;
123ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		global->cb_ctx = conf->cb_ctx;
124ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		global->cert_in_cb = conf->cert_in_cb;
125ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
126ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return global;
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid tls_deinit(void *ssl_ctx)
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = ssl_ctx;
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global) {
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (global->params_set)
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_free_credentials(global->xcred);
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(global->session_data);
138d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt		os_free(global->ocsp_stapling_response);
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(global);
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tls_gnutls_ref_count--;
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tls_gnutls_ref_count == 0)
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_global_deinit();
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_get_errors(void *ssl_ctx)
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     size_t len)
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_connection *conn = (struct tls_connection *) ptr;
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *end;
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->pull_buf == NULL) {
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		errno = EWOULDBLOCK;
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((size_t) (end - conn->pull_buf_offset) < len)
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		len = end - conn->pull_buf_offset;
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(buf, conn->pull_buf_offset, len);
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->pull_buf_offset += len;
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->pull_buf_offset == end) {
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(conn->pull_buf);
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->pull_buf = NULL;
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->pull_buf_offset = NULL;
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__,
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) (end - conn->pull_buf_offset));
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return len;
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     size_t len)
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_connection *conn = (struct tls_connection *) ptr;
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpabuf_resize(&conn->push_buf, len) < 0) {
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		errno = ENOMEM;
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(conn->push_buf, buf, len);
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return len;
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tls_gnutls_init_session(struct tls_global *global,
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   struct tls_connection *conn)
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const char *err;
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_init(&conn->session,
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "connection: %s", gnutls_strerror(ret));
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_set_default_priority(conn->session);
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0)
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
2171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					 &err);
2181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret < 0) {
2191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
2201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "'%s'", err);
2211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto fail;
2221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_transport_set_push_function(conn->session, tls_push_func);
2266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
227ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_session_set_ptr(conn->session, conn);
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail:
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   gnutls_strerror(ret));
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_deinit(conn->session);
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct tls_connection * tls_connection_init(void *ssl_ctx)
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = ssl_ctx;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_connection *conn;
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn = os_zalloc(sizeof(*conn));
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
248ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	conn->global = global;
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tls_gnutls_init_session(global, conn)) {
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(conn);
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global->params_set) {
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_credentials_set(conn->session,
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     GNUTLS_CRD_CERTIFICATE,
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     global->xcred);
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "Failed to configure "
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "credentials: %s", gnutls_strerror(ret));
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(conn);
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(conn);
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn;
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_free_credentials(conn->xcred);
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_deinit(conn->session);
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(conn->pre_shared_secret);
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(conn->push_buf);
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(conn->pull_buf);
286ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	os_free(conn->suffix_match);
2872f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	os_free(conn->domain_match);
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(conn);
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn ? conn->established : 0;
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = ssl_ctx;
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Shutdown previous TLS connection without notifying the peer
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * because the connection was already terminated in practice
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * and "close notify" shutdown alert would confuse AS. */
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(conn->push_buf);
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->push_buf = NULL;
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->established = 0;
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_deinit(conn->session);
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tls_gnutls_init_session(global, conn)) {
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "for session resumption use");
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     conn->params_set ? conn->xcred :
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     global->xcred);
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "for session resumption: %s", gnutls_strerror(ret));
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global->session_data) {
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_session_set_data(conn->session,
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      global->session_data,
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      global->session_data_size);
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "data: %s", gnutls_strerror(ret));
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      const struct tls_connection_params *params)
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL || params == NULL)
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
353d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
354d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt		wpa_printf(MSG_INFO,
355d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt			   "GnuTLS: ocsp=3 not supported");
356d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt		return -1;
357d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	}
358d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt
3591b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt	if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
3601b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt		wpa_printf(MSG_INFO,
3611b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt			   "GnuTLS: tls_ext_cert_check=1 not supported");
3621b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt		return -1;
3631b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt	}
3641b46775bb44f06b3cc285481ff5f7a673559ed7dDmitry Shmidt
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->subject_match) {
366ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
367ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return -1;
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->altsubject_match) {
371ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
372ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return -1;
373ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
374ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
375ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	os_free(conn->suffix_match);
376ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	conn->suffix_match = NULL;
377ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (params->suffix_match) {
378ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		conn->suffix_match = os_strdup(params->suffix_match);
379ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (conn->suffix_match == NULL)
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3832f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030300
3842f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	os_free(conn->domain_match);
3852f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	conn->domain_match = NULL;
3862f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (params->domain_match) {
3872f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		conn->domain_match = os_strdup(params->domain_match);
3882f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		if (conn->domain_match == NULL)
3892f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			return -1;
3902f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	}
3912f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt#else /* < 3.3.0 */
3922f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (params->domain_match) {
3932f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
3942f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		return -1;
3952f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	}
3962f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt#endif /* >= 3.3.0 */
3972f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
398ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	conn->flags = params->flags;
399ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
400ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (params->openssl_ciphers) {
401ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
402ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return -1;
403ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
404ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
405293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * to force peer validation(?) */
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ca_cert) {
409ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
410ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   params->ca_cert);
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_trust_file(
412ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
414ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_DEBUG,
415ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
416ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   params->ca_cert,
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   gnutls_strerror(ret));
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = gnutls_certificate_set_x509_trust_file(
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->xcred, params->ca_cert,
420ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				GNUTLS_X509_FMT_PEM);
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ret < 0) {
422ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				wpa_printf(MSG_DEBUG,
423ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "Failed to read CA cert '%s' in PEM format: %s",
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   params->ca_cert,
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   gnutls_strerror(ret));
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
429ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	} else if (params->ca_cert_blob) {
430ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_datum_t ca;
431ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
432ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ca.data = (unsigned char *) params->ca_cert_blob;
433ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ca.size = params->ca_cert_blob_len;
434ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
435ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ret = gnutls_certificate_set_x509_trust_mem(
436ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->xcred, &ca, GNUTLS_X509_FMT_DER);
437ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (ret < 0) {
438ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_DEBUG,
439ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "Failed to parse CA cert in DER format: %s",
440ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   gnutls_strerror(ret));
441ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			ret = gnutls_certificate_set_x509_trust_mem(
442ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
443ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (ret < 0) {
444ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				wpa_printf(MSG_DEBUG,
445ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "Failed to parse CA cert in PEM format: %s",
446ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   gnutls_strerror(ret));
447ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				return -1;
448ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
449ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
450ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	} else if (params->ca_path) {
451ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
452ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return -1;
453ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
454ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
455ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	conn->disable_time_checks = 0;
456ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (params->ca_cert || params->ca_cert_blob) {
457ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		conn->verify_peer = 1;
458ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_certificate_set_verify_function(
459ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->xcred, tls_connection_verify_peer);
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_set_verify_flags(
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
467ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->disable_time_checks = 1;
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_set_verify_flags(
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->xcred,
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->client_cert && params->private_key) {
4756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x03010b
4766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = gnutls_certificate_set_x509_key_file2(
4776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			conn->xcred, params->client_cert, params->private_key,
478ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
4796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#else
4806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/* private_key_passwd not (easily) supported here */
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_key_file(
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->xcred, params->client_cert, params->private_key,
483ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			GNUTLS_X509_FMT_DER);
4846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
487ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "in DER format: %s", gnutls_strerror(ret));
4886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x03010b
4896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			ret = gnutls_certificate_set_x509_key_file2(
4906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				conn->xcred, params->client_cert,
491ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				params->private_key, GNUTLS_X509_FMT_PEM,
4926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				params->private_key_passwd, 0);
4936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#else
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = gnutls_certificate_set_x509_key_file(
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->xcred, params->client_cert,
496ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				params->private_key, GNUTLS_X509_FMT_PEM);
4976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ret < 0) {
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "Failed to read client "
500ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "cert/key in PEM format: %s",
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   gnutls_strerror(ret));
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return ret;
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (params->private_key) {
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int pkcs12_ok = 0;
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef PKCS12_FUNCS
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try to load in PKCS#12 format */
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->private_key_passwd);
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret != 0) {
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "PKCS#12 format: %s", gnutls_strerror(ret));
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pkcs12_ok = 1;
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* PKCS12_FUNCS */
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!pkcs12_ok) {
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "included");
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
525ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	} else if (params->client_cert_blob && params->private_key_blob) {
526ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_datum_t cert, key;
527ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
528ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		cert.data = (unsigned char *) params->client_cert_blob;
529ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		cert.size = params->client_cert_blob_len;
530ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		key.data = (unsigned char *) params->private_key_blob;
531ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		key.size = params->private_key_blob_len;
532ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
533ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x03010b
534ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ret = gnutls_certificate_set_x509_key_mem2(
535ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
536ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			params->private_key_passwd, 0);
537ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else
538ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		/* private_key_passwd not (easily) supported here */
539ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ret = gnutls_certificate_set_x509_key_mem(
540ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
541ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif
542ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (ret < 0) {
543ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
544ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "in DER format: %s", gnutls_strerror(ret));
545ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x03010b
546ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			ret = gnutls_certificate_set_x509_key_mem2(
547ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
548ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				params->private_key_passwd, 0);
549ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else
550ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			/* private_key_passwd not (easily) supported here */
551ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			ret = gnutls_certificate_set_x509_key_mem(
552ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
553ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif
554ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (ret < 0) {
555ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				wpa_printf(MSG_DEBUG, "Failed to read client "
556ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "cert/key in PEM format: %s",
557ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   gnutls_strerror(ret));
558ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				return ret;
559ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
560ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
561ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	} else if (params->private_key_blob) {
562ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#ifdef PKCS12_FUNCS
563ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_datum_t key;
564ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
565ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		key.data = (unsigned char *) params->private_key_blob;
566ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		key.size = params->private_key_blob_len;
567ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
568ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		/* Try to load in PKCS#12 format */
569ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
570ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->xcred, &key, GNUTLS_X509_FMT_DER,
571ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			params->private_key_passwd);
572ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (ret != 0) {
573ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
574ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "PKCS#12 format: %s", gnutls_strerror(ret));
575ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			return -1;
576ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
577ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else /* PKCS12_FUNCS */
578ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
579ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return -1;
580ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* PKCS12_FUNCS */
581ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
582ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
583ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030103
584ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
585ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ret = gnutls_ocsp_status_request_enable_client(conn->session,
586ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt							       NULL, 0, NULL);
587ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (ret != GNUTLS_E_SUCCESS) {
588ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_INFO,
589ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "GnuTLS: Failed to enable OCSP client");
590ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			return -1;
591ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
592ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
593ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else /* 3.1.3 */
594ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (params->flags & TLS_CONN_REQUIRE_OCSP) {
595ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO,
596ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: OCSP not supported by this version of GnuTLS");
597ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return -1;
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
599ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* 3.1.3 */
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->params_set = 1;
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     conn->xcred);
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   gnutls_strerror(ret));
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
614d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030103
615d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidtstatic int server_ocsp_status_req(gnutls_session_t session, void *ptr,
616d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt				  gnutls_datum_t *resp)
617d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt{
618d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	struct tls_global *global = ptr;
619d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	char *cached;
620d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	size_t len;
621d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt
622d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	if (!global->ocsp_stapling_response) {
623d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt		wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
624d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt		return GNUTLS_E_NO_CERTIFICATE_STATUS;
625d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	}
626d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt
627d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	cached = os_readfile(global->ocsp_stapling_response, &len);
628d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	if (!cached) {
629d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt		wpa_printf(MSG_DEBUG,
630d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt			   "GnuTLS: OCSP status callback - could not read response file (%s)",
631d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt			   global->ocsp_stapling_response);
632d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt		return GNUTLS_E_NO_CERTIFICATE_STATUS;
633d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	}
634d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt
635d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	wpa_printf(MSG_DEBUG,
636d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt		   "GnuTLS: OCSP status callback - send cached response");
637d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	resp->data = gnutls_malloc(len);
638d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	if (!resp->data) {
639d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt		os_free(resp);
640d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt		return GNUTLS_E_MEMORY_ERROR;
641d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	}
642d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt
643d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	os_memcpy(resp->data, cached, len);
644d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	resp->size = len;
645d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	os_free(cached);
646d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt
647d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	return GNUTLS_E_SUCCESS;
648d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt}
649d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt#endif /* 3.1.3 */
650d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt
651d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_global_set_params(void *tls_ctx,
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  const struct tls_connection_params *params)
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = tls_ctx;
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Currently, global parameters are only set when running in server
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * mode. */
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	global->server = 1;
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global->params_set) {
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_certificate_free_credentials(global->xcred);
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		global->params_set = 0;
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_certificate_allocate_credentials(&global->xcred);
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "%s", gnutls_strerror(ret));
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ca_cert) {
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_trust_file(
676ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
679ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "in DER format: %s", params->ca_cert,
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   gnutls_strerror(ret));
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = gnutls_certificate_set_x509_trust_file(
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				global->xcred, params->ca_cert,
683ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				GNUTLS_X509_FMT_PEM);
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ret < 0) {
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
686ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "'%s' in PEM format: %s",
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   params->ca_cert,
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   gnutls_strerror(ret));
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				goto fail;
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_set_verify_flags(
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				global->xcred,
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_set_verify_flags(
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				global->xcred,
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->client_cert && params->private_key) {
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* TODO: private_key_passwd? */
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_key_file(
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			global->xcred, params->client_cert,
710ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			params->private_key, GNUTLS_X509_FMT_DER);
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
713ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "in DER format: %s", gnutls_strerror(ret));
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = gnutls_certificate_set_x509_key_file(
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				global->xcred, params->client_cert,
716ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				params->private_key, GNUTLS_X509_FMT_PEM);
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ret < 0) {
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "Failed to read client "
719ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "cert/key in PEM format: %s",
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   gnutls_strerror(ret));
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				goto fail;
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (params->private_key) {
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int pkcs12_ok = 0;
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef PKCS12_FUNCS
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try to load in PKCS#12 format */
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			global->xcred, params->private_key,
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			GNUTLS_X509_FMT_DER, params->private_key_passwd);
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret != 0) {
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "PKCS#12 format: %s", gnutls_strerror(ret));
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fail;
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pkcs12_ok = 1;
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* PKCS12_FUNCS */
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!pkcs12_ok) {
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "included");
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fail;
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
746d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030103
747d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	os_free(global->ocsp_stapling_response);
748d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	if (params->ocsp_stapling_response)
749d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt		global->ocsp_stapling_response =
750d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt			os_strdup(params->ocsp_stapling_response);
751d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	else
752d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt		global->ocsp_stapling_response = NULL;
753d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt	gnutls_certificate_set_ocsp_status_request_function(
754d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt		global->xcred, server_ocsp_status_req, global);
755d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt#endif /* 3.1.3 */
756d97138ded63ac5388da3a2b63dea563c8b44c8ecDmitry Shmidt
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	global->params_set = 1;
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail:
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_free_credentials(global->xcred);
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_global_set_verify(void *ssl_ctx, int check_crl)
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
775d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			      int verify_peer, unsigned int flags,
776d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			      const u8 *session_ctx, size_t session_ctx_len)
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL || conn->session == NULL)
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->verify_peer = verify_peer;
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_server_set_request(conn->session,
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      verify_peer ? GNUTLS_CERT_REQUIRE
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      : GNUTLS_CERT_REQUEST);
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
790d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtint tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
791d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			    struct tls_random *keys)
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
793ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030012
794ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_datum_t client, server;
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL || conn->session == NULL || keys == NULL)
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(keys, 0, sizeof(*keys));
800ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_session_get_random(conn->session, &client, &server);
801ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	keys->client_random = client.data;
802ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	keys->server_random = server.data;
803ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	keys->client_random_len = client.size;
804ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	keys->server_random_len = client.size;
8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
807ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else /* 3.0.18 */
808ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return -1;
809ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* 3.0.18 */
8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
813849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtint tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
814849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt			      const char *label, u8 *out, size_t out_len)
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
816849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt	if (conn == NULL || conn->session == NULL)
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return gnutls_prf(conn->session, os_strlen(label), label,
820849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt			  0 /* client_random first */, 0, NULL, out_len,
821849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt			  (char *) out);
822849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt}
823849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
824849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt
825849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidtint tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
826849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt				    u8 *out, size_t out_len)
827849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt{
828849734c8d1847920ed7042463f7480b1e0c1dfeaDmitry Shmidt	return -1;
829ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt}
830ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
831ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
832ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstatic void gnutls_tls_fail_event(struct tls_connection *conn,
833ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				  const gnutls_datum_t *cert, int depth,
834ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				  const char *subject, const char *err_str,
835ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				  enum tls_fail_reason reason)
836ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{
837ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	union tls_event_data ev;
838ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	struct tls_global *global = conn->global;
839ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	struct wpabuf *cert_buf = NULL;
840ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
841ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (global->event_cb == NULL)
842ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return;
843ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
844ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	os_memset(&ev, 0, sizeof(ev));
845ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	ev.cert_fail.depth = depth;
846ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	ev.cert_fail.subject = subject ? subject : "";
847ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	ev.cert_fail.reason = reason;
848ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	ev.cert_fail.reason_txt = err_str;
849ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (cert) {
850ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
851ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ev.cert_fail.cert = cert_buf;
852ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
853ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
854ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	wpabuf_free(cert_buf);
855ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt}
856ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
857ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
858ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER < 0x030300
859ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstatic int server_eku_purpose(gnutls_x509_crt_t cert)
860ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{
861ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	unsigned int i;
862ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
863ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	for (i = 0; ; i++) {
864ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		char oid[128];
865ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		size_t oid_size = sizeof(oid);
866ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		int res;
867ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
868ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
869ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt							  &oid_size, NULL);
870ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
871ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (i == 0) {
872ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				/* No EKU - assume any use allowed */
873ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				return 1;
874ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
875ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			break;
876ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
877ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
878ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (res < 0) {
879ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
880ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			return 0;
881ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
882ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
883ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
884ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
885ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		    os_strcmp(oid, GNUTLS_KP_ANY) == 0)
886ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			return 1;
887ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
888ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
889ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return 0;
890ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt}
891ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* < 3.3.0 */
892ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
893ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
894ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstatic int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
895ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		      gnutls_alert_description_t *err)
896ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{
897ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030103
898ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_datum_t response, buf;
899ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_ocsp_resp_t resp;
900ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	unsigned int cert_status;
901ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	int res;
902ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
903ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
904ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return 0;
905ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
906ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
907ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
908ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_INFO,
909ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "GnuTLS: No valid OCSP response received");
910ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto ocsp_error;
911ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
912ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
913ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG,
914ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
915ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return 0;
916ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
917ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
918ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	/*
919ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * GnuTLS has already verified the OCSP response in
920ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * check_ocsp_response() and rejected handshake if the certificate was
921ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * found to be revoked. However, if the response indicates that the
922ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * status is unknown, handshake continues and reaches here. We need to
923ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * re-import the OCSP response to check for unknown certificate status,
924ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
925ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * gnutls_ocsp_resp_verify_direct() calls.
926ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 */
927ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
928ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	res = gnutls_ocsp_status_request_get(session, &response);
929ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (res != GNUTLS_E_SUCCESS) {
930ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO,
931ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: OCSP response was received, but it was not valid");
932ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto ocsp_error;
933ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
934ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
935ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
936ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto ocsp_error;
937ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
938ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	res = gnutls_ocsp_resp_import(resp, &response);
939ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (res != GNUTLS_E_SUCCESS) {
940ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO,
941ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: Could not parse received OCSP response: %s",
942ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   gnutls_strerror(res));
943ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_ocsp_resp_deinit(resp);
944ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto ocsp_error;
945ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
946ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
947ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
948ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (res == GNUTLS_E_SUCCESS) {
949ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
950ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_free(buf.data);
951ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
952ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
953ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
954ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					  NULL, &cert_status, NULL,
955ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					  NULL, NULL, NULL);
956ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_ocsp_resp_deinit(resp);
957ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (res != GNUTLS_E_SUCCESS) {
958ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO,
959ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: Failed to extract OCSP information: %s",
960ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   gnutls_strerror(res));
961ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto ocsp_error;
962ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
963ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
964ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
965ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
966ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	} else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
967ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG,
968ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: OCSP cert status: revoked");
969ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto ocsp_error;
970ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	} else {
971ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG,
972ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: OCSP cert status: unknown");
973ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (conn->flags & TLS_CONN_REQUIRE_OCSP)
974ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto ocsp_error;
975ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG,
976ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: OCSP was not required, so allow connection to continue");
977ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
978ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
979ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return 0;
980ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
981ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtocsp_error:
982ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_tls_fail_event(conn, NULL, 0, NULL,
983ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			      "bad certificate status response",
984ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			      TLS_FAIL_REVOKED);
985ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	*err = GNUTLS_A_CERTIFICATE_REVOKED;
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
987ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else /* GnuTLS 3.1.3 or newer */
988ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return 0;
989ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* GnuTLS 3.1.3 or newer */
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
993ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstatic int tls_connection_verify_peer(gnutls_session_t session)
9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
995ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	struct tls_connection *conn;
9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int status, num_certs, i;
9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct os_time now;
9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const gnutls_datum_t *certs;
9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_x509_crt_t cert;
1000ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_alert_description_t err;
1001ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	int res;
1002ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1003ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	conn = gnutls_session_get_ptr(session);
1004ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (!conn->verify_peer) {
1005ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG,
1006ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: No peer certificate verification enabled");
1007ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return 0;
1008ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
1009ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1010ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
1011ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1012ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030300
1013ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	{
1014ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_typed_vdata_st data[1];
1015ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		unsigned int elements = 0;
10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1017ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		os_memset(data, 0, sizeof(data));
1018ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (!conn->global->server) {
1019ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
1020ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
1021ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			elements++;
1022ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
1023ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		res = gnutls_certificate_verify_peers(session, data, 1,
1024ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt						      &status);
1025ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
1026ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else /* < 3.3.0 */
1027ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	res = gnutls_certificate_verify_peers2(session, &status);
1028ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif
1029ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (res < 0) {
10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "certificate chain");
1032ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		err = GNUTLS_A_INTERNAL_ERROR;
1033ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
1034ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
1035ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1036ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030104
1037ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	{
1038ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_datum_t info;
1039ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		int ret, type;
1040ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1041ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		type = gnutls_certificate_type_get(session);
1042ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ret = gnutls_certificate_verification_status_print(status, type,
1043ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt								   &info, 0);
1044ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (ret < 0) {
1045ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_DEBUG,
1046ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "GnuTLS: Failed to print verification status");
1047ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_INTERNAL_ERROR;
1048ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
1049ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
1050ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
1051ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_free(info.data);
1052ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
1053ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* GnuTLS 3.1.4 or newer */
1054ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1055ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	certs = gnutls_certificate_get_peers(session, &num_certs);
1056ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (certs == NULL || num_certs == 0) {
1057ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
1058ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		err = GNUTLS_A_UNKNOWN_CA;
1059ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "algorithm");
1067ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			gnutls_tls_fail_event(conn, NULL, 0, NULL,
1068ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					      "certificate uses insecure algorithm",
1069ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					      TLS_FAIL_BAD_CERTIFICATE);
1070ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_INSUFFICIENT_SECURITY;
1071ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "activated");
1076ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			gnutls_tls_fail_event(conn, NULL, 0, NULL,
1077ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					      "certificate not yet valid",
1078ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					      TLS_FAIL_NOT_YET_VALID);
1079ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_CERTIFICATE_EXPIRED;
1080ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (status & GNUTLS_CERT_EXPIRED) {
10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Certificate expired");
1084ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			gnutls_tls_fail_event(conn, NULL, 0, NULL,
1085ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					      "certificate has expired",
1086ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					      TLS_FAIL_EXPIRED);
1087ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_CERTIFICATE_EXPIRED;
1088ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1090ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_tls_fail_event(conn, NULL, 0, NULL,
1091ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				      "untrusted certificate",
1092ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				      TLS_FAIL_UNTRUSTED);
1093ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		err = GNUTLS_A_INTERNAL_ERROR;
1094ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "known issuer");
1100ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
1101ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				      TLS_FAIL_UNTRUSTED);
1102ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		err = GNUTLS_A_UNKNOWN_CA;
1103ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (status & GNUTLS_CERT_REVOKED) {
11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
1108ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_tls_fail_event(conn, NULL, 0, NULL,
1109ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				      "certificate revoked",
1110ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				      TLS_FAIL_REVOKED);
1111ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		err = GNUTLS_A_CERTIFICATE_REVOKED;
1112ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1115ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (status != 0) {
1116ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
1117ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   status);
1118ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		err = GNUTLS_A_INTERNAL_ERROR;
1119ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1122ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (check_ocsp(conn, session, &err))
1123ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
1124ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1125ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	os_get_time(&now);
1126ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < num_certs; i++) {
11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char *buf;
11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t len;
11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (gnutls_x509_crt_init(&cert) < 0) {
11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "failed");
1133ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_BAD_CERTIFICATE;
1134ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (gnutls_x509_crt_import(cert, &certs[i],
11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   GNUTLS_X509_FMT_DER) < 0) {
11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "certificate %d/%d", i + 1, num_certs);
11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_x509_crt_deinit(cert);
1142ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_BAD_CERTIFICATE;
1143ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_x509_crt_get_dn(cert, NULL, &len);
11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		len++;
11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		buf = os_malloc(len + 1);
11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (buf) {
11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			buf[0] = buf[len] = '\0';
11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_x509_crt_get_dn(cert, buf, &len);
11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   i + 1, num_certs, buf);
11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1156ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (conn->global->event_cb) {
1157ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			struct wpabuf *cert_buf = NULL;
1158ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			union tls_event_data ev;
1159ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#ifdef CONFIG_SHA256
1160ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			u8 hash[32];
1161ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			const u8 *_addr[1];
1162ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			size_t _len[1];
1163ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* CONFIG_SHA256 */
1164ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1165ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			os_memset(&ev, 0, sizeof(ev));
1166ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (conn->global->cert_in_cb) {
1167ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				cert_buf = wpabuf_alloc_copy(certs[i].data,
1168ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt							     certs[i].size);
1169ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				ev.peer_cert.cert = cert_buf;
1170ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
1171ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#ifdef CONFIG_SHA256
1172ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			_addr[0] = certs[i].data;
1173ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			_len[0] = certs[i].size;
1174ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (sha256_vector(1, _addr, _len, hash) == 0) {
1175ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				ev.peer_cert.hash = hash;
1176ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				ev.peer_cert.hash_len = sizeof(hash);
1177ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
1178ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* CONFIG_SHA256 */
1179ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			ev.peer_cert.depth = i;
1180ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			ev.peer_cert.subject = buf;
1181ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->global->event_cb(conn->global->cb_ctx,
1182ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					       TLS_PEER_CERTIFICATE, &ev);
1183ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpabuf_free(cert_buf);
11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1186ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (i == 0) {
1187ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (conn->suffix_match &&
1188ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			    !gnutls_x509_crt_check_hostname(
1189ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				    cert, conn->suffix_match)) {
1190ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				wpa_printf(MSG_WARNING,
1191ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "TLS: Domain suffix match '%s' not found",
1192ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   conn->suffix_match);
1193ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				gnutls_tls_fail_event(
1194ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					conn, &certs[i], i, buf,
1195ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					"Domain suffix mismatch",
1196ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1197ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				err = GNUTLS_A_BAD_CERTIFICATE;
1198ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				gnutls_x509_crt_deinit(cert);
1199ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				os_free(buf);
1200ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				goto out;
1201ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
1202ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
12032f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030300
12042f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			if (conn->domain_match &&
12052f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			    !gnutls_x509_crt_check_hostname2(
12062f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				    cert, conn->domain_match,
12072f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				    GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
12082f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				wpa_printf(MSG_WARNING,
12092f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt					   "TLS: Domain match '%s' not found",
12102f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt					   conn->domain_match);
12112f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				gnutls_tls_fail_event(
12122f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt					conn, &certs[i], i, buf,
12132f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt					"Domain mismatch",
12142f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt					TLS_FAIL_DOMAIN_MISMATCH);
12152f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				err = GNUTLS_A_BAD_CERTIFICATE;
12162f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				gnutls_x509_crt_deinit(cert);
12172f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				os_free(buf);
12182f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				goto out;
12192f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			}
12202f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt#endif /* >= 3.3.0 */
12212f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
1222ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			/* TODO: validate altsubject_match.
1223ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			 * For now, any such configuration is rejected in
1224ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			 * tls_connection_set_params() */
1225ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1226ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER < 0x030300
1227ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			/*
1228ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			 * gnutls_certificate_verify_peers() not available, so
1229ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			 * need to check EKU separately.
1230ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			 */
1231ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (!conn->global->server &&
1232ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			    !server_eku_purpose(cert)) {
1233ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				wpa_printf(MSG_WARNING,
1234ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "GnuTLS: No server EKU");
1235ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				gnutls_tls_fail_event(
1236ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					conn, &certs[i], i, buf,
1237ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					"No server EKU",
1238ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					TLS_FAIL_BAD_CERTIFICATE);
1239ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				err = GNUTLS_A_BAD_CERTIFICATE;
1240ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				gnutls_x509_crt_deinit(cert);
1241ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				os_free(buf);
1242ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				goto out;
1243ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
1244ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* < 3.3.0 */
1245ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1247ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (!conn->disable_time_checks &&
1248ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		    (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
1249ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		     gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "not valid at this time",
12528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   i + 1, num_certs);
1253ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			gnutls_tls_fail_event(
1254ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				conn, &certs[i], i, buf,
1255ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				"Certificate is not valid at this time",
1256ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				TLS_FAIL_EXPIRED);
12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_x509_crt_deinit(cert);
1258ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			os_free(buf);
1259ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_CERTIFICATE_EXPIRED;
1260ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
12618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
12628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1263ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		os_free(buf);
1264ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
12658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_x509_crt_deinit(cert);
12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1268ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (conn->global->event_cb != NULL)
1269ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		conn->global->event_cb(conn->global->cb_ctx,
1270ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				       TLS_CERT_CHAIN_SUCCESS, NULL);
1271ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
12728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1273ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1274ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtout:
1275ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	conn->failed++;
1276ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
1277ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return GNUTLS_E_CERTIFICATE_ERROR;
12788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
12828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
12848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *ad;
12858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
12868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
12878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ad == NULL)
12888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
12898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
12918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpabuf_size(ad));
12928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
12938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
12941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
12958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", __func__, (int) res,
12968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   gnutls_strerror(res));
12978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(ad);
12988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
12998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put(ad, res);
13028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
13038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   res);
13048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ad;
13058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tls_connection_handshake(void *tls_ctx,
13098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 struct tls_connection *conn,
13108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 const struct wpabuf *in_data,
13118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 struct wpabuf **appl_data)
13128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = tls_ctx;
13148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *out_data;
13158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
13168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (appl_data)
13188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*appl_data = NULL;
13198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (in_data && wpabuf_len(in_data) > 0) {
13218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->pull_buf) {
13228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
13238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "pull_buf", __func__,
13248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (unsigned long) wpabuf_len(conn->pull_buf));
13258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpabuf_free(conn->pull_buf);
13268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->pull_buf = wpabuf_dup(in_data);
13288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->pull_buf == NULL)
13298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
13308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
13318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_handshake(conn->session);
13348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
1335ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_alert_description_t alert;
1336ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
13378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (ret) {
13388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case GNUTLS_E_AGAIN:
13398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (global->server && conn->established &&
13408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    conn->push_buf == NULL) {
13418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				/* Need to return something to trigger
13428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 * completion of EAP-TLS. */
13438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->push_buf = wpabuf_alloc(0);
13448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
13458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
13468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case GNUTLS_E_FATAL_ALERT_RECEIVED:
1347ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			alert = gnutls_alert_get(conn->session);
13488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
1349ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   __func__, gnutls_alert_get_name(alert));
13508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->read_alerts++;
1351ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (conn->global->event_cb != NULL) {
1352ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				union tls_event_data ev;
1353ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1354ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				os_memset(&ev, 0, sizeof(ev));
1355ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				ev.alert.is_local = 0;
1356ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				ev.alert.type = gnutls_alert_get_name(alert);
1357ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				ev.alert.description = ev.alert.type;
1358ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				conn->global->event_cb(conn->global->cb_ctx,
1359ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt						       TLS_ALERT, &ev);
1360ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
13618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* continue */
13628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
13638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
13648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "-> %s", __func__, gnutls_strerror(ret));
13658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->failed++;
13668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
13688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t size;
13698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1370ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
1371ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1372ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x03010a
1373ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		{
1374ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			char *desc;
1375ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1376ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			desc = gnutls_session_get_desc(conn->session);
1377ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (desc) {
1378ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
1379ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				gnutls_free(desc);
1380ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
13818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1382ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* GnuTLS 3.1.10 or newer */
13838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->established = 1;
13858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->push_buf == NULL) {
13868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* Need to return something to get final TLS ACK. */
13878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->push_buf = wpabuf_alloc(0);
13888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_session_get_data(conn->session, NULL, &size);
13918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (global->session_data == NULL ||
13928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    global->session_data_size < size) {
13938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(global->session_data);
13948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			global->session_data = os_malloc(size);
13958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (global->session_data) {
13978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			global->session_data_size = size;
13988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_session_get_data(conn->session,
13998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						global->session_data,
14008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						&global->session_data_size);
14018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
14028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->pull_buf && appl_data)
14048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*appl_data = gnutls_get_appl_data(conn);
14058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	out_data = conn->push_buf;
14088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->push_buf = NULL;
14098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return out_data;
14108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tls_connection_server_handshake(void *tls_ctx,
14148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						struct tls_connection *conn,
14158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						const struct wpabuf *in_data,
14168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						struct wpabuf **appl_data)
14178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
14198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tls_connection_encrypt(void *tls_ctx,
14238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct tls_connection *conn,
14248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       const struct wpabuf *in_data)
14258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssize_t res;
14278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
14288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = gnutls_record_send(conn->session, wpabuf_head(in_data),
14308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpabuf_len(in_data));
14318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
14328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
14338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, gnutls_strerror(res));
14348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
14358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = conn->push_buf;
14388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->push_buf = NULL;
14398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
14408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tls_connection_decrypt(void *tls_ctx,
14448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct tls_connection *conn,
14458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       const struct wpabuf *in_data)
14468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssize_t res;
14488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *out;
14498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->pull_buf) {
14518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
14528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "pull_buf", __func__,
14538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) wpabuf_len(conn->pull_buf));
14548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(conn->pull_buf);
14558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->pull_buf = wpabuf_dup(in_data);
14578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->pull_buf == NULL)
14588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
14598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
14608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
14628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Even though we try to disable TLS compression, it is possible that
14638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * this cannot be done with all TLS libraries. Add extra buffer space
14648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * to handle the possibility of the decrypted data being longer than
14658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * input data.
14668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
14678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
14688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (out == NULL)
14698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
14708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
14728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpabuf_size(out));
14738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
14748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
14758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", __func__, (int) res, gnutls_strerror(res));
14768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(out);
14778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
14788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put(out, res);
14808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return out;
14828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
14868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
14888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
14898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return gnutls_session_is_resumed(conn->session);
14908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
14948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   u8 *ciphers)
14958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
14978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
14988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1501d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtint tls_get_version(void *ssl_ctx, struct tls_connection *conn,
1502d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		    char *buf, size_t buflen)
1503d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt{
1504d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	/* TODO */
1505d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	return -1;
1506d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt}
1507d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1508d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
15098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
15108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   char *buf, size_t buflen)
15118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
15138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf[0] = '\0';
15148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
15158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_enable_workaround(void *ssl_ctx,
15198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     struct tls_connection *conn)
15208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_record_disable_padding(conn->session);
15228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
15238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
15278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    int ext_type, const u8 *data,
15288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    size_t data_len)
15298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
15318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
15328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
15368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
15388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
15398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn->failed;
15408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
15448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
15468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
15478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn->read_alerts;
15488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
15528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
15548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
15558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn->write_alerts;
15568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_set_session_ticket_cb(void *tls_ctx,
15608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 struct tls_connection *conn,
15618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 tls_session_ticket_cb cb, void *ctx)
15628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
15648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1565ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1566ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1567ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtint tls_get_library_version(char *buf, size_t buf_len)
1568ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{
1569ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
1570ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   GNUTLS_VERSION, gnutls_check_version(NULL));
1571ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt}
1572d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1573d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1574d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtvoid tls_connection_set_success_data(struct tls_connection *conn,
1575d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt				     struct wpabuf *data)
1576d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt{
1577d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt}
1578d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1579d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1580d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtvoid tls_connection_set_success_data_resumed(struct tls_connection *conn)
1581d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt{
1582d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt}
1583d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1584d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1585d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtconst struct wpabuf *
1586d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidttls_connection_get_success_data(struct tls_connection *conn)
1587d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt{
1588d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	return NULL;
1589d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt}
1590d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1591d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt
1592d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidtvoid tls_connection_remove_session(struct tls_connection *conn)
1593d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt{
1594d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt}
1595