Commit Graph

98 Commits

Author SHA1 Message Date
gram-signal
533d11dd7c Remove usePqRatchet from client-facing code, defaulting to always use. 2025-10-02 11:32:36 -07:00
Jordan Rose
15af92c93d protocol: Record signed prekey and base key used with a Kyber prekey 2025-09-16 15:33:59 -07:00
Rolfe Schmidt
5293caa6ca protocol: Check that base keys are torsion free and in range
Co-authored-by: Jordan Rose <jrose@signal.org>
2025-09-09 15:37:37 -07:00
Alex Bakon
4ea5b762ba Format Rust using 2024 edition rules 2025-09-03 14:22:08 -04:00
Jordan Rose
47a142fde8 protocol: Generialize has_usable_sender_chain checking
It can now also check whether a session was established with PQXDH and
whether it's using SPQR.
2025-07-31 09:42:15 -07:00
Jordan Rose
2879220e93 Require Kyber keys/ciphertexts throughout all XDH APIs 2025-06-13 16:06:07 -07:00
Alex Bakon
3157a9be55 Fix device ID construction in cross-version tests 2025-06-13 17:24:01 -04:00
Jordan Rose
69bb363840 protocol: Reject X3DH PreKey messages
- Drop X3DH tests

- Drop cross-version tests with libsignal v0.12 and v0.21

- Change session benchmarks to use PQXDH, which is relevant if doing
  comparisons before/after this commit.
2025-06-13 12:19:04 -07:00
Alex Bakon
02b786b07e Limit device ID to the range 1-127
This is already required for sealed sender messages and enforced by the server.
2025-06-13 14:18:16 -04:00
gram-signal
3d677ee3d7 Test for PQR state and message contents. 2025-06-12 11:21:42 -07:00
Jordan Rose
a280bc6555 Resolve an age-old X3DH test inconsistency
This known-answer test was originally ported over from
libsignal-protocol-java, but did not produce the same results. Why?
Because one of the private keys chosen by libsignal-protocol-java for
its test was unclamped, while libsignal-the-Rust-implementation always
clamps private keys as part of deserialization, not just generation.
Consequently, the public key didn't actually correspond to the private
key according to our modern libsignal.

Rather than try to line up exactly with what libsignal-protocol-java
was coincidentally doing, this commit clamps the private key, computes
the resulting public key, and verifies a new
consistent-between-both-sides outcome.
2025-06-10 16:20:08 -07:00
gram-signal
b7b8040e3a Integrate post-quantum ratchet SPQR.
This PR integrates a post-quantum ratchet (SPQR) into libsignal, using an API that maintains its own internal chain and provides per-message keys.  In doing so, it also aims to be fully backwards-compatible with current clients and stored session state.

## Backwards compatibility with current clients

Remote clients that connect to us or that we connect to may not have this integration.  If they don't, their SignalMessage wire format should still deserialize, and in doing so we'll receive an empty pq_ratchet field.  SQPR handles this internally, by downgrading the protocol version to "version 0" or "don't do anything".  Note that should we eventually want to disallow this, we can do so via increasing the `min_version` field passed into the SQPR init functions to V1.  This is also the method by which we would upgrade SQPR from v1 to a future v2, etc.

## Opt-in

The publicly facing API calls for this now expose an explicit opt-in via a passed-in `use_pq_ratchet` bool (and associated enums in language-specific APIs).  If false, they default to SQPR `v0`, IE: none.  If true, they try to set up SPQR on new sessions, but will downgrade if the remote party cannot or will not do the same.
2025-06-04 11:18:12 -07:00
Alex Bakon
8a9e18b6c6 Remove unused #[allow], replace with #[expect] 2025-06-03 16:07:06 -04:00
Alex Bakon
151c96e52b Apply lint fixes from latest clippy 2025-05-23 10:29:25 -04:00
Jordan Rose
7d1cacbaa8 protocol: Eagerly promote sessions during pre-key processing
This fixes a bug introduced by cd36118 where starting a new session
locally would prevent incoming messages on a previous session from
being decrypted if that session hadn't advanced past the "pre-key"
stage. Fix this by promoting the session *before* successful
decryption instead of after; since we won't *save* the promotion
unless the message decrypts successfully, there's ultimately no change
in either the failure or success cases *except* when hitting this bug.
2025-05-14 16:52:18 -07:00
Alex Bakon
2f1112c999 Persist pre-key message sender identity after message decryption 2025-04-29 16:19:55 -04:00
Alex Bakon
13b2b8aff4 Take RNG as a parameter when generating kyber keys 2025-04-29 10:54:21 -04:00
Alex Bakon
aeb2f2a561 Bump rand dependency to 0.9 2025-04-24 13:12:56 -04:00
Alex Bakon
9392062a7e Return enum from IdentityKeyStore::save_identity 2025-04-23 09:16:51 -04:00
Alex Bakon
03a739a95c Use const_str::hex instead of hex_literal::hex 2025-03-28 14:48:19 -04:00
Jordan Rose
cd361186fb Don't bother trying to decrypt a PreKey message with older sessions
Co-authored-by: Rolfe Schmidt <rolfe@signal.org>
2025-03-28 10:39:33 -07:00
Alex Konradi
a54e6b5b33 Format with group_imports=StdExternalCrate 2024-08-28 14:52:47 -04:00
Jordan Rose
2dd3896bba protocol: Remove legacy SSv2 receive support 2024-08-08 15:10:25 -07:00
Alex Konradi
09bffd5ab4 Use a named type for protocol timestamp 2024-04-30 16:33:11 -04:00
Jordan Rose
8ae45dcd27 protocol: Flip SSv2 encryption to the "new" key derivation
All official clients should now support receiving this format.
2024-03-05 14:54:51 -08:00
Jordan Rose
16653ffea1 SSv2: Add send support for excluded recipients 2023-12-11 12:36:54 -08:00
moiseev-signal
0ae3eb3c14 protocol: Clean up pending Kyber pre-keys from sessions 2023-11-17 14:46:03 -08:00
Jordan Rose
9839a5be79 Always use the original SSv2 version byte, 0x22, for ReceivedMessages
The format hasn't changed, so we don't need to bump the version number
for the messages the server sends to recipients.

This is implemented in two places: the Rust side for round-trip
testing, and the Java side for what the server actually does. (Both
are implemented to avoid unnecessary copies and unfortunately the two
aren't conveniently compatible with one another, but it's a simple
implementation anyway.)
2023-11-10 09:30:39 -08:00
Jordan Rose
08df716540 protocol: Coalesce duplicate recipients in SSv2 parsing
There should be no reason for a client to split up devices of the same
recipient in a non-contiguous manner, but since we'd have to check it
anyway, we might as well accept it. (Duplicating devices within a
recipient can then be checked separately.)
2023-11-07 12:19:14 -08:00
akonradi-signal
58a16be1b3 Bump all crates to Rust 2021 2023-10-31 13:43:33 -04:00
Jordan Rose
bb1f0baf5e Support the old SSv2 format in SealedSenderV2SentMessage as well
It hasn't been that long since we switched to using service IDs, so we
can't drop the old format yet.
2023-10-20 10:16:51 -07:00
Jordan Rose
5c841ef281 Add proper parse logic for the SSv2 SentMessage format
This isn't hooked up to anything that the fan_out test method wasn't,
but it will come in handy for future testing.
2023-10-20 10:16:51 -07:00
akonradi-signal
ef542e3b9f Bump rust compiler version to nightly 2023-09-01 2023-09-12 14:27:08 -04:00
Jordan Rose
144a0037d8 Use hex! macro in more tests, rather than hex::decode + expect 2023-09-01 17:33:02 -07:00
Jordan Rose
468ea4a0b1 protocol: Simplify key derivation for multi-recipient sealed sender 2023-08-23 13:35:32 -07:00
Jordan Rose
024c618f20 protocol: Throw SessionNotFound for an expired unacknowledged session
For the most part this should happen transparently without any
explicit adoption, like the previous change, but for Java code the
NoSessionException is now properly declared on SessionCipher.encrypt.
(This was always technically possible, but clients were expected to
have previously checked for session validity before using
SessionCipher; now that there's an expiration involved, that's not
strictly possible.)
2023-08-22 17:00:35 -07:00
Jordan Rose
9ca91fe2c0 protocol: Record the timestamp when a pre-key bundle is processed 2023-08-22 17:00:35 -07:00
Jordan Rose
008fad966e protocol: Rip "Context" out of the Rust layer
Only the iOS client ever used this extra parameter, and it's one
that's easily stored alongside the reference to a store. This is
massively simpler than having it threaded down to the Rust
libsignal_protocol and back up through the bridging layer.
2023-07-27 15:40:44 -07:00
moiseev-signal
28e112bac1 Add PQXDH tests 2023-05-23 16:14:44 -07:00
Rolfe Schmidt
ff09619432 Add Kyber KEM and implement PQXDH protocol
Co-authored-by: Jordan Rose <jrose@signal.org>
Co-authored-by: Max Moiseev <moiseev@signal.org>
2023-05-09 16:44:40 -07:00
Jordan Rose
d9feb9dc96 protocol: Distinguish pre-key ID 0 from "no one-time pre-key" 2023-05-02 13:45:43 -07:00
Danny McClanahan
c8b81c9585 [#476] set imports granularity 2022-07-20 13:10:43 -07:00
Danny McClanahan
ec3c2d32bc [#289] introduce wrapper structs for DeviceId, SignedPreKeyId, and PreKeyId 2022-07-20 13:10:43 -07:00
Jordan Rose
b5da2eac9d Update Rust to nightly-2022-06-22 2022-06-24 10:56:48 -07:00
Jordan Rose
0eaedd0f08 Revert "Add a new 'needs_pni_signature' field to the session state"
This reverts commit 7d761a9744.
2022-05-25 10:38:32 -07:00
Jordan Rose
601454d201 protocol: Audit the failability of 1:1 session operations
Anything that stays within the crate gets a dedicated error type, or
no error at all if the operation cannot actually fail. The "defensive"
signatures remain for public operations.

Apart from making 'Result' more meaningful, this also keeps from
propagating low-level errors out that really indicate a corrupt
session.
2022-03-21 14:12:04 -07:00
Jordan Rose
4e0ab0b08f protocol: Collapse ProtobufDecodingError into InvalidProtobufEncoding
The former was used for errors in the protobuf format itself, while
the latter was used when the decoded protobuf failed some higher-level
precondition. But apps can't really distinguish those cases, and
neither one "should" happen in a reliable system, so this is just
defending against rare or malicious inputs.

This commit mechanically turns every prost::DecodeError into
InvalidProtobufEncoding, but the next commit will make more of a
distinction of these errors.
2022-03-18 12:07:51 -07:00
Dimitris Apostolou
f6f609242d Fix typos 2022-02-09 22:49:42 +02:00
Jordan Rose
7d761a9744 Add a new 'needs_pni_signature' field to the session state
This marks that a session is being opened by Alice to reply to Bob,
who has sent a message to Alice's phone number rather than her account
UUID. Apps can check this flag to determine if they need to include
extra information in the message content to certify that yes, this
account is the owner of this phone number. The state is automatically
cleared once the current session receives a response from Bob.
2021-12-20 10:21:31 -08:00
Jordan Rose
8c5b6af3fa Sealed sender v2: add an InvalidRegistrationId exception/error
This dedicated error is thrown when a recipient has a registration ID
that's out of the range used by Signal [0, 0x3FFF]. These IDs cannot
be encoded in the sealed sender v2 format and are not supported, even
though they don't cause any problems for 1:1 messages.
2021-08-31 13:11:10 -07:00