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