@@ -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) {
@@ -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.
@@ -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;
@@ -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");
@@ -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
@@ -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;
}