1
0
mirror of https://github.com/profanity-im/profanity.git synced 2024-11-03 19:37:16 -05:00

Add support for sending encrypted message in MUC

This commit is contained in:
Paul Fariello 2019-03-18 07:11:19 +01:40
parent f7ce1607f9
commit a9d55dec92
5 changed files with 123 additions and 55 deletions

View File

@ -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

View File

@ -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 *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);
continue;
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);
}
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);
} else {
ProfChatWin *chatwin = (ProfChatWin *)win;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
recipients = g_list_append(recipients, strdup(chatwin->barejid));
}
GList *device_ids_iter;
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;
}
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);
}
}
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);

View File

@ -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);

View File

@ -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");

View File

@ -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);