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 */
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "tls.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#define WPA_TLS_RANDOM_SIZE 32
211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#define WPA_TLS_MASTER_SIZE 48
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if LIBGNUTLS_VERSION_NUMBER < 0x010302
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * use of internal structures to get the master_secret and
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * {server,client}_random.
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define GNUTLS_INTERNAL_STRUCTURE_HACK
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * It looks like gnutls does not provide access to client/server_random and
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * master_key. This is somewhat unfortunate since these are needed for key
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hack that copies the gnutls_session_int definition from gnutls_int.h so that
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * we can get the needed information.
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidttypedef u8 uint8;
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidttypedef unsigned char opaque;
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidttypedef struct {
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt    uint8 suite[2];
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} cipher_suite_st;
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidttypedef struct {
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_connection_end_t entity;
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_kx_algorithm_t kx_algorithm;
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_mac_algorithm_t read_mac_algorithm;
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_compression_method_t read_compression_algorithm;
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_mac_algorithm_t write_mac_algorithm;
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_compression_method_t write_compression_algorithm;
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cipher_suite_st current_cipher_suite;
581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	opaque master_secret[WPA_TLS_MASTER_SIZE];
591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	opaque client_random[WPA_TLS_RANDOM_SIZE];
601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	opaque server_random[WPA_TLS_RANDOM_SIZE];
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* followed by stuff we are not interested in */
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} security_parameters_st;
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct gnutls_session_int {
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	security_parameters_st security_parameters;
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* followed by things we are not interested in */
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tls_gnutls_ref_count = 0;
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct tls_global {
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Data for session resumption */
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *session_data;
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t session_data_size;
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int server;
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int params_set;
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_credentials_t xcred;
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct tls_connection {
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_session session;
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *subject_match, *altsubject_match;
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int read_alerts, write_alerts, failed;
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pre_shared_secret;
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t pre_shared_secret_len;
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int established;
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int verify_peer;
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *push_buf;
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *pull_buf;
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *pull_buf_offset;
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int params_set;
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_credentials_t xcred;
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void tls_log_func(int level, const char *msg)
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *s, *pos;
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (level == 6 || level == 7) {
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* These levels seem to be mostly I/O debug and msg dumps */
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	s = os_strdup(msg);
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (s == NULL)
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = s;
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (*pos != '\0') {
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (*pos == '\n') {
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*pos = '\0';
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos++;
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "gnutls<%d> %s", level, s);
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(s);
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid * tls_init(const struct tls_config *conf)
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global;
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Because of the horrible hack to get master_secret and client/server
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * random, we need to make sure that the gnutls version is something
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * that is expected to have same structure definition for the session
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * data.. */
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const char *ver;
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 "1.3.2",
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 NULL };
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	global = os_zalloc(sizeof(*global));
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global == NULL)
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(global);
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tls_gnutls_ref_count++;
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ver = gnutls_check_version(NULL);
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ver == NULL) {
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tls_deinit(global);
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; ok_ver[i]; i++) {
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (strcmp(ok_ver[i], ver) == 0)
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ok_ver[i] == NULL) {
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "to be tested and enabled in tls_gnutls.c", ver);
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tls_deinit(global);
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_global_set_log_function(tls_log_func);
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_debug_show_keys)
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_global_set_log_level(11);
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return global;
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid tls_deinit(void *ssl_ctx)
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = ssl_ctx;
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global) {
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (global->params_set)
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_free_credentials(global->xcred);
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(global->session_data);
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(global);
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tls_gnutls_ref_count--;
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tls_gnutls_ref_count == 0)
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_global_deinit();
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_get_errors(void *ssl_ctx)
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     size_t len)
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_connection *conn = (struct tls_connection *) ptr;
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *end;
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->pull_buf == NULL) {
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		errno = EWOULDBLOCK;
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((size_t) (end - conn->pull_buf_offset) < len)
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		len = end - conn->pull_buf_offset;
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(buf, conn->pull_buf_offset, len);
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->pull_buf_offset += len;
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->pull_buf_offset == end) {
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(conn->pull_buf);
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->pull_buf = NULL;
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->pull_buf_offset = NULL;
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__,
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) (end - conn->pull_buf_offset));
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return len;
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     size_t len)
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_connection *conn = (struct tls_connection *) ptr;
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpabuf_resize(&conn->push_buf, len) < 0) {
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		errno = ENOMEM;
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_data(conn->push_buf, buf, len);
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return len;
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tls_gnutls_init_session(struct tls_global *global,
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   struct tls_connection *conn)
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
2501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const char *err;
2511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const int protos[2] = { GNUTLS_TLS1, 0 };
2541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_init(&conn->session,
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "connection: %s", gnutls_strerror(ret));
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_set_default_priority(conn->session);
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0)
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
2701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
2711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					 &err);
2721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret < 0) {
2731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
2741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "'%s'", err);
2751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto fail;
2761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
2771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0)
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_protocol_set_priority(conn->session, protos);
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0)
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
2851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_transport_set_push_function(conn->session, tls_push_func);
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail:
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   gnutls_strerror(ret));
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_deinit(conn->session);
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct tls_connection * tls_connection_init(void *ssl_ctx)
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = ssl_ctx;
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_connection *conn;
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn = os_zalloc(sizeof(*conn));
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tls_gnutls_init_session(global, conn)) {
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(conn);
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global->params_set) {
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_credentials_set(conn->session,
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     GNUTLS_CRD_CERTIFICATE,
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     global->xcred);
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "Failed to configure "
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "credentials: %s", gnutls_strerror(ret));
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(conn);
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(conn);
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn;
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_free_credentials(conn->xcred);
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_deinit(conn->session);
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(conn->pre_shared_secret);
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(conn->subject_match);
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(conn->altsubject_match);
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(conn->push_buf);
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(conn->pull_buf);
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(conn);
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn ? conn->established : 0;
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = ssl_ctx;
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Shutdown previous TLS connection without notifying the peer
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * because the connection was already terminated in practice
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * and "close notify" shutdown alert would confuse AS. */
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(conn->push_buf);
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->push_buf = NULL;
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->established = 0;
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_deinit(conn->session);
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tls_gnutls_init_session(global, conn)) {
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "for session resumption use");
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     conn->params_set ? conn->xcred :
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     global->xcred);
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "for session resumption: %s", gnutls_strerror(ret));
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global->session_data) {
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_session_set_data(conn->session,
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      global->session_data,
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      global->session_data_size);
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "data: %s", gnutls_strerror(ret));
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if 0
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tls_match_altsubject(X509 *cert, const char *match)
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	GENERAL_NAME *gen;
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *field, *tmp;
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *ext;
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, found = 0;
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len;
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gen = sk_GENERAL_NAME_value(ext, i);
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (gen->type) {
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case GEN_EMAIL:
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			field = "EMAIL";
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case GEN_DNS:
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			field = "DNS";
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case GEN_URI:
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			field = "URI";
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			field = NULL;
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "unsupported type=%d", gen->type);
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!field)
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   field, gen->d.ia5->data);
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		len = os_strlen(field) + 1 +
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			strlen((char *) gen->d.ia5->data) + 1;
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		tmp = os_malloc(len);
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tmp == NULL)
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (strstr(tmp, match))
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			found++;
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(tmp);
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return found;
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if 0
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char buf[256];
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	X509 *err_cert;
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int err, depth;
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SSL *ssl;
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_connection *conn;
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *match, *altmatch;
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = X509_STORE_CTX_get_error(x509_ctx);
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	depth = X509_STORE_CTX_get_error_depth(x509_ctx);
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 SSL_get_ex_data_X509_STORE_CTX_idx());
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn = SSL_get_app_data(ssl);
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	match = conn ? conn->subject_match : NULL;
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	altmatch = conn ? conn->altsubject_match : NULL;
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!preverify_ok) {
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   " error %d (%s) depth %d for '%s'", err,
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   X509_verify_cert_error_string(err), depth, buf);
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   preverify_ok, err,
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   X509_verify_cert_error_string(err), depth, buf);
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (depth == 0 && match && strstr(buf, match) == NULL) {
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "match with '%s'", buf, match);
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			preverify_ok = 0;
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else if (depth == 0 && altmatch &&
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   !tls_match_altsubject(err_cert, altmatch)) {
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "'%s' not found", altmatch);
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			preverify_ok = 0;
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return preverify_ok;
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      const struct tls_connection_params *params)
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL || params == NULL)
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(conn->subject_match);
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->subject_match = NULL;
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->subject_match) {
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->subject_match = os_strdup(params->subject_match);
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->subject_match == NULL)
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(conn->altsubject_match);
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->altsubject_match = NULL;
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->altsubject_match) {
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->altsubject_match = os_strdup(params->altsubject_match);
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->altsubject_match == NULL)
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * to force peer validation(?) */
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ca_cert) {
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->verify_peer = 1;
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_trust_file(
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "in PEM format: %s", params->ca_cert,
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   gnutls_strerror(ret));
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = gnutls_certificate_set_x509_trust_file(
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->xcred, params->ca_cert,
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				GNUTLS_X509_FMT_DER);
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ret < 0) {
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "'%s' in DER format: %s",
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   params->ca_cert,
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   gnutls_strerror(ret));
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_set_verify_flags(
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_set_verify_flags(
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->xcred,
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->client_cert && params->private_key) {
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* TODO: private_key_passwd? */
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_key_file(
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->xcred, params->client_cert, params->private_key,
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			GNUTLS_X509_FMT_PEM);
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "in PEM format: %s", gnutls_strerror(ret));
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = gnutls_certificate_set_x509_key_file(
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->xcred, params->client_cert,
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				params->private_key, GNUTLS_X509_FMT_DER);
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ret < 0) {
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "Failed to read client "
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "cert/key in DER format: %s",
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   gnutls_strerror(ret));
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return ret;
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (params->private_key) {
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int pkcs12_ok = 0;
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef PKCS12_FUNCS
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try to load in PKCS#12 format */
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->private_key_passwd);
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret != 0) {
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "PKCS#12 format: %s", gnutls_strerror(ret));
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pkcs12_ok = 1;
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* PKCS12_FUNCS */
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!pkcs12_ok) {
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "included");
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->params_set = 1;
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     conn->xcred);
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   gnutls_strerror(ret));
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_global_set_params(void *tls_ctx,
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  const struct tls_connection_params *params)
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = tls_ctx;
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Currently, global parameters are only set when running in server
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * mode. */
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	global->server = 1;
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global->params_set) {
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_certificate_free_credentials(global->xcred);
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		global->params_set = 0;
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_certificate_allocate_credentials(&global->xcred);
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "%s", gnutls_strerror(ret));
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ca_cert) {
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_trust_file(
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "in PEM format: %s", params->ca_cert,
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   gnutls_strerror(ret));
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = gnutls_certificate_set_x509_trust_file(
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				global->xcred, params->ca_cert,
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				GNUTLS_X509_FMT_DER);
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ret < 0) {
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "'%s' in DER format: %s",
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   params->ca_cert,
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   gnutls_strerror(ret));
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				goto fail;
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_set_verify_flags(
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				global->xcred,
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_certificate_set_verify_flags(
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				global->xcred,
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->client_cert && params->private_key) {
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* TODO: private_key_passwd? */
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_key_file(
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			global->xcred, params->client_cert,
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->private_key, GNUTLS_X509_FMT_PEM);
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret < 0) {
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "in PEM format: %s", gnutls_strerror(ret));
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = gnutls_certificate_set_x509_key_file(
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				global->xcred, params->client_cert,
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				params->private_key, GNUTLS_X509_FMT_DER);
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ret < 0) {
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "Failed to read client "
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "cert/key in DER format: %s",
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   gnutls_strerror(ret));
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				goto fail;
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (params->private_key) {
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int pkcs12_ok = 0;
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef PKCS12_FUNCS
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try to load in PKCS#12 format */
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			global->xcred, params->private_key,
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			GNUTLS_X509_FMT_DER, params->private_key_passwd);
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret != 0) {
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "PKCS#12 format: %s", gnutls_strerror(ret));
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fail;
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			pkcs12_ok = 1;
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* PKCS12_FUNCS */
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!pkcs12_ok) {
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "included");
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto fail;
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	global->params_set = 1;
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail:
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_free_credentials(global->xcred);
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_global_set_verify(void *ssl_ctx, int check_crl)
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      int verify_peer)
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL || conn->session == NULL)
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->verify_peer = verify_peer;
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_certificate_server_set_request(conn->session,
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      verify_peer ? GNUTLS_CERT_REQUIRE
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      : GNUTLS_CERT_REQUEST);
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct tls_keys *keys)
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	security_parameters_st *sec;
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL || conn->session == NULL || keys == NULL)
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(keys, 0, sizeof(*keys));
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sec = &conn->session->security_parameters;
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->master_key = sec->master_secret;
7661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	keys->master_key_len = WPA_TLS_MASTER_SIZE;
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->client_random = sec->client_random;
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->server_random = sec->server_random;
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->client_random =
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(u8 *) gnutls_session_get_client_random(conn->session);
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	keys->server_random =
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(u8 *) gnutls_session_get_server_random(conn->session);
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* No access to master_secret */
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
7761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
7791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	keys->client_random_len = WPA_TLS_RANDOM_SIZE;
7801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	keys->server_random_len = WPA_TLS_RANDOM_SIZE;
7811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       const char *label, int server_random_first,
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       u8 *out, size_t out_len)
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL || conn->session == NULL)
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return gnutls_prf(conn->session, os_strlen(label), label,
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  server_random_first, 0, NULL, out_len, (char *) out);
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int tls_connection_verify_peer(struct tls_connection *conn,
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      gnutls_alert_description_t *err)
8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int status, num_certs, i;
8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct os_time now;
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const gnutls_datum_t *certs;
8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_x509_crt_t cert;
8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "certificate chain");
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*err = GNUTLS_A_INTERNAL_ERROR;
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
8201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		*err = GNUTLS_A_INTERNAL_ERROR;
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "algorithm");
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*err = GNUTLS_A_INSUFFICIENT_SECURITY;
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "activated");
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (status & GNUTLS_CERT_EXPIRED) {
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Certificate expired");
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "known issuer");
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*err = GNUTLS_A_UNKNOWN_CA;
8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (status & GNUTLS_CERT_REVOKED) {
8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*err = GNUTLS_A_CERTIFICATE_REVOKED;
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_get_time(&now);
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	certs = gnutls_certificate_get_peers(conn->session, &num_certs);
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (certs == NULL) {
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "received");
8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*err = GNUTLS_A_UNKNOWN_CA;
8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < num_certs; i++) {
8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char *buf;
8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t len;
8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (gnutls_x509_crt_init(&cert) < 0) {
8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "failed");
8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*err = GNUTLS_A_BAD_CERTIFICATE;
8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (gnutls_x509_crt_import(cert, &certs[i],
8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   GNUTLS_X509_FMT_DER) < 0) {
8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "certificate %d/%d", i + 1, num_certs);
8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_x509_crt_deinit(cert);
8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*err = GNUTLS_A_BAD_CERTIFICATE;
8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_x509_crt_get_dn(cert, NULL, &len);
8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		len++;
8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		buf = os_malloc(len + 1);
8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (buf) {
8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			buf[0] = buf[len] = '\0';
8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_x509_crt_get_dn(cert, buf, &len);
8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   i + 1, num_certs, buf);
8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (i == 0) {
8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* TODO: validate subject_match and altsubject_match */
8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(buf);
8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    gnutls_x509_crt_get_activation_time(cert) > now.sec) {
9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "not valid at this time",
9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   i + 1, num_certs);
9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_x509_crt_deinit(cert);
9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_x509_crt_deinit(cert);
9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *ad;
9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ad == NULL)
9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpabuf_size(ad));
9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
9281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", __func__, (int) res,
9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   gnutls_strerror(res));
9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(ad);
9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put(ad, res);
9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   res);
9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ad;
9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tls_connection_handshake(void *tls_ctx,
9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 struct tls_connection *conn,
9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 const struct wpabuf *in_data,
9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 struct wpabuf **appl_data)
9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct tls_global *global = tls_ctx;
9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *out_data;
9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (appl_data)
9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*appl_data = NULL;
9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (in_data && wpabuf_len(in_data) > 0) {
9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->pull_buf) {
9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "pull_buf", __func__,
9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (unsigned long) wpabuf_len(conn->pull_buf));
9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpabuf_free(conn->pull_buf);
9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->pull_buf = wpabuf_dup(in_data);
9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->pull_buf == NULL)
9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NULL;
9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = gnutls_handshake(conn->session);
9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (ret) {
9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case GNUTLS_E_AGAIN:
9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (global->server && conn->established &&
9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    conn->push_buf == NULL) {
9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				/* Need to return something to trigger
9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 * completion of EAP-TLS. */
9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				conn->push_buf = wpabuf_alloc(0);
9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case GNUTLS_E_FATAL_ALERT_RECEIVED:
9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   __func__, gnutls_alert_get_name(
9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   gnutls_alert_get(conn->session)));
9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->read_alerts++;
9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* continue */
9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "-> %s", __func__, gnutls_strerror(ret));
9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->failed++;
9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		size_t size;
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_alert_description_t err;
9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->verify_peer &&
9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    tls_connection_verify_peer(conn, &err)) {
9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "failed validation");
9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->failed++;
9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto out;
10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		conn->established = 1;
10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->push_buf == NULL) {
10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* Need to return something to get final TLS ACK. */
10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			conn->push_buf = wpabuf_alloc(0);
10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		gnutls_session_get_data(conn->session, NULL, &size);
10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (global->session_data == NULL ||
10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    global->session_data_size < size) {
10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(global->session_data);
10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			global->session_data = os_malloc(size);
10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (global->session_data) {
10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			global->session_data_size = size;
10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			gnutls_session_get_data(conn->session,
10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						global->session_data,
10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						&global->session_data_size);
10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (conn->pull_buf && appl_data)
10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*appl_data = gnutls_get_appl_data(conn);
10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtout:
10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	out_data = conn->push_buf;
10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->push_buf = NULL;
10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return out_data;
10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tls_connection_server_handshake(void *tls_ctx,
10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						struct tls_connection *conn,
10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						const struct wpabuf *in_data,
10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						struct wpabuf **appl_data)
10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tls_connection_encrypt(void *tls_ctx,
10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct tls_connection *conn,
10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       const struct wpabuf *in_data)
10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssize_t res;
10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = gnutls_record_send(conn->session, wpabuf_head(in_data),
10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpabuf_len(in_data));
10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   __func__, gnutls_strerror(res));
10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = conn->push_buf;
10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->push_buf = NULL;
10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpabuf * tls_connection_decrypt(void *tls_ctx,
10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct tls_connection *conn,
10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       const struct wpabuf *in_data)
10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssize_t res;
10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *out;
10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->pull_buf) {
10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "pull_buf", __func__,
10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) wpabuf_len(conn->pull_buf));
10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(conn->pull_buf);
10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->pull_buf = wpabuf_dup(in_data);
10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn->pull_buf == NULL)
10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Even though we try to disable TLS compression, it is possible that
10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * this cannot be done with all TLS libraries. Add extra buffer space
10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * to handle the possibility of the decrypted data being longer than
10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * input data.
10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (out == NULL)
10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpabuf_size(out));
10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", __func__, (int) res, gnutls_strerror(res));
10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(out);
10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put(out, res);
11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return out;
11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return gnutls_session_is_resumed(conn->session);
11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   u8 *ciphers)
11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   char *buf, size_t buflen)
11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf[0] = '\0';
11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_enable_workaround(void *ssl_ctx,
11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     struct tls_connection *conn)
11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	gnutls_record_disable_padding(conn->session);
11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    int ext_type, const u8 *data,
11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    size_t data_len)
11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn->failed;
11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn->read_alerts;
11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conn == NULL)
11668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return conn->write_alerts;
11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_get_keyblock_size(void *tls_ctx,
11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     struct tls_connection *conn)
11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtunsigned int tls_capabilities(void *tls_ctx)
11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint tls_connection_set_session_ticket_cb(void *tls_ctx,
11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 struct tls_connection *conn,
11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 tls_session_ticket_cb cb, void *ctx)
11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1191