Skip to content

Refuse prekey messages without a usable one-time prekey id - #65

Open
Voyd-star wants to merge 1 commit into
HANCORE-linux:mainfrom
Voyd-star:fix/prekey-id-guard
Open

Voyd-star wants to merge 1 commit into
HANCORE-linux:mainfrom
Voyd-star:fix/prekey-id-guard

Conversation

@Voyd-star

Copy link
Copy Markdown

As discussed privately, this is the fix for the helper abort on malformed prekey messages.

Problem. In omaq_ratchet_decrypt, a CIPHERTEXT_PREKEY_TYPE message goes to pre_key_signal_message_get_pre_key_id() without a pre_key_signal_message_has_pre_key_id() check. The id is optional in the protobuf, and the libsignal-protocol-c getter asserts it is present, so a message from an accepted contact without that id aborts the helper. An id of 0 also matches the "any id" sentinel of prekey_reservation_find / consumed_prekey_find and skips the per-peer reservation check.

Fix.

  • Both forms are refused through the existing error path (-1), without recovery or session reset.
  • pre_rm refuses id 0 too.
  • OmaQ only issues ids in [1, 0xFFFFFF], so OmaQ clients never send either form.

Test. ratchet_prekey_test gains prekey_id_guard. It forges both forms, missing id and id 0, on a first message and on a follow-up prekey message. It checks that:

  • they are refused;
  • no prekey is consumed;
  • the genuine messages still decrypt.

Verified on Arch with Signal enabled:

  • ratchet_prekey_test aborts (SIGABRT) without the fix and passes with it (ASan/UBSan, -Werror).
  • make test is otherwise unchanged. Only chat-transcript-layout, panel-request-focus and chat-input-scroll fail, the same on unpatched main in a fresh checkout (generated emoji assets missing).
  • helper-update failed once in the full run, then passed 3/3 on its own with the patch.

🤖 Generated with Claude Code

A PreKeySignalMessage's one-time prekey id is optional on the wire, and
libsignal-protocol-c's pre_key_signal_message_get_pre_key_id() asserts it
is present. omaq_ratchet_decrypt() called the getter without checking
pre_key_signal_message_has_pre_key_id() first, so a message from an
accepted contact without that id aborted the helper.

An id of 0 is also refused: it is the "any id" sentinel of
prekey_reservation_find() and consumed_prekey_find(), so it skipped the
per-peer reservation check. OmaQ only issues ids in [1, 0xFFFFFF], so
neither form is ever sent by an OmaQ client. pre_rm() refuses id 0 too.

The message is rejected through the existing error path (-1), without
recovery or session reset. ratchet_prekey_test forges both forms, on a
first message and on a follow-up prekey message, and checks that no
prekey is consumed and that the genuine messages still decrypt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant