Files
profanity/src/omemo/store.c
Paul Fariello ad21021ce7 Fix issue with first encrypted message
When decrypting first message with prekey, libsignal wants to remove
used prekey from storage. Return value on success should be 0.

We used to return number of deleted keys. Thus libsignal was considering
we failed to remove the key and we were ignoring plaintext.
2019-04-10 17:24:56 +02:00

383 lines
11 KiB
C

#include <glib.h>
#include <signal/signal_protocol.h>
#include "config.h"
#include "omemo/omemo.h"
#include "omemo/store.h"
GHashTable *
session_store_new(void)
{
return g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
}
GHashTable *
pre_key_store_new(void)
{
return g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)signal_buffer_free);
}
GHashTable *
signed_pre_key_store_new(void)
{
return g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)signal_buffer_free);
}
void
identity_key_store_new(identity_key_store_t *identity_key_store)
{
identity_key_store->trusted = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)signal_buffer_free);
identity_key_store->private = NULL;
identity_key_store->public = NULL;
}
#ifdef HAVE_LIBSIGNAL_LT_2_3_2
int
load_session(signal_buffer **record, const signal_protocol_address *address,
void *user_data)
#else
int
load_session(signal_buffer **record, signal_buffer **user_record,
const signal_protocol_address *address, void *user_data)
#endif
{
GHashTable *session_store = (GHashTable *)user_data;
GHashTable *device_store = NULL;
device_store = g_hash_table_lookup(session_store, address->name);
if (!device_store) {
*record = NULL;
return 0;
}
signal_buffer *original = g_hash_table_lookup(device_store, GINT_TO_POINTER(address->device_id));
if (!original) {
*record = NULL;
return 0;
}
*record = signal_buffer_copy(original);
return 1;
}
int
get_sub_device_sessions(signal_int_list **sessions, const char *name,
size_t name_len, void *user_data)
{
GHashTable *session_store = (GHashTable *)user_data;
GHashTable *device_store = NULL;
GHashTableIter iter;
gpointer key, value;
device_store = g_hash_table_lookup(session_store, name);
if (!device_store) {
return SG_SUCCESS;
}
*sessions = signal_int_list_alloc();
g_hash_table_iter_init(&iter, device_store);
while (g_hash_table_iter_next(&iter, &key, &value)) {
signal_int_list_push_back(*sessions, GPOINTER_TO_INT(key));
}
return SG_SUCCESS;
}
#ifdef HAVE_LIBSIGNAL_LT_2_3_2
int
store_session(const signal_protocol_address *address, uint8_t *record,
size_t record_len, void *user_data)
#else
int
store_session(const signal_protocol_address *address,
uint8_t *record, size_t record_len,
uint8_t *user_record, size_t user_record_len,
void *user_data)
#endif
{
GHashTable *session_store = (GHashTable *)user_data;
GHashTable *device_store = NULL;
device_store = g_hash_table_lookup(session_store, (void *)address->name);
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(session_store, strdup(address->name), device_store);
}
signal_buffer *buffer = signal_buffer_create(record, record_len);
g_hash_table_insert(device_store, GINT_TO_POINTER(address->device_id), buffer);
char *record_b64 = g_base64_encode(record, record_len);
char *device_id = g_strdup_printf("%d", address->device_id);
g_key_file_set_string(omemo_sessions_keyfile(), address->name, device_id, record_b64);
free(device_id);
g_free(record_b64);
omemo_sessions_keyfile_save();
return SG_SUCCESS;
}
int
contains_session(const signal_protocol_address *address, void *user_data)
{
GHashTable *session_store = (GHashTable *)user_data;
GHashTable *device_store = NULL;
device_store = g_hash_table_lookup(session_store, address->name);
if (!device_store) {
return 0;
}
if (!g_hash_table_lookup(device_store, GINT_TO_POINTER(address->device_id))) {
return 0;
}
return 1;
}
int
delete_session(const signal_protocol_address *address, void *user_data)
{
GHashTable *session_store = (GHashTable *)user_data;
GHashTable *device_store = NULL;
device_store = g_hash_table_lookup(session_store, address->name);
if (!device_store) {
return SG_SUCCESS;
}
return g_hash_table_remove(device_store, GINT_TO_POINTER(address->device_id));
}
int
delete_all_sessions(const char *name, size_t name_len, void *user_data)
{
GHashTable *session_store = (GHashTable *)user_data;
GHashTable *device_store = NULL;
device_store = g_hash_table_lookup(session_store, name);
if (!device_store) {
return SG_SUCCESS;
}
guint len = g_hash_table_size(device_store);
g_hash_table_remove_all(device_store);
return len;
}
int
load_pre_key(signal_buffer **record, uint32_t pre_key_id, void *user_data)
{
signal_buffer *original;
GHashTable *pre_key_store = (GHashTable *)user_data;
original = g_hash_table_lookup(pre_key_store, GINT_TO_POINTER(pre_key_id));
if (original == NULL) {
return SG_ERR_INVALID_KEY_ID;
}
*record = signal_buffer_copy(original);
return SG_SUCCESS;
}
int
store_pre_key(uint32_t pre_key_id, uint8_t *record, size_t record_len,
void *user_data)
{
GHashTable *pre_key_store = (GHashTable *)user_data;
signal_buffer *buffer = signal_buffer_create(record, record_len);
g_hash_table_insert(pre_key_store, GINT_TO_POINTER(pre_key_id), buffer);
/* Long term storage */
char *pre_key_id_str = g_strdup_printf("%d", pre_key_id);
char *record_b64 = g_base64_encode(record, record_len);
g_key_file_set_string(omemo_identity_keyfile(), OMEMO_STORE_GROUP_PREKEYS, pre_key_id_str, record_b64);
g_free(pre_key_id_str);
g_free(record_b64);
omemo_identity_keyfile_save();
return SG_SUCCESS;
}
int
contains_pre_key(uint32_t pre_key_id, void *user_data)
{
GHashTable *pre_key_store = (GHashTable *)user_data;
return g_hash_table_lookup(pre_key_store, GINT_TO_POINTER(pre_key_id)) != NULL;
}
int
remove_pre_key(uint32_t pre_key_id, void *user_data)
{
GHashTable *pre_key_store = (GHashTable *)user_data;
int ret = g_hash_table_remove(pre_key_store, GINT_TO_POINTER(pre_key_id));
/* Long term storage */
char *pre_key_id_str = g_strdup_printf("%d", pre_key_id);
g_key_file_remove_key(omemo_identity_keyfile(), OMEMO_STORE_GROUP_PREKEYS, pre_key_id_str, NULL);
g_free(pre_key_id_str);
omemo_identity_keyfile_save();
if (ret > 0) {
return SG_SUCCESS;
} else {
return SG_ERR_INVALID_KEY_ID;
}
}
int
load_signed_pre_key(signal_buffer **record, uint32_t signed_pre_key_id,
void *user_data)
{
signal_buffer *original;
GHashTable *signed_pre_key_store = (GHashTable *)user_data;
original = g_hash_table_lookup(signed_pre_key_store, GINT_TO_POINTER(signed_pre_key_id));
if (!original) {
return SG_ERR_INVALID_KEY_ID;
}
*record = signal_buffer_copy(original);
return SG_SUCCESS;
}
int
store_signed_pre_key(uint32_t signed_pre_key_id, uint8_t *record,
size_t record_len, void *user_data)
{
GHashTable *signed_pre_key_store = (GHashTable *)user_data;
signal_buffer *buffer = signal_buffer_create(record, record_len);
g_hash_table_insert(signed_pre_key_store, GINT_TO_POINTER(signed_pre_key_id), buffer);
/* Long term storage */
char *signed_pre_key_id_str = g_strdup_printf("%d", signed_pre_key_id);
char *record_b64 = g_base64_encode(record, record_len);
g_key_file_set_string(omemo_identity_keyfile(), OMEMO_STORE_GROUP_SIGNED_PREKEYS, signed_pre_key_id_str, record_b64);
g_free(signed_pre_key_id_str);
g_free(record_b64);
omemo_identity_keyfile_save();
return SG_SUCCESS;
}
int
contains_signed_pre_key(uint32_t signed_pre_key_id, void *user_data)
{
GHashTable *signed_pre_key_store = (GHashTable *)user_data;
return g_hash_table_lookup(signed_pre_key_store, GINT_TO_POINTER(signed_pre_key_id)) != NULL;
}
int
remove_signed_pre_key(uint32_t signed_pre_key_id, void *user_data)
{
GHashTable *signed_pre_key_store = (GHashTable *)user_data;
int ret = g_hash_table_remove(signed_pre_key_store, GINT_TO_POINTER(signed_pre_key_id));
/* Long term storage */
char *signed_pre_key_id_str = g_strdup_printf("%d", signed_pre_key_id);
g_key_file_remove_key(omemo_identity_keyfile(), OMEMO_STORE_GROUP_PREKEYS, signed_pre_key_id_str, NULL);
g_free(signed_pre_key_id_str);
omemo_identity_keyfile_save();
return ret;
}
int
get_identity_key_pair(signal_buffer **public_data, signal_buffer **private_data,
void *user_data)
{
identity_key_store_t *identity_key_store = (identity_key_store_t *)user_data;
*public_data = signal_buffer_copy(identity_key_store->public);
*private_data = signal_buffer_copy(identity_key_store->private);
return SG_SUCCESS;
}
int
get_local_registration_id(void *user_data, uint32_t *registration_id)
{
identity_key_store_t *identity_key_store = (identity_key_store_t *)user_data;
*registration_id = identity_key_store->registration_id;
return SG_SUCCESS;
}
int
save_identity(const signal_protocol_address *address, uint8_t *key_data,
size_t key_len, void *user_data)
{
identity_key_store_t *identity_key_store = (identity_key_store_t *)user_data;
signal_buffer *buffer = signal_buffer_create(key_data, key_len);
GHashTable *trusted = g_hash_table_lookup(identity_key_store->trusted, strdup(address->name));
if (!trusted) {
trusted = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)signal_buffer_free);
g_hash_table_insert(identity_key_store->trusted, strdup(address->name), trusted);
}
g_hash_table_insert(trusted, GINT_TO_POINTER(address->device_id), buffer);
/* Long term storage */
char *key_b64 = g_base64_encode(key_data, key_len);
char *device_id = g_strdup_printf("%d", address->device_id);
g_key_file_set_string(omemo_trust_keyfile(), address->name, strdup(device_id), key_b64);
g_free(device_id);
g_free(key_b64);
omemo_trust_keyfile_save();
return SG_SUCCESS;
}
int
is_trusted_identity(const signal_protocol_address *address, uint8_t *key_data,
size_t key_len, void *user_data)
{
int ret;
identity_key_store_t *identity_key_store = (identity_key_store_t *)user_data;
GHashTable *trusted = g_hash_table_lookup(identity_key_store->trusted, address->name);
if (!trusted) {
return 0;
}
signal_buffer *buffer = signal_buffer_create(key_data, key_len);
signal_buffer *original = g_hash_table_lookup(trusted, GINT_TO_POINTER(address->device_id));
ret = original != NULL && signal_buffer_compare(buffer, original) == 0;
signal_buffer_free(buffer);
return ret;
}
int
store_sender_key(const signal_protocol_sender_key_name *sender_key_name,
uint8_t *record, size_t record_len, uint8_t *user_record,
size_t user_record_len, void *user_data)
{
return SG_SUCCESS;
}
int
load_sender_key(signal_buffer **record, signal_buffer **user_record,
const signal_protocol_sender_key_name *sender_key_name,
void *user_data)
{
return SG_SUCCESS;
}