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 
42 typedef u8 uint8;
43 typedef unsigned char opaque;
44 typedef struct {
45     uint8 suite[2];
46 } cipher_suite_st;
47 
48 typedef 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 
64 struct 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 
70 static int tls_gnutls_ref_count = 0;
71 
72 struct 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 
83 struct 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 
102 static 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 
128 void * 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 
180 void 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 
196 int tls_get_errors(void *ssl_ctx)
197 {
198 	return 0;
199 }
200 
201 
202 static 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 
231 static 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 
246 static 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 
293 fail:
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 
301 struct 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 
337 void 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 
353 int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
354 {
355 	return conn ? conn->established : 0;
356 }
357 
358 
359 int 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
407 static 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
458 static 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 
504 int 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 
620 int 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 
722 fail:
723 	gnutls_certificate_free_credentials(global->xcred);
724 	return -1;
725 }
726 
727 
728 int tls_global_set_verify(void *ssl_ctx, int check_crl)
729 {
730 	/* TODO */
731 	return 0;
732 }
733 
734 
735 int 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 
750 int 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 
787 int 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 
803 static 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 
915 static 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 
942 struct 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 
1026 out:
1027 	out_data = conn->push_buf;
1028 	conn->push_buf = NULL;
1029 	return out_data;
1030 }
1031 
1032 
1033 struct 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 
1042 struct 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 
1063 struct 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 
1105 int 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 
1113 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1114 				   u8 *ciphers)
1115 {
1116 	/* TODO */
1117 	return -1;
1118 }
1119 
1120 
1121 int 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 
1130 int 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 
1138 int 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 
1147 int 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 
1155 int 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 
1163 int 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 
1171 int tls_connection_get_keyblock_size(void *tls_ctx,
1172 				     struct tls_connection *conn)
1173 {
1174 	/* TODO */
1175 	return -1;
1176 }
1177 
1178 
1179 unsigned int tls_capabilities(void *tls_ctx)
1180 {
1181 	return 0;
1182 }
1183 
1184 
1185 int 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