xref: /freebsd/contrib/wpa/src/crypto/tls_gnutls.c (revision f05cddf9)
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 extern int wpa_debug_show_keys;
129 
130 void * 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 
182 void 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 
198 int tls_get_errors(void *ssl_ctx)
199 {
200 	return 0;
201 }
202 
203 
204 static 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 
233 static 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 
248 static 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 
295 fail:
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 
303 struct 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 
339 void 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 
355 int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
356 {
357 	return conn ? conn->established : 0;
358 }
359 
360 
361 int 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
409 static 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
460 static 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 
506 int 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 
622 int 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 
724 fail:
725 	gnutls_certificate_free_credentials(global->xcred);
726 	return -1;
727 }
728 
729 
730 int tls_global_set_verify(void *ssl_ctx, int check_crl)
731 {
732 	/* TODO */
733 	return 0;
734 }
735 
736 
737 int 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 
752 int 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 
789 int 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 
805 static 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 
917 static 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 
944 struct 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 
1028 out:
1029 	out_data = conn->push_buf;
1030 	conn->push_buf = NULL;
1031 	return out_data;
1032 }
1033 
1034 
1035 struct 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 
1044 struct 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 
1065 struct 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 
1107 int 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 
1115 int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1116 				   u8 *ciphers)
1117 {
1118 	/* TODO */
1119 	return -1;
1120 }
1121 
1122 
1123 int 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 
1132 int 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 
1140 int 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 
1149 int 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 
1157 int 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 
1165 int 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 
1173 int tls_connection_get_keyblock_size(void *tls_ctx,
1174 				     struct tls_connection *conn)
1175 {
1176 	/* TODO */
1177 	return -1;
1178 }
1179 
1180 
1181 unsigned int tls_capabilities(void *tls_ctx)
1182 {
1183 	return 0;
1184 }
1185 
1186 
1187 int 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