snow/
stateless_transportstate.rs

1use crate::{
2    cipherstate::StatelessCipherStates,
3    constants::{CIPHERKEYLEN, MAXDHLEN, MAXMSGLEN, TAGLEN},
4    error::{Error, StateProblem},
5    handshakestate::HandshakeState,
6    params::HandshakePattern,
7    utils::Toggle,
8};
9use core::{convert::TryFrom, fmt};
10
11/// A state machine encompassing the transport phase of a Noise session, using the two
12/// `CipherState`s (for sending and receiving) that were spawned from the `SymmetricState`'s
13/// `Split()` method, called after a handshake has been finished.
14///
15/// See: <https://noiseprotocol.org/noise.html#the-handshakestate-object>
16pub struct StatelessTransportState {
17    cipherstates: StatelessCipherStates,
18    pattern: HandshakePattern,
19    dh_len: usize,
20    rs: Toggle<[u8; MAXDHLEN]>,
21    initiator: bool,
22}
23
24impl StatelessTransportState {
25    pub(crate) fn new(handshake: HandshakeState) -> Result<Self, Error> {
26        if !handshake.is_handshake_finished() {
27            return Err(StateProblem::HandshakeNotFinished.into());
28        }
29
30        let dh_len = handshake.dh_len();
31        let HandshakeState { cipherstates, params, rs, initiator, .. } = handshake;
32        let pattern = params.handshake.pattern;
33
34        Ok(Self { cipherstates: cipherstates.into(), pattern, dh_len, rs, initiator })
35    }
36
37    /// Get the remote party's static public key, if available.
38    ///
39    /// Note: will return `None` if either the chosen Noise pattern
40    /// doesn't necessitate a remote static key, *or* if the remote
41    /// static key is not yet known (as can be the case in the `XX`
42    /// pattern, for example).
43    #[must_use]
44    pub fn get_remote_static(&self) -> Option<&[u8]> {
45        self.rs.get().map(|rs| &rs[..self.dh_len])
46    }
47
48    /// Construct a message from `payload` (and pending handshake tokens if in handshake state),
49    /// and write it to the `message` buffer.
50    ///
51    /// Returns the number of bytes written to `message`.
52    ///
53    /// # Errors
54    ///
55    /// Will result in `Error::Input` if the size of the output exceeds the max message
56    /// length in the Noise Protocol (65535 bytes).
57    pub fn write_message(
58        &self,
59        nonce: u64,
60        payload: &[u8],
61        message: &mut [u8],
62    ) -> Result<usize, Error> {
63        if !self.initiator && self.pattern.is_oneway() {
64            return Err(StateProblem::OneWay.into());
65        } else if payload.len() + TAGLEN > MAXMSGLEN || payload.len() + TAGLEN > message.len() {
66            return Err(Error::Input);
67        }
68
69        let cipher = if self.initiator { &self.cipherstates.0 } else { &self.cipherstates.1 };
70        cipher.encrypt(nonce, payload, message)
71    }
72
73    /// Read a noise message from `message` and write the payload to the `payload` buffer.
74    ///
75    /// Returns the number of bytes written to `payload`.
76    ///
77    /// # Errors
78    /// Will result in `Error::Input` if the message is more than 65535 bytes.
79    ///
80    /// Will result in `Error::Decrypt` if the contents couldn't be decrypted and/or the
81    /// authentication tag didn't verify.
82    ///
83    /// Will result in `StateProblem::Exhausted` if the max nonce overflows.
84    pub fn read_message(
85        &self,
86        nonce: u64,
87        payload: &[u8],
88        message: &mut [u8],
89    ) -> Result<usize, Error> {
90        if payload.len() > MAXMSGLEN {
91            Err(Error::Input)
92        } else if self.initiator && self.pattern.is_oneway() {
93            Err(StateProblem::OneWay.into())
94        } else {
95            let cipher = if self.initiator { &self.cipherstates.1 } else { &self.cipherstates.0 };
96            cipher.decrypt(nonce, payload, message)
97        }
98    }
99
100    /// Generate a new key for the egress symmetric cipher according to Section 4.2
101    /// of the Noise Specification. Synchronizing timing of rekey between initiator and
102    /// responder is the responsibility of the application, as described in Section 11.3
103    /// of the Noise Specification.
104    pub fn rekey_outgoing(&mut self) {
105        if self.initiator {
106            self.cipherstates.rekey_initiator();
107        } else {
108            self.cipherstates.rekey_responder();
109        }
110    }
111
112    /// Generate a new key for the ingress symmetric cipher according to Section 4.2
113    /// of the Noise Specification. Synchronizing timing of rekey between initiator and
114    /// responder is the responsibility of the application, as described in Section 11.3
115    /// of the Noise Specification.
116    pub fn rekey_incoming(&mut self) {
117        if self.initiator {
118            self.cipherstates.rekey_responder();
119        } else {
120            self.cipherstates.rekey_initiator();
121        }
122    }
123
124    /// Set a new key for the one or both of the initiator-egress and responder-egress symmetric ciphers.
125    pub fn rekey_manually(
126        &mut self,
127        initiator: Option<&[u8; CIPHERKEYLEN]>,
128        responder: Option<&[u8; CIPHERKEYLEN]>,
129    ) {
130        if let Some(key) = initiator {
131            self.rekey_initiator_manually(key);
132        }
133        if let Some(key) = responder {
134            self.rekey_responder_manually(key);
135        }
136    }
137
138    /// Set a new key for the initiator-egress symmetric cipher.
139    pub fn rekey_initiator_manually(&mut self, key: &[u8; CIPHERKEYLEN]) {
140        self.cipherstates.rekey_initiator_manually(key);
141    }
142
143    /// Set a new key for the responder-egress symmetric cipher.
144    pub fn rekey_responder_manually(&mut self, key: &[u8; CIPHERKEYLEN]) {
145        self.cipherstates.rekey_responder_manually(key);
146    }
147
148    /// Check if this session was started with the "initiator" role.
149    #[must_use]
150    pub fn is_initiator(&self) -> bool {
151        self.initiator
152    }
153}
154
155impl fmt::Debug for StatelessTransportState {
156    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
157        fmt.debug_struct("StatelessTransportState").finish()
158    }
159}
160
161impl TryFrom<HandshakeState> for StatelessTransportState {
162    type Error = Error;
163
164    fn try_from(old: HandshakeState) -> Result<Self, Self::Error> {
165        StatelessTransportState::new(old)
166    }
167}