server config UPDATE dynamic endpt references

Get endpoint references dynamically based on referenced endpt name.
Also some tls fixes.
diff --git a/modules/libnetconf2-netconf-server@2023-09-07.yang b/modules/libnetconf2-netconf-server@2023-09-07.yang
index 6fb4b0f..0ef941f 100644
--- a/modules/libnetconf2-netconf-server@2023-09-07.yang
+++ b/modules/libnetconf2-netconf-server@2023-09-07.yang
@@ -281,7 +281,7 @@
     }
   }
 
-  grouping endpoint-auth-reference-grouping {
+  grouping endpoint-reference-grouping {
     description
       "Reference to another endpoint. The purpose is to use the referenced endpoint's authentication mechanisms.
        If a connection occurs on an endpoint, the connecting user will be tried to be authenticated
@@ -290,14 +290,9 @@
        using the referenced endpoint's mechanisms. The references can be
        multiple, however there must not be a cycle.";
 
-    leaf endpoint-client-auth {
-      type union {
-        type leafref {
-          path "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:name";
-        }
-        type leafref {
-          path "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:name";
-        }
+    leaf endpoint-reference {
+      type leafref {
+        path "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:name";
       }
     }
   }
@@ -403,19 +398,19 @@
   }
 
   augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" {
-    uses endpoint-auth-reference-grouping;
+    uses endpoint-reference-grouping;
   }
 
   augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:ssh/ncs:ssh/ncs:ssh-server-parameters/ncs:client-authentication" {
-    uses endpoint-auth-reference-grouping;
+    uses endpoint-reference-grouping;
   }
 
   augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" {
-    uses endpoint-auth-reference-grouping;
+    uses endpoint-reference-grouping;
   }
 
   augment "/ncs:netconf-server/ncs:call-home/ncs:netconf-client/ncs:endpoints/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" {
-    uses endpoint-auth-reference-grouping;
+    uses endpoint-reference-grouping;
   }
 
   augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport/ncs:tls/ncs:tls/ncs:tls-server-parameters/ncs:client-authentication" {
diff --git a/src/server_config.c b/src/server_config.c
index d31c191..47bda15 100644
--- a/src/server_config.c
+++ b/src/server_config.c
@@ -776,10 +776,60 @@
     free(opts);
 }
 
+static void
+nc_server_config_del_endpt_references(const char *referenced_endpt_name)
+{
+    uint16_t i, j;
+
+    for (i = 0; i < server_opts.endpt_count; i++) {
+        if (server_opts.endpts[i].referenced_endpt_name) {
+            if (!strcmp(server_opts.endpts[i].referenced_endpt_name, referenced_endpt_name)) {
+                free(server_opts.endpts[i].referenced_endpt_name);
+                server_opts.endpts[i].referenced_endpt_name = NULL;
+
+                if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
+                    server_opts.endpts[i].opts.ssh->referenced_endpt_name = NULL;
+                } else {
+                    server_opts.endpts[i].opts.tls->referenced_endpt_name = NULL;
+                }
+            }
+        }
+    }
+
+    /* LOCK */
+    pthread_rwlock_rdlock(&server_opts.ch_client_lock);
+    for (i = 0; i < server_opts.ch_client_count; i++) {
+        /* LOCK */
+        pthread_mutex_lock(&server_opts.ch_clients[i].lock);
+        for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
+            if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
+                if (!strcmp(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, referenced_endpt_name)) {
+                    free(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name);
+                    server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name = NULL;
+
+                    if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_LIBSSH) {
+                        server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = NULL;
+                    } else {
+                        server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = NULL;
+                    }
+                }
+            }
+        }
+        /* UNLOCK */
+        pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
+    }
+
+    /* UNLOCK */
+    pthread_rwlock_unlock(&server_opts.ch_client_lock);
+}
+
 void
 nc_server_config_del_endpt_ssh(struct nc_endpt *endpt, struct nc_bind *bind)
 {
+    /* delete any references to this endpoint */
+    nc_server_config_del_endpt_references(endpt->name);
     free(endpt->name);
+
     free(endpt->referenced_endpt_name);
     nc_server_config_del_ssh_opts(bind, endpt->opts.ssh);
 
@@ -936,7 +986,10 @@
 static void
 nc_server_config_del_endpt_tls(struct nc_endpt *endpt, struct nc_bind *bind)
 {
+    /* delete any references to this endpoint */
+    nc_server_config_del_endpt_references(endpt->name);
     free(endpt->name);
+
     free(endpt->referenced_endpt_name);
 
     nc_server_config_del_tls_opts(bind, endpt->opts.tls);
@@ -2954,148 +3007,213 @@
 
 #ifdef NC_ENABLED_SSH_TLS
 
+static int
+nc_server_config_check_endpt_reference_cycle(struct nc_endpt *original, struct nc_endpt *next)
+{
+    if (!next->referenced_endpt_name) {
+        /* no further reference -> no cycle */
+        return 0;
+    }
+
+    if (!strcmp(original->name, next->referenced_endpt_name)) {
+        /* found cycle */
+        return 1;
+    } else {
+        if (nc_server_get_referenced_endpt(next->referenced_endpt_name, &next)) {
+            /* referenced endpoint does not exist */
+            return 1;
+        }
+
+        /* continue further */
+        return nc_server_config_check_endpt_reference_cycle(original, next);
+    }
+}
+
 /**
- * @brief Set all endpoint client auth references, which couldn't be set while parsing data.
+ * @brief Set all endpoint references.
  *
  * @return 0 on success, 1 on error.
  */
 static int
-nc_server_config_fill_endpt_client_auth(void)
+nc_server_config_check_endpt_references(void)
 {
     uint16_t i, j;
+    struct nc_endpt *referenced_endpt = NULL;
 
+    /* first do listen endpoints */
     for (i = 0; i < server_opts.endpt_count; i++) {
         /* go through all the endpoints */
         if (server_opts.endpts[i].referenced_endpt_name) {
-            /* endpt has a reference, that hasn't been set yet */
-            for (j = 0; j < server_opts.endpt_count; j++) {
-                /* go through all the endpts */
-                if (!strcmp(server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[j].name)) {
-                    /* found the endpoint we were looking for,
-                     * assign the server opts from the referenced endpt */
-                    if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
-                        server_opts.endpts[i].opts.ssh->endpt_client_ref = &server_opts.endpts[j];
-                        break;
-                    } else if (server_opts.endpts[i].ti == NC_TI_OPENSSL) {
-                        server_opts.endpts[i].opts.tls->endpt_client_ref = &server_opts.endpts[j];
-                        break;
-                    } else {
-                        ERRINT;
-                        return 1;
-                    }
-                }
-            }
-
-            /* didn't find the endpoint */
-            if (j == server_opts.endpt_count) {
-                ERR(NULL, "Endpoint \"%s\" referenced by \"%s\" not found.",
+            /* get referenced endpt */
+            if (nc_server_get_referenced_endpt(server_opts.endpts[i].referenced_endpt_name, &referenced_endpt)) {
+                ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" does not exist.",
                         server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
                 return 1;
             }
+
+            /* check if the endpoint references itself */
+            if (&server_opts.endpts[i] == referenced_endpt) {
+                ERR(NULL, "Endpoint \"%s\" references itself.", server_opts.endpts[i].name);
+                return 1;
+            }
+
+            /* check transport */
+            if ((server_opts.endpts[i].ti != referenced_endpt->ti)) {
+                ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has different transport type.",
+                        server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
+                return 1;
+            } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) {
+                ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" has unsupported transport type.",
+                        server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
+                return 1;
+            }
+
+            /* check cyclic reference */
+            if (nc_server_config_check_endpt_reference_cycle(&server_opts.endpts[i], referenced_endpt)) {
+                ERR(NULL, "Endpoint \"%s\" referenced by endpoint \"%s\" creates a cycle.",
+                        server_opts.endpts[i].referenced_endpt_name, server_opts.endpts[i].name);
+                return 1;
+            }
+
+            /* all went well, assign the name to the opts, so we can access it for auth */
+            if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
+                server_opts.endpts[i].opts.ssh->referenced_endpt_name = referenced_endpt->name;
+            } else {
+                server_opts.endpts[i].opts.tls->referenced_endpt_name = referenced_endpt->name;
+            }
         }
     }
 
+    /* now check all the call home endpoints */
+    /* LOCK */
+    pthread_rwlock_rdlock(&server_opts.ch_client_lock);
+    for (i = 0; i < server_opts.ch_client_count; i++) {
+        /* LOCK */
+        pthread_mutex_lock(&server_opts.ch_clients[i].lock);
+        for (j = 0; j < server_opts.ch_clients[i].ch_endpt_count; j++) {
+            if (server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name) {
+                /* get referenced endpt */
+                if (nc_server_get_referenced_endpt(server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, &referenced_endpt)) {
+                    ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" does not exist.",
+                            server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
+                    goto ch_fail;
+                }
+
+                /* check transport */
+                if (server_opts.ch_clients[i].ch_endpts[j].ti != referenced_endpt->ti) {
+                    ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has different transport type.",
+                            server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
+                    goto ch_fail;
+                } else if ((referenced_endpt->ti != NC_TI_LIBSSH) && (referenced_endpt->ti != NC_TI_OPENSSL)) {
+                    ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" has unsupported transport type.",
+                            server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
+                    goto ch_fail;
+                }
+
+                /* check cyclic reference */
+                if (nc_server_config_check_endpt_reference_cycle(referenced_endpt, referenced_endpt)) {
+                    ERR(NULL, "Endpoint \"%s\" referenced by call home endpoint \"%s\" creates a cycle.",
+                            server_opts.ch_clients[i].ch_endpts[j].referenced_endpt_name, server_opts.ch_clients[i].ch_endpts[j].name);
+                    goto ch_fail;
+                }
+
+                /* all went well, assign the name to the opts, so we can access it for auth */
+                if (server_opts.ch_clients[i].ch_endpts[j].ti == NC_TI_LIBSSH) {
+                    server_opts.ch_clients[i].ch_endpts[j].opts.ssh->referenced_endpt_name = referenced_endpt->name;
+                } else {
+                    server_opts.ch_clients[i].ch_endpts[j].opts.tls->referenced_endpt_name = referenced_endpt->name;
+                }
+            }
+        }
+        /* UNLOCK */
+        pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
+    }
+
+    /* UNLOCK */
+    pthread_rwlock_unlock(&server_opts.ch_client_lock);
     return 0;
+
+ch_fail:
+    /* UNLOCK */
+    pthread_mutex_unlock(&server_opts.ch_clients[i].lock);
+    /* UNLOCK */
+    pthread_rwlock_unlock(&server_opts.ch_client_lock);
+    return 1;      
 }
 
 static int
-nc_server_config_endpoint_client_auth_has_cycle(struct nc_endpt *original, struct nc_endpt *next)
-{
-    if (original->ti == NC_TI_LIBSSH) {
-        if (!next->opts.ssh->endpt_client_ref) {
-            /* no further reference -> no cycle */
-            return 0;
-        }
-
-        if (next->opts.ssh->endpt_client_ref == original) {
-            /* found cycle */
-            return 1;
-        } else {
-            /* continue further */
-            return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.ssh->endpt_client_ref);
-        }
-    } else if (original->ti == NC_TI_OPENSSL) {
-        if (!next->opts.tls->endpt_client_ref) {
-            /* no further reference -> no cycle */
-            return 0;
-        }
-
-        if (next->opts.tls->endpt_client_ref == original) {
-            /* found cycle */
-            return 1;
-        } else {
-            /* continue further */
-            return nc_server_config_endpoint_client_auth_has_cycle(original, next->opts.tls->endpt_client_ref);
-        }
-    } else {
-        ERRINT;
-        return 1;
-    }
-}
-
-static int
-nc_server_config_endpoint_client_auth(const struct lyd_node *node, NC_OPERATION op)
+nc_server_config_endpoint_reference(const struct lyd_node *node, NC_OPERATION op)
 {
     int ret = 0;
-    uint16_t i;
-    const char *endpt_name;
-    struct nc_endpt *endpt;
+    struct nc_endpt *endpt = NULL;
+    struct nc_ch_client *ch_client;
+    struct nc_ch_endpt *ch_endpt = NULL;
+    struct nc_server_ssh_opts *ssh = NULL;
+    struct nc_server_tls_opts *tls = NULL;
 
-    assert(!strcmp(LYD_NAME(node), "endpoint-client-auth"));
+    assert(!strcmp(LYD_NAME(node), "endpoint-reference"));
 
-    /* get current endpoint */
-    ret = nc_server_config_get_endpt(node, &endpt, NULL);
+    if (is_ch(node) && nc_server_config_get_ch_client_with_lock(node, &ch_client)) {
+        /* to avoid unlock on fail */
+        return 1;
+    }
+
+    /* get endpt */
+    if (is_listen(node)) {
+        ret = nc_server_config_get_endpt(node, &endpt, NULL);
+    } else {
+        ret = nc_server_config_get_ch_endpt(node, &ch_endpt);
+    }
     if (ret) {
         goto cleanup;
     }
 
     if (op == NC_OP_DELETE) {
-        if (is_ssh(node)) {
-            endpt->opts.ssh->endpt_client_ref = NULL;
+        if (endpt) {
+            free(endpt->referenced_endpt_name);
+            endpt->referenced_endpt_name = NULL;
         } else {
-            endpt->opts.tls->endpt_client_ref = NULL;
+            free(ch_endpt->referenced_endpt_name);
+            ch_endpt->referenced_endpt_name = NULL;
         }
-        goto cleanup;
-    }
+        if (is_ssh(node)) {
+            if (nc_server_config_get_ssh_opts(node, &ssh)) {
+                ret = 1;
+                goto cleanup;
+            }
+        
+            ssh->referenced_endpt_name = NULL;
+        } else {
+            if (nc_server_config_get_tls_opts(node, &tls)) {
+                ret = 1;
+                goto cleanup;
+            }
 
-    /* find the endpoint leafref is referring to */
-    endpt_name = lyd_get_value(node);
-    for (i = 0; i < server_opts.endpt_count; i++) {
-        if (!strcmp(endpt_name, server_opts.endpts[i].name)) {
-            break;
+            tls->referenced_endpt_name = NULL;
         }
-    }
 
-    if (i == server_opts.endpt_count) {
-        /* endpt not found, save the name and try to look it up later */
-        free(endpt->referenced_endpt_name);
-        endpt->referenced_endpt_name = strdup(endpt_name);
-        NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup);
         goto cleanup;
-    }
-
-    /* check for self reference */
-    if (endpt == &server_opts.endpts[i]) {
-        ERR(NULL, "Self endpoint reference detected for endpoint \"%s\".", endpt->name);
-        ret = 1;
-        goto cleanup;
-    }
-
-    /* check for cyclic references */
-    ret = nc_server_config_endpoint_client_auth_has_cycle(endpt, &server_opts.endpts[i]);
-    if (ret) {
-        ERR(NULL, "Cyclic endpoint reference detected for endpoint \"%s\".", endpt->name);
-        goto cleanup;
-    }
-
-    /* assign the current endpt the referrenced endpt */
-    if (is_ssh(node)) {
-        endpt->opts.ssh->endpt_client_ref = &server_opts.endpts[i];
     } else {
-        endpt->opts.tls->endpt_client_ref = &server_opts.endpts[i];
+        /* just set the name, check it once configuring of all nodes is done */
+        if (endpt) {
+            free(endpt->referenced_endpt_name);
+            endpt->referenced_endpt_name = strdup(lyd_get_value(node));
+            NC_CHECK_ERRMEM_GOTO(!endpt->referenced_endpt_name, ret = 1, cleanup);
+        } else {
+            free(ch_endpt->referenced_endpt_name);
+            ch_endpt->referenced_endpt_name = strdup(lyd_get_value(node));
+            NC_CHECK_ERRMEM_GOTO(!ch_endpt->referenced_endpt_name, ret = 1, cleanup);
+        }
+
+        goto cleanup;
     }
 
 cleanup:
+    if (is_ch(node)) {
+        /* UNLOCK */
+        nc_ch_client_unlock(ch_client);
+    }
+
     return ret;
 }
 
@@ -3154,7 +3272,7 @@
 nc_server_config_asymmetric_key(const struct lyd_node *node, NC_OPERATION op)
 {
     int ret = 0;
-    struct nc_endpt *endpt;
+    struct nc_server_tls_opts *opts;
     struct nc_ch_client *ch_client;
 
     assert(!strcmp(LYD_NAME(node), "asymmetric-key"));
@@ -3165,21 +3283,21 @@
         return 1;
     }
 
-    if (nc_server_config_get_endpt(node, &endpt, NULL)) {
+    if (nc_server_config_get_tls_opts(node, &opts)) {
         ret = 1;
         goto cleanup;
     }
 
     if ((op == NC_OP_CREATE) || (op == NC_OP_REPLACE)) {
         /* set to keystore */
-        endpt->opts.tls->store = NC_STORE_KEYSTORE;
+        opts->store = NC_STORE_KEYSTORE;
 
-        free(endpt->opts.tls->key_ref);
-        endpt->opts.tls->key_ref = strdup(lyd_get_value(node));
-        NC_CHECK_ERRMEM_GOTO(!endpt->opts.tls->key_ref, ret = 1, cleanup);
+        free(opts->key_ref);
+        opts->key_ref = strdup(lyd_get_value(node));
+        NC_CHECK_ERRMEM_GOTO(!opts->key_ref, ret = 1, cleanup);
     } else {
-        free(endpt->opts.tls->key_ref);
-        endpt->opts.tls->key_ref = NULL;
+        free(opts->key_ref);
+        opts->key_ref = NULL;
     }
 
 cleanup:
@@ -4134,8 +4252,8 @@
         ret = nc_server_config_encryption_alg(node, op);
     } else if (!strcmp(name, "mac-alg")) {
         ret = nc_server_config_mac_alg(node, op);
-    } else if (!strcmp(name, "endpoint-client-auth")) {
-        ret = nc_server_config_endpoint_client_auth(node, op);
+    } else if (!strcmp(name, "endpoint-reference")) {
+        ret = nc_server_config_endpoint_reference(node, op);
     } else if (!strcmp(name, "tls")) {
         ret = nc_server_config_tls(node, op);
     } else if (!strcmp(name, "cert-data")) {
@@ -4378,8 +4496,8 @@
     }
 
 #ifdef NC_ENABLED_SSH_TLS
-    /* backward check of client auth reference */
-    if (nc_server_config_fill_endpt_client_auth()) {
+    /* check and set all endpoint references */
+    if (nc_server_config_check_endpt_references()) {
         ret = 1;
         goto cleanup;
     }
diff --git a/src/server_config_util_ssh.c b/src/server_config_util_ssh.c
index f3ca8c0..8b162ee 100644
--- a/src/server_config_util_ssh.c
+++ b/src/server_config_util_ssh.c
@@ -605,7 +605,7 @@
     NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1);
 
     return nc_server_config_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/"
-            "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name);
+            "client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name);
 }
 
 API int
@@ -614,7 +614,7 @@
     NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
 
     return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/"
-            "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name);
+            "client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name);
 }
 
 API int
diff --git a/src/server_config_util_tls.c b/src/server_config_util_tls.c
index 66b2559..047a6d5 100644
--- a/src/server_config_util_tls.c
+++ b/src/server_config_util_tls.c
@@ -777,7 +777,7 @@
     NC_CHECK_ARG_RET(NULL, ctx, endpt_name, referenced_endpt, config, 1);
 
     return nc_server_config_create(ctx, config, referenced_endpt, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/"
-            "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name);
+            "client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name);
 }
 
 API int
@@ -786,5 +786,5 @@
     NC_CHECK_ARG_RET(NULL, endpt_name, config, 1);
 
     return nc_server_config_delete(config, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/tls/tls-server-parameters/"
-            "client-authentication/libnetconf2-netconf-server:endpoint-client-auth", endpt_name);
+            "client-authentication/libnetconf2-netconf-server:endpoint-reference", endpt_name);
 }
diff --git a/src/session_p.h b/src/session_p.h
index 5d2ccb1..2b3524d 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -202,7 +202,7 @@
     struct nc_auth_client *auth_clients;    /**< Server's authorized clients. */
     uint16_t client_count;                  /**< Number of server's authorized clients. */
 
-    struct nc_endpt *endpt_client_ref;      /**< Reference to another endpoint (used for client authentication). */
+    char *referenced_endpt_name;            /**< Reference to another endpoint (used for client authentication). */
 
     char *hostkey_algs;                     /**< Hostkey algorithms supported by the server. */
     char *encryption_algs;                  /**< Encryption algorithms supported by the server. */
@@ -275,7 +275,7 @@
     int crl_cert_ext;                           /**< Indicates to use CA's distribution points to obtain CRLs */
     X509_STORE *crl_store;                      /**< Stores all the CRLs */
 
-    struct nc_endpt *endpt_client_ref;          /**< Reference to another endpoint (used for client authentication). */
+    char *referenced_endpt_name;                /**< Reference to another endpoint (used for client authentication). */
 
     unsigned int tls_versions;                  /**< TLS versions */
     char *ciphers;                              /**< TLS ciphers */
@@ -476,12 +476,14 @@
      *                modify CH clients - READ lock ch_client_lock + ch_client_lock */
     struct nc_ch_client {
         char *name;
-
         pthread_t tid;                                  /**< Call Home client's thread ID */
         struct nc_ch_client_thread_arg *thread_data;    /**< Data of the Call Home client's thread */
 
         struct nc_ch_endpt {
             char *name;
+#ifdef NC_ENABLED_SSH_TLS
+            char *referenced_endpt_name;
+#endif /* NC_ENABLED_SSH_TLS */
             NC_TRANSPORT_IMPL ti;
             char *address;
             uint16_t port;
@@ -965,6 +967,15 @@
 void nc_server_ch_client_unlock(struct nc_ch_client *client);
 
 /**
+ * @brief Gets an endpoint structure based on its name.
+ * 
+ * @param[in] name The name of the endpoint.
+ * @param[out] endpt Pointer to the endpoint structure.
+ * @return 0 on success, 1 on failure.
+ */
+int nc_server_get_referenced_endpt(const char *name, struct nc_endpt **endpt);
+
+/**
  * @brief Add a client Call Home bind, listen on it.
  *
  * @param[in] address Address to bind to.
diff --git a/src/session_server.c b/src/session_server.c
index 1fd84fb..90e02ff 100644
--- a/src/session_server.c
+++ b/src/session_server.c
@@ -151,6 +151,22 @@
     pthread_rwlock_unlock(&server_opts.ch_client_lock);
 }
 
+int
+nc_server_get_referenced_endpt(const char *name, struct nc_endpt **endpt)
+{
+    uint16_t i;
+
+    for (i = 0; i < server_opts.endpt_count; i++) {
+        if (!strcmp(name, server_opts.endpts[i].name)) {
+            *endpt = &server_opts.endpts[i];
+            return 0;
+        }
+    }
+
+    ERR(NULL, "Referenced endpoint \"%s\" was not found.", name);
+    return 1;
+}
+
 API void
 nc_session_set_term_reason(struct nc_session *session, NC_SESSION_TERM_REASON reason)
 {
diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c
index c4c3085..cc1f3de 100644
--- a/src/session_server_ssh.c
+++ b/src/session_server_ssh.c
@@ -829,6 +829,7 @@
     int subtype, type, libssh_auth_methods = 0, ret = 0;
     uint16_t i;
     struct nc_auth_client *auth_client = NULL;
+    struct nc_endpt *referenced_endpt;
 
     type = ssh_message_type(msg);
     subtype = ssh_message_subtype(msg);
@@ -980,8 +981,14 @@
         }
 
         if (!auth_client) {
-            if (opts->endpt_client_ref) {
-                return nc_session_ssh_msg(session, opts->endpt_client_ref->opts.ssh, msg, state);
+            if (opts->referenced_endpt_name) {
+                /* client not known by the endpt, but it references another one so try it */
+                if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) {
+                    ERRINT;
+                    return 1;
+                }
+
+                return nc_session_ssh_msg(session, referenced_endpt->opts.ssh, msg, state);
             }
 
             ERR(NULL, "User \"%s\" not known by the server.", username);
diff --git a/src/session_server_tls.c b/src/session_server_tls.c
index de898c8..a11c11b 100644
--- a/src/session_server_tls.c
+++ b/src/session_server_tls.c
@@ -38,12 +38,8 @@
 #include "session_p.h"
 
 struct nc_server_tls_opts tls_ch_opts;
-pthread_mutex_t tls_ch_opts_lock = PTHREAD_MUTEX_INITIALIZER;
 extern struct nc_server_opts server_opts;
 
-static pthread_key_t verify_key;
-static pthread_once_t verify_once = PTHREAD_ONCE_INIT;
-
 static char *
 asn1time_to_str(const ASN1_TIME *t)
 {
@@ -312,7 +308,7 @@
 
         /* first make sure the entry is valid */
         if (!ctn->map_type || ((ctn->map_type == NC_TLS_CTN_SPECIFIED) && !ctn->name)) {
-            VRB(NULL, "Cert verify CTN: entry with id %u not valid, skipping.", ctn->id);
+            VRB(session, "Cert verify CTN: entry with id %u not valid, skipping.", ctn->id);
             continue;
         }
 
@@ -324,7 +320,7 @@
         } else if (!strncmp(ctn->fingerprint, "01", 2)) {
             if (!digest_md5) {
                 if (X509_digest(cert, EVP_md5(), buf, &buf_len) != 1) {
-                    ERR(NULL, "Calculating MD5 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
+                    ERR(session, "Calculating MD5 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
                     ret = -1;
                     goto cleanup;
                 }
@@ -333,7 +329,7 @@
 
             if (!strcasecmp(ctn->fingerprint + 3, digest_md5)) {
                 /* we got ourselves a potential winner! */
-                VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found.");
+                VRB(session, "Cert verify CTN: entry with a matching fingerprint found.");
                 map_type = ctn->map_type;
             }
             free(digest_md5);
@@ -343,7 +339,7 @@
         } else if (!strncmp(ctn->fingerprint, "02", 2)) {
             if (!digest_sha1) {
                 if (X509_digest(cert, EVP_sha1(), buf, &buf_len) != 1) {
-                    ERR(NULL, "Calculating SHA-1 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
+                    ERR(session, "Calculating SHA-1 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
                     ret = -1;
                     goto cleanup;
                 }
@@ -352,7 +348,7 @@
 
             if (!strcasecmp(ctn->fingerprint + 3, digest_sha1)) {
                 /* we got ourselves a potential winner! */
-                VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found.");
+                VRB(session, "Cert verify CTN: entry with a matching fingerprint found.");
                 map_type = ctn->map_type;
             }
             free(digest_sha1);
@@ -362,7 +358,7 @@
         } else if (!strncmp(ctn->fingerprint, "03", 2)) {
             if (!digest_sha224) {
                 if (X509_digest(cert, EVP_sha224(), buf, &buf_len) != 1) {
-                    ERR(NULL, "Calculating SHA-224 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
+                    ERR(session, "Calculating SHA-224 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
                     ret = -1;
                     goto cleanup;
                 }
@@ -371,7 +367,7 @@
 
             if (!strcasecmp(ctn->fingerprint + 3, digest_sha224)) {
                 /* we got ourselves a potential winner! */
-                VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found.");
+                VRB(session, "Cert verify CTN: entry with a matching fingerprint found.");
                 map_type = ctn->map_type;
             }
             free(digest_sha224);
@@ -381,7 +377,7 @@
         } else if (!strncmp(ctn->fingerprint, "04", 2)) {
             if (!digest_sha256) {
                 if (X509_digest(cert, EVP_sha256(), buf, &buf_len) != 1) {
-                    ERR(NULL, "Calculating SHA-256 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
+                    ERR(session, "Calculating SHA-256 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
                     ret = -1;
                     goto cleanup;
                 }
@@ -390,7 +386,7 @@
 
             if (!strcasecmp(ctn->fingerprint + 3, digest_sha256)) {
                 /* we got ourselves a potential winner! */
-                VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found.");
+                VRB(session, "Cert verify CTN: entry with a matching fingerprint found.");
                 map_type = ctn->map_type;
             }
             free(digest_sha256);
@@ -400,7 +396,7 @@
         } else if (!strncmp(ctn->fingerprint, "05", 2)) {
             if (!digest_sha384) {
                 if (X509_digest(cert, EVP_sha384(), buf, &buf_len) != 1) {
-                    ERR(NULL, "Calculating SHA-384 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
+                    ERR(session, "Calculating SHA-384 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
                     ret = -1;
                     goto cleanup;
                 }
@@ -409,7 +405,7 @@
 
             if (!strcasecmp(ctn->fingerprint + 3, digest_sha384)) {
                 /* we got ourselves a potential winner! */
-                VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found.");
+                VRB(session, "Cert verify CTN: entry with a matching fingerprint found.");
                 map_type = ctn->map_type;
             }
             free(digest_sha384);
@@ -419,7 +415,7 @@
         } else if (!strncmp(ctn->fingerprint, "06", 2)) {
             if (!digest_sha512) {
                 if (X509_digest(cert, EVP_sha512(), buf, &buf_len) != 1) {
-                    ERR(NULL, "Calculating SHA-512 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
+                    ERR(session, "Calculating SHA-512 digest failed (%s).", ERR_reason_error_string(ERR_get_error()));
                     ret = -1;
                     goto cleanup;
                 }
@@ -428,7 +424,7 @@
 
             if (!strcasecmp(ctn->fingerprint + 3, digest_sha512)) {
                 /* we got ourselves a potential winner! */
-                VRB(NULL, "Cert verify CTN: entry with a matching fingerprint found.");
+                VRB(session, "Cert verify CTN: entry with a matching fingerprint found.");
                 map_type = ctn->map_type;
             }
             free(digest_sha512);
@@ -436,7 +432,7 @@
 
             /* unknown */
         } else {
-            WRN(NULL, "Unknown fingerprint algorithm used (%s), skipping.", ctn->fingerprint);
+            WRN(session, "Unknown fingerprint algorithm used (%s), skipping.", ctn->fingerprint);
             continue;
         }
 
@@ -668,16 +664,24 @@
     X509_NAME *issuer;
     X509 *cert;
     char *cp;
+    X509_STORE *store;
 
     STACK_OF(X509) * cert_stack;
     struct nc_session *session;
     struct nc_server_tls_opts *opts;
+    struct nc_endpt *referenced_endpt;
     int rc, depth;
 
-    /* get the thread session */
-    session = pthread_getspecific(verify_key);
+    store = X509_STORE_CTX_get0_store(x509_ctx);
+    if (!store) {
+        ERR(NULL, "Error getting store from context (%s).", ERR_reason_error_string(ERR_get_error()));
+        return 0;
+    }
+
+    /* get session from the store */
+    session = X509_STORE_get_ex_data(store, 0);
     if (!session) {
-        ERRINT;
+        ERR(session, "Error getting session from store (%s).", ERR_reason_error_string(ERR_get_error()));
         return 0;
     }
 
@@ -702,7 +706,7 @@
         }
 
         /* no match, continue */
-        if (opts->endpt_client_ref) {
+        if (opts->referenced_endpt_name) {
             /* check referenced endpoint's end-entity certs */
             rc = nc_server_tls_do_preverify(session, x509_ctx, 2);
             if (rc == -1) {
@@ -751,12 +755,19 @@
         /* fatal error */
         depth = 0;
         goto fail;
-    } else if ((rc == 1) && !opts->endpt_client_ref) {
+    } else if ((rc == 1) && !opts->referenced_endpt_name) {
         /* no match found and no referenced endpoint */
         goto fail;
-    } else if ((rc == 1) && opts->endpt_client_ref) {
+    } else if ((rc == 1) && opts->referenced_endpt_name) {
         /* no match found, but has a referenced endpoint so try it */
-        rc = nc_tls_cert_to_name(session, opts->endpt_client_ref->opts.tls->ctn, cert);
+        if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) {
+            /* fatal error */
+            ERRINT;
+            depth = 0;
+            goto fail;
+        }
+
+        rc = nc_tls_cert_to_name(session, referenced_endpt->opts.tls->ctn, cert);
         if (rc) {
             if (rc == -1) {
                 /* fatal error */
@@ -890,12 +901,6 @@
     server_opts.user_verify_clb = verify_clb;
 }
 
-static void
-nc_tls_make_verify_key(void)
-{
-    pthread_key_create(&verify_key, NULL);
-}
-
 static int
 nc_server_tls_ks_ref_get_cert_key(const char *referenced_key_name, const char *referenced_cert_name,
         char **privkey_data, NC_PRIVKEY_FORMAT *privkey_type, char **cert_data)
@@ -918,7 +923,7 @@
     }
 
     for (j = 0; j < ks->asym_keys[i].cert_count; j++) {
-        if (!strcmp(referenced_cert_name, ks->asym_keys[i].certs[i].name)) {
+        if (!strcmp(referenced_cert_name, ks->asym_keys[i].certs[j].name)) {
             break;
         }
     }
@@ -1403,6 +1408,7 @@
     SSL_CTX *tls_ctx;
     int ret;
     struct timespec ts_timeout;
+    struct nc_endpt *referenced_endpt;
 
     /* SSL_CTX */
     tls_ctx = SSL_CTX_new(TLS_server_method());
@@ -1424,6 +1430,13 @@
         goto error;
     }
 
+    /* store the session, retrieve it when needed */
+    ret = X509_STORE_set_ex_data(cert_store, 0, session);
+    if (!ret) {
+        ERR(session, "Setting certificate store data failed (%s).", ERR_reason_error_string(ERR_get_error()));
+        goto error;
+    }
+
     /* set end-entity certs as cert store data, retrieve them if verification fails later */
     ret = X509_STORE_set_ex_data(cert_store, 1, &opts->ee_certs);
     if (!ret) {
@@ -1432,8 +1445,13 @@
     }
 
     /* do the same for referenced endpoint's end entity certs */
-    if (opts->endpt_client_ref) {
-        ret = X509_STORE_set_ex_data(cert_store, 2, &opts->endpt_client_ref->opts.tls->ee_certs);
+    if (opts->referenced_endpt_name) {
+        if (nc_server_get_referenced_endpt(opts->referenced_endpt_name, &referenced_endpt)) {
+            ERRINT;
+            goto error;
+        }
+
+        ret = X509_STORE_set_ex_data(cert_store, 2, &referenced_endpt->opts.tls->ee_certs);
         if (!ret) {
             ERR(session, "Setting certificate store data failed (%s).", ERR_reason_error_string(ERR_get_error()));
             goto error;
@@ -1449,8 +1467,8 @@
     }
 
     /* set referenced endpoint's CA certs if set */
-    if (opts->endpt_client_ref) {
-        if (nc_tls_store_set_trusted_certs(cert_store, &opts->endpt_client_ref->opts.tls->ca_certs)) {
+    if (opts->referenced_endpt_name) {
+        if (nc_tls_store_set_trusted_certs(cert_store, &referenced_endpt->opts.tls->ca_certs)) {
             goto error;
         }
     }
@@ -1502,10 +1520,6 @@
     sock = -1;
     SSL_set_mode(session->ti.tls, SSL_MODE_AUTO_RETRY);
 
-    /* store session on per-thread basis */
-    pthread_once(&verify_once, nc_tls_make_verify_key);
-    pthread_setspecific(verify_key, session);
-
     if (timeout > -1) {
         nc_timeouttime_get(&ts_timeout, timeout);
     }