Merge pull request #2137 from profanity-im/omemo-prekey

fix(omemo): standardize PreKey management to prevent decryption failures
This commit is contained in:
Michael Vetter
2026-03-30 10:54:56 +02:00
committed by GitHub

View File

@@ -78,6 +78,7 @@ typedef struct omemo_context
ratchet_identity_key_pair* identity_key_pair;
uint32_t registration_id;
uint32_t signed_pre_key_id;
uint32_t max_pre_key_id;
signal_protocol_store_context* store;
GHashTable* session_store;
GHashTable* pre_key_store;
@@ -323,6 +324,7 @@ omemo_generate_crypto_materials(ProfAccount* account)
g_key_file_set_uint64(omemo_ctx.identity.keyfile, OMEMO_STORE_GROUP_IDENTITY, OMEMO_STORE_KEY_REGISTRATION_ID, omemo_ctx.registration_id);
/* Pre keys */
omemo_ctx.max_pre_key_id = 0;
_generate_pre_keys(100);
/* Signed pre key */
@@ -1095,16 +1097,17 @@ omemo_on_message_recv(const char* const from_jid, uint32_t sid,
signal_buffer_len(identity_buffer), &omemo_ctx.identity_key_store);
signal_buffer_free(identity_buffer);
/* Replace used pre_key in bundle */
/* Remove used pre_key from store */
uint32_t pre_key_id = pre_key_signal_message_get_pre_key_id(message);
ec_key_pair* ec_pair;
session_pre_key* new_pre_key;
curve_generate_key_pair(omemo_ctx.signal, &ec_pair);
session_pre_key_create(&new_pre_key, pre_key_id, ec_pair);
signal_protocol_pre_key_store_key(omemo_ctx.store, new_pre_key);
SIGNAL_UNREF(new_pre_key);
signal_protocol_pre_key_remove_key(omemo_ctx.store, pre_key_id);
/* If we have few pre_keys left, generate more */
if (g_hash_table_size(omemo_ctx.pre_key_store) < 10) {
log_debug("[OMEMO] Few pre keys left, generating more");
_generate_pre_keys(100);
}
SIGNAL_UNREF(message);
SIGNAL_UNREF(ec_pair);
omemo_bundle_publish(TRUE);
if (res == 0) {
@@ -1784,14 +1787,19 @@ _load_identity(void)
int i;
/* Pre keys */
i = 0;
omemo_ctx.max_pre_key_id = 0;
keys = g_key_file_get_keys(omemo_ctx.identity.keyfile, OMEMO_STORE_GROUP_PREKEYS, NULL, NULL);
if (keys) {
for (i = 0; keys[i] != NULL; i++) {
uint32_t id = strtoul(keys[i], NULL, 10);
if (id > omemo_ctx.max_pre_key_id) {
omemo_ctx.max_pre_key_id = id;
}
auto_gchar gchar* pre_key_b64 = g_key_file_get_string(omemo_ctx.identity.keyfile, OMEMO_STORE_GROUP_PREKEYS, keys[i], NULL);
size_t pre_key_len;
auto_guchar guchar* pre_key = g_base64_decode(pre_key_b64, &pre_key_len);
signal_buffer* buffer = signal_buffer_create(pre_key, pre_key_len);
g_hash_table_insert(omemo_ctx.pre_key_store, GINT_TO_POINTER(strtoul(keys[i], NULL, 10)), buffer);
g_hash_table_insert(omemo_ctx.pre_key_store, GINT_TO_POINTER(id), buffer);
}
g_strfreev(keys);
@@ -1980,8 +1988,7 @@ _cache_device_identity(const char* const jid, uint32_t device_id, ec_public_key*
static void
_generate_pre_keys(int count)
{
unsigned int start;
gcry_randomize(&start, sizeof(unsigned int), GCRY_VERY_STRONG_RANDOM);
uint32_t start = omemo_ctx.max_pre_key_id + 1;
signal_protocol_key_helper_pre_key_list_node* pre_keys_head;
signal_protocol_key_helper_generate_pre_keys(&pre_keys_head, start, count, omemo_ctx.signal);
@@ -1991,6 +1998,8 @@ _generate_pre_keys(int count)
signal_protocol_pre_key_store_key(omemo_ctx.store, prekey);
}
signal_protocol_key_helper_key_list_free(pre_keys_head);
omemo_ctx.max_pre_key_id += count;
}
static void