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;
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct tls_connection {
43ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	struct tls_global *global;
446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	gnutls_session_t session;
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int read_alerts, write_alerts, failed;
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pre_shared_secret;
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t pre_shared_secret_len;
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int established;
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int verify_peer;
51ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	unsigned int disable_time_checks:1;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *push_buf;
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *pull_buf;
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pull_buf_offset;
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int params_set;
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_credentials_t xcred;
59ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
60ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	char *suffix_match;
612f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	char *domain_match;
62ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	unsigned int flags;
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
66ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstatic int tls_connection_verify_peer(gnutls_session_t session);
67ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
68ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void tls_log_func(int level, const char *msg)
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *s, *pos;
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (level == 6 || level == 7) {
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* These levels seem to be mostly I/O debug and msg dumps */
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	s = os_strdup(msg);
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (s == NULL)
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = s;
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (*pos != '\0') {
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (*pos == '\n') {
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*pos = '\0';
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos++;
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "gnutls<%d> %s", level, s);
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(s);
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid * tls_init(const struct tls_config *conf)
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global;
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
99ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (tls_gnutls_ref_count == 0) {
100ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG,
101ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: Library version %s (runtime) - %s (build)",
102ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   gnutls_check_version(NULL), GNUTLS_VERSION);
103ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	global = os_zalloc(sizeof(*global));
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global == NULL)
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(global);
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tls_gnutls_ref_count++;
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_global_set_log_function(tls_log_func);
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_debug_show_keys)
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_global_set_log_level(11);
118ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
119ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (conf) {
120ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		global->event_cb = conf->event_cb;
121ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		global->cb_ctx = conf->cb_ctx;
122ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		global->cert_in_cb = conf->cert_in_cb;
123ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
124ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return global;
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid tls_deinit(void *ssl_ctx)
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = ssl_ctx;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global) {
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (global->params_set)
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_free_credentials(global->xcred);
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(global->session_data);
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(global);
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tls_gnutls_ref_count--;
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tls_gnutls_ref_count == 0)
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_global_deinit();
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_get_errors(void *ssl_ctx)
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     size_t len)
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_connection *conn = (struct tls_connection *) ptr;
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *end;
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->pull_buf == NULL) {
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		errno = EWOULDBLOCK;
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((size_t) (end - conn->pull_buf_offset) < len)
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		len = end - conn->pull_buf_offset;
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(buf, conn->pull_buf_offset, len);
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->pull_buf_offset += len;
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->pull_buf_offset == end) {
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(conn->pull_buf);
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->pull_buf = NULL;
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->pull_buf_offset = NULL;
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__,
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) (end - conn->pull_buf_offset));
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return len;
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     size_t len)
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_connection *conn = (struct tls_connection *) ptr;
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpabuf_resize(&conn->push_buf, len) < 0) {
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		errno = ENOMEM;
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(conn->push_buf, buf, len);
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return len;
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tls_gnutls_init_session(struct tls_global *global,
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   struct tls_connection *conn)
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const char *err;
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_init(&conn->session,
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "connection: %s", gnutls_strerror(ret));
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_set_default_priority(conn->session);
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0)
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
2141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					 &err);
2151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret < 0) {
2161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
2171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "'%s'", err);
2181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto fail;
2191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_transport_set_push_function(conn->session, tls_push_func);
2236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
224ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_session_set_ptr(conn->session, conn);
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail:
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   gnutls_strerror(ret));
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_deinit(conn->session);
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct tls_connection * tls_connection_init(void *ssl_ctx)
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = ssl_ctx;
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_connection *conn;
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn = os_zalloc(sizeof(*conn));
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
245ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	conn->global = global;
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tls_gnutls_init_session(global, conn)) {
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(conn);
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global->params_set) {
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_credentials_set(conn->session,
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     GNUTLS_CRD_CERTIFICATE,
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     global->xcred);
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "Failed to configure "
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "credentials: %s", gnutls_strerror(ret));
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(conn);
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(conn);
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn;
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_free_credentials(conn->xcred);
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_deinit(conn->session);
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(conn->pre_shared_secret);
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(conn->push_buf);
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(conn->pull_buf);
283ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	os_free(conn->suffix_match);
2842f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	os_free(conn->domain_match);
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(conn);
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn ? conn->established : 0;
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = ssl_ctx;
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Shutdown previous TLS connection without notifying the peer
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * because the connection was already terminated in practice
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * and "close notify" shutdown alert would confuse AS. */
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(conn->push_buf);
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->push_buf = NULL;
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->established = 0;
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_deinit(conn->session);
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tls_gnutls_init_session(global, conn)) {
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "for session resumption use");
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     conn->params_set ? conn->xcred :
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     global->xcred);
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "for session resumption: %s", gnutls_strerror(ret));
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global->session_data) {
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_session_set_data(conn->session,
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      global->session_data,
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      global->session_data_size);
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "data: %s", gnutls_strerror(ret));
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      const struct tls_connection_params *params)
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL || params == NULL)
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->subject_match) {
351ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
352ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return -1;
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->altsubject_match) {
356ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
357ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return -1;
358ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
359ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
360ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	os_free(conn->suffix_match);
361ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	conn->suffix_match = NULL;
362ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (params->suffix_match) {
363ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		conn->suffix_match = os_strdup(params->suffix_match);
364ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (conn->suffix_match == NULL)
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3682f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030300
3692f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	os_free(conn->domain_match);
3702f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	conn->domain_match = NULL;
3712f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (params->domain_match) {
3722f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		conn->domain_match = os_strdup(params->domain_match);
3732f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		if (conn->domain_match == NULL)
3742f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			return -1;
3752f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	}
3762f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt#else /* < 3.3.0 */
3772f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (params->domain_match) {
3782f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
3792f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		return -1;
3802f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	}
3812f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt#endif /* >= 3.3.0 */
3822f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
383ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	conn->flags = params->flags;
384ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
385ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (params->openssl_ciphers) {
386ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
387ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return -1;
388ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
389ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * to force peer validation(?) */
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ca_cert) {
394ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
395ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   params->ca_cert);
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_trust_file(
397ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
399ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_DEBUG,
400ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
401ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   params->ca_cert,
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   gnutls_strerror(ret));
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = gnutls_certificate_set_x509_trust_file(
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->xcred, params->ca_cert,
405ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				GNUTLS_X509_FMT_PEM);
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ret < 0) {
407ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				wpa_printf(MSG_DEBUG,
408ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "Failed to read CA cert '%s' in PEM format: %s",
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   params->ca_cert,
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   gnutls_strerror(ret));
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
414ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	} else if (params->ca_cert_blob) {
415ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_datum_t ca;
416ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
417ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ca.data = (unsigned char *) params->ca_cert_blob;
418ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ca.size = params->ca_cert_blob_len;
419ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
420ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ret = gnutls_certificate_set_x509_trust_mem(
421ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->xcred, &ca, GNUTLS_X509_FMT_DER);
422ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (ret < 0) {
423ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_DEBUG,
424ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "Failed to parse CA cert in DER format: %s",
425ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   gnutls_strerror(ret));
426ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			ret = gnutls_certificate_set_x509_trust_mem(
427ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
428ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (ret < 0) {
429ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				wpa_printf(MSG_DEBUG,
430ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "Failed to parse CA cert in PEM format: %s",
431ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   gnutls_strerror(ret));
432ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				return -1;
433ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
434ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
435ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	} else if (params->ca_path) {
436ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
437ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return -1;
438ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
439ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
440ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	conn->disable_time_checks = 0;
441ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (params->ca_cert || params->ca_cert_blob) {
442ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		conn->verify_peer = 1;
443ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_certificate_set_verify_function(
444ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->xcred, tls_connection_verify_peer);
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_set_verify_flags(
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
452ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->disable_time_checks = 1;
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_set_verify_flags(
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->xcred,
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->client_cert && params->private_key) {
4606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x03010b
4616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = gnutls_certificate_set_x509_key_file2(
4626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			conn->xcred, params->client_cert, params->private_key,
463ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
4646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#else
4656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/* private_key_passwd not (easily) supported here */
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_key_file(
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->xcred, params->client_cert, params->private_key,
468ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			GNUTLS_X509_FMT_DER);
4696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
472ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "in DER format: %s", gnutls_strerror(ret));
4736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x03010b
4746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			ret = gnutls_certificate_set_x509_key_file2(
4756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				conn->xcred, params->client_cert,
476ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				params->private_key, GNUTLS_X509_FMT_PEM,
4776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				params->private_key_passwd, 0);
4786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#else
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = gnutls_certificate_set_x509_key_file(
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->xcred, params->client_cert,
481ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				params->private_key, GNUTLS_X509_FMT_PEM);
4826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ret < 0) {
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "Failed to read client "
485ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "cert/key in PEM format: %s",
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   gnutls_strerror(ret));
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return ret;
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (params->private_key) {
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int pkcs12_ok = 0;
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef PKCS12_FUNCS
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try to load in PKCS#12 format */
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->private_key_passwd);
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret != 0) {
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "PKCS#12 format: %s", gnutls_strerror(ret));
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pkcs12_ok = 1;
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* PKCS12_FUNCS */
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!pkcs12_ok) {
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "included");
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
510ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	} else if (params->client_cert_blob && params->private_key_blob) {
511ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_datum_t cert, key;
512ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
513ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		cert.data = (unsigned char *) params->client_cert_blob;
514ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		cert.size = params->client_cert_blob_len;
515ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		key.data = (unsigned char *) params->private_key_blob;
516ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		key.size = params->private_key_blob_len;
517ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
518ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x03010b
519ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ret = gnutls_certificate_set_x509_key_mem2(
520ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
521ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			params->private_key_passwd, 0);
522ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else
523ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		/* private_key_passwd not (easily) supported here */
524ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ret = gnutls_certificate_set_x509_key_mem(
525ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
526ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif
527ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (ret < 0) {
528ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
529ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "in DER format: %s", gnutls_strerror(ret));
530ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x03010b
531ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			ret = gnutls_certificate_set_x509_key_mem2(
532ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
533ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				params->private_key_passwd, 0);
534ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else
535ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			/* private_key_passwd not (easily) supported here */
536ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			ret = gnutls_certificate_set_x509_key_mem(
537ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
538ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif
539ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (ret < 0) {
540ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				wpa_printf(MSG_DEBUG, "Failed to read client "
541ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "cert/key in PEM format: %s",
542ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   gnutls_strerror(ret));
543ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				return ret;
544ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
545ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
546ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	} else if (params->private_key_blob) {
547ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#ifdef PKCS12_FUNCS
548ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_datum_t key;
549ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
550ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		key.data = (unsigned char *) params->private_key_blob;
551ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		key.size = params->private_key_blob_len;
552ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
553ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		/* Try to load in PKCS#12 format */
554ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
555ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->xcred, &key, GNUTLS_X509_FMT_DER,
556ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			params->private_key_passwd);
557ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (ret != 0) {
558ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
559ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "PKCS#12 format: %s", gnutls_strerror(ret));
560ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			return -1;
561ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
562ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else /* PKCS12_FUNCS */
563ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
564ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return -1;
565ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* PKCS12_FUNCS */
566ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
567ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
568ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030103
569ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
570ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ret = gnutls_ocsp_status_request_enable_client(conn->session,
571ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt							       NULL, 0, NULL);
572ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (ret != GNUTLS_E_SUCCESS) {
573ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_INFO,
574ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "GnuTLS: Failed to enable OCSP client");
575ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			return -1;
576ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
577ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
578ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else /* 3.1.3 */
579ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (params->flags & TLS_CONN_REQUIRE_OCSP) {
580ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO,
581ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: OCSP not supported by this version of GnuTLS");
582ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return -1;
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
584ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* 3.1.3 */
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->params_set = 1;
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     conn->xcred);
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   gnutls_strerror(ret));
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_global_set_params(void *tls_ctx,
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  const struct tls_connection_params *params)
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = tls_ctx;
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Currently, global parameters are only set when running in server
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * mode. */
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	global->server = 1;
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global->params_set) {
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_certificate_free_credentials(global->xcred);
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		global->params_set = 0;
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_certificate_allocate_credentials(&global->xcred);
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "%s", gnutls_strerror(ret));
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ca_cert) {
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_trust_file(
623ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
626ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "in DER format: %s", params->ca_cert,
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   gnutls_strerror(ret));
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = gnutls_certificate_set_x509_trust_file(
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				global->xcred, params->ca_cert,
630ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				GNUTLS_X509_FMT_PEM);
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ret < 0) {
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
633ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "'%s' in PEM format: %s",
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   params->ca_cert,
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   gnutls_strerror(ret));
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				goto fail;
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_set_verify_flags(
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				global->xcred,
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_set_verify_flags(
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				global->xcred,
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->client_cert && params->private_key) {
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* TODO: private_key_passwd? */
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_key_file(
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			global->xcred, params->client_cert,
657ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			params->private_key, GNUTLS_X509_FMT_DER);
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
660ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "in DER format: %s", gnutls_strerror(ret));
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = gnutls_certificate_set_x509_key_file(
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				global->xcred, params->client_cert,
663ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				params->private_key, GNUTLS_X509_FMT_PEM);
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ret < 0) {
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "Failed to read client "
666ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "cert/key in PEM format: %s",
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   gnutls_strerror(ret));
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				goto fail;
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (params->private_key) {
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int pkcs12_ok = 0;
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef PKCS12_FUNCS
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try to load in PKCS#12 format */
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			global->xcred, params->private_key,
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			GNUTLS_X509_FMT_DER, params->private_key_passwd);
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret != 0) {
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "PKCS#12 format: %s", gnutls_strerror(ret));
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fail;
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pkcs12_ok = 1;
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* PKCS12_FUNCS */
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!pkcs12_ok) {
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "included");
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fail;
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	global->params_set = 1;
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail:
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_free_credentials(global->xcred);
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_global_set_verify(void *ssl_ctx, int check_crl)
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      int verify_peer)
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL || conn->session == NULL)
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->verify_peer = verify_peer;
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_server_set_request(conn->session,
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      verify_peer ? GNUTLS_CERT_REQUIRE
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      : GNUTLS_CERT_REQUEST);
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct tls_keys *keys)
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
728ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030012
729ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_datum_t client, server;
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL || conn->session == NULL || keys == NULL)
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(keys, 0, sizeof(*keys));
735ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_session_get_random(conn->session, &client, &server);
736ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	keys->client_random = client.data;
737ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	keys->server_random = server.data;
738ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	keys->client_random_len = client.size;
739ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	keys->server_random_len = client.size;
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
742ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else /* 3.0.18 */
743ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return -1;
744ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* 3.0.18 */
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const char *label, int server_random_first,
750af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt		       int skip_keyblock, u8 *out, size_t out_len)
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
752af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt	if (conn == NULL || conn->session == NULL || skip_keyblock)
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return gnutls_prf(conn->session, os_strlen(label), label,
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  server_random_first, 0, NULL, out_len, (char *) out);
757ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt}
758ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
759ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
760ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstatic void gnutls_tls_fail_event(struct tls_connection *conn,
761ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				  const gnutls_datum_t *cert, int depth,
762ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				  const char *subject, const char *err_str,
763ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				  enum tls_fail_reason reason)
764ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{
765ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	union tls_event_data ev;
766ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	struct tls_global *global = conn->global;
767ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	struct wpabuf *cert_buf = NULL;
768ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
769ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (global->event_cb == NULL)
770ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return;
771ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
772ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	os_memset(&ev, 0, sizeof(ev));
773ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	ev.cert_fail.depth = depth;
774ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	ev.cert_fail.subject = subject ? subject : "";
775ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	ev.cert_fail.reason = reason;
776ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	ev.cert_fail.reason_txt = err_str;
777ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (cert) {
778ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
779ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ev.cert_fail.cert = cert_buf;
780ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
781ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
782ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	wpabuf_free(cert_buf);
783ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt}
784ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
785ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
786ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER < 0x030300
787ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstatic int server_eku_purpose(gnutls_x509_crt_t cert)
788ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{
789ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	unsigned int i;
790ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
791ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	for (i = 0; ; i++) {
792ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		char oid[128];
793ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		size_t oid_size = sizeof(oid);
794ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		int res;
795ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
796ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
797ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt							  &oid_size, NULL);
798ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
799ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (i == 0) {
800ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				/* No EKU - assume any use allowed */
801ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				return 1;
802ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
803ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			break;
804ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
805ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
806ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (res < 0) {
807ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
808ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			return 0;
809ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
810ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
811ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
812ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
813ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		    os_strcmp(oid, GNUTLS_KP_ANY) == 0)
814ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			return 1;
815ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
816ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
817ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return 0;
818ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt}
819ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* < 3.3.0 */
820ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
821ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
822ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstatic int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
823ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		      gnutls_alert_description_t *err)
824ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{
825ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030103
826ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_datum_t response, buf;
827ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_ocsp_resp_t resp;
828ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	unsigned int cert_status;
829ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	int res;
830ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
831ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
832ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return 0;
833ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
834ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
835ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
836ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_INFO,
837ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "GnuTLS: No valid OCSP response received");
838ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto ocsp_error;
839ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
840ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
841ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG,
842ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
843ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return 0;
844ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
845ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
846ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	/*
847ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * GnuTLS has already verified the OCSP response in
848ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * check_ocsp_response() and rejected handshake if the certificate was
849ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * found to be revoked. However, if the response indicates that the
850ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * status is unknown, handshake continues and reaches here. We need to
851ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * re-import the OCSP response to check for unknown certificate status,
852ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
853ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * gnutls_ocsp_resp_verify_direct() calls.
854ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 */
855ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
856ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	res = gnutls_ocsp_status_request_get(session, &response);
857ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (res != GNUTLS_E_SUCCESS) {
858ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO,
859ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: OCSP response was received, but it was not valid");
860ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto ocsp_error;
861ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
862ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
863ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
864ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto ocsp_error;
865ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
866ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	res = gnutls_ocsp_resp_import(resp, &response);
867ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (res != GNUTLS_E_SUCCESS) {
868ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO,
869ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: Could not parse received OCSP response: %s",
870ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   gnutls_strerror(res));
871ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_ocsp_resp_deinit(resp);
872ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto ocsp_error;
873ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
874ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
875ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
876ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (res == GNUTLS_E_SUCCESS) {
877ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
878ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_free(buf.data);
879ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
880ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
881ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
882ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					  NULL, &cert_status, NULL,
883ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					  NULL, NULL, NULL);
884ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_ocsp_resp_deinit(resp);
885ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (res != GNUTLS_E_SUCCESS) {
886ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO,
887ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: Failed to extract OCSP information: %s",
888ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   gnutls_strerror(res));
889ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto ocsp_error;
890ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
891ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
892ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
893ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
894ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	} else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
895ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG,
896ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: OCSP cert status: revoked");
897ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto ocsp_error;
898ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	} else {
899ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG,
900ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: OCSP cert status: unknown");
901ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (conn->flags & TLS_CONN_REQUIRE_OCSP)
902ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto ocsp_error;
903ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG,
904ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: OCSP was not required, so allow connection to continue");
905ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
906ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
907ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return 0;
908ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
909ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtocsp_error:
910ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_tls_fail_event(conn, NULL, 0, NULL,
911ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			      "bad certificate status response",
912ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			      TLS_FAIL_REVOKED);
913ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	*err = GNUTLS_A_CERTIFICATE_REVOKED;
9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
915ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else /* GnuTLS 3.1.3 or newer */
916ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return 0;
917ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* GnuTLS 3.1.3 or newer */
9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
921ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstatic int tls_connection_verify_peer(gnutls_session_t session)
9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
923ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	struct tls_connection *conn;
9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int status, num_certs, i;
9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct os_time now;
9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const gnutls_datum_t *certs;
9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_x509_crt_t cert;
928ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_alert_description_t err;
929ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	int res;
930ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
931ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	conn = gnutls_session_get_ptr(session);
932ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (!conn->verify_peer) {
933ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG,
934ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "GnuTLS: No peer certificate verification enabled");
935ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return 0;
936ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
937ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
938ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
939ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
940ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030300
941ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	{
942ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_typed_vdata_st data[1];
943ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		unsigned int elements = 0;
9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
945ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		os_memset(data, 0, sizeof(data));
946ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (!conn->global->server) {
947ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
948ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
949ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			elements++;
950ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
951ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		res = gnutls_certificate_verify_peers(session, data, 1,
952ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt						      &status);
953ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
954ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#else /* < 3.3.0 */
955ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	res = gnutls_certificate_verify_peers2(session, &status);
956ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif
957ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (res < 0) {
9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "certificate chain");
960ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		err = GNUTLS_A_INTERNAL_ERROR;
961ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
962ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
963ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
964ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030104
965ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	{
966ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_datum_t info;
967ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		int ret, type;
968ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
969ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		type = gnutls_certificate_type_get(session);
970ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		ret = gnutls_certificate_verification_status_print(status, type,
971ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt								   &info, 0);
972ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (ret < 0) {
973ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpa_printf(MSG_DEBUG,
974ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   "GnuTLS: Failed to print verification status");
975ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_INTERNAL_ERROR;
976ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
977ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
978ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
979ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_free(info.data);
980ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
981ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* GnuTLS 3.1.4 or newer */
982ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
983ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	certs = gnutls_certificate_get_peers(session, &num_certs);
984ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (certs == NULL || num_certs == 0) {
985ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
986ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		err = GNUTLS_A_UNKNOWN_CA;
987ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "algorithm");
995ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			gnutls_tls_fail_event(conn, NULL, 0, NULL,
996ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					      "certificate uses insecure algorithm",
997ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					      TLS_FAIL_BAD_CERTIFICATE);
998ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_INSUFFICIENT_SECURITY;
999ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "activated");
1004ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			gnutls_tls_fail_event(conn, NULL, 0, NULL,
1005ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					      "certificate not yet valid",
1006ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					      TLS_FAIL_NOT_YET_VALID);
1007ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_CERTIFICATE_EXPIRED;
1008ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (status & GNUTLS_CERT_EXPIRED) {
10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Certificate expired");
1012ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			gnutls_tls_fail_event(conn, NULL, 0, NULL,
1013ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					      "certificate has expired",
1014ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					      TLS_FAIL_EXPIRED);
1015ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_CERTIFICATE_EXPIRED;
1016ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1018ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_tls_fail_event(conn, NULL, 0, NULL,
1019ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				      "untrusted certificate",
1020ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				      TLS_FAIL_UNTRUSTED);
1021ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		err = GNUTLS_A_INTERNAL_ERROR;
1022ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "known issuer");
1028ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
1029ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				      TLS_FAIL_UNTRUSTED);
1030ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		err = GNUTLS_A_UNKNOWN_CA;
1031ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (status & GNUTLS_CERT_REVOKED) {
10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
1036ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_tls_fail_event(conn, NULL, 0, NULL,
1037ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				      "certificate revoked",
1038ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				      TLS_FAIL_REVOKED);
1039ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		err = GNUTLS_A_CERTIFICATE_REVOKED;
1040ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1043ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (status != 0) {
1044ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
1045ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   status);
1046ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		err = GNUTLS_A_INTERNAL_ERROR;
1047ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1050ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (check_ocsp(conn, session, &err))
1051ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		goto out;
1052ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1053ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	os_get_time(&now);
1054ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < num_certs; i++) {
10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char *buf;
10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t len;
10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (gnutls_x509_crt_init(&cert) < 0) {
10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "failed");
1061ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_BAD_CERTIFICATE;
1062ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (gnutls_x509_crt_import(cert, &certs[i],
10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   GNUTLS_X509_FMT_DER) < 0) {
10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "certificate %d/%d", i + 1, num_certs);
10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_x509_crt_deinit(cert);
1070ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_BAD_CERTIFICATE;
1071ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_x509_crt_get_dn(cert, NULL, &len);
10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		len++;
10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		buf = os_malloc(len + 1);
10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (buf) {
10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			buf[0] = buf[len] = '\0';
10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_x509_crt_get_dn(cert, buf, &len);
10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   i + 1, num_certs, buf);
10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1084ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (conn->global->event_cb) {
1085ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			struct wpabuf *cert_buf = NULL;
1086ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			union tls_event_data ev;
1087ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#ifdef CONFIG_SHA256
1088ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			u8 hash[32];
1089ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			const u8 *_addr[1];
1090ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			size_t _len[1];
1091ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* CONFIG_SHA256 */
1092ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1093ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			os_memset(&ev, 0, sizeof(ev));
1094ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (conn->global->cert_in_cb) {
1095ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				cert_buf = wpabuf_alloc_copy(certs[i].data,
1096ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt							     certs[i].size);
1097ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				ev.peer_cert.cert = cert_buf;
1098ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
1099ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#ifdef CONFIG_SHA256
1100ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			_addr[0] = certs[i].data;
1101ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			_len[0] = certs[i].size;
1102ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (sha256_vector(1, _addr, _len, hash) == 0) {
1103ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				ev.peer_cert.hash = hash;
1104ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				ev.peer_cert.hash_len = sizeof(hash);
1105ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
1106ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* CONFIG_SHA256 */
1107ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			ev.peer_cert.depth = i;
1108ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			ev.peer_cert.subject = buf;
1109ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			conn->global->event_cb(conn->global->cb_ctx,
1110ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					       TLS_PEER_CERTIFICATE, &ev);
1111ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			wpabuf_free(cert_buf);
11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1114ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (i == 0) {
1115ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (conn->suffix_match &&
1116ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			    !gnutls_x509_crt_check_hostname(
1117ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				    cert, conn->suffix_match)) {
1118ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				wpa_printf(MSG_WARNING,
1119ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "TLS: Domain suffix match '%s' not found",
1120ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   conn->suffix_match);
1121ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				gnutls_tls_fail_event(
1122ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					conn, &certs[i], i, buf,
1123ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					"Domain suffix mismatch",
1124ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1125ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				err = GNUTLS_A_BAD_CERTIFICATE;
1126ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				gnutls_x509_crt_deinit(cert);
1127ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				os_free(buf);
1128ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				goto out;
1129ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
1130ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
11312f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x030300
11322f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			if (conn->domain_match &&
11332f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			    !gnutls_x509_crt_check_hostname2(
11342f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				    cert, conn->domain_match,
11352f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				    GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
11362f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				wpa_printf(MSG_WARNING,
11372f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt					   "TLS: Domain match '%s' not found",
11382f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt					   conn->domain_match);
11392f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				gnutls_tls_fail_event(
11402f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt					conn, &certs[i], i, buf,
11412f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt					"Domain mismatch",
11422f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt					TLS_FAIL_DOMAIN_MISMATCH);
11432f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				err = GNUTLS_A_BAD_CERTIFICATE;
11442f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				gnutls_x509_crt_deinit(cert);
11452f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				os_free(buf);
11462f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				goto out;
11472f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			}
11482f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt#endif /* >= 3.3.0 */
11492f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
1150ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			/* TODO: validate altsubject_match.
1151ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			 * For now, any such configuration is rejected in
1152ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			 * tls_connection_set_params() */
1153ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1154ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER < 0x030300
1155ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			/*
1156ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			 * gnutls_certificate_verify_peers() not available, so
1157ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			 * need to check EKU separately.
1158ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			 */
1159ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (!conn->global->server &&
1160ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			    !server_eku_purpose(cert)) {
1161ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				wpa_printf(MSG_WARNING,
1162ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					   "GnuTLS: No server EKU");
1163ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				gnutls_tls_fail_event(
1164ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					conn, &certs[i], i, buf,
1165ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					"No server EKU",
1166ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt					TLS_FAIL_BAD_CERTIFICATE);
1167ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				err = GNUTLS_A_BAD_CERTIFICATE;
1168ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				gnutls_x509_crt_deinit(cert);
1169ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				os_free(buf);
1170ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				goto out;
1171ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
1172ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* < 3.3.0 */
1173ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		}
11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1175ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		if (!conn->disable_time_checks &&
1176ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		    (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
1177ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		     gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "not valid at this time",
11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   i + 1, num_certs);
1181ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			gnutls_tls_fail_event(
1182ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				conn, &certs[i], i, buf,
1183ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				"Certificate is not valid at this time",
1184ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				TLS_FAIL_EXPIRED);
11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_x509_crt_deinit(cert);
1186ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			os_free(buf);
1187ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			err = GNUTLS_A_CERTIFICATE_EXPIRED;
1188ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			goto out;
11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1191ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		os_free(buf);
1192ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_x509_crt_deinit(cert);
11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1196ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (conn->global->event_cb != NULL)
1197ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		conn->global->event_cb(conn->global->cb_ctx,
1198ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				       TLS_CERT_CHAIN_SUCCESS, NULL);
1199ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1201ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1202ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtout:
1203ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	conn->failed++;
1204ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
1205ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return GNUTLS_E_CERTIFICATE_ERROR;
12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
12108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
12128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *ad;
12138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
12148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
12158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ad == NULL)
12168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
12178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpabuf_size(ad));
12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
12221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", __func__, (int) res,
12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   gnutls_strerror(res));
12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(ad);
12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put(ad, res);
12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   res);
12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ad;
12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tls_connection_handshake(void *tls_ctx,
12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 struct tls_connection *conn,
12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 const struct wpabuf *in_data,
12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 struct wpabuf **appl_data)
12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = tls_ctx;
12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *out_data;
12438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
12448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (appl_data)
12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*appl_data = NULL;
12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (in_data && wpabuf_len(in_data) > 0) {
12498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->pull_buf) {
12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "pull_buf", __func__,
12528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (unsigned long) wpabuf_len(conn->pull_buf));
12538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpabuf_free(conn->pull_buf);
12548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->pull_buf = wpabuf_dup(in_data);
12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->pull_buf == NULL)
12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
12598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_handshake(conn->session);
12628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
1263ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		gnutls_alert_description_t alert;
1264ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
12658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (ret) {
12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case GNUTLS_E_AGAIN:
12678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (global->server && conn->established &&
12688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    conn->push_buf == NULL) {
12698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				/* Need to return something to trigger
12708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 * completion of EAP-TLS. */
12718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->push_buf = wpabuf_alloc(0);
12728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
12738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
12748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case GNUTLS_E_FATAL_ALERT_RECEIVED:
1275ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			alert = gnutls_alert_get(conn->session);
12768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
1277ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   __func__, gnutls_alert_get_name(alert));
12788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->read_alerts++;
1279ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (conn->global->event_cb != NULL) {
1280ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				union tls_event_data ev;
1281ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1282ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				os_memset(&ev, 0, sizeof(ev));
1283ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				ev.alert.is_local = 0;
1284ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				ev.alert.type = gnutls_alert_get_name(alert);
1285ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				ev.alert.description = ev.alert.type;
1286ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				conn->global->event_cb(conn->global->cb_ctx,
1287ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt						       TLS_ALERT, &ev);
1288ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
12898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* continue */
12908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
12918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
12928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "-> %s", __func__, gnutls_strerror(ret));
12938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->failed++;
12948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
12958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
12968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t size;
12978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1298ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
1299ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1300ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#if GNUTLS_VERSION_NUMBER >= 0x03010a
1301ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		{
1302ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			char *desc;
1303ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1304ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			desc = gnutls_session_get_desc(conn->session);
1305ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			if (desc) {
1306ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
1307ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				gnutls_free(desc);
1308ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			}
13098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1310ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt#endif /* GnuTLS 3.1.10 or newer */
13118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->established = 1;
13138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->push_buf == NULL) {
13148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* Need to return something to get final TLS ACK. */
13158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->push_buf = wpabuf_alloc(0);
13168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_session_get_data(conn->session, NULL, &size);
13198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (global->session_data == NULL ||
13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    global->session_data_size < size) {
13218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(global->session_data);
13228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			global->session_data = os_malloc(size);
13238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (global->session_data) {
13258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			global->session_data_size = size;
13268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_session_get_data(conn->session,
13278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						global->session_data,
13288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						&global->session_data_size);
13298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->pull_buf && appl_data)
13328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*appl_data = gnutls_get_appl_data(conn);
13338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	out_data = conn->push_buf;
13368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->push_buf = NULL;
13378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return out_data;
13388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tls_connection_server_handshake(void *tls_ctx,
13428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						struct tls_connection *conn,
13438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						const struct wpabuf *in_data,
13448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						struct wpabuf **appl_data)
13458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
13478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tls_connection_encrypt(void *tls_ctx,
13518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct tls_connection *conn,
13528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       const struct wpabuf *in_data)
13538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssize_t res;
13558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
13568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = gnutls_record_send(conn->session, wpabuf_head(in_data),
13588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpabuf_len(in_data));
13598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
13608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
13618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, gnutls_strerror(res));
13628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
13638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = conn->push_buf;
13668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->push_buf = NULL;
13678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
13688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tls_connection_decrypt(void *tls_ctx,
13728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct tls_connection *conn,
13738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       const struct wpabuf *in_data)
13748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssize_t res;
13768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *out;
13778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->pull_buf) {
13798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
13808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "pull_buf", __func__,
13818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) wpabuf_len(conn->pull_buf));
13828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(conn->pull_buf);
13838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->pull_buf = wpabuf_dup(in_data);
13858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->pull_buf == NULL)
13868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
13878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
13888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
13908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Even though we try to disable TLS compression, it is possible that
13918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * this cannot be done with all TLS libraries. Add extra buffer space
13928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * to handle the possibility of the decrypted data being longer than
13938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * input data.
13948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
13958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (out == NULL)
13978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
13988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
14008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpabuf_size(out));
14018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
14028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
14038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", __func__, (int) res, gnutls_strerror(res));
14048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(out);
14058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
14068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put(out, res);
14088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return out;
14108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
14148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
14168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
14178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return gnutls_session_is_resumed(conn->session);
14188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
14228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   u8 *ciphers)
14238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
14258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
14268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
14308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   char *buf, size_t buflen)
14318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
14338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf[0] = '\0';
14348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
14358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_enable_workaround(void *ssl_ctx,
14398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     struct tls_connection *conn)
14408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_record_disable_padding(conn->session);
14428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
14438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
14478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    int ext_type, const u8 *data,
14488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    size_t data_len)
14498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
14518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
14528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
14568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
14588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
14598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn->failed;
14608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
14648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
14668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
14678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn->read_alerts;
14688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
14728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
14748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
14758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn->write_alerts;
14768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int tls_capabilities(void *tls_ctx)
14808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
14828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_set_session_ticket_cb(void *tls_ctx,
14868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 struct tls_connection *conn,
14878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 tls_session_ticket_cb cb, void *ctx)
14888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
14908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1491ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1492ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1493ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtint tls_get_library_version(char *buf, size_t buf_len)
1494ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{
1495ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
1496ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   GNUTLS_VERSION, gnutls_check_version(NULL));
1497ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt}
1498