about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorPaul Fariello <paul@fariello.eu>2019-03-01 19:21:20 +0140
committerPaul Fariello <paul@fariello.eu>2019-04-10 16:31:39 +0200
commit421d1b15608d21e693c97b77cacf6e2db74d5abd (patch)
treedd83d879b816b0334e7c00fb8f90dc7509e7b6d2
parent810ea3222319e349bfc149fd85be470247b66c96 (diff)
downloadprofani-tty-421d1b15608d21e693c97b77cacf6e2db74d5abd.tar.gz
Add OMEMO identity materials long term storage
-rw-r--r--src/config/files.h1
-rw-r--r--src/event/server_events.c8
-rw-r--r--src/omemo/omemo.c97
-rw-r--r--src/omemo/omemo.h1
-rw-r--r--src/omemo/store.h6
5 files changed, 109 insertions, 4 deletions
diff --git a/src/config/files.h b/src/config/files.h
index 1d8d2890..f7dfa29a 100644
--- a/src/config/files.h
+++ b/src/config/files.h
@@ -50,6 +50,7 @@
 #define DIR_CHATLOGS "chatlogs"
 #define DIR_OTR "otr"
 #define DIR_PGP "pgp"
+#define DIR_OMEMO "omemo"
 #define DIR_PLUGINS "plugins"
 
 void files_create_directories(void);
diff --git a/src/event/server_events.c b/src/event/server_events.c
index ccb57213..b8ee36cf 100644
--- a/src/event/server_events.c
+++ b/src/event/server_events.c
@@ -59,6 +59,10 @@
 #include "pgp/gpg.h"
 #endif
 
+#ifdef HAVE_OMEMO
+#include "omemo/omemo.h"
+#endif
+
 #include "ui/ui.h"
 
 void
@@ -76,6 +80,10 @@ sv_ev_login_account_success(char *account_name, gboolean secured)
     p_gpg_on_connect(account->jid);
 #endif
 
+#ifdef HAVE_OMEMO
+    omemo_on_connect(account);
+#endif
+
     ui_handle_login_account_success(account, secured);
 
     // attempt to rejoin rooms with passwords
diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c
index a9860851..8b052d4e 100644
--- a/src/omemo/omemo.c
+++ b/src/omemo/omemo.c
@@ -1,5 +1,7 @@
 #include <sys/time.h>
+#include <sys/stat.h>
 
+#include <errno.h>
 #include <glib.h>
 #include <pthread.h>
 #include <signal/key_helper.h>
@@ -18,9 +20,11 @@
 #include "xmpp/xmpp.h"
 #include "xmpp/connection.h"
 #include "xmpp/omemo.h"
+#include "config/files.h"
 
 static gboolean loaded;
 
+static void omemo_generate_short_term_crypto_materials(ProfAccount *account);
 static void lock(void *user_data);
 static void unlock(void *user_data);
 static void omemo_log(int level, const char *message, size_t len, void *user_data);
@@ -41,6 +45,8 @@ struct omemo_context_t {
     GHashTable *signed_pre_key_store;
     identity_key_store_t identity_key_store;
     GHashTable *device_ids;
+    GString *identity_filename;
+    GKeyFile *identity_keyfile;
 };
 
 static omemo_context omemo_ctx;
@@ -142,15 +148,98 @@ omemo_init(void)
 }
 
 void
-omemo_generate_crypto_materials(ProfAccount *account)
+omemo_on_connect(ProfAccount *account)
 {
     xmpp_ctx_t * const ctx = connection_get_ctx();
     char *barejid = xmpp_jid_bare(ctx, session_get_account_name());
+    char *omemodir = files_get_data_path(DIR_OMEMO);
+    GString *basedir = g_string_new(omemodir);
+    free(omemodir);
+    gchar *account_dir = str_replace(barejid, "@", "_at_");
+    g_string_append(basedir, "/");
+    g_string_append(basedir, account_dir);
+    g_string_append(basedir, "/");
+    free(account_dir);
+
+    omemo_ctx.identity_filename = g_string_new(basedir->str);
+    g_string_append(omemo_ctx.identity_filename, "identity.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);
+        } else {
+            log_error("Error creating directory: %s", omemo_ctx.identity_filename->str);
+        }
+    }
+
+    omemo_ctx.identity_keyfile = g_key_file_new();
+    if (g_key_file_load_from_file(omemo_ctx.identity_keyfile, omemo_ctx.identity_filename->str, G_KEY_FILE_KEEP_COMMENTS, NULL)) {
+        omemo_ctx.device_id = g_key_file_get_uint64(omemo_ctx.identity_keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_DEVICE_ID, NULL);
+        omemo_ctx.registration_id = g_key_file_get_uint64(omemo_ctx.identity_keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_REGISTRATION_ID, NULL);
+
+        char *identity_key_public_b64 = g_key_file_get_string(omemo_ctx.identity_keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_IDENTITY_KEY_PUBLIC, NULL);
+        size_t identity_key_public_len;
+        unsigned char *identity_key_public = g_base64_decode(identity_key_public_b64, &identity_key_public_len);
+        omemo_ctx.identity_key_store.public = signal_buffer_create(identity_key_public, identity_key_public_len);
+
+        char *identity_key_private_b64 = g_key_file_get_string(omemo_ctx.identity_keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_IDENTITY_KEY_PRIVATE, NULL);
+        size_t identity_key_private_len;
+        unsigned char *identity_key_private = g_base64_decode(identity_key_private_b64, &identity_key_private_len);
+        omemo_ctx.identity_key_store.private = signal_buffer_create(identity_key_private, identity_key_private_len);
+        signal_buffer_create(identity_key_private, identity_key_private_len);
+
+        ec_public_key *public_key;
+        curve_decode_point(&public_key, identity_key_public, identity_key_public_len, omemo_ctx.signal);
+        ec_private_key *private_key;
+        curve_decode_private_point(&private_key, identity_key_private, identity_key_private_len, omemo_ctx.signal);
+        ratchet_identity_key_pair_create(&omemo_ctx.identity_key_pair, public_key, private_key);
+
+        g_free(identity_key_public);
+        g_free(identity_key_private);
+
+        omemo_generate_short_term_crypto_materials(account);
+    }
+}
+
+void
+omemo_generate_crypto_materials(ProfAccount *account)
+{
+    GError *error = NULL;
+
+    if (loaded) {
+        return;
+    }
 
     omemo_ctx.device_id = randombytes_uniform(0x80000000);
 
     signal_protocol_key_helper_generate_identity_key_pair(&omemo_ctx.identity_key_pair, omemo_ctx.signal);
     signal_protocol_key_helper_generate_registration_id(&omemo_ctx.registration_id, 0, omemo_ctx.signal);
+
+    ec_public_key_serialize(&omemo_ctx.identity_key_store.public, ratchet_identity_key_pair_get_public(omemo_ctx.identity_key_pair));
+    ec_private_key_serialize(&omemo_ctx.identity_key_store.private, ratchet_identity_key_pair_get_private(omemo_ctx.identity_key_pair));
+
+    g_key_file_set_uint64(omemo_ctx.identity_keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_DEVICE_ID, omemo_ctx.device_id);
+    g_key_file_set_uint64(omemo_ctx.identity_keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_REGISTRATION_ID, omemo_ctx.registration_id);
+    char *identity_key_public = g_base64_encode(signal_buffer_data(omemo_ctx.identity_key_store.public), signal_buffer_len(omemo_ctx.identity_key_store.public));
+    g_key_file_set_string(omemo_ctx.identity_keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_IDENTITY_KEY_PUBLIC, identity_key_public);
+    g_free(identity_key_public);
+    char *identity_key_private = g_base64_encode(signal_buffer_data(omemo_ctx.identity_key_store.private), signal_buffer_len(omemo_ctx.identity_key_store.private));
+    g_key_file_set_string(omemo_ctx.identity_keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_IDENTITY_KEY_PRIVATE, identity_key_private);
+    g_free(identity_key_private);
+
+    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);
+    }
+
+    omemo_generate_short_term_crypto_materials(account);
+}
+
+static void
+omemo_generate_short_term_crypto_materials(ProfAccount *account)
+{
     signal_protocol_key_helper_generate_pre_keys(&omemo_ctx.pre_keys_head, randombytes_random(), 100, omemo_ctx.signal);
 
     struct timeval tv;
@@ -158,14 +247,14 @@ omemo_generate_crypto_materials(ProfAccount *account)
     unsigned long long timestamp = (unsigned long long)(tv.tv_sec) * 1000 + (unsigned long long)(tv.tv_usec) / 1000;
     signal_protocol_key_helper_generate_signed_pre_key(&omemo_ctx.signed_pre_key, omemo_ctx.identity_key_pair, 5, timestamp, omemo_ctx.signal);
 
-    ec_public_key_serialize(&omemo_ctx.identity_key_store.public, ratchet_identity_key_pair_get_public(omemo_ctx.identity_key_pair));
-    ec_private_key_serialize(&omemo_ctx.identity_key_store.private, ratchet_identity_key_pair_get_private(omemo_ctx.identity_key_pair));
-
     loaded = TRUE;
 
     /* Ensure we get our current device list, and it gets updated with our
      * device_id */
+    xmpp_ctx_t * const ctx = connection_get_ctx();
+    char *barejid = xmpp_jid_bare(ctx, session_get_account_name());
     omemo_devicelist_request(barejid);
+
     omemo_bundle_publish();
 }
 
diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h
index eb9569a3..cffc63f1 100644
--- a/src/omemo/omemo.h
+++ b/src/omemo/omemo.h
@@ -15,6 +15,7 @@ typedef struct omemo_key {
 } omemo_key_t;
 
 void omemo_init(void);
+void omemo_on_connect(ProfAccount *account);
 void omemo_generate_crypto_materials(ProfAccount *account);
 
 uint32_t omemo_device_id(void);
diff --git a/src/omemo/store.h b/src/omemo/store.h
index e99c514b..491e1495 100644
--- a/src/omemo/store.h
+++ b/src/omemo/store.h
@@ -1,5 +1,11 @@
 #include <signal/signal_protocol.h>
 
+#define OMEMO_STORE_GROUP_IDENTITY "identity"
+#define OMEMO_STORE_KEY_DEVICE_ID "device_id"
+#define OMEMO_STORE_KEY_REGISTRATION_ID "registration_id"
+#define OMEMO_STORE_KEY_IDENTITY_KEY_PUBLIC "identity_key_public"
+#define OMEMO_STORE_KEY_IDENTITY_KEY_PRIVATE "identity_key_private"
+
 typedef struct {
    signal_buffer *public;
    signal_buffer *private;