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