Skip to content

Commit

Permalink
describe the significance of each limit
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmicexplorer committed Dec 8, 2022
1 parent a144357 commit f657c79
Showing 1 changed file with 55 additions and 10 deletions.
65 changes: 55 additions & 10 deletions rust/protocol/src/limits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,70 @@

//! Various positive integers bounding the maximum size of other data structures.
/// The maximum number of encrypted messages that the client chain which decrypts Signal
/// messages in a [Double Ratchet] instance can retrieve at once (tracked in
/// [crate::proto::storage::session_structure::chain::ChainKey::index] as well as a separate
/// `counter`).
/// The maximum number of dropped messages to allow in a row before reporting an error.
///
/// A Signal client session allows for out-of-order and dropped messages by providing a "chain
/// index" along with each message (tracked in
/// [`ChainKey::index`](crate::proto::storage::session_structure::chain::ChainKey::index)). Each
/// time the session iterates its ratcheting KDF, it increments a local integer counter, and
/// associates the resulting key material with the value of that counter in that session's key
/// store. This technique is used in the [Double Ratchet] protocol from
/// [`message_decrypt_prekey()`](crate::session_cipher::message_decrypt_prekey), as well as the
/// single ratchet sender key protocol in [`group_decrypt()`](crate::group_cipher::group_decrypt).
///
/// When the session receives a new message, it looks up the chain index provided with that message
/// to obtain the appropriate key material. If the chain index is greater than the value of the
/// local counter, then the session must iterate its ratcheting KDF until it produces the key
/// material for the specified chain index. The session stores all of the intermediate keys
/// generated by this process in between its previous counter and the new chain index, so that it
/// can decrypt any out-of-order messages that come later.
///
/// As a result, if a message is modified to provide an extremely large chain index, it could force
/// a session to fill up its key store with a huge number of entries, which could induce
/// a denial-of-service. Instead, if the session needs to iterate its ratcheting KDF more than this
/// limit, it bails out of attempting to decrypt the message, and instead returns an error.
///
/// [Double Ratchet]: https://signal.org/docs/specifications/doubleratchet/
pub const MAX_FORWARD_JUMPS: usize = 25_000;
/// The maximum number of per-message keys that can be retained to decrypt messages within
/// a specific chain from `message_keys` in [crate::proto::storage::session_structure::Chain].

/// The maximum number of per-message keys retained by a session to decrypt previous messages, in
/// case messages arrive out of order or missing.
///
/// As described in [`MAX_FORWARD_JUMPS`], the session retains a local database of key material
/// obtained by iterating a ratcheting KDF. Each time the ratcheting KDF is iterated, the session
/// increments a counter and adds an entry to its key store associated with that counter. When the
/// number of stored entries exceeds this limit, the session begins to evict the oldest entry from
/// its key store each time the ratcheting KDF is iterated to produce a new entry.
///
/// This limit therefore bounds the amount of memory consumed by any session's key store so that an
/// attacker can't induce a denial-of-service by modifying a message's chain index.
pub const MAX_MESSAGE_KEYS: usize = 2000;
/// The maximum number of temporary backup chains to allow for `receiver_chains` in
/// [crate::proto::storage::SessionStructure]. These backup chains corresponds to the [Sesame]
/// protocol for syncing a Double Ratchet chain between two users.

/// The maximum number of backup chains to retain for out-of-order messages from a double
/// ratchet session.
///
/// In the [Double Ratchet] protocol, individual message keys are generated not just from the output
/// of a a ratcheting KDF, but also from a [DH] secret shared between both clients via the
/// [`SignalMessage::sender_ratchet_key()`](crate::protocol::SignalMessage::sender_ratchet_key)
/// field of each successive message. This means that unlike the sender key single ratchet method,
/// each chain of double ratchet message keys has an additional chunk of ratcheting state that gets
/// sent back and forth between participants, which can't be idempotently reproduced by just
/// iterating a single KDF.
///
/// In order to support out-of-order messages (and therefore out-of-order DH secrets), the double
/// ratchet session maintains multiple chains of contiguous messages. Similarly to
/// [`MAX_MESSAGE_KEYS`], this limit bounds the number of such chains to retain, and therefore
/// bounds the memory consumed by a session's key store so an attacker can't induce
/// a denial-of-service by modifying a message's DH field.
///
/// [Sesame]: https://signal.org/docs/specifications/sesame/#server
/// [Double Ratchet]: https://signal.org/docs/specifications/doubleratchet/
/// [DH]: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
pub const MAX_RECEIVER_CHAINS: usize = 5;

/// The maximum number of sessions allowed for
/// [crate::proto::storage::RecordStructure::previous_sessions].
pub const ARCHIVED_STATES_MAX_LENGTH: usize = 40;

/// The maximum number of sender key states allowed for
/// [crate::proto::storage::SenderKeyRecordStructure::sender_key_states].
pub const MAX_SENDER_KEY_STATES: usize = 5;

0 comments on commit f657c79

Please sign in to comment.