tls_gnutls.c revision 189261
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#define TLS_RANDOM_SIZE 32
39#define TLS_MASTER_SIZE 48
40
41
42#if LIBGNUTLS_VERSION_NUMBER < 0x010302
43/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
44 * use of internal structures to get the master_secret and
45 * {server,client}_random.
46 */
47#define GNUTLS_INTERNAL_STRUCTURE_HACK
48#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
49
50
51#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
52/*
53 * It looks like gnutls does not provide access to client/server_random and
54 * master_key. This is somewhat unfortunate since these are needed for key
55 * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
56 * hack that copies the gnutls_session_int definition from gnutls_int.h so that
57 * we can get the needed information.
58 */
59
60typedef u8 uint8;
61typedef unsigned char opaque;
62typedef struct {
63    uint8 suite[2];
64} cipher_suite_st;
65
66typedef struct {
67	gnutls_connection_end_t entity;
68	gnutls_kx_algorithm_t kx_algorithm;
69	gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
70	gnutls_mac_algorithm_t read_mac_algorithm;
71	gnutls_compression_method_t read_compression_algorithm;
72	gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
73	gnutls_mac_algorithm_t write_mac_algorithm;
74	gnutls_compression_method_t write_compression_algorithm;
75	cipher_suite_st current_cipher_suite;
76	opaque master_secret[TLS_MASTER_SIZE];
77	opaque client_random[TLS_RANDOM_SIZE];
78	opaque server_random[TLS_RANDOM_SIZE];
79	/* followed by stuff we are not interested in */
80} security_parameters_st;
81
82struct gnutls_session_int {
83	security_parameters_st security_parameters;
84	/* followed by things we are not interested in */
85};
86#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
87
88static int tls_gnutls_ref_count = 0;
89
90struct tls_global {
91	/* Data for session resumption */
92	void *session_data;
93	size_t session_data_size;
94
95	int server;
96
97	int params_set;
98	gnutls_certificate_credentials_t xcred;
99};
100
101struct tls_connection {
102	gnutls_session session;
103	char *subject_match, *altsubject_match;
104	int read_alerts, write_alerts, failed;
105
106	u8 *pre_shared_secret;
107	size_t pre_shared_secret_len;
108	int established;
109	int verify_peer;
110
111	u8 *push_buf, *pull_buf, *pull_buf_offset;
112	size_t push_buf_len, pull_buf_len;
113
114	int params_set;
115	gnutls_certificate_credentials_t xcred;
116
117	int tls_ia;
118	int final_phase_finished;
119
120#ifdef GNUTLS_IA
121	gnutls_ia_server_credentials_t iacred_srv;
122	gnutls_ia_client_credentials_t iacred_cli;
123
124	/* Session keys generated in the current phase for inner secret
125	 * permutation before generating/verifying PhaseFinished. */
126	u8 *session_keys;
127	size_t session_keys_len;
128
129	u8 inner_secret[TLS_MASTER_SIZE];
130#endif /* GNUTLS_IA */
131};
132
133
134static void tls_log_func(int level, const char *msg)
135{
136	char *s, *pos;
137	if (level == 6 || level == 7) {
138		/* These levels seem to be mostly I/O debug and msg dumps */
139		return;
140	}
141
142	s = os_strdup(msg);
143	if (s == NULL)
144		return;
145
146	pos = s;
147	while (*pos != '\0') {
148		if (*pos == '\n') {
149			*pos = '\0';
150			break;
151		}
152		pos++;
153	}
154	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
155		   "gnutls<%d> %s", level, s);
156	os_free(s);
157}
158
159
160extern int wpa_debug_show_keys;
161
162void * tls_init(const struct tls_config *conf)
163{
164	struct tls_global *global;
165
166#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
167	/* Because of the horrible hack to get master_secret and client/server
168	 * random, we need to make sure that the gnutls version is something
169	 * that is expected to have same structure definition for the session
170	 * data.. */
171	const char *ver;
172	const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
173				 "1.3.2",
174				 NULL };
175	int i;
176#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
177
178	global = os_zalloc(sizeof(*global));
179	if (global == NULL)
180		return NULL;
181
182	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
183		os_free(global);
184		return NULL;
185	}
186	tls_gnutls_ref_count++;
187
188#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
189	ver = gnutls_check_version(NULL);
190	if (ver == NULL) {
191		tls_deinit(global);
192		return NULL;
193	}
194	wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
195	for (i = 0; ok_ver[i]; i++) {
196		if (strcmp(ok_ver[i], ver) == 0)
197			break;
198	}
199	if (ok_ver[i] == NULL) {
200		wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
201			   "to be tested and enabled in tls_gnutls.c", ver);
202		tls_deinit(global);
203		return NULL;
204	}
205#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
206
207	gnutls_global_set_log_function(tls_log_func);
208	if (wpa_debug_show_keys)
209		gnutls_global_set_log_level(11);
210	return global;
211}
212
213
214void tls_deinit(void *ssl_ctx)
215{
216	struct tls_global *global = ssl_ctx;
217	if (global) {
218		if (global->params_set)
219			gnutls_certificate_free_credentials(global->xcred);
220		os_free(global->session_data);
221		os_free(global);
222	}
223
224	tls_gnutls_ref_count--;
225	if (tls_gnutls_ref_count == 0)
226		gnutls_global_deinit();
227}
228
229
230int tls_get_errors(void *ssl_ctx)
231{
232	return 0;
233}
234
235
236static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
237			     size_t len)
238{
239	struct tls_connection *conn = (struct tls_connection *) ptr;
240	u8 *end;
241	if (conn->pull_buf == NULL) {
242		errno = EWOULDBLOCK;
243		return -1;
244	}
245
246	end = conn->pull_buf + conn->pull_buf_len;
247	if ((size_t) (end - conn->pull_buf_offset) < len)
248		len = end - conn->pull_buf_offset;
249	os_memcpy(buf, conn->pull_buf_offset, len);
250	conn->pull_buf_offset += len;
251	if (conn->pull_buf_offset == end) {
252		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
253		os_free(conn->pull_buf);
254		conn->pull_buf = conn->pull_buf_offset = NULL;
255		conn->pull_buf_len = 0;
256	} else {
257		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
258			   __func__,
259			   (unsigned long) (end - conn->pull_buf_offset));
260	}
261	return len;
262}
263
264
265static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
266			     size_t len)
267{
268	struct tls_connection *conn = (struct tls_connection *) ptr;
269	u8 *nbuf;
270
271	nbuf = os_realloc(conn->push_buf, conn->push_buf_len + len);
272	if (nbuf == NULL) {
273		errno = ENOMEM;
274		return -1;
275	}
276	os_memcpy(nbuf + conn->push_buf_len, buf, len);
277	conn->push_buf = nbuf;
278	conn->push_buf_len += len;
279
280	return len;
281}
282
283
284static int tls_gnutls_init_session(struct tls_global *global,
285				   struct tls_connection *conn)
286{
287	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
288	const int protos[2] = { GNUTLS_TLS1, 0 };
289	int ret;
290
291	ret = gnutls_init(&conn->session,
292			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
293	if (ret < 0) {
294		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
295			   "connection: %s", gnutls_strerror(ret));
296		return -1;
297	}
298
299	ret = gnutls_set_default_priority(conn->session);
300	if (ret < 0)
301		goto fail;
302
303	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
304	if (ret < 0)
305		goto fail;
306
307	ret = gnutls_protocol_set_priority(conn->session, protos);
308	if (ret < 0)
309		goto fail;
310
311	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
312	gnutls_transport_set_push_function(conn->session, tls_push_func);
313	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
314
315	return 0;
316
317fail:
318	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
319		   gnutls_strerror(ret));
320	gnutls_deinit(conn->session);
321	return -1;
322}
323
324
325struct tls_connection * tls_connection_init(void *ssl_ctx)
326{
327	struct tls_global *global = ssl_ctx;
328	struct tls_connection *conn;
329	int ret;
330
331	conn = os_zalloc(sizeof(*conn));
332	if (conn == NULL)
333		return NULL;
334
335	if (tls_gnutls_init_session(global, conn)) {
336		os_free(conn);
337		return NULL;
338	}
339
340	if (global->params_set) {
341		ret = gnutls_credentials_set(conn->session,
342					     GNUTLS_CRD_CERTIFICATE,
343					     global->xcred);
344		if (ret < 0) {
345			wpa_printf(MSG_INFO, "Failed to configure "
346				   "credentials: %s", gnutls_strerror(ret));
347			os_free(conn);
348			return NULL;
349		}
350	}
351
352	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
353		os_free(conn);
354		return NULL;
355	}
356
357	return conn;
358}
359
360
361void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
362{
363	if (conn == NULL)
364		return;
365
366#ifdef GNUTLS_IA
367	if (conn->iacred_srv)
368		gnutls_ia_free_server_credentials(conn->iacred_srv);
369	if (conn->iacred_cli)
370		gnutls_ia_free_client_credentials(conn->iacred_cli);
371	if (conn->session_keys) {
372		os_memset(conn->session_keys, 0, conn->session_keys_len);
373		os_free(conn->session_keys);
374	}
375#endif /* GNUTLS_IA */
376
377	gnutls_certificate_free_credentials(conn->xcred);
378	gnutls_deinit(conn->session);
379	os_free(conn->pre_shared_secret);
380	os_free(conn->subject_match);
381	os_free(conn->altsubject_match);
382	os_free(conn->push_buf);
383	os_free(conn->pull_buf);
384	os_free(conn);
385}
386
387
388int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
389{
390	return conn ? conn->established : 0;
391}
392
393
394int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
395{
396	struct tls_global *global = ssl_ctx;
397	int ret;
398
399	if (conn == NULL)
400		return -1;
401
402	/* Shutdown previous TLS connection without notifying the peer
403	 * because the connection was already terminated in practice
404	 * and "close notify" shutdown alert would confuse AS. */
405	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
406	os_free(conn->push_buf);
407	conn->push_buf = NULL;
408	conn->push_buf_len = 0;
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
596	if (params->client_cert && params->private_key) {
597		/* TODO: private_key_passwd? */
598		ret = gnutls_certificate_set_x509_key_file(
599			conn->xcred, params->client_cert, params->private_key,
600			GNUTLS_X509_FMT_PEM);
601		if (ret < 0) {
602			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
603				   "in PEM format: %s", gnutls_strerror(ret));
604			ret = gnutls_certificate_set_x509_key_file(
605				conn->xcred, params->client_cert,
606				params->private_key, GNUTLS_X509_FMT_DER);
607			if (ret < 0) {
608				wpa_printf(MSG_DEBUG, "Failed to read client "
609					   "cert/key in DER format: %s",
610					   gnutls_strerror(ret));
611				return ret;
612			}
613		}
614	} else if (params->private_key) {
615		int pkcs12_ok = 0;
616#ifdef PKCS12_FUNCS
617		/* Try to load in PKCS#12 format */
618#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
619		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
620			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
621			params->private_key_passwd);
622		if (ret != 0) {
623			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
624				   "PKCS#12 format: %s", gnutls_strerror(ret));
625			return -1;
626		} else
627			pkcs12_ok = 1;
628#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
629#endif /* PKCS12_FUNCS */
630
631		if (!pkcs12_ok) {
632			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
633				   "included");
634			return -1;
635		}
636	}
637
638	conn->tls_ia = params->tls_ia;
639	conn->params_set = 1;
640
641	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
642				     conn->xcred);
643	if (ret < 0) {
644		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
645			   gnutls_strerror(ret));
646	}
647
648#ifdef GNUTLS_IA
649	if (conn->iacred_cli)
650		gnutls_ia_free_client_credentials(conn->iacred_cli);
651
652	ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli);
653	if (ret) {
654		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
655			   gnutls_strerror(ret));
656		return -1;
657	}
658
659	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
660				     conn->iacred_cli);
661	if (ret) {
662		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
663			   gnutls_strerror(ret));
664		gnutls_ia_free_client_credentials(conn->iacred_cli);
665		conn->iacred_cli = NULL;
666		return -1;
667	}
668#endif /* GNUTLS_IE */
669
670	return ret;
671}
672
673
674int tls_global_set_params(void *tls_ctx,
675			  const struct tls_connection_params *params)
676{
677	struct tls_global *global = tls_ctx;
678	int ret;
679
680	/* Currently, global parameters are only set when running in server
681	 * mode. */
682	global->server = 1;
683
684	if (global->params_set) {
685		gnutls_certificate_free_credentials(global->xcred);
686		global->params_set = 0;
687	}
688
689	ret = gnutls_certificate_allocate_credentials(&global->xcred);
690	if (ret) {
691		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
692			   "%s", gnutls_strerror(ret));
693		return -1;
694	}
695
696	if (params->ca_cert) {
697		ret = gnutls_certificate_set_x509_trust_file(
698			global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
699		if (ret < 0) {
700			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
701				   "in PEM format: %s", params->ca_cert,
702				   gnutls_strerror(ret));
703			ret = gnutls_certificate_set_x509_trust_file(
704				global->xcred, params->ca_cert,
705				GNUTLS_X509_FMT_DER);
706			if (ret < 0) {
707				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
708					   "'%s' in DER format: %s",
709					   params->ca_cert,
710					   gnutls_strerror(ret));
711				goto fail;
712			}
713		}
714	}
715
716	if (params->client_cert && params->private_key) {
717		/* TODO: private_key_passwd? */
718		ret = gnutls_certificate_set_x509_key_file(
719			global->xcred, params->client_cert,
720			params->private_key, GNUTLS_X509_FMT_PEM);
721		if (ret < 0) {
722			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
723				   "in PEM format: %s", gnutls_strerror(ret));
724			ret = gnutls_certificate_set_x509_key_file(
725				global->xcred, params->client_cert,
726				params->private_key, GNUTLS_X509_FMT_DER);
727			if (ret < 0) {
728				wpa_printf(MSG_DEBUG, "Failed to read client "
729					   "cert/key in DER format: %s",
730					   gnutls_strerror(ret));
731				goto fail;
732			}
733		}
734	} else if (params->private_key) {
735		int pkcs12_ok = 0;
736#ifdef PKCS12_FUNCS
737		/* Try to load in PKCS#12 format */
738#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
739		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
740			global->xcred, params->private_key,
741			GNUTLS_X509_FMT_DER, params->private_key_passwd);
742		if (ret != 0) {
743			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
744				   "PKCS#12 format: %s", gnutls_strerror(ret));
745			goto fail;
746		} else
747			pkcs12_ok = 1;
748#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
749#endif /* PKCS12_FUNCS */
750
751		if (!pkcs12_ok) {
752			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
753				   "included");
754			goto fail;
755		}
756	}
757
758	global->params_set = 1;
759
760	return 0;
761
762fail:
763	gnutls_certificate_free_credentials(global->xcred);
764	return -1;
765}
766
767
768int tls_global_set_verify(void *ssl_ctx, int check_crl)
769{
770	/* TODO */
771	return 0;
772}
773
774
775int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
776			      int verify_peer)
777{
778	if (conn == NULL || conn->session == NULL)
779		return -1;
780
781	conn->verify_peer = verify_peer;
782	gnutls_certificate_server_set_request(conn->session,
783					      verify_peer ? GNUTLS_CERT_REQUIRE
784					      : GNUTLS_CERT_REQUEST);
785
786	return 0;
787}
788
789
790int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
791			    struct tls_keys *keys)
792{
793#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
794	security_parameters_st *sec;
795#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
796
797	if (conn == NULL || conn->session == NULL || keys == NULL)
798		return -1;
799
800	os_memset(keys, 0, sizeof(*keys));
801
802#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
803	sec = &conn->session->security_parameters;
804	keys->master_key = sec->master_secret;
805	keys->master_key_len = TLS_MASTER_SIZE;
806	keys->client_random = sec->client_random;
807	keys->server_random = sec->server_random;
808#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
809	keys->client_random =
810		(u8 *) gnutls_session_get_client_random(conn->session);
811	keys->server_random =
812		(u8 *) gnutls_session_get_server_random(conn->session);
813	/* No access to master_secret */
814#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
815
816#ifdef GNUTLS_IA
817	gnutls_ia_extract_inner_secret(conn->session,
818				       (char *) conn->inner_secret);
819	keys->inner_secret = conn->inner_secret;
820	keys->inner_secret_len = TLS_MASTER_SIZE;
821#endif /* GNUTLS_IA */
822
823	keys->client_random_len = TLS_RANDOM_SIZE;
824	keys->server_random_len = TLS_RANDOM_SIZE;
825
826	return 0;
827}
828
829
830int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
831		       const char *label, int server_random_first,
832		       u8 *out, size_t out_len)
833{
834#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
835	if (conn == NULL || conn->session == NULL)
836		return -1;
837
838	return gnutls_prf(conn->session, os_strlen(label), label,
839			  server_random_first, 0, NULL, out_len, (char *) out);
840#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
841	return -1;
842#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
843}
844
845
846static int tls_connection_verify_peer(struct tls_connection *conn)
847{
848	unsigned int status, num_certs, i;
849	struct os_time now;
850	const gnutls_datum_t *certs;
851	gnutls_x509_crt_t cert;
852
853	if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
854		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
855			   "certificate chain");
856		return -1;
857	}
858
859	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
860		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
861		return -1;
862	}
863
864	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
865		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
866			   "known issuer");
867		return -1;
868	}
869
870	if (status & GNUTLS_CERT_REVOKED) {
871		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
872		return -1;
873	}
874
875	os_get_time(&now);
876
877	certs = gnutls_certificate_get_peers(conn->session, &num_certs);
878	if (certs == NULL) {
879		wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
880			   "received");
881		return -1;
882	}
883
884	for (i = 0; i < num_certs; i++) {
885		char *buf;
886		size_t len;
887		if (gnutls_x509_crt_init(&cert) < 0) {
888			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
889				   "failed");
890			return -1;
891		}
892
893		if (gnutls_x509_crt_import(cert, &certs[i],
894					   GNUTLS_X509_FMT_DER) < 0) {
895			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
896				   "certificate %d/%d", i + 1, num_certs);
897			gnutls_x509_crt_deinit(cert);
898			return -1;
899		}
900
901		gnutls_x509_crt_get_dn(cert, NULL, &len);
902		len++;
903		buf = os_malloc(len + 1);
904		if (buf) {
905			buf[0] = buf[len] = '\0';
906			gnutls_x509_crt_get_dn(cert, buf, &len);
907		}
908		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
909			   i + 1, num_certs, buf);
910
911		if (i == 0) {
912			/* TODO: validate subject_match and altsubject_match */
913		}
914
915		os_free(buf);
916
917		if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
918		    gnutls_x509_crt_get_activation_time(cert) > now.sec) {
919			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
920				   "not valid at this time",
921				   i + 1, num_certs);
922			gnutls_x509_crt_deinit(cert);
923			return -1;
924		}
925
926		gnutls_x509_crt_deinit(cert);
927	}
928
929	return 0;
930}
931
932
933u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
934			      const u8 *in_data, size_t in_len,
935			      size_t *out_len, u8 **appl_data,
936			      size_t *appl_data_len)
937{
938	struct tls_global *global = ssl_ctx;
939	u8 *out_data;
940	int ret;
941
942	if (appl_data)
943		*appl_data = NULL;
944
945	if (in_data && in_len) {
946		if (conn->pull_buf) {
947			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
948				   "pull_buf", __func__,
949				   (unsigned long) conn->pull_buf_len);
950			os_free(conn->pull_buf);
951		}
952		conn->pull_buf = os_malloc(in_len);
953		if (conn->pull_buf == NULL)
954			return NULL;
955		os_memcpy(conn->pull_buf, in_data, in_len);
956		conn->pull_buf_offset = conn->pull_buf;
957		conn->pull_buf_len = in_len;
958	}
959
960	ret = gnutls_handshake(conn->session);
961	if (ret < 0) {
962		switch (ret) {
963		case GNUTLS_E_AGAIN:
964			if (global->server && conn->established &&
965			    conn->push_buf == NULL) {
966				/* Need to return something to trigger
967				 * completion of EAP-TLS. */
968				conn->push_buf = os_malloc(1);
969			}
970			break;
971		case GNUTLS_E_FATAL_ALERT_RECEIVED:
972			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
973				   __func__, gnutls_alert_get_name(
974					   gnutls_alert_get(conn->session)));
975			conn->read_alerts++;
976			/* continue */
977		default:
978			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
979				   "-> %s", __func__, gnutls_strerror(ret));
980			conn->failed++;
981		}
982	} else {
983		size_t size;
984
985		if (conn->verify_peer && tls_connection_verify_peer(conn)) {
986			wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
987				   "failed validation");
988			conn->failed++;
989			return NULL;
990		}
991
992		if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
993			wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
994			conn->failed++;
995			return NULL;
996		}
997
998		if (conn->tls_ia)
999			wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
1000		else {
1001			wpa_printf(MSG_DEBUG, "TLS: Handshake completed "
1002				   "successfully");
1003		}
1004		conn->established = 1;
1005		if (conn->push_buf == NULL) {
1006			/* Need to return something to get final TLS ACK. */
1007			conn->push_buf = os_malloc(1);
1008		}
1009
1010		gnutls_session_get_data(conn->session, NULL, &size);
1011		if (global->session_data == NULL ||
1012		    global->session_data_size < size) {
1013			os_free(global->session_data);
1014			global->session_data = os_malloc(size);
1015		}
1016		if (global->session_data) {
1017			global->session_data_size = size;
1018			gnutls_session_get_data(conn->session,
1019						global->session_data,
1020						&global->session_data_size);
1021		}
1022	}
1023
1024	out_data = conn->push_buf;
1025	*out_len = conn->push_buf_len;
1026	conn->push_buf = NULL;
1027	conn->push_buf_len = 0;
1028	return out_data;
1029}
1030
1031
1032u8 * tls_connection_server_handshake(void *ssl_ctx,
1033				     struct tls_connection *conn,
1034				     const u8 *in_data, size_t in_len,
1035				     size_t *out_len)
1036{
1037	return tls_connection_handshake(ssl_ctx, conn, in_data, in_len,
1038					out_len, NULL, NULL);
1039}
1040
1041
1042int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
1043			   const u8 *in_data, size_t in_len,
1044			   u8 *out_data, size_t out_len)
1045{
1046	ssize_t res;
1047
1048#ifdef GNUTLS_IA
1049	if (conn->tls_ia)
1050		res = gnutls_ia_send(conn->session, (char *) in_data, in_len);
1051	else
1052#endif /* GNUTLS_IA */
1053	res = gnutls_record_send(conn->session, in_data, in_len);
1054	if (res < 0) {
1055		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1056			   __func__, gnutls_strerror(res));
1057		return -1;
1058	}
1059	if (conn->push_buf == NULL)
1060		return -1;
1061	if (conn->push_buf_len < out_len)
1062		out_len = conn->push_buf_len;
1063	else if (conn->push_buf_len > out_len) {
1064		wpa_printf(MSG_INFO, "GnuTLS: Not enough buffer space for "
1065			   "encrypted message (in_len=%lu push_buf_len=%lu "
1066			   "out_len=%lu",
1067			   (unsigned long) in_len,
1068			   (unsigned long) conn->push_buf_len,
1069			   (unsigned long) out_len);
1070	}
1071	os_memcpy(out_data, conn->push_buf, out_len);
1072	os_free(conn->push_buf);
1073	conn->push_buf = NULL;
1074	conn->push_buf_len = 0;
1075	return out_len;
1076}
1077
1078
1079int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
1080			   const u8 *in_data, size_t in_len,
1081			   u8 *out_data, size_t out_len)
1082{
1083	ssize_t res;
1084
1085	if (conn->pull_buf) {
1086		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1087			   "pull_buf", __func__,
1088			   (unsigned long) conn->pull_buf_len);
1089		os_free(conn->pull_buf);
1090	}
1091	conn->pull_buf = os_malloc(in_len);
1092	if (conn->pull_buf == NULL)
1093		return -1;
1094	os_memcpy(conn->pull_buf, in_data, in_len);
1095	conn->pull_buf_offset = conn->pull_buf;
1096	conn->pull_buf_len = in_len;
1097
1098#ifdef GNUTLS_IA
1099	if (conn->tls_ia) {
1100		res = gnutls_ia_recv(conn->session, (char *) out_data,
1101				     out_len);
1102		if (out_len >= 12 &&
1103		    (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
1104		     res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)) {
1105			int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
1106			wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished",
1107				   __func__, final ? "Final" : "Intermediate");
1108
1109			res = gnutls_ia_permute_inner_secret(
1110				conn->session, conn->session_keys_len,
1111				(char *) conn->session_keys);
1112			if (conn->session_keys) {
1113				os_memset(conn->session_keys, 0,
1114					  conn->session_keys_len);
1115				os_free(conn->session_keys);
1116			}
1117			conn->session_keys = NULL;
1118			conn->session_keys_len = 0;
1119			if (res) {
1120				wpa_printf(MSG_DEBUG, "%s: Failed to permute "
1121					   "inner secret: %s",
1122					   __func__, gnutls_strerror(res));
1123				return -1;
1124			}
1125
1126			res = gnutls_ia_verify_endphase(conn->session,
1127							(char *) out_data);
1128			if (res == 0) {
1129				wpa_printf(MSG_DEBUG, "%s: Correct endphase "
1130					   "checksum", __func__);
1131			} else {
1132				wpa_printf(MSG_INFO, "%s: Endphase "
1133					   "verification failed: %s",
1134					   __func__, gnutls_strerror(res));
1135				return -1;
1136			}
1137
1138			if (final)
1139				conn->final_phase_finished = 1;
1140
1141			return 0;
1142		}
1143
1144		if (res < 0) {
1145			wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
1146				   "(%s)", __func__, (int) res,
1147				   gnutls_strerror(res));
1148		}
1149		return res;
1150	}
1151#endif /* GNUTLS_IA */
1152
1153	res = gnutls_record_recv(conn->session, out_data, out_len);
1154	if (res < 0) {
1155		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1156			   "(%s)", __func__, (int) res, gnutls_strerror(res));
1157	}
1158
1159	return res;
1160}
1161
1162
1163int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1164{
1165	if (conn == NULL)
1166		return 0;
1167	return gnutls_session_is_resumed(conn->session);
1168}
1169
1170
1171int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1172				   u8 *ciphers)
1173{
1174	/* TODO */
1175	return -1;
1176}
1177
1178
1179int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1180		   char *buf, size_t buflen)
1181{
1182	/* TODO */
1183	buf[0] = '\0';
1184	return 0;
1185}
1186
1187
1188int tls_connection_enable_workaround(void *ssl_ctx,
1189				     struct tls_connection *conn)
1190{
1191	/* TODO: set SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */
1192	return 0;
1193}
1194
1195
1196int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1197				    int ext_type, const u8 *data,
1198				    size_t data_len)
1199{
1200	/* TODO */
1201	return -1;
1202}
1203
1204
1205int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1206{
1207	if (conn == NULL)
1208		return -1;
1209	return conn->failed;
1210}
1211
1212
1213int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1214{
1215	if (conn == NULL)
1216		return -1;
1217	return conn->read_alerts;
1218}
1219
1220
1221int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1222{
1223	if (conn == NULL)
1224		return -1;
1225	return conn->write_alerts;
1226}
1227
1228
1229int tls_connection_get_keyblock_size(void *tls_ctx,
1230				     struct tls_connection *conn)
1231{
1232	/* TODO */
1233	return -1;
1234}
1235
1236
1237unsigned int tls_capabilities(void *tls_ctx)
1238{
1239	unsigned int capa = 0;
1240
1241#ifdef GNUTLS_IA
1242	capa |= TLS_CAPABILITY_IA;
1243#endif /* GNUTLS_IA */
1244
1245	return capa;
1246}
1247
1248
1249int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
1250			  int tls_ia)
1251{
1252#ifdef GNUTLS_IA
1253	int ret;
1254
1255	if (conn == NULL)
1256		return -1;
1257
1258	conn->tls_ia = tls_ia;
1259	if (!tls_ia)
1260		return 0;
1261
1262	ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv);
1263	if (ret) {
1264		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
1265			   gnutls_strerror(ret));
1266		return -1;
1267	}
1268
1269	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
1270				     conn->iacred_srv);
1271	if (ret) {
1272		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
1273			   gnutls_strerror(ret));
1274		gnutls_ia_free_server_credentials(conn->iacred_srv);
1275		conn->iacred_srv = NULL;
1276		return -1;
1277	}
1278
1279	return 0;
1280#else /* GNUTLS_IA */
1281	return -1;
1282#endif /* GNUTLS_IA */
1283}
1284
1285
1286int tls_connection_ia_send_phase_finished(void *tls_ctx,
1287					  struct tls_connection *conn,
1288					  int final,
1289					  u8 *out_data, size_t out_len)
1290{
1291#ifdef GNUTLS_IA
1292	int ret;
1293
1294	if (conn == NULL || conn->session == NULL || !conn->tls_ia)
1295		return -1;
1296
1297	ret = gnutls_ia_permute_inner_secret(conn->session,
1298					     conn->session_keys_len,
1299					     (char *) conn->session_keys);
1300	if (conn->session_keys) {
1301		os_memset(conn->session_keys, 0, conn->session_keys_len);
1302		os_free(conn->session_keys);
1303	}
1304	conn->session_keys = NULL;
1305	conn->session_keys_len = 0;
1306	if (ret) {
1307		wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s",
1308			   __func__, gnutls_strerror(ret));
1309		return -1;
1310	}
1311
1312	ret = gnutls_ia_endphase_send(conn->session, final);
1313	if (ret) {
1314		wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s",
1315			   __func__, gnutls_strerror(ret));
1316		return -1;
1317	}
1318
1319	if (conn->push_buf == NULL)
1320		return -1;
1321	if (conn->push_buf_len < out_len)
1322		out_len = conn->push_buf_len;
1323	os_memcpy(out_data, conn->push_buf, out_len);
1324	os_free(conn->push_buf);
1325	conn->push_buf = NULL;
1326	conn->push_buf_len = 0;
1327	return out_len;
1328#else /* GNUTLS_IA */
1329	return -1;
1330#endif /* GNUTLS_IA */
1331}
1332
1333
1334int tls_connection_ia_final_phase_finished(void *tls_ctx,
1335					   struct tls_connection *conn)
1336{
1337	if (conn == NULL)
1338		return -1;
1339
1340	return conn->final_phase_finished;
1341}
1342
1343
1344int tls_connection_ia_permute_inner_secret(void *tls_ctx,
1345					   struct tls_connection *conn,
1346					   const u8 *key, size_t key_len)
1347{
1348#ifdef GNUTLS_IA
1349	if (conn == NULL || !conn->tls_ia)
1350		return -1;
1351
1352	if (conn->session_keys) {
1353		os_memset(conn->session_keys, 0, conn->session_keys_len);
1354		os_free(conn->session_keys);
1355	}
1356	conn->session_keys_len = 0;
1357
1358	if (key) {
1359		conn->session_keys = os_malloc(key_len);
1360		if (conn->session_keys == NULL)
1361			return -1;
1362		os_memcpy(conn->session_keys, key, key_len);
1363		conn->session_keys_len = key_len;
1364	} else {
1365		conn->session_keys = NULL;
1366		conn->session_keys_len = 0;
1367	}
1368
1369	return 0;
1370#else /* GNUTLS_IA */
1371	return -1;
1372#endif /* GNUTLS_IA */
1373}
1374