about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/command/cmd_ac.c1
-rw-r--r--src/command/cmd_defs.c7
-rw-r--r--src/command/cmd_funcs.c58
-rw-r--r--src/command/cmd_funcs.h1
-rw-r--r--src/omemo/omemo.c244
-rw-r--r--src/omemo/omemo.h4
6 files changed, 268 insertions, 47 deletions
diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c
index 55f05c7c..ce66d507 100644
--- a/src/command/cmd_ac.c
+++ b/src/command/cmd_ac.c
@@ -579,6 +579,7 @@ cmd_ac_init(void)
     omemo_ac = autocomplete_new();
     autocomplete_add(omemo_ac, "gen");
     autocomplete_add(omemo_ac, "start");
+    autocomplete_add(omemo_ac, "trust");
     autocomplete_add(omemo_ac, "fingerprint");
 
     connect_property_ac = autocomplete_new();
diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c
index 7b2df39b..200a46d3 100644
--- a/src/command/cmd_defs.c
+++ b/src/command/cmd_defs.c
@@ -2331,10 +2331,11 @@ static struct cmd_t command_defs[] =
     },
 
     { "/omemo",
-        parse_args, 1, 2, NULL,
+        parse_args, 1, 3, NULL,
         CMD_SUBFUNCS(
             { "gen", cmd_omemo_gen },
             { "start", cmd_omemo_start },
+            { "trust", cmd_omemo_trust },
             { "fingerprint", cmd_omemo_fingerprint })
         CMD_NOMAINFUNC
         CMD_TAGS(
@@ -2343,6 +2344,7 @@ static struct cmd_t command_defs[] =
         CMD_SYN(
             "/omemo gen",
             "/omemo start [<contact>]",
+            "/omemo trust [<contact>] <fingerprint>",
             "/omemo fingerprint")
         CMD_DESC(
             "Omemo commands to manage keys, and perform encryption during chat sessions.")
@@ -2352,7 +2354,8 @@ static struct cmd_t command_defs[] =
             { "fingerprint",       "Show current device fingerprint." })
         CMD_EXAMPLES(
             "/omemo gen",
-            "/omemo start buddy@buddychat.org")
+            "/omemo start buddy@buddychat.org",
+            "/omemo trust c4f9c875-144d7a3b-0c4a05b6-ca3be51a-a037f329-0bd3ae62-07f99719-55559d2a")
     },
 };
 
diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c
index 70940f17..63c3df1b 100644
--- a/src/command/cmd_funcs.c
+++ b/src/command/cmd_funcs.c
@@ -8003,12 +8003,60 @@ cmd_omemo_fingerprint(ProfWin *window, const char *const command, gchar **args)
         return TRUE;
     }
 
-    char *fingerprint = omemo_own_fingerprint();
-    char *formated_fingerprint = omemo_format_fingerprint(fingerprint);
-    cons_show("%s", formated_fingerprint);
-
+    char *fingerprint = omemo_own_fingerprint(TRUE);
+    cons_show("%s", fingerprint);
     free(fingerprint);
-    free(formated_fingerprint);
+
+    return TRUE;
+#else
+    cons_show("This version of Profanity has not been built with OMEMO support enabled");
+    return TRUE;
+#endif
+}
+
+gboolean
+cmd_omemo_trust(ProfWin *window, const char *const command, gchar **args)
+{
+#ifdef HAVE_OMEMO
+    if (connection_get_status() != JABBER_CONNECTED) {
+        cons_show("You must be connected with an account to load OMEMO information.");
+        return TRUE;
+    }
+
+    if (!args[1]) {
+        cons_bad_cmd_usage(command);
+        return TRUE;
+    }
+
+    if (!omemo_loaded()) {
+        win_println(window, THEME_DEFAULT, '!', "You have not generated or loaded a cryptographic materials, use '/omemo gen'");
+        return TRUE;
+    }
+
+    char *fingerprint;
+    char *barejid;
+
+    /* Contact not provided */
+    if (!args[2]) {
+        fingerprint = args[1];
+
+        if (window->type != WIN_CHAT) {
+            win_println(window, THEME_DEFAULT, '-', "You must be in a regular chat window to trust a device without providing the contact.");
+            return TRUE;
+        }
+
+        ProfChatWin *chatwin = (ProfChatWin*)window;
+        assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
+        barejid = chatwin->barejid;
+    } else {
+        char *contact = args[2];
+        barejid = roster_barejid_from_name(contact);
+        if (barejid == NULL) {
+            barejid = contact;
+        }
+    }
+
+    omemo_trust(barejid, fingerprint);
 
     return TRUE;
 #else
diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h
index 4809f703..8a11881b 100644
--- a/src/command/cmd_funcs.h
+++ b/src/command/cmd_funcs.h
@@ -217,5 +217,6 @@ gboolean cmd_form_field(ProfWin *window, char *tag, gchar **args);
 gboolean cmd_omemo_gen(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_omemo_start(ProfWin *window, const char *const command, gchar **args);
 gboolean cmd_omemo_fingerprint(ProfWin *window, const char *const command, gchar **args);
+gboolean cmd_omemo_trust(ProfWin *window, const char *const command, gchar **args);
 
 #endif
diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c
index d649ff7e..3cae3315 100644
--- a/src/omemo/omemo.c
+++ b/src/omemo/omemo.c
@@ -12,15 +12,16 @@
 #include <gcrypt.h>
 
 #include "config/account.h"
+#include "config/files.h"
 #include "log.h"
-#include "omemo/store.h"
 #include "omemo/crypto.h"
 #include "omemo/omemo.h"
+#include "omemo/store.h"
 #include "ui/ui.h"
-#include "xmpp/xmpp.h"
+#include "ui/window_list.h"
 #include "xmpp/connection.h"
 #include "xmpp/omemo.h"
-#include "config/files.h"
+#include "xmpp/xmpp.h"
 
 static gboolean loaded;
 
@@ -33,6 +34,10 @@ static void omemo_log(int level, const char *message, size_t len, void *user_dat
 static gboolean handle_own_device_list(const char *const jid, GList *device_list);
 static gboolean handle_device_list_start_session(const char *const jid, GList *device_list);
 static void free_omemo_key(omemo_key_t *key);
+static char * omemo_fingerprint(ec_public_key *identity, gboolean formatted);
+static unsigned char *omemo_fingerprint_decode(const char *const fingerprint, size_t *len);
+static void cache_device_identity(const char *const jid, uint32_t device_id, ec_public_key *identity);
+static void g_hash_table_free(GHashTable *hash_table);
 
 typedef gboolean (*OmemoDeviceListHandler)(const char *const jid, GList *device_list);
 
@@ -56,6 +61,7 @@ struct omemo_context_t {
     GKeyFile *identity_keyfile;
     GString *sessions_filename;
     GKeyFile *sessions_keyfile;
+    GHashTable *known_devices;
 };
 
 static omemo_context omemo_ctx;
@@ -63,7 +69,7 @@ static omemo_context omemo_ctx;
 void
 omemo_init(void)
 {
-    log_info("Initialising OMEMO");
+    log_info("OMEMO: initialising");
     signal_crypto_provider crypto_provider = {
         .random_func = omemo_random_func,
         .hmac_sha256_init_func = omemo_hmac_sha256_init_func,
@@ -155,6 +161,7 @@ omemo_init(void)
     loaded = FALSE;
     omemo_ctx.device_list = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)g_list_free);
     omemo_ctx.device_list_handler = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
+    omemo_ctx.known_devices = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)g_hash_table_free);
 }
 
 void
@@ -182,9 +189,9 @@ omemo_on_connect(ProfAccount *account)
     if (res == -1) {
         char *errmsg = strerror(errno);
         if (errmsg) {
-            log_error("Error creating directory: %s, %s", basedir->str, errmsg);
+            log_error("OMEMO: error creating directory: %s, %s", basedir->str, errmsg);
         } else {
-            log_error("Error creating directory: %s", basedir->str);
+            log_error("OMEMO: creating directory: %s", basedir->str);
         }
     }
 
@@ -270,9 +277,10 @@ omemo_generate_short_term_crypto_materials(ProfAccount *account)
 void
 omemo_start_session(const char *const barejid)
 {
-    log_info("Start OMEMO session with %s", barejid);
+    log_info("OMEMO: start session with %s", barejid);
     GList *device_list = g_hash_table_lookup(omemo_ctx.device_list, barejid);
     if (!device_list) {
+        log_info("OMEMO: missing device list for %s", barejid);
         omemo_devicelist_request(barejid);
         g_hash_table_insert(omemo_ctx.device_list_handler, strdup(barejid), handle_device_list_start_session);
         return;
@@ -393,7 +401,7 @@ omemo_identity_keyfile_save(void)
     GError *error = NULL;
 
     if (!g_key_file_save_to_file(omemo_ctx.identity_keyfile, omemo_ctx.identity_filename->str, &error)) {
-        log_error("Error saving OMEMO identity to: %s, %s", omemo_ctx.identity_filename->str, error->message);
+        log_error("OMEMO: error saving identity to: %s, %s", omemo_ctx.identity_filename->str, error->message);
     }
 }
 
@@ -409,7 +417,7 @@ omemo_sessions_keyfile_save(void)
     GError *error = NULL;
 
     if (!g_key_file_save_to_file(omemo_ctx.sessions_keyfile, omemo_ctx.sessions_filename->str, &error)) {
-        log_error("Error saving OMEMO sessions to: %s, %s", omemo_ctx.sessions_filename->str, error->message);
+        log_error("OMEMO: error saving sessions to: %s, %s", omemo_ctx.sessions_filename->str, error->message);
     }
 }
 
@@ -426,8 +434,26 @@ omemo_start_device_session(const char *const jid, uint32_t device_id,
         .device_id = device_id,
     };
 
+    ec_public_key *identity_key;
+    curve_decode_point(&identity_key, identity_key_raw, identity_key_len, omemo_ctx.signal);
+    cache_device_identity(jid, device_id, identity_key);
+
+    gboolean trusted = is_trusted_identity(&address, (uint8_t *)identity_key_raw, identity_key_len, &omemo_ctx.identity_key_store);
+
+    ProfChatWin *chatwin = wins_get_chat(jid);
+    if (chatwin) {
+        char *fingerprint = omemo_fingerprint(identity_key, TRUE);
+
+        win_println((ProfWin *)chatwin, THEME_DEFAULT, '-', "Available device identity: %s%s", fingerprint, trusted ? " (trusted)" : "");
+        free(fingerprint);
+    }
+
+    if (!trusted) {
+        goto out;
+    }
+
     if (!contains_session(&address, omemo_ctx.session_store)) {
-        log_info("Create OMEMO session with %s device %d", jid, device_id);
+        int res;
         session_pre_key_bundle *bundle;
         signal_protocol_address *address;
 
@@ -437,7 +463,11 @@ omemo_start_device_session(const char *const jid, uint32_t device_id,
         address->device_id = device_id;
 
         session_builder *builder;
-        session_builder_create(&builder, omemo_ctx.store, address, omemo_ctx.signal);
+        res = session_builder_create(&builder, omemo_ctx.store, address, omemo_ctx.signal);
+        if (res != 0) {
+            log_error("OMEMO: cannot create session builder for %s device %d", jid, device_id);
+            goto out;
+        }
 
         int prekey_index;
         gcry_randomize(&prekey_index, sizeof(int), GCRY_STRONG_RANDOM);
@@ -448,14 +478,24 @@ omemo_start_device_session(const char *const jid, uint32_t device_id,
         curve_decode_point(&prekey_public, prekey->data, prekey->length, omemo_ctx.signal);
         ec_public_key *signed_prekey;
         curve_decode_point(&signed_prekey, signed_prekey_raw, signed_prekey_len, omemo_ctx.signal);
-        ec_public_key *identity_key;
-        curve_decode_point(&identity_key, identity_key_raw, identity_key_len, omemo_ctx.signal);
 
-        session_pre_key_bundle_create(&bundle, 0, device_id, prekey->id, prekey_public, signed_prekey_id, signed_prekey, signature, signature_len, identity_key);
-        session_builder_process_pre_key_bundle(builder, bundle);
+        res = session_pre_key_bundle_create(&bundle, 0, device_id, prekey->id, prekey_public, signed_prekey_id, signed_prekey, signature, signature_len, identity_key);
+        if (res != 0) {
+            log_error("OMEMO: cannot create pre key bundle for %s device %d", jid, device_id);
+            goto out;
+        }
 
-        g_list_free_full(prekeys, (GDestroyNotify)free_omemo_key);
+        res = session_builder_process_pre_key_bundle(builder, bundle);
+        if (res != 0) {
+            log_error("OMEMO: cannot process pre key bundle for %s device %d", jid, device_id);
+            goto out;
+        }
+
+        log_info("OMEMO: create session with %s device %d", jid, device_id);
     }
+
+out:
+        g_list_free_full(prekeys, (GDestroyNotify)free_omemo_key);
 }
 
 gboolean
@@ -492,6 +532,7 @@ omemo_on_message_send(ProfChatWin *chatwin, const char *const message, gboolean
 
     res = aes128gcm_encrypt(ciphertext, &ciphertext_len, tag, &tag_len, (const unsigned char * const)message, strlen(message), iv, key);
     if (res != 0) {
+        log_error("OMEMO: cannot encrypt message");
         return FALSE;
     }
 
@@ -505,16 +546,20 @@ omemo_on_message_send(ProfChatWin *chatwin, const char *const message, gboolean
         ciphertext_message *ciphertext;
         session_cipher *cipher;
         signal_protocol_address address = {
-            chatwin->barejid, strlen(chatwin->barejid), GPOINTER_TO_INT(device_ids_iter->data)
+            .name = chatwin->barejid,
+            .name_len = strlen(chatwin->barejid),
+            .device_id = GPOINTER_TO_INT(device_ids_iter->data)
         };
 
         res = session_cipher_create(&cipher, omemo_ctx.store, &address, omemo_ctx.signal);
         if (res != 0) {
+            log_error("OMEMO: cannot create cipher for %s device id %d", address.name, address.device_id);
             continue;
         }
 
         res = session_cipher_encrypt(cipher, key_tag, AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH, &ciphertext);
         if (res != 0) {
+            log_error("OMEMO: cannot encrypt key for %s device id %d", address.name, address.device_id);
             continue;
         }
         signal_buffer *buffer = ciphertext_message_get_serialized(ciphertext);
@@ -531,16 +576,20 @@ omemo_on_message_send(ProfChatWin *chatwin, const char *const message, gboolean
         ciphertext_message *ciphertext;
         session_cipher *cipher;
         signal_protocol_address address = {
-            barejid, strlen(barejid), GPOINTER_TO_INT(device_ids_iter->data)
+            .name = barejid,
+            .name_len = strlen(barejid),
+            .device_id = GPOINTER_TO_INT(device_ids_iter->data)
         };
 
         res = session_cipher_create(&cipher, omemo_ctx.store, &address, omemo_ctx.signal);
         if (res != 0) {
+            log_error("OMEMO: cannot create cipher for %s device id %d", address.name, address.device_id);
             continue;
         }
 
         res = session_cipher_encrypt(cipher, key_tag, AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH, &ciphertext);
         if (res != 0) {
+            log_error("OMEMO: cannot encrypt key for %s device id %d", address.name, address.device_id);
             continue;
         }
         signal_buffer *buffer = ciphertext_message_get_serialized(ciphertext);
@@ -583,21 +632,26 @@ omemo_on_message_recv(const char *const from, uint32_t sid,
     }
 
     if (!key) {
+        log_warning("OMEMO: Received a message with no corresponding key");
         return NULL;
     }
 
     session_cipher *cipher;
     signal_buffer *plaintext_key;
     signal_protocol_address address = {
-        from, strlen(from), sid
+        .name = from,
+        .name_len = strlen(from),
+        .device_id = sid
     };
 
     res = session_cipher_create(&cipher, omemo_ctx.store, &address, omemo_ctx.signal);
     if (res != 0) {
+        log_error("OMEMO: cannot create session cipher");
         return NULL;
     }
 
     if (key->prekey) {
+        log_debug("OMEMO: decrypting message with prekey");
         pre_key_signal_message *message;
 
         pre_key_signal_message_deserialize(&message, key->data, key->length, omemo_ctx.signal);
@@ -618,11 +672,13 @@ omemo_on_message_recv(const char *const from, uint32_t sid,
         /* Try to decrypt message anyway, it will fail */
         res = session_cipher_decrypt_pre_key_signal_message(cipher, message, NULL, &plaintext_key);
     } else {
+        log_debug("OMEMO: decrypting message with existing session");
         signal_message *message;
         signal_message_deserialize(&message, key->data, key->length, omemo_ctx.signal);
         res = session_cipher_decrypt_signal_message(cipher, message, NULL, &plaintext_key);
     }
     if (res != 0) {
+        log_debug("OMEMO: cannot to decrypt message key");
         return NULL;
     }
 
@@ -647,13 +703,12 @@ omemo_on_message_recv(const char *const from, uint32_t sid,
     plaintext[plaintext_len] = '\0';
 
     return (char *)plaintext;
-
 }
 
 char *
 omemo_format_fingerprint(const char *const fingerprint)
 {
-    char *output = malloc(strlen(fingerprint) + strlen(fingerprint) / 8 + 1);
+    char *output = malloc(strlen(fingerprint) + strlen(fingerprint) / 8);
 
     int i, j;
     for (i = 0, j = 0; i < strlen(fingerprint); i++) {
@@ -663,42 +718,134 @@ omemo_format_fingerprint(const char *const fingerprint)
         output[j++] = fingerprint[i];
     }
 
-    output[strlen(fingerprint) + strlen(fingerprint) / 8] = '\0';
+    output[j] = '\0';
 
     return output;
 }
 
 char *
-omemo_own_fingerprint()
+omemo_own_fingerprint(gboolean formatted)
 {
-    signal_buffer *public = omemo_ctx.identity_key_store.public;
-    /* Skip first byte corresponding to signal base type */
-    return omemo_fingerprint(signal_buffer_data(public) + 1, signal_buffer_len(public) - 1);
+    ec_public_key *identity = ratchet_identity_key_pair_get_public(omemo_ctx.identity_key_pair);
+    return omemo_fingerprint(identity, formatted);
 }
 
-char *
-omemo_fingerprint(const unsigned char *const identity_key_public, size_t len)
+static char *
+omemo_fingerprint(ec_public_key *identity, gboolean formatted)
 {
     int i;
-    char *fingerprint = malloc(len * 2 + 1);
+    signal_buffer *identity_public_key;
+
+    ec_public_key_serialize(&identity_public_key, identity);
+    size_t identity_public_key_len = signal_buffer_len(identity_public_key);
+    unsigned char *identity_public_key_data = signal_buffer_data(identity_public_key);
+
+    /* Skip first byte corresponding to signal DJB_TYPE */
+    identity_public_key_len--;
+    identity_public_key_data = &identity_public_key_data[1];
 
-    for (i = 0; i < len; i++) {
-        fingerprint[i * 2] = (identity_key_public[i] & 0xf0) >> 4;
-        fingerprint[i * 2] += 0x30;
-        if (fingerprint[i * 2] > 0x39) {
+    char *fingerprint = malloc(identity_public_key_len * 2 + 1);
+
+    for (i = 0; i < identity_public_key_len; i++) {
+        fingerprint[i * 2] = (identity_public_key_data[i] & 0xf0) >> 4;
+        fingerprint[i * 2] += '0';
+        if (fingerprint[i * 2] > '9') {
             fingerprint[i * 2] += 0x27;
         }
 
-        fingerprint[(i * 2) + 1] = identity_key_public[i] & 0x0f;
-        fingerprint[(i * 2) + 1] += 0x30;
-        if (fingerprint[(i * 2) + 1] > 0x39) {
+        fingerprint[(i * 2) + 1] = identity_public_key_data[i] & 0x0f;
+        fingerprint[(i * 2) + 1] += '0';
+        if (fingerprint[(i * 2) + 1] > '9') {
             fingerprint[(i * 2) + 1] += 0x27;
         }
     }
 
-    fingerprint[len * 2] = '\0';
+    fingerprint[i * 2] = '\0';
+    signal_buffer_free(identity_public_key);
+
+    if (!formatted) {
+        return fingerprint;
+    } else {
+        char *formatted_fingerprint = omemo_format_fingerprint(fingerprint);
+        free(fingerprint);
+        return formatted_fingerprint;
+    }
+}
+
+static unsigned char *
+omemo_fingerprint_decode(const char *const fingerprint, size_t *len)
+{
+    unsigned char *output = malloc(strlen(fingerprint) / 2 + 1);
+
+    int i;
+    int j;
+    for (i = 0, j = 0; i < strlen(fingerprint);) {
+        if (!g_ascii_isxdigit(fingerprint[i])) {
+            i++;
+            continue;
+        }
+
+        output[j] = g_ascii_xdigit_value(fingerprint[i++]) << 4;
+        output[j] |= g_ascii_xdigit_value(fingerprint[i++]);
+        j++;
+    }
+
+    *len = j;
 
-    return fingerprint;
+    return output;
+}
+
+void
+omemo_trust(const char *const jid, const char *const fingerprint_formatted)
+{
+    size_t len;
+
+    GHashTable *known_identities = g_hash_table_lookup(omemo_ctx.known_devices, jid);
+    if (!known_identities) {
+        log_warning("OMEMO: cannot trust unknown device: %s", fingerprint_formatted);
+        cons_show("Cannot trust unknown device: %s", fingerprint_formatted);
+        return;
+    }
+
+    /* Unformat fingerprint */
+    char *fingerprint = malloc(strlen(fingerprint_formatted));
+    int i;
+    int j;
+    for (i = 0, j = 0; fingerprint_formatted[i] != '\0'; i++) {
+        if (!g_ascii_isxdigit(fingerprint_formatted[i])) {
+            continue;
+        }
+        fingerprint[j++] = fingerprint_formatted[i];
+    }
+
+    fingerprint[j] = '\0';
+
+    uint32_t device_id = GPOINTER_TO_INT(g_hash_table_lookup(known_identities, fingerprint));
+    free(fingerprint);
+
+    if (!device_id) {
+        log_warning("OMEMO: cannot trust unknown device: %s", fingerprint_formatted);
+        cons_show("Cannot trust unknown device: %s", fingerprint_formatted);
+        return;
+    }
+
+    /* TODO should not hardcode DJB_TYPE here
+     * should instead store identity key in known_identities along with
+     * device_id */
+    signal_protocol_address address = {
+        .name = jid,
+        .name_len = strlen(jid),
+        .device_id = device_id,
+    };
+    unsigned char *fingerprint_raw = omemo_fingerprint_decode(fingerprint_formatted, &len);
+    unsigned char djb_type[] = {'\x05'};
+    signal_buffer *buffer = signal_buffer_create(djb_type, 1);
+    buffer = signal_buffer_append(buffer, fingerprint_raw, len);
+    save_identity(&address, signal_buffer_data(buffer), signal_buffer_len(buffer), &omemo_ctx.identity_key_store);
+    free(fingerprint_raw);
+    signal_buffer_free(buffer);
+
+    omemo_bundle_request(jid, device_id, omemo_start_device_session_handle_bundle, free, strdup(jid));
 }
 
 static void
@@ -843,3 +990,24 @@ load_sessions(void)
         }
     }
 }
+
+static void
+cache_device_identity(const char *const jid, uint32_t device_id, ec_public_key *identity)
+{
+    GHashTable *known_identities = g_hash_table_lookup(omemo_ctx.known_devices, jid);
+    if (!known_identities) {
+        known_identities = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
+        g_hash_table_insert(omemo_ctx.known_devices, strdup(jid), known_identities);
+    }
+
+    char *fingerprint = omemo_fingerprint(identity, FALSE);
+    log_info("OMEMO: cache identity for %s:%d: %s", jid, device_id, fingerprint);
+    g_hash_table_insert(known_identities, fingerprint, GINT_TO_POINTER(device_id));
+}
+
+static void
+g_hash_table_free(GHashTable *hash_table)
+{
+    g_hash_table_remove_all(hash_table);
+    g_hash_table_unref(hash_table);
+}
diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h
index 72d3d3aa..5be0e0cd 100644
--- a/src/omemo/omemo.h
+++ b/src/omemo/omemo.h
@@ -30,9 +30,9 @@ GKeyFile *omemo_identity_keyfile(void);
 void omemo_identity_keyfile_save(void);
 GKeyFile *omemo_sessions_keyfile(void);
 void omemo_sessions_keyfile_save(void);
-char *omemo_fingerprint(const unsigned char *const identity_key_public, size_t len);
 char *omemo_format_fingerprint(const char *const fingerprint);
-char *omemo_own_fingerprint();
+char *omemo_own_fingerprint(gboolean formatted);
+void omemo_trust(const char *const jid, const char *const fingerprint);
 
 void omemo_start_session(const char *const barejid);
 void omemo_start_device_session(const char *const jid, uint32_t device_id, GList *prekeys, uint32_t signed_prekey_id, const unsigned char *const signed_prekey, size_t signed_prekey_len, const unsigned char *const signature, size_t signature_len, const unsigned char *const identity_key, size_t identity_key_len);