crl_reload_interval: Add reload crl support

Message ID 1526920785-39066-1-git-send-email-sam.voss@rockwellcollins.com
State New
Headers show
Series
  • crl_reload_interval: Add reload crl support
Related show

Commit Message

Sam Voss May 21, 2018, 4:39 p.m.
From: Paresh Chaudhary <paresh.chaudhary@rockwellcollins.com>

This patch has been added new flag 'crl_reload_interval' to reload crl. This can
be used to reload ca_cert file on every new tls session if difference between
last reload and current reload time(seconds) greater-than crl_reload_interval.

Note: If interval time > 0 and < 300 then crl_reload_interval will reset
to 300 seconds. For this support 'check_crl' should be 1 or 2.

Signed-off-by: Paresh Chaudhary <paresh.chaudhary@rockwellcollins.com>
Signed-off-by: Sam Voss <sam.voss@rockwellcollins.com>
---
 hostapd/config_file.c    |   2 +
 hostapd/hostapd.conf     |   9 +++++
 src/ap/ap_config.h       |   1 +
 src/ap/authsrv.c         |   9 +++++
 src/crypto/tls.h         |  11 ++++++
 src/crypto/tls_openssl.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++-
 6 files changed, 131 insertions(+), 1 deletion(-)

Patch

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 5079f69..5116857 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2131,6 +2131,8 @@  static int hostapd_config_fill(struct hostapd_config *conf,
 		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, "crl_reload_interval") == 0) {
+		bss->crl_reload_interval = 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) {
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index fa9a855..3f1c325 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -795,6 +795,15 @@  eap_server=0
 # 2 = check all CRLs in the certificate path
 #check_crl=1
 
+# crl reload interval in seconds
+# This can be used to reload ca_cert file on every new tls session if difference
+# between last reload and current reload time(seconds) greater-than
+# crl_reload_interval
+# Note: If interval time > 0 and < 300 then crl_reload_interval will reset to
+# 300 seconds. For this support 'check_crl' should be 1 or 2.
+# 0 = do not reload CRLS (default)
+#crl_reload_interval = 300
+
 # 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.
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 8c8f7e2..63d3786 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -352,6 +352,7 @@  struct hostapd_bss_config {
 	char *private_key;
 	char *private_key_passwd;
 	int check_crl;
+	unsigned int crl_reload_interval;
 	unsigned int tls_session_lifetime;
 	char *ocsp_stapling_response;
 	char *ocsp_stapling_response_multi;
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index cdb49cd..c16d679 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -157,6 +157,15 @@  int authsrv_init(struct hostapd_data *hapd)
 
 		os_memset(&conf, 0, sizeof(conf));
 		conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
+		if (hapd->conf->crl_reload_interval > 0 && hapd->conf->check_crl <=0) {
+			wpa_printf(MSG_INFO, "Failed to enable crl reload functionality,"
+				   "It's depend on check_crl.");
+		}
+		if (hapd->conf->check_crl > 0 && hapd->conf->crl_reload_interval > 0) {
+			conf.crl_reload_interval = hapd->conf->crl_reload_interval;
+			wpa_printf(MSG_INFO, "Enabled crl reload functionality");
+		}
+
 		hapd->ssl_ctx = tls_init(&conf);
 		if (hapd->ssl_ctx == NULL) {
 			wpa_printf(MSG_ERROR, "Failed to initialize TLS");
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 11d504a..adbc9d9 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -8,6 +8,7 @@ 
 
 #ifndef TLS_H
 #define TLS_H
+#include <openssl/x509v3.h>
 
 struct tls_connection;
 
@@ -80,6 +81,7 @@  struct tls_config {
 	int cert_in_cb;
 	const char *openssl_ciphers;
 	unsigned int tls_session_lifetime;
+	unsigned int crl_reload_interval;
 
 	void (*event_cb)(void *ctx, enum tls_event ev,
 			 union tls_event_data *data);
@@ -224,6 +226,15 @@  void tls_deinit(void *tls_ctx);
 int tls_get_errors(void *tls_ctx);
 
 /**
+ * tls_crl_cert_reload - Reload crl cert and init new store
+ * @ca_cert : ca_cert file
+ * @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
+ * 2 = verify CRL for all certificates
+ * Returns : store pointer on success and NULL on failure
+ */
+X509_STORE *tls_crl_cert_reload(const char *ca_cert, int check_crl);
+
+/**
  * tls_connection_init - Initialize a new TLS connection
  * @tls_ctx: TLS context data from tls_init()
  * Returns: Connection context data, conn for other function calls
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 23ac64b..7575688 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -7,6 +7,7 @@ 
  */
 
 #include "includes.h"
+#include <pthread.h>
 
 #ifndef CONFIG_SMARTCARD
 #ifndef OPENSSL_NO_ENGINE
@@ -188,6 +189,8 @@  struct tls_context {
 	void *cb_ctx;
 	int cert_in_cb;
 	char *ocsp_stapling_response;
+	int check_crl;
+	const char *ca_cert;
 };
 
 static struct tls_context *tls_global = NULL;
@@ -196,6 +199,10 @@  static struct tls_context *tls_global = NULL;
 struct tls_data {
 	SSL_CTX *ssl;
 	unsigned int tls_session_lifetime;
+	unsigned int crl_reload_interval;
+	unsigned int crl_last_reload;
+	X509_STORE   *old_x509_store;
+	pthread_mutex_t mutex;
 };
 
 struct tls_connection {
@@ -966,8 +973,15 @@  void * tls_init(const struct tls_config *conf)
 		return NULL;
 	}
 	data->ssl = ssl;
-	if (conf)
+	if (conf) {
 		data->tls_session_lifetime = conf->tls_session_lifetime;
+		data->crl_reload_interval  = conf->crl_reload_interval;
+		if (data->crl_reload_interval > 0 && data->crl_reload_interval < 300) {
+			wpa_printf(MSG_INFO,
+				   "crl reload interval is set too low, reset it to 300");
+			data->crl_reload_interval = 300;
+		}
+	}
 
 	SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
 	SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
@@ -1026,6 +1040,9 @@  void * tls_init(const struct tls_config *conf)
 		return NULL;
 	}
 
+	/* Init mutex */
+	pthread_mutex_init(&data->mutex, NULL);
+
 	return data;
 }
 
@@ -1058,6 +1075,7 @@  void tls_deinit(void *ssl_ctx)
 		tls_global = NULL;
 	}
 
+	pthread_mutex_destroy(&data->mutex);
 	os_free(data);
 }
 
@@ -1331,8 +1349,39 @@  struct tls_connection * tls_connection_init(void *ssl_ctx)
 	SSL_CTX *ssl = data->ssl;
 	struct tls_connection *conn;
 	long options;
+	X509_STORE  *new_cert_store;
+	time_t now;
 	struct tls_context *context = SSL_CTX_get_app_data(ssl);
 
+	/* Get current time */
+	now = time(NULL);
+
+	/* Replace X509 store if it is time to update crl */
+	/* Replace X509 store if difference between current time and previous store
+	 * reload time greater-than crl_reload_interval */
+	if (data->crl_reload_interval > 0 && data->crl_last_reload +
+					data->crl_reload_interval <= now) {
+		pthread_mutex_lock(&data->mutex);
+		/* recheck data->crl_last_reload because it may be inaccurate
+		 * without mutex */
+		if (data->crl_last_reload + data->crl_reload_interval <= now) {
+			wpa_printf(MSG_INFO, "Flushing X509 store with ca_cert file");
+			new_cert_store = (X509_STORE *)tls_crl_cert_reload
+					(tls_global->ca_cert, tls_global->check_crl);
+			if (new_cert_store == NULL) {
+				wpa_printf(MSG_ERROR,
+					   "Error replacing X509 store with ca_cert file");
+			} else {
+				/*Free old store */
+				if (data->old_x509_store) X509_STORE_free(data->old_x509_store);
+				data->old_x509_store = ssl->cert_store;
+				ssl->cert_store = new_cert_store;
+				data->crl_last_reload = now;
+			}
+		}
+		pthread_mutex_unlock(&data->mutex);
+	}
+
 	conn = os_zalloc(sizeof(*conn));
 	if (conn == NULL)
 		return NULL;
@@ -2159,6 +2208,37 @@  static int tls_connection_ca_cert(struct tls_data *data,
 }
 
 
+X509_STORE *tls_crl_cert_reload(const char *ca_cert, int check_crl)
+{
+	int flags;
+	X509_STORE *store;
+
+	store = X509_STORE_new();
+	if (store == NULL) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
+			   "certificate store", __func__);
+		return NULL;
+	}
+
+	if (ca_cert) {
+		if (!X509_STORE_load_locations(store, ca_cert, NULL)) {
+			tls_show_errors(MSG_WARNING, __func__,
+					"Failed to load root certificates");
+			return NULL;
+		}
+	}
+
+	if (check_crl)
+		flags = X509_V_FLAG_CRL_CHECK;
+	if (check_crl == 2)
+		flags |= X509_V_FLAG_CRL_CHECK_ALL;
+
+	X509_STORE_set_flags(store, flags);
+
+	return store;
+}
+
+
 static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
 {
 	SSL_CTX *ssl_ctx = data->ssl;
@@ -2179,6 +2259,13 @@  static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
 		SSL_CTX_set_client_CA_list(ssl_ctx,
 					   SSL_load_client_CA_file(ca_cert));
 #endif /* OPENSSL_NO_STDIO */
+
+		if (NULL == tls_global) {
+			tls_show_errors(MSG_INFO, __func__, "Failed setting "
+					"ca_cert in tls_global context.");
+		} else {
+			tls_global->ca_cert = ca_cert;
+		}
 	}
 
 	return 0;
@@ -2202,6 +2289,17 @@  int tls_global_set_verify(void *ssl_ctx, int check_crl)
 		if (check_crl == 2)
 			flags |= X509_V_FLAG_CRL_CHECK_ALL;
 		X509_STORE_set_flags(cs, flags);
+
+		if (NULL == tls_global) {
+			tls_show_errors(MSG_INFO, __func__, "Failed setting "
+					"check crl mode in tls_global context.");
+		} else {
+			tls_global->check_crl = check_crl;
+		}
+
+		/* Store crl last reload time */
+		data->crl_last_reload = time(NULL);
+		data->old_x509_store = NULL;
 	}
 	return 0;
 }