about summary refs log tree commit diff stats
path: root/src/omemo/omemo.c
diff options
context:
space:
mode:
authorPaul Fariello <paul@fariello.eu>2019-03-07 08:00:29 +0140
committerPaul Fariello <paul@fariello.eu>2019-04-10 16:31:45 +0200
commit55407ee15f0ebdf93c076ae5ea28ec865497b121 (patch)
tree01057228ff99f86bbca8c7c929f88b273acc3554 /src/omemo/omemo.c
parent5eb66aea267c53c63af6dd76fe2555f113051fcd (diff)
downloadprofani-tty-55407ee15f0ebdf93c076ae5ea28ec865497b121.tar.gz
Add OMEMO session long term storage
Diffstat (limited to 'src/omemo/omemo.c')
-rw-r--r--src/omemo/omemo.c115
1 files changed, 85 insertions, 30 deletions
diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c
index 169623f4..3a771b6b 100644
--- a/src/omemo/omemo.c
+++ b/src/omemo/omemo.c
@@ -52,6 +52,8 @@ struct omemo_context_t {
     GHashTable *device_ids;
     GString *identity_filename;
     GKeyFile *identity_keyfile;
+    GString *sessions_filename;
+    GKeyFile *sessions_keyfile;
 };
 
 static omemo_context omemo_ctx;
@@ -169,15 +171,18 @@ omemo_on_connect(ProfAccount *account)
 
     omemo_ctx.identity_filename = g_string_new(basedir->str);
     g_string_append(omemo_ctx.identity_filename, "identity.txt");
+    omemo_ctx.sessions_filename = g_string_new(basedir->str);
+    g_string_append(omemo_ctx.sessions_filename, "sessions.txt");
+
 
     errno = 0;
     int res = g_mkdir_with_parents(basedir->str, S_IRWXU);
     if (res == -1) {
         char *errmsg = strerror(errno);
         if (errmsg) {
-            log_error("Error creating directory: %s, %s", omemo_ctx.identity_filename->str, errmsg);
+            log_error("Error creating directory: %s, %s", basedir->str, errmsg);
         } else {
-            log_error("Error creating directory: %s", omemo_ctx.identity_filename->str);
+            log_error("Error creating directory: %s", basedir->str);
         }
     }
 
@@ -208,6 +213,32 @@ omemo_on_connect(ProfAccount *account)
 
         omemo_generate_short_term_crypto_materials(account);
     }
+
+    omemo_ctx.sessions_keyfile = g_key_file_new();
+    if (g_key_file_load_from_file(omemo_ctx.sessions_keyfile, omemo_ctx.sessions_filename->str, G_KEY_FILE_KEEP_COMMENTS, NULL)) {
+        int i;
+        char **groups = g_key_file_get_groups(omemo_ctx.sessions_keyfile, NULL);
+        for (i = 0; groups[i] != NULL; i++) {
+            int j;
+            GHashTable *device_store = NULL;
+
+            device_store = g_hash_table_lookup(omemo_ctx.session_store, groups[i]);
+            if (!device_store) {
+                device_store = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)signal_buffer_free);
+                g_hash_table_insert(omemo_ctx.session_store, groups[i], device_store);
+            }
+
+            char **keys = g_key_file_get_keys(omemo_ctx.sessions_keyfile, groups[i], NULL, NULL);
+            for (j = 0; keys[j] != NULL; j++) {
+                uint32_t id = strtoul(keys[j], NULL, 10);
+                char *record_b64 = g_key_file_get_string(omemo_ctx.sessions_keyfile, groups[i], keys[j], NULL);
+                size_t record_len;
+                unsigned char *record = g_base64_decode(record_b64, &record_len);
+                signal_buffer *buffer = signal_buffer_create(record, record_len);
+                g_hash_table_insert(device_store, GINT_TO_POINTER(id), buffer);
+            }
+        }
+    }
 }
 
 void
@@ -395,6 +426,22 @@ omemo_set_device_list(const char *const jid, GList * device_list)
     free(barejid);
 }
 
+GKeyFile *
+omemo_sessions_keyfile(void)
+{
+    return omemo_ctx.sessions_keyfile;
+}
+
+void
+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);
+    }
+}
+
 void
 omemo_start_device_session(const char *const jid, uint32_t device_id,
     GList *prekeys, uint32_t signed_prekey_id,
@@ -402,34 +449,42 @@ omemo_start_device_session(const char *const jid, uint32_t device_id,
     const unsigned char *const signature, size_t signature_len,
     const unsigned char *const identity_key_raw, size_t identity_key_len)
 {
-    log_info("Start OMEMO session with %s device %d", jid, device_id);
-    session_pre_key_bundle *bundle;
-    signal_protocol_address *address;
-
-    address = malloc(sizeof(signal_protocol_address));
-    address->name = strdup(jid);
-    address->name_len = strlen(jid);
-    address->device_id = device_id;
-
-    session_builder *builder;
-    session_builder_create(&builder, omemo_ctx.store, address, omemo_ctx.signal);
-
-    int prekey_index;
-    gcry_randomize(&prekey_index, sizeof(int), GCRY_STRONG_RANDOM);
-    prekey_index %= g_list_length(prekeys);
-    omemo_key_t *prekey = g_list_nth_data(prekeys, prekey_index);
-
-    ec_public_key *prekey_public;
-    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);
-
-    g_list_free_full(prekeys, (GDestroyNotify)free_omemo_key);
+    signal_protocol_address address = {
+        .name = strdup(jid),
+        .name_len = strlen(jid),
+        .device_id = device_id,
+    };
+
+    if (!contains_session(&address, omemo_ctx.session_store)) {
+        log_info("Create OMEMO session with %s device %d", jid, device_id);
+        session_pre_key_bundle *bundle;
+        signal_protocol_address *address;
+
+        address = malloc(sizeof(signal_protocol_address));
+        address->name = strdup(jid);
+        address->name_len = strlen(jid);
+        address->device_id = device_id;
+
+        session_builder *builder;
+        session_builder_create(&builder, omemo_ctx.store, address, omemo_ctx.signal);
+
+        int prekey_index;
+        gcry_randomize(&prekey_index, sizeof(int), GCRY_STRONG_RANDOM);
+        prekey_index %= g_list_length(prekeys);
+        omemo_key_t *prekey = g_list_nth_data(prekeys, prekey_index);
+
+        ec_public_key *prekey_public;
+        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);
+
+        g_list_free_full(prekeys, (GDestroyNotify)free_omemo_key);
+    }
 }
 
 gboolean