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. */
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	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
138static 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
164extern int wpa_debug_show_keys;
165
166void * 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
218void 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
234int tls_get_errors(void *ssl_ctx)
235{
236	return 0;
237}
238
239
240static 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
269static 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
288static 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
321fail:
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
329struct 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
365void 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
392int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
393{
394	return conn ? conn->established : 0;
395}
396
397
398int 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
455static 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
506static 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
552int 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
689int 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
789fail:
790	gnutls_certificate_free_credentials(global->xcred);
791	return -1;
792}
793
794
795int tls_global_set_verify(void *ssl_ctx, int check_crl)
796{
797	/* TODO */
798	return 0;
799}
800
801
802int 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
817int 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
857int 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
873static 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
982u8 * 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
1078out:
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
1087u8 * 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
1097int 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
1134int 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
1218int 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
1226int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1227				   u8 *ciphers)
1228{
1229	/* TODO */
1230	return -1;
1231}
1232
1233
1234int 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
1243int 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
1251int 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
1260int 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
1268int 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
1276int 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
1284int tls_connection_get_keyblock_size(void *tls_ctx,
1285				     struct tls_connection *conn)
1286{
1287	/* TODO */
1288	return -1;
1289}
1290
1291
1292unsigned 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
1304int 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
1341int 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
1389int 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
1399int 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