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