1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * SSL/TLS interface functions for GnuTLS
3e5b75505Sopenharmony_ci * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#include "includes.h"
10e5b75505Sopenharmony_ci#include <gnutls/gnutls.h>
11e5b75505Sopenharmony_ci#include <gnutls/x509.h>
12e5b75505Sopenharmony_ci#ifdef PKCS12_FUNCS
13e5b75505Sopenharmony_ci#include <gnutls/pkcs12.h>
14e5b75505Sopenharmony_ci#endif /* PKCS12_FUNCS */
15e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x030103
16e5b75505Sopenharmony_ci#include <gnutls/ocsp.h>
17e5b75505Sopenharmony_ci#endif /* 3.1.3 */
18e5b75505Sopenharmony_ci
19e5b75505Sopenharmony_ci#include "common.h"
20e5b75505Sopenharmony_ci#include "crypto/crypto.h"
21e5b75505Sopenharmony_ci#include "tls.h"
22e5b75505Sopenharmony_ci
23e5b75505Sopenharmony_ci
24e5b75505Sopenharmony_cistatic int tls_gnutls_ref_count = 0;
25e5b75505Sopenharmony_ci
26e5b75505Sopenharmony_cistruct tls_global {
27e5b75505Sopenharmony_ci	/* Data for session resumption */
28e5b75505Sopenharmony_ci	void *session_data;
29e5b75505Sopenharmony_ci	size_t session_data_size;
30e5b75505Sopenharmony_ci
31e5b75505Sopenharmony_ci	int server;
32e5b75505Sopenharmony_ci
33e5b75505Sopenharmony_ci	int params_set;
34e5b75505Sopenharmony_ci	gnutls_certificate_credentials_t xcred;
35e5b75505Sopenharmony_ci
36e5b75505Sopenharmony_ci	void (*event_cb)(void *ctx, enum tls_event ev,
37e5b75505Sopenharmony_ci			 union tls_event_data *data);
38e5b75505Sopenharmony_ci	void *cb_ctx;
39e5b75505Sopenharmony_ci	int cert_in_cb;
40e5b75505Sopenharmony_ci
41e5b75505Sopenharmony_ci	char *ocsp_stapling_response;
42e5b75505Sopenharmony_ci};
43e5b75505Sopenharmony_ci
44e5b75505Sopenharmony_cistruct tls_connection {
45e5b75505Sopenharmony_ci	struct tls_global *global;
46e5b75505Sopenharmony_ci	gnutls_session_t session;
47e5b75505Sopenharmony_ci	int read_alerts, write_alerts, failed;
48e5b75505Sopenharmony_ci
49e5b75505Sopenharmony_ci	u8 *pre_shared_secret;
50e5b75505Sopenharmony_ci	size_t pre_shared_secret_len;
51e5b75505Sopenharmony_ci	int established;
52e5b75505Sopenharmony_ci	int verify_peer;
53e5b75505Sopenharmony_ci	unsigned int disable_time_checks:1;
54e5b75505Sopenharmony_ci
55e5b75505Sopenharmony_ci	struct wpabuf *push_buf;
56e5b75505Sopenharmony_ci	struct wpabuf *pull_buf;
57e5b75505Sopenharmony_ci	const u8 *pull_buf_offset;
58e5b75505Sopenharmony_ci
59e5b75505Sopenharmony_ci	int params_set;
60e5b75505Sopenharmony_ci	gnutls_certificate_credentials_t xcred;
61e5b75505Sopenharmony_ci
62e5b75505Sopenharmony_ci	char *suffix_match;
63e5b75505Sopenharmony_ci	char *domain_match;
64e5b75505Sopenharmony_ci	unsigned int flags;
65e5b75505Sopenharmony_ci};
66e5b75505Sopenharmony_ci
67e5b75505Sopenharmony_ci
68e5b75505Sopenharmony_cistatic int tls_connection_verify_peer(gnutls_session_t session);
69e5b75505Sopenharmony_ci
70e5b75505Sopenharmony_ci
71e5b75505Sopenharmony_cistatic void tls_log_func(int level, const char *msg)
72e5b75505Sopenharmony_ci{
73e5b75505Sopenharmony_ci	char *s, *pos;
74e5b75505Sopenharmony_ci	if (level == 6 || level == 7) {
75e5b75505Sopenharmony_ci		/* These levels seem to be mostly I/O debug and msg dumps */
76e5b75505Sopenharmony_ci		return;
77e5b75505Sopenharmony_ci	}
78e5b75505Sopenharmony_ci
79e5b75505Sopenharmony_ci	s = os_strdup(msg);
80e5b75505Sopenharmony_ci	if (s == NULL)
81e5b75505Sopenharmony_ci		return;
82e5b75505Sopenharmony_ci
83e5b75505Sopenharmony_ci	pos = s;
84e5b75505Sopenharmony_ci	while (*pos != '\0') {
85e5b75505Sopenharmony_ci		if (*pos == '\n') {
86e5b75505Sopenharmony_ci			*pos = '\0';
87e5b75505Sopenharmony_ci			break;
88e5b75505Sopenharmony_ci		}
89e5b75505Sopenharmony_ci		pos++;
90e5b75505Sopenharmony_ci	}
91e5b75505Sopenharmony_ci	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
92e5b75505Sopenharmony_ci		   "gnutls<%d> %s", level, s);
93e5b75505Sopenharmony_ci	os_free(s);
94e5b75505Sopenharmony_ci}
95e5b75505Sopenharmony_ci
96e5b75505Sopenharmony_ci
97e5b75505Sopenharmony_civoid * tls_init(const struct tls_config *conf)
98e5b75505Sopenharmony_ci{
99e5b75505Sopenharmony_ci	struct tls_global *global;
100e5b75505Sopenharmony_ci
101e5b75505Sopenharmony_ci	if (tls_gnutls_ref_count == 0) {
102e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
103e5b75505Sopenharmony_ci			   "GnuTLS: Library version %s (runtime) - %s (build)",
104e5b75505Sopenharmony_ci			   gnutls_check_version(NULL), GNUTLS_VERSION);
105e5b75505Sopenharmony_ci	}
106e5b75505Sopenharmony_ci
107e5b75505Sopenharmony_ci	global = os_zalloc(sizeof(*global));
108e5b75505Sopenharmony_ci	if (global == NULL)
109e5b75505Sopenharmony_ci		return NULL;
110e5b75505Sopenharmony_ci
111e5b75505Sopenharmony_ci	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
112e5b75505Sopenharmony_ci		os_free(global);
113e5b75505Sopenharmony_ci		return NULL;
114e5b75505Sopenharmony_ci	}
115e5b75505Sopenharmony_ci	tls_gnutls_ref_count++;
116e5b75505Sopenharmony_ci
117e5b75505Sopenharmony_ci	gnutls_global_set_log_function(tls_log_func);
118e5b75505Sopenharmony_ci	if (wpa_debug_show_keys)
119e5b75505Sopenharmony_ci		gnutls_global_set_log_level(11);
120e5b75505Sopenharmony_ci
121e5b75505Sopenharmony_ci	if (conf) {
122e5b75505Sopenharmony_ci		global->event_cb = conf->event_cb;
123e5b75505Sopenharmony_ci		global->cb_ctx = conf->cb_ctx;
124e5b75505Sopenharmony_ci		global->cert_in_cb = conf->cert_in_cb;
125e5b75505Sopenharmony_ci	}
126e5b75505Sopenharmony_ci
127e5b75505Sopenharmony_ci	return global;
128e5b75505Sopenharmony_ci}
129e5b75505Sopenharmony_ci
130e5b75505Sopenharmony_ci
131e5b75505Sopenharmony_civoid tls_deinit(void *ssl_ctx)
132e5b75505Sopenharmony_ci{
133e5b75505Sopenharmony_ci	struct tls_global *global = ssl_ctx;
134e5b75505Sopenharmony_ci	if (global) {
135e5b75505Sopenharmony_ci		if (global->params_set)
136e5b75505Sopenharmony_ci			gnutls_certificate_free_credentials(global->xcred);
137e5b75505Sopenharmony_ci		os_free(global->session_data);
138e5b75505Sopenharmony_ci		os_free(global->ocsp_stapling_response);
139e5b75505Sopenharmony_ci		os_free(global);
140e5b75505Sopenharmony_ci	}
141e5b75505Sopenharmony_ci
142e5b75505Sopenharmony_ci	tls_gnutls_ref_count--;
143e5b75505Sopenharmony_ci	if (tls_gnutls_ref_count == 0)
144e5b75505Sopenharmony_ci		gnutls_global_deinit();
145e5b75505Sopenharmony_ci}
146e5b75505Sopenharmony_ci
147e5b75505Sopenharmony_ci
148e5b75505Sopenharmony_ciint tls_get_errors(void *ssl_ctx)
149e5b75505Sopenharmony_ci{
150e5b75505Sopenharmony_ci	return 0;
151e5b75505Sopenharmony_ci}
152e5b75505Sopenharmony_ci
153e5b75505Sopenharmony_ci
154e5b75505Sopenharmony_cistatic ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
155e5b75505Sopenharmony_ci			     size_t len)
156e5b75505Sopenharmony_ci{
157e5b75505Sopenharmony_ci	struct tls_connection *conn = (struct tls_connection *) ptr;
158e5b75505Sopenharmony_ci	const u8 *end;
159e5b75505Sopenharmony_ci	if (conn->pull_buf == NULL) {
160e5b75505Sopenharmony_ci		errno = EWOULDBLOCK;
161e5b75505Sopenharmony_ci		return -1;
162e5b75505Sopenharmony_ci	}
163e5b75505Sopenharmony_ci
164e5b75505Sopenharmony_ci	end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
165e5b75505Sopenharmony_ci	if ((size_t) (end - conn->pull_buf_offset) < len)
166e5b75505Sopenharmony_ci		len = end - conn->pull_buf_offset;
167e5b75505Sopenharmony_ci	os_memcpy(buf, conn->pull_buf_offset, len);
168e5b75505Sopenharmony_ci	conn->pull_buf_offset += len;
169e5b75505Sopenharmony_ci	if (conn->pull_buf_offset == end) {
170e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
171e5b75505Sopenharmony_ci		wpabuf_free(conn->pull_buf);
172e5b75505Sopenharmony_ci		conn->pull_buf = NULL;
173e5b75505Sopenharmony_ci		conn->pull_buf_offset = NULL;
174e5b75505Sopenharmony_ci	} else {
175e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
176e5b75505Sopenharmony_ci			   __func__,
177e5b75505Sopenharmony_ci			   (unsigned long) (end - conn->pull_buf_offset));
178e5b75505Sopenharmony_ci	}
179e5b75505Sopenharmony_ci	return len;
180e5b75505Sopenharmony_ci}
181e5b75505Sopenharmony_ci
182e5b75505Sopenharmony_ci
183e5b75505Sopenharmony_cistatic ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
184e5b75505Sopenharmony_ci			     size_t len)
185e5b75505Sopenharmony_ci{
186e5b75505Sopenharmony_ci	struct tls_connection *conn = (struct tls_connection *) ptr;
187e5b75505Sopenharmony_ci
188e5b75505Sopenharmony_ci	if (wpabuf_resize(&conn->push_buf, len) < 0) {
189e5b75505Sopenharmony_ci		errno = ENOMEM;
190e5b75505Sopenharmony_ci		return -1;
191e5b75505Sopenharmony_ci	}
192e5b75505Sopenharmony_ci	wpabuf_put_data(conn->push_buf, buf, len);
193e5b75505Sopenharmony_ci
194e5b75505Sopenharmony_ci	return len;
195e5b75505Sopenharmony_ci}
196e5b75505Sopenharmony_ci
197e5b75505Sopenharmony_ci
198e5b75505Sopenharmony_cistatic int tls_gnutls_init_session(struct tls_global *global,
199e5b75505Sopenharmony_ci				   struct tls_connection *conn)
200e5b75505Sopenharmony_ci{
201e5b75505Sopenharmony_ci	const char *err;
202e5b75505Sopenharmony_ci	int ret;
203e5b75505Sopenharmony_ci
204e5b75505Sopenharmony_ci	ret = gnutls_init(&conn->session,
205e5b75505Sopenharmony_ci			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
206e5b75505Sopenharmony_ci	if (ret < 0) {
207e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
208e5b75505Sopenharmony_ci			   "connection: %s", gnutls_strerror(ret));
209e5b75505Sopenharmony_ci		return -1;
210e5b75505Sopenharmony_ci	}
211e5b75505Sopenharmony_ci
212e5b75505Sopenharmony_ci	ret = gnutls_set_default_priority(conn->session);
213e5b75505Sopenharmony_ci	if (ret < 0)
214e5b75505Sopenharmony_ci		goto fail;
215e5b75505Sopenharmony_ci
216e5b75505Sopenharmony_ci	ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
217e5b75505Sopenharmony_ci					 &err);
218e5b75505Sopenharmony_ci	if (ret < 0) {
219e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
220e5b75505Sopenharmony_ci			   "'%s'", err);
221e5b75505Sopenharmony_ci		goto fail;
222e5b75505Sopenharmony_ci	}
223e5b75505Sopenharmony_ci
224e5b75505Sopenharmony_ci	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
225e5b75505Sopenharmony_ci	gnutls_transport_set_push_function(conn->session, tls_push_func);
226e5b75505Sopenharmony_ci	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
227e5b75505Sopenharmony_ci	gnutls_session_set_ptr(conn->session, conn);
228e5b75505Sopenharmony_ci
229e5b75505Sopenharmony_ci	return 0;
230e5b75505Sopenharmony_ci
231e5b75505Sopenharmony_cifail:
232e5b75505Sopenharmony_ci	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
233e5b75505Sopenharmony_ci		   gnutls_strerror(ret));
234e5b75505Sopenharmony_ci	gnutls_deinit(conn->session);
235e5b75505Sopenharmony_ci	return -1;
236e5b75505Sopenharmony_ci}
237e5b75505Sopenharmony_ci
238e5b75505Sopenharmony_ci
239e5b75505Sopenharmony_cistruct tls_connection * tls_connection_init(void *ssl_ctx)
240e5b75505Sopenharmony_ci{
241e5b75505Sopenharmony_ci	struct tls_global *global = ssl_ctx;
242e5b75505Sopenharmony_ci	struct tls_connection *conn;
243e5b75505Sopenharmony_ci	int ret;
244e5b75505Sopenharmony_ci
245e5b75505Sopenharmony_ci	conn = os_zalloc(sizeof(*conn));
246e5b75505Sopenharmony_ci	if (conn == NULL)
247e5b75505Sopenharmony_ci		return NULL;
248e5b75505Sopenharmony_ci	conn->global = global;
249e5b75505Sopenharmony_ci
250e5b75505Sopenharmony_ci	if (tls_gnutls_init_session(global, conn)) {
251e5b75505Sopenharmony_ci		os_free(conn);
252e5b75505Sopenharmony_ci		return NULL;
253e5b75505Sopenharmony_ci	}
254e5b75505Sopenharmony_ci
255e5b75505Sopenharmony_ci	if (global->params_set) {
256e5b75505Sopenharmony_ci		ret = gnutls_credentials_set(conn->session,
257e5b75505Sopenharmony_ci					     GNUTLS_CRD_CERTIFICATE,
258e5b75505Sopenharmony_ci					     global->xcred);
259e5b75505Sopenharmony_ci		if (ret < 0) {
260e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "Failed to configure "
261e5b75505Sopenharmony_ci				   "credentials: %s", gnutls_strerror(ret));
262e5b75505Sopenharmony_ci			os_free(conn);
263e5b75505Sopenharmony_ci			return NULL;
264e5b75505Sopenharmony_ci		}
265e5b75505Sopenharmony_ci	}
266e5b75505Sopenharmony_ci
267e5b75505Sopenharmony_ci	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
268e5b75505Sopenharmony_ci		os_free(conn);
269e5b75505Sopenharmony_ci		return NULL;
270e5b75505Sopenharmony_ci	}
271e5b75505Sopenharmony_ci
272e5b75505Sopenharmony_ci	return conn;
273e5b75505Sopenharmony_ci}
274e5b75505Sopenharmony_ci
275e5b75505Sopenharmony_ci
276e5b75505Sopenharmony_civoid tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
277e5b75505Sopenharmony_ci{
278e5b75505Sopenharmony_ci	if (conn == NULL)
279e5b75505Sopenharmony_ci		return;
280e5b75505Sopenharmony_ci
281e5b75505Sopenharmony_ci	gnutls_certificate_free_credentials(conn->xcred);
282e5b75505Sopenharmony_ci	gnutls_deinit(conn->session);
283e5b75505Sopenharmony_ci	os_free(conn->pre_shared_secret);
284e5b75505Sopenharmony_ci	wpabuf_free(conn->push_buf);
285e5b75505Sopenharmony_ci	wpabuf_free(conn->pull_buf);
286e5b75505Sopenharmony_ci	os_free(conn->suffix_match);
287e5b75505Sopenharmony_ci	os_free(conn->domain_match);
288e5b75505Sopenharmony_ci	os_free(conn);
289e5b75505Sopenharmony_ci}
290e5b75505Sopenharmony_ci
291e5b75505Sopenharmony_ci
292e5b75505Sopenharmony_ciint tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
293e5b75505Sopenharmony_ci{
294e5b75505Sopenharmony_ci	return conn ? conn->established : 0;
295e5b75505Sopenharmony_ci}
296e5b75505Sopenharmony_ci
297e5b75505Sopenharmony_ci
298e5b75505Sopenharmony_cichar * tls_connection_peer_serial_num(void *tls_ctx,
299e5b75505Sopenharmony_ci				      struct tls_connection *conn)
300e5b75505Sopenharmony_ci{
301e5b75505Sopenharmony_ci	/* TODO */
302e5b75505Sopenharmony_ci	return NULL;
303e5b75505Sopenharmony_ci}
304e5b75505Sopenharmony_ci
305e5b75505Sopenharmony_ci
306e5b75505Sopenharmony_ciint tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
307e5b75505Sopenharmony_ci{
308e5b75505Sopenharmony_ci	struct tls_global *global = ssl_ctx;
309e5b75505Sopenharmony_ci	int ret;
310e5b75505Sopenharmony_ci
311e5b75505Sopenharmony_ci	if (conn == NULL)
312e5b75505Sopenharmony_ci		return -1;
313e5b75505Sopenharmony_ci
314e5b75505Sopenharmony_ci	/* Shutdown previous TLS connection without notifying the peer
315e5b75505Sopenharmony_ci	 * because the connection was already terminated in practice
316e5b75505Sopenharmony_ci	 * and "close notify" shutdown alert would confuse AS. */
317e5b75505Sopenharmony_ci	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
318e5b75505Sopenharmony_ci	wpabuf_free(conn->push_buf);
319e5b75505Sopenharmony_ci	conn->push_buf = NULL;
320e5b75505Sopenharmony_ci	conn->established = 0;
321e5b75505Sopenharmony_ci
322e5b75505Sopenharmony_ci	gnutls_deinit(conn->session);
323e5b75505Sopenharmony_ci	if (tls_gnutls_init_session(global, conn)) {
324e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
325e5b75505Sopenharmony_ci			   "for session resumption use");
326e5b75505Sopenharmony_ci		return -1;
327e5b75505Sopenharmony_ci	}
328e5b75505Sopenharmony_ci
329e5b75505Sopenharmony_ci	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
330e5b75505Sopenharmony_ci				     conn->params_set ? conn->xcred :
331e5b75505Sopenharmony_ci				     global->xcred);
332e5b75505Sopenharmony_ci	if (ret < 0) {
333e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
334e5b75505Sopenharmony_ci			   "for session resumption: %s", gnutls_strerror(ret));
335e5b75505Sopenharmony_ci		return -1;
336e5b75505Sopenharmony_ci	}
337e5b75505Sopenharmony_ci
338e5b75505Sopenharmony_ci	if (global->session_data) {
339e5b75505Sopenharmony_ci		ret = gnutls_session_set_data(conn->session,
340e5b75505Sopenharmony_ci					      global->session_data,
341e5b75505Sopenharmony_ci					      global->session_data_size);
342e5b75505Sopenharmony_ci		if (ret < 0) {
343e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
344e5b75505Sopenharmony_ci				   "data: %s", gnutls_strerror(ret));
345e5b75505Sopenharmony_ci			return -1;
346e5b75505Sopenharmony_ci		}
347e5b75505Sopenharmony_ci	}
348e5b75505Sopenharmony_ci
349e5b75505Sopenharmony_ci	return 0;
350e5b75505Sopenharmony_ci}
351e5b75505Sopenharmony_ci
352e5b75505Sopenharmony_ci
353e5b75505Sopenharmony_ciint tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
354e5b75505Sopenharmony_ci			      const struct tls_connection_params *params)
355e5b75505Sopenharmony_ci{
356e5b75505Sopenharmony_ci	int ret;
357e5b75505Sopenharmony_ci	const char *err;
358e5b75505Sopenharmony_ci	char prio_buf[100];
359e5b75505Sopenharmony_ci	const char *prio = NULL;
360e5b75505Sopenharmony_ci
361e5b75505Sopenharmony_ci	if (conn == NULL || params == NULL)
362e5b75505Sopenharmony_ci		return -1;
363e5b75505Sopenharmony_ci
364e5b75505Sopenharmony_ci	if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
365e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
366e5b75505Sopenharmony_ci			   "GnuTLS: ocsp=3 not supported");
367e5b75505Sopenharmony_ci		return -1;
368e5b75505Sopenharmony_ci	}
369e5b75505Sopenharmony_ci
370e5b75505Sopenharmony_ci	if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
371e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
372e5b75505Sopenharmony_ci			   "GnuTLS: tls_ext_cert_check=1 not supported");
373e5b75505Sopenharmony_ci		return -1;
374e5b75505Sopenharmony_ci	}
375e5b75505Sopenharmony_ci
376e5b75505Sopenharmony_ci	if (params->subject_match) {
377e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
378e5b75505Sopenharmony_ci		return -1;
379e5b75505Sopenharmony_ci	}
380e5b75505Sopenharmony_ci
381e5b75505Sopenharmony_ci	if (params->altsubject_match) {
382e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "GnuTLS: altsubject_match not supported");
383e5b75505Sopenharmony_ci		return -1;
384e5b75505Sopenharmony_ci	}
385e5b75505Sopenharmony_ci
386e5b75505Sopenharmony_ci	os_free(conn->suffix_match);
387e5b75505Sopenharmony_ci	conn->suffix_match = NULL;
388e5b75505Sopenharmony_ci	if (params->suffix_match) {
389e5b75505Sopenharmony_ci		conn->suffix_match = os_strdup(params->suffix_match);
390e5b75505Sopenharmony_ci		if (conn->suffix_match == NULL)
391e5b75505Sopenharmony_ci			return -1;
392e5b75505Sopenharmony_ci	}
393e5b75505Sopenharmony_ci
394e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x030300
395e5b75505Sopenharmony_ci	os_free(conn->domain_match);
396e5b75505Sopenharmony_ci	conn->domain_match = NULL;
397e5b75505Sopenharmony_ci	if (params->domain_match) {
398e5b75505Sopenharmony_ci		conn->domain_match = os_strdup(params->domain_match);
399e5b75505Sopenharmony_ci		if (conn->domain_match == NULL)
400e5b75505Sopenharmony_ci			return -1;
401e5b75505Sopenharmony_ci	}
402e5b75505Sopenharmony_ci#else /* < 3.3.0 */
403e5b75505Sopenharmony_ci	if (params->domain_match) {
404e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported");
405e5b75505Sopenharmony_ci		return -1;
406e5b75505Sopenharmony_ci	}
407e5b75505Sopenharmony_ci#endif /* >= 3.3.0 */
408e5b75505Sopenharmony_ci
409e5b75505Sopenharmony_ci	conn->flags = params->flags;
410e5b75505Sopenharmony_ci
411e5b75505Sopenharmony_ci	if (params->flags & (TLS_CONN_DISABLE_TLSv1_0 |
412e5b75505Sopenharmony_ci			     TLS_CONN_DISABLE_TLSv1_1 |
413e5b75505Sopenharmony_ci			     TLS_CONN_DISABLE_TLSv1_2)) {
414e5b75505Sopenharmony_ci		os_snprintf(prio_buf, sizeof(prio_buf),
415e5b75505Sopenharmony_ci			    "NORMAL:-VERS-SSL3.0%s%s%s",
416e5b75505Sopenharmony_ci			    params->flags & TLS_CONN_DISABLE_TLSv1_0 ?
417e5b75505Sopenharmony_ci			    ":-VERS-TLS1.0" : "",
418e5b75505Sopenharmony_ci			    params->flags & TLS_CONN_DISABLE_TLSv1_1 ?
419e5b75505Sopenharmony_ci			    ":-VERS-TLS1.1" : "",
420e5b75505Sopenharmony_ci			    params->flags & TLS_CONN_DISABLE_TLSv1_2 ?
421e5b75505Sopenharmony_ci			    ":-VERS-TLS1.2" : "");
422e5b75505Sopenharmony_ci		prio = prio_buf;
423e5b75505Sopenharmony_ci	}
424e5b75505Sopenharmony_ci
425e5b75505Sopenharmony_ci	if (params->openssl_ciphers) {
426e5b75505Sopenharmony_ci		if (os_strcmp(params->openssl_ciphers, "SUITEB128") == 0) {
427e5b75505Sopenharmony_ci			prio = "SUITEB128";
428e5b75505Sopenharmony_ci		} else if (os_strcmp(params->openssl_ciphers,
429e5b75505Sopenharmony_ci				     "SUITEB192") == 0) {
430e5b75505Sopenharmony_ci			prio = "SUITEB192";
431e5b75505Sopenharmony_ci		} else if ((params->flags & TLS_CONN_SUITEB) &&
432e5b75505Sopenharmony_ci			   os_strcmp(params->openssl_ciphers,
433e5b75505Sopenharmony_ci				     "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
434e5b75505Sopenharmony_ci			prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
435e5b75505Sopenharmony_ci		} else if (os_strcmp(params->openssl_ciphers,
436e5b75505Sopenharmony_ci				     "ECDHE-RSA-AES256-GCM-SHA384") == 0) {
437e5b75505Sopenharmony_ci			prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
438e5b75505Sopenharmony_ci		} else if (os_strcmp(params->openssl_ciphers,
439e5b75505Sopenharmony_ci				     "DHE-RSA-AES256-GCM-SHA384") == 0) {
440e5b75505Sopenharmony_ci			prio = "NONE:+VERS-TLS1.2:+AEAD:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
441e5b75505Sopenharmony_ci		} else if (os_strcmp(params->openssl_ciphers,
442e5b75505Sopenharmony_ci				     "ECDHE-ECDSA-AES256-GCM-SHA384") == 0) {
443e5b75505Sopenharmony_ci			prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
444e5b75505Sopenharmony_ci		} else {
445e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO,
446e5b75505Sopenharmony_ci				   "GnuTLS: openssl_ciphers not supported");
447e5b75505Sopenharmony_ci			return -1;
448e5b75505Sopenharmony_ci		}
449e5b75505Sopenharmony_ci	} else if (params->flags & TLS_CONN_SUITEB) {
450e5b75505Sopenharmony_ci		prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
451e5b75505Sopenharmony_ci	}
452e5b75505Sopenharmony_ci
453e5b75505Sopenharmony_ci	if (prio) {
454e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "GnuTLS: Set priority string: %s", prio);
455e5b75505Sopenharmony_ci		ret = gnutls_priority_set_direct(conn->session, prio, &err);
456e5b75505Sopenharmony_ci		if (ret < 0) {
457e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR,
458e5b75505Sopenharmony_ci				   "GnuTLS: Priority string failure at '%s'",
459e5b75505Sopenharmony_ci				   err);
460e5b75505Sopenharmony_ci			return -1;
461e5b75505Sopenharmony_ci		}
462e5b75505Sopenharmony_ci	}
463e5b75505Sopenharmony_ci
464e5b75505Sopenharmony_ci	if (params->openssl_ecdh_curves) {
465e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
466e5b75505Sopenharmony_ci			   "GnuTLS: openssl_ecdh_curves not supported");
467e5b75505Sopenharmony_ci		return -1;
468e5b75505Sopenharmony_ci	}
469e5b75505Sopenharmony_ci
470e5b75505Sopenharmony_ci	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
471e5b75505Sopenharmony_ci	 * to force peer validation(?) */
472e5b75505Sopenharmony_ci
473e5b75505Sopenharmony_ci	if (params->ca_cert) {
474e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "GnuTLS: Try to parse %s in DER format",
475e5b75505Sopenharmony_ci			   params->ca_cert);
476e5b75505Sopenharmony_ci		ret = gnutls_certificate_set_x509_trust_file(
477e5b75505Sopenharmony_ci			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
478e5b75505Sopenharmony_ci		if (ret < 0) {
479e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
480e5b75505Sopenharmony_ci				   "GnuTLS: Failed to read CA cert '%s' in DER format (%s) - try in PEM format",
481e5b75505Sopenharmony_ci				   params->ca_cert,
482e5b75505Sopenharmony_ci				   gnutls_strerror(ret));
483e5b75505Sopenharmony_ci			ret = gnutls_certificate_set_x509_trust_file(
484e5b75505Sopenharmony_ci				conn->xcred, params->ca_cert,
485e5b75505Sopenharmony_ci				GNUTLS_X509_FMT_PEM);
486e5b75505Sopenharmony_ci			if (ret < 0) {
487e5b75505Sopenharmony_ci				wpa_printf(MSG_DEBUG,
488e5b75505Sopenharmony_ci					   "Failed to read CA cert '%s' in PEM format: %s",
489e5b75505Sopenharmony_ci					   params->ca_cert,
490e5b75505Sopenharmony_ci					   gnutls_strerror(ret));
491e5b75505Sopenharmony_ci				return -1;
492e5b75505Sopenharmony_ci			}
493e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
494e5b75505Sopenharmony_ci				   "GnuTLS: Successfully read CA cert '%s' in PEM format",
495e5b75505Sopenharmony_ci				   params->ca_cert);
496e5b75505Sopenharmony_ci		} else {
497e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
498e5b75505Sopenharmony_ci				   "GnuTLS: Successfully read CA cert '%s' in DER format",
499e5b75505Sopenharmony_ci				   params->ca_cert);
500e5b75505Sopenharmony_ci		}
501e5b75505Sopenharmony_ci	} else if (params->ca_cert_blob) {
502e5b75505Sopenharmony_ci		gnutls_datum_t ca;
503e5b75505Sopenharmony_ci
504e5b75505Sopenharmony_ci		ca.data = (unsigned char *) params->ca_cert_blob;
505e5b75505Sopenharmony_ci		ca.size = params->ca_cert_blob_len;
506e5b75505Sopenharmony_ci
507e5b75505Sopenharmony_ci		ret = gnutls_certificate_set_x509_trust_mem(
508e5b75505Sopenharmony_ci			conn->xcred, &ca, GNUTLS_X509_FMT_DER);
509e5b75505Sopenharmony_ci		if (ret < 0) {
510e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
511e5b75505Sopenharmony_ci				   "Failed to parse CA cert in DER format: %s",
512e5b75505Sopenharmony_ci				   gnutls_strerror(ret));
513e5b75505Sopenharmony_ci			ret = gnutls_certificate_set_x509_trust_mem(
514e5b75505Sopenharmony_ci				conn->xcred, &ca, GNUTLS_X509_FMT_PEM);
515e5b75505Sopenharmony_ci			if (ret < 0) {
516e5b75505Sopenharmony_ci				wpa_printf(MSG_DEBUG,
517e5b75505Sopenharmony_ci					   "Failed to parse CA cert in PEM format: %s",
518e5b75505Sopenharmony_ci					   gnutls_strerror(ret));
519e5b75505Sopenharmony_ci				return -1;
520e5b75505Sopenharmony_ci			}
521e5b75505Sopenharmony_ci		}
522e5b75505Sopenharmony_ci	} else if (params->ca_path) {
523e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "GnuTLS: ca_path not supported");
524e5b75505Sopenharmony_ci		return -1;
525e5b75505Sopenharmony_ci	}
526e5b75505Sopenharmony_ci
527e5b75505Sopenharmony_ci	conn->disable_time_checks = 0;
528e5b75505Sopenharmony_ci	if (params->ca_cert || params->ca_cert_blob) {
529e5b75505Sopenharmony_ci		conn->verify_peer = 1;
530e5b75505Sopenharmony_ci		gnutls_certificate_set_verify_function(
531e5b75505Sopenharmony_ci			conn->xcred, tls_connection_verify_peer);
532e5b75505Sopenharmony_ci
533e5b75505Sopenharmony_ci		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
534e5b75505Sopenharmony_ci			gnutls_certificate_set_verify_flags(
535e5b75505Sopenharmony_ci				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
536e5b75505Sopenharmony_ci		}
537e5b75505Sopenharmony_ci
538e5b75505Sopenharmony_ci		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
539e5b75505Sopenharmony_ci			conn->disable_time_checks = 1;
540e5b75505Sopenharmony_ci			gnutls_certificate_set_verify_flags(
541e5b75505Sopenharmony_ci				conn->xcred,
542e5b75505Sopenharmony_ci				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
543e5b75505Sopenharmony_ci		}
544e5b75505Sopenharmony_ci	}
545e5b75505Sopenharmony_ci
546e5b75505Sopenharmony_ci	if (params->client_cert && params->private_key) {
547e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
548e5b75505Sopenharmony_ci			   "GnuTLS: Try to parse client cert '%s' and key '%s' in DER format",
549e5b75505Sopenharmony_ci			   params->client_cert, params->private_key);
550e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x03010b
551e5b75505Sopenharmony_ci		ret = gnutls_certificate_set_x509_key_file2(
552e5b75505Sopenharmony_ci			conn->xcred, params->client_cert, params->private_key,
553e5b75505Sopenharmony_ci			GNUTLS_X509_FMT_DER, params->private_key_passwd, 0);
554e5b75505Sopenharmony_ci#else
555e5b75505Sopenharmony_ci		/* private_key_passwd not (easily) supported here */
556e5b75505Sopenharmony_ci		ret = gnutls_certificate_set_x509_key_file(
557e5b75505Sopenharmony_ci			conn->xcred, params->client_cert, params->private_key,
558e5b75505Sopenharmony_ci			GNUTLS_X509_FMT_DER);
559e5b75505Sopenharmony_ci#endif
560e5b75505Sopenharmony_ci		if (ret < 0) {
561e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
562e5b75505Sopenharmony_ci				   "GnuTLS: Failed to read client cert/key in DER format (%s) - try in PEM format",
563e5b75505Sopenharmony_ci				   gnutls_strerror(ret));
564e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x03010b
565e5b75505Sopenharmony_ci			ret = gnutls_certificate_set_x509_key_file2(
566e5b75505Sopenharmony_ci				conn->xcred, params->client_cert,
567e5b75505Sopenharmony_ci				params->private_key, GNUTLS_X509_FMT_PEM,
568e5b75505Sopenharmony_ci				params->private_key_passwd, 0);
569e5b75505Sopenharmony_ci#else
570e5b75505Sopenharmony_ci			ret = gnutls_certificate_set_x509_key_file(
571e5b75505Sopenharmony_ci				conn->xcred, params->client_cert,
572e5b75505Sopenharmony_ci				params->private_key, GNUTLS_X509_FMT_PEM);
573e5b75505Sopenharmony_ci#endif
574e5b75505Sopenharmony_ci			if (ret < 0) {
575e5b75505Sopenharmony_ci				wpa_printf(MSG_DEBUG, "Failed to read client "
576e5b75505Sopenharmony_ci					   "cert/key in PEM format: %s",
577e5b75505Sopenharmony_ci					   gnutls_strerror(ret));
578e5b75505Sopenharmony_ci				return ret;
579e5b75505Sopenharmony_ci			}
580e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
581e5b75505Sopenharmony_ci				   "GnuTLS: Successfully read client cert/key in PEM format");
582e5b75505Sopenharmony_ci		} else {
583e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
584e5b75505Sopenharmony_ci				   "GnuTLS: Successfully read client cert/key in DER format");
585e5b75505Sopenharmony_ci		}
586e5b75505Sopenharmony_ci	} else if (params->private_key) {
587e5b75505Sopenharmony_ci		int pkcs12_ok = 0;
588e5b75505Sopenharmony_ci#ifdef PKCS12_FUNCS
589e5b75505Sopenharmony_ci		/* Try to load in PKCS#12 format */
590e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
591e5b75505Sopenharmony_ci			   "GnuTLS: Try to parse client cert/key '%s'in PKCS#12 DER format",
592e5b75505Sopenharmony_ci			   params->private_key);
593e5b75505Sopenharmony_ci		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
594e5b75505Sopenharmony_ci			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
595e5b75505Sopenharmony_ci			params->private_key_passwd);
596e5b75505Sopenharmony_ci		if (ret != 0) {
597e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
598e5b75505Sopenharmony_ci				   "PKCS#12 format: %s", gnutls_strerror(ret));
599e5b75505Sopenharmony_ci			return -1;
600e5b75505Sopenharmony_ci		} else
601e5b75505Sopenharmony_ci			pkcs12_ok = 1;
602e5b75505Sopenharmony_ci#endif /* PKCS12_FUNCS */
603e5b75505Sopenharmony_ci
604e5b75505Sopenharmony_ci		if (!pkcs12_ok) {
605e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
606e5b75505Sopenharmony_ci				   "included");
607e5b75505Sopenharmony_ci			return -1;
608e5b75505Sopenharmony_ci		}
609e5b75505Sopenharmony_ci	} else if (params->client_cert_blob && params->private_key_blob) {
610e5b75505Sopenharmony_ci		gnutls_datum_t cert, key;
611e5b75505Sopenharmony_ci
612e5b75505Sopenharmony_ci		cert.data = (unsigned char *) params->client_cert_blob;
613e5b75505Sopenharmony_ci		cert.size = params->client_cert_blob_len;
614e5b75505Sopenharmony_ci		key.data = (unsigned char *) params->private_key_blob;
615e5b75505Sopenharmony_ci		key.size = params->private_key_blob_len;
616e5b75505Sopenharmony_ci
617e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x03010b
618e5b75505Sopenharmony_ci		ret = gnutls_certificate_set_x509_key_mem2(
619e5b75505Sopenharmony_ci			conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER,
620e5b75505Sopenharmony_ci			params->private_key_passwd, 0);
621e5b75505Sopenharmony_ci#else
622e5b75505Sopenharmony_ci		/* private_key_passwd not (easily) supported here */
623e5b75505Sopenharmony_ci		ret = gnutls_certificate_set_x509_key_mem(
624e5b75505Sopenharmony_ci			conn->xcred, &cert, &key, GNUTLS_X509_FMT_DER);
625e5b75505Sopenharmony_ci#endif
626e5b75505Sopenharmony_ci		if (ret < 0) {
627e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
628e5b75505Sopenharmony_ci				   "in DER format: %s", gnutls_strerror(ret));
629e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x03010b
630e5b75505Sopenharmony_ci			ret = gnutls_certificate_set_x509_key_mem2(
631e5b75505Sopenharmony_ci				conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM,
632e5b75505Sopenharmony_ci				params->private_key_passwd, 0);
633e5b75505Sopenharmony_ci#else
634e5b75505Sopenharmony_ci			/* private_key_passwd not (easily) supported here */
635e5b75505Sopenharmony_ci			ret = gnutls_certificate_set_x509_key_mem(
636e5b75505Sopenharmony_ci				conn->xcred, &cert, &key, GNUTLS_X509_FMT_PEM);
637e5b75505Sopenharmony_ci#endif
638e5b75505Sopenharmony_ci			if (ret < 0) {
639e5b75505Sopenharmony_ci				wpa_printf(MSG_DEBUG, "Failed to read client "
640e5b75505Sopenharmony_ci					   "cert/key in PEM format: %s",
641e5b75505Sopenharmony_ci					   gnutls_strerror(ret));
642e5b75505Sopenharmony_ci				return ret;
643e5b75505Sopenharmony_ci			}
644e5b75505Sopenharmony_ci		}
645e5b75505Sopenharmony_ci	} else if (params->private_key_blob) {
646e5b75505Sopenharmony_ci#ifdef PKCS12_FUNCS
647e5b75505Sopenharmony_ci		gnutls_datum_t key;
648e5b75505Sopenharmony_ci
649e5b75505Sopenharmony_ci		key.data = (unsigned char *) params->private_key_blob;
650e5b75505Sopenharmony_ci		key.size = params->private_key_blob_len;
651e5b75505Sopenharmony_ci
652e5b75505Sopenharmony_ci		/* Try to load in PKCS#12 format */
653e5b75505Sopenharmony_ci		ret = gnutls_certificate_set_x509_simple_pkcs12_mem(
654e5b75505Sopenharmony_ci			conn->xcred, &key, GNUTLS_X509_FMT_DER,
655e5b75505Sopenharmony_ci			params->private_key_passwd);
656e5b75505Sopenharmony_ci		if (ret != 0) {
657e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
658e5b75505Sopenharmony_ci				   "PKCS#12 format: %s", gnutls_strerror(ret));
659e5b75505Sopenharmony_ci			return -1;
660e5b75505Sopenharmony_ci		}
661e5b75505Sopenharmony_ci#else /* PKCS12_FUNCS */
662e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not included");
663e5b75505Sopenharmony_ci		return -1;
664e5b75505Sopenharmony_ci#endif /* PKCS12_FUNCS */
665e5b75505Sopenharmony_ci	}
666e5b75505Sopenharmony_ci
667e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x030103
668e5b75505Sopenharmony_ci	if (params->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)) {
669e5b75505Sopenharmony_ci		ret = gnutls_ocsp_status_request_enable_client(conn->session,
670e5b75505Sopenharmony_ci							       NULL, 0, NULL);
671e5b75505Sopenharmony_ci		if (ret != GNUTLS_E_SUCCESS) {
672e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO,
673e5b75505Sopenharmony_ci				   "GnuTLS: Failed to enable OCSP client");
674e5b75505Sopenharmony_ci			return -1;
675e5b75505Sopenharmony_ci		}
676e5b75505Sopenharmony_ci	}
677e5b75505Sopenharmony_ci#else /* 3.1.3 */
678e5b75505Sopenharmony_ci	if (params->flags & TLS_CONN_REQUIRE_OCSP) {
679e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
680e5b75505Sopenharmony_ci			   "GnuTLS: OCSP not supported by this version of GnuTLS");
681e5b75505Sopenharmony_ci		return -1;
682e5b75505Sopenharmony_ci	}
683e5b75505Sopenharmony_ci#endif /* 3.1.3 */
684e5b75505Sopenharmony_ci
685e5b75505Sopenharmony_ci	conn->params_set = 1;
686e5b75505Sopenharmony_ci
687e5b75505Sopenharmony_ci	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
688e5b75505Sopenharmony_ci				     conn->xcred);
689e5b75505Sopenharmony_ci	if (ret < 0) {
690e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
691e5b75505Sopenharmony_ci			   gnutls_strerror(ret));
692e5b75505Sopenharmony_ci	}
693e5b75505Sopenharmony_ci
694e5b75505Sopenharmony_ci	return ret;
695e5b75505Sopenharmony_ci}
696e5b75505Sopenharmony_ci
697e5b75505Sopenharmony_ci
698e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x030103
699e5b75505Sopenharmony_cistatic int server_ocsp_status_req(gnutls_session_t session, void *ptr,
700e5b75505Sopenharmony_ci				  gnutls_datum_t *resp)
701e5b75505Sopenharmony_ci{
702e5b75505Sopenharmony_ci	struct tls_global *global = ptr;
703e5b75505Sopenharmony_ci	char *cached;
704e5b75505Sopenharmony_ci	size_t len;
705e5b75505Sopenharmony_ci
706e5b75505Sopenharmony_ci	if (!global->ocsp_stapling_response) {
707e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
708e5b75505Sopenharmony_ci		return GNUTLS_E_NO_CERTIFICATE_STATUS;
709e5b75505Sopenharmony_ci	}
710e5b75505Sopenharmony_ci
711e5b75505Sopenharmony_ci	cached = os_readfile(global->ocsp_stapling_response, &len);
712e5b75505Sopenharmony_ci	if (!cached) {
713e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
714e5b75505Sopenharmony_ci			   "GnuTLS: OCSP status callback - could not read response file (%s)",
715e5b75505Sopenharmony_ci			   global->ocsp_stapling_response);
716e5b75505Sopenharmony_ci		return GNUTLS_E_NO_CERTIFICATE_STATUS;
717e5b75505Sopenharmony_ci	}
718e5b75505Sopenharmony_ci
719e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG,
720e5b75505Sopenharmony_ci		   "GnuTLS: OCSP status callback - send cached response");
721e5b75505Sopenharmony_ci	resp->data = gnutls_malloc(len);
722e5b75505Sopenharmony_ci	if (!resp->data) {
723e5b75505Sopenharmony_ci		os_free(resp);
724e5b75505Sopenharmony_ci		return GNUTLS_E_MEMORY_ERROR;
725e5b75505Sopenharmony_ci	}
726e5b75505Sopenharmony_ci
727e5b75505Sopenharmony_ci	os_memcpy(resp->data, cached, len);
728e5b75505Sopenharmony_ci	resp->size = len;
729e5b75505Sopenharmony_ci	os_free(cached);
730e5b75505Sopenharmony_ci
731e5b75505Sopenharmony_ci	return GNUTLS_E_SUCCESS;
732e5b75505Sopenharmony_ci}
733e5b75505Sopenharmony_ci#endif /* 3.1.3 */
734e5b75505Sopenharmony_ci
735e5b75505Sopenharmony_ci
736e5b75505Sopenharmony_ciint tls_global_set_params(void *tls_ctx,
737e5b75505Sopenharmony_ci			  const struct tls_connection_params *params)
738e5b75505Sopenharmony_ci{
739e5b75505Sopenharmony_ci	struct tls_global *global = tls_ctx;
740e5b75505Sopenharmony_ci	int ret;
741e5b75505Sopenharmony_ci
742e5b75505Sopenharmony_ci	if (params->check_cert_subject)
743e5b75505Sopenharmony_ci		return -1; /* not yet supported */
744e5b75505Sopenharmony_ci
745e5b75505Sopenharmony_ci	/* Currently, global parameters are only set when running in server
746e5b75505Sopenharmony_ci	 * mode. */
747e5b75505Sopenharmony_ci	global->server = 1;
748e5b75505Sopenharmony_ci
749e5b75505Sopenharmony_ci	if (global->params_set) {
750e5b75505Sopenharmony_ci		gnutls_certificate_free_credentials(global->xcred);
751e5b75505Sopenharmony_ci		global->params_set = 0;
752e5b75505Sopenharmony_ci	}
753e5b75505Sopenharmony_ci
754e5b75505Sopenharmony_ci	ret = gnutls_certificate_allocate_credentials(&global->xcred);
755e5b75505Sopenharmony_ci	if (ret) {
756e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
757e5b75505Sopenharmony_ci			   "%s", gnutls_strerror(ret));
758e5b75505Sopenharmony_ci		return -1;
759e5b75505Sopenharmony_ci	}
760e5b75505Sopenharmony_ci
761e5b75505Sopenharmony_ci	if (params->ca_cert) {
762e5b75505Sopenharmony_ci		ret = gnutls_certificate_set_x509_trust_file(
763e5b75505Sopenharmony_ci			global->xcred, params->ca_cert, GNUTLS_X509_FMT_DER);
764e5b75505Sopenharmony_ci		if (ret < 0) {
765e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
766e5b75505Sopenharmony_ci				   "in DER format: %s", params->ca_cert,
767e5b75505Sopenharmony_ci				   gnutls_strerror(ret));
768e5b75505Sopenharmony_ci			ret = gnutls_certificate_set_x509_trust_file(
769e5b75505Sopenharmony_ci				global->xcred, params->ca_cert,
770e5b75505Sopenharmony_ci				GNUTLS_X509_FMT_PEM);
771e5b75505Sopenharmony_ci			if (ret < 0) {
772e5b75505Sopenharmony_ci				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
773e5b75505Sopenharmony_ci					   "'%s' in PEM format: %s",
774e5b75505Sopenharmony_ci					   params->ca_cert,
775e5b75505Sopenharmony_ci					   gnutls_strerror(ret));
776e5b75505Sopenharmony_ci				goto fail;
777e5b75505Sopenharmony_ci			}
778e5b75505Sopenharmony_ci		}
779e5b75505Sopenharmony_ci
780e5b75505Sopenharmony_ci		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
781e5b75505Sopenharmony_ci			gnutls_certificate_set_verify_flags(
782e5b75505Sopenharmony_ci				global->xcred,
783e5b75505Sopenharmony_ci				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
784e5b75505Sopenharmony_ci		}
785e5b75505Sopenharmony_ci
786e5b75505Sopenharmony_ci		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
787e5b75505Sopenharmony_ci			gnutls_certificate_set_verify_flags(
788e5b75505Sopenharmony_ci				global->xcred,
789e5b75505Sopenharmony_ci				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
790e5b75505Sopenharmony_ci		}
791e5b75505Sopenharmony_ci	}
792e5b75505Sopenharmony_ci
793e5b75505Sopenharmony_ci	if (params->client_cert && params->private_key) {
794e5b75505Sopenharmony_ci		/* TODO: private_key_passwd? */
795e5b75505Sopenharmony_ci		ret = gnutls_certificate_set_x509_key_file(
796e5b75505Sopenharmony_ci			global->xcred, params->client_cert,
797e5b75505Sopenharmony_ci			params->private_key, GNUTLS_X509_FMT_DER);
798e5b75505Sopenharmony_ci		if (ret < 0) {
799e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
800e5b75505Sopenharmony_ci				   "in DER format: %s", gnutls_strerror(ret));
801e5b75505Sopenharmony_ci			ret = gnutls_certificate_set_x509_key_file(
802e5b75505Sopenharmony_ci				global->xcred, params->client_cert,
803e5b75505Sopenharmony_ci				params->private_key, GNUTLS_X509_FMT_PEM);
804e5b75505Sopenharmony_ci			if (ret < 0) {
805e5b75505Sopenharmony_ci				wpa_printf(MSG_DEBUG, "Failed to read client "
806e5b75505Sopenharmony_ci					   "cert/key in PEM format: %s",
807e5b75505Sopenharmony_ci					   gnutls_strerror(ret));
808e5b75505Sopenharmony_ci				goto fail;
809e5b75505Sopenharmony_ci			}
810e5b75505Sopenharmony_ci		}
811e5b75505Sopenharmony_ci	} else if (params->private_key) {
812e5b75505Sopenharmony_ci		int pkcs12_ok = 0;
813e5b75505Sopenharmony_ci#ifdef PKCS12_FUNCS
814e5b75505Sopenharmony_ci		/* Try to load in PKCS#12 format */
815e5b75505Sopenharmony_ci		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
816e5b75505Sopenharmony_ci			global->xcred, params->private_key,
817e5b75505Sopenharmony_ci			GNUTLS_X509_FMT_DER, params->private_key_passwd);
818e5b75505Sopenharmony_ci		if (ret != 0) {
819e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
820e5b75505Sopenharmony_ci				   "PKCS#12 format: %s", gnutls_strerror(ret));
821e5b75505Sopenharmony_ci			goto fail;
822e5b75505Sopenharmony_ci		} else
823e5b75505Sopenharmony_ci			pkcs12_ok = 1;
824e5b75505Sopenharmony_ci#endif /* PKCS12_FUNCS */
825e5b75505Sopenharmony_ci
826e5b75505Sopenharmony_ci		if (!pkcs12_ok) {
827e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
828e5b75505Sopenharmony_ci				   "included");
829e5b75505Sopenharmony_ci			goto fail;
830e5b75505Sopenharmony_ci		}
831e5b75505Sopenharmony_ci	}
832e5b75505Sopenharmony_ci
833e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x030103
834e5b75505Sopenharmony_ci	os_free(global->ocsp_stapling_response);
835e5b75505Sopenharmony_ci	if (params->ocsp_stapling_response)
836e5b75505Sopenharmony_ci		global->ocsp_stapling_response =
837e5b75505Sopenharmony_ci			os_strdup(params->ocsp_stapling_response);
838e5b75505Sopenharmony_ci	else
839e5b75505Sopenharmony_ci		global->ocsp_stapling_response = NULL;
840e5b75505Sopenharmony_ci	gnutls_certificate_set_ocsp_status_request_function(
841e5b75505Sopenharmony_ci		global->xcred, server_ocsp_status_req, global);
842e5b75505Sopenharmony_ci#endif /* 3.1.3 */
843e5b75505Sopenharmony_ci
844e5b75505Sopenharmony_ci	global->params_set = 1;
845e5b75505Sopenharmony_ci
846e5b75505Sopenharmony_ci	return 0;
847e5b75505Sopenharmony_ci
848e5b75505Sopenharmony_cifail:
849e5b75505Sopenharmony_ci	gnutls_certificate_free_credentials(global->xcred);
850e5b75505Sopenharmony_ci	return -1;
851e5b75505Sopenharmony_ci}
852e5b75505Sopenharmony_ci
853e5b75505Sopenharmony_ci
854e5b75505Sopenharmony_ciint tls_global_set_verify(void *ssl_ctx, int check_crl, int strict)
855e5b75505Sopenharmony_ci{
856e5b75505Sopenharmony_ci	/* TODO */
857e5b75505Sopenharmony_ci	return 0;
858e5b75505Sopenharmony_ci}
859e5b75505Sopenharmony_ci
860e5b75505Sopenharmony_ci
861e5b75505Sopenharmony_ciint tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
862e5b75505Sopenharmony_ci			      int verify_peer, unsigned int flags,
863e5b75505Sopenharmony_ci			      const u8 *session_ctx, size_t session_ctx_len)
864e5b75505Sopenharmony_ci{
865e5b75505Sopenharmony_ci	if (conn == NULL || conn->session == NULL)
866e5b75505Sopenharmony_ci		return -1;
867e5b75505Sopenharmony_ci
868e5b75505Sopenharmony_ci	conn->verify_peer = verify_peer;
869e5b75505Sopenharmony_ci	gnutls_certificate_server_set_request(conn->session,
870e5b75505Sopenharmony_ci					      verify_peer ? GNUTLS_CERT_REQUIRE
871e5b75505Sopenharmony_ci					      : GNUTLS_CERT_REQUEST);
872e5b75505Sopenharmony_ci
873e5b75505Sopenharmony_ci	return 0;
874e5b75505Sopenharmony_ci}
875e5b75505Sopenharmony_ci
876e5b75505Sopenharmony_ci
877e5b75505Sopenharmony_ciint tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
878e5b75505Sopenharmony_ci			    struct tls_random *keys)
879e5b75505Sopenharmony_ci{
880e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x030012
881e5b75505Sopenharmony_ci	gnutls_datum_t client, server;
882e5b75505Sopenharmony_ci
883e5b75505Sopenharmony_ci	if (conn == NULL || conn->session == NULL || keys == NULL)
884e5b75505Sopenharmony_ci		return -1;
885e5b75505Sopenharmony_ci
886e5b75505Sopenharmony_ci	os_memset(keys, 0, sizeof(*keys));
887e5b75505Sopenharmony_ci	gnutls_session_get_random(conn->session, &client, &server);
888e5b75505Sopenharmony_ci	keys->client_random = client.data;
889e5b75505Sopenharmony_ci	keys->server_random = server.data;
890e5b75505Sopenharmony_ci	keys->client_random_len = client.size;
891e5b75505Sopenharmony_ci	keys->server_random_len = client.size;
892e5b75505Sopenharmony_ci
893e5b75505Sopenharmony_ci	return 0;
894e5b75505Sopenharmony_ci#else /* 3.0.18 */
895e5b75505Sopenharmony_ci	return -1;
896e5b75505Sopenharmony_ci#endif /* 3.0.18 */
897e5b75505Sopenharmony_ci}
898e5b75505Sopenharmony_ci
899e5b75505Sopenharmony_ci
900e5b75505Sopenharmony_ciint tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
901e5b75505Sopenharmony_ci			      const char *label, const u8 *context,
902e5b75505Sopenharmony_ci			      size_t context_len, u8 *out, size_t out_len)
903e5b75505Sopenharmony_ci{
904e5b75505Sopenharmony_ci	if (conn == NULL || conn->session == NULL)
905e5b75505Sopenharmony_ci		return -1;
906e5b75505Sopenharmony_ci
907e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x030404
908e5b75505Sopenharmony_ci	return gnutls_prf_rfc5705(conn->session, os_strlen(label), label,
909e5b75505Sopenharmony_ci				  context_len, (const char *) context,
910e5b75505Sopenharmony_ci				  out_len, (char *) out);
911e5b75505Sopenharmony_ci#else /* 3.4.4 */
912e5b75505Sopenharmony_ci	if (context)
913e5b75505Sopenharmony_ci		return -1;
914e5b75505Sopenharmony_ci	return gnutls_prf(conn->session, os_strlen(label), label,
915e5b75505Sopenharmony_ci			  0 /* client_random first */, 0, NULL, out_len,
916e5b75505Sopenharmony_ci			  (char *) out);
917e5b75505Sopenharmony_ci#endif /* 3.4.4 */
918e5b75505Sopenharmony_ci}
919e5b75505Sopenharmony_ci
920e5b75505Sopenharmony_ci
921e5b75505Sopenharmony_ciint tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
922e5b75505Sopenharmony_ci				    u8 *out, size_t out_len)
923e5b75505Sopenharmony_ci{
924e5b75505Sopenharmony_ci	return -1;
925e5b75505Sopenharmony_ci}
926e5b75505Sopenharmony_ci
927e5b75505Sopenharmony_ci
928e5b75505Sopenharmony_cistatic void gnutls_tls_fail_event(struct tls_connection *conn,
929e5b75505Sopenharmony_ci				  const gnutls_datum_t *cert, int depth,
930e5b75505Sopenharmony_ci				  const char *subject, const char *err_str,
931e5b75505Sopenharmony_ci				  enum tls_fail_reason reason)
932e5b75505Sopenharmony_ci{
933e5b75505Sopenharmony_ci	union tls_event_data ev;
934e5b75505Sopenharmony_ci	struct tls_global *global = conn->global;
935e5b75505Sopenharmony_ci	struct wpabuf *cert_buf = NULL;
936e5b75505Sopenharmony_ci
937e5b75505Sopenharmony_ci	if (global->event_cb == NULL)
938e5b75505Sopenharmony_ci		return;
939e5b75505Sopenharmony_ci
940e5b75505Sopenharmony_ci	os_memset(&ev, 0, sizeof(ev));
941e5b75505Sopenharmony_ci	ev.cert_fail.depth = depth;
942e5b75505Sopenharmony_ci	ev.cert_fail.subject = subject ? subject : "";
943e5b75505Sopenharmony_ci	ev.cert_fail.reason = reason;
944e5b75505Sopenharmony_ci	ev.cert_fail.reason_txt = err_str;
945e5b75505Sopenharmony_ci	if (cert) {
946e5b75505Sopenharmony_ci		cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
947e5b75505Sopenharmony_ci		ev.cert_fail.cert = cert_buf;
948e5b75505Sopenharmony_ci	}
949e5b75505Sopenharmony_ci	global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
950e5b75505Sopenharmony_ci	wpabuf_free(cert_buf);
951e5b75505Sopenharmony_ci}
952e5b75505Sopenharmony_ci
953e5b75505Sopenharmony_ci
954e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER < 0x030300
955e5b75505Sopenharmony_cistatic int server_eku_purpose(gnutls_x509_crt_t cert)
956e5b75505Sopenharmony_ci{
957e5b75505Sopenharmony_ci	unsigned int i;
958e5b75505Sopenharmony_ci
959e5b75505Sopenharmony_ci	for (i = 0; ; i++) {
960e5b75505Sopenharmony_ci		char oid[128];
961e5b75505Sopenharmony_ci		size_t oid_size = sizeof(oid);
962e5b75505Sopenharmony_ci		int res;
963e5b75505Sopenharmony_ci
964e5b75505Sopenharmony_ci		res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid,
965e5b75505Sopenharmony_ci							  &oid_size, NULL);
966e5b75505Sopenharmony_ci		if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
967e5b75505Sopenharmony_ci			if (i == 0) {
968e5b75505Sopenharmony_ci				/* No EKU - assume any use allowed */
969e5b75505Sopenharmony_ci				return 1;
970e5b75505Sopenharmony_ci			}
971e5b75505Sopenharmony_ci			break;
972e5b75505Sopenharmony_ci		}
973e5b75505Sopenharmony_ci
974e5b75505Sopenharmony_ci		if (res < 0) {
975e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU");
976e5b75505Sopenharmony_ci			return 0;
977e5b75505Sopenharmony_ci		}
978e5b75505Sopenharmony_ci
979e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid);
980e5b75505Sopenharmony_ci		if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 ||
981e5b75505Sopenharmony_ci		    os_strcmp(oid, GNUTLS_KP_ANY) == 0)
982e5b75505Sopenharmony_ci			return 1;
983e5b75505Sopenharmony_ci	}
984e5b75505Sopenharmony_ci
985e5b75505Sopenharmony_ci	return 0;
986e5b75505Sopenharmony_ci}
987e5b75505Sopenharmony_ci#endif /* < 3.3.0 */
988e5b75505Sopenharmony_ci
989e5b75505Sopenharmony_ci
990e5b75505Sopenharmony_cistatic int check_ocsp(struct tls_connection *conn, gnutls_session_t session,
991e5b75505Sopenharmony_ci		      gnutls_alert_description_t *err)
992e5b75505Sopenharmony_ci{
993e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x030103
994e5b75505Sopenharmony_ci	gnutls_datum_t response, buf;
995e5b75505Sopenharmony_ci	gnutls_ocsp_resp_t resp;
996e5b75505Sopenharmony_ci	unsigned int cert_status;
997e5b75505Sopenharmony_ci	int res;
998e5b75505Sopenharmony_ci
999e5b75505Sopenharmony_ci	if (!(conn->flags & (TLS_CONN_REQUEST_OCSP | TLS_CONN_REQUIRE_OCSP)))
1000e5b75505Sopenharmony_ci		return 0;
1001e5b75505Sopenharmony_ci
1002e5b75505Sopenharmony_ci	if (!gnutls_ocsp_status_request_is_checked(session, 0)) {
1003e5b75505Sopenharmony_ci		if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
1004e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO,
1005e5b75505Sopenharmony_ci				   "GnuTLS: No valid OCSP response received");
1006e5b75505Sopenharmony_ci			goto ocsp_error;
1007e5b75505Sopenharmony_ci		}
1008e5b75505Sopenharmony_ci
1009e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1010e5b75505Sopenharmony_ci			   "GnuTLS: Valid OCSP response was not received - continue since OCSP was not required");
1011e5b75505Sopenharmony_ci		return 0;
1012e5b75505Sopenharmony_ci	}
1013e5b75505Sopenharmony_ci
1014e5b75505Sopenharmony_ci	/*
1015e5b75505Sopenharmony_ci	 * GnuTLS has already verified the OCSP response in
1016e5b75505Sopenharmony_ci	 * check_ocsp_response() and rejected handshake if the certificate was
1017e5b75505Sopenharmony_ci	 * found to be revoked. However, if the response indicates that the
1018e5b75505Sopenharmony_ci	 * status is unknown, handshake continues and reaches here. We need to
1019e5b75505Sopenharmony_ci	 * re-import the OCSP response to check for unknown certificate status,
1020e5b75505Sopenharmony_ci	 * but we do not need to repeat gnutls_ocsp_resp_check_crt() and
1021e5b75505Sopenharmony_ci	 * gnutls_ocsp_resp_verify_direct() calls.
1022e5b75505Sopenharmony_ci	 */
1023e5b75505Sopenharmony_ci
1024e5b75505Sopenharmony_ci	res = gnutls_ocsp_status_request_get(session, &response);
1025e5b75505Sopenharmony_ci	if (res != GNUTLS_E_SUCCESS) {
1026e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
1027e5b75505Sopenharmony_ci			   "GnuTLS: OCSP response was received, but it was not valid");
1028e5b75505Sopenharmony_ci		goto ocsp_error;
1029e5b75505Sopenharmony_ci	}
1030e5b75505Sopenharmony_ci
1031e5b75505Sopenharmony_ci	if (gnutls_ocsp_resp_init(&resp) != GNUTLS_E_SUCCESS)
1032e5b75505Sopenharmony_ci		goto ocsp_error;
1033e5b75505Sopenharmony_ci
1034e5b75505Sopenharmony_ci	res = gnutls_ocsp_resp_import(resp, &response);
1035e5b75505Sopenharmony_ci	if (res != GNUTLS_E_SUCCESS) {
1036e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
1037e5b75505Sopenharmony_ci			   "GnuTLS: Could not parse received OCSP response: %s",
1038e5b75505Sopenharmony_ci			   gnutls_strerror(res));
1039e5b75505Sopenharmony_ci		gnutls_ocsp_resp_deinit(resp);
1040e5b75505Sopenharmony_ci		goto ocsp_error;
1041e5b75505Sopenharmony_ci	}
1042e5b75505Sopenharmony_ci
1043e5b75505Sopenharmony_ci	res = gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL, &buf);
1044e5b75505Sopenharmony_ci	if (res == GNUTLS_E_SUCCESS) {
1045e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "GnuTLS: %s", buf.data);
1046e5b75505Sopenharmony_ci		gnutls_free(buf.data);
1047e5b75505Sopenharmony_ci	}
1048e5b75505Sopenharmony_ci
1049e5b75505Sopenharmony_ci	res = gnutls_ocsp_resp_get_single(resp, 0, NULL, NULL, NULL,
1050e5b75505Sopenharmony_ci					  NULL, &cert_status, NULL,
1051e5b75505Sopenharmony_ci					  NULL, NULL, NULL);
1052e5b75505Sopenharmony_ci	gnutls_ocsp_resp_deinit(resp);
1053e5b75505Sopenharmony_ci	if (res != GNUTLS_E_SUCCESS) {
1054e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO,
1055e5b75505Sopenharmony_ci			   "GnuTLS: Failed to extract OCSP information: %s",
1056e5b75505Sopenharmony_ci			   gnutls_strerror(res));
1057e5b75505Sopenharmony_ci		goto ocsp_error;
1058e5b75505Sopenharmony_ci	}
1059e5b75505Sopenharmony_ci
1060e5b75505Sopenharmony_ci	if (cert_status == GNUTLS_OCSP_CERT_GOOD) {
1061e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "GnuTLS: OCSP cert status: good");
1062e5b75505Sopenharmony_ci	} else if (cert_status == GNUTLS_OCSP_CERT_REVOKED) {
1063e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1064e5b75505Sopenharmony_ci			   "GnuTLS: OCSP cert status: revoked");
1065e5b75505Sopenharmony_ci		goto ocsp_error;
1066e5b75505Sopenharmony_ci	} else {
1067e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1068e5b75505Sopenharmony_ci			   "GnuTLS: OCSP cert status: unknown");
1069e5b75505Sopenharmony_ci		if (conn->flags & TLS_CONN_REQUIRE_OCSP)
1070e5b75505Sopenharmony_ci			goto ocsp_error;
1071e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1072e5b75505Sopenharmony_ci			   "GnuTLS: OCSP was not required, so allow connection to continue");
1073e5b75505Sopenharmony_ci	}
1074e5b75505Sopenharmony_ci
1075e5b75505Sopenharmony_ci	return 0;
1076e5b75505Sopenharmony_ci
1077e5b75505Sopenharmony_ciocsp_error:
1078e5b75505Sopenharmony_ci	gnutls_tls_fail_event(conn, NULL, 0, NULL,
1079e5b75505Sopenharmony_ci			      "bad certificate status response",
1080e5b75505Sopenharmony_ci			      TLS_FAIL_REVOKED);
1081e5b75505Sopenharmony_ci	*err = GNUTLS_A_CERTIFICATE_REVOKED;
1082e5b75505Sopenharmony_ci	return -1;
1083e5b75505Sopenharmony_ci#else /* GnuTLS 3.1.3 or newer */
1084e5b75505Sopenharmony_ci	return 0;
1085e5b75505Sopenharmony_ci#endif /* GnuTLS 3.1.3 or newer */
1086e5b75505Sopenharmony_ci}
1087e5b75505Sopenharmony_ci
1088e5b75505Sopenharmony_ci
1089e5b75505Sopenharmony_cistatic int tls_match_suffix_helper(gnutls_x509_crt_t cert, const char *match,
1090e5b75505Sopenharmony_ci				   int full)
1091e5b75505Sopenharmony_ci{
1092e5b75505Sopenharmony_ci	int res = -1;
1093e5b75505Sopenharmony_ci
1094e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x030300
1095e5b75505Sopenharmony_ci	if (full)
1096e5b75505Sopenharmony_ci		res = gnutls_x509_crt_check_hostname2(
1097e5b75505Sopenharmony_ci			cert, match,
1098e5b75505Sopenharmony_ci			GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS);
1099e5b75505Sopenharmony_ci#endif /* >= 3.3.0 */
1100e5b75505Sopenharmony_ci	if (res == -1)
1101e5b75505Sopenharmony_ci		res = gnutls_x509_crt_check_hostname(cert, match);
1102e5b75505Sopenharmony_ci
1103e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s --> res=%d",
1104e5b75505Sopenharmony_ci		   full ? "": "suffix ", match, res);
1105e5b75505Sopenharmony_ci	return res;
1106e5b75505Sopenharmony_ci}
1107e5b75505Sopenharmony_ci
1108e5b75505Sopenharmony_ci
1109e5b75505Sopenharmony_cistatic int tls_match_suffix(gnutls_x509_crt_t cert, const char *match,
1110e5b75505Sopenharmony_ci			    int full)
1111e5b75505Sopenharmony_ci{
1112e5b75505Sopenharmony_ci	char *values, *token, *context = NULL;
1113e5b75505Sopenharmony_ci	int ret = 0;
1114e5b75505Sopenharmony_ci
1115e5b75505Sopenharmony_ci	if (!os_strchr(match, ';'))
1116e5b75505Sopenharmony_ci		return tls_match_suffix_helper(cert, match, full);
1117e5b75505Sopenharmony_ci
1118e5b75505Sopenharmony_ci	values = os_strdup(match);
1119e5b75505Sopenharmony_ci	if (!values)
1120e5b75505Sopenharmony_ci		return 0;
1121e5b75505Sopenharmony_ci
1122e5b75505Sopenharmony_ci	/* Process each match alternative separately until a match is found */
1123e5b75505Sopenharmony_ci	while ((token = str_token(values, ";", &context))) {
1124e5b75505Sopenharmony_ci		if (tls_match_suffix_helper(cert, token, full)) {
1125e5b75505Sopenharmony_ci			ret = 1;
1126e5b75505Sopenharmony_ci			break;
1127e5b75505Sopenharmony_ci		}
1128e5b75505Sopenharmony_ci	}
1129e5b75505Sopenharmony_ci
1130e5b75505Sopenharmony_ci	os_free(values);
1131e5b75505Sopenharmony_ci	return ret;
1132e5b75505Sopenharmony_ci}
1133e5b75505Sopenharmony_ci
1134e5b75505Sopenharmony_ci
1135e5b75505Sopenharmony_cistatic int tls_connection_verify_peer(gnutls_session_t session)
1136e5b75505Sopenharmony_ci{
1137e5b75505Sopenharmony_ci	struct tls_connection *conn;
1138e5b75505Sopenharmony_ci	unsigned int status, num_certs, i;
1139e5b75505Sopenharmony_ci	struct os_time now;
1140e5b75505Sopenharmony_ci	const gnutls_datum_t *certs;
1141e5b75505Sopenharmony_ci	gnutls_x509_crt_t cert;
1142e5b75505Sopenharmony_ci	gnutls_alert_description_t err;
1143e5b75505Sopenharmony_ci	int res;
1144e5b75505Sopenharmony_ci
1145e5b75505Sopenharmony_ci	conn = gnutls_session_get_ptr(session);
1146e5b75505Sopenharmony_ci	if (!conn->verify_peer) {
1147e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG,
1148e5b75505Sopenharmony_ci			   "GnuTLS: No peer certificate verification enabled");
1149e5b75505Sopenharmony_ci		return 0;
1150e5b75505Sopenharmony_ci	}
1151e5b75505Sopenharmony_ci
1152e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate");
1153e5b75505Sopenharmony_ci
1154e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x030300
1155e5b75505Sopenharmony_ci	{
1156e5b75505Sopenharmony_ci		gnutls_typed_vdata_st data[1];
1157e5b75505Sopenharmony_ci		unsigned int elements = 0;
1158e5b75505Sopenharmony_ci
1159e5b75505Sopenharmony_ci		os_memset(data, 0, sizeof(data));
1160e5b75505Sopenharmony_ci		if (!conn->global->server) {
1161e5b75505Sopenharmony_ci			data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID;
1162e5b75505Sopenharmony_ci			data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER;
1163e5b75505Sopenharmony_ci			elements++;
1164e5b75505Sopenharmony_ci		}
1165e5b75505Sopenharmony_ci		res = gnutls_certificate_verify_peers(session, data, 1,
1166e5b75505Sopenharmony_ci						      &status);
1167e5b75505Sopenharmony_ci	}
1168e5b75505Sopenharmony_ci#else /* < 3.3.0 */
1169e5b75505Sopenharmony_ci	res = gnutls_certificate_verify_peers2(session, &status);
1170e5b75505Sopenharmony_ci#endif
1171e5b75505Sopenharmony_ci	if (res < 0) {
1172e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
1173e5b75505Sopenharmony_ci			   "certificate chain");
1174e5b75505Sopenharmony_ci		err = GNUTLS_A_INTERNAL_ERROR;
1175e5b75505Sopenharmony_ci		goto out;
1176e5b75505Sopenharmony_ci	}
1177e5b75505Sopenharmony_ci
1178e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x030104
1179e5b75505Sopenharmony_ci	{
1180e5b75505Sopenharmony_ci		gnutls_datum_t info;
1181e5b75505Sopenharmony_ci		int ret, type;
1182e5b75505Sopenharmony_ci
1183e5b75505Sopenharmony_ci		type = gnutls_certificate_type_get(session);
1184e5b75505Sopenharmony_ci		ret = gnutls_certificate_verification_status_print(status, type,
1185e5b75505Sopenharmony_ci								   &info, 0);
1186e5b75505Sopenharmony_ci		if (ret < 0) {
1187e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG,
1188e5b75505Sopenharmony_ci				   "GnuTLS: Failed to print verification status");
1189e5b75505Sopenharmony_ci			err = GNUTLS_A_INTERNAL_ERROR;
1190e5b75505Sopenharmony_ci			goto out;
1191e5b75505Sopenharmony_ci		}
1192e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "GnuTLS: %s", info.data);
1193e5b75505Sopenharmony_ci		gnutls_free(info.data);
1194e5b75505Sopenharmony_ci	}
1195e5b75505Sopenharmony_ci#endif /* GnuTLS 3.1.4 or newer */
1196e5b75505Sopenharmony_ci
1197e5b75505Sopenharmony_ci	certs = gnutls_certificate_get_peers(session, &num_certs);
1198e5b75505Sopenharmony_ci	if (certs == NULL || num_certs == 0) {
1199e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "TLS: No peer certificate chain received");
1200e5b75505Sopenharmony_ci		err = GNUTLS_A_UNKNOWN_CA;
1201e5b75505Sopenharmony_ci		goto out;
1202e5b75505Sopenharmony_ci	}
1203e5b75505Sopenharmony_ci
1204e5b75505Sopenharmony_ci	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
1205e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
1206e5b75505Sopenharmony_ci		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
1207e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
1208e5b75505Sopenharmony_ci				   "algorithm");
1209e5b75505Sopenharmony_ci			gnutls_tls_fail_event(conn, NULL, 0, NULL,
1210e5b75505Sopenharmony_ci					      "certificate uses insecure algorithm",
1211e5b75505Sopenharmony_ci					      TLS_FAIL_BAD_CERTIFICATE);
1212e5b75505Sopenharmony_ci			err = GNUTLS_A_INSUFFICIENT_SECURITY;
1213e5b75505Sopenharmony_ci			goto out;
1214e5b75505Sopenharmony_ci		}
1215e5b75505Sopenharmony_ci		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
1216e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
1217e5b75505Sopenharmony_ci				   "activated");
1218e5b75505Sopenharmony_ci			gnutls_tls_fail_event(conn, NULL, 0, NULL,
1219e5b75505Sopenharmony_ci					      "certificate not yet valid",
1220e5b75505Sopenharmony_ci					      TLS_FAIL_NOT_YET_VALID);
1221e5b75505Sopenharmony_ci			err = GNUTLS_A_CERTIFICATE_EXPIRED;
1222e5b75505Sopenharmony_ci			goto out;
1223e5b75505Sopenharmony_ci		}
1224e5b75505Sopenharmony_ci		if (status & GNUTLS_CERT_EXPIRED) {
1225e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "TLS: Certificate expired");
1226e5b75505Sopenharmony_ci			gnutls_tls_fail_event(conn, NULL, 0, NULL,
1227e5b75505Sopenharmony_ci					      "certificate has expired",
1228e5b75505Sopenharmony_ci					      TLS_FAIL_EXPIRED);
1229e5b75505Sopenharmony_ci			err = GNUTLS_A_CERTIFICATE_EXPIRED;
1230e5b75505Sopenharmony_ci			goto out;
1231e5b75505Sopenharmony_ci		}
1232e5b75505Sopenharmony_ci		gnutls_tls_fail_event(conn, NULL, 0, NULL,
1233e5b75505Sopenharmony_ci				      "untrusted certificate",
1234e5b75505Sopenharmony_ci				      TLS_FAIL_UNTRUSTED);
1235e5b75505Sopenharmony_ci		err = GNUTLS_A_INTERNAL_ERROR;
1236e5b75505Sopenharmony_ci		goto out;
1237e5b75505Sopenharmony_ci	}
1238e5b75505Sopenharmony_ci
1239e5b75505Sopenharmony_ci	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
1240e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
1241e5b75505Sopenharmony_ci			   "known issuer");
1242e5b75505Sopenharmony_ci		gnutls_tls_fail_event(conn, NULL, 0, NULL, "signed not found",
1243e5b75505Sopenharmony_ci				      TLS_FAIL_UNTRUSTED);
1244e5b75505Sopenharmony_ci		err = GNUTLS_A_UNKNOWN_CA;
1245e5b75505Sopenharmony_ci		goto out;
1246e5b75505Sopenharmony_ci	}
1247e5b75505Sopenharmony_ci
1248e5b75505Sopenharmony_ci	if (status & GNUTLS_CERT_REVOKED) {
1249e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
1250e5b75505Sopenharmony_ci		gnutls_tls_fail_event(conn, NULL, 0, NULL,
1251e5b75505Sopenharmony_ci				      "certificate revoked",
1252e5b75505Sopenharmony_ci				      TLS_FAIL_REVOKED);
1253e5b75505Sopenharmony_ci		err = GNUTLS_A_CERTIFICATE_REVOKED;
1254e5b75505Sopenharmony_ci		goto out;
1255e5b75505Sopenharmony_ci	}
1256e5b75505Sopenharmony_ci
1257e5b75505Sopenharmony_ci	if (status != 0) {
1258e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "TLS: Unknown verification status: %d",
1259e5b75505Sopenharmony_ci			   status);
1260e5b75505Sopenharmony_ci		err = GNUTLS_A_INTERNAL_ERROR;
1261e5b75505Sopenharmony_ci		goto out;
1262e5b75505Sopenharmony_ci	}
1263e5b75505Sopenharmony_ci
1264e5b75505Sopenharmony_ci	if (check_ocsp(conn, session, &err))
1265e5b75505Sopenharmony_ci		goto out;
1266e5b75505Sopenharmony_ci
1267e5b75505Sopenharmony_ci	os_get_time(&now);
1268e5b75505Sopenharmony_ci
1269e5b75505Sopenharmony_ci	for (i = 0; i < num_certs; i++) {
1270e5b75505Sopenharmony_ci		char *buf;
1271e5b75505Sopenharmony_ci		size_t len;
1272e5b75505Sopenharmony_ci		if (gnutls_x509_crt_init(&cert) < 0) {
1273e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
1274e5b75505Sopenharmony_ci				   "failed");
1275e5b75505Sopenharmony_ci			err = GNUTLS_A_BAD_CERTIFICATE;
1276e5b75505Sopenharmony_ci			goto out;
1277e5b75505Sopenharmony_ci		}
1278e5b75505Sopenharmony_ci
1279e5b75505Sopenharmony_ci		if (gnutls_x509_crt_import(cert, &certs[i],
1280e5b75505Sopenharmony_ci					   GNUTLS_X509_FMT_DER) < 0) {
1281e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
1282e5b75505Sopenharmony_ci				   "certificate %d/%d", i + 1, num_certs);
1283e5b75505Sopenharmony_ci			gnutls_x509_crt_deinit(cert);
1284e5b75505Sopenharmony_ci			err = GNUTLS_A_BAD_CERTIFICATE;
1285e5b75505Sopenharmony_ci			goto out;
1286e5b75505Sopenharmony_ci		}
1287e5b75505Sopenharmony_ci
1288e5b75505Sopenharmony_ci		gnutls_x509_crt_get_dn(cert, NULL, &len);
1289e5b75505Sopenharmony_ci		len++;
1290e5b75505Sopenharmony_ci		buf = os_malloc(len + 1);
1291e5b75505Sopenharmony_ci		if (buf) {
1292e5b75505Sopenharmony_ci			buf[0] = buf[len] = '\0';
1293e5b75505Sopenharmony_ci			gnutls_x509_crt_get_dn(cert, buf, &len);
1294e5b75505Sopenharmony_ci		}
1295e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
1296e5b75505Sopenharmony_ci			   i + 1, num_certs, buf);
1297e5b75505Sopenharmony_ci
1298e5b75505Sopenharmony_ci		if (conn->global->event_cb) {
1299e5b75505Sopenharmony_ci			struct wpabuf *cert_buf = NULL;
1300e5b75505Sopenharmony_ci			union tls_event_data ev;
1301e5b75505Sopenharmony_ci#ifdef CONFIG_SHA256
1302e5b75505Sopenharmony_ci			u8 hash[32];
1303e5b75505Sopenharmony_ci			const u8 *_addr[1];
1304e5b75505Sopenharmony_ci			size_t _len[1];
1305e5b75505Sopenharmony_ci#endif /* CONFIG_SHA256 */
1306e5b75505Sopenharmony_ci
1307e5b75505Sopenharmony_ci			os_memset(&ev, 0, sizeof(ev));
1308e5b75505Sopenharmony_ci			if (conn->global->cert_in_cb) {
1309e5b75505Sopenharmony_ci				cert_buf = wpabuf_alloc_copy(certs[i].data,
1310e5b75505Sopenharmony_ci							     certs[i].size);
1311e5b75505Sopenharmony_ci				ev.peer_cert.cert = cert_buf;
1312e5b75505Sopenharmony_ci			}
1313e5b75505Sopenharmony_ci#ifdef CONFIG_SHA256
1314e5b75505Sopenharmony_ci			_addr[0] = certs[i].data;
1315e5b75505Sopenharmony_ci			_len[0] = certs[i].size;
1316e5b75505Sopenharmony_ci			if (sha256_vector(1, _addr, _len, hash) == 0) {
1317e5b75505Sopenharmony_ci				ev.peer_cert.hash = hash;
1318e5b75505Sopenharmony_ci				ev.peer_cert.hash_len = sizeof(hash);
1319e5b75505Sopenharmony_ci			}
1320e5b75505Sopenharmony_ci#endif /* CONFIG_SHA256 */
1321e5b75505Sopenharmony_ci			ev.peer_cert.depth = i;
1322e5b75505Sopenharmony_ci			ev.peer_cert.subject = buf;
1323e5b75505Sopenharmony_ci			conn->global->event_cb(conn->global->cb_ctx,
1324e5b75505Sopenharmony_ci					       TLS_PEER_CERTIFICATE, &ev);
1325e5b75505Sopenharmony_ci			wpabuf_free(cert_buf);
1326e5b75505Sopenharmony_ci		}
1327e5b75505Sopenharmony_ci
1328e5b75505Sopenharmony_ci		if (i == 0) {
1329e5b75505Sopenharmony_ci			if (conn->suffix_match &&
1330e5b75505Sopenharmony_ci			    !tls_match_suffix(cert, conn->suffix_match, 0)) {
1331e5b75505Sopenharmony_ci				wpa_printf(MSG_WARNING,
1332e5b75505Sopenharmony_ci					   "TLS: Domain suffix match '%s' not found",
1333e5b75505Sopenharmony_ci					   conn->suffix_match);
1334e5b75505Sopenharmony_ci				gnutls_tls_fail_event(
1335e5b75505Sopenharmony_ci					conn, &certs[i], i, buf,
1336e5b75505Sopenharmony_ci					"Domain suffix mismatch",
1337e5b75505Sopenharmony_ci					TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
1338e5b75505Sopenharmony_ci				err = GNUTLS_A_BAD_CERTIFICATE;
1339e5b75505Sopenharmony_ci				gnutls_x509_crt_deinit(cert);
1340e5b75505Sopenharmony_ci				os_free(buf);
1341e5b75505Sopenharmony_ci				goto out;
1342e5b75505Sopenharmony_ci			}
1343e5b75505Sopenharmony_ci
1344e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x030300
1345e5b75505Sopenharmony_ci			if (conn->domain_match &&
1346e5b75505Sopenharmony_ci			    !tls_match_suffix(cert, conn->domain_match, 1)) {
1347e5b75505Sopenharmony_ci				wpa_printf(MSG_WARNING,
1348e5b75505Sopenharmony_ci					   "TLS: Domain match '%s' not found",
1349e5b75505Sopenharmony_ci					   conn->domain_match);
1350e5b75505Sopenharmony_ci				gnutls_tls_fail_event(
1351e5b75505Sopenharmony_ci					conn, &certs[i], i, buf,
1352e5b75505Sopenharmony_ci					"Domain mismatch",
1353e5b75505Sopenharmony_ci					TLS_FAIL_DOMAIN_MISMATCH);
1354e5b75505Sopenharmony_ci				err = GNUTLS_A_BAD_CERTIFICATE;
1355e5b75505Sopenharmony_ci				gnutls_x509_crt_deinit(cert);
1356e5b75505Sopenharmony_ci				os_free(buf);
1357e5b75505Sopenharmony_ci				goto out;
1358e5b75505Sopenharmony_ci			}
1359e5b75505Sopenharmony_ci#endif /* >= 3.3.0 */
1360e5b75505Sopenharmony_ci
1361e5b75505Sopenharmony_ci			/* TODO: validate altsubject_match.
1362e5b75505Sopenharmony_ci			 * For now, any such configuration is rejected in
1363e5b75505Sopenharmony_ci			 * tls_connection_set_params() */
1364e5b75505Sopenharmony_ci
1365e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER < 0x030300
1366e5b75505Sopenharmony_ci			/*
1367e5b75505Sopenharmony_ci			 * gnutls_certificate_verify_peers() not available, so
1368e5b75505Sopenharmony_ci			 * need to check EKU separately.
1369e5b75505Sopenharmony_ci			 */
1370e5b75505Sopenharmony_ci			if (!conn->global->server &&
1371e5b75505Sopenharmony_ci			    !server_eku_purpose(cert)) {
1372e5b75505Sopenharmony_ci				wpa_printf(MSG_WARNING,
1373e5b75505Sopenharmony_ci					   "GnuTLS: No server EKU");
1374e5b75505Sopenharmony_ci				gnutls_tls_fail_event(
1375e5b75505Sopenharmony_ci					conn, &certs[i], i, buf,
1376e5b75505Sopenharmony_ci					"No server EKU",
1377e5b75505Sopenharmony_ci					TLS_FAIL_BAD_CERTIFICATE);
1378e5b75505Sopenharmony_ci				err = GNUTLS_A_BAD_CERTIFICATE;
1379e5b75505Sopenharmony_ci				gnutls_x509_crt_deinit(cert);
1380e5b75505Sopenharmony_ci				os_free(buf);
1381e5b75505Sopenharmony_ci				goto out;
1382e5b75505Sopenharmony_ci			}
1383e5b75505Sopenharmony_ci#endif /* < 3.3.0 */
1384e5b75505Sopenharmony_ci		}
1385e5b75505Sopenharmony_ci
1386e5b75505Sopenharmony_ci		if (!conn->disable_time_checks &&
1387e5b75505Sopenharmony_ci		    (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
1388e5b75505Sopenharmony_ci		     gnutls_x509_crt_get_activation_time(cert) > now.sec)) {
1389e5b75505Sopenharmony_ci			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
1390e5b75505Sopenharmony_ci				   "not valid at this time",
1391e5b75505Sopenharmony_ci				   i + 1, num_certs);
1392e5b75505Sopenharmony_ci			gnutls_tls_fail_event(
1393e5b75505Sopenharmony_ci				conn, &certs[i], i, buf,
1394e5b75505Sopenharmony_ci				"Certificate is not valid at this time",
1395e5b75505Sopenharmony_ci				TLS_FAIL_EXPIRED);
1396e5b75505Sopenharmony_ci			gnutls_x509_crt_deinit(cert);
1397e5b75505Sopenharmony_ci			os_free(buf);
1398e5b75505Sopenharmony_ci			err = GNUTLS_A_CERTIFICATE_EXPIRED;
1399e5b75505Sopenharmony_ci			goto out;
1400e5b75505Sopenharmony_ci		}
1401e5b75505Sopenharmony_ci
1402e5b75505Sopenharmony_ci		os_free(buf);
1403e5b75505Sopenharmony_ci
1404e5b75505Sopenharmony_ci		gnutls_x509_crt_deinit(cert);
1405e5b75505Sopenharmony_ci	}
1406e5b75505Sopenharmony_ci
1407e5b75505Sopenharmony_ci	if (conn->global->event_cb != NULL)
1408e5b75505Sopenharmony_ci		conn->global->event_cb(conn->global->cb_ctx,
1409e5b75505Sopenharmony_ci				       TLS_CERT_CHAIN_SUCCESS, NULL);
1410e5b75505Sopenharmony_ci
1411e5b75505Sopenharmony_ci	return 0;
1412e5b75505Sopenharmony_ci
1413e5b75505Sopenharmony_ciout:
1414e5b75505Sopenharmony_ci	conn->failed++;
1415e5b75505Sopenharmony_ci	gnutls_alert_send(session, GNUTLS_AL_FATAL, err);
1416e5b75505Sopenharmony_ci	return GNUTLS_E_CERTIFICATE_ERROR;
1417e5b75505Sopenharmony_ci}
1418e5b75505Sopenharmony_ci
1419e5b75505Sopenharmony_ci
1420e5b75505Sopenharmony_cistatic struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
1421e5b75505Sopenharmony_ci{
1422e5b75505Sopenharmony_ci	int res;
1423e5b75505Sopenharmony_ci	struct wpabuf *ad;
1424e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
1425e5b75505Sopenharmony_ci	ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
1426e5b75505Sopenharmony_ci	if (ad == NULL)
1427e5b75505Sopenharmony_ci		return NULL;
1428e5b75505Sopenharmony_ci
1429e5b75505Sopenharmony_ci	res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
1430e5b75505Sopenharmony_ci				 wpabuf_size(ad));
1431e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
1432e5b75505Sopenharmony_ci	if (res < 0) {
1433e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1434e5b75505Sopenharmony_ci			   "(%s)", __func__, (int) res,
1435e5b75505Sopenharmony_ci			   gnutls_strerror(res));
1436e5b75505Sopenharmony_ci		wpabuf_free(ad);
1437e5b75505Sopenharmony_ci		return NULL;
1438e5b75505Sopenharmony_ci	}
1439e5b75505Sopenharmony_ci
1440e5b75505Sopenharmony_ci	wpabuf_put(ad, res);
1441e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
1442e5b75505Sopenharmony_ci		   res);
1443e5b75505Sopenharmony_ci	return ad;
1444e5b75505Sopenharmony_ci}
1445e5b75505Sopenharmony_ci
1446e5b75505Sopenharmony_ci
1447e5b75505Sopenharmony_cistruct wpabuf * tls_connection_handshake(void *tls_ctx,
1448e5b75505Sopenharmony_ci					 struct tls_connection *conn,
1449e5b75505Sopenharmony_ci					 const struct wpabuf *in_data,
1450e5b75505Sopenharmony_ci					 struct wpabuf **appl_data)
1451e5b75505Sopenharmony_ci{
1452e5b75505Sopenharmony_ci	struct tls_global *global = tls_ctx;
1453e5b75505Sopenharmony_ci	struct wpabuf *out_data;
1454e5b75505Sopenharmony_ci	int ret;
1455e5b75505Sopenharmony_ci
1456e5b75505Sopenharmony_ci	if (appl_data)
1457e5b75505Sopenharmony_ci		*appl_data = NULL;
1458e5b75505Sopenharmony_ci
1459e5b75505Sopenharmony_ci	if (in_data && wpabuf_len(in_data) > 0) {
1460e5b75505Sopenharmony_ci		if (conn->pull_buf) {
1461e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1462e5b75505Sopenharmony_ci				   "pull_buf", __func__,
1463e5b75505Sopenharmony_ci				   (unsigned long) wpabuf_len(conn->pull_buf));
1464e5b75505Sopenharmony_ci			wpabuf_free(conn->pull_buf);
1465e5b75505Sopenharmony_ci		}
1466e5b75505Sopenharmony_ci		conn->pull_buf = wpabuf_dup(in_data);
1467e5b75505Sopenharmony_ci		if (conn->pull_buf == NULL)
1468e5b75505Sopenharmony_ci			return NULL;
1469e5b75505Sopenharmony_ci		conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1470e5b75505Sopenharmony_ci	}
1471e5b75505Sopenharmony_ci
1472e5b75505Sopenharmony_ci	ret = gnutls_handshake(conn->session);
1473e5b75505Sopenharmony_ci	if (ret < 0) {
1474e5b75505Sopenharmony_ci		gnutls_alert_description_t alert;
1475e5b75505Sopenharmony_ci		union tls_event_data ev;
1476e5b75505Sopenharmony_ci
1477e5b75505Sopenharmony_ci		switch (ret) {
1478e5b75505Sopenharmony_ci		case GNUTLS_E_AGAIN:
1479e5b75505Sopenharmony_ci			if (global->server && conn->established &&
1480e5b75505Sopenharmony_ci			    conn->push_buf == NULL) {
1481e5b75505Sopenharmony_ci				/* Need to return something to trigger
1482e5b75505Sopenharmony_ci				 * completion of EAP-TLS. */
1483e5b75505Sopenharmony_ci				conn->push_buf = wpabuf_alloc(0);
1484e5b75505Sopenharmony_ci			}
1485e5b75505Sopenharmony_ci			break;
1486e5b75505Sopenharmony_ci		case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
1487e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "GnuTLS: Unacceptable DH prime");
1488e5b75505Sopenharmony_ci			if (conn->global->event_cb) {
1489e5b75505Sopenharmony_ci				os_memset(&ev, 0, sizeof(ev));
1490e5b75505Sopenharmony_ci				ev.alert.is_local = 1;
1491e5b75505Sopenharmony_ci				ev.alert.type = "fatal";
1492e5b75505Sopenharmony_ci				ev.alert.description = "insufficient security";
1493e5b75505Sopenharmony_ci				conn->global->event_cb(conn->global->cb_ctx,
1494e5b75505Sopenharmony_ci						       TLS_ALERT, &ev);
1495e5b75505Sopenharmony_ci			}
1496e5b75505Sopenharmony_ci			/*
1497e5b75505Sopenharmony_ci			 * Could send a TLS Alert to the server, but for now,
1498e5b75505Sopenharmony_ci			 * simply terminate handshake.
1499e5b75505Sopenharmony_ci			 */
1500e5b75505Sopenharmony_ci			conn->failed++;
1501e5b75505Sopenharmony_ci			conn->write_alerts++;
1502e5b75505Sopenharmony_ci			break;
1503e5b75505Sopenharmony_ci		case GNUTLS_E_FATAL_ALERT_RECEIVED:
1504e5b75505Sopenharmony_ci			alert = gnutls_alert_get(conn->session);
1505e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
1506e5b75505Sopenharmony_ci				   __func__, gnutls_alert_get_name(alert));
1507e5b75505Sopenharmony_ci			conn->read_alerts++;
1508e5b75505Sopenharmony_ci			if (conn->global->event_cb != NULL) {
1509e5b75505Sopenharmony_ci				os_memset(&ev, 0, sizeof(ev));
1510e5b75505Sopenharmony_ci				ev.alert.is_local = 0;
1511e5b75505Sopenharmony_ci				ev.alert.type = gnutls_alert_get_name(alert);
1512e5b75505Sopenharmony_ci				ev.alert.description = ev.alert.type;
1513e5b75505Sopenharmony_ci				conn->global->event_cb(conn->global->cb_ctx,
1514e5b75505Sopenharmony_ci						       TLS_ALERT, &ev);
1515e5b75505Sopenharmony_ci			}
1516e5b75505Sopenharmony_ci			/* continue */
1517e5b75505Sopenharmony_ci		default:
1518e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
1519e5b75505Sopenharmony_ci				   "-> %s", __func__, gnutls_strerror(ret));
1520e5b75505Sopenharmony_ci			conn->failed++;
1521e5b75505Sopenharmony_ci		}
1522e5b75505Sopenharmony_ci	} else {
1523e5b75505Sopenharmony_ci		size_t size;
1524e5b75505Sopenharmony_ci
1525e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
1526e5b75505Sopenharmony_ci
1527e5b75505Sopenharmony_ci#if GNUTLS_VERSION_NUMBER >= 0x03010a
1528e5b75505Sopenharmony_ci		{
1529e5b75505Sopenharmony_ci			char *desc;
1530e5b75505Sopenharmony_ci
1531e5b75505Sopenharmony_ci			desc = gnutls_session_get_desc(conn->session);
1532e5b75505Sopenharmony_ci			if (desc) {
1533e5b75505Sopenharmony_ci				wpa_printf(MSG_DEBUG, "GnuTLS: %s", desc);
1534e5b75505Sopenharmony_ci				gnutls_free(desc);
1535e5b75505Sopenharmony_ci			}
1536e5b75505Sopenharmony_ci		}
1537e5b75505Sopenharmony_ci#endif /* GnuTLS 3.1.10 or newer */
1538e5b75505Sopenharmony_ci
1539e5b75505Sopenharmony_ci		conn->established = 1;
1540e5b75505Sopenharmony_ci		if (conn->push_buf == NULL) {
1541e5b75505Sopenharmony_ci			/* Need to return something to get final TLS ACK. */
1542e5b75505Sopenharmony_ci			conn->push_buf = wpabuf_alloc(0);
1543e5b75505Sopenharmony_ci		}
1544e5b75505Sopenharmony_ci
1545e5b75505Sopenharmony_ci		gnutls_session_get_data(conn->session, NULL, &size);
1546e5b75505Sopenharmony_ci		if (global->session_data == NULL ||
1547e5b75505Sopenharmony_ci		    global->session_data_size < size) {
1548e5b75505Sopenharmony_ci			os_free(global->session_data);
1549e5b75505Sopenharmony_ci			global->session_data = os_malloc(size);
1550e5b75505Sopenharmony_ci		}
1551e5b75505Sopenharmony_ci		if (global->session_data) {
1552e5b75505Sopenharmony_ci			global->session_data_size = size;
1553e5b75505Sopenharmony_ci			gnutls_session_get_data(conn->session,
1554e5b75505Sopenharmony_ci						global->session_data,
1555e5b75505Sopenharmony_ci						&global->session_data_size);
1556e5b75505Sopenharmony_ci		}
1557e5b75505Sopenharmony_ci
1558e5b75505Sopenharmony_ci		if (conn->pull_buf && appl_data)
1559e5b75505Sopenharmony_ci			*appl_data = gnutls_get_appl_data(conn);
1560e5b75505Sopenharmony_ci	}
1561e5b75505Sopenharmony_ci
1562e5b75505Sopenharmony_ci	out_data = conn->push_buf;
1563e5b75505Sopenharmony_ci	conn->push_buf = NULL;
1564e5b75505Sopenharmony_ci	return out_data;
1565e5b75505Sopenharmony_ci}
1566e5b75505Sopenharmony_ci
1567e5b75505Sopenharmony_ci
1568e5b75505Sopenharmony_cistruct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1569e5b75505Sopenharmony_ci						struct tls_connection *conn,
1570e5b75505Sopenharmony_ci						const struct wpabuf *in_data,
1571e5b75505Sopenharmony_ci						struct wpabuf **appl_data)
1572e5b75505Sopenharmony_ci{
1573e5b75505Sopenharmony_ci	return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1574e5b75505Sopenharmony_ci}
1575e5b75505Sopenharmony_ci
1576e5b75505Sopenharmony_ci
1577e5b75505Sopenharmony_cistruct wpabuf * tls_connection_encrypt(void *tls_ctx,
1578e5b75505Sopenharmony_ci				       struct tls_connection *conn,
1579e5b75505Sopenharmony_ci				       const struct wpabuf *in_data)
1580e5b75505Sopenharmony_ci{
1581e5b75505Sopenharmony_ci	ssize_t res;
1582e5b75505Sopenharmony_ci	struct wpabuf *buf;
1583e5b75505Sopenharmony_ci
1584e5b75505Sopenharmony_ci	res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1585e5b75505Sopenharmony_ci				 wpabuf_len(in_data));
1586e5b75505Sopenharmony_ci	if (res < 0) {
1587e5b75505Sopenharmony_ci		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1588e5b75505Sopenharmony_ci			   __func__, gnutls_strerror(res));
1589e5b75505Sopenharmony_ci		return NULL;
1590e5b75505Sopenharmony_ci	}
1591e5b75505Sopenharmony_ci
1592e5b75505Sopenharmony_ci	buf = conn->push_buf;
1593e5b75505Sopenharmony_ci	conn->push_buf = NULL;
1594e5b75505Sopenharmony_ci	return buf;
1595e5b75505Sopenharmony_ci}
1596e5b75505Sopenharmony_ci
1597e5b75505Sopenharmony_ci
1598e5b75505Sopenharmony_cistruct wpabuf * tls_connection_decrypt(void *tls_ctx,
1599e5b75505Sopenharmony_ci				       struct tls_connection *conn,
1600e5b75505Sopenharmony_ci				       const struct wpabuf *in_data)
1601e5b75505Sopenharmony_ci{
1602e5b75505Sopenharmony_ci	ssize_t res;
1603e5b75505Sopenharmony_ci	struct wpabuf *out;
1604e5b75505Sopenharmony_ci
1605e5b75505Sopenharmony_ci	if (conn->pull_buf) {
1606e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1607e5b75505Sopenharmony_ci			   "pull_buf", __func__,
1608e5b75505Sopenharmony_ci			   (unsigned long) wpabuf_len(conn->pull_buf));
1609e5b75505Sopenharmony_ci		wpabuf_free(conn->pull_buf);
1610e5b75505Sopenharmony_ci	}
1611e5b75505Sopenharmony_ci	conn->pull_buf = wpabuf_dup(in_data);
1612e5b75505Sopenharmony_ci	if (conn->pull_buf == NULL)
1613e5b75505Sopenharmony_ci		return NULL;
1614e5b75505Sopenharmony_ci	conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1615e5b75505Sopenharmony_ci
1616e5b75505Sopenharmony_ci	/*
1617e5b75505Sopenharmony_ci	 * Even though we try to disable TLS compression, it is possible that
1618e5b75505Sopenharmony_ci	 * this cannot be done with all TLS libraries. Add extra buffer space
1619e5b75505Sopenharmony_ci	 * to handle the possibility of the decrypted data being longer than
1620e5b75505Sopenharmony_ci	 * input data.
1621e5b75505Sopenharmony_ci	 */
1622e5b75505Sopenharmony_ci	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1623e5b75505Sopenharmony_ci	if (out == NULL)
1624e5b75505Sopenharmony_ci		return NULL;
1625e5b75505Sopenharmony_ci
1626e5b75505Sopenharmony_ci	res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1627e5b75505Sopenharmony_ci				 wpabuf_size(out));
1628e5b75505Sopenharmony_ci	if (res < 0) {
1629e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1630e5b75505Sopenharmony_ci			   "(%s)", __func__, (int) res, gnutls_strerror(res));
1631e5b75505Sopenharmony_ci		wpabuf_free(out);
1632e5b75505Sopenharmony_ci		return NULL;
1633e5b75505Sopenharmony_ci	}
1634e5b75505Sopenharmony_ci	wpabuf_put(out, res);
1635e5b75505Sopenharmony_ci
1636e5b75505Sopenharmony_ci	return out;
1637e5b75505Sopenharmony_ci}
1638e5b75505Sopenharmony_ci
1639e5b75505Sopenharmony_ci
1640e5b75505Sopenharmony_ciint tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1641e5b75505Sopenharmony_ci{
1642e5b75505Sopenharmony_ci	if (conn == NULL)
1643e5b75505Sopenharmony_ci		return 0;
1644e5b75505Sopenharmony_ci	return gnutls_session_is_resumed(conn->session);
1645e5b75505Sopenharmony_ci}
1646e5b75505Sopenharmony_ci
1647e5b75505Sopenharmony_ci
1648e5b75505Sopenharmony_ciint tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1649e5b75505Sopenharmony_ci				   u8 *ciphers)
1650e5b75505Sopenharmony_ci{
1651e5b75505Sopenharmony_ci	/* TODO */
1652e5b75505Sopenharmony_ci	return -1;
1653e5b75505Sopenharmony_ci}
1654e5b75505Sopenharmony_ci
1655e5b75505Sopenharmony_ci
1656e5b75505Sopenharmony_ciint tls_get_version(void *ssl_ctx, struct tls_connection *conn,
1657e5b75505Sopenharmony_ci		    char *buf, size_t buflen)
1658e5b75505Sopenharmony_ci{
1659e5b75505Sopenharmony_ci	gnutls_protocol_t ver;
1660e5b75505Sopenharmony_ci
1661e5b75505Sopenharmony_ci	ver = gnutls_protocol_get_version(conn->session);
1662e5b75505Sopenharmony_ci	if (ver == GNUTLS_TLS1_0)
1663e5b75505Sopenharmony_ci		os_strlcpy(buf, "TLSv1", buflen);
1664e5b75505Sopenharmony_ci	else if (ver == GNUTLS_TLS1_1)
1665e5b75505Sopenharmony_ci		os_strlcpy(buf, "TLSv1.1", buflen);
1666e5b75505Sopenharmony_ci	else if (ver == GNUTLS_TLS1_2)
1667e5b75505Sopenharmony_ci		os_strlcpy(buf, "TLSv1.2", buflen);
1668e5b75505Sopenharmony_ci	else
1669e5b75505Sopenharmony_ci		return -1;
1670e5b75505Sopenharmony_ci	return 0;
1671e5b75505Sopenharmony_ci}
1672e5b75505Sopenharmony_ci
1673e5b75505Sopenharmony_ci
1674e5b75505Sopenharmony_ciint tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1675e5b75505Sopenharmony_ci		   char *buf, size_t buflen)
1676e5b75505Sopenharmony_ci{
1677e5b75505Sopenharmony_ci	gnutls_cipher_algorithm_t cipher;
1678e5b75505Sopenharmony_ci	gnutls_kx_algorithm_t kx;
1679e5b75505Sopenharmony_ci	gnutls_mac_algorithm_t mac;
1680e5b75505Sopenharmony_ci	const char *kx_str, *cipher_str, *mac_str;
1681e5b75505Sopenharmony_ci	int res;
1682e5b75505Sopenharmony_ci
1683e5b75505Sopenharmony_ci	cipher = gnutls_cipher_get(conn->session);
1684e5b75505Sopenharmony_ci	cipher_str = gnutls_cipher_get_name(cipher);
1685e5b75505Sopenharmony_ci	if (!cipher_str)
1686e5b75505Sopenharmony_ci		cipher_str = "";
1687e5b75505Sopenharmony_ci
1688e5b75505Sopenharmony_ci	kx = gnutls_kx_get(conn->session);
1689e5b75505Sopenharmony_ci	kx_str = gnutls_kx_get_name(kx);
1690e5b75505Sopenharmony_ci	if (!kx_str)
1691e5b75505Sopenharmony_ci		kx_str = "";
1692e5b75505Sopenharmony_ci
1693e5b75505Sopenharmony_ci	mac = gnutls_mac_get(conn->session);
1694e5b75505Sopenharmony_ci	mac_str = gnutls_mac_get_name(mac);
1695e5b75505Sopenharmony_ci	if (!mac_str)
1696e5b75505Sopenharmony_ci		mac_str = "";
1697e5b75505Sopenharmony_ci
1698e5b75505Sopenharmony_ci	if (kx == GNUTLS_KX_RSA)
1699e5b75505Sopenharmony_ci		res = os_snprintf(buf, buflen, "%s-%s", cipher_str, mac_str);
1700e5b75505Sopenharmony_ci	else
1701e5b75505Sopenharmony_ci		res = os_snprintf(buf, buflen, "%s-%s-%s",
1702e5b75505Sopenharmony_ci				  kx_str, cipher_str, mac_str);
1703e5b75505Sopenharmony_ci	if (os_snprintf_error(buflen, res))
1704e5b75505Sopenharmony_ci		return -1;
1705e5b75505Sopenharmony_ci
1706e5b75505Sopenharmony_ci	return 0;
1707e5b75505Sopenharmony_ci}
1708e5b75505Sopenharmony_ci
1709e5b75505Sopenharmony_ci
1710e5b75505Sopenharmony_ciint tls_connection_enable_workaround(void *ssl_ctx,
1711e5b75505Sopenharmony_ci				     struct tls_connection *conn)
1712e5b75505Sopenharmony_ci{
1713e5b75505Sopenharmony_ci	gnutls_record_disable_padding(conn->session);
1714e5b75505Sopenharmony_ci	return 0;
1715e5b75505Sopenharmony_ci}
1716e5b75505Sopenharmony_ci
1717e5b75505Sopenharmony_ci
1718e5b75505Sopenharmony_ciint tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1719e5b75505Sopenharmony_ci				    int ext_type, const u8 *data,
1720e5b75505Sopenharmony_ci				    size_t data_len)
1721e5b75505Sopenharmony_ci{
1722e5b75505Sopenharmony_ci	/* TODO */
1723e5b75505Sopenharmony_ci	return -1;
1724e5b75505Sopenharmony_ci}
1725e5b75505Sopenharmony_ci
1726e5b75505Sopenharmony_ci
1727e5b75505Sopenharmony_ciint tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1728e5b75505Sopenharmony_ci{
1729e5b75505Sopenharmony_ci	if (conn == NULL)
1730e5b75505Sopenharmony_ci		return -1;
1731e5b75505Sopenharmony_ci	return conn->failed;
1732e5b75505Sopenharmony_ci}
1733e5b75505Sopenharmony_ci
1734e5b75505Sopenharmony_ci
1735e5b75505Sopenharmony_ciint tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1736e5b75505Sopenharmony_ci{
1737e5b75505Sopenharmony_ci	if (conn == NULL)
1738e5b75505Sopenharmony_ci		return -1;
1739e5b75505Sopenharmony_ci	return conn->read_alerts;
1740e5b75505Sopenharmony_ci}
1741e5b75505Sopenharmony_ci
1742e5b75505Sopenharmony_ci
1743e5b75505Sopenharmony_ciint tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1744e5b75505Sopenharmony_ci{
1745e5b75505Sopenharmony_ci	if (conn == NULL)
1746e5b75505Sopenharmony_ci		return -1;
1747e5b75505Sopenharmony_ci	return conn->write_alerts;
1748e5b75505Sopenharmony_ci}
1749e5b75505Sopenharmony_ci
1750e5b75505Sopenharmony_ci
1751e5b75505Sopenharmony_ciint tls_connection_set_session_ticket_cb(void *tls_ctx,
1752e5b75505Sopenharmony_ci					 struct tls_connection *conn,
1753e5b75505Sopenharmony_ci					 tls_session_ticket_cb cb, void *ctx)
1754e5b75505Sopenharmony_ci{
1755e5b75505Sopenharmony_ci	return -1;
1756e5b75505Sopenharmony_ci}
1757e5b75505Sopenharmony_ci
1758e5b75505Sopenharmony_ci
1759e5b75505Sopenharmony_ciint tls_get_library_version(char *buf, size_t buf_len)
1760e5b75505Sopenharmony_ci{
1761e5b75505Sopenharmony_ci	return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
1762e5b75505Sopenharmony_ci			   GNUTLS_VERSION, gnutls_check_version(NULL));
1763e5b75505Sopenharmony_ci}
1764e5b75505Sopenharmony_ci
1765e5b75505Sopenharmony_ci
1766e5b75505Sopenharmony_civoid tls_connection_set_success_data(struct tls_connection *conn,
1767e5b75505Sopenharmony_ci				     struct wpabuf *data)
1768e5b75505Sopenharmony_ci{
1769e5b75505Sopenharmony_ci}
1770e5b75505Sopenharmony_ci
1771e5b75505Sopenharmony_ci
1772e5b75505Sopenharmony_civoid tls_connection_set_success_data_resumed(struct tls_connection *conn)
1773e5b75505Sopenharmony_ci{
1774e5b75505Sopenharmony_ci}
1775e5b75505Sopenharmony_ci
1776e5b75505Sopenharmony_ci
1777e5b75505Sopenharmony_ciconst struct wpabuf *
1778e5b75505Sopenharmony_citls_connection_get_success_data(struct tls_connection *conn)
1779e5b75505Sopenharmony_ci{
1780e5b75505Sopenharmony_ci	return NULL;
1781e5b75505Sopenharmony_ci}
1782e5b75505Sopenharmony_ci
1783e5b75505Sopenharmony_ci
1784e5b75505Sopenharmony_civoid tls_connection_remove_session(struct tls_connection *conn)
1785e5b75505Sopenharmony_ci{
1786e5b75505Sopenharmony_ci}
1787