libsignal_protocol/state/
session.rs

1//
2// Copyright 2020-2022 Signal Messenger, LLC.
3// SPDX-License-Identifier: AGPL-3.0-only
4//
5
6use std::result::Result;
7use std::time::{Duration, SystemTime};
8
9use prost::Message;
10use subtle::ConstantTimeEq;
11
12use crate::proto::storage::{session_structure, RecordStructure, SessionStructure};
13use crate::ratchet::{ChainKey, MessageKeys, RootKey};
14use crate::state::{KyberPreKeyId, PreKeyId, SignedPreKeyId};
15use crate::{consts, kem, IdentityKey, KeyPair, PrivateKey, PublicKey, SignalProtocolError};
16
17/// A distinct error type to keep from accidentally propagating deserialization errors.
18#[derive(Debug)]
19pub(crate) struct InvalidSessionError(&'static str);
20
21impl std::fmt::Display for InvalidSessionError {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        self.0.fmt(f)
24    }
25}
26
27impl From<InvalidSessionError> for SignalProtocolError {
28    fn from(e: InvalidSessionError) -> Self {
29        Self::InvalidSessionStructure(e.0)
30    }
31}
32
33#[derive(Debug, Clone)]
34pub(crate) struct UnacknowledgedPreKeyMessageItems<'a> {
35    pre_key_id: Option<PreKeyId>,
36    signed_pre_key_id: SignedPreKeyId,
37    base_key: PublicKey,
38    kyber_pre_key_id: Option<KyberPreKeyId>,
39    kyber_ciphertext: Option<&'a [u8]>,
40    timestamp: SystemTime,
41}
42
43impl<'a> UnacknowledgedPreKeyMessageItems<'a> {
44    fn new(
45        pre_key_id: Option<PreKeyId>,
46        signed_pre_key_id: SignedPreKeyId,
47        base_key: PublicKey,
48        pending_kyber_pre_key: Option<&'a session_structure::PendingKyberPreKey>,
49        timestamp: SystemTime,
50    ) -> Self {
51        let (kyber_pre_key_id, kyber_ciphertext) = pending_kyber_pre_key
52            .map(|pending| (pending.pre_key_id.into(), pending.ciphertext.as_slice()))
53            .unzip();
54        Self {
55            pre_key_id,
56            signed_pre_key_id,
57            base_key,
58            kyber_pre_key_id,
59            kyber_ciphertext,
60            timestamp,
61        }
62    }
63
64    pub(crate) fn pre_key_id(&self) -> Option<PreKeyId> {
65        self.pre_key_id
66    }
67
68    pub(crate) fn signed_pre_key_id(&self) -> SignedPreKeyId {
69        self.signed_pre_key_id
70    }
71
72    pub(crate) fn base_key(&self) -> &PublicKey {
73        &self.base_key
74    }
75
76    pub(crate) fn kyber_pre_key_id(&self) -> Option<KyberPreKeyId> {
77        self.kyber_pre_key_id
78    }
79
80    pub(crate) fn kyber_ciphertext(&self) -> Option<&'a [u8]> {
81        self.kyber_ciphertext
82    }
83
84    pub(crate) fn timestamp(&self) -> SystemTime {
85        self.timestamp
86    }
87}
88
89#[derive(Clone, Debug)]
90pub(crate) struct SessionState {
91    session: SessionStructure,
92}
93
94impl SessionState {
95    pub(crate) fn from_session_structure(session: SessionStructure) -> Self {
96        Self { session }
97    }
98
99    pub(crate) fn new(
100        version: u8,
101        our_identity: &IdentityKey,
102        their_identity: &IdentityKey,
103        root_key: &RootKey,
104        alice_base_key: &PublicKey,
105    ) -> Self {
106        Self {
107            session: SessionStructure {
108                session_version: version as u32,
109                local_identity_public: our_identity.public_key().serialize().into_vec(),
110                remote_identity_public: their_identity.serialize().into_vec(),
111                root_key: root_key.key().to_vec(),
112                previous_counter: 0,
113                sender_chain: None,
114                receiver_chains: vec![],
115                pending_pre_key: None,
116                pending_kyber_pre_key: None,
117                remote_registration_id: 0,
118                local_registration_id: 0,
119                alice_base_key: alice_base_key.serialize().into_vec(),
120            },
121        }
122    }
123
124    pub(crate) fn alice_base_key(&self) -> &[u8] {
125        // Check the length before returning?
126        &self.session.alice_base_key
127    }
128
129    pub(crate) fn session_version(&self) -> Result<u32, InvalidSessionError> {
130        match self.session.session_version {
131            0 => Ok(2),
132            v => Ok(v),
133        }
134    }
135
136    pub(crate) fn remote_identity_key(&self) -> Result<Option<IdentityKey>, InvalidSessionError> {
137        match self.session.remote_identity_public.len() {
138            0 => Ok(None),
139            _ => Ok(Some(
140                IdentityKey::decode(&self.session.remote_identity_public)
141                    .map_err(|_| InvalidSessionError("invalid remote identity key"))?,
142            )),
143        }
144    }
145
146    pub(crate) fn remote_identity_key_bytes(&self) -> Result<Option<Vec<u8>>, InvalidSessionError> {
147        Ok(self.remote_identity_key()?.map(|k| k.serialize().to_vec()))
148    }
149
150    pub(crate) fn local_identity_key(&self) -> Result<IdentityKey, InvalidSessionError> {
151        IdentityKey::decode(&self.session.local_identity_public)
152            .map_err(|_| InvalidSessionError("invalid local identity key"))
153    }
154
155    pub(crate) fn local_identity_key_bytes(&self) -> Result<Vec<u8>, InvalidSessionError> {
156        Ok(self.local_identity_key()?.serialize().to_vec())
157    }
158
159    pub(crate) fn session_with_self(&self) -> Result<bool, InvalidSessionError> {
160        if let Some(remote_id) = self.remote_identity_key_bytes()? {
161            let local_id = self.local_identity_key_bytes()?;
162            return Ok(remote_id == local_id);
163        }
164
165        // If remote ID is not set then we can't be sure but treat as non-self
166        Ok(false)
167    }
168
169    pub(crate) fn previous_counter(&self) -> u32 {
170        self.session.previous_counter
171    }
172
173    pub(crate) fn set_previous_counter(&mut self, ctr: u32) {
174        self.session.previous_counter = ctr;
175    }
176
177    pub(crate) fn root_key(&self) -> Result<RootKey, InvalidSessionError> {
178        let root_key_bytes = self.session.root_key[..]
179            .try_into()
180            .map_err(|_| InvalidSessionError("invalid root key"))?;
181        Ok(RootKey::new(root_key_bytes))
182    }
183
184    pub(crate) fn set_root_key(&mut self, root_key: &RootKey) {
185        self.session.root_key = root_key.key().to_vec();
186    }
187
188    pub(crate) fn sender_ratchet_key(&self) -> Result<PublicKey, InvalidSessionError> {
189        match self.session.sender_chain {
190            None => Err(InvalidSessionError("missing sender chain")),
191            Some(ref c) => PublicKey::deserialize(&c.sender_ratchet_key)
192                .map_err(|_| InvalidSessionError("invalid sender chain ratchet key")),
193        }
194    }
195
196    pub(crate) fn sender_ratchet_key_for_logging(&self) -> Result<String, InvalidSessionError> {
197        Ok(hex::encode(
198            self.sender_ratchet_key()?
199                .public_key_bytes()
200                .expect("no invalid public keys"),
201        ))
202    }
203
204    pub(crate) fn sender_ratchet_private_key(&self) -> Result<PrivateKey, InvalidSessionError> {
205        match self.session.sender_chain {
206            None => Err(InvalidSessionError("missing sender chain")),
207            Some(ref c) => PrivateKey::deserialize(&c.sender_ratchet_key_private)
208                .map_err(|_| InvalidSessionError("invalid sender chain private ratchet key")),
209        }
210    }
211
212    pub fn has_usable_sender_chain(&self, now: SystemTime) -> Result<bool, InvalidSessionError> {
213        if self.session.sender_chain.is_none() {
214            return Ok(false);
215        }
216        if let Some(pending_pre_key) = &self.session.pending_pre_key {
217            let creation_timestamp =
218                SystemTime::UNIX_EPOCH + Duration::from_secs(pending_pre_key.timestamp);
219            if creation_timestamp + consts::MAX_UNACKNOWLEDGED_SESSION_AGE < now {
220                return Ok(false);
221            }
222        }
223        Ok(true)
224    }
225
226    pub(crate) fn all_receiver_chain_logging_info(&self) -> Vec<(Vec<u8>, Option<u32>)> {
227        let mut results = vec![];
228        for chain in self.session.receiver_chains.iter() {
229            let sender_ratchet_public = chain.sender_ratchet_key.clone();
230
231            let chain_key_idx = chain.chain_key.as_ref().map(|chain_key| chain_key.index);
232
233            results.push((sender_ratchet_public, chain_key_idx))
234        }
235        results
236    }
237
238    pub(crate) fn get_receiver_chain(
239        &self,
240        sender: &PublicKey,
241    ) -> Result<Option<(session_structure::Chain, usize)>, InvalidSessionError> {
242        for (idx, chain) in self.session.receiver_chains.iter().enumerate() {
243            // If we compared bytes directly it would be faster, but may miss non-canonical points.
244            // It's unclear if supporting such points is desirable.
245            let chain_ratchet_key = PublicKey::deserialize(&chain.sender_ratchet_key)
246                .map_err(|_| InvalidSessionError("invalid receiver chain ratchet key"))?;
247
248            if &chain_ratchet_key == sender {
249                return Ok(Some((chain.clone(), idx)));
250            }
251        }
252
253        Ok(None)
254    }
255
256    pub(crate) fn get_receiver_chain_key(
257        &self,
258        sender: &PublicKey,
259    ) -> Result<Option<ChainKey>, InvalidSessionError> {
260        match self.get_receiver_chain(sender)? {
261            None => Ok(None),
262            Some((chain, _)) => match chain.chain_key {
263                None => Err(InvalidSessionError("missing receiver chain key")),
264                Some(c) => {
265                    let chain_key_bytes = c.key[..]
266                        .try_into()
267                        .map_err(|_| InvalidSessionError("invalid receiver chain key"))?;
268                    Ok(Some(ChainKey::new(chain_key_bytes, c.index)))
269                }
270            },
271        }
272    }
273
274    pub(crate) fn add_receiver_chain(&mut self, sender: &PublicKey, chain_key: &ChainKey) {
275        let chain_key = session_structure::chain::ChainKey {
276            index: chain_key.index(),
277            key: chain_key.key().to_vec(),
278        };
279
280        let chain = session_structure::Chain {
281            sender_ratchet_key: sender.serialize().to_vec(),
282            sender_ratchet_key_private: vec![],
283            chain_key: Some(chain_key),
284            message_keys: vec![],
285        };
286
287        self.session.receiver_chains.push(chain);
288
289        if self.session.receiver_chains.len() > consts::MAX_RECEIVER_CHAINS {
290            log::info!(
291                "Trimming excessive receiver_chain for session with base key {}, chain count: {}",
292                self.sender_ratchet_key_for_logging()
293                    .unwrap_or_else(|e| format!("<error: {}>", e.0)),
294                self.session.receiver_chains.len()
295            );
296            self.session.receiver_chains.remove(0);
297        }
298    }
299
300    pub(crate) fn with_receiver_chain(mut self, sender: &PublicKey, chain_key: &ChainKey) -> Self {
301        self.add_receiver_chain(sender, chain_key);
302        self
303    }
304
305    pub(crate) fn set_sender_chain(&mut self, sender: &KeyPair, next_chain_key: &ChainKey) {
306        let chain_key = session_structure::chain::ChainKey {
307            index: next_chain_key.index(),
308            key: next_chain_key.key().to_vec(),
309        };
310
311        let new_chain = session_structure::Chain {
312            sender_ratchet_key: sender.public_key.serialize().to_vec(),
313            sender_ratchet_key_private: sender.private_key.serialize().to_vec(),
314            chain_key: Some(chain_key),
315            message_keys: vec![],
316        };
317
318        self.session.sender_chain = Some(new_chain);
319    }
320
321    pub(crate) fn with_sender_chain(mut self, sender: &KeyPair, next_chain_key: &ChainKey) -> Self {
322        self.set_sender_chain(sender, next_chain_key);
323        self
324    }
325
326    pub(crate) fn get_sender_chain_key(&self) -> Result<ChainKey, InvalidSessionError> {
327        let sender_chain = self
328            .session
329            .sender_chain
330            .as_ref()
331            .ok_or(InvalidSessionError("missing sender chain"))?;
332
333        let chain_key = sender_chain
334            .chain_key
335            .as_ref()
336            .ok_or(InvalidSessionError("missing sender chain key"))?;
337
338        let chain_key_bytes = chain_key.key[..]
339            .try_into()
340            .map_err(|_| InvalidSessionError("invalid sender chain key"))?;
341
342        Ok(ChainKey::new(chain_key_bytes, chain_key.index))
343    }
344
345    pub(crate) fn get_sender_chain_key_bytes(&self) -> Result<Vec<u8>, InvalidSessionError> {
346        Ok(self.get_sender_chain_key()?.key().to_vec())
347    }
348
349    pub(crate) fn set_sender_chain_key(&mut self, next_chain_key: &ChainKey) {
350        let chain_key = session_structure::chain::ChainKey {
351            index: next_chain_key.index(),
352            key: next_chain_key.key().to_vec(),
353        };
354
355        // Is it actually valid to call this function with sender_chain == None?
356
357        let new_chain = match self.session.sender_chain.take() {
358            None => session_structure::Chain {
359                sender_ratchet_key: vec![],
360                sender_ratchet_key_private: vec![],
361                chain_key: Some(chain_key),
362                message_keys: vec![],
363            },
364            Some(mut c) => {
365                c.chain_key = Some(chain_key);
366                c
367            }
368        };
369
370        self.session.sender_chain = Some(new_chain);
371    }
372
373    pub(crate) fn get_message_keys(
374        &mut self,
375        sender: &PublicKey,
376        counter: u32,
377    ) -> Result<Option<MessageKeys>, InvalidSessionError> {
378        if let Some(mut chain_and_index) = self.get_receiver_chain(sender)? {
379            let message_key_idx = chain_and_index
380                .0
381                .message_keys
382                .iter()
383                .position(|m| m.index == counter);
384
385            if let Some(position) = message_key_idx {
386                let message_key = chain_and_index.0.message_keys.remove(position);
387
388                let cipher_key_bytes = message_key
389                    .cipher_key
390                    .try_into()
391                    .map_err(|_| InvalidSessionError("invalid message cipher key"))?;
392                let mac_key_bytes = message_key
393                    .mac_key
394                    .try_into()
395                    .map_err(|_| InvalidSessionError("invalid message MAC key"))?;
396                let iv_bytes = message_key
397                    .iv
398                    .try_into()
399                    .map_err(|_| InvalidSessionError("invalid message IV"))?;
400
401                let keys = MessageKeys::new(cipher_key_bytes, mac_key_bytes, iv_bytes, counter);
402
403                // Update with message key removed
404                self.session.receiver_chains[chain_and_index.1] = chain_and_index.0;
405                return Ok(Some(keys));
406            }
407        }
408
409        Ok(None)
410    }
411
412    pub(crate) fn set_message_keys(
413        &mut self,
414        sender: &PublicKey,
415        message_keys: &MessageKeys,
416    ) -> Result<(), InvalidSessionError> {
417        let new_keys = session_structure::chain::MessageKey {
418            cipher_key: message_keys.cipher_key().to_vec(),
419            mac_key: message_keys.mac_key().to_vec(),
420            iv: message_keys.iv().to_vec(),
421            index: message_keys.counter(),
422        };
423
424        let chain_and_index = self
425            .get_receiver_chain(sender)?
426            .expect("called set_message_keys for a non-existent chain");
427        let mut updated_chain = chain_and_index.0;
428        updated_chain.message_keys.insert(0, new_keys);
429
430        if updated_chain.message_keys.len() > consts::MAX_MESSAGE_KEYS {
431            updated_chain.message_keys.pop();
432        }
433
434        self.session.receiver_chains[chain_and_index.1] = updated_chain;
435
436        Ok(())
437    }
438
439    pub(crate) fn set_receiver_chain_key(
440        &mut self,
441        sender: &PublicKey,
442        chain_key: &ChainKey,
443    ) -> Result<(), InvalidSessionError> {
444        let chain_and_index = self
445            .get_receiver_chain(sender)?
446            .expect("called set_receiver_chain_key for a non-existent chain");
447        let mut updated_chain = chain_and_index.0;
448        updated_chain.chain_key = Some(session_structure::chain::ChainKey {
449            index: chain_key.index(),
450            key: chain_key.key().to_vec(),
451        });
452
453        self.session.receiver_chains[chain_and_index.1] = updated_chain;
454
455        Ok(())
456    }
457
458    pub(crate) fn set_unacknowledged_pre_key_message(
459        &mut self,
460        pre_key_id: Option<PreKeyId>,
461        signed_ec_pre_key_id: SignedPreKeyId,
462        base_key: &PublicKey,
463        now: SystemTime,
464    ) {
465        let signed_ec_pre_key_id: u32 = signed_ec_pre_key_id.into();
466        let pending = session_structure::PendingPreKey {
467            pre_key_id: pre_key_id.map(PreKeyId::into),
468            signed_pre_key_id: signed_ec_pre_key_id as i32,
469            base_key: base_key.serialize().to_vec(),
470            timestamp: now
471                .duration_since(SystemTime::UNIX_EPOCH)
472                .unwrap_or_default()
473                .as_secs(),
474        };
475        self.session.pending_pre_key = Some(pending);
476    }
477
478    #[allow(clippy::boxed_local)]
479    pub(crate) fn set_kyber_ciphertext(&mut self, ciphertext: kem::SerializedCiphertext) {
480        let pending = session_structure::PendingKyberPreKey {
481            pre_key_id: u32::MAX, // has to be set to the actual value separately
482            ciphertext: ciphertext.to_vec(),
483        };
484        self.session.pending_kyber_pre_key = Some(pending);
485    }
486
487    pub(crate) fn set_unacknowledged_kyber_pre_key_id(
488        &mut self,
489        signed_kyber_pre_key_id: KyberPreKeyId,
490    ) {
491        let pending = self
492            .session
493            .pending_kyber_pre_key
494            .as_mut()
495            .expect("must have been set if kyber pre key is present");
496        pending.pre_key_id = signed_kyber_pre_key_id.into();
497    }
498
499    pub(crate) fn unacknowledged_pre_key_message_items(
500        &self,
501    ) -> Result<Option<UnacknowledgedPreKeyMessageItems>, InvalidSessionError> {
502        if let Some(ref pending_pre_key) = self.session.pending_pre_key {
503            Ok(Some(UnacknowledgedPreKeyMessageItems::new(
504                pending_pre_key.pre_key_id.map(Into::into),
505                (pending_pre_key.signed_pre_key_id as u32).into(),
506                PublicKey::deserialize(&pending_pre_key.base_key)
507                    .map_err(|_| InvalidSessionError("invalid pending PreKey message base key"))?,
508                self.session.pending_kyber_pre_key.as_ref(),
509                SystemTime::UNIX_EPOCH + Duration::from_secs(pending_pre_key.timestamp),
510            )))
511        } else {
512            Ok(None)
513        }
514    }
515
516    pub(crate) fn clear_unacknowledged_pre_key_message(&mut self) {
517        // Explicitly destructuring the SessionStructure in case there are new
518        // pending fields that need to be cleared.
519        let SessionStructure {
520            session_version: _session_version,
521            local_identity_public: _local_identity_public,
522            remote_identity_public: _remote_identity_public,
523            root_key: _root_key,
524            previous_counter: _previous_counter,
525            sender_chain: _sender_chain,
526            receiver_chains: _receiver_chains,
527            pending_pre_key: _pending_pre_key,
528            pending_kyber_pre_key: _pending_kyber_pre_key,
529            remote_registration_id: _remote_registration_id,
530            local_registration_id: _local_registration_id,
531            alice_base_key: _alice_base_key,
532        } = &self.session;
533        // ####### IMPORTANT #######
534        // Don't forget to clean up new pending fields.
535        // ####### IMPORTANT #######
536        self.session.pending_pre_key = None;
537        self.session.pending_kyber_pre_key = None;
538    }
539
540    pub(crate) fn set_remote_registration_id(&mut self, registration_id: u32) {
541        self.session.remote_registration_id = registration_id;
542    }
543
544    pub(crate) fn remote_registration_id(&self) -> u32 {
545        self.session.remote_registration_id
546    }
547
548    pub(crate) fn set_local_registration_id(&mut self, registration_id: u32) {
549        self.session.local_registration_id = registration_id;
550    }
551
552    pub(crate) fn local_registration_id(&self) -> u32 {
553        self.session.local_registration_id
554    }
555
556    pub(crate) fn get_kyber_ciphertext(&self) -> Option<&Vec<u8>> {
557        self.session
558            .pending_kyber_pre_key
559            .as_ref()
560            .map(|pending| &pending.ciphertext)
561    }
562}
563
564impl From<SessionStructure> for SessionState {
565    fn from(value: SessionStructure) -> SessionState {
566        SessionState::from_session_structure(value)
567    }
568}
569
570impl From<SessionState> for SessionStructure {
571    fn from(value: SessionState) -> SessionStructure {
572        value.session
573    }
574}
575
576impl From<&SessionState> for SessionStructure {
577    fn from(value: &SessionState) -> SessionStructure {
578        value.session.clone()
579    }
580}
581
582#[derive(Clone)]
583pub struct SessionRecord {
584    current_session: Option<SessionState>,
585    previous_sessions: Vec<Vec<u8>>,
586}
587
588impl SessionRecord {
589    pub fn new_fresh() -> Self {
590        Self {
591            current_session: None,
592            previous_sessions: Vec::new(),
593        }
594    }
595
596    pub(crate) fn new(state: SessionState) -> Self {
597        Self {
598            current_session: Some(state),
599            previous_sessions: Vec::new(),
600        }
601    }
602
603    pub fn deserialize(bytes: &[u8]) -> Result<Self, SignalProtocolError> {
604        let record = RecordStructure::decode(bytes)
605            .map_err(|_| InvalidSessionError("failed to decode session record protobuf"))?;
606
607        Ok(Self {
608            current_session: record.current_session.map(|s| s.into()),
609            previous_sessions: record.previous_sessions,
610        })
611    }
612
613    pub(crate) fn has_session_state(
614        &self,
615        version: u32,
616        alice_base_key: &[u8],
617    ) -> Result<bool, InvalidSessionError> {
618        if let Some(current_session) = &self.current_session {
619            if current_session.session_version()? == version
620                && alice_base_key
621                    .ct_eq(current_session.alice_base_key())
622                    .into()
623            {
624                return Ok(true);
625            }
626        }
627
628        for previous in self.previous_session_states() {
629            let previous = previous?;
630            if previous.session_version()? == version
631                && alice_base_key.ct_eq(previous.alice_base_key()).into()
632            {
633                return Ok(true);
634            }
635        }
636
637        Ok(false)
638    }
639
640    pub(crate) fn session_state(&self) -> Option<&SessionState> {
641        self.current_session.as_ref()
642    }
643
644    pub(crate) fn session_state_mut(&mut self) -> Option<&mut SessionState> {
645        self.current_session.as_mut()
646    }
647
648    pub(crate) fn set_session_state(&mut self, session: SessionState) {
649        self.current_session = Some(session);
650    }
651
652    pub(crate) fn previous_session_states(
653        &self,
654    ) -> impl ExactSizeIterator<Item = Result<SessionState, InvalidSessionError>> + '_ {
655        self.previous_sessions.iter().map(|bytes| {
656            Ok(SessionStructure::decode(&bytes[..])
657                .map_err(|_| InvalidSessionError("failed to decode previous session protobuf"))?
658                .into())
659        })
660    }
661
662    pub(crate) fn promote_old_session(
663        &mut self,
664        old_session: usize,
665        updated_session: SessionState,
666    ) {
667        self.previous_sessions.remove(old_session);
668        self.promote_state(updated_session)
669    }
670
671    pub(crate) fn promote_state(&mut self, new_state: SessionState) {
672        self.archive_current_state_inner();
673        self.current_session = Some(new_state);
674    }
675
676    // A non-fallible version of archive_current_state.
677    //
678    // Returns `true` if there was a session to archive, `false` if not.
679    fn archive_current_state_inner(&mut self) -> bool {
680        if let Some(mut current_session) = self.current_session.take() {
681            if self.previous_sessions.len() >= consts::ARCHIVED_STATES_MAX_LENGTH {
682                self.previous_sessions.pop();
683            }
684            current_session.clear_unacknowledged_pre_key_message();
685            self.previous_sessions
686                .insert(0, current_session.session.encode_to_vec());
687            true
688        } else {
689            false
690        }
691    }
692
693    pub fn archive_current_state(&mut self) -> Result<(), SignalProtocolError> {
694        if !self.archive_current_state_inner() {
695            log::info!("Skipping archive, current session state is fresh");
696        }
697        Ok(())
698    }
699
700    pub fn serialize(&self) -> Result<Vec<u8>, SignalProtocolError> {
701        let record = RecordStructure {
702            current_session: self.current_session.as_ref().map(|s| s.into()),
703            previous_sessions: self.previous_sessions.clone(),
704        };
705        Ok(record.encode_to_vec())
706    }
707
708    pub fn remote_registration_id(&self) -> Result<u32, SignalProtocolError> {
709        Ok(self
710            .session_state()
711            .ok_or_else(|| {
712                SignalProtocolError::InvalidState(
713                    "remote_registration_id",
714                    "No current session".into(),
715                )
716            })?
717            .remote_registration_id())
718    }
719
720    pub fn local_registration_id(&self) -> Result<u32, SignalProtocolError> {
721        Ok(self
722            .session_state()
723            .ok_or_else(|| {
724                SignalProtocolError::InvalidState(
725                    "local_registration_id",
726                    "No current session".into(),
727                )
728            })?
729            .local_registration_id())
730    }
731
732    pub fn session_version(&self) -> Result<u32, SignalProtocolError> {
733        Ok(self
734            .session_state()
735            .ok_or_else(|| {
736                SignalProtocolError::InvalidState("session_version", "No current session".into())
737            })?
738            .session_version()?)
739    }
740
741    pub fn local_identity_key_bytes(&self) -> Result<Vec<u8>, SignalProtocolError> {
742        Ok(self
743            .session_state()
744            .ok_or_else(|| {
745                SignalProtocolError::InvalidState(
746                    "local_identity_key_bytes",
747                    "No current session".into(),
748                )
749            })?
750            .local_identity_key_bytes()?)
751    }
752
753    pub fn remote_identity_key_bytes(&self) -> Result<Option<Vec<u8>>, SignalProtocolError> {
754        Ok(self
755            .session_state()
756            .ok_or_else(|| {
757                SignalProtocolError::InvalidState(
758                    "remote_identity_key_bytes",
759                    "No current session".into(),
760                )
761            })?
762            .remote_identity_key_bytes()?)
763    }
764
765    pub fn has_usable_sender_chain(&self, now: SystemTime) -> Result<bool, SignalProtocolError> {
766        match &self.current_session {
767            Some(session) => Ok(session.has_usable_sender_chain(now)?),
768            None => Ok(false),
769        }
770    }
771
772    pub fn alice_base_key(&self) -> Result<&[u8], SignalProtocolError> {
773        Ok(self
774            .session_state()
775            .ok_or_else(|| {
776                SignalProtocolError::InvalidState("alice_base_key", "No current session".into())
777            })?
778            .alice_base_key())
779    }
780
781    pub fn get_receiver_chain_key_bytes(
782        &self,
783        sender: &PublicKey,
784    ) -> Result<Option<Box<[u8]>>, SignalProtocolError> {
785        Ok(self
786            .session_state()
787            .ok_or_else(|| {
788                SignalProtocolError::InvalidState(
789                    "get_receiver_chain_key",
790                    "No current session".into(),
791                )
792            })?
793            .get_receiver_chain_key(sender)?
794            .map(|chain| chain.key()[..].into()))
795    }
796
797    pub fn get_sender_chain_key_bytes(&self) -> Result<Vec<u8>, SignalProtocolError> {
798        Ok(self
799            .session_state()
800            .ok_or_else(|| {
801                SignalProtocolError::InvalidState(
802                    "get_sender_chain_key_bytes",
803                    "No current session".into(),
804                )
805            })?
806            .get_sender_chain_key_bytes()?)
807    }
808
809    pub fn current_ratchet_key_matches(
810        &self,
811        key: &PublicKey,
812    ) -> Result<bool, SignalProtocolError> {
813        match &self.current_session {
814            Some(session) => Ok(&session.sender_ratchet_key()? == key),
815            None => Ok(false),
816        }
817    }
818
819    pub fn get_kyber_ciphertext(&self) -> Result<Option<&Vec<u8>>, SignalProtocolError> {
820        Ok(self
821            .session_state()
822            .ok_or_else(|| {
823                SignalProtocolError::InvalidState(
824                    "get_kyber_ciphertext",
825                    "No current session".into(),
826                )
827            })?
828            .get_kyber_ciphertext())
829    }
830}