1139825Simp/*
299654Sbenno * SSL/TLS interface functions for GnuTLS
399654Sbenno * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
499654Sbenno *
599654Sbenno * This software may be distributed under the terms of the BSD license.
699654Sbenno * See README for more details.
799654Sbenno */
899654Sbenno
999654Sbenno#include "includes.h"
1099654Sbenno#include <gnutls/gnutls.h>
1199654Sbenno#include <gnutls/x509.h>
1299654Sbenno#ifdef PKCS12_FUNCS
1399654Sbenno#include <gnutls/pkcs12.h>
1499654Sbenno#endif /* PKCS12_FUNCS */
1599654Sbenno
1699654Sbenno#include "common.h"
1799654Sbenno#include "tls.h"
1899654Sbenno
1999654Sbenno
2099654Sbenno#define WPA_TLS_RANDOM_SIZE 32
2199654Sbenno#define WPA_TLS_MASTER_SIZE 48
2299654Sbenno
2399654Sbenno
2499654Sbenno#if LIBGNUTLS_VERSION_NUMBER < 0x010302
2599654Sbenno/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
2699654Sbenno * use of internal structures to get the master_secret and
2799654Sbenno * {server,client}_random.
2899654Sbenno */
2999654Sbenno#define GNUTLS_INTERNAL_STRUCTURE_HACK
3099654Sbenno#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
3199654Sbenno
3299654Sbenno
33209486Snwhitehorn#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
34171805Smarcel/*
35209486Snwhitehorn * It looks like gnutls does not provide access to client/server_random and
3699654Sbenno * master_key. This is somewhat unfortunate since these are needed for key
3799654Sbenno * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
3899654Sbenno * hack that copies the gnutls_session_int definition from gnutls_int.h so that
3999654Sbenno * we can get the needed information.
4099654Sbenno */
4199654Sbenno
4299654Sbennotypedef u8 uint8;
4399654Sbennotypedef unsigned char opaque;
4499654Sbennotypedef struct {
4599654Sbenno    uint8 suite[2];
4699654Sbenno} cipher_suite_st;
4799654Sbenno
4899654Sbennotypedef struct {
4999654Sbenno	gnutls_connection_end_t entity;
5099654Sbenno	gnutls_kx_algorithm_t kx_algorithm;
51171805Smarcel	gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
52171805Smarcel	gnutls_mac_algorithm_t read_mac_algorithm;
5399654Sbenno	gnutls_compression_method_t read_compression_algorithm;
5499654Sbenno	gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
5599654Sbenno	gnutls_mac_algorithm_t write_mac_algorithm;
56209298Snwhitehorn	gnutls_compression_method_t write_compression_algorithm;
5799654Sbenno	cipher_suite_st current_cipher_suite;
58171805Smarcel	opaque master_secret[WPA_TLS_MASTER_SIZE];
59171805Smarcel	opaque client_random[WPA_TLS_RANDOM_SIZE];
60171805Smarcel	opaque server_random[WPA_TLS_RANDOM_SIZE];
61171805Smarcel	/* followed by stuff we are not interested in */
62171805Smarcel} security_parameters_st;
6399654Sbenno
64171805Smarcelstruct gnutls_session_int {
65171805Smarcel	security_parameters_st security_parameters;
6699654Sbenno	/* followed by things we are not interested in */
67171805Smarcel};
68171805Smarcel#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
69124469Sgrehan
70171805Smarcelstatic int tls_gnutls_ref_count = 0;
71176208Smarcel
72171805Smarcelstruct tls_global {
73176208Smarcel	/* Data for session resumption */
74171805Smarcel	void *session_data;
7599654Sbenno	size_t session_data_size;
76209486Snwhitehorn
77209725Snwhitehorn	int server;
78176208Smarcel
79176208Smarcel	int params_set;
80171805Smarcel	gnutls_certificate_credentials_t xcred;
81176208Smarcel};
82209486Snwhitehorn
83124469Sgrehanstruct tls_connection {
8499654Sbenno	gnutls_session session;
85124469Sgrehan	char *subject_match, *altsubject_match;
86218075Smarcel	int read_alerts, write_alerts, failed;
87124469Sgrehan
88124469Sgrehan	u8 *pre_shared_secret;
89178628Smarcel	size_t pre_shared_secret_len;
90124469Sgrehan	int established;
91103603Sgrehan	int verify_peer;
92124469Sgrehan
93171805Smarcel	struct wpabuf *push_buf;
94103603Sgrehan	struct wpabuf *pull_buf;
95171805Smarcel	const u8 *pull_buf_offset;
96171805Smarcel
97171805Smarcel	int params_set;
98124469Sgrehan	gnutls_certificate_credentials_t xcred;
99171805Smarcel};
100171805Smarcel
101171805Smarcel
102171805Smarcelstatic void tls_log_func(int level, const char *msg)
103171805Smarcel{
104171805Smarcel	char *s, *pos;
105171805Smarcel	if (level == 6 || level == 7) {
106171805Smarcel		/* These levels seem to be mostly I/O debug and msg dumps */
107208149Snwhitehorn		return;
108208149Snwhitehorn	}
109208149Snwhitehorn
110208149Snwhitehorn	s = os_strdup(msg);
111208149Snwhitehorn	if (s == NULL)
112208149Snwhitehorn		return;
113208149Snwhitehorn
114208149Snwhitehorn	pos = s;
115208149Snwhitehorn	while (*pos != '\0') {
116208149Snwhitehorn		if (*pos == '\n') {
117209298Snwhitehorn			*pos = '\0';
118209298Snwhitehorn			break;
119209298Snwhitehorn		}
120209485Smarcel		pos++;
121209485Smarcel	}
122209485Smarcel	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
123209485Smarcel		   "gnutls<%d> %s", level, s);
124209485Smarcel	os_free(s);
125209485Smarcel}
126209485Smarcel
127209485Smarcel
128209485Smarcelextern int wpa_debug_show_keys;
129209298Snwhitehorn
130209298Snwhitehornvoid * tls_init(const struct tls_config *conf)
131209298Snwhitehorn{
132209298Snwhitehorn	struct tls_global *global;
133209298Snwhitehorn
134209298Snwhitehorn#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
135209485Smarcel	/* Because of the horrible hack to get master_secret and client/server
136209298Snwhitehorn	 * random, we need to make sure that the gnutls version is something
137209298Snwhitehorn	 * that is expected to have same structure definition for the session
138209298Snwhitehorn	 * data.. */
139209298Snwhitehorn	const char *ver;
140209298Snwhitehorn	const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
141209298Snwhitehorn				 "1.3.2",
142209298Snwhitehorn				 NULL };
143209298Snwhitehorn	int i;
144209298Snwhitehorn#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
145209298Snwhitehorn
146209298Snwhitehorn	global = os_zalloc(sizeof(*global));
147124469Sgrehan	if (global == NULL)
148124469Sgrehan		return NULL;
14999654Sbenno
15099654Sbenno	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
15199654Sbenno		os_free(global);
15299654Sbenno		return NULL;
15399654Sbenno	}
15499654Sbenno	tls_gnutls_ref_count++;
15599654Sbenno
15699654Sbenno#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
15799654Sbenno	ver = gnutls_check_version(NULL);
15899654Sbenno	if (ver == NULL) {
15999654Sbenno		tls_deinit(global);
16099654Sbenno		return NULL;
16199654Sbenno	}
16299654Sbenno	wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
163124469Sgrehan	for (i = 0; ok_ver[i]; i++) {
164110167Sbenno		if (strcmp(ok_ver[i], ver) == 0)
165124469Sgrehan			break;
166110167Sbenno	}
16799654Sbenno	if (ok_ver[i] == NULL) {
168111156Sgrehan		wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
169193909Sgrehan			   "to be tested and enabled in tls_gnutls.c", ver);
170111156Sgrehan		tls_deinit(global);
171193909Sgrehan		return NULL;
172111156Sgrehan	}
173193909Sgrehan#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
174193909Sgrehan
175111156Sgrehan	gnutls_global_set_log_function(tls_log_func);
176124469Sgrehan	if (wpa_debug_show_keys)
177124469Sgrehan		gnutls_global_set_log_level(11);
178124469Sgrehan	return global;
179124469Sgrehan}
18099654Sbenno
181178628Smarcel
182178628Smarcelvoid tls_deinit(void *ssl_ctx)
183178628Smarcel{
184176208Smarcel	struct tls_global *global = ssl_ctx;
185176208Smarcel	if (global) {
186176208Smarcel		if (global->params_set)
187176208Smarcel			gnutls_certificate_free_credentials(global->xcred);
188209299Snwhitehorn		os_free(global->session_data);
189176208Smarcel		os_free(global);
190176208Smarcel	}
191176208Smarcel
192176208Smarcel	tls_gnutls_ref_count--;
19399654Sbenno	if (tls_gnutls_ref_count == 0)
194176208Smarcel		gnutls_global_deinit();
195176208Smarcel}
196176208Smarcel
197176208Smarcel
198176208Smarcelint tls_get_errors(void *ssl_ctx)
199176208Smarcel{
200176208Smarcel	return 0;
20199654Sbenno}
20299654Sbenno
20399654Sbenno
20499654Sbennostatic ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
20599654Sbenno			     size_t len)
20699654Sbenno{
20799654Sbenno	struct tls_connection *conn = (struct tls_connection *) ptr;
20899654Sbenno	const u8 *end;
20999654Sbenno	if (conn->pull_buf == NULL) {
21099654Sbenno		errno = EWOULDBLOCK;
211209725Snwhitehorn		return -1;
212103603Sgrehan	}
213209725Snwhitehorn
214209725Snwhitehorn	end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
21599654Sbenno	if ((size_t) (end - conn->pull_buf_offset) < len)
21699654Sbenno		len = end - conn->pull_buf_offset;
217183028Smarcel	os_memcpy(buf, conn->pull_buf_offset, len);
218183028Smarcel	conn->pull_buf_offset += len;
219183028Smarcel	if (conn->pull_buf_offset == end) {
220218075Smarcel		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
22199654Sbenno		wpabuf_free(conn->pull_buf);
222209298Snwhitehorn		conn->pull_buf = NULL;
223209298Snwhitehorn		conn->pull_buf_offset = NULL;
224209298Snwhitehorn	} else {
225209298Snwhitehorn		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
22699654Sbenno			   __func__,
22799654Sbenno			   (unsigned long) (end - conn->pull_buf_offset));
22899654Sbenno	}
22999654Sbenno	return len;
230171805Smarcel}
23199654Sbenno
23299654Sbenno
233171805Smarcelstatic ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
234222813Sattilio			     size_t len)
235209486Snwhitehorn{
236209486Snwhitehorn	struct tls_connection *conn = (struct tls_connection *) ptr;
237209486Snwhitehorn
238209486Snwhitehorn	if (wpabuf_resize(&conn->push_buf, len) < 0) {
239209486Snwhitehorn		errno = ENOMEM;
240209486Snwhitehorn		return -1;
241209486Snwhitehorn	}
242209486Snwhitehorn	wpabuf_put_data(conn->push_buf, buf, len);
243222813Sattilio
244222813Sattilio	return len;
245222813Sattilio}
246222813Sattilio
247222813Sattilio
248222813Sattiliostatic int tls_gnutls_init_session(struct tls_global *global,
249209486Snwhitehorn				   struct tls_connection *conn)
250209486Snwhitehorn{
251209486Snwhitehorn#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
252176918Smarcel	const char *err;
253176918Smarcel#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
254176918Smarcel	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
255176918Smarcel	const int protos[2] = { GNUTLS_TLS1, 0 };
256176918Smarcel#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
257176918Smarcel	int ret;
258176918Smarcel
259176918Smarcel	ret = gnutls_init(&conn->session,
260176918Smarcel			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
261176918Smarcel	if (ret < 0) {
262176918Smarcel		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
263176918Smarcel			   "connection: %s", gnutls_strerror(ret));
264176918Smarcel		return -1;
265176918Smarcel	}
266176918Smarcel
267176918Smarcel	ret = gnutls_set_default_priority(conn->session);
268176918Smarcel	if (ret < 0)
269176918Smarcel		goto fail;
270176918Smarcel
271209298Snwhitehorn#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
272209298Snwhitehorn	ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
273209298Snwhitehorn					 &err);
274209298Snwhitehorn	if (ret < 0) {
275209298Snwhitehorn		wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
276209298Snwhitehorn			   "'%s'", err);
277209298Snwhitehorn		goto fail;
278209298Snwhitehorn	}
279209298Snwhitehorn#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
280209298Snwhitehorn	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
281209298Snwhitehorn	if (ret < 0)
282176918Smarcel		goto fail;
283171805Smarcel
28499654Sbenno	ret = gnutls_protocol_set_priority(conn->session, protos);
285171805Smarcel	if (ret < 0)
286183028Smarcel		goto fail;
28799654Sbenno#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
288192532Sraj
289192532Sraj	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
290209725Snwhitehorn	gnutls_transport_set_push_function(conn->session, tls_push_func);
291209725Snwhitehorn	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
292183028Smarcel
293171805Smarcel	return 0;
294183028Smarcel
295171805Smarcelfail:
296171805Smarcel	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
297171805Smarcel		   gnutls_strerror(ret));
298171805Smarcel	gnutls_deinit(conn->session);
299124469Sgrehan	return -1;
30099654Sbenno}
30199654Sbenno
302171805Smarcel
303171805Smarcelstruct tls_connection * tls_connection_init(void *ssl_ctx)
30499654Sbenno{
305171805Smarcel	struct tls_global *global = ssl_ctx;
306171805Smarcel	struct tls_connection *conn;
30799654Sbenno	int ret;
30899654Sbenno
309176208Smarcel	conn = os_zalloc(sizeof(*conn));
310176208Smarcel	if (conn == NULL)
311176208Smarcel		return NULL;
312176208Smarcel
313176208Smarcel	if (tls_gnutls_init_session(global, conn)) {
314176208Smarcel		os_free(conn);
315176208Smarcel		return NULL;
316176208Smarcel	}
317176208Smarcel
318176208Smarcel	if (global->params_set) {
319176208Smarcel		ret = gnutls_credentials_set(conn->session,
32099654Sbenno					     GNUTLS_CRD_CERTIFICATE,
32199654Sbenno					     global->xcred);
322171805Smarcel		if (ret < 0) {
323171805Smarcel			wpa_printf(MSG_INFO, "Failed to configure "
32499654Sbenno				   "credentials: %s", gnutls_strerror(ret));
325171805Smarcel			os_free(conn);
326209725Snwhitehorn			return NULL;
32799654Sbenno		}
328209725Snwhitehorn	}
329209725Snwhitehorn
330171805Smarcel	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
331209725Snwhitehorn		os_free(conn);
33299654Sbenno		return NULL;
33399654Sbenno	}
334171805Smarcel
335176208Smarcel	return conn;
336176208Smarcel}
337176208Smarcel
338176208Smarcel
339209726Snwhitehornvoid tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
340209726Snwhitehorn{
341176208Smarcel	if (conn == NULL)
342209486Snwhitehorn		return;
343209726Snwhitehorn
344176208Smarcel	gnutls_certificate_free_credentials(conn->xcred);
345209486Snwhitehorn	gnutls_deinit(conn->session);
346176208Smarcel	os_free(conn->pre_shared_secret);
347176208Smarcel	os_free(conn->subject_match);
348176208Smarcel	os_free(conn->altsubject_match);
349171805Smarcel	wpabuf_free(conn->push_buf);
35099654Sbenno	wpabuf_free(conn->pull_buf);
351171805Smarcel	os_free(conn);
352171805Smarcel}
35399654Sbenno
354171805Smarcel
355176208Smarcelint tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
356176208Smarcel{
357176208Smarcel	return conn ? conn->established : 0;
358176208Smarcel}
359176208Smarcel
360176208Smarcel
361176208Smarcelint tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
362176208Smarcel{
363176208Smarcel	struct tls_global *global = ssl_ctx;
36499654Sbenno	int ret;
36599654Sbenno
366171805Smarcel	if (conn == NULL)
367171805Smarcel		return -1;
36899654Sbenno
369171805Smarcel	/* Shutdown previous TLS connection without notifying the peer
370171805Smarcel	 * because the connection was already terminated in practice
37199654Sbenno	 * and "close notify" shutdown alert would confuse AS. */
372171805Smarcel	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
373176208Smarcel	wpabuf_free(conn->push_buf);
374176208Smarcel	conn->push_buf = NULL;
375176208Smarcel	conn->established = 0;
376176208Smarcel
377176208Smarcel	gnutls_deinit(conn->session);
378176208Smarcel	if (tls_gnutls_init_session(global, conn)) {
379176208Smarcel		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
380176208Smarcel			   "for session resumption use");
381176208Smarcel		return -1;
38299654Sbenno	}
383
384	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
385				     conn->params_set ? conn->xcred :
386				     global->xcred);
387	if (ret < 0) {
388		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
389			   "for session resumption: %s", gnutls_strerror(ret));
390		return -1;
391	}
392
393	if (global->session_data) {
394		ret = gnutls_session_set_data(conn->session,
395					      global->session_data,
396					      global->session_data_size);
397		if (ret < 0) {
398			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
399				   "data: %s", gnutls_strerror(ret));
400			return -1;
401		}
402	}
403
404	return 0;
405}
406
407
408#if 0
409static int tls_match_altsubject(X509 *cert, const char *match)
410{
411	GENERAL_NAME *gen;
412	char *field, *tmp;
413	void *ext;
414	int i, found = 0;
415	size_t len;
416
417	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
418
419	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
420		gen = sk_GENERAL_NAME_value(ext, i);
421		switch (gen->type) {
422		case GEN_EMAIL:
423			field = "EMAIL";
424			break;
425		case GEN_DNS:
426			field = "DNS";
427			break;
428		case GEN_URI:
429			field = "URI";
430			break;
431		default:
432			field = NULL;
433			wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
434				   "unsupported type=%d", gen->type);
435			break;
436		}
437
438		if (!field)
439			continue;
440
441		wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
442			   field, gen->d.ia5->data);
443		len = os_strlen(field) + 1 +
444			strlen((char *) gen->d.ia5->data) + 1;
445		tmp = os_malloc(len);
446		if (tmp == NULL)
447			continue;
448		snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
449		if (strstr(tmp, match))
450			found++;
451		os_free(tmp);
452	}
453
454	return found;
455}
456#endif
457
458
459#if 0
460static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
461{
462	char buf[256];
463	X509 *err_cert;
464	int err, depth;
465	SSL *ssl;
466	struct tls_connection *conn;
467	char *match, *altmatch;
468
469	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
470	err = X509_STORE_CTX_get_error(x509_ctx);
471	depth = X509_STORE_CTX_get_error_depth(x509_ctx);
472	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
473					 SSL_get_ex_data_X509_STORE_CTX_idx());
474	X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
475
476	conn = SSL_get_app_data(ssl);
477	match = conn ? conn->subject_match : NULL;
478	altmatch = conn ? conn->altsubject_match : NULL;
479
480	if (!preverify_ok) {
481		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
482			   " error %d (%s) depth %d for '%s'", err,
483			   X509_verify_cert_error_string(err), depth, buf);
484	} else {
485		wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
486			   "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
487			   preverify_ok, err,
488			   X509_verify_cert_error_string(err), depth, buf);
489		if (depth == 0 && match && strstr(buf, match) == NULL) {
490			wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
491				   "match with '%s'", buf, match);
492			preverify_ok = 0;
493		} else if (depth == 0 && altmatch &&
494			   !tls_match_altsubject(err_cert, altmatch)) {
495			wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
496				   "'%s' not found", altmatch);
497			preverify_ok = 0;
498		}
499	}
500
501	return preverify_ok;
502}
503#endif
504
505
506int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
507			      const struct tls_connection_params *params)
508{
509	int ret;
510
511	if (conn == NULL || params == NULL)
512		return -1;
513
514	os_free(conn->subject_match);
515	conn->subject_match = NULL;
516	if (params->subject_match) {
517		conn->subject_match = os_strdup(params->subject_match);
518		if (conn->subject_match == NULL)
519			return -1;
520	}
521
522	os_free(conn->altsubject_match);
523	conn->altsubject_match = NULL;
524	if (params->altsubject_match) {
525		conn->altsubject_match = os_strdup(params->altsubject_match);
526		if (conn->altsubject_match == NULL)
527			return -1;
528	}
529
530	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
531	 * to force peer validation(?) */
532
533	if (params->ca_cert) {
534		conn->verify_peer = 1;
535		ret = gnutls_certificate_set_x509_trust_file(
536			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
537		if (ret < 0) {
538			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
539				   "in PEM format: %s", params->ca_cert,
540				   gnutls_strerror(ret));
541			ret = gnutls_certificate_set_x509_trust_file(
542				conn->xcred, params->ca_cert,
543				GNUTLS_X509_FMT_DER);
544			if (ret < 0) {
545				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
546					   "'%s' in DER format: %s",
547					   params->ca_cert,
548					   gnutls_strerror(ret));
549				return -1;
550			}
551		}
552
553		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
554			gnutls_certificate_set_verify_flags(
555				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
556		}
557
558#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
559		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
560			gnutls_certificate_set_verify_flags(
561				conn->xcred,
562				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
563		}
564#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
565	}
566
567	if (params->client_cert && params->private_key) {
568		/* TODO: private_key_passwd? */
569		ret = gnutls_certificate_set_x509_key_file(
570			conn->xcred, params->client_cert, params->private_key,
571			GNUTLS_X509_FMT_PEM);
572		if (ret < 0) {
573			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
574				   "in PEM format: %s", gnutls_strerror(ret));
575			ret = gnutls_certificate_set_x509_key_file(
576				conn->xcred, params->client_cert,
577				params->private_key, GNUTLS_X509_FMT_DER);
578			if (ret < 0) {
579				wpa_printf(MSG_DEBUG, "Failed to read client "
580					   "cert/key in DER format: %s",
581					   gnutls_strerror(ret));
582				return ret;
583			}
584		}
585	} else if (params->private_key) {
586		int pkcs12_ok = 0;
587#ifdef PKCS12_FUNCS
588		/* Try to load in PKCS#12 format */
589#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
590		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
591			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
592			params->private_key_passwd);
593		if (ret != 0) {
594			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
595				   "PKCS#12 format: %s", gnutls_strerror(ret));
596			return -1;
597		} else
598			pkcs12_ok = 1;
599#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
600#endif /* PKCS12_FUNCS */
601
602		if (!pkcs12_ok) {
603			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
604				   "included");
605			return -1;
606		}
607	}
608
609	conn->params_set = 1;
610
611	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
612				     conn->xcred);
613	if (ret < 0) {
614		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
615			   gnutls_strerror(ret));
616	}
617
618	return ret;
619}
620
621
622int tls_global_set_params(void *tls_ctx,
623			  const struct tls_connection_params *params)
624{
625	struct tls_global *global = tls_ctx;
626	int ret;
627
628	/* Currently, global parameters are only set when running in server
629	 * mode. */
630	global->server = 1;
631
632	if (global->params_set) {
633		gnutls_certificate_free_credentials(global->xcred);
634		global->params_set = 0;
635	}
636
637	ret = gnutls_certificate_allocate_credentials(&global->xcred);
638	if (ret) {
639		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
640			   "%s", gnutls_strerror(ret));
641		return -1;
642	}
643
644	if (params->ca_cert) {
645		ret = gnutls_certificate_set_x509_trust_file(
646			global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
647		if (ret < 0) {
648			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
649				   "in PEM format: %s", params->ca_cert,
650				   gnutls_strerror(ret));
651			ret = gnutls_certificate_set_x509_trust_file(
652				global->xcred, params->ca_cert,
653				GNUTLS_X509_FMT_DER);
654			if (ret < 0) {
655				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
656					   "'%s' in DER format: %s",
657					   params->ca_cert,
658					   gnutls_strerror(ret));
659				goto fail;
660			}
661		}
662
663		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
664			gnutls_certificate_set_verify_flags(
665				global->xcred,
666				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
667		}
668
669#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
670		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
671			gnutls_certificate_set_verify_flags(
672				global->xcred,
673				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
674		}
675#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
676	}
677
678	if (params->client_cert && params->private_key) {
679		/* TODO: private_key_passwd? */
680		ret = gnutls_certificate_set_x509_key_file(
681			global->xcred, params->client_cert,
682			params->private_key, GNUTLS_X509_FMT_PEM);
683		if (ret < 0) {
684			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
685				   "in PEM format: %s", gnutls_strerror(ret));
686			ret = gnutls_certificate_set_x509_key_file(
687				global->xcred, params->client_cert,
688				params->private_key, GNUTLS_X509_FMT_DER);
689			if (ret < 0) {
690				wpa_printf(MSG_DEBUG, "Failed to read client "
691					   "cert/key in DER format: %s",
692					   gnutls_strerror(ret));
693				goto fail;
694			}
695		}
696	} else if (params->private_key) {
697		int pkcs12_ok = 0;
698#ifdef PKCS12_FUNCS
699		/* Try to load in PKCS#12 format */
700#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
701		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
702			global->xcred, params->private_key,
703			GNUTLS_X509_FMT_DER, params->private_key_passwd);
704		if (ret != 0) {
705			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
706				   "PKCS#12 format: %s", gnutls_strerror(ret));
707			goto fail;
708		} else
709			pkcs12_ok = 1;
710#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
711#endif /* PKCS12_FUNCS */
712
713		if (!pkcs12_ok) {
714			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
715				   "included");
716			goto fail;
717		}
718	}
719
720	global->params_set = 1;
721
722	return 0;
723
724fail:
725	gnutls_certificate_free_credentials(global->xcred);
726	return -1;
727}
728
729
730int tls_global_set_verify(void *ssl_ctx, int check_crl)
731{
732	/* TODO */
733	return 0;
734}
735
736
737int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
738			      int verify_peer)
739{
740	if (conn == NULL || conn->session == NULL)
741		return -1;
742
743	conn->verify_peer = verify_peer;
744	gnutls_certificate_server_set_request(conn->session,
745					      verify_peer ? GNUTLS_CERT_REQUIRE
746					      : GNUTLS_CERT_REQUEST);
747
748	return 0;
749}
750
751
752int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
753			    struct tls_keys *keys)
754{
755#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
756	security_parameters_st *sec;
757#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
758
759	if (conn == NULL || conn->session == NULL || keys == NULL)
760		return -1;
761
762	os_memset(keys, 0, sizeof(*keys));
763
764#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
765#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
766	sec = &conn->session->security_parameters;
767	keys->master_key = sec->master_secret;
768	keys->master_key_len = WPA_TLS_MASTER_SIZE;
769	keys->client_random = sec->client_random;
770	keys->server_random = sec->server_random;
771#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
772	keys->client_random =
773		(u8 *) gnutls_session_get_client_random(conn->session);
774	keys->server_random =
775		(u8 *) gnutls_session_get_server_random(conn->session);
776	/* No access to master_secret */
777#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
778#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
779
780#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
781	keys->client_random_len = WPA_TLS_RANDOM_SIZE;
782	keys->server_random_len = WPA_TLS_RANDOM_SIZE;
783#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
784
785	return 0;
786}
787
788
789int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
790		       const char *label, int server_random_first,
791		       u8 *out, size_t out_len)
792{
793#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
794	if (conn == NULL || conn->session == NULL)
795		return -1;
796
797	return gnutls_prf(conn->session, os_strlen(label), label,
798			  server_random_first, 0, NULL, out_len, (char *) out);
799#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
800	return -1;
801#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
802}
803
804
805static int tls_connection_verify_peer(struct tls_connection *conn,
806				      gnutls_alert_description_t *err)
807{
808	unsigned int status, num_certs, i;
809	struct os_time now;
810	const gnutls_datum_t *certs;
811	gnutls_x509_crt_t cert;
812
813	if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
814		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
815			   "certificate chain");
816		*err = GNUTLS_A_INTERNAL_ERROR;
817		return -1;
818	}
819
820	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
821		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
822		*err = GNUTLS_A_INTERNAL_ERROR;
823		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
824			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
825				   "algorithm");
826			*err = GNUTLS_A_INSUFFICIENT_SECURITY;
827		}
828#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
829		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
830			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
831				   "activated");
832			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
833		}
834		if (status & GNUTLS_CERT_EXPIRED) {
835			wpa_printf(MSG_INFO, "TLS: Certificate expired");
836			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
837		}
838#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
839		return -1;
840	}
841
842	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
843		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
844			   "known issuer");
845		*err = GNUTLS_A_UNKNOWN_CA;
846		return -1;
847	}
848
849	if (status & GNUTLS_CERT_REVOKED) {
850		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
851		*err = GNUTLS_A_CERTIFICATE_REVOKED;
852		return -1;
853	}
854
855	os_get_time(&now);
856
857	certs = gnutls_certificate_get_peers(conn->session, &num_certs);
858	if (certs == NULL) {
859		wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
860			   "received");
861		*err = GNUTLS_A_UNKNOWN_CA;
862		return -1;
863	}
864
865	for (i = 0; i < num_certs; i++) {
866		char *buf;
867		size_t len;
868		if (gnutls_x509_crt_init(&cert) < 0) {
869			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
870				   "failed");
871			*err = GNUTLS_A_BAD_CERTIFICATE;
872			return -1;
873		}
874
875		if (gnutls_x509_crt_import(cert, &certs[i],
876					   GNUTLS_X509_FMT_DER) < 0) {
877			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
878				   "certificate %d/%d", i + 1, num_certs);
879			gnutls_x509_crt_deinit(cert);
880			*err = GNUTLS_A_BAD_CERTIFICATE;
881			return -1;
882		}
883
884		gnutls_x509_crt_get_dn(cert, NULL, &len);
885		len++;
886		buf = os_malloc(len + 1);
887		if (buf) {
888			buf[0] = buf[len] = '\0';
889			gnutls_x509_crt_get_dn(cert, buf, &len);
890		}
891		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
892			   i + 1, num_certs, buf);
893
894		if (i == 0) {
895			/* TODO: validate subject_match and altsubject_match */
896		}
897
898		os_free(buf);
899
900		if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
901		    gnutls_x509_crt_get_activation_time(cert) > now.sec) {
902			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
903				   "not valid at this time",
904				   i + 1, num_certs);
905			gnutls_x509_crt_deinit(cert);
906			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
907			return -1;
908		}
909
910		gnutls_x509_crt_deinit(cert);
911	}
912
913	return 0;
914}
915
916
917static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
918{
919	int res;
920	struct wpabuf *ad;
921	wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
922	ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
923	if (ad == NULL)
924		return NULL;
925
926	res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
927				 wpabuf_size(ad));
928	wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
929	if (res < 0) {
930		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
931			   "(%s)", __func__, (int) res,
932			   gnutls_strerror(res));
933		wpabuf_free(ad);
934		return NULL;
935	}
936
937	wpabuf_put(ad, res);
938	wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
939		   res);
940	return ad;
941}
942
943
944struct wpabuf * tls_connection_handshake(void *tls_ctx,
945					 struct tls_connection *conn,
946					 const struct wpabuf *in_data,
947					 struct wpabuf **appl_data)
948{
949	struct tls_global *global = tls_ctx;
950	struct wpabuf *out_data;
951	int ret;
952
953	if (appl_data)
954		*appl_data = NULL;
955
956	if (in_data && wpabuf_len(in_data) > 0) {
957		if (conn->pull_buf) {
958			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
959				   "pull_buf", __func__,
960				   (unsigned long) wpabuf_len(conn->pull_buf));
961			wpabuf_free(conn->pull_buf);
962		}
963		conn->pull_buf = wpabuf_dup(in_data);
964		if (conn->pull_buf == NULL)
965			return NULL;
966		conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
967	}
968
969	ret = gnutls_handshake(conn->session);
970	if (ret < 0) {
971		switch (ret) {
972		case GNUTLS_E_AGAIN:
973			if (global->server && conn->established &&
974			    conn->push_buf == NULL) {
975				/* Need to return something to trigger
976				 * completion of EAP-TLS. */
977				conn->push_buf = wpabuf_alloc(0);
978			}
979			break;
980		case GNUTLS_E_FATAL_ALERT_RECEIVED:
981			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
982				   __func__, gnutls_alert_get_name(
983					   gnutls_alert_get(conn->session)));
984			conn->read_alerts++;
985			/* continue */
986		default:
987			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
988				   "-> %s", __func__, gnutls_strerror(ret));
989			conn->failed++;
990		}
991	} else {
992		size_t size;
993		gnutls_alert_description_t err;
994
995		if (conn->verify_peer &&
996		    tls_connection_verify_peer(conn, &err)) {
997			wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
998				   "failed validation");
999			conn->failed++;
1000			gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
1001			goto out;
1002		}
1003
1004		wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
1005		conn->established = 1;
1006		if (conn->push_buf == NULL) {
1007			/* Need to return something to get final TLS ACK. */
1008			conn->push_buf = wpabuf_alloc(0);
1009		}
1010
1011		gnutls_session_get_data(conn->session, NULL, &size);
1012		if (global->session_data == NULL ||
1013		    global->session_data_size < size) {
1014			os_free(global->session_data);
1015			global->session_data = os_malloc(size);
1016		}
1017		if (global->session_data) {
1018			global->session_data_size = size;
1019			gnutls_session_get_data(conn->session,
1020						global->session_data,
1021						&global->session_data_size);
1022		}
1023
1024		if (conn->pull_buf && appl_data)
1025			*appl_data = gnutls_get_appl_data(conn);
1026	}
1027
1028out:
1029	out_data = conn->push_buf;
1030	conn->push_buf = NULL;
1031	return out_data;
1032}
1033
1034
1035struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
1036						struct tls_connection *conn,
1037						const struct wpabuf *in_data,
1038						struct wpabuf **appl_data)
1039{
1040	return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
1041}
1042
1043
1044struct wpabuf * tls_connection_encrypt(void *tls_ctx,
1045				       struct tls_connection *conn,
1046				       const struct wpabuf *in_data)
1047{
1048	ssize_t res;
1049	struct wpabuf *buf;
1050
1051	res = gnutls_record_send(conn->session, wpabuf_head(in_data),
1052				 wpabuf_len(in_data));
1053	if (res < 0) {
1054		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
1055			   __func__, gnutls_strerror(res));
1056		return NULL;
1057	}
1058
1059	buf = conn->push_buf;
1060	conn->push_buf = NULL;
1061	return buf;
1062}
1063
1064
1065struct wpabuf * tls_connection_decrypt(void *tls_ctx,
1066				       struct tls_connection *conn,
1067				       const struct wpabuf *in_data)
1068{
1069	ssize_t res;
1070	struct wpabuf *out;
1071
1072	if (conn->pull_buf) {
1073		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
1074			   "pull_buf", __func__,
1075			   (unsigned long) wpabuf_len(conn->pull_buf));
1076		wpabuf_free(conn->pull_buf);
1077	}
1078	conn->pull_buf = wpabuf_dup(in_data);
1079	if (conn->pull_buf == NULL)
1080		return NULL;
1081	conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
1082
1083	/*
1084	 * Even though we try to disable TLS compression, it is possible that
1085	 * this cannot be done with all TLS libraries. Add extra buffer space
1086	 * to handle the possibility of the decrypted data being longer than
1087	 * input data.
1088	 */
1089	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
1090	if (out == NULL)
1091		return NULL;
1092
1093	res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
1094				 wpabuf_size(out));
1095	if (res < 0) {
1096		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
1097			   "(%s)", __func__, (int) res, gnutls_strerror(res));
1098		wpabuf_free(out);
1099		return NULL;
1100	}
1101	wpabuf_put(out, res);
1102
1103	return out;
1104}
1105
1106
1107int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
1108{
1109	if (conn == NULL)
1110		return 0;
1111	return gnutls_session_is_resumed(conn->session);
1112}
1113
1114
1115int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
1116				   u8 *ciphers)
1117{
1118	/* TODO */
1119	return -1;
1120}
1121
1122
1123int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
1124		   char *buf, size_t buflen)
1125{
1126	/* TODO */
1127	buf[0] = '\0';
1128	return 0;
1129}
1130
1131
1132int tls_connection_enable_workaround(void *ssl_ctx,
1133				     struct tls_connection *conn)
1134{
1135	gnutls_record_disable_padding(conn->session);
1136	return 0;
1137}
1138
1139
1140int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
1141				    int ext_type, const u8 *data,
1142				    size_t data_len)
1143{
1144	/* TODO */
1145	return -1;
1146}
1147
1148
1149int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
1150{
1151	if (conn == NULL)
1152		return -1;
1153	return conn->failed;
1154}
1155
1156
1157int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
1158{
1159	if (conn == NULL)
1160		return -1;
1161	return conn->read_alerts;
1162}
1163
1164
1165int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
1166{
1167	if (conn == NULL)
1168		return -1;
1169	return conn->write_alerts;
1170}
1171
1172
1173int tls_connection_get_keyblock_size(void *tls_ctx,
1174				     struct tls_connection *conn)
1175{
1176	/* TODO */
1177	return -1;
1178}
1179
1180
1181unsigned int tls_capabilities(void *tls_ctx)
1182{
1183	return 0;
1184}
1185
1186
1187int tls_connection_set_session_ticket_cb(void *tls_ctx,
1188					 struct tls_connection *conn,
1189					 tls_session_ticket_cb cb, void *ctx)
1190{
1191	return -1;
1192}
1193