From c6f678fda42af8920ca6513c74f256ade4a48ab7 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Tue, 12 May 2020 14:51:21 +0300
Subject: [PATCH] [+] Metadata read & tool

---
 dap-sdk/core/include/dap_binary_tree.h |   2 +-
 dap-sdk/core/include/dap_common.h      |   7 +
 dap-sdk/core/src/dap_binary_tree.c     |   8 +-
 dap-sdk/core/src/dap_common.c          |  69 ++++++++++
 dap-sdk/crypto/include/dap_cert.h      |  17 ++-
 dap-sdk/crypto/include/dap_cert_file.h |   5 +
 dap-sdk/crypto/src/dap_cert.c          | 119 ++++++++++++++++-
 dap-sdk/crypto/src/dap_cert_file.c     | 177 +++++++++++++++++++++++--
 modules/net/dap_dns_server.c           |   1 -
 9 files changed, 380 insertions(+), 25 deletions(-)

diff --git a/dap-sdk/core/include/dap_binary_tree.h b/dap-sdk/core/include/dap_binary_tree.h
index ae28d74ca5..e2eaba9ffa 100644
--- a/dap-sdk/core/include/dap_binary_tree.h
+++ b/dap-sdk/core/include/dap_binary_tree.h
@@ -44,7 +44,7 @@ dap_list_t *dap_binary_tree_inorder_list(dap_binary_tree_t *a_tree_root);
 void *dap_binary_tree_search(dap_binary_tree_t *a_tree_root, dap_binary_tree_key_t a_key);
 void *dap_binary_tree_minimum(dap_binary_tree_t *a_tree_root);
 void *dap_binary_tree_maximum(dap_binary_tree_t *a_tree_root);
-void dap_binary_tree_insert(dap_binary_tree_t *a_tree_root, dap_binary_tree_key_t a_key, void *a_data);
+dap_binary_tree_t *dap_binary_tree_insert(dap_binary_tree_t *a_tree_root, dap_binary_tree_key_t a_key, void *a_data);
 dap_binary_tree_t *dap_binary_tree_delete(dap_binary_tree_t *a_tree_root, dap_binary_tree_key_t a_key);
 size_t dap_binary_tree_count(dap_binary_tree_t *a_tree_root);
 void dap_binary_tree_clear(dap_binary_tree_t *a_tree_root);
diff --git a/dap-sdk/core/include/dap_common.h b/dap-sdk/core/include/dap_common.h
index ee1b595c5b..543b50ca57 100755
--- a/dap-sdk/core/include/dap_common.h
+++ b/dap-sdk/core/include/dap_common.h
@@ -391,6 +391,13 @@ void dap_digit_from_string2(const char *num_str, void *raw, size_t raw_len);
 void *dap_interval_timer_create(unsigned int a_msec, dap_timer_callback_t a_callback, void *a_param);
 int dap_interval_timer_delete(void *a_timer);
 
+uint16_t dap_lendian_get16(const uint8_t *a_buf);
+void dap_lendian_put16(uint8_t *a_buf, uint16_t a_val);
+uint32_t dap_lendian_get32(const uint8_t *a_buf);
+void dap_lendian_put32(uint8_t *a_buf, uint32_t a_val);
+uint64_t dap_lendian_get64(const uint8_t *a_buf);
+void dap_lendian_put64(uint8_t *a_buf, uint64_t a_val);
+
 #ifdef __MINGW32__
 int exec_silent(const char *a_cmd);
 #endif
diff --git a/dap-sdk/core/src/dap_binary_tree.c b/dap-sdk/core/src/dap_binary_tree.c
index 530f956536..3735fad5c5 100644
--- a/dap-sdk/core/src/dap_binary_tree.c
+++ b/dap-sdk/core/src/dap_binary_tree.c
@@ -112,9 +112,9 @@ static dap_binary_tree_t *s_tree_insert(dap_binary_tree_t *a_elm, dap_binary_tre
     return a_elm;
 }
 
-void dap_binary_tree_insert(dap_binary_tree_t *a_tree_root, dap_binary_tree_key_t a_key, void *a_data)
+dap_binary_tree_t *dap_binary_tree_insert(dap_binary_tree_t *a_tree_root, dap_binary_tree_key_t a_key, void *a_data)
 {
-    s_tree_insert(a_tree_root, a_key, a_data);
+    return s_tree_insert(a_tree_root, a_key, a_data);
 }
 
 static dap_binary_tree_t *s_tree_delete(dap_binary_tree_t *a_elm, dap_binary_tree_key_t a_key)
@@ -132,12 +132,15 @@ static dap_binary_tree_t *s_tree_delete(dap_binary_tree_t *a_elm, dap_binary_tre
         a_elm->data = l_tmp->data;
         a_elm->right = s_tree_delete(a_elm->right, a_elm->key);
     } else if (a_elm->left) {
+        DAP_DELETE(a_elm->data);
         DAP_DELETE(a_elm);
         a_elm = a_elm->left;
     } else if (a_elm->right) {
+        DAP_DELETE(a_elm->data);
         DAP_DELETE(a_elm);
         a_elm = a_elm->right;
     } else {
+        DAP_DELETE(a_elm->data);
         DAP_DELETE(a_elm);
         a_elm = NULL;
     }
@@ -183,6 +186,7 @@ dap_binary_tree_t *s_tree_clear(dap_binary_tree_t *a_elm)
     if (a_elm->right) {
         a_elm->right = s_tree_clear(a_elm->right);
     }
+    DAP_DELETE(a_elm->data);
     DAP_DELETE(a_elm);
     return NULL;
 }
diff --git a/dap-sdk/core/src/dap_common.c b/dap-sdk/core/src/dap_common.c
index 78b63ee843..8a6b893ec9 100755
--- a/dap-sdk/core/src/dap_common.c
+++ b/dap-sdk/core/src/dap_common.c
@@ -922,3 +922,72 @@ int dap_interval_timer_delete(void *a_timer)
     return timer_delete((timer_t)a_timer);
 #endif
 }
+
+/**
+ * @brief dap_lendian_get16 Get uint16 from little endian memory
+ * @param a_buf a buffer read from
+ * @return uint16 in host endian memory
+ */
+uint16_t dap_lendian_get16(const uint8_t *a_buf)
+{
+    uint8_t u = *a_buf;
+    return (uint16_t)(*(a_buf + 1)) << 8 | u;
+}
+
+/**
+ * @brief dap_lendian_put16 Put uint16 to little endian memory
+ * @param buf a buffer write to
+ * @param val uint16 in host endian memory
+ * @return none
+ */
+void dap_lendian_put16(uint8_t *a_buf, uint16_t a_val)
+{
+    *(a_buf) = a_val;
+    *(a_buf + 1) = a_val >> 8;
+}
+
+/**
+ * @brief dap_lendian_get32 Get uint32 from little endian memory
+ * @param a_buf a buffer read from
+ * @return uint32 in host endian memory
+ */
+uint32_t dap_lendian_get32(const uint8_t *a_buf)
+{
+    uint16_t u = dap_lendian_get16(a_buf);
+    return (uint32_t)dap_lendian_get16(a_buf + 2) << 16 | u;
+}
+
+/**
+ * @brief dap_lendian_put32 Put uint32 to little endian memory
+ * @param buf a buffer write to
+ * @param val uint32 in host endian memory
+ * @return none
+ */
+void dap_lendian_put32(uint8_t *a_buf, uint32_t a_val)
+{
+    dap_lendian_put16(a_buf, a_val);
+    dap_lendian_put16(a_buf + 2, a_val >> 16);
+}
+
+/**
+ * @brief dap_lendian_get64 Get uint64 from little endian memory
+ * @param a_buf a buffer read from
+ * @return uint64 in host endian memory
+ */
+uint64_t dap_lendian_get64(const uint8_t *a_buf)
+{
+    uint32_t u = dap_lendian_get32(a_buf);
+    return (uint64_t)dap_lendian_get32(a_buf + 4) << 32 | u;
+}
+
+/**
+ * @brief dap_lendian_put64 Put uint64 to little endian memory
+ * @param buf a buffer write to
+ * @param val uint64 in host endian memory
+ * @return none
+ */
+void dap_lendian_put64(uint8_t *a_buf, uint64_t a_val)
+{
+    dap_lendian_put32(a_buf, a_val);
+    dap_lendian_put32(a_buf + 4, a_val >> 32);
+}
diff --git a/dap-sdk/crypto/include/dap_cert.h b/dap-sdk/crypto/include/dap_cert.h
index e610c30523..9ba4e00ec1 100755
--- a/dap-sdk/crypto/include/dap_cert.h
+++ b/dap-sdk/crypto/include/dap_cert.h
@@ -43,8 +43,8 @@ typedef enum dap_cert_metadata_type {
 } dap_cert_metadata_type_t;
 
 typedef struct dap_cert_metadata {
-    dap_binary_tree_key_t key;      // Key also may be outside the structure
-    size_t length;
+    const char *key;
+    uint32_t length;
     dap_cert_metadata_type_t type : 8;
     byte_t value[];
 } dap_cert_metadata_t;
@@ -104,13 +104,24 @@ void dap_cert_deinit();
 void dap_cert_delete(dap_cert_t * a_cert);
 void dap_cert_delete_by_name(const char * a_cert_name);
 
+dap_cert_metadata_t *dap_cert_new_meta(const char *a_key, dap_cert_metadata_type_t a_type, void *a_value, size_t a_value_size);
+void dap_cert_add_meta(dap_cert_t *a_cert, const char *a_key, dap_cert_metadata_type_t a_type, void *a_value, size_t a_value_size);
+void dap_cert_add_meta_scalar(dap_cert_t *a_cert, const char *a_key, dap_cert_metadata_type_t a_type, uint64_t a_value, size_t a_value_size);
+#define dap_cert_add_meta_string(a_cert, a_key, a_str) dap_cert_add_meta(a_cert, a_key, DAP_CERT_META_STRING, (void *)a_str, strlen(a_str))
+#define dap_cert_add_meta_sign(a_cert, a_key, a_sign) dap_cert_add_meta(a_cert, a_key, DAP_CERT_META_SIGN, (void *)a_sign, dap_sign_get_size(a_sign))
+#define dap_cert_add_meta_custom(a_cert, a_key, a_val, a_size) dap_cert_add_meta(a_cert, a_key, DAP_CERT_META_CUSTOM, a_val, a_size)
+#define dap_cert_add_meta_bool(a_cert, a_key, a_bool) dap_cert_add_meta_scalar(a_cert, a_key, DAP_CERT_META_BOOL, a_bool, sizeof(bool))
+#define dap_cert_add_meta_int(a_cert, a_key, a_int) dap_cert_add_meta_scalar(a_cert, a_key, DAP_CERT_META_INT, a_int, sizeof(int))
+#define dap_cert_add_meta_time(a_cert, a_key, a_time) dap_cert_add_meta_scalar(a_cert, a_key, DAP_CERT_META_DATETIME, a_time, sizeof(time_t))
+#define dap_cert_add_meta_period(a_cert, a_key, a_period) dap_cert_add_meta_scalar(a_cert, a_key, DAP_CERT_META_DATETIME_PERIOD, a_period, sizeof(time_t))
+
 char *dap_cert_get_meta_string(dap_cert_t *a_cert, const char *a_field);
 bool dap_cert_get_meta_bool(dap_cert_t *a_cert, const char *a_field);
 int dap_cert_get_meta_int(dap_cert_t *a_cert, const char *a_field);
 time_t dap_cert_get_meta_time(dap_cert_t *a_cert, const char *a_field);
 time_t dap_cert_get_meta_period(dap_cert_t *a_cert, const char *a_field);
 dap_sign_t *dap_cert_get_meta_sign(dap_cert_t *a_cert, const char *a_field);
-void *dap_cert_get_meta_custom(dap_cert_t *a_cert, const char *a_field);
+void *dap_cert_get_meta_custom(dap_cert_t *a_cert, const char *a_field, size_t *a_meta_size_out);
 
 #ifdef __cplusplus
 }
diff --git a/dap-sdk/crypto/include/dap_cert_file.h b/dap-sdk/crypto/include/dap_cert_file.h
index 6ab2293a43..2753faa1e7 100755
--- a/dap-sdk/crypto/include/dap_cert_file.h
+++ b/dap-sdk/crypto/include/dap_cert_file.h
@@ -53,6 +53,11 @@ typedef struct dap_cert_file{
     uint8_t data[];
 }DAP_ALIGN_PACKED dap_cert_file_t;
 
+typedef struct dap_cert_file_aux {
+    size_t *buf;
+    size_t idx;
+} dap_cert_file_aux_t;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/dap-sdk/crypto/src/dap_cert.c b/dap-sdk/crypto/src/dap_cert.c
index 63cab81548..c3e3410fff 100755
--- a/dap-sdk/crypto/src/dap_cert.c
+++ b/dap-sdk/crypto/src/dap_cert.c
@@ -447,8 +447,20 @@ void dap_cert_dump(dap_cert_t * a_cert)
     printf ("Signature type: %s\n", dap_sign_type_to_str( dap_sign_type_from_key_type(a_cert->enc_key->type) ) );
     printf ("Private key size: %llu\n",a_cert->enc_key->priv_key_data_size);
     printf ("Public key size: %llu\n", a_cert->enc_key->pub_key_data_size);
-    printf ("Metadata section count: %llu\n", dap_binary_tree_count(a_cert->metadata));
+    size_t l_meta_items_cnt = dap_binary_tree_count(a_cert->metadata);
+    printf ("Metadata section count: %llu\n", l_meta_items_cnt);
     printf ("Certificates signatures chain size: %llu\n",dap_cert_count_cert_sign (a_cert));
+    if (l_meta_items_cnt) {
+        printf ("Metadata section\n");
+        dap_list_t *l_meta_list = dap_binary_tree_inorder_list(a_cert->metadata);
+        dap_list_t *l_meta_list_item = dap_list_first(l_meta_list);
+        while (l_meta_list_item) {
+            dap_cert_metadata_t *l_meta_item = (dap_cert_metadata_t *)l_meta_list_item->data;
+            printf("%s\t%u\t%u\t%s", l_meta_item->key, l_meta_item->type, l_meta_item->length, l_meta_item->value);
+            l_meta_list_item = l_meta_list_item->next;
+        }
+        dap_list_free(l_meta_list);
+    }
 }
 
 /**
@@ -512,6 +524,80 @@ void dap_cert_add_folder(const char *a_folder_path)
         log_it(L_WARNING, "Can't add folder %s to cert manager",a_folder_path);
 }
 
+dap_cert_metadata_t *dap_cert_new_meta(const char *a_key, dap_cert_metadata_type_t a_type, void *a_value, size_t a_value_size)
+{
+    if (!a_key || a_type > DAP_CERT_META_CUSTOM || (!a_value && a_value_size)) {
+        log_it(L_WARNING, "Incorrect arguments for dap_cert_new_meta()");
+        return NULL;
+    }
+    size_t l_meta_item_size = sizeof(dap_cert_metadata_t) + a_value_size + strlen(a_key) + 1;
+    dap_cert_metadata_t *l_new_meta = DAP_NEW_SIZE(void, l_meta_item_size);
+    l_new_meta->length = a_value_size;
+    l_new_meta->type = a_type;
+    memcpy((void *)l_new_meta->value, a_value, a_value_size);
+    dap_stpcpy((char *)&l_new_meta->value[a_value_size], a_key);
+    l_new_meta->key = (const char *)&l_new_meta->value[a_value_size];
+    return l_new_meta;
+}
+
+/**
+ * @brief dap_cert_add_meta Add metadata to certificate
+ * @param a_cert
+ * @param a_key
+ * @param a_type
+ * @param a_value
+ * @param a_value_size
+ */
+void dap_cert_add_meta(dap_cert_t *a_cert, const char *a_key, dap_cert_metadata_type_t a_type, void *a_value, size_t a_value_size)
+{
+    if (!a_cert) {
+        log_it(L_WARNING, "Certificate pointer to add metadata is NULL");
+        return;
+    }
+    dap_cert_metadata_t *l_new_meta = dap_cert_new_meta(a_key, a_type, a_value, a_value_size);
+    dap_binary_tree_t *l_new_root = dap_binary_tree_insert(a_cert->metadata, a_key, (void *)l_new_meta);
+    if (!a_cert->metadata) {
+        a_cert->metadata = l_new_root;
+    }
+}
+
+void dap_cert_add_meta_scalar(dap_cert_t *a_cert, const char *a_key, dap_cert_metadata_type_t a_type, uint64_t a_value, size_t a_value_size)
+{
+    byte_t l_tmp8, *l_value;
+    uint16_t l_tmp16;
+    uint32_t l_tmp32;
+    uint64_t l_tmp64;
+    switch (a_type) {
+    case DAP_CERT_META_STRING:
+    case DAP_CERT_META_SIGN:
+    case DAP_CERT_META_CUSTOM:
+        log_it(L_WARNING, "incoorect metadata type for dap_cert_add_meta_scalar()");
+        return;
+    default:
+        switch (a_value_size) {
+        case 1:
+            l_tmp8 = a_value;
+            l_value = &l_tmp8;
+            break;
+        case 2:
+            l_tmp16 = a_value;
+            l_value = (byte_t *)&l_tmp16;
+            break;
+        case 4:
+            l_tmp32 = a_value;
+            l_value = (byte_t *)&l_tmp32;
+            break;
+        case 8:
+        default:
+            l_tmp64 = a_value;
+            l_value = (byte_t *)&l_tmp64;
+            break;
+        }
+        break;
+    }
+    dap_cert_add_meta(a_cert, a_key, a_type, (void *)&l_value, a_value_size);
+}
+
 /**
  * @brief dap_cert_get_meta
  * @param a_cert
@@ -525,19 +611,22 @@ dap_cert_metadata_t *dap_cert_get_meta(dap_cert_t *a_cert, const char *a_field)
 char *dap_cert_get_meta_string(dap_cert_t *a_cert, const char *a_field)
 {
     dap_cert_metadata_t *l_meta = dap_cert_get_meta(a_cert, a_field);
+    if (!l_meta) {
+        return NULL;
+    }
     if (l_meta->type != DAP_CERT_META_STRING) {
         log_it(L_DEBUG, "Requested and actual metadata types are not equal");
         return NULL;
     }
-    char *l_ret_str = DAP_NEW_SIZE(char, l_meta->length);
-    strncpy(l_ret_str, (char *)&l_meta->value[0], l_meta->length);
-    l_ret_str[l_meta->length] = 0;
-    return l_ret_str;
+    return strndup((char *)&l_meta->value[0], l_meta->length);
 }
 
 bool dap_cert_get_meta_bool(dap_cert_t *a_cert, const char *a_field)
 {
     dap_cert_metadata_t *l_meta = dap_cert_get_meta(a_cert, a_field);
+    if (!l_meta) {
+        return -1;
+    }
     if (l_meta->type != DAP_CERT_META_BOOL) {
         log_it(L_DEBUG, "Requested and actual metadata types are not equal");
         return -1;
@@ -551,6 +640,9 @@ bool dap_cert_get_meta_bool(dap_cert_t *a_cert, const char *a_field)
 int dap_cert_get_meta_int(dap_cert_t *a_cert, const char *a_field)
 {
     dap_cert_metadata_t *l_meta = dap_cert_get_meta(a_cert, a_field);
+    if (!l_meta) {
+        return -1;
+    }
     if (l_meta->type != DAP_CERT_META_INT) {
         log_it(L_DEBUG, "Requested and actual metadata types are not equal");
         return -1;
@@ -564,6 +656,9 @@ int dap_cert_get_meta_int(dap_cert_t *a_cert, const char *a_field)
 time_t dap_cert_get_meta_time(dap_cert_t *a_cert, const char *a_field)
 {
     dap_cert_metadata_t *l_meta = dap_cert_get_meta(a_cert, a_field);
+    if (!l_meta) {
+        return -1;
+    }
     if (l_meta->type != DAP_CERT_META_DATETIME) {
         log_it(L_DEBUG, "Requested and actual metadata types are not equal");
         return -1;
@@ -577,6 +672,9 @@ time_t dap_cert_get_meta_time(dap_cert_t *a_cert, const char *a_field)
 time_t dap_cert_get_meta_period(dap_cert_t *a_cert, const char *a_field)
 {
     dap_cert_metadata_t *l_meta = dap_cert_get_meta(a_cert, a_field);
+    if (!l_meta) {
+        return -1;
+    }
     if (l_meta->type != DAP_CERT_META_DATETIME_PERIOD) {
         log_it(L_DEBUG, "Requested and actual metadata types are not equal");
         return -1;
@@ -590,6 +688,9 @@ time_t dap_cert_get_meta_period(dap_cert_t *a_cert, const char *a_field)
 dap_sign_t *dap_cert_get_meta_sign(dap_cert_t *a_cert, const char *a_field)
 {
     dap_cert_metadata_t *l_meta = dap_cert_get_meta(a_cert, a_field);
+    if (!l_meta) {
+        return NULL;
+    }
     if (l_meta->type != DAP_CERT_META_SIGN) {
         log_it(L_DEBUG, "Requested and actual metadata types are not equal");
         return NULL;
@@ -601,13 +702,19 @@ dap_sign_t *dap_cert_get_meta_sign(dap_cert_t *a_cert, const char *a_field)
     return l_ret;
 }
 
-void *dap_cert_get_meta_custom(dap_cert_t *a_cert, const char *a_field)
+void *dap_cert_get_meta_custom(dap_cert_t *a_cert, const char *a_field, size_t *a_meta_size_out)
 {
     dap_cert_metadata_t *l_meta = dap_cert_get_meta(a_cert, a_field);
+    if (!l_meta) {
+        return NULL;
+    }
     if (l_meta->type != DAP_CERT_META_CUSTOM) {
         log_it(L_DEBUG, "Requested and actual metadata types are not equal");
         return NULL;
     }
+    if (a_meta_size_out) {
+        *a_meta_size_out = l_meta->length;
+    }
     return (void *)&l_meta->value[0];
 }
 
diff --git a/dap-sdk/crypto/src/dap_cert_file.c b/dap-sdk/crypto/src/dap_cert_file.c
index e6880ce440..94ddf77323 100755
--- a/dap-sdk/crypto/src/dap_cert_file.c
+++ b/dap-sdk/crypto/src/dap_cert_file.c
@@ -32,6 +32,8 @@
 
 #define LOG_TAG "dap_cert_file"
 
+static const char s_key_inheritor[] = "Inheritor";
+
 /**
  * @brief dap_cert_file_save
  * @param a_cert
@@ -64,6 +66,146 @@ int dap_cert_file_save(dap_cert_t * a_cert, const char * a_cert_file_path)
     }
 }
 
+// balance the binary tree
+void s_balance_the_tree(dap_cert_file_aux_t *a_reorder, size_t a_left_idx, size_t a_right_idx)
+{
+    if (a_left_idx == a_right_idx) {
+        a_reorder->buf[a_reorder->idx++] = a_left_idx;
+        return;
+    }
+    size_t i = (a_left_idx + a_right_idx) / 2 + 1;
+    a_reorder->buf[a_reorder->idx++] = i;
+    s_balance_the_tree(a_reorder, a_left_idx, i - 1);
+    if (i < a_right_idx) {
+        s_balance_the_tree(a_reorder, i + 1, a_right_idx);
+    }
+}
+
+void dap_cert_deserialize_meta(dap_cert_t *a_cert, const uint8_t *a_data, size_t a_size)
+{
+    dap_cert_metadata_t **l_meta_arr = NULL;
+    size_t l_mem_shift = 0;
+    size_t l_meta_items_count = 0;
+    while (l_mem_shift < a_size) {
+        const char *l_key_str = (const char *)&a_data[l_mem_shift];
+        if (!l_key_str) {
+            break;
+        }
+        l_mem_shift += strlen(l_key_str) + 1;
+        uint32_t l_value_size = dap_lendian_get32(&a_data[l_mem_shift]);
+        l_mem_shift += sizeof(uint32_t);
+        dap_cert_metadata_type_t l_meta_type = (dap_cert_metadata_type_t)a_data[l_mem_shift++];
+        const uint8_t *l_value = &a_data[l_mem_shift];
+        uint16_t l_tmp16;
+        uint32_t l_tmp32;
+        uint64_t l_tmp64;
+        switch (l_meta_type) {
+        case DAP_CERT_META_STRING:
+        case DAP_CERT_META_SIGN:
+        case DAP_CERT_META_CUSTOM:
+            break;
+        default:
+            switch (l_value_size) {
+            case 1:
+                break;
+            case 2:
+                l_tmp16 = dap_lendian_get16(l_value);
+                l_value = (const uint8_t *)&l_tmp16;
+                break;
+            case 4:
+                l_tmp32 = dap_lendian_get32(l_value);
+                l_value = (const uint8_t *)&l_tmp32;
+                break;
+            case 8:
+            default:
+                l_tmp64 = dap_lendian_get64(l_value);
+                l_value = (const uint8_t *)&l_tmp64;
+                break;
+            }
+            break;
+        }
+        dap_cert_metadata_t *l_new_meta = dap_cert_new_meta(l_key_str, l_meta_type, (void *)l_value, l_value_size);
+        if (l_meta_arr == NULL) {
+            l_meta_arr = DAP_NEW(dap_cert_metadata_t *);
+        } else {
+            l_meta_arr = DAP_REALLOC(l_meta_arr, (l_meta_items_count + 1) * sizeof(dap_cert_metadata_t *));
+        }
+        l_meta_arr[l_meta_items_count++] = l_new_meta;
+    }
+    size_t l_reorder_arr[l_meta_items_count];
+    dap_cert_file_aux_t l_reorder = {l_reorder_arr, 0};
+    s_balance_the_tree(&l_reorder, 0, l_meta_items_count);
+    size_t n = l_reorder_arr[0];
+    a_cert->metadata = dap_binary_tree_insert(NULL, l_meta_arr[n]->key, (void *)l_meta_arr[n]);
+    for (size_t i = 1; i < l_meta_items_count; i++) {
+        n = l_reorder_arr[i];
+        dap_binary_tree_insert(a_cert->metadata, l_meta_arr[n]->key, (void *)l_meta_arr[n]);
+    }
+    DAP_DELETE(l_meta_arr);
+}
+
+uint8_t *dap_cert_serialize_meta(dap_cert_t *a_cert, size_t *a_buflen_out)
+{
+    if (!a_cert) {
+        return NULL;
+    }
+    if ( a_cert->enc_key->_inheritor_size) {
+        dap_cert_add_meta_custom(a_cert, s_key_inheritor, a_cert->enc_key->_inheritor, a_cert->enc_key->_inheritor_size);
+    }
+    dap_list_t *l_meta_list = dap_binary_tree_inorder_list(a_cert->metadata);
+    dap_list_t *l_meta_list_item = dap_list_first(l_meta_list);
+    uint8_t *l_buf = NULL;
+    size_t l_mem_shift = 0;
+    while (l_meta_list_item) {
+        dap_cert_metadata_t *l_meta_item = l_meta_list_item->data;
+        size_t l_meta_item_size = sizeof(dap_cert_metadata_t) - sizeof(const char *) + l_meta_item->length + strlen(l_meta_item->key) + 1;
+        if (l_buf) {
+            l_buf = DAP_REALLOC(l_buf, l_mem_shift + l_meta_item_size);
+        } else {
+            l_buf = DAP_NEW_SIZE(uint8_t, l_meta_item_size);
+        }
+        strcpy((char *)&l_buf[l_mem_shift], l_meta_item->key);
+        l_mem_shift += strlen(l_meta_item->key) + 1;
+        dap_lendian_put32(&l_buf[l_mem_shift], l_meta_item->length);
+        l_mem_shift += sizeof(uint32_t);
+        l_buf[l_mem_shift++] = l_meta_item->type;
+        switch (l_meta_item->type) {
+        case DAP_CERT_META_STRING:
+        case DAP_CERT_META_SIGN:
+        case DAP_CERT_META_CUSTOM:
+            memcpy(&l_buf[l_mem_shift], l_meta_item->value, l_meta_item->length);
+            l_mem_shift += l_meta_item->length;
+            break;
+        default:
+            switch (l_meta_item->length) {
+            case 1:
+                l_buf[l_mem_shift++] = l_meta_item->value[0];
+                break;
+            case 2:
+                dap_lendian_put16(&l_buf[l_mem_shift], *(uint16_t *)&l_meta_item->value[0]);
+                l_mem_shift += 2;
+                break;
+            case 4:
+                dap_lendian_put32(&l_buf[l_mem_shift], *(uint32_t *)&l_meta_item->value[0]);
+                l_mem_shift += 4;
+                break;
+            case 8:
+            default:
+                dap_lendian_put64(&l_buf[l_mem_shift], *(uint64_t *)&l_meta_item->value[0]);
+                l_mem_shift += 8;
+                break;
+            }
+            break;
+        }
+        l_meta_list_item = l_meta_list_item->next;
+    }
+    dap_list_free(l_meta_list);
+    if (a_buflen_out) {
+        *a_buflen_out = l_mem_shift;
+    }
+    return l_buf;
+}
+
 /**
  * @brief dap_cert_file_save_to_mem
  * @param a_cert
@@ -79,12 +221,14 @@ uint8_t* dap_cert_mem_save(dap_cert_t * a_cert, uint32_t *a_cert_size_out)
 
     size_t l_priv_key_data_size = a_cert->enc_key->priv_key_data_size;
     size_t l_pub_key_data_size = a_cert->enc_key->pub_key_data_size;
+    size_t l_metadata_size = l_key->_inheritor_size;
     uint8_t *l_pub_key_data = a_cert->enc_key->pub_key_data_size ?
                 dap_enc_key_serealize_pub_key(l_key, &l_pub_key_data_size) :
                 NULL;
     uint8_t *l_priv_key_data = a_cert->enc_key->priv_key_data ?
                 dap_enc_key_serealize_priv_key(l_key, &l_priv_key_data_size) :
                 NULL;
+    uint8_t *l_metadata = dap_cert_serialize_meta(a_cert, &l_metadata_size);
 
     l_hdr.sign = dap_cert_FILE_HDR_SIGN;
     l_hdr.type = dap_cert_FILE_TYPE_PUBLIC;
@@ -103,13 +247,17 @@ uint8_t* dap_cert_mem_save(dap_cert_t * a_cert, uint32_t *a_cert_size_out)
     l_hdr.version = dap_cert_FILE_VERSION;
     l_hdr.data_size = l_pub_key_data_size;
     l_hdr.data_pvt_size = l_priv_key_data_size;
-    l_hdr.metadata_size = l_key->_inheritor_size;
+    l_hdr.metadata_size = l_metadata_size;
 
     l_hdr.ts_last_used = l_key->last_used_timestamp;
     l_hdr.sign_type = dap_sign_type_from_key_type ( l_key->type );
 
 
-    l_data = DAP_NEW_SIZE(void, sizeof(l_hdr) + DAP_CERT_ITEM_NAME_MAX + l_priv_key_data_size + l_pub_key_data_size + l_hdr.metadata_size);
+    l_data = DAP_NEW_SIZE(void, sizeof(l_hdr) + DAP_CERT_ITEM_NAME_MAX + l_priv_key_data_size + l_pub_key_data_size + l_metadata_size);
+    if (!l_data) {
+        log_it(L_ERROR,"Certificate \"%s\" was not serialized",a_cert->name);
+        goto lb_exit;
+    }
 
     memcpy(l_data +l_data_offset, &l_hdr ,sizeof(l_hdr) );
     l_data_offset += sizeof(l_hdr);
@@ -125,17 +273,21 @@ uint8_t* dap_cert_mem_save(dap_cert_t * a_cert, uint32_t *a_cert_size_out)
         l_data_offset += l_priv_key_data_size;
     }
 
-    if ( l_key->_inheritor_size ) {
-        memcpy(l_data +l_data_offset, l_key->_inheritor ,l_key->_inheritor_size );
-        l_data_offset += l_key->_inheritor_size;
+    if ( l_metadata_size ) {
+        memcpy(l_data +l_data_offset, l_metadata, l_metadata_size );
+        l_data_offset += l_metadata_size;
     }
 lb_exit:
     DAP_DELETE(l_pub_key_data);
-    DAP_DELETE(l_priv_key_data);
-    if (l_data)
-        log_it(L_NOTICE,"Certificate \"%s\" successfully serialized",a_cert->name);
-    else
-        log_it(L_ERROR,"Certificate \"%s\" was not serialized",a_cert->name);
+    if ( l_priv_key_data_size ) {
+        DAP_DELETE(l_priv_key_data);
+    }
+    if ( l_metadata_size ) {
+        DAP_DELETE(l_metadata);
+    }
+
+    log_it(L_NOTICE,"Certificate \"%s\" successfully serialized",a_cert->name);
+
     if(a_cert_size_out)
         *a_cert_size_out = l_data_offset;
     return l_data;
@@ -217,8 +369,9 @@ dap_cert_t* dap_cert_mem_load(const void * a_data, size_t a_data_size)
             dap_enc_key_deserealize_priv_key(l_ret->enc_key, l_data + l_data_offset, l_hdr.data_pvt_size);
             l_data_offset += l_hdr.data_pvt_size;
         }
-        if(l_hdr.metadata_size > 0 && l_ret->enc_key->_inheritor && l_ret->enc_key->_inheritor_size == l_hdr.metadata_size) {
-            memcpy(l_ret->enc_key->_inheritor, l_data + l_data_offset, l_ret->enc_key->_inheritor_size);
+        if ( l_hdr.metadata_size > 0 ){
+            dap_cert_deserialize_meta(l_ret, l_data + l_data_offset, l_hdr.metadata_size);
+            l_data_offset += l_hdr.metadata_size;
         }
         dap_enc_key_update(l_ret->enc_key);
         log_it(L_NOTICE,"Successfully loaded certificate %s", l_ret->name);
diff --git a/modules/net/dap_dns_server.c b/modules/net/dap_dns_server.c
index 64322e2a78..27ead03d2b 100644
--- a/modules/net/dap_dns_server.c
+++ b/modules/net/dap_dns_server.c
@@ -33,7 +33,6 @@
 #include "dap_chain_global_db.h"
 #include "dap_chain_global_db_remote.h"
 
-#define UNUSED(x) (void)(x)
 #define LOG_TAG "dap_dns_server"
 
 static dap_dns_server_t *s_dns_server;
-- 
GitLab