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