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
16#include "common.h"
17#include "tls.h"
18
19
20#define WPA_TLS_RANDOM_SIZE 32
21#define WPA_TLS_MASTER_SIZE 48
22
23
24#if LIBGNUTLS_VERSION_NUMBER < 0x010302
25/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
26 * use of internal structures to get the master_secret and
27 * {server,client}_random.
28 */
29#define GNUTLS_INTERNAL_STRUCTURE_HACK
30#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
31
32
33#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
34/*
35 * It looks like gnutls does not provide access to client/server_random and
36 * master_key. This is somewhat unfortunate since these are needed for key
37 * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
38 * hack that copies the gnutls_session_int definition from gnutls_int.h so that
39 * we can get the needed information.
40 */
41
42typedef u8 uint8;
43typedef unsigned char opaque;
44typedef struct {
45    uint8 suite[2];
46} cipher_suite_st;
47
48typedef struct {
49	gnutls_connection_end_t entity;
50	gnutls_kx_algorithm_t kx_algorithm;
51	gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
52	gnutls_mac_algorithm_t read_mac_algorithm;
53	gnutls_compression_method_t read_compression_algorithm;
54	gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
55	gnutls_mac_algorithm_t write_mac_algorithm;
56	gnutls_compression_method_t write_compression_algorithm;
57	cipher_suite_st current_cipher_suite;
58	opaque master_secret[WPA_TLS_MASTER_SIZE];
59	opaque client_random[WPA_TLS_RANDOM_SIZE];
60	opaque server_random[WPA_TLS_RANDOM_SIZE];
61	/* followed by stuff we are not interested in */
62} security_parameters_st;
63
64struct gnutls_session_int {
65	security_parameters_st security_parameters;
66	/* followed by things we are not interested in */
67};
68#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
69
70static int tls_gnutls_ref_count = 0;
71
72struct tls_global {
73	/* Data for session resumption */
74	void *session_data;
75	size_t session_data_size;
76
77	int server;
78
79	int params_set;
80	gnutls_certificate_credentials_t xcred;
81};
82
83struct tls_connection {
84	gnutls_session session;
85	char *subject_match, *altsubject_match;
86	int read_alerts, write_alerts, failed;
87
88	u8 *pre_shared_secret;
89	size_t pre_shared_secret_len;
90	int established;
91	int verify_peer;
92
93	struct wpabuf *push_buf;
94	struct wpabuf *pull_buf;
95	const u8 *pull_buf_offset;
96
97	int params_set;
98	gnutls_certificate_credentials_t xcred;
99};
100
101
102static void tls_log_func(int level, const char *msg)
103{
104	char *s, *pos;
105	if (level == 6 || level == 7) {
106		/* These levels seem to be mostly I/O debug and msg dumps */
107		return;
108	}
109
110	s = os_strdup(msg);
111	if (s == NULL)
112		return;
113
114	pos = s;
115	while (*pos != '\0') {
116		if (*pos == '\n') {
117			*pos = '\0';
118			break;
119		}
120		pos++;
121	}
122	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
123		   "gnutls<%d> %s", level, s);
124	os_free(s);
125}
126
127
128void * tls_init(const struct tls_config *conf)
129{
130	struct tls_global *global;
131
132#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
133	/* Because of the horrible hack to get master_secret and client/server
134	 * random, we need to make sure that the gnutls version is something
135	 * that is expected to have same structure definition for the session
136	 * data.. */
137	const char *ver;
138	const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
139				 "1.3.2",
140				 NULL };
141	int i;
142#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
143
144	global = os_zalloc(sizeof(*global));
145	if (global == NULL)
146		return NULL;
147
148	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
149		os_free(global);
150		return NULL;
151	}
152	tls_gnutls_ref_count++;
153
154#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
155	ver = gnutls_check_version(NULL);
156	if (ver == NULL) {
157		tls_deinit(global);
158		return NULL;
159	}
160	wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
161	for (i = 0; ok_ver[i]; i++) {
162		if (strcmp(ok_ver[i], ver) == 0)
163			break;
164	}
165	if (ok_ver[i] == NULL) {
166		wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
167			   "to be tested and enabled in tls_gnutls.c", ver);
168		tls_deinit(global);
169		return NULL;
170	}
171#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
172
173	gnutls_global_set_log_function(tls_log_func);
174	if (wpa_debug_show_keys)
175		gnutls_global_set_log_level(11);
176	return global;
177}
178
179
180void tls_deinit(void *ssl_ctx)
181{
182	struct tls_global *global = ssl_ctx;
183	if (global) {
184		if (global->params_set)
185			gnutls_certificate_free_credentials(global->xcred);
186		os_free(global->session_data);
187		os_free(global);
188	}
189
190	tls_gnutls_ref_count--;
191	if (tls_gnutls_ref_count == 0)
192		gnutls_global_deinit();
193}
194
195
196int tls_get_errors(void *ssl_ctx)
197{
198	return 0;
199}
200
201
202static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
203			     size_t len)
204{
205	struct tls_connection *conn = (struct tls_connection *) ptr;
206	const u8 *end;
207	if (conn->pull_buf == NULL) {
208		errno = EWOULDBLOCK;
209		return -1;
210	}
211
212	end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
213	if ((size_t) (end - conn->pull_buf_offset) < len)
214		len = end - conn->pull_buf_offset;
215	os_memcpy(buf, conn->pull_buf_offset, len);
216	conn->pull_buf_offset += len;
217	if (conn->pull_buf_offset == end) {
218		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
219		wpabuf_free(conn->pull_buf);
220		conn->pull_buf = NULL;
221		conn->pull_buf_offset = NULL;
222	} else {
223		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
224			   __func__,
225			   (unsigned long) (end - conn->pull_buf_offset));
226	}
227	return len;
228}
229
230
231static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
232			     size_t len)
233{
234	struct tls_connection *conn = (struct tls_connection *) ptr;
235
236	if (wpabuf_resize(&conn->push_buf, len) < 0) {
237		errno = ENOMEM;
238		return -1;
239	}
240	wpabuf_put_data(conn->push_buf, buf, len);
241
242	return len;
243}
244
245
246static int tls_gnutls_init_session(struct tls_global *global,
247				   struct tls_connection *conn)
248{
249#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
250	const char *err;
251#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
252	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
253	const int protos[2] = { GNUTLS_TLS1, 0 };
254#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
255	int ret;
256
257	ret = gnutls_init(&conn->session,
258			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
259	if (ret < 0) {
260		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
261			   "connection: %s", gnutls_strerror(ret));
262		return -1;
263	}
264
265	ret = gnutls_set_default_priority(conn->session);
266	if (ret < 0)
267		goto fail;
268
269#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
270	ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
271					 &err);
272	if (ret < 0) {
273		wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
274			   "'%s'", err);
275		goto fail;
276	}
277#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
278	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
279	if (ret < 0)
280		goto fail;
281
282	ret = gnutls_protocol_set_priority(conn->session, protos);
283	if (ret < 0)
284		goto fail;
285#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
286
287	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
288	gnutls_transport_set_push_function(conn->session, tls_push_func);
289	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
290
291	return 0;
292
293fail:
294	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
295		   gnutls_strerror(ret));
296	gnutls_deinit(conn->session);
297	return -1;
298}
299
300
301struct tls_connection * tls_connection_init(void *ssl_ctx)
302{
303	struct tls_global *global = ssl_ctx;
304	struct tls_connection *conn;
305	int ret;
306
307	conn = os_zalloc(sizeof(*conn));
308	if (conn == NULL)
309		return NULL;
310
311	if (tls_gnutls_init_session(global, conn)) {
312		os_free(conn);
313		return NULL;
314	}
315
316	if (global->params_set) {
317		ret = gnutls_credentials_set(conn->session,
318					     GNUTLS_CRD_CERTIFICATE,
319					     global->xcred);
320		if (ret < 0) {
321			wpa_printf(MSG_INFO, "Failed to configure "
322				   "credentials: %s", gnutls_strerror(ret));
323			os_free(conn);
324			return NULL;
325		}
326	}
327
328	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
329		os_free(conn);
330		return NULL;
331	}
332
333	return conn;
334}
335
336
337void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
338{
339	if (conn == NULL)
340		return;
341
342	gnutls_certificate_free_credentials(conn->xcred);
343	gnutls_deinit(conn->session);
344	os_free(conn->pre_shared_secret);
345	os_free(conn->subject_match);
346	os_free(conn->altsubject_match);
347	wpabuf_free(conn->push_buf);
348	wpabuf_free(conn->pull_buf);
349	os_free(conn);
350}
351
352
353int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
354{
355	return conn ? conn->established : 0;
356}
357
358
359int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
360{
361	struct tls_global *global = ssl_ctx;
362	int ret;
363
364	if (conn == NULL)
365		return -1;
366
367	/* Shutdown previous TLS connection without notifying the peer
368	 * because the connection was already terminated in practice
369	 * and "close notify" shutdown alert would confuse AS. */
370	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
371	wpabuf_free(conn->push_buf);
372	conn->push_buf = NULL;
373	conn->established = 0;
374
375	gnutls_deinit(conn->session);
376	if (tls_gnutls_init_session(global, conn)) {
377		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
378			   "for session resumption use");
379		return -1;
380	}
381
382	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
383				     conn->params_set ? conn->xcred :
384				     global->xcred);
385	if (ret < 0) {
386		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
387			   "for session resumption: %s", gnutls_strerror(ret));
388		return -1;
389	}
390
391	if (global->session_data) {
392		ret = gnutls_session_set_data(conn->session,
393					      global->session_data,
394					      global->session_data_size);
395		if (ret < 0) {
396			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
397				   "data: %s", gnutls_strerror(ret));
398			return -1;
399		}
400	}
401
402	return 0;
403}
404
405
406#if 0
407static int tls_match_altsubject(X509 *cert, const char *match)
408{
409	GENERAL_NAME *gen;
410	char *field, *tmp;
411	void *ext;
412	int i, found = 0;
413	size_t len;
414
415	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
416
417	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
418		gen = sk_GENERAL_NAME_value(ext, i);
419		switch (gen->type) {
420		case GEN_EMAIL:
421			field = "EMAIL";
422			break;
423		case GEN_DNS:
424			field = "DNS";
425			break;
426		case GEN_URI:
427			field = "URI";
428			break;
429		default:
430			field = NULL;
431			wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
432				   "unsupported type=%d", gen->type);
433			break;
434		}
435
436		if (!field)
437			continue;
438
439		wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
440			   field, gen->d.ia5->data);
441		len = os_strlen(field) + 1 +
442			strlen((char *) gen->d.ia5->data) + 1;
443		tmp = os_malloc(len);
444		if (tmp == NULL)
445			continue;
446		snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
447		if (strstr(tmp, match))
448			found++;
449		os_free(tmp);
450	}
451
452	return found;
453}
454#endif
455
456
457#if 0
458static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
459{
460	char buf[256];
461	X509 *err_cert;
462	int err, depth;
463	SSL *ssl;
464	struct tls_connection *conn;
465	char *match, *altmatch;
466
467	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
468	err = X509_STORE_CTX_get_error(x509_ctx);
469	depth = X509_STORE_CTX_get_error_depth(x509_ctx);
470	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
471					 SSL_get_ex_data_X509_STORE_CTX_idx());
472	X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
473
474	conn = SSL_get_app_data(ssl);
475	match = conn ? conn->subject_match : NULL;
476	altmatch = conn ? conn->altsubject_match : NULL;
477
478	if (!preverify_ok) {
479		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
480			   " error %d (%s) depth %d for '%s'", err,
481			   X509_verify_cert_error_string(err), depth, buf);
482	} else {
483		wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
484			   "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
485			   preverify_ok, err,
486			   X509_verify_cert_error_string(err), depth, buf);
487		if (depth == 0 && match && strstr(buf, match) == NULL) {
488			wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
489				   "match with '%s'", buf, match);
490			preverify_ok = 0;
491		} else if (depth == 0 && altmatch &&
492			   !tls_match_altsubject(err_cert, altmatch)) {
493			wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
494				   "'%s' not found", altmatch);
495			preverify_ok = 0;
496		}
497	}
498
499	return preverify_ok;
500}
501#endif
502
503
504int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
505			      const struct tls_connection_params *params)
506{
507	int ret;
508
509	if (conn == NULL || params == NULL)
510		return -1;
511
512	os_free(conn->subject_match);
513	conn->subject_match = NULL;
514	if (params->subject_match) {
515		conn->subject_match = os_strdup(params->subject_match);
516		if (conn->subject_match == NULL)
517			return -1;
518	}
519
520	os_free(conn->altsubject_match);
521	conn->altsubject_match = NULL;
522	if (params->altsubject_match) {
523		conn->altsubject_match = os_strdup(params->altsubject_match);
524		if (conn->altsubject_match == NULL)
525			return -1;
526	}
527
528	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
529	 * to force peer validation(?) */
530
531	if (params->ca_cert) {
532		conn->verify_peer = 1;
533		ret = gnutls_certificate_set_x509_trust_file(
534			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
535		if (ret < 0) {
536			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
537				   "in PEM format: %s", params->ca_cert,
538				   gnutls_strerror(ret));
539			ret = gnutls_certificate_set_x509_trust_file(
540				conn->xcred, params->ca_cert,
541				GNUTLS_X509_FMT_DER);
542			if (ret < 0) {
543				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
544					   "'%s' in DER format: %s",
545					   params->ca_cert,
546					   gnutls_strerror(ret));
547				return -1;
548			}
549		}
550
551		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
552			gnutls_certificate_set_verify_flags(
553				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
554		}
555
556#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
557		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
558			gnutls_certificate_set_verify_flags(
559				conn->xcred,
560				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
561		}
562#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
563	}
564
565	if (params->client_cert && params->private_key) {
566		/* TODO: private_key_passwd? */
567		ret = gnutls_certificate_set_x509_key_file(
568			conn->xcred, params->client_cert, params->private_key,
569			GNUTLS_X509_FMT_PEM);
570		if (ret < 0) {
571			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
572				   "in PEM format: %s", gnutls_strerror(ret));
573			ret = gnutls_certificate_set_x509_key_file(
574				conn->xcred, params->client_cert,
575				params->private_key, GNUTLS_X509_FMT_DER);
576			if (ret < 0) {
577				wpa_printf(MSG_DEBUG, "Failed to read client "
578					   "cert/key in DER format: %s",
579					   gnutls_strerror(ret));
580				return ret;
581			}
582		}
583	} else if (params->private_key) {
584		int pkcs12_ok = 0;
585#ifdef PKCS12_FUNCS
586		/* Try to load in PKCS#12 format */
587#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
588		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
589			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
590			params->private_key_passwd);
591		if (ret != 0) {
592			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
593				   "PKCS#12 format: %s", gnutls_strerror(ret));
594			return -1;
595		} else
596			pkcs12_ok = 1;
597#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
598#endif /* PKCS12_FUNCS */
599
600		if (!pkcs12_ok) {
601			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
602				   "included");
603			return -1;
604		}
605	}
606
607	conn->params_set = 1;
608
609	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
610				     conn->xcred);
611	if (ret < 0) {
612		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
613			   gnutls_strerror(ret));
614	}
615
616	return ret;
617}
618
619
620int tls_global_set_params(void *tls_ctx,
621			  const struct tls_connection_params *params)
622{
623	struct tls_global *global = tls_ctx;
624	int ret;
625
626	/* Currently, global parameters are only set when running in server
627	 * mode. */
628	global->server = 1;
629
630	if (global->params_set) {
631		gnutls_certificate_free_credentials(global->xcred);
632		global->params_set = 0;
633	}
634
635	ret = gnutls_certificate_allocate_credentials(&global->xcred);
636	if (ret) {
637		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
638			   "%s", gnutls_strerror(ret));
639		return -1;
640	}
641
642	if (params->ca_cert) {
643		ret = gnutls_certificate_set_x509_trust_file(
644			global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
645		if (ret < 0) {
646			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
647				   "in PEM format: %s", params->ca_cert,
648				   gnutls_strerror(ret));
649			ret = gnutls_certificate_set_x509_trust_file(
650				global->xcred, params->ca_cert,
651				GNUTLS_X509_FMT_DER);
652			if (ret < 0) {
653				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
654					   "'%s' in DER format: %s",
655					   params->ca_cert,
656					   gnutls_strerror(ret));
657				goto fail;
658			}
659		}
660
661		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
662			gnutls_certificate_set_verify_flags(
663				global->xcred,
664				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
665		}
666
667#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
668		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
669			gnutls_certificate_set_verify_flags(
670				global->xcred,
671				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
672		}
673#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
674	}
675
676	if (params->client_cert && params->private_key) {
677		/* TODO: private_key_passwd? */
678		ret = gnutls_certificate_set_x509_key_file(
679			global->xcred, params->client_cert,
680			params->private_key, GNUTLS_X509_FMT_PEM);
681		if (ret < 0) {
682			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
683				   "in PEM format: %s", gnutls_strerror(ret));
684			ret = gnutls_certificate_set_x509_key_file(
685				global->xcred, params->client_cert,
686				params->private_key, GNUTLS_X509_FMT_DER);
687			if (ret < 0) {
688				wpa_printf(MSG_DEBUG, "Failed to read client "
689					   "cert/key in DER format: %s",
690					   gnutls_strerror(ret));
691				goto fail;
692			}
693		}
694	} else if (params->private_key) {
695		int pkcs12_ok = 0;
696#ifdef PKCS12_FUNCS
697		/* Try to load in PKCS#12 format */
698#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
699		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
700			global->xcred, params->private_key,
701			GNUTLS_X509_FMT_DER, params->private_key_passwd);
702		if (ret != 0) {
703			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
704				   "PKCS#12 format: %s", gnutls_strerror(ret));
705			goto fail;
706		} else
707			pkcs12_ok = 1;
708#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
709#endif /* PKCS12_FUNCS */
710
711		if (!pkcs12_ok) {
712			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
713				   "included");
714			goto fail;
715		}
716	}
717
718	global->params_set = 1;
719
720	return 0;
721
722fail:
723	gnutls_certificate_free_credentials(global->xcred);
724	return -1;
725}
726
727
728int tls_global_set_verify(void *ssl_ctx, int check_crl)
729{
730	/* TODO */
731	return 0;
732}
733
734
735int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
736			      int verify_peer)
737{
738	if (conn == NULL || conn->session == NULL)
739		return -1;
740
741	conn->verify_peer = verify_peer;
742	gnutls_certificate_server_set_request(conn->session,
743					      verify_peer ? GNUTLS_CERT_REQUIRE
744					      : GNUTLS_CERT_REQUEST);
745
746	return 0;
747}
748
749
750int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
751			    struct tls_keys *keys)
752{
753#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
754	security_parameters_st *sec;
755#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
756
757	if (conn == NULL || conn->session == NULL || keys == NULL)
758		return -1;
759
760	os_memset(keys, 0, sizeof(*keys));
761
762#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
763#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
764	sec = &conn->session->security_parameters;
765	keys->master_key = sec->master_secret;
766	keys->master_key_len = WPA_TLS_MASTER_SIZE;
767	keys->client_random = sec->client_random;
768	keys->server_random = sec->server_random;
769#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
770	keys->client_random =
771		(u8 *) gnutls_session_get_client_random(conn->session);
772	keys->server_random =
773		(u8 *) gnutls_session_get_server_random(conn->session);
774	/* No access to master_secret */
775#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
776#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
777
778#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
779	keys->client_random_len = WPA_TLS_RANDOM_SIZE;
780	keys->server_random_len = WPA_TLS_RANDOM_SIZE;
781#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
782
783	return 0;
784}
785
786
787int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
788		       const char *label, int server_random_first,
789		       u8 *out, size_t out_len)
790{
791#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
792	if (conn == NULL || conn->session == NULL)
793		return -1;
794
795	return gnutls_prf(conn->session, os_strlen(label), label,
796			  server_random_first, 0, NULL, out_len, (char *) out);
797#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
798	return -1;
799#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
800}
801
802
803static int tls_connection_verify_peer(struct tls_connection *conn,
804				      gnutls_alert_description_t *err)
805{
806	unsigned int status, num_certs, i;
807	struct os_time now;
808	const gnutls_datum_t *certs;
809	gnutls_x509_crt_t cert;
810
811	if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
812		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
813			   "certificate chain");
814		*err = GNUTLS_A_INTERNAL_ERROR;
815		return -1;
816	}
817
818	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
819		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
820		*err = GNUTLS_A_INTERNAL_ERROR;
821		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
822			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
823				   "algorithm");
824			*err = GNUTLS_A_INSUFFICIENT_SECURITY;
825		}
826#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
827		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
828			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
829				   "activated");
830			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
831		}
832		if (status & GNUTLS_CERT_EXPIRED) {
833			wpa_printf(MSG_INFO, "TLS: Certificate expired");
834			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
835		}
836#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
837		return -1;
838	}
839
840	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
841		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
842			   "known issuer");
843		*err = GNUTLS_A_UNKNOWN_CA;
844		return -1;
845	}
846
847	if (status & GNUTLS_CERT_REVOKED) {
848		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
849		*err = GNUTLS_A_CERTIFICATE_REVOKED;
850		return -1;
851	}
852
853	os_get_time(&now);
854
855	certs = gnutls_certificate_get_peers(conn->session, &num_certs);
856	if (certs == NULL) {
857		wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
858			   "received");
859		*err = GNUTLS_A_UNKNOWN_CA;
860		return -1;
861	}
862
863	for (i = 0; i < num_certs; i++) {
864		char *buf;
865		size_t len;
866		if (gnutls_x509_crt_init(&cert) < 0) {
867			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
868				   "failed");
869			*err = GNUTLS_A_BAD_CERTIFICATE;
870			return -1;
871		}
872
873		if (gnutls_x509_crt_import(cert, &certs[i],
874					   GNUTLS_X509_FMT_DER) < 0) {
875			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
876				   "certificate %d/%d", i + 1, num_certs);
877			gnutls_x509_crt_deinit(cert);
878			*err = GNUTLS_A_BAD_CERTIFICATE;
879			return -1;
880		}
881
882		gnutls_x509_crt_get_dn(cert, NULL, &len);
883		len++;
884		buf = os_malloc(len + 1);
885		if (buf) {
886			buf[0] = buf[len] = '\0';
887			gnutls_x509_crt_get_dn(cert, buf, &len);
888		}
889		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
890			   i + 1, num_certs, buf);
891
892		if (i == 0) {
893			/* TODO: validate subject_match and altsubject_match */
894		}
895
896		os_free(buf);
897
898		if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
899		    gnutls_x509_crt_get_activation_time(cert) > now.sec) {
900			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
901				   "not valid at this time",
902				   i + 1, num_certs);
903			gnutls_x509_crt_deinit(cert);
904			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
905			return -1;
906		}
907
908		gnutls_x509_crt_deinit(cert);
909	}
910
911	return 0;
912}
913
914
915static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
916{
917	int res;
918	struct wpabuf *ad;
919	wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
920	ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
921	if (ad == NULL)
922		return NULL;
923
924	res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
925				 wpabuf_size(ad));
926	wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
927	if (res < 0) {
928		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
929			   "(%s)", __func__, (int) res,
930			   gnutls_strerror(res));
931		wpabuf_free(ad);
932		return NULL;
933	}
934
935	wpabuf_put(ad, res);
936	wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
937		   res);
938	return ad;
939}
940
941
942struct wpabuf * tls_connection_handshake(void *tls_ctx,
943					 struct tls_connection *conn,
944					 const struct wpabuf *in_data,
945					 struct wpabuf **appl_data)
946{
947	struct tls_global *global = tls_ctx;
948	struct wpabuf *out_data;
949	int ret;
950
951	if (appl_data)
952		*appl_data = NULL;
953
954	if (in_data && wpabuf_len(in_data) > 0) {
955		if (conn->pull_buf) {
956			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
957				   "pull_buf", __func__,
958				   (unsigned long) wpabuf_len(conn->pull_buf));
959			wpabuf_free(conn->pull_buf);
960		}
961		conn->pull_buf = wpabuf_dup(in_data);
962		if (conn->pull_buf == NULL)
963			return NULL;
964		conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
965	}
966
967	ret = gnutls_handshake(conn->session);
968	if (ret < 0) {
969		switch (ret) {
970		case GNUTLS_E_AGAIN:
971			if (global->server && conn->established &&
972			    conn->push_buf == NULL) {
973				/* Need to return something to trigger
974				 * completion of EAP-TLS. */
975				conn->push_buf = wpabuf_alloc(0);
976			}
977			break;
978		case GNUTLS_E_FATAL_ALERT_RECEIVED:
979			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
980				   __func__, gnutls_alert_get_name(
981					   gnutls_alert_get(conn->session)));
982			conn->read_alerts++;
983			/* continue */
984		default:
985			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
986				   "-> %s", __func__, gnutls_strerror(ret));
987			conn->failed++;
988		}
989	} else {
990		size_t size;
991		gnutls_alert_description_t err;
992
993		if (conn->verify_peer &&
994		    tls_connection_verify_peer(conn, &err)) {
995			wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
996				   "failed validation");
997			conn->failed++;
998			gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
999			goto out;
1000		}
1001
1002		wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
1003		conn->established = 1;
1004		if (conn->push_buf == NULL) {
1005			/* Need to return something to get final TLS ACK. */
1006			conn->push_buf = wpabuf_alloc(0);
1007		}
1008
1009		gnutls_session_get_data(conn->session, NULL, &size);
1010		if (global->session_data == NULL ||
1011		    global->session_data_size < size) {
1012			os_free(global->session_data);
1013			global->session_data = os_malloc(size);
1014		}
1015		if (global->session_data) {
1016			global->session_data_size = size;
1017			gnutls_session_get_data(conn->session,
1018						global->session_data,
1019						&global->session_data_size);
1020		}
1021
1022		if (conn->pull_buf && appl_data)
1023			*appl_data = gnutls_get_appl_data(conn);
1024	}
1025
1026out:
1027	out_data = conn->push_buf;
1028	conn->push_buf = NULL;
1029	return out_data;
1030}
1031
1032
1033struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1034						struct tls_connection *conn,
1035						const struct wpabuf *in_data,
1036						struct wpabuf **appl_data)
1037{
1038	return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1039}
1040
1041
1042struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1043				       struct tls_connection *conn,
1044				       const struct wpabuf *in_data)
1045{
1046	ssize_t res;
1047	struct wpabuf *buf;
1048
1049	res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1050				 wpabuf_len(in_data));
1051	if (res < 0) {
1052		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1053			   __func__, gnutls_strerror(res));
1054		return NULL;
1055	}
1056
1057	buf = conn->push_buf;
1058	conn->push_buf = NULL;
1059	return buf;
1060}
1061
1062
1063struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1064				       struct tls_connection *conn,
1065				       const struct wpabuf *in_data)
1066{
1067	ssize_t res;
1068	struct wpabuf *out;
1069
1070	if (conn->pull_buf) {
1071		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1072			   "pull_buf", __func__,
1073			   (unsigned long) wpabuf_len(conn->pull_buf));
1074		wpabuf_free(conn->pull_buf);
1075	}
1076	conn->pull_buf = wpabuf_dup(in_data);
1077	if (conn->pull_buf == NULL)
1078		return NULL;
1079	conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1080
1081	/*
1082	 * Even though we try to disable TLS compression, it is possible that
1083	 * this cannot be done with all TLS libraries. Add extra buffer space
1084	 * to handle the possibility of the decrypted data being longer than
1085	 * input data.
1086	 */
1087	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1088	if (out == NULL)
1089		return NULL;
1090
1091	res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1092				 wpabuf_size(out));
1093	if (res < 0) {
1094		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1095			   "(%s)", __func__, (int) res, gnutls_strerror(res));
1096		wpabuf_free(out);
1097		return NULL;
1098	}
1099	wpabuf_put(out, res);
1100
1101	return out;
1102}
1103
1104
1105int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1106{
1107	if (conn == NULL)
1108		return 0;
1109	return gnutls_session_is_resumed(conn->session);
1110}
1111
1112
1113int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1114				   u8 *ciphers)
1115{
1116	/* TODO */
1117	return -1;
1118}
1119
1120
1121int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1122		   char *buf, size_t buflen)
1123{
1124	/* TODO */
1125	buf[0] = '\0';
1126	return 0;
1127}
1128
1129
1130int tls_connection_enable_workaround(void *ssl_ctx,
1131				     struct tls_connection *conn)
1132{
1133	gnutls_record_disable_padding(conn->session);
1134	return 0;
1135}
1136
1137
1138int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1139				    int ext_type, const u8 *data,
1140				    size_t data_len)
1141{
1142	/* TODO */
1143	return -1;
1144}
1145
1146
1147int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1148{
1149	if (conn == NULL)
1150		return -1;
1151	return conn->failed;
1152}
1153
1154
1155int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1156{
1157	if (conn == NULL)
1158		return -1;
1159	return conn->read_alerts;
1160}
1161
1162
1163int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1164{
1165	if (conn == NULL)
1166		return -1;
1167	return conn->write_alerts;
1168}
1169
1170
1171int tls_connection_get_keyblock_size(void *tls_ctx,
1172				     struct tls_connection *conn)
1173{
1174	/* TODO */
1175	return -1;
1176}
1177
1178
1179unsigned int tls_capabilities(void *tls_ctx)
1180{
1181	return 0;
1182}
1183
1184
1185int tls_connection_set_session_ticket_cb(void *tls_ctx,
1186					 struct tls_connection *conn,
1187					 tls_session_ticket_cb cb, void *ctx)
1188{
1189	return -1;
1190}
1191