tls_gnutls.c revision 214734
1132718Skan/*
2169689Skan * SSL/TLS interface functions for GnuTLS
3132718Skan * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
4132718Skan *
5132718Skan * This program is free software; you can redistribute it and/or modify
6132718Skan * it under the terms of the GNU General Public License version 2 as
7132718Skan * published by the Free Software Foundation.
8132718Skan *
9132718Skan * Alternatively, this software may be distributed under the terms of BSD
10132718Skan * license.
11132718Skan *
12132718Skan * See README and COPYING for more details.
13132718Skan */
14132718Skan
15132718Skan#include "includes.h"
16132718Skan#include <gnutls/gnutls.h>
17132718Skan#include <gnutls/x509.h>
18132718Skan#ifdef PKCS12_FUNCS
19169689Skan#include <gnutls/pkcs12.h>
20169689Skan#endif /* PKCS12_FUNCS */
21132718Skan
22132718Skan#ifdef CONFIG_GNUTLS_EXTRA
23132718Skan#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
24169689Skan#define GNUTLS_IA
25169689Skan#include <gnutls/extra.h>
26132718Skan#if LIBGNUTLS_VERSION_NUMBER == 0x010302
27169689Skan/* This function is not included in the current gnutls/extra.h even though it
28169689Skan * should be, so define it here as a workaround for the time being. */
29169689Skanint gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
30169689Skan#endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */
31169689Skan#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
32169689Skan#endif /* CONFIG_GNUTLS_EXTRA */
33169689Skan
34169689Skan#include "common.h"
35169689Skan#include "tls.h"
36169689Skan
37169689Skan
38169689Skan#ifndef TLS_RANDOM_SIZE
39169689Skan#define TLS_RANDOM_SIZE 32
40169689Skan#endif
41169689Skan#ifndef TLS_MASTER_SIZE
42169689Skan#define TLS_MASTER_SIZE 48
43169689Skan#endif
44169689Skan
45169689Skan
46169689Skan#if LIBGNUTLS_VERSION_NUMBER < 0x010302
47169689Skan/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
48169689Skan * use of internal structures to get the master_secret and
49132718Skan * {server,client}_random.
50132718Skan */
51132718Skan#define GNUTLS_INTERNAL_STRUCTURE_HACK
52132718Skan#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
53132718Skan
54132718Skan
55132718Skan#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
56132718Skan/*
57132718Skan * It looks like gnutls does not provide access to client/server_random and
58169689Skan * master_key. This is somewhat unfortunate since these are needed for key
59169689Skan * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
60169689Skan * hack that copies the gnutls_session_int definition from gnutls_int.h so that
61169689Skan * we can get the needed information.
62169689Skan */
63169689Skan
64132718Skantypedef u8 uint8;
65169689Skantypedef unsigned char opaque;
66132718Skantypedef struct {
67132718Skan    uint8 suite[2];
68169689Skan} cipher_suite_st;
69169689Skan
70169689Skantypedef struct {
71169689Skan	gnutls_connection_end_t entity;
72169689Skan	gnutls_kx_algorithm_t kx_algorithm;
73132718Skan	gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
74132718Skan	gnutls_mac_algorithm_t read_mac_algorithm;
75169689Skan	gnutls_compression_method_t read_compression_algorithm;
76169689Skan	gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
77169689Skan	gnutls_mac_algorithm_t write_mac_algorithm;
78169689Skan	gnutls_compression_method_t write_compression_algorithm;
79169689Skan	cipher_suite_st current_cipher_suite;
80169689Skan	opaque master_secret[TLS_MASTER_SIZE];
81169689Skan	opaque client_random[TLS_RANDOM_SIZE];
82169689Skan	opaque server_random[TLS_RANDOM_SIZE];
83169689Skan	/* followed by stuff we are not interested in */
84132718Skan} security_parameters_st;
85132718Skan
86132718Skanstruct gnutls_session_int {
87132718Skan	security_parameters_st security_parameters;
88132718Skan	/* followed by things we are not interested in */
89132718Skan};
90132718Skan#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
91169689Skan
92169689Skanstatic int tls_gnutls_ref_count = 0;
93169689Skan
94132718Skanstruct tls_global {
95132718Skan	/* Data for session resumption */
96132718Skan	void *session_data;
97169689Skan	size_t session_data_size;
98169689Skan
99132718Skan	int server;
100169689Skan
101132718Skan	int params_set;
102132718Skan	gnutls_certificate_credentials_t xcred;
103132718Skan};
104132718Skan
105132718Skanstruct tls_connection {
106132718Skan	gnutls_session session;
107132718Skan	char *subject_match, *altsubject_match;
108132718Skan	int read_alerts, write_alerts, failed;
109132718Skan
110132718Skan	u8 *pre_shared_secret;
111132718Skan	size_t pre_shared_secret_len;
112132718Skan	int established;
113132718Skan	int verify_peer;
114132718Skan
115132718Skan	struct wpabuf *push_buf;
116132718Skan	struct wpabuf *pull_buf;
117132718Skan	const u8 *pull_buf_offset;
118132718Skan
119132718Skan	int params_set;
120132718Skan	gnutls_certificate_credentials_t xcred;
121132718Skan
122132718Skan	int tls_ia;
123132718Skan	int final_phase_finished;
124132718Skan
125132718Skan#ifdef GNUTLS_IA
126132718Skan	gnutls_ia_server_credentials_t iacred_srv;
127132718Skan	gnutls_ia_client_credentials_t iacred_cli;
128132718Skan
129132718Skan	/* Session keys generated in the current phase for inner secret
130169689Skan	 * permutation before generating/verifying PhaseFinished. */
131169689Skan	u8 *session_keys;
132169689Skan	size_t session_keys_len;
133169689Skan
134169689Skan	u8 inner_secret[TLS_MASTER_SIZE];
135169689Skan#endif /* GNUTLS_IA */
136169689Skan};
137169689Skan
138169689Skan
139132718Skanstatic void tls_log_func(int level, const char *msg)
140169689Skan{
141169689Skan	char *s, *pos;
142132718Skan	if (level == 6 || level == 7) {
143132718Skan		/* These levels seem to be mostly I/O debug and msg dumps */
144132718Skan		return;
145169689Skan	}
146169689Skan
147169689Skan	s = os_strdup(msg);
148132718Skan	if (s == NULL)
149132718Skan		return;
150169689Skan
151169689Skan	pos = s;
152169689Skan	while (*pos != '\0') {
153132718Skan		if (*pos == '\n') {
154169689Skan			*pos = '\0';
155169689Skan			break;
156132718Skan		}
157132718Skan		pos++;
158169689Skan	}
159169689Skan	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
160169689Skan		   "gnutls<%d> %s", level, s);
161132718Skan	os_free(s);
162132718Skan}
163169689Skan
164132718Skan
165169689Skanextern int wpa_debug_show_keys;
166169689Skan
167169689Skanvoid * tls_init(const struct tls_config *conf)
168169689Skan{
169169689Skan	struct tls_global *global;
170169689Skan
171169689Skan#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
172169689Skan	/* Because of the horrible hack to get master_secret and client/server
173132718Skan	 * random, we need to make sure that the gnutls version is something
174132718Skan	 * that is expected to have same structure definition for the session
175169689Skan	 * data.. */
176132718Skan	const char *ver;
177132718Skan	const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
178132718Skan				 "1.3.2",
179169689Skan				 NULL };
180132718Skan	int i;
181169689Skan#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
182132718Skan
183169689Skan	global = os_zalloc(sizeof(*global));
184169689Skan	if (global == NULL)
185132718Skan		return NULL;
186132718Skan
187132718Skan	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
188169689Skan		os_free(global);
189169689Skan		return NULL;
190169689Skan	}
191169689Skan	tls_gnutls_ref_count++;
192132718Skan
193132718Skan#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
194169689Skan	ver = gnutls_check_version(NULL);
195169689Skan	if (ver == NULL) {
196169689Skan		tls_deinit(global);
197169689Skan		return NULL;
198169689Skan	}
199132718Skan	wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
200132718Skan	for (i = 0; ok_ver[i]; i++) {
201132718Skan		if (strcmp(ok_ver[i], ver) == 0)
202132718Skan			break;
203132718Skan	}
204132718Skan	if (ok_ver[i] == NULL) {
205169689Skan		wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
206169689Skan			   "to be tested and enabled in tls_gnutls.c", ver);
207132718Skan		tls_deinit(global);
208132718Skan		return NULL;
209169689Skan	}
210169689Skan#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
211132718Skan
212132718Skan	gnutls_global_set_log_function(tls_log_func);
213169689Skan	if (wpa_debug_show_keys)
214169689Skan		gnutls_global_set_log_level(11);
215169689Skan	return global;
216169689Skan}
217169689Skan
218169689Skan
219169689Skanvoid tls_deinit(void *ssl_ctx)
220169689Skan{
221132718Skan	struct tls_global *global = ssl_ctx;
222169689Skan	if (global) {
223169689Skan		if (global->params_set)
224169689Skan			gnutls_certificate_free_credentials(global->xcred);
225169689Skan		os_free(global->session_data);
226169689Skan		os_free(global);
227169689Skan	}
228169689Skan
229132718Skan	tls_gnutls_ref_count--;
230132718Skan	if (tls_gnutls_ref_count == 0)
231169689Skan		gnutls_global_deinit();
232169689Skan}
233169689Skan
234169689Skan
235169689Skanint tls_get_errors(void *ssl_ctx)
236169689Skan{
237169689Skan	return 0;
238169689Skan}
239169689Skan
240169689Skan
241169689Skanstatic ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
242169689Skan			     size_t len)
243132718Skan{
244132718Skan	struct tls_connection *conn = (struct tls_connection *) ptr;
245132718Skan	const u8 *end;
246132718Skan	if (conn->pull_buf == NULL) {
247169689Skan		errno = EWOULDBLOCK;
248132718Skan		return -1;
249169689Skan	}
250132718Skan
251169689Skan	end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
252169689Skan	if ((size_t) (end - conn->pull_buf_offset) < len)
253132718Skan		len = end - conn->pull_buf_offset;
254169689Skan	os_memcpy(buf, conn->pull_buf_offset, len);
255169689Skan	conn->pull_buf_offset += len;
256169689Skan	if (conn->pull_buf_offset == end) {
257132718Skan		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
258132718Skan		wpabuf_free(conn->pull_buf);
259132718Skan		conn->pull_buf = NULL;
260169689Skan		conn->pull_buf_offset = NULL;
261169689Skan	} else {
262169689Skan		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
263169689Skan			   __func__,
264169689Skan			   (unsigned long) (end - conn->pull_buf_offset));
265132718Skan	}
266169689Skan	return len;
267169689Skan}
268169689Skan
269169689Skan
270169689Skanstatic ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
271169689Skan			     size_t len)
272169689Skan{
273169689Skan	struct tls_connection *conn = (struct tls_connection *) ptr;
274132718Skan
275132718Skan	if (wpabuf_resize(&conn->push_buf, len) < 0) {
276132718Skan		errno = ENOMEM;
277132718Skan		return -1;
278169689Skan	}
279169689Skan	wpabuf_put_data(conn->push_buf, buf, len);
280169689Skan
281169689Skan	return len;
282169689Skan}
283132718Skan
284169689Skan
285169689Skanstatic int tls_gnutls_init_session(struct tls_global *global,
286132718Skan				   struct tls_connection *conn)
287132718Skan{
288169689Skan	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
289132718Skan	const int protos[2] = { GNUTLS_TLS1, 0 };
290169689Skan	int ret;
291169689Skan
292132718Skan	ret = gnutls_init(&conn->session,
293169689Skan			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
294169689Skan	if (ret < 0) {
295169689Skan		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
296169689Skan			   "connection: %s", gnutls_strerror(ret));
297132718Skan		return -1;
298169689Skan	}
299169689Skan
300169689Skan	ret = gnutls_set_default_priority(conn->session);
301169689Skan	if (ret < 0)
302169689Skan		goto fail;
303169689Skan
304132718Skan	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
305261188Spfg	if (ret < 0)
306261188Spfg		goto fail;
307132718Skan
308169689Skan	ret = gnutls_protocol_set_priority(conn->session, protos);
309132718Skan	if (ret < 0)
310132718Skan		goto fail;
311132718Skan
312132718Skan	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
313132718Skan	gnutls_transport_set_push_function(conn->session, tls_push_func);
314169689Skan	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
315169689Skan
316169689Skan	return 0;
317169689Skan
318169689Skanfail:
319169689Skan	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
320169689Skan		   gnutls_strerror(ret));
321169689Skan	gnutls_deinit(conn->session);
322169689Skan	return -1;
323169689Skan}
324169689Skan
325169689Skan
326132718Skanstruct tls_connection * tls_connection_init(void *ssl_ctx)
327169689Skan{
328169689Skan	struct tls_global *global = ssl_ctx;
329169689Skan	struct tls_connection *conn;
330169689Skan	int ret;
331169689Skan
332169689Skan	conn = os_zalloc(sizeof(*conn));
333169689Skan	if (conn == NULL)
334169689Skan		return NULL;
335169689Skan
336132718Skan	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