tls_gnutls.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
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. */
29int 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
64typedef u8 uint8;
65typedef unsigned char opaque;
66typedef struct {
67    uint8 suite[2];
68} cipher_suite_st;
69
70typedef 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
86struct 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
92static int tls_gnutls_ref_count = 0;
93
94struct 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
105struct 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
139static 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
165extern int wpa_debug_show_keys;
166
167void * 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
219void 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
235int tls_get_errors(void *ssl_ctx)
236{
237	return 0;
238}
239
240
241static 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
270static 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
285static 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
318fail:
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
326struct 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
362void 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
389int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
390{
391	return conn ? conn->established : 0;
392}
393
394
395int 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
451static 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
502static 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
548int 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
685int 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
785fail:
786	gnutls_certificate_free_credentials(global->xcred);
787	return -1;
788}
789
790
791int tls_global_set_verify(void *ssl_ctx, int check_crl)
792{
793	/* TODO */
794	return 0;
795}
796
797
798int 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
813int 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
853int 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
869static 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
978static 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
1005struct 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
1102out:
1103	out_data = conn->push_buf;
1104	conn->push_buf = NULL;
1105	return out_data;
1106}
1107
1108
1109struct 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
1118struct 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
1145struct 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
1246int 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
1254int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1255				   u8 *ciphers)
1256{
1257	/* TODO */
1258	return -1;
1259}
1260
1261
1262int 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
1271int 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
1279int 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
1288int 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
1296int 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
1304int 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
1312int tls_connection_get_keyblock_size(void *tls_ctx,
1313				     struct tls_connection *conn)
1314{
1315	/* TODO */
1316	return -1;
1317}
1318
1319
1320unsigned 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
1332int 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
1369struct 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
1410int 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
1420int 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
1452int 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