libsignal_protocol/storage/
traits.rs

1//
2// Copyright 2020-2022 Signal Messenger, LLC.
3// SPDX-License-Identifier: AGPL-3.0-only
4//
5
6//! Traits defining several stores used throughout the Signal Protocol.
7
8use async_trait::async_trait;
9use uuid::Uuid;
10
11use crate::error::Result;
12use crate::sender_keys::SenderKeyRecord;
13use crate::state::{
14    KyberPreKeyId, KyberPreKeyRecord, PreKeyId, PreKeyRecord, SessionRecord, SignedPreKeyId,
15    SignedPreKeyRecord,
16};
17use crate::{IdentityKey, IdentityKeyPair, ProtocolAddress};
18
19// TODO: consider moving this enum into utils.rs?
20/// Each Signal message can be considered to have exactly two participants, a sender and receiver.
21///
22/// [IdentityKeyStore::is_trusted_identity] uses this to ensure the identity provided is configured
23/// for the appropriate role.
24#[derive(Debug, Clone, Eq, PartialEq)]
25pub enum Direction {
26    /// We are in the context of sending a message.
27    Sending,
28    /// We are in the context of receiving a message.
29    Receiving,
30}
31
32/// Interface defining the identity store, which may be in-memory, on-disk, etc.
33///
34/// Signal clients usually use the identity store in a [TOFU] manner, but this is not required.
35///
36/// [TOFU]: https://en.wikipedia.org/wiki/Trust_on_first_use
37#[async_trait(?Send)]
38pub trait IdentityKeyStore {
39    /// Return the single specific identity the store is assumed to represent, with private key.
40    async fn get_identity_key_pair(&self) -> Result<IdentityKeyPair>;
41
42    /// Return a [u32] specific to this store instance.
43    ///
44    /// This local registration id is separate from the per-device identifier used in
45    /// [ProtocolAddress] and should not change run over run.
46    ///
47    /// If the same *device* is unregistered, then registers again, the [ProtocolAddress::device_id]
48    /// may be the same, but the store registration id returned by this method should
49    /// be regenerated.
50    async fn get_local_registration_id(&self) -> Result<u32>;
51
52    // TODO: make this into an enum instead of a bool!
53    /// Record an identity into the store. The identity is then considered "trusted".
54    ///
55    /// The return value represents whether an existing identity was replaced (`Ok(true)`). If it is
56    /// new or hasn't changed, the return value should be `Ok(false)`.
57    async fn save_identity(
58        &mut self,
59        address: &ProtocolAddress,
60        identity: &IdentityKey,
61    ) -> Result<bool>;
62
63    /// Return whether an identity is trusted for the role specified by `direction`.
64    async fn is_trusted_identity(
65        &self,
66        address: &ProtocolAddress,
67        identity: &IdentityKey,
68        direction: Direction,
69    ) -> Result<bool>;
70
71    /// Return the public identity for the given `address`, if known.
72    async fn get_identity(&self, address: &ProtocolAddress) -> Result<Option<IdentityKey>>;
73}
74
75/// Interface for storing pre-keys downloaded from a server.
76#[async_trait(?Send)]
77pub trait PreKeyStore {
78    /// Look up the pre-key corresponding to `prekey_id`.
79    async fn get_pre_key(&self, prekey_id: PreKeyId) -> Result<PreKeyRecord>;
80
81    /// Set the entry for `prekey_id` to the value of `record`.
82    async fn save_pre_key(&mut self, prekey_id: PreKeyId, record: &PreKeyRecord) -> Result<()>;
83
84    /// Remove the entry for `prekey_id`.
85    async fn remove_pre_key(&mut self, prekey_id: PreKeyId) -> Result<()>;
86}
87
88/// Interface for storing signed pre-keys downloaded from a server.
89#[async_trait(?Send)]
90pub trait SignedPreKeyStore {
91    /// Look up the signed pre-key corresponding to `signed_prekey_id`.
92    async fn get_signed_pre_key(
93        &self,
94        signed_prekey_id: SignedPreKeyId,
95    ) -> Result<SignedPreKeyRecord>;
96
97    /// Set the entry for `signed_prekey_id` to the value of `record`.
98    async fn save_signed_pre_key(
99        &mut self,
100        signed_prekey_id: SignedPreKeyId,
101        record: &SignedPreKeyRecord,
102    ) -> Result<()>;
103}
104
105/// Interface for storing signed Kyber pre-keys downloaded from a server.
106///
107/// NB: libsignal makes no distinction between one-time and last-resort pre-keys.
108#[async_trait(?Send)]
109pub trait KyberPreKeyStore {
110    /// Look up the signed kyber pre-key corresponding to `kyber_prekey_id`.
111    async fn get_kyber_pre_key(&self, kyber_prekey_id: KyberPreKeyId) -> Result<KyberPreKeyRecord>;
112
113    /// Set the entry for `kyber_prekey_id` to the value of `record`.
114    async fn save_kyber_pre_key(
115        &mut self,
116        kyber_prekey_id: KyberPreKeyId,
117        record: &KyberPreKeyRecord,
118    ) -> Result<()>;
119
120    /// Mark the entry for `kyber_prekey_id` as "used".
121    /// This would mean different things for one-time and last-resort Kyber keys.
122    async fn mark_kyber_pre_key_used(&mut self, kyber_prekey_id: KyberPreKeyId) -> Result<()>;
123}
124
125/// Interface for a Signal client instance to store a session associated with another particular
126/// separate Signal client instance.
127///
128/// This [SessionRecord] object between a pair of Signal clients is used to drive the state for the
129/// forward-secret message chain in the [Double Ratchet] protocol.
130///
131/// [Double Ratchet]: https://signal.org/docs/specifications/doubleratchet/
132#[async_trait(?Send)]
133pub trait SessionStore {
134    /// Look up the session corresponding to `address`.
135    async fn load_session(&self, address: &ProtocolAddress) -> Result<Option<SessionRecord>>;
136
137    /// Set the entry for `address` to the value of `record`.
138    async fn store_session(
139        &mut self,
140        address: &ProtocolAddress,
141        record: &SessionRecord,
142    ) -> Result<()>;
143}
144
145/// Interface for storing sender key records, allowing multiple keys per user.
146#[async_trait(?Send)]
147pub trait SenderKeyStore {
148    /// Assign `record` to the entry for `(sender, distribution_id)`.
149    async fn store_sender_key(
150        &mut self,
151        sender: &ProtocolAddress,
152        distribution_id: Uuid,
153        // TODO: pass this by value!
154        record: &SenderKeyRecord,
155    ) -> Result<()>;
156
157    /// Look up the entry corresponding to `(sender, distribution_id)`.
158    async fn load_sender_key(
159        &mut self,
160        sender: &ProtocolAddress,
161        distribution_id: Uuid,
162    ) -> Result<Option<SenderKeyRecord>>;
163}
164
165/// Mixes in all the store interfaces defined in this module.
166pub trait ProtocolStore:
167    SessionStore + PreKeyStore + SignedPreKeyStore + KyberPreKeyStore + IdentityKeyStore
168{
169}