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