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