1
0
mirror of https://github.com/profanity-im/profanity.git synced 2024-12-04 14:46:46 -05:00
profanity/src/omemo/omemo.c

1898 lines
66 KiB
C
Raw Normal View History

2019-06-17 04:47:56 -04:00
/*
* omemo.c
2019-11-13 06:11:05 -05:00
* vim: expandtab:ts=4:sts=4:sw=4
2019-06-17 04:47:56 -04:00
*
* Copyright (C) 2019 Paul Fariello <paul@fariello.eu>
2021-01-08 10:36:30 -05:00
* Copyright (C) 2019 - 2021 Michael Vetter <jubalh@iodoru.org>
2019-06-17 04:47:56 -04:00
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
*/
#include "config.h"
#include <sys/time.h>
#include <sys/stat.h>
2019-02-21 13:04:01 -05:00
#include <assert.h>
#include <errno.h>
2019-02-21 13:04:01 -05:00
#include <glib.h>
2019-02-19 12:58:40 -05:00
#include <pthread.h>
2019-02-21 13:04:01 -05:00
#include <signal/key_helper.h>
#include <signal/protocol.h>
#include <signal/signal_protocol.h>
#include <signal/session_builder.h>
#include <signal/session_cipher.h>
2019-02-18 23:44:47 -05:00
#include "config/account.h"
2019-03-07 13:05:11 -05:00
#include "config/files.h"
#include "config/preferences.h"
2019-02-21 13:04:01 -05:00
#include "log.h"
2019-02-19 12:38:15 -05:00
#include "omemo/crypto.h"
2019-02-21 13:04:01 -05:00
#include "omemo/omemo.h"
2019-03-07 13:05:11 -05:00
#include "omemo/store.h"
2019-02-21 13:04:01 -05:00
#include "ui/ui.h"
2019-03-07 13:05:11 -05:00
#include "ui/window_list.h"
#include "xmpp/connection.h"
2019-03-14 15:45:47 -04:00
#include "xmpp/muc.h"
2019-02-21 13:04:01 -05:00
#include "xmpp/omemo.h"
#include "xmpp/roster_list.h"
2019-03-07 13:05:11 -05:00
#include "xmpp/xmpp.h"
2019-02-21 13:04:01 -05:00
#define AESGCM_URL_NONCE_LEN (2 * OMEMO_AESGCM_NONCE_LENGTH)
#define AESGCM_URL_KEY_LEN (2 * OMEMO_AESGCM_KEY_LENGTH)
2019-02-21 13:04:01 -05:00
static gboolean loaded;
2019-02-18 23:44:47 -05:00
static void _generate_pre_keys(int count);
static void _generate_signed_pre_key(void);
static gboolean _load_identity(void);
static void _load_trust(void);
2019-04-01 15:16:39 -04:00
static void _load_sessions(void);
static void _load_known_devices(void);
2020-07-07 08:18:57 -04:00
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);
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 char* _omemo_fingerprint(ec_public_key* identity, gboolean formatted);
static unsigned char* _omemo_fingerprint_decode(const char* const fingerprint, size_t* len);
static char* _omemo_unformat_fingerprint(const char* const fingerprint_formatted);
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);
struct omemo_context_t
{
2019-02-19 12:58:40 -05:00
pthread_mutexattr_t attr;
pthread_mutex_t lock;
2020-07-07 08:18:57 -04:00
signal_context* signal;
2019-02-21 13:04:01 -05:00
uint32_t device_id;
2020-07-07 08:18:57 -04:00
GHashTable* device_list;
GHashTable* device_list_handler;
ratchet_identity_key_pair* identity_key_pair;
2019-02-21 13:04:01 -05:00
uint32_t registration_id;
uint32_t signed_pre_key_id;
2020-07-07 08:18:57 -04:00
signal_protocol_store_context* store;
GHashTable* session_store;
GHashTable* pre_key_store;
GHashTable* signed_pre_key_store;
identity_key_store_t identity_key_store;
2020-07-07 08:18:57 -04:00
GString* identity_filename;
GKeyFile* identity_keyfile;
GString* trust_filename;
GKeyFile* trust_keyfile;
GString* sessions_filename;
GKeyFile* sessions_keyfile;
GHashTable* known_devices;
GString* known_devices_filename;
GKeyFile* known_devices_keyfile;
GHashTable* fingerprint_ac;
2019-02-19 12:58:40 -05:00
};
2019-02-21 13:04:01 -05:00
static omemo_context omemo_ctx;
2019-02-18 23:44:47 -05:00
void
omemo_init(void)
2019-02-18 23:44:47 -05:00
{
2021-03-06 13:51:34 -05:00
log_info("[OMEMO] initialising");
2019-02-19 12:38:15 -05:00
if (omemo_crypto_init() != 0) {
2020-02-21 04:30:09 -05:00
cons_show("Error initializing OMEMO crypto: gcry_check_version() failed");
2019-02-19 12:38:15 -05:00
}
2019-02-21 13:04:01 -05:00
pthread_mutexattr_init(&omemo_ctx.attr);
pthread_mutexattr_settype(&omemo_ctx.attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&omemo_ctx.lock, &omemo_ctx.attr);
2019-02-19 12:58:40 -05:00
omemo_ctx.fingerprint_ac = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)autocomplete_free);
}
void
omemo_close(void)
{
if (omemo_ctx.fingerprint_ac) {
g_hash_table_destroy(omemo_ctx.fingerprint_ac);
omemo_ctx.fingerprint_ac = NULL;
}
}
void
2020-07-07 08:18:57 -04:00
omemo_on_connect(ProfAccount* account)
{
2020-07-07 08:18:57 -04:00
GError* error = NULL;
2019-02-21 13:04:01 -05:00
if (signal_context_create(&omemo_ctx.signal, &omemo_ctx) != 0) {
cons_show("Error initializing OMEMO context");
2019-02-19 12:38:15 -05:00
return;
}
2019-04-01 15:16:39 -04:00
if (signal_context_set_log_function(omemo_ctx.signal, _omemo_log) != 0) {
cons_show("Error initializing OMEMO log");
}
signal_crypto_provider crypto_provider = {
.random_func = omemo_random_func,
.hmac_sha256_init_func = omemo_hmac_sha256_init_func,
.hmac_sha256_update_func = omemo_hmac_sha256_update_func,
.hmac_sha256_final_func = omemo_hmac_sha256_final_func,
.hmac_sha256_cleanup_func = omemo_hmac_sha256_cleanup_func,
.sha512_digest_init_func = omemo_sha512_digest_init_func,
.sha512_digest_update_func = omemo_sha512_digest_update_func,
.sha512_digest_final_func = omemo_sha512_digest_final_func,
.sha512_digest_cleanup_func = omemo_sha512_digest_cleanup_func,
.encrypt_func = omemo_encrypt_func,
.decrypt_func = omemo_decrypt_func,
.user_data = NULL
};
2019-02-21 13:04:01 -05:00
if (signal_context_set_crypto_provider(omemo_ctx.signal, &crypto_provider) != 0) {
2020-02-21 04:30:09 -05:00
cons_show("Error initializing OMEMO crypto: unable to set crypto provider");
2019-02-19 12:38:15 -05:00
return;
}
2019-02-19 12:58:40 -05:00
2019-04-01 15:16:39 -04:00
signal_context_set_locking_functions(omemo_ctx.signal, _lock, _unlock);
2019-02-21 13:04:01 -05:00
signal_protocol_store_context_create(&omemo_ctx.store, omemo_ctx.signal);
omemo_ctx.session_store = session_store_new();
signal_protocol_session_store session_store = {
.load_session_func = load_session,
.get_sub_device_sessions_func = get_sub_device_sessions,
.store_session_func = store_session,
.contains_session_func = contains_session,
.delete_session_func = delete_session,
.delete_all_sessions_func = delete_all_sessions,
.destroy_func = NULL,
.user_data = omemo_ctx.session_store
};
signal_protocol_store_context_set_session_store(omemo_ctx.store, &session_store);
omemo_ctx.pre_key_store = pre_key_store_new();
signal_protocol_pre_key_store pre_key_store = {
.load_pre_key = load_pre_key,
.store_pre_key = store_pre_key,
.contains_pre_key = contains_pre_key,
.remove_pre_key = remove_pre_key,
.destroy_func = NULL,
.user_data = omemo_ctx.pre_key_store
};
signal_protocol_store_context_set_pre_key_store(omemo_ctx.store, &pre_key_store);
omemo_ctx.signed_pre_key_store = signed_pre_key_store_new();
signal_protocol_signed_pre_key_store signed_pre_key_store = {
.load_signed_pre_key = load_signed_pre_key,
.store_signed_pre_key = store_signed_pre_key,
.contains_signed_pre_key = contains_signed_pre_key,
.remove_signed_pre_key = remove_signed_pre_key,
.destroy_func = NULL,
.user_data = omemo_ctx.signed_pre_key_store
};
signal_protocol_store_context_set_signed_pre_key_store(omemo_ctx.store, &signed_pre_key_store);
identity_key_store_new(&omemo_ctx.identity_key_store);
signal_protocol_identity_key_store identity_key_store = {
.get_identity_key_pair = get_identity_key_pair,
.get_local_registration_id = get_local_registration_id,
.save_identity = save_identity,
.is_trusted_identity = is_trusted_identity,
.destroy_func = NULL,
.user_data = &omemo_ctx.identity_key_store
};
signal_protocol_store_context_set_identity_key_store(omemo_ctx.store, &identity_key_store);
2019-02-21 13:04:01 -05:00
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);
2019-04-01 15:16:39 -04:00
omemo_ctx.known_devices = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_g_hash_table_free);
2019-03-25 13:27:36 -04:00
2020-07-07 08:18:57 -04:00
gchar* omemo_dir = files_get_account_data_path(DIR_OMEMO, account->jid);
omemo_ctx.identity_filename = g_string_new(omemo_dir);
g_string_append(omemo_ctx.identity_filename, "/identity.txt");
omemo_ctx.trust_filename = g_string_new(omemo_dir);
g_string_append(omemo_ctx.trust_filename, "/trust.txt");
omemo_ctx.sessions_filename = g_string_new(omemo_dir);
g_string_append(omemo_ctx.sessions_filename, "/sessions.txt");
omemo_ctx.known_devices_filename = g_string_new(omemo_dir);
g_string_append(omemo_ctx.known_devices_filename, "/known_devices.txt");
2019-03-07 01:20:29 -05:00
errno = 0;
int res = g_mkdir_with_parents(omemo_dir, S_IRWXU);
if (res == -1) {
const char* errmsg = strerror(errno);
if (errmsg) {
2021-03-06 13:51:34 -05:00
log_error("[OMEMO] error creating directory: %s, %s", omemo_dir, errmsg);
} else {
2021-03-06 13:51:34 -05:00
log_error("[OMEMO] creating directory: %s", omemo_dir);
}
}
g_free(omemo_dir);
2019-03-21 19:03:16 -04:00
omemo_devicelist_subscribe();
omemo_ctx.identity_keyfile = g_key_file_new();
omemo_ctx.trust_keyfile = g_key_file_new();
omemo_ctx.sessions_keyfile = g_key_file_new();
omemo_ctx.known_devices_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)) {
if (!_load_identity()) {
return;
}
} else if (error->code != G_FILE_ERROR_NOENT) {
2021-03-06 13:51:34 -05:00
log_warning("[OMEMO] error loading identity from: %s, %s", omemo_ctx.identity_filename->str, error->message);
g_error_free(error);
return;
}
2019-03-07 01:20:29 -05:00
error = NULL;
if (g_key_file_load_from_file(omemo_ctx.trust_keyfile, omemo_ctx.trust_filename->str, G_KEY_FILE_KEEP_COMMENTS, &error)) {
_load_trust();
} else if (error->code != G_FILE_ERROR_NOENT) {
2021-03-06 13:51:34 -05:00
log_warning("[OMEMO] error loading trust from: %s, %s", omemo_ctx.trust_filename->str, error->message);
g_error_free(error);
} else {
log_warning("[OMEMO] no such file: %s", omemo_ctx.trust_filename->str);
g_error_free(error);
}
error = NULL;
if (g_key_file_load_from_file(omemo_ctx.sessions_keyfile, omemo_ctx.sessions_filename->str, G_KEY_FILE_KEEP_COMMENTS, &error)) {
2019-04-01 15:16:39 -04:00
_load_sessions();
} else if (error->code != G_FILE_ERROR_NOENT) {
2021-03-06 13:51:34 -05:00
log_warning("[OMEMO] error loading sessions from: %s, %s", omemo_ctx.sessions_filename->str, error->message);
g_error_free(error);
} else {
log_warning("[OMEMO] no such file: %s", omemo_ctx.trust_filename->str);
g_error_free(error);
2019-03-07 01:20:29 -05:00
}
error = NULL;
if (g_key_file_load_from_file(omemo_ctx.known_devices_keyfile, omemo_ctx.known_devices_filename->str, G_KEY_FILE_KEEP_COMMENTS, &error)) {
_load_known_devices();
} else if (error->code != G_FILE_ERROR_NOENT) {
2021-03-06 13:51:34 -05:00
log_warning("[OMEMO] error loading known devices from: %s, %s", omemo_ctx.known_devices_filename->str, error->message);
g_error_free(error);
} else {
log_warning("[OMEMO] no such file: %s", omemo_ctx.trust_filename->str);
g_error_free(error);
}
}
2019-03-21 19:03:16 -04:00
void
omemo_on_disconnect(void)
{
if (!loaded) {
return;
}
2019-04-01 15:16:39 -04:00
_g_hash_table_free(omemo_ctx.signed_pre_key_store);
_g_hash_table_free(omemo_ctx.pre_key_store);
2019-07-04 04:47:50 -04:00
_g_hash_table_free(omemo_ctx.device_list_handler);
2019-03-21 19:03:16 -04:00
g_string_free(omemo_ctx.identity_filename, TRUE);
g_key_file_free(omemo_ctx.identity_keyfile);
g_string_free(omemo_ctx.trust_filename, TRUE);
g_key_file_free(omemo_ctx.trust_keyfile);
2019-03-21 19:03:16 -04:00
g_string_free(omemo_ctx.sessions_filename, TRUE);
g_key_file_free(omemo_ctx.sessions_keyfile);
_g_hash_table_free(omemo_ctx.session_store);
g_string_free(omemo_ctx.known_devices_filename, TRUE);
g_key_file_free(omemo_ctx.known_devices_keyfile);
2019-03-21 19:03:16 -04:00
}
void
2020-07-07 08:18:57 -04:00
omemo_generate_crypto_materials(ProfAccount* account)
{
if (loaded) {
return;
}
2019-08-23 04:14:04 -04:00
log_info("Generate long term OMEMO cryptography materials");
2019-04-01 07:00:19 -04:00
/* Device ID */
2019-03-06 12:17:11 -05:00
gcry_randomize(&omemo_ctx.device_id, 4, GCRY_VERY_STRONG_RANDOM);
omemo_ctx.device_id &= 0x7fffffff;
2019-04-01 07:00:19 -04:00
g_key_file_set_uint64(omemo_ctx.identity_keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_DEVICE_ID, omemo_ctx.device_id);
2021-03-06 13:51:34 -05:00
log_info("[OMEMO] device id: %d", omemo_ctx.device_id);
2019-04-01 07:00:19 -04:00
/* Identity key */
2019-02-21 13:04:01 -05:00
signal_protocol_key_helper_generate_identity_key_pair(&omemo_ctx.identity_key_pair, omemo_ctx.signal);
ec_public_key_serialize(&omemo_ctx.identity_key_store.public, ratchet_identity_key_pair_get_public(omemo_ctx.identity_key_pair));
2020-07-07 08:18:57 -04:00
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);
2019-04-01 07:00:19 -04:00
ec_private_key_serialize(&omemo_ctx.identity_key_store.private, ratchet_identity_key_pair_get_private(omemo_ctx.identity_key_pair));
2020-07-07 08:18:57 -04:00
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);
2019-04-01 07:00:19 -04:00
/* Registration ID */
signal_protocol_key_helper_generate_registration_id(&omemo_ctx.registration_id, 0, omemo_ctx.signal);
g_key_file_set_uint64(omemo_ctx.identity_keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_REGISTRATION_ID, omemo_ctx.registration_id);
2019-04-01 07:00:19 -04:00
/* Pre keys */
_generate_pre_keys(100);
2019-03-21 19:03:16 -04:00
2019-04-01 07:00:19 -04:00
/* Signed pre key */
_generate_signed_pre_key();
2019-02-21 13:04:01 -05:00
2019-04-01 07:00:19 -04:00
omemo_identity_keyfile_save();
2019-02-21 13:04:01 -05:00
loaded = TRUE;
omemo_publish_crypto_materials();
omemo_start_sessions();
2019-04-01 07:00:19 -04:00
}
void
omemo_publish_crypto_materials(void)
2019-04-01 07:00:19 -04:00
{
log_debug("[OMEMO] publish crypto materials");
if (loaded != TRUE) {
2021-03-06 13:51:34 -05:00
cons_show("OMEMO: cannot publish crypto materials before they are generated");
log_error("[OMEMO] cannot publish crypto materials before they are generated");
return;
}
2020-07-07 08:18:57 -04:00
char* barejid = connection_get_barejid();
/* Ensure we get our current device list, and it gets updated with our
* device_id */
g_hash_table_insert(omemo_ctx.device_list_handler, strdup(barejid), _handle_own_device_list);
omemo_devicelist_request(barejid);
omemo_bundle_publish(true);
free(barejid);
2019-02-21 13:04:01 -05:00
}
void
omemo_start_sessions(void)
{
2020-07-07 08:18:57 -04:00
GSList* contacts = roster_get_contacts(ROSTER_ORD_NAME);
if (contacts) {
2020-07-07 08:18:57 -04:00
GSList* curr;
for (curr = contacts; curr != NULL; curr = g_slist_next(curr)) {
PContact contact = curr->data;
2020-07-07 08:18:57 -04:00
const char* jid = p_contact_barejid(contact);
omemo_start_session(jid);
}
g_slist_free(contacts);
}
}
2019-02-21 13:04:01 -05:00
void
2020-07-07 08:18:57 -04:00
omemo_start_session(const char* const barejid)
2019-02-21 13:04:01 -05:00
{
2020-07-07 08:18:57 -04:00
if (omemo_loaded()) {
log_debug("[OMEMO] start session with %s", barejid);
2020-07-07 08:18:57 -04:00
GList* device_list = g_hash_table_lookup(omemo_ctx.device_list, barejid);
if (!device_list) {
log_debug("[OMEMO] missing device list for %s", barejid);
// Own devices are handled by _handle_own_device_list
// We won't add _handle_device_list_start_session for ourself
char* mybarejid = connection_get_barejid();
if( g_strcmp0(mybarejid, barejid ) != 0 ) {
g_hash_table_insert(omemo_ctx.device_list_handler, strdup(barejid), _handle_device_list_start_session);
}
free(mybarejid);
omemo_devicelist_request(barejid);
return;
}
2019-02-21 13:04:01 -05:00
2020-07-07 08:18:57 -04:00
GList* device_id;
for (device_id = device_list; device_id != NULL; device_id = device_id->next) {
omemo_bundle_request(barejid, GPOINTER_TO_INT(device_id->data), omemo_start_device_session_handle_bundle, free, strdup(barejid));
}
}
2019-02-21 13:04:01 -05:00
}
2019-03-15 13:52:28 -04:00
void
2020-07-07 08:18:57 -04:00
omemo_start_muc_sessions(const char* const roomjid)
2019-03-15 13:52:28 -04:00
{
2020-07-07 08:18:57 -04:00
GList* members = muc_members(roomjid);
GList* iter;
for (iter = members; iter != NULL; iter = iter->next) {
2020-07-07 08:18:57 -04:00
Jid* jid = jid_create(iter->data);
omemo_start_session(jid->barejid);
jid_destroy(jid);
2019-03-15 13:52:28 -04:00
}
g_list_free(members);
2019-03-15 13:52:28 -04:00
}
2019-02-21 13:04:01 -05:00
gboolean
omemo_loaded(void)
{
return loaded;
}
uint32_t
omemo_device_id(void)
{
return omemo_ctx.device_id;
}
void
2020-07-07 08:18:57 -04:00
omemo_identity_key(unsigned char** output, size_t* length)
2019-02-21 13:04:01 -05:00
{
2020-07-07 08:18:57 -04:00
signal_buffer* buffer = NULL;
2019-02-21 13:04:01 -05:00
ec_public_key_serialize(&buffer, ratchet_identity_key_pair_get_public(omemo_ctx.identity_key_pair));
*length = signal_buffer_len(buffer);
*output = malloc(*length);
memcpy(*output, signal_buffer_data(buffer), *length);
2019-02-21 13:04:01 -05:00
signal_buffer_free(buffer);
}
void
2020-07-07 08:18:57 -04:00
omemo_signed_prekey(unsigned char** output, size_t* length)
2019-02-21 13:04:01 -05:00
{
2020-07-07 08:18:57 -04:00
session_signed_pre_key* signed_pre_key;
signal_buffer* buffer = NULL;
2019-04-01 07:00:19 -04:00
if (signal_protocol_signed_pre_key_load_key(omemo_ctx.store, &signed_pre_key, omemo_ctx.signed_pre_key_id) != SG_SUCCESS) {
*output = NULL;
*length = 0;
return;
}
ec_public_key_serialize(&buffer, ec_key_pair_get_public(session_signed_pre_key_get_key_pair(signed_pre_key)));
2019-03-21 19:03:16 -04:00
SIGNAL_UNREF(signed_pre_key);
2019-02-21 13:04:01 -05:00
*length = signal_buffer_len(buffer);
*output = malloc(*length);
memcpy(*output, signal_buffer_data(buffer), *length);
2019-02-21 13:04:01 -05:00
signal_buffer_free(buffer);
}
void
2020-07-07 08:18:57 -04:00
omemo_signed_prekey_signature(unsigned char** output, size_t* length)
2019-02-21 13:04:01 -05:00
{
2020-07-07 08:18:57 -04:00
session_signed_pre_key* signed_pre_key;
2019-04-01 07:00:19 -04:00
if (signal_protocol_signed_pre_key_load_key(omemo_ctx.store, &signed_pre_key, omemo_ctx.signed_pre_key_id) != SG_SUCCESS) {
*output = NULL;
*length = 0;
return;
}
*length = session_signed_pre_key_get_signature_len(signed_pre_key);
2019-02-21 13:04:01 -05:00
*output = malloc(*length);
memcpy(*output, session_signed_pre_key_get_signature(signed_pre_key), *length);
2019-03-21 19:03:16 -04:00
SIGNAL_UNREF(signed_pre_key);
2019-02-21 13:04:01 -05:00
}
void
2020-07-07 08:18:57 -04:00
omemo_prekeys(GList** prekeys, GList** ids, GList** lengths)
2019-02-21 13:04:01 -05:00
{
GHashTableIter iter;
gpointer id;
g_hash_table_iter_init(&iter, omemo_ctx.pre_key_store);
while (g_hash_table_iter_next(&iter, &id, NULL)) {
2020-07-07 08:18:57 -04:00
session_pre_key* pre_key;
int ret;
ret = signal_protocol_pre_key_load_key(omemo_ctx.store, &pre_key, GPOINTER_TO_INT(id));
if (ret != SG_SUCCESS) {
continue;
}
2020-07-07 08:18:57 -04:00
signal_buffer* public_key;
ec_public_key_serialize(&public_key, ec_key_pair_get_public(session_pre_key_get_key_pair(pre_key)));
2019-03-21 19:03:16 -04:00
SIGNAL_UNREF(pre_key);
size_t length = signal_buffer_len(public_key);
2020-07-07 08:18:57 -04:00
unsigned char* prekey_value = malloc(length);
memcpy(prekey_value, signal_buffer_data(public_key), length);
2019-03-21 19:03:16 -04:00
signal_buffer_free(public_key);
2019-02-21 13:04:01 -05:00
*prekeys = g_list_append(*prekeys, prekey_value);
*ids = g_list_append(*ids, GINT_TO_POINTER(id));
2019-02-21 13:04:01 -05:00
*lengths = g_list_append(*lengths, GINT_TO_POINTER(length));
}
}
void
2020-07-07 08:18:57 -04:00
omemo_set_device_list(const char* const from, GList* device_list)
{
log_debug("[OMEMO] Setting device list for %s", from);
2020-07-07 08:18:57 -04:00
Jid* jid;
if (from) {
jid = jid_create(from);
} else {
jid = jid_create(connection_get_fulljid());
}
2019-03-13 14:29:45 -04:00
g_hash_table_insert(omemo_ctx.device_list, strdup(jid->barejid), device_list);
2019-03-13 14:29:45 -04:00
OmemoDeviceListHandler handler = g_hash_table_lookup(omemo_ctx.device_list_handler, jid->barejid);
if (handler) {
2019-03-13 14:29:45 -04:00
gboolean keep = handler(jid->barejid, device_list);
if (!keep) {
2019-03-13 14:29:45 -04:00
g_hash_table_remove(omemo_ctx.device_list_handler, jid->barejid);
}
} else {
log_debug("[OMEMO] No Device List Handler for %s", from);
}
// OMEMO trustmode ToFu
if (g_strcmp0(prefs_get_string(PREF_OMEMO_TRUST_MODE), "firstusage") == 0) {
log_debug("[OMEMO] Checking firstusage state for %s", jid->barejid);
GHashTable* trusted = g_hash_table_lookup(omemo_ctx.identity_key_store.trusted, jid->barejid);
if (trusted) {
if (g_hash_table_size(trusted) > 0) {
log_debug("[OMEMO] Found trusted device for %s - skip firstusage", jid->barejid);
return;
}
} else {
if (device_list) {
cons_show("OMEMO: No trusted devices found for %s", jid->barejid);
GList* device_id;
for (device_id = device_list; device_id != NULL; device_id = device_id->next) {
GHashTable* known_identities = g_hash_table_lookup(omemo_ctx.known_devices, jid->barejid);
if (known_identities) {
GList* fp = NULL;
for (fp = g_hash_table_get_keys(known_identities); fp != NULL; fp = fp->next) {
if (device_id->data == g_hash_table_lookup(known_identities, fp->data)) {
cons_show("OMEMO: Adding firstusage trust for %s device %d - Fingerprint %s", jid->barejid, device_id->data, omemo_format_fingerprint(fp->data));
omemo_trust(jid->barejid, omemo_format_fingerprint(fp->data));
}
}
}
}
}
}
}
2019-03-14 15:45:47 -04:00
jid_destroy(jid);
}
2020-07-07 08:18:57 -04:00
GKeyFile*
omemo_identity_keyfile(void)
{
return omemo_ctx.identity_keyfile;
}
void
omemo_identity_keyfile_save(void)
{
2020-07-07 08:18:57 -04:00
GError* error = NULL;
if (!g_key_file_save_to_file(omemo_ctx.identity_keyfile, omemo_ctx.identity_filename->str, &error)) {
2021-03-06 13:51:34 -05:00
log_error("[OMEMO] error saving identity to: %s, %s", omemo_ctx.identity_filename->str, error->message);
}
}
2020-07-07 08:18:57 -04:00
GKeyFile*
omemo_trust_keyfile(void)
{
return omemo_ctx.trust_keyfile;
}
void
omemo_trust_keyfile_save(void)
{
2020-07-07 08:18:57 -04:00
GError* error = NULL;
if (!g_key_file_save_to_file(omemo_ctx.trust_keyfile, omemo_ctx.trust_filename->str, &error)) {
2021-03-06 13:51:34 -05:00
log_error("[OMEMO] error saving trust to: %s, %s", omemo_ctx.trust_filename->str, error->message);