about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorPaul Fariello <paul@fariello.eu>2019-03-18 07:11:19 +0140
committerPaul Fariello <paul@fariello.eu>2019-04-10 17:12:31 +0200
commita9d55dec9275c472d7eea2ff79304eda1aefd3be (patch)
tree3b648f1756b402fc7768b8a62f84587f4a6f99a8
parentf7ce1607f96f527b5c22e89510ab5185a200800d (diff)
downloadprofani-tty-a9d55dec9275c472d7eea2ff79304eda1aefd3be.tar.gz
Add support for sending encrypted message in MUC
-rw-r--r--src/event/client_events.c23
-rw-r--r--src/omemo/omemo.c127
-rw-r--r--src/omemo/omemo.h2
-rw-r--r--src/xmpp/message.c14
-rw-r--r--src/xmpp/xmpp.h2
5 files changed, 118 insertions, 50 deletions
diff --git a/src/event/client_events.c b/src/event/client_events.c
index 79ed88f6..1488174a 100644
--- a/src/event/client_events.c
+++ b/src/event/client_events.c
@@ -218,7 +218,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo
 #ifndef HAVE_LIBGPGME
 #ifdef HAVE_OMEMO
     if (chatwin->is_omemo) {
-        omemo_on_message_send(chatwin, plugin_msg, request_receipt);
+        omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE);
     } else {
         char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt);
         chat_log_msg_out(chatwin->barejid, plugin_msg);
@@ -238,7 +238,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo
 #ifndef HAVE_LIBGPGME
 #ifdef HAVE_OMEMO
     if (chatwin->is_omemo) {
-        omemo_on_message_send(chatwin, plugin_msg, request_receipt);
+        omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE);
     } else {
         gboolean handled = otr_on_message_send(chatwin, plugin_msg, request_receipt);
         if (!handled) {
@@ -261,7 +261,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo
 #ifdef HAVE_LIBGPGME
 #ifdef HAVE_OMEMO
     if (chatwin->is_omemo) {
-        omemo_on_message_send(chatwin, plugin_msg, request_receipt);
+        omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE);
     } else if (chatwin->pgp_send) {
         char *id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt);
         chat_log_pgp_msg_out(chatwin->barejid, plugin_msg);
@@ -286,7 +286,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo
 #ifdef HAVE_LIBGPGME
 #ifdef HAVE_OMEMO
     if (chatwin->is_omemo) {
-        omemo_on_message_send(chatwin, plugin_msg, request_receipt);
+        omemo_on_message_send((ProfWin *)chatwin, plugin_msg, request_receipt, FALSE);
     } else if (chatwin->pgp_send) {
         char *id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt);
         chat_log_pgp_msg_out(chatwin->barejid, plugin_msg);
@@ -334,10 +334,25 @@ cl_ev_send_muc_msg(ProfMucWin *mucwin, const char *const msg, const char *const
         return;
     }
 
+#ifdef HAVE_OMEMO
+    if (mucwin->is_omemo) {
+        omemo_on_message_send((ProfWin *)mucwin, plugin_msg, FALSE, TRUE);
+    } else {
+        message_send_groupchat(mucwin->roomjid, plugin_msg, oob_url);
+    }
+
+    plugins_post_room_message_send(mucwin->roomjid, plugin_msg);
+    free(plugin_msg);
+    return;
+#endif
+
+#ifndef HAVE_OMEMO
     message_send_groupchat(mucwin->roomjid, plugin_msg, oob_url);
 
     plugins_post_room_message_send(mucwin->roomjid, plugin_msg);
     free(plugin_msg);
+    return;
+#endif
 }
 
 void
diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c
index f7a305ee..3fb52b08 100644
--- a/src/omemo/omemo.c
+++ b/src/omemo/omemo.c
@@ -1,6 +1,7 @@
 #include <sys/time.h>
 #include <sys/stat.h>
 
+#include <assert.h>
 #include <errno.h>
 #include <glib.h>
 #include <pthread.h>
@@ -168,6 +169,7 @@ omemo_init(void)
 void
 omemo_on_connect(ProfAccount *account)
 {
+    GError *error = NULL;
     char *omemodir = files_get_data_path(DIR_OMEMO);
     GString *basedir = g_string_new(omemodir);
     free(omemodir);
@@ -194,18 +196,26 @@ omemo_on_connect(ProfAccount *account)
         }
     }
 
+    omemo_devicelist_subscribe();
+
     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.sessions_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, &error)) {
         load_identity();
         omemo_generate_short_term_crypto_materials(account);
+    } else if (error->code != G_FILE_ERROR_NOENT) {
+        log_warning("OMEMO: error loading identity from: %s, %s", omemo_ctx.identity_filename->str, error->message);
+        return;
     }
 
-    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)) {
+    error = NULL;
+    if (g_key_file_load_from_file(omemo_ctx.sessions_keyfile, omemo_ctx.sessions_filename->str, G_KEY_FILE_KEEP_COMMENTS, &error)) {
         load_sessions();
+    } else if (error->code != G_FILE_ERROR_NOENT) {
+        log_warning("OMEMO: error loading sessions from: %s, %s", omemo_ctx.sessions_filename->str, error->message);
     }
 
-    omemo_devicelist_subscribe();
 }
 
 void
@@ -533,22 +543,15 @@ out:
 }
 
 gboolean
-omemo_on_message_send(ProfChatWin *chatwin, const char *const message, gboolean request_receipt)
+omemo_on_message_send(ProfWin *win, const char *const message, gboolean request_receipt, gboolean muc)
 {
     int res;
     gboolean ret = FALSE;
     Jid *jid = jid_create(connection_get_fulljid());
     GList *keys = NULL;
 
-    GList *recipient_device_id = g_hash_table_lookup(omemo_ctx.device_list, chatwin->barejid);
-    if (!recipient_device_id) {
-        goto out;
-    }
-
     GList *sender_device_id = g_hash_table_lookup(omemo_ctx.device_list, jid->barejid);
 
-    /* TODO generate fresh AES-GCM materials */
-    /* TODO encrypt message */
     unsigned char *key;
     unsigned char *iv;
     unsigned char *ciphertext;
@@ -574,37 +577,72 @@ omemo_on_message_send(ProfChatWin *chatwin, const char *const message, gboolean
     memcpy(key_tag, key, AES128_GCM_KEY_LENGTH);
     memcpy(key_tag + AES128_GCM_KEY_LENGTH, tag, AES128_GCM_TAG_LENGTH);
 
+    GList *recipients = NULL;
+    if (muc) {
+        ProfMucWin *mucwin = (ProfMucWin *)win;
+        assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
+        GList *roster = muc_roster(mucwin->roomjid);
+        GList *iter;
+        for (iter = roster; iter != NULL; iter = iter->next) {
+            Occupant *occupant = (Occupant *)iter->data;
+            Jid *jid = jid_create(occupant->jid);
+            if (!jid->barejid) {
+                log_warning("OMEMO: missing barejid for MUC %s occupant %s", mucwin->roomjid, occupant->nick);
+            } else {
+                recipients = g_list_append(recipients, strdup(jid->barejid));
+            }
+            jid_destroy(jid);
+        }
+    } else {
+        ProfChatWin *chatwin = (ProfChatWin *)win;
+        assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
+        recipients = g_list_append(recipients, strdup(chatwin->barejid));
+    }
+
     GList *device_ids_iter;
-    for (device_ids_iter = recipient_device_id; device_ids_iter != NULL; device_ids_iter = device_ids_iter->next) {
-        int res;
-        ciphertext_message *ciphertext;
-        session_cipher *cipher;
-        signal_protocol_address address = {
-            .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);
+    GList *recipients_iter;
+    for (recipients_iter = recipients; recipients_iter != NULL; recipients_iter = recipients_iter->next) {
+        GList *recipient_device_id = NULL;
+        recipient_device_id = g_hash_table_lookup(omemo_ctx.device_list, recipients_iter->data);
+        if (!recipient_device_id) {
+            log_warning("OMEMO: cannot find device ids for %s", recipients_iter->data);
             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;
+        for (device_ids_iter = recipient_device_id; device_ids_iter != NULL; device_ids_iter = device_ids_iter->next) {
+            int res;
+            ciphertext_message *ciphertext;
+            session_cipher *cipher;
+            signal_protocol_address address = {
+                .name = recipients_iter->data,
+                .name_len = strlen(recipients_iter->data),
+                .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);
+            omemo_key_t *key = malloc(sizeof(omemo_key_t));
+            key->data = signal_buffer_data(buffer);
+            key->length = signal_buffer_len(buffer);
+            key->device_id = GPOINTER_TO_INT(device_ids_iter->data);
+            key->prekey = ciphertext_message_get_type(ciphertext) == CIPHERTEXT_PREKEY_TYPE;
+            keys = g_list_append(keys, key);
         }
-        signal_buffer *buffer = ciphertext_message_get_serialized(ciphertext);
-        omemo_key_t *key = malloc(sizeof(omemo_key_t));
-        key->data = signal_buffer_data(buffer);
-        key->length = signal_buffer_len(buffer);
-        key->device_id = GPOINTER_TO_INT(device_ids_iter->data);
-        key->prekey = ciphertext_message_get_type(ciphertext) == CIPHERTEXT_PREKEY_TYPE;
-        keys = g_list_append(keys, key);
     }
 
+    g_list_free_full(recipients, free);
+
     for (device_ids_iter = sender_device_id; device_ids_iter != NULL; device_ids_iter = device_ids_iter->next) {
         int res;
         ciphertext_message *ciphertext;
@@ -635,14 +673,23 @@ omemo_on_message_send(ProfChatWin *chatwin, const char *const message, gboolean
         keys = g_list_append(keys, key);
     }
 
-    char *id = message_send_chat_omemo(chatwin->barejid, omemo_ctx.device_id, keys, iv, AES128_GCM_IV_LENGTH, ciphertext, ciphertext_len, request_receipt);
-    chat_log_omemo_msg_out(chatwin->barejid, message);
-    chatwin_outgoing_msg(chatwin, message, id, PROF_MSG_OMEMO, request_receipt);
+    if (muc) {
+        ProfMucWin *mucwin = (ProfMucWin *)win;
+        assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
+        char *id = message_send_chat_omemo(mucwin->roomjid, omemo_ctx.device_id, keys, iv, AES128_GCM_IV_LENGTH, ciphertext, ciphertext_len, request_receipt, TRUE);
+        free(id);
+    } else {
+        ProfChatWin *chatwin = (ProfChatWin *)win;
+        assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
+        char *id = message_send_chat_omemo(chatwin->barejid, omemo_ctx.device_id, keys, iv, AES128_GCM_IV_LENGTH, ciphertext, ciphertext_len, request_receipt, FALSE);
+        chat_log_omemo_msg_out(chatwin->barejid, message);
+        chatwin_outgoing_msg(chatwin, message, id, PROF_MSG_OMEMO, request_receipt);
+        free(id);
+    }
     ret = TRUE;
 
 out:
     jid_destroy(jid);
-    free(id);
     g_list_free_full(keys, free);
     free(ciphertext);
     gcry_free(key);
@@ -659,7 +706,7 @@ omemo_on_message_recv(const char *const from_jid, uint32_t sid,
     const unsigned char *const payload, size_t payload_len, gboolean muc)
 {
     unsigned char *plaintext = NULL;
-    Jid *sender;
+    Jid *sender = NULL;
     Jid *from = jid_create(from_jid);
     if (!from) {
         log_error("Invalid jid %s", from_jid);
diff --git a/src/omemo/omemo.h b/src/omemo/omemo.h
index b56b50a5..a8af1a66 100644
--- a/src/omemo/omemo.h
+++ b/src/omemo/omemo.h
@@ -40,5 +40,5 @@ void omemo_start_muc_sessions(const char *const roomjid);
 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);
 
 gboolean omemo_loaded(void);
-gboolean omemo_on_message_send(ProfChatWin *chatwin, const char *const message, gboolean request_receipt);
+gboolean omemo_on_message_send(ProfWin *win, const char *const message, gboolean request_receipt, gboolean muc);
 char * omemo_on_message_recv(const char *const from, uint32_t sid, const unsigned char *const iv, size_t iv_len, GList *keys, const unsigned char *const payload, size_t payload_len, gboolean muc);
diff --git a/src/xmpp/message.c b/src/xmpp/message.c
index 8fbaedd9..47a21438 100644
--- a/src/xmpp/message.c
+++ b/src/xmpp/message.c
@@ -318,13 +318,19 @@ char*
 message_send_chat_omemo(const char *const jid, uint32_t sid, GList *keys,
     const unsigned char *const iv, size_t iv_len,
     const unsigned char *const ciphertext, size_t ciphertext_len,
-    gboolean request_receipt)
+    gboolean request_receipt, gboolean muc)
 {
     char *state = chat_session_get_state(jid);
     xmpp_ctx_t * const ctx = connection_get_ctx();
-    char *id = connection_create_stanza_id("msg");
-
-    xmpp_stanza_t *message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id);
+    char *id;
+    xmpp_stanza_t *message;
+    if (muc) {
+        id = connection_create_stanza_id("muc");
+        message = xmpp_message_new(ctx, STANZA_TYPE_GROUPCHAT, jid, id);
+    } else {
+        id = connection_create_stanza_id("msg");
+        message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id);
+    }
 
     xmpp_stanza_t *encrypted = xmpp_stanza_new(ctx);
     xmpp_stanza_set_name(encrypted, "encrypted");
diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h
index f2eec6c7..6675369a 100644
--- a/src/xmpp/xmpp.h
+++ b/src/xmpp/xmpp.h
@@ -140,7 +140,7 @@ char* message_send_chat(const char *const barejid, const char *const msg, const
     gboolean request_receipt);
 char* message_send_chat_otr(const char *const barejid, const char *const msg, gboolean request_receipt);
 char* message_send_chat_pgp(const char *const barejid, const char *const msg, gboolean request_receipt);
-char* message_send_chat_omemo(const char *const jid, uint32_t sid, GList *keys, const unsigned char *const iv, size_t iv_len, const unsigned char *const ciphertext, size_t ciphertext_len, gboolean request_receipt);
+char* message_send_chat_omemo(const char *const jid, uint32_t sid, GList *keys, const unsigned char *const iv, size_t iv_len, const unsigned char *const ciphertext, size_t ciphertext_len, gboolean request_receipt, gboolean muc);
 void message_send_private(const char *const fulljid, const char *const msg, const char *const oob_url);
 void message_send_groupchat(const char *const roomjid, const char *const msg, const char *const oob_url);
 void message_send_groupchat_subject(const char *const roomjid, const char *const subject);