snow/
transportstate.rs

1use crate::{
2    cipherstate::CipherStates,
3    constants::{MAXDHLEN, MAXMSGLEN, TAGLEN},
4    error::{Error, StateProblem},
5    handshakestate::HandshakeState,
6    params::HandshakePattern,
7    utils::Toggle,
8};
9use std::{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/// Also see: [the relevant Noise spec section](https://noiseprotocol.org/noise.html#the-handshakestate-object).
16pub struct TransportState {
17    cipherstates: CipherStates,
18    pattern:      HandshakePattern,
19    dh_len:       usize,
20    rs:           Toggle<[u8; MAXDHLEN]>,
21    initiator:    bool,
22}
23
24impl TransportState {
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(TransportState { cipherstates, 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    pub fn get_remote_static(&self) -> Option<&[u8]> {
44        self.rs.get().map(|rs| &rs[..self.dh_len])
45    }
46
47    /// Construct a message from `payload` (and pending handshake tokens if in handshake state),
48    /// and writes it to the `output` buffer.
49    ///
50    /// Returns the size of the written payload.
51    ///
52    /// # Errors
53    ///
54    /// Will result in `Error::Input` if the size of the output exceeds the max message
55    /// length in the Noise Protocol (65535 bytes).
56    pub fn write_message(&mut self, payload: &[u8], message: &mut [u8]) -> Result<usize, Error> {
57        if !self.initiator && self.pattern.is_oneway() {
58            return Err(StateProblem::OneWay.into());
59        } else if payload.len() + TAGLEN > MAXMSGLEN || payload.len() + TAGLEN > message.len() {
60            return Err(Error::Input);
61        }
62
63        let cipher =
64            if self.initiator { &mut self.cipherstates.0 } else { &mut self.cipherstates.1 };
65        cipher.encrypt(payload, message)
66    }
67
68    /// Reads a noise message from `input`
69    ///
70    /// Returns the size of the payload written to `payload`.
71    ///
72    /// # Errors
73    ///
74    /// Will result in `Error::Decrypt` if the contents couldn't be decrypted and/or the
75    /// authentication tag didn't verify.
76    ///
77    /// Will result in `StateProblem::Exhausted` if the max nonce overflows.
78    pub fn read_message(&mut self, payload: &[u8], message: &mut [u8]) -> Result<usize, Error> {
79        if payload.len() > MAXMSGLEN {
80            Err(Error::Input)
81        } else if self.initiator && self.pattern.is_oneway() {
82            Err(StateProblem::OneWay.into())
83        } else {
84            let cipher =
85                if self.initiator { &mut self.cipherstates.1 } else { &mut self.cipherstates.0 };
86            cipher.decrypt(payload, message)
87        }
88    }
89
90    /// Generates a new key for the egress symmetric cipher according to Section 4.2
91    /// of the Noise Specification. Synchronizing timing of rekey between initiator and
92    /// responder is the responsibility of the application, as described in Section 11.3
93    /// of the Noise Specification.
94    pub fn rekey_outgoing(&mut self) {
95        if self.initiator {
96            self.cipherstates.rekey_initiator()
97        } else {
98            self.cipherstates.rekey_responder()
99        }
100    }
101
102    /// Generates a new key for the ingress symmetric cipher according to Section 4.2
103    /// of the Noise Specification. Synchronizing timing of rekey between initiator and
104    /// responder is the responsibility of the application, as described in Section 11.3
105    /// of the Noise Specification.
106    pub fn rekey_incoming(&mut self) {
107        if self.initiator {
108            self.cipherstates.rekey_responder()
109        } else {
110            self.cipherstates.rekey_initiator()
111        }
112    }
113
114    /// Set a new key for the one or both of the initiator-egress and responder-egress symmetric ciphers.
115    pub fn rekey_manually(&mut self, initiator: Option<&[u8]>, responder: Option<&[u8]>) {
116        if let Some(key) = initiator {
117            self.rekey_initiator_manually(key);
118        }
119        if let Some(key) = responder {
120            self.rekey_responder_manually(key);
121        }
122    }
123
124    /// Set a new key for the initiator-egress symmetric cipher.
125    pub fn rekey_initiator_manually(&mut self, key: &[u8]) {
126        self.cipherstates.rekey_initiator_manually(key)
127    }
128
129    /// Set a new key for the responder-egress symmetric cipher.
130    pub fn rekey_responder_manually(&mut self, key: &[u8]) {
131        self.cipherstates.rekey_responder_manually(key)
132    }
133
134    /// Sets the *receiving* CipherState's nonce. Useful for using noise on lossy transports.
135    pub fn set_receiving_nonce(&mut self, nonce: u64) {
136        if self.initiator {
137            self.cipherstates.1.set_nonce(nonce);
138        } else {
139            self.cipherstates.0.set_nonce(nonce);
140        }
141    }
142
143    /// Get the forthcoming inbound nonce value.
144    ///
145    /// # Errors
146    ///
147    /// Will result in `Error::State` if not in transport mode.
148    pub fn receiving_nonce(&self) -> u64 {
149        if self.initiator {
150            self.cipherstates.1.nonce()
151        } else {
152            self.cipherstates.0.nonce()
153        }
154    }
155
156    /// Get the forthcoming outbound nonce value.
157    ///
158    /// # Errors
159    ///
160    /// Will result in `Error::State` if not in transport mode.
161    pub fn sending_nonce(&self) -> u64 {
162        if self.initiator {
163            self.cipherstates.0.nonce()
164        } else {
165            self.cipherstates.1.nonce()
166        }
167    }
168
169    /// Check if this session was started with the "initiator" role.
170    pub fn is_initiator(&self) -> bool {
171        self.initiator
172    }
173}
174
175impl fmt::Debug for TransportState {
176    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
177        fmt.debug_struct("TransportState").finish()
178    }
179}
180
181impl TryFrom<HandshakeState> for TransportState {
182    type Error = Error;
183
184    fn try_from(old: HandshakeState) -> Result<Self, Self::Error> {
185        TransportState::new(old)
186    }
187}