session FEATURE server fucntions now thread-safe
Hopefully.
diff --git a/src/session_server_tls.c b/src/session_server_tls.c
index c3e9f9e..1abca70 100644
--- a/src/session_server_tls.c
+++ b/src/session_server_tls.c
@@ -34,6 +34,9 @@
extern struct nc_server_opts server_opts;
struct nc_tls_server_opts tls_opts = {
+ .tls_ctx_lock = PTHREAD_MUTEX_INITIALIZER,
+ .crl_lock = PTHREAD_MUTEX_INITIALIZER,
+ .ctn_lock = PTHREAD_MUTEX_INITIALIZER,
.verify_once = PTHREAD_ONCE_INIT
};
@@ -287,11 +290,14 @@
unsigned int buf_len = 64;
int ret = 0;
- if (cert == NULL || map_type == NULL || name == NULL) {
+ if (!cert || !map_type || !name) {
free(buf);
return -1;
}
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.ctn_lock);
+
for (i = 0; i < tls_opts.ctn_count; ++i) {
/* MD5 */
if (!strncmp(tls_opts.ctn[i].fingerprint, "01", 2)) {
@@ -430,6 +436,9 @@
}
cleanup:
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.ctn_lock);
+
free(digest_md5);
free(digest_sha1);
free(digest_sha224);
@@ -515,6 +524,9 @@
VRB("Cert verify: issuer: %s", cp);
OPENSSL_free(cp);
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.crl_lock);
+
/* check for revocation if set */
if (tls_opts.crl_store) {
/* try to retrieve a CRL corresponding to the _subject_ of
@@ -547,6 +559,8 @@
if (pubkey) {
EVP_PKEY_free(pubkey);
}
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.crl_lock);
return 0;
}
if (pubkey) {
@@ -558,19 +572,23 @@
ERR("Cert verify CRL: invalid nextUpdate field.");
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
X509_OBJECT_free_contents(&obj);
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.crl_lock);
return 0;
}
if (X509_cmp_current_time(next_update) < 0) {
ERR("Cert verify CRL: expired - revoking all certificates.");
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CRL_HAS_EXPIRED);
X509_OBJECT_free_contents(&obj);
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.crl_lock);
return 0;
}
X509_OBJECT_free_contents(&obj);
}
/* try to retrieve a CRL corresponding to the _issuer_ of
- * the current certificate in order to check for revocation */
+ * the current certificate in order to check for revocation */
memset((char *)&obj, 0, sizeof(obj));
X509_STORE_CTX_init(&store_ctx, tls_opts.crl_store, NULL, NULL);
rc = X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj);
@@ -588,6 +606,8 @@
OPENSSL_free(cp);
X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_CERT_REVOKED);
X509_OBJECT_free_contents(&obj);
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.crl_lock);
return 0;
}
}
@@ -595,6 +615,9 @@
}
}
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.crl_lock);
+
/* cert-to-name already successful */
if (session->username) {
return 1;
@@ -649,11 +672,14 @@
return -1;
}
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.tls_ctx_lock);
+
if (!tls_opts.tls_ctx) {
tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!tls_opts.tls_ctx) {
ERR("%s: failed to create TLS context.", __func__);
- return -1;
+ goto fail;
}
SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
}
@@ -662,14 +688,20 @@
if (!x509_cert || (SSL_CTX_use_certificate(tls_opts.tls_ctx, x509_cert) != 1)) {
ERR("%s: loading the server certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
X509_free(x509_cert);
- return -1;
+ goto fail;
}
X509_free(x509_cert);
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
return 0;
+
+fail:
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
+ return -1;
}
-/* PEM only */
API int
nc_tls_server_set_cert_path(const char *cert_path)
{
@@ -678,21 +710,31 @@
return -1;
}
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.tls_ctx_lock);
+
if (!tls_opts.tls_ctx) {
tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!tls_opts.tls_ctx) {
ERR("%s: failed to create TLS context.", __func__);
- return -1;
+ goto fail;
}
SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
}
if (SSL_CTX_use_certificate_file(tls_opts.tls_ctx, cert_path, SSL_FILETYPE_PEM) != 1) {
ERR("%s: loading the server certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
- return -1;
+ goto fail;
}
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
return 0;
+
+fail:
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
+ return -1;
}
API int
@@ -705,11 +747,14 @@
return -1;
}
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.tls_ctx_lock);
+
if (!tls_opts.tls_ctx) {
tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!tls_opts.tls_ctx) {
ERR("%s: failed to create TLS context.", __func__);
- return -1;
+ goto fail;
}
SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
}
@@ -718,14 +763,20 @@
if (!key || (SSL_CTX_use_PrivateKey(tls_opts.tls_ctx, key) != 1)) {
ERR("%s: loading the server private key failed (%s).", ERR_reason_error_string(ERR_get_error()));
EVP_PKEY_free(key);
- return -1;
+ goto fail;
}
EVP_PKEY_free(key);
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
return 0;
+
+fail:
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
+ return -1;
}
-/* PEM only */
API int
nc_tls_server_set_key_path(const char *privkey_path)
{
@@ -734,21 +785,31 @@
return -1;
}
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.tls_ctx_lock);
+
if (!tls_opts.tls_ctx) {
tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!tls_opts.tls_ctx) {
ERR("%s: failed to create TLS context.", __func__);
- return -1;
+ goto fail;
}
SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
}
if (SSL_CTX_use_PrivateKey_file(tls_opts.tls_ctx, privkey_path, SSL_FILETYPE_PEM) != 1) {
ERR("%s: loading the server priavte key failed (%s).", ERR_reason_error_string(ERR_get_error()));
- return -1;
+ goto fail;
}
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
return 0;
+
+fail:
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
+ return -1;
}
API int
@@ -762,11 +823,14 @@
return -1;
}
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.tls_ctx_lock);
+
if (!tls_opts.tls_ctx) {
tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!tls_opts.tls_ctx) {
ERR("%s: failed to create TLS context.", __func__);
- return -1;
+ goto fail;
}
SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
}
@@ -781,11 +845,18 @@
if (!x509_cert || (X509_STORE_add_cert(cert_store, x509_cert) != 1)) {
ERR("%s: adding a trusted certificate failed (%s).", ERR_reason_error_string(ERR_get_error()));
X509_free(x509_cert);
- return -1;
+ goto fail;
}
X509_free(x509_cert);
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
return 0;
+
+fail:
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
+ return -1;
}
API int
@@ -799,11 +870,14 @@
return -1;
}
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.tls_ctx_lock);
+
if (!tls_opts.tls_ctx) {
tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!tls_opts.tls_ctx) {
ERR("%s: failed to create TLS context.", __func__);
- return -1;
+ goto fail;
}
SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
}
@@ -820,11 +894,18 @@
ERR("%s: adding a trusted certificate failed (%s).",
(errno ? strerror(errno) : ERR_reason_error_string(ERR_get_error())));
X509_free(x509_cert);
- return -1;
+ goto fail;
}
X509_free(x509_cert);
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
return 0;
+
+fail:
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
+ return -1;
}
API int
@@ -838,11 +919,14 @@
return -1;
}
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.tls_ctx_lock);
+
if (!tls_opts.tls_ctx) {
tls_opts.tls_ctx = SSL_CTX_new(TLSv1_2_server_method());
if (!tls_opts.tls_ctx) {
ERR("%s: failed to create TLS context.", __func__);
- return -1;
+ goto fail;
}
SSL_CTX_set_verify(tls_opts.tls_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nc_tlsclb_verify);
}
@@ -857,12 +941,12 @@
lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_file());
if (!lookup) {
ERR("%s: failed to add lookup method.", __func__);
- return -1;
+ goto fail;
}
if (X509_LOOKUP_load_file(lookup, cacert_file_path, X509_FILETYPE_PEM) != 1) {
ERR("%s: failed to add trusted cert file (%s).", __func__, ERR_reason_error_string(ERR_get_error()));
- return -1;
+ goto fail;
}
}
@@ -870,27 +954,40 @@
lookup = X509_STORE_add_lookup(cert_store, X509_LOOKUP_hash_dir());
if (!lookup) {
ERR("%s: failed to add lookup method.", __func__);
- return -1;
+ goto fail;
}
if (X509_LOOKUP_add_dir(lookup, cacert_dir_path, X509_FILETYPE_PEM) != 1) {
ERR("%s: failed to add trusted cert directory (%s).", __func__, ERR_reason_error_string(ERR_get_error()));
- return -1;
+ goto fail;
}
}
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
return 0;
+
+fail:
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
+ return -1;
}
API void
nc_tls_server_destroy_certs(void)
{
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.tls_ctx_lock);
+
if (!tls_opts.tls_ctx) {
return;
}
SSL_CTX_free(tls_opts.tls_ctx);
tls_opts.tls_ctx = NULL;
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
}
API int
@@ -903,6 +1000,9 @@
return -1;
}
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.crl_lock);
+
if (!tls_opts.crl_store) {
tls_opts.crl_store = X509_STORE_new();
}
@@ -911,12 +1011,12 @@
lookup = X509_STORE_add_lookup(tls_opts.crl_store, X509_LOOKUP_file());
if (!lookup) {
ERR("%s: failed to add lookup method.", __func__);
- return -1;
+ goto fail;
}
if (X509_LOOKUP_load_file(lookup, crl_file_path, X509_FILETYPE_PEM) != 1) {
ERR("%s: failed to add revocation lookup file (%s).", __func__, ERR_reason_error_string(ERR_get_error()));
- return -1;
+ goto fail;
}
}
@@ -924,27 +1024,40 @@
lookup = X509_STORE_add_lookup(tls_opts.crl_store, X509_LOOKUP_hash_dir());
if (!lookup) {
ERR("%s: failed to add lookup method.", __func__);
- return -1;
+ goto fail;
}
if (X509_LOOKUP_add_dir(lookup, crl_dir_path, X509_FILETYPE_PEM) != 1) {
ERR("%s: failed to add revocation lookup directory (%s).", __func__, ERR_reason_error_string(ERR_get_error()));
- return -1;
+ goto fail;
}
}
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.crl_lock);
return 0;
+
+fail:
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.crl_lock);
+ return -1;
}
API void
nc_tls_server_destroy_crls(void)
{
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.crl_lock);
+
if (!tls_opts.crl_store) {
return;
}
X509_STORE_free(tls_opts.crl_store);
tls_opts.crl_store = NULL;
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.crl_lock);
}
API int
@@ -956,6 +1069,9 @@
return -1;
}
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.ctn_lock);
+
++tls_opts.ctn_count;
tls_opts.ctn = realloc(tls_opts.ctn, tls_opts.ctn_count * sizeof *tls_opts.ctn);
@@ -964,6 +1080,9 @@
tls_opts.ctn[tls_opts.ctn_count - 1].map_type = map_type;
tls_opts.ctn[tls_opts.ctn_count - 1].name = lydict_insert(server_opts.ctx, name, 0);
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.ctn_lock);
+
return 0;
}
@@ -973,6 +1092,9 @@
uint16_t i;
int ret = -1;
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.ctn_lock);
+
if ((id < 0) && !fingerprint && !map_type && !name) {
for (i = 0; i < tls_opts.ctn_count; ++i) {
lydict_remove(server_opts.ctx, tls_opts.ctn[i].fingerprint);
@@ -1000,6 +1122,9 @@
}
}
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.ctn_lock);
+
return ret;
}
@@ -1040,11 +1165,15 @@
return -1;
}
- /* data waiting */
+ /* data waiting, prepare session */
session->ti_type = NC_TI_OPENSSL;
+ /* LOCK */
+ pthread_mutex_lock(&tls_opts.tls_ctx_lock);
session->ti.tls = SSL_new(tls_opts.tls_ctx);
+ /* UNLOCK */
+ pthread_mutex_unlock(&tls_opts.tls_ctx_lock);
if (!session->ti.tls) {
- ERRMEM;
+ ERR("%s: failed to create TLS structure from context.", __func__);
close(sock);
return -1;
}
@@ -1057,6 +1186,7 @@
pthread_setspecific(tls_opts.verify_key, session);
ret = SSL_accept(session->ti.tls);
+
if (ret != 1) {
switch (SSL_get_error(session->ti.tls, ret)) {
case SSL_ERROR_SYSCALL: