diff --git a/dap-sdk/core/src/dap_fnmatch.c b/dap-sdk/core/src/dap_fnmatch.c
index 21096cf46828208d76ad0e0e54158b6f36eabf37..f89fa536eff2959625980c269d6dd60e5f42d784 100644
--- a/dap-sdk/core/src/dap_fnmatch.c
+++ b/dap-sdk/core/src/dap_fnmatch.c
@@ -179,7 +179,7 @@ __wcschrnul (const wchar_t *s, wint_t c)
 # endif
 # define STRLEN(S) strlen(S)
 # define STRCAT(D, S) strcat (D, S)
-# define MEMPCPY(D, S, N) __mempcpy (D, S, N)
+# define MEMPCPY(D, S, N) mempcpy (D, S, N)
 # define MEMCHR(S, C, N) memchr (S, C, N)
 # define STRCOLL(S1, S2) strcoll (S1, S2)
 # define WIDE_CHAR_VERSION 0
diff --git a/dap-sdk/crypto/include/dap_cert.h b/dap-sdk/crypto/include/dap_cert.h
index 9ba4e00ec17c8232b469a25c2c2e5e89f2b4e0d1..0dee3bf8858f543c7878ac73e8eaf341be497b25 100755
--- a/dap-sdk/crypto/include/dap_cert.h
+++ b/dap-sdk/crypto/include/dap_cert.h
@@ -82,6 +82,7 @@ void dap_cert_dump(dap_cert_t * a_cert);
 dap_pkey_t * dap_cert_to_pkey(dap_cert_t * a_cert);
 
 dap_cert_t * dap_cert_find_by_name(const char * a_cert_name);
+dap_list_t *dap_cert_get_all_mem();
 
 dap_sign_t * dap_cert_sign(dap_cert_t * a_cert, const void * a_data, size_t a_data_size, size_t a_output_size_wished );
 
diff --git a/dap-sdk/crypto/src/dap_cert.c b/dap-sdk/crypto/src/dap_cert.c
index 5f5da67741246f0be603313d4a33cf54a2bc8c82..2916d19b6707d73da4597d8231f928bc3d99400e 100755
--- a/dap-sdk/crypto/src/dap_cert.c
+++ b/dap-sdk/crypto/src/dap_cert.c
@@ -300,6 +300,15 @@ dap_cert_t * dap_cert_find_by_name(const char * a_cert_name)
         }
 }
 
+dap_list_t *dap_cert_get_all_mem()
+{
+    dap_list_t *l_ret = NULL;
+    dap_cert_item_t *l_cert_item = NULL, *l_cert_tmp;
+    HASH_ITER(hh, s_certs, l_cert_item, l_cert_tmp) {
+        l_ret = dap_list_append(l_ret, l_cert_item->cert);
+    }
+    return l_ret;
+}
 
 /**
  * @brief dap_cert_new
diff --git a/dap-sdk/net/client/dap_client.c b/dap-sdk/net/client/dap_client.c
index d33a1a96b022361521045842c2cecf0014d7db30..b799fe8080941db2ce65225fc546f9a3312f6650 100644
--- a/dap-sdk/net/client/dap_client.c
+++ b/dap-sdk/net/client/dap_client.c
@@ -138,7 +138,6 @@ void dap_client_set_active_channels (dap_client_t * a_client, const char * a_act
     DAP_CLIENT_PVT(a_client)->active_channels = dap_strdup( a_active_channels);
 }
 
-
 /**
  * @brief dap_client_get_uplink_port
  * @param a_client
@@ -149,6 +148,11 @@ uint16_t dap_client_get_uplink_port(dap_client_t * a_client)
     return DAP_CLIENT_PVT(a_client)->uplink_port;
 }
 
+void dap_client_set_auth_cert(dap_client_t * a_client, dap_cert_t *a_cert)
+{
+    DAP_CLIENT_PVT(a_client)->auth_cert = a_cert;
+}
+
 
 /**
  * @brief dap_client_reset
diff --git a/dap-sdk/net/client/dap_client_pvt.c b/dap-sdk/net/client/dap_client_pvt.c
index ed75611c32415c6ae8195bb6ef06a52cfc00d79e..1bb6f9708ef684d963df77157f6adcdb09724e0d 100644
--- a/dap-sdk/net/client/dap_client_pvt.c
+++ b/dap-sdk/net/client/dap_client_pvt.c
@@ -56,6 +56,7 @@
 #include "dap_enc.h"
 #include "dap_common.h"
 #include "dap_strfuncs.h"
+#include "dap_cert.h"
 
 //#include "dap_http_client_simple.h"
 #include "dap_client_http.h"
@@ -396,25 +397,37 @@ static void s_stage_status_after(dap_client_pvt_t * a_client_pvt)
     case STAGE_STATUS_IN_PROGRESS: {
         switch (a_client_pvt->stage) {
         case STAGE_ENC_INIT: {
-            log_it(L_INFO, "Go to stage ENC: prepare the request");
-
+            log_it(L_INFO, "Go to stage ENC: prepare the request");         
             a_client_pvt->session_key_open = dap_enc_key_new_generate(DAP_ENC_KEY_TYPE_MSRLN, NULL, 0, NULL, 0, 0);
-
-            size_t l_key_str_size_max = DAP_ENC_BASE64_ENCODE_SIZE(a_client_pvt->session_key_open->pub_key_data_size);
-            char *l_key_str = DAP_NEW_Z_SIZE(char, l_key_str_size_max + 1);
+            if (!a_client_pvt->session_key_open) {
+                log_it(L_ERROR, "Insufficient memory! May be a huge memory leak present");
+                a_client_pvt->stage_status = STAGE_STATUS_ERROR;
+                break;
+            }
+            size_t l_key_size = a_client_pvt->session_key_open->pub_key_data_size;
+            dap_cert_t *l_cert = a_client_pvt->auth_cert;
+            dap_sign_t *l_sign = NULL;
+            size_t l_sign_size = 0;
+            if (l_cert) {
+                l_sign = dap_sign_create(l_cert->enc_key, a_client_pvt->session_key_open->pub_key_data, l_key_size, 0);
+                l_sign_size = dap_sign_get_size(l_sign);
+            }
+            uint8_t l_data[l_key_size + l_sign_size];
+            memcpy(l_data, a_client_pvt->session_key_open->pub_key_data, l_key_size);
+            if (l_sign) {
+                memcpy(l_data + l_key_size, l_sign, l_sign_size);
+            }
+            size_t l_data_str_size_max = DAP_ENC_BASE64_ENCODE_SIZE(l_key_size + l_sign_size);
+            char l_data_str[l_data_str_size_max + 1];
             // DAP_ENC_DATA_TYPE_B64_URLSAFE not need because send it by POST request
-            size_t l_key_str_enc_size = dap_enc_base64_encode(a_client_pvt->session_key_open->pub_key_data,
-                    a_client_pvt->session_key_open->pub_key_data_size,
-                    l_key_str, DAP_ENC_DATA_TYPE_B64);
-
-            log_it(L_DEBUG, "ENC request size %u", l_key_str_enc_size);
+            size_t l_data_str_enc_size = dap_enc_base64_encode(l_data, l_key_size + l_sign_size, l_data_str, DAP_ENC_DATA_TYPE_B64);
+            log_it(L_DEBUG, "ENC request size %u", l_data_str_enc_size);
             int l_res = dap_client_pvt_request(a_client_pvt, DAP_UPLINK_PATH_ENC_INIT "/gd4y5yh78w42aaagh",
-                    l_key_str, l_key_str_enc_size, m_enc_init_response, m_enc_init_error);
+                    l_data_str, l_data_str_enc_size, m_enc_init_response, m_enc_init_error);
             // bad request
             if(l_res<0){
             	a_client_pvt->stage_status = STAGE_STATUS_ERROR;
             }
-            DAP_DELETE(l_key_str);
         }
             break;
         case STAGE_STREAM_CTL: {
diff --git a/dap-sdk/net/client/include/dap_client.h b/dap-sdk/net/client/include/dap_client.h
index 7a81af9734559fdf27c8efb458d548553c22a212..dc49c63796fc313f5084043988a51f75231ba117 100644
--- a/dap-sdk/net/client/include/dap_client.h
+++ b/dap-sdk/net/client/include/dap_client.h
@@ -28,6 +28,7 @@
 #include "dap_events.h"
 #include "dap_stream.h"
 #include "dap_stream_ch.h"
+#include "dap_cert.h"
 
 /**
  * @brief The dap_client_stage enum. Top level of client's state machine
@@ -133,6 +134,7 @@ dap_stream_t * dap_client_get_stream(dap_client_t * a_client);
 dap_stream_ch_t * dap_client_get_stream_ch(dap_client_t * a_client, uint8_t a_ch_id);
 const char * dap_client_get_stream_id(dap_client_t * a_client);
 void dap_client_set_active_channels (dap_client_t * a_client, const char * a_active_channels);
+void dap_client_set_auth_cert(dap_client_t * a_client, dap_cert_t *a_cert);
 
 dap_client_stage_t dap_client_get_stage(dap_client_t * a_client);
 dap_client_stage_status_t dap_client_get_stage_status(dap_client_t * a_client);
diff --git a/dap-sdk/net/client/include/dap_client_pvt.h b/dap-sdk/net/client/include/dap_client_pvt.h
index 9c93e03ad62ae463db9d407657e397b1d629810a..04aa7439242657964d7bd4bf8f5627aa36af1241 100644
--- a/dap-sdk/net/client/include/dap_client_pvt.h
+++ b/dap-sdk/net/client/include/dap_client_pvt.h
@@ -28,6 +28,8 @@
 #include "dap_client.h"
 #include "dap_stream.h"
 #include "dap_events_socket.h"
+#include "dap_cert.h"
+
 typedef struct dap_enc_key dap_enc_key_t;
 typedef struct dap_http_client dap_http_client_t;
 
@@ -47,7 +49,7 @@ typedef struct dap_client_internal
     dap_enc_key_t * session_key; // Symmetric private key for session encryption
     dap_enc_key_t * stream_key; // Stream private key for stream encryption
     char stream_id[25];
-
+    dap_cert_t *auth_cert;
 
     char  * session_key_id;
     //void  *curl;// curl connection descriptor
diff --git a/dap-sdk/net/server/enc_server/dap_enc_http.c b/dap-sdk/net/server/enc_server/dap_enc_http.c
index e5513c121635f35a4749ae377c8983717ba23bc5..c04ddf05f18018e72f717db26160bf6e7580b79a 100644
--- a/dap-sdk/net/server/enc_server/dap_enc_http.c
+++ b/dap-sdk/net/server/enc_server/dap_enc_http.c
@@ -37,6 +37,7 @@
 
 
 #include "dap_common.h"
+#include "dap_sign.h"
 
 #include "include/dap_http.h"
 #include "dap_http_client.h"
@@ -55,6 +56,8 @@
 
 #define LOG_TAG "dap_enc_http"
 
+static dap_enc_acl_callback_t s_acl_callback = NULL;
+
 int enc_http_init()
 {
     return 0;
@@ -79,6 +82,12 @@ static void _enc_http_write_reply(struct dap_http_simple *cl_st,
 }
 
 void dap_enc_http_json_response_format_enable(bool);
+
+void dap_enc_http_set_acl_callback(dap_enc_acl_callback_t a_callback)
+{
+    s_acl_callback = a_callback;
+}
+
 /**
  * @brief enc_http_proc Enc http interface
  * @param cl_st HTTP Simple client instance
@@ -93,16 +102,29 @@ void enc_http_proc(struct dap_http_simple *cl_st, void * arg)
 
         uint8_t alice_msg[cl_st->request_size];
         size_t decode_len = dap_enc_base64_decode(cl_st->request, cl_st->request_size, alice_msg, DAP_ENC_DATA_TYPE_B64);
-        if(decode_len != MSRLN_PKA_BYTES) {
+        dap_chain_hash_fast_t l_sign_hash = {};
+        if (decode_len < MSRLN_PKA_BYTES) {
             log_it(L_WARNING, "Wrong http_enc request. Key not equal MSRLN_PKA_BYTES");
             *return_code = Http_Status_BadRequest;
             return;
+        } else if (decode_len > MSRLN_PKA_BYTES) {
+            dap_sign_t *l_sign = (dap_sign_t *)&alice_msg[MSRLN_PKA_BYTES];
+            if (dap_sign_verify(l_sign, alice_msg, MSRLN_PKA_BYTES) != 1) {
+                *return_code = Http_Status_Unauthorized;
+                return;
+            }
+            dap_sign_get_pkey_hash(l_sign, &l_sign_hash);
         }
 
         dap_enc_key_t* msrln_key = dap_enc_key_new(DAP_ENC_KEY_TYPE_MSRLN);
         msrln_key->gen_bob_shared_key(msrln_key, alice_msg, MSRLN_PKA_BYTES, (void**)&msrln_key->pub_key_data);
 
         dap_enc_ks_key_t * key_ks = dap_enc_ks_new();
+        if (s_acl_callback) {
+            key_ks->acl_list = s_acl_callback(&l_sign_hash);
+        } else {
+            log_it(L_WARNING, "Callback for ACL is not set, pass anauthorized");
+        }
 
         char encrypt_msg[DAP_ENC_BASE64_ENCODE_SIZE(msrln_key->pub_key_data_size) + 1];
         size_t encrypt_msg_size = dap_enc_base64_encode(msrln_key->pub_key_data, msrln_key->pub_key_data_size, encrypt_msg, DAP_ENC_DATA_TYPE_B64);
@@ -124,6 +146,7 @@ void enc_http_proc(struct dap_http_simple *cl_st, void * arg)
         dap_enc_key_delete(msrln_key);
 
         *return_code = Http_Status_OK;
+
     } else{
         log_it(L_ERROR,"Wrong path '%s' in the request to enc_http module",cl_st->http->url_path);
         *return_code = Http_Status_NotFound;
diff --git a/dap-sdk/net/server/enc_server/include/dap_enc_http.h b/dap-sdk/net/server/enc_server/include/dap_enc_http.h
index b92032188d2fa2f0c729f35a290182e1f442a3d1..4660b5250969586abea87ba461115e6169929bbc 100644
--- a/dap-sdk/net/server/enc_server/include/dap_enc_http.h
+++ b/dap-sdk/net/server/enc_server/include/dap_enc_http.h
@@ -22,6 +22,7 @@
 #define _ENC_HTTP_H_
 #include <stddef.h>
 #include <stdbool.h>
+#include "dap_hash.h"
 
 struct dap_http;
 struct dap_http_client;
@@ -63,6 +64,7 @@ typedef struct enc_http_delegate{
 } enc_http_delegate_t;
 
 typedef void (*dap_enc_http_callback_t) (enc_http_delegate_t *,void *); // Callback for specific client operations
+typedef uint8_t *(* dap_enc_acl_callback_t) (dap_chain_hash_fast_t *);   // Callback for access list for private chain networks
 
 int enc_http_init(void);
 void enc_http_deinit(void);
@@ -70,6 +72,7 @@ void enc_http_deinit(void);
 size_t enc_http_reply(enc_http_delegate_t * dg, void * data, size_t data_size);
 size_t enc_http_reply_f(enc_http_delegate_t * dg, const char * data, ...);
 
+void dap_enc_http_set_acl_callback(dap_enc_acl_callback_t a_callback);
 
 enc_http_delegate_t *enc_http_request_decode(struct dap_http_simple *a_http_simple);
 
diff --git a/dap-sdk/net/server/enc_server/include/dap_enc_ks.h b/dap-sdk/net/server/enc_server/include/dap_enc_ks.h
index 828ac4e583a59a4fec184383cb655d5d3a6af19d..07c51b19ecf378acd9e7e776228aa7b89dbc4fe3 100644
--- a/dap-sdk/net/server/enc_server/include/dap_enc_ks.h
+++ b/dap-sdk/net/server/enc_server/include/dap_enc_ks.h
@@ -25,6 +25,7 @@
 #include "uthash.h"
 #include "dap_enc_key.h"
 #include "stdbool.h"
+#include "dap_hash.h"
 
 #define DAP_ENC_KS_KEY_ID_SIZE 33
 struct dap_http_client;
@@ -34,6 +35,7 @@ typedef struct dap_enc_ks_key{
     dap_enc_key_t *key;
     time_t time_created;
     pthread_mutex_t mutex;
+    uint8_t *acl_list;
     UT_hash_handle hh; // makes this structure hashable with UTHASH library
 } dap_enc_ks_key_t;
 
diff --git a/dap-sdk/net/stream/session/include/dap_stream_session.h b/dap-sdk/net/stream/session/include/dap_stream_session.h
index 9fdfb91c061fbd4c62356f17eb39cc83863ed7e7..2f8d9e624d23a5eebb694515b06796f31aac87f7 100644
--- a/dap-sdk/net/stream/session/include/dap_stream_session.h
+++ b/dap-sdk/net/stream/session/include/dap_stream_session.h
@@ -30,6 +30,7 @@
 
 #include "uthash.h"
 #include "dap_enc_key.h"
+#include "dap_hash.h"
 
 typedef enum stream_session_type {STREAM_SESSION_TYPE_MEDIA=0,STREAM_SESSION_TYPE_VPN} stream_session_type_t;
 typedef enum stream_session_connection_type {STEAM_SESSION_HTTP = 0, STREAM_SESSION_UDP, STREAM_SESSION_END_TYPE} stream_session_connection_type_t;
@@ -56,6 +57,7 @@ struct dap_stream_session {
 
     stream_session_connection_type_t conn_type;
     stream_session_type_t type;
+    uint8_t *acl;
     UT_hash_handle hh;
     struct in_addr tun_client_addr;
 
diff --git a/dap-sdk/net/stream/stream/dap_stream_ctl.c b/dap-sdk/net/stream/stream/dap_stream_ctl.c
index 80a9427af0390ce774fbe849e93f6706f4399b56..21bd39eb99423262c6199bc573df54b2b48036e8 100644
--- a/dap-sdk/net/stream/stream/dap_stream_ctl.c
+++ b/dap-sdk/net/stream/stream/dap_stream_ctl.c
@@ -50,6 +50,7 @@
 #include "dap_stream_session.h"
 #include "dap_stream_ctl.h"
 #include "http_status_code.h"
+#include "dap_enc_ks.h"
 
 #define LOG_TAG "dap_stream_ctl"
 
@@ -145,6 +146,16 @@ void s_proc(struct dap_http_simple *a_http_simple, void * a_arg)
             dap_random_string_fill(key_str, KEX_KEY_STR_SIZE);
             ss->key = dap_enc_key_new_generate( s_socket_forward_key.type, key_str, KEX_KEY_STR_SIZE,
                                                NULL, 0, s_socket_forward_key.size);
+            dap_http_header_t *l_hdr_key_id = dap_http_header_find(a_http_simple->http->in_headers, "KeyID");
+            if (l_hdr_key_id) {
+                dap_enc_ks_key_t *l_ks_key = dap_enc_ks_find(l_hdr_key_id->value);
+                if (!l_ks_key) {
+                    log_it(L_WARNING, "Key with ID %s not found", l_hdr_key_id->value);
+                    *return_code = Http_Status_BadRequest;
+                    return;
+                }
+                ss->acl = l_ks_key->acl_list;
+            }
             enc_http_reply_f(l_dg,"%u %s",ss->id,key_str);
             *return_code = Http_Status_OK;
 
@@ -154,6 +165,7 @@ void s_proc(struct dap_http_simple *a_http_simple, void * a_arg)
         }else{
             log_it(L_ERROR,"Wrong request: \"%s\"",l_dg->in_query);
             *return_code = Http_Status_BadRequest;
+            return;
         }
 
         unsigned int conn_t = 0;
diff --git a/modules/channel/chain-net/dap_stream_ch_chain_net.c b/modules/channel/chain-net/dap_stream_ch_chain_net.c
index 22d437782c12cd4189d5b922ef8503aa5c509f0e..74dcd903c674c4f4e93b15f8ca5c9da53562adbc 100644
--- a/modules/channel/chain-net/dap_stream_ch_chain_net.c
+++ b/modules/channel/chain-net/dap_stream_ch_chain_net.c
@@ -43,6 +43,7 @@
 
 #include "dap_common.h"
 #include "dap_strfuncs.h"
+#include "dap_cert.h"
 #include "uthash.h"
 #include "dap_http_client.h"
 #include "dap_chain_global_db.h"
@@ -192,8 +193,27 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
         pthread_mutex_lock(&l_ch_chain_net->mutex);
         dap_stream_ch_pkt_t *l_ch_pkt = (dap_stream_ch_pkt_t *) a_arg;
         dap_stream_ch_chain_net_pkt_t *l_ch_chain_net_pkt = (dap_stream_ch_chain_net_pkt_t *) l_ch_pkt->data;
-        size_t l_ch_chain_net_pkt_data_size = (size_t) l_ch_pkt->hdr.size - sizeof (l_ch_chain_net_pkt->hdr);
-        if(l_ch_chain_net_pkt) {
+        uint8_t l_acl_idx = dap_chain_net_acl_idx_by_id(l_ch_chain_net_pkt->hdr.net_id);
+        bool l_error = false;
+        char l_err_str[64];
+        if (l_acl_idx == (uint8_t)-1) {
+            log_it(L_ERROR, "Invalid net id in packet");
+            strcpy(l_err_str, "ERROR_NET_INVALID_ID");
+            l_error = true;
+        }
+        if (!l_error && a_ch->stream->session->acl && !a_ch->stream->session->acl[l_acl_idx]) {
+            log_it(L_WARNING, "Unauthorized request attempt to network %s",
+                   dap_chain_net_by_id(l_ch_chain_net_pkt->hdr.net_id)->pub.name);
+            strcpy(l_err_str, "ERROR_NET_NOT_AUTHORIZED");
+            l_error = true;
+        }
+        if (l_error) {
+            dap_stream_ch_chain_net_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ERROR ,
+                                              l_ch_chain_net_pkt->hdr.net_id, l_err_str, strlen(l_err_str) + 1);
+            dap_stream_ch_set_ready_to_write(a_ch, true);
+        }
+        //size_t l_ch_chain_net_pkt_data_size = (size_t) l_ch_pkt->hdr.size - sizeof (l_ch_chain_net_pkt->hdr);
+        if (!l_error && l_ch_chain_net_pkt) {
             size_t l_ch_chain_net_pkt_data_size = l_ch_pkt->hdr.size - sizeof(dap_stream_ch_chain_net_pkt_hdr_t);
             switch (l_ch_pkt->hdr.type) {
                 case DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_DBG: {
@@ -239,7 +259,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                             dap_stream_ch_chain_net_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ERROR ,
                                                               l_ch_chain_net_pkt->hdr.net_id, l_err_str,sizeof (l_err_str));
                             dap_stream_ch_set_ready_to_write(a_ch, true);
-                            log_it(L_WARNING,"Invalid net id in packet");
+                            log_it(L_ERROR, "Invalid net id in packet");
                         } else {
                             if (dap_db_set_cur_node_addr_exp( l_addr->uint64, l_net->pub.name ))
                                 log_it(L_NOTICE,"Set up cur node address 0x%016llX",l_addr->uint64);
@@ -284,7 +304,6 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                     }
                 }
                 break;
-
             }
             if(l_ch_chain_net->notify_callback)
                 l_ch_chain_net->notify_callback(l_ch_chain_net,l_ch_pkt->hdr.type, l_ch_chain_net_pkt,
diff --git a/modules/channel/chain/dap_stream_ch_chain.c b/modules/channel/chain/dap_stream_ch_chain.c
index 6db28cf82c6a3d5cae62933b56dd47fac8517a9d..7d18a4d996e72920f61074bcba5f4eb585816ffb 100644
--- a/modules/channel/chain/dap_stream_ch_chain.c
+++ b/modules/channel/chain/dap_stream_ch_chain.c
@@ -130,8 +130,27 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
     if(l_ch_chain) {
         dap_stream_ch_pkt_t * l_ch_pkt = (dap_stream_ch_pkt_t *) a_arg;
         dap_stream_ch_chain_pkt_t * l_chain_pkt = (dap_stream_ch_chain_pkt_t *) l_ch_pkt->data;
+        uint8_t l_acl_idx = dap_chain_net_acl_idx_by_id(l_chain_pkt->hdr.net_id);
+        bool l_error = false;
+        char l_err_str[64];
+        if (l_acl_idx == (uint8_t)-1) {
+            log_it(L_ERROR, "Invalid net id in packet");
+            strcpy(l_err_str, "ERROR_NET_INVALID_ID");
+            l_error = true;
+        }
+        if (!l_error && a_ch->stream->session->acl && !a_ch->stream->session->acl[l_acl_idx]) {
+            log_it(L_WARNING, "Unauthorized request attempt to network %s",
+                   dap_chain_net_by_id(l_chain_pkt->hdr.net_id)->pub.name);
+            strcpy(l_err_str, "ERROR_NET_NOT_AUTHORIZED");
+            l_error = true;
+        }
+        if (l_error) {
+            dap_stream_ch_chain_pkt_write_error(a_ch, l_chain_pkt->hdr.net_id,
+                    l_chain_pkt->hdr.chain_id, l_chain_pkt->hdr.cell_id, l_err_str);
+            dap_stream_ch_set_ready_to_write(a_ch, true);
+        }
         size_t l_chain_pkt_data_size = l_ch_pkt->hdr.size - sizeof(l_chain_pkt->hdr);
-        if(l_chain_pkt) {
+        if (!l_error && l_chain_pkt) {
             switch (l_ch_pkt->hdr.type) {
             case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_ALL: {
                 log_it(L_INFO, "In:  SYNCED_ALL pkt");
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 7243d534264a8cf343ede61b62874a71ca124758..5a9025d903b6abd49d6bdfa932643094081b727e 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -60,6 +60,8 @@
 #include "dap_config.h"
 #include "dap_hash.h"
 #include "dap_cert.h"
+#include "dap_cert_file.h"
+#include "dap_enc_http.h"
 #include "dap_chain_common.h"
 #include "dap_chain_net.h"
 #include "dap_chain_net_srv.h"
@@ -141,6 +143,7 @@ typedef struct dap_chain_net_pvt{
 
     dap_chain_net_state_t state;
     dap_chain_net_state_t state_target;
+    uint16_t acl_idx;
 } dap_chain_net_pvt_t;
 
 typedef struct dap_chain_net_item{
@@ -174,7 +177,7 @@ static int s_net_states_proc(dap_chain_net_t * l_net);
 static void * s_net_proc_thread ( void * a_net);
 static void s_net_proc_thread_start( dap_chain_net_t * a_net );
 static void s_net_proc_kill( dap_chain_net_t * a_net );
-int s_net_load(const char * a_net_name);
+int s_net_load(const char * a_net_name, uint16_t a_acl_idx);
 
 static void s_gbd_history_callback_notify (void * a_arg,const char a_op_code, const char * a_prefix, const char * a_group,
                                                      const char * a_key, const void * a_value,
@@ -185,6 +188,23 @@ static int s_cli_net(int argc, char ** argv, void *arg_func, char **str_reply);
 
 static bool s_seed_mode = false;
 
+static uint8_t *dap_chain_net_set_acl(dap_chain_hash_fast_t *a_pkey_hash);
+
+char *dap_chain_net_get_gdb_group_acl(dap_chain_net_t *a_net)
+{
+    if (a_net) {
+        const char l_path[] = "network/";
+        char l_cfg_path[strlen(a_net->pub.name) + strlen(l_path) + 1];
+        strcpy(l_cfg_path, l_path);
+        strcat(l_cfg_path, a_net->pub.name);
+        dap_config_t *l_cfg = dap_config_open(l_cfg_path);
+        const char *l_auth_gdb = dap_config_get_item_str(l_cfg, "auth", "acl_accept_ca_gdb");
+        if (l_auth_gdb) {
+            return dap_strdup_printf("%s.%s", a_net->pub.gdb_groups_prefix, l_auth_gdb);
+        }
+    }
+    return NULL;
+}
 
 /**
  * @brief s_net_set_go_sync
@@ -1014,9 +1034,15 @@ int dap_chain_net_init()
         "net -net <chain net name> stats tx [-from <From time>] [-to <To time>] [-prev_sec <Seconds>] \n"
             "\tTransactions statistics. Time format is <Year>-<Month>-<Day>_<Hours>:<Minutes>:<Seconds> or just <Seconds> \n"
         "net -net <chain net name> sync < all | gdb | chains >\n"
-            "\tSyncronyze gdb, chains or everything\n\n"
+            "\tSyncronyze gdb, chains or everything\n"
         "net -net <chain net name> link < list | add | del | info | establish >\n"
-            "\tList,add,del, dump or establish links\n\n"
+            "\tList, add, del, dump or establish links\n"
+        "net -net <chain net name> ca add {-cert <cert name> | -hash <cert hash>}\n"
+            "\tAdd certificate to list of authority cetificates in GDB group\n"
+        "net -net <chain net name> ca list\n"
+            "\tPrint list of authority cetificates from GDB group\n"
+        "net -net <chain net name> ca del -hash <cert hash>\n"
+            "\tDelete certificate from list of authority cetificates in GDB group by it's hash\n"
                                         );
     s_seed_mode = dap_config_get_item_bool_default(g_config,"general","seed_mode",false);
     dap_chain_global_db_add_history_group_prefix("global", GROUP_LOCAL_HISTORY);
@@ -1029,6 +1055,8 @@ int dap_chain_net_init()
     s_required_links_count = dap_config_get_item_int32_default(g_config, "general", "require_links", s_required_links_count);
 
     dap_chain_net_load_all();
+
+    dap_enc_http_set_acl_callback(dap_chain_net_set_acl);
     return 0;
 }
 
@@ -1038,6 +1066,7 @@ void dap_chain_net_load_all()
     DIR * l_net_dir = opendir( l_net_dir_str);
     if ( l_net_dir ){
         struct dirent * l_dir_entry;
+        uint16_t l_acl_idx = 0;
         while ( (l_dir_entry = readdir(l_net_dir) )!= NULL ){
             if (l_dir_entry->d_name[0]=='\0' || l_dir_entry->d_name[0]=='.')
                 continue;
@@ -1060,7 +1089,7 @@ void dap_chain_net_load_all()
             char* l_dot_pos = strchr(l_dir_entry->d_name,'.');
             if ( l_dot_pos )
                 *l_dot_pos = '\0';
-            s_net_load(l_dir_entry->d_name );
+            s_net_load(l_dir_entry->d_name, l_acl_idx++);
         }
         closedir(l_net_dir);
     }
@@ -1106,6 +1135,7 @@ void s_set_reply_text_node_status(char **a_str_reply, dap_chain_net_t * a_net){
  */
 static int s_cli_net( int argc, char **argv, void *arg_func, char **a_str_reply)
 {
+    UNUSED(arg_func);
     int arg_index = 1;
     dap_chain_net_t * l_net = NULL;
 
@@ -1141,11 +1171,13 @@ static int s_cli_net( int argc, char **argv, void *arg_func, char **a_str_reply)
         const char *l_go_str = NULL;
         const char *l_get_str = NULL;
         const char *l_stats_str = NULL;
+        const char *l_ca_str = NULL;
         dap_chain_node_cli_find_option_val(argv, arg_index, argc, "sync", &l_sync_str);
         dap_chain_node_cli_find_option_val(argv, arg_index, argc, "link", &l_links_str);
         dap_chain_node_cli_find_option_val(argv, arg_index, argc, "go", &l_go_str);
         dap_chain_node_cli_find_option_val(argv, arg_index, argc, "get", &l_get_str);
         dap_chain_node_cli_find_option_val(argv, arg_index, argc, "stats", &l_stats_str);
+        dap_chain_node_cli_find_option_val(argv, arg_index, argc, "ca", &l_ca_str);
 
         if ( l_stats_str ){
             if ( strcmp(l_stats_str,"tx") == 0 ) {
@@ -1278,6 +1310,91 @@ static int s_cli_net( int argc, char **argv, void *arg_func, char **a_str_reply)
                                                   "Subcommand \"sync\" requires one of parameter: all,gdb,chains\n");
                 ret = -2;
             }
+        } else if (l_ca_str) {
+            if (strcmp(l_ca_str, "add") == 0 ) {
+                const char *l_cert_string = NULL, *l_hash_string = NULL;
+                dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-cert", &l_cert_string);
+                dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-hash", &l_hash_string);
+                if (!l_cert_string && !l_hash_string) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "One of -cert or -hash parameters is mandatory");
+                    return -6;
+                }
+                if (l_cert_string) {
+                    dap_cert_t * l_cert = dap_cert_find_by_name(l_cert_string);
+                    if (l_cert == NULL) {
+                        dap_chain_node_cli_set_reply_text(a_str_reply, "Can't find \"%s\" certificate", l_cert_string);
+                        return -7;
+                    }
+                    if (l_cert->enc_key == NULL) {
+                        dap_chain_node_cli_set_reply_text(a_str_reply, "No key found in \"%s\" certificate", l_cert_string );
+                        return -8;
+                    }
+                    // Get publivc key hash
+                    size_t l_pub_key_size = 0;
+                    uint8_t *l_pub_key = dap_enc_key_serealize_pub_key(l_cert->enc_key, &l_pub_key_size);;
+                    if (l_pub_key == NULL) {
+                        dap_chain_node_cli_set_reply_text(a_str_reply, "Can't serialize public key of certificate \"%s\"", l_cert_string);
+                        return -9;
+                    }
+                    dap_chain_hash_fast_t l_pkey_hash;
+                    dap_hash_fast(l_pub_key, l_pub_key_size, &l_pkey_hash);
+                    l_hash_string = dap_chain_hash_fast_to_str_new(&l_pkey_hash);
+                }
+                const char c = '1';
+                char *l_gdb_group_str = dap_chain_net_get_gdb_group_acl(l_net);
+                if (!l_gdb_group_str) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "Database ACL group not defined for this network");
+                    return -11;
+                }
+                ret = dap_chain_global_db_gr_set(dap_strdup(l_hash_string), (void *)&c, 1, dap_chain_net_get_gdb_group_acl(l_net));
+                DAP_DELETE(l_gdb_group_str);
+                if (!ret) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "Can't save public key hash in database");
+                    return -10;
+                }
+                return 0;
+            } else if (strcmp(l_ca_str, "list") == 0 ) {
+                char *l_gdb_group_str = dap_chain_net_get_gdb_group_acl(l_net);
+                if (!l_gdb_group_str) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "Database ACL group not defined for this network");
+                    return -11;
+                }
+                size_t l_objs_count;
+                dap_global_db_obj_t *l_objs = dap_chain_global_db_gr_load(l_gdb_group_str, &l_objs_count);
+                DAP_DELETE(l_gdb_group_str);
+                dap_string_t *l_reply = dap_string_new("");
+                for (size_t i = 0; i < l_objs_count; i++) {
+                    dap_string_append(l_reply, l_objs[i].key);
+                    dap_string_append(l_reply, "\n");
+                }
+                dap_chain_global_db_objs_delete(l_objs, l_objs_count);
+                *a_str_reply = l_reply->len ? l_reply->str : dap_strdup("No entries found");
+                dap_string_free(l_reply, false);
+                return 0;
+            } else if (strcmp(l_ca_str, "del") == 0 ) {
+                const char *l_hash_string = NULL;
+                dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-hash", &l_hash_string);
+                if (!l_hash_string) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "Format should be 'net ca del -hash <hash string>");
+                    return -6;
+                }
+                char *l_gdb_group_str = dap_chain_net_get_gdb_group_acl(l_net);
+                if (!l_gdb_group_str) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "Database ACL group not defined for this network");
+                    return -11;
+                }
+                ret = dap_chain_global_db_gr_del((char *)l_hash_string, l_gdb_group_str);
+                DAP_DELETE(l_gdb_group_str);
+                if (!ret) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "Cant't find certificate public key hash in database");
+                    return -10;
+                }
+                return 0;
+            } else {
+                dap_chain_node_cli_set_reply_text(a_str_reply,
+                                                  "Subcommand \"ca\" requires one of parameter: add, list, del\n");
+                ret = -5;
+            }
         } else {
             dap_chain_node_cli_set_reply_text(a_str_reply,"Command requires one of subcomand: sync, links\n");
             ret = -1;
@@ -1309,7 +1426,7 @@ static int callback_compare_prioritity_list(const void * a_item1, const void * a
  * @param a_net_name
  * @return
  */
-int s_net_load(const char * a_net_name)
+int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
 {
     dap_config_t *l_cfg=NULL;
     dap_string_t *l_cfg_path = dap_string_new("network/");
@@ -1331,6 +1448,7 @@ int s_net_load(const char * a_net_name)
             return -1;
         }
         PVT(l_net)->load_mode = true;
+        PVT(l_net)->acl_idx = a_acl_idx;
         l_net->pub.gdb_groups_prefix = dap_strdup (
                     dap_config_get_item_str_default(l_cfg , "general" , "gdb_groups_prefix",
                                                     dap_config_get_item_str(l_cfg , "general" , "name" ) ) );
@@ -1850,6 +1968,22 @@ dap_chain_net_t * dap_chain_net_by_id( dap_chain_net_id_t a_id)
 
 }
 
+/**
+ * @brief dap_chain_net_by_id
+ * @param a_id
+ * @return
+ */
+uint16_t dap_chain_net_acl_idx_by_id(dap_chain_net_id_t a_id)
+{
+    dap_chain_net_item_t * l_net_item = NULL;
+    HASH_FIND(hh,s_net_items_ids,&a_id,sizeof (a_id), l_net_item );
+    if (l_net_item)
+        return PVT(l_net_item->chain_net)->acl_idx;
+    else
+        return -1;
+
+}
+
 
 /**
  * @brief dap_chain_net_id_by_name
@@ -2408,3 +2542,77 @@ void dap_chain_net_dump_datum(dap_string_t * a_str_out, dap_chain_datum_t * a_da
         }break;
     }
 }
+
+static bool s_net_check_acl(dap_chain_net_t *a_net, dap_chain_hash_fast_t *a_pkey_hash)
+{
+    const char l_path[] = "network/";
+    char l_cfg_path[strlen(a_net->pub.name) + strlen(l_path) + 1];
+    strcpy(l_cfg_path, l_path);
+    strcat(l_cfg_path, a_net->pub.name);
+    dap_config_t *l_cfg = dap_config_open(l_cfg_path);
+    const char *l_auth_type = dap_config_get_item_str(l_cfg, "auth", "type");
+    bool l_authorized = true;
+    if (l_auth_type && !strcmp(l_auth_type, "ca")) {
+        if (dap_hash_fast_is_blank(a_pkey_hash)) {
+            return false;
+        }
+        l_authorized = false;
+        const char *l_auth_hash_str = dap_chain_hash_fast_to_str_new(a_pkey_hash);
+        uint16_t l_acl_list_len = 0;
+        char **l_acl_list = dap_config_get_array_str(l_cfg, "auth", "acl_accept_ca_list", &l_acl_list_len);
+        for (uint16_t i = 0; i < l_acl_list_len; i++) {
+            if (!strcmp(l_acl_list[i], l_auth_hash_str)) {
+                l_authorized = true;
+                break;
+            }
+        }
+        if (!l_authorized) {
+            const char *l_acl_gdb = dap_config_get_item_str(l_cfg, "auth", "acl_accept_ca_gdb");
+            if (l_acl_gdb) {
+                size_t l_objs_count;
+                dap_global_db_obj_t *l_objs = dap_chain_global_db_gr_load(l_acl_gdb, &l_objs_count);
+                for (size_t i = 0; i < l_objs_count; i++) {
+                    if (!strcmp(l_objs[i].key, l_auth_hash_str)) {
+                        l_authorized = true;
+                        break;
+                    }
+                }
+                dap_chain_global_db_objs_delete(l_objs, l_objs_count);
+            }
+        }
+        if (!l_authorized) {
+            const char *l_acl_chains = dap_config_get_item_str(l_cfg, "auth", "acl_accept_ca_chains");
+            if (l_acl_chains && !strcmp(l_acl_chains, "all")) {
+                dap_list_t *l_certs = dap_cert_get_all_mem();
+                for (dap_list_t *l_tmp = l_certs; l_tmp; l_tmp = dap_list_next(l_tmp)) {
+                    dap_cert_t *l_cert = (dap_cert_t *)l_tmp->data;
+                    size_t l_pkey_size;
+                    uint8_t *l_pkey_ser = dap_enc_key_serealize_pub_key(l_cert->enc_key, &l_pkey_size);
+                    dap_chain_hash_fast_t l_cert_hash;
+                    dap_hash_fast(l_pkey_ser, l_pkey_size, &l_cert_hash);
+                    if (!memcmp(l_pkey_ser, a_pkey_hash, sizeof(dap_chain_hash_fast_t))) {
+                        l_authorized = true;
+                        DAP_DELETE(l_pkey_ser);
+                        break;
+                    }
+                    DAP_DELETE(l_pkey_ser);
+                }
+            }
+        }
+    }
+    return l_authorized;
+}
+
+static uint8_t *dap_chain_net_set_acl(dap_chain_hash_fast_t *a_pkey_hash)
+{
+    uint16_t l_net_count;
+    dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
+    if (l_net_count) {
+        uint8_t *l_ret = DAP_NEW_SIZE(uint8_t, l_net_count);
+        for (uint16_t i = 0; i < l_net_count; i++) {
+            l_ret[i] = s_net_check_acl(l_net_list[i], a_pkey_hash);
+        }
+        return l_ret;
+    }
+    return NULL;
+}
diff --git a/modules/net/dap_chain_node_client.c b/modules/net/dap_chain_node_client.c
index 84d03e43b69081b38ff4302c70bf58ffb51650be..1c3fe94d75e7944768ed291173f5714867dc825a 100644
--- a/modules/net/dap_chain_node_client.c
+++ b/modules/net/dap_chain_node_client.c
@@ -477,6 +477,8 @@ dap_chain_node_client_t* dap_chain_client_connect(dap_chain_node_info_t *a_node_
     l_node_client->remote_node_addr.uint64 = a_node_info->hdr.address.uint64;
     dap_client_set_active_channels(l_node_client->client, a_active_channels);
 
+    //dap_client_set_auth_cert(l_node_client->client, dap_cert_find_by_name("auth")); // TODO provide the certificate choice
+
     int hostlen = 128;
     char host[hostlen];
     if(a_node_info->hdr.ext_addr_v4.s_addr)
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index edcbffcbf3927be70cf4f4525f911a1659804566..941019b63282482e9f5c6cd61dc7d59b69c32412 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -102,6 +102,7 @@ void dap_chain_net_proc_mempool (dap_chain_net_t * a_net);
 
 dap_chain_net_t * dap_chain_net_by_name( const char * a_name);
 dap_chain_net_t * dap_chain_net_by_id( dap_chain_net_id_t a_id);
+uint16_t dap_chain_net_acl_idx_by_id(dap_chain_net_id_t a_id);
 dap_chain_net_id_t dap_chain_net_id_by_name( const char * a_name);
 dap_ledger_t * dap_chain_ledger_by_net_name( const char * a_net_name);