EAP server: Add tls_session_lifetime configuration

This new hostapd configuration parameter can be used to enable TLS
session resumption. This commit adds the configuration parameter through
the configuration system and RADIUS/EAPOL/EAP server components. The
actual changes to enable session caching will be addressed in followup
commits.

Signed-off-by: Jouni Malinen <j@w1.fi>
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index f8ca6da..e91c86c 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2079,6 +2079,8 @@
 		bss->private_key_passwd = os_strdup(pos);
 	} else if (os_strcmp(buf, "check_crl") == 0) {
 		bss->check_crl = atoi(pos);
+	} else if (os_strcmp(buf, "tls_session_lifetime") == 0) {
+		bss->tls_session_lifetime = atoi(pos);
 	} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
 		os_free(bss->ocsp_stapling_response);
 		bss->ocsp_stapling_response = os_strdup(pos);
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 1690588..4a829ea 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -768,6 +768,12 @@
 # 2 = check all CRLs in the certificate path
 #check_crl=1
 
+# TLS Session Lifetime in seconds
+# This can be used to allow TLS sessions to be cached and resumed with an
+# abbreviated handshake when using EAP-TLS/TTLS/PEAP.
+# (default: 0 = session caching and resumption disabled)
+#tls_session_lifetime=3600
+
 # Cached OCSP stapling response (DER encoded)
 # If set, this file is sent as a certificate status response by the EAP server
 # if the EAP peer requests certificate status in the ClientHello message.
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 07550bd..c9a3764 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -330,6 +330,7 @@
 	char *private_key;
 	char *private_key_passwd;
 	int check_crl;
+	unsigned int tls_session_lifetime;
 	char *ocsp_stapling_response;
 	char *dh_file;
 	char *openssl_ciphers;
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index f10e1b7..934dcfc 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -132,6 +132,7 @@
 #endif /* CONFIG_HS20 */
 	srv.erp = conf->eap_server_erp;
 	srv.erp_domain = conf->erp_domain;
+	srv.tls_session_lifetime = conf->tls_session_lifetime;
 
 	hapd->radius_srv = radius_server_init(&srv);
 	if (hapd->radius_srv == NULL) {
@@ -151,9 +152,12 @@
 	if (hapd->conf->eap_server &&
 	    (hapd->conf->ca_cert || hapd->conf->server_cert ||
 	     hapd->conf->private_key || hapd->conf->dh_file)) {
+		struct tls_config conf;
 		struct tls_connection_params params;
 
-		hapd->ssl_ctx = tls_init(NULL);
+		os_memset(&conf, 0, sizeof(conf));
+		conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
+		hapd->ssl_ctx = tls_init(&conf);
 		if (hapd->ssl_ctx == NULL) {
 			wpa_printf(MSG_ERROR, "Failed to initialize TLS");
 			authsrv_deinit(hapd);
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 2edc9e0..0f2d428 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -2106,6 +2106,7 @@
 	conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
 	conf.erp_domain = hapd->conf->erp_domain;
 	conf.erp = hapd->conf->eap_server_erp;
+	conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
 	conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
 	conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
 	conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 31c4e36..d2196dd 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -79,6 +79,7 @@
 	int fips_mode;
 	int cert_in_cb;
 	const char *openssl_ciphers;
+	unsigned int tls_session_lifetime;
 
 	void (*event_cb)(void *ctx, enum tls_event ev,
 			 union tls_event_data *data);
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 09be581..69eaab8 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -131,6 +131,7 @@
 	const u8 *server_id;
 	size_t server_id_len;
 	int erp;
+	unsigned int tls_session_lifetime;
 
 #ifdef CONFIG_TESTING_OPTIONS
 	u32 tls_test_flags;
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 978c879..c90443d 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -210,6 +210,7 @@
 	Boolean initiate_reauth_start_sent;
 	Boolean try_initiate_reauth;
 	int erp;
+	unsigned int tls_session_lifetime;
 
 #ifdef CONFIG_TESTING_OPTIONS
 	u32 tls_test_flags;
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index b235a0f..84ecafc 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -1865,6 +1865,7 @@
 	sm->server_id = conf->server_id;
 	sm->server_id_len = conf->server_id_len;
 	sm->erp = conf->erp;
+	sm->tls_session_lifetime = conf->tls_session_lifetime;
 
 #ifdef CONFIG_TESTING_OPTIONS
 	sm->tls_test_flags = conf->tls_test_flags;
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index cbd5287..f9f91ad 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -835,6 +835,7 @@
 	eap_conf.server_id = eapol->conf.server_id;
 	eap_conf.server_id_len = eapol->conf.server_id_len;
 	eap_conf.erp = eapol->conf.erp;
+	eap_conf.tls_session_lifetime = eapol->conf.tls_session_lifetime;
 	sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
 	if (sm->eap == NULL) {
 		eapol_auth_free(sm);
@@ -1229,6 +1230,7 @@
 	}
 	dst->erp_send_reauth_start = src->erp_send_reauth_start;
 	dst->erp = src->erp;
+	dst->tls_session_lifetime = src->tls_session_lifetime;
 
 	return 0;
 
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index 1e0d3cc..e1974e4 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -27,6 +27,7 @@
 	int erp_send_reauth_start;
 	char *erp_domain; /* a copy of this will be allocated */
 	int erp; /* Whether ERP is enabled on authentication server */
+	unsigned int tls_session_lifetime;
 	u8 *pac_opaque_encr_key;
 	u8 *eap_fast_a_id;
 	size_t eap_fast_a_id_len;
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index bdb7e42..744283c 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -265,6 +265,8 @@
 
 	struct dl_list erp_keys; /* struct eap_server_erp_key */
 
+	unsigned int tls_session_lifetime;
+
 	/**
 	 * wps - Wi-Fi Protected Setup context
 	 *
@@ -688,6 +690,7 @@
 	eap_conf.server_id = (const u8 *) data->server_id;
 	eap_conf.server_id_len = os_strlen(data->server_id);
 	eap_conf.erp = data->erp;
+	eap_conf.tls_session_lifetime = data->tls_session_lifetime;
 	radius_server_testing_options(sess, &eap_conf);
 	sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
 				       &eap_conf);
@@ -1745,6 +1748,7 @@
 	}
 	data->erp = conf->erp;
 	data->erp_domain = conf->erp_domain;
+	data->tls_session_lifetime = conf->tls_session_lifetime;
 
 	if (conf->subscr_remediation_url) {
 		data->subscr_remediation_url =
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index ca4e38c..7a25802 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -170,6 +170,8 @@
 
 	const char *erp_domain;
 
+	unsigned int tls_session_lifetime;
+
 	/**
 	 * wps - Wi-Fi Protected Setup context
 	 *