bitwarden_ipc/crypto_provider/noise/
handshake.rs1use std::fmt::{Display, Formatter};
16
17use serde::{Deserialize, Serialize};
18
19use crate::crypto_provider::noise::transport_state::{
20 PersistentTransportState, SymmetricKey, TransportCipher,
21};
22
23#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
24pub(crate) enum CipherSuite {
25 #[allow(non_camel_case_types)]
26 Noise_NN_25519_ChaChaPoly_BLAKE2s,
27 #[allow(non_camel_case_types)]
28 #[default]
29 Noise_NN_25519_AESGCM_SHA256,
30}
31
32impl CipherSuite {
33 pub(crate) fn transport_cipher(&self) -> TransportCipher {
35 match self {
36 Self::Noise_NN_25519_ChaChaPoly_BLAKE2s => TransportCipher::ChaCha20Poly1305,
37 Self::Noise_NN_25519_AESGCM_SHA256 => TransportCipher::Aes256Gcm,
38 }
39 }
40}
41
42impl Display for CipherSuite {
43 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
44 match self {
45 Self::Noise_NN_25519_ChaChaPoly_BLAKE2s => {
46 write!(f, "Noise_NN_25519_ChaChaPoly_BLAKE2s")
47 }
48 Self::Noise_NN_25519_AESGCM_SHA256 => {
49 write!(f, "Noise_NN_25519_AESGCM_SHA256")
50 }
51 }
52 }
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub(crate) struct HandshakeStartMessage {
57 pub(super) ciphersuite: CipherSuite,
58 pub(super) noise_frame: Vec<u8>,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
62#[serde(transparent)]
63pub(crate) struct HandshakeFinishMessage {
64 pub(super) noise_frame: Vec<u8>,
65}
66
67pub(crate) struct HandshakeInitiator {
68 ciphersuite: CipherSuite,
69 state: snow::HandshakeState,
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub(crate) struct WriteError;
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq)]
76pub(crate) struct ReadError;
77
78impl HandshakeInitiator {
79 pub(crate) fn new(ciphersuite: &CipherSuite) -> Self {
80 let builder = snow::Builder::new(
81 ciphersuite
82 .to_string()
83 .parse()
84 .expect("Ciphersuite should be valid"),
85 );
86 let handshake_state = builder
87 .build_initiator()
88 .expect("Handshake state should be buildable");
89 Self {
90 ciphersuite: *ciphersuite,
91 state: handshake_state,
92 }
93 }
94
95 pub(crate) fn write_start_message(&mut self) -> Result<HandshakeStartMessage, WriteError> {
96 let mut buf = [0u8; super::NOISE_MAX_MESSAGE_LEN];
97 let len = self
98 .state
99 .write_message(&[], &mut buf)
100 .map_err(|_| WriteError)?;
101 Ok(HandshakeStartMessage {
102 ciphersuite: self.ciphersuite,
103 noise_frame: buf[..len].to_vec(),
104 })
105 }
106
107 pub(crate) fn read_response_message(
108 &mut self,
109 message: &HandshakeFinishMessage,
110 ) -> Result<(), ReadError> {
111 let mut buf = [0u8; super::NOISE_MAX_MESSAGE_LEN];
112 self.state
113 .read_message(&message.noise_frame, &mut buf)
114 .map_err(|_| ReadError)?;
115 Ok(())
116 }
117}
118
119impl From<&mut HandshakeInitiator> for PersistentTransportState {
120 fn from(initiator: &mut HandshakeInitiator) -> Self {
121 let (i2r, r2i) = initiator.state.dangerously_get_raw_split();
122 PersistentTransportState::new(
123 SymmetricKey(i2r),
124 SymmetricKey(r2i),
125 initiator.ciphersuite.transport_cipher(),
126 )
127 }
128}
129
130pub(crate) struct HandshakeResponder {
131 ciphersuite: CipherSuite,
132 state: snow::HandshakeState,
133}
134
135impl HandshakeResponder {
136 pub(crate) fn new(ciphersuite: &CipherSuite) -> Self {
137 let builder = snow::Builder::new(
138 ciphersuite
139 .to_string()
140 .parse()
141 .expect("Ciphersuite should be valid"),
142 );
143 let handshake_state = builder
144 .build_responder()
145 .expect("Handshake state should be buildable");
146 Self {
147 ciphersuite: *ciphersuite,
148 state: handshake_state,
149 }
150 }
151
152 pub(crate) fn read_start_message(
153 &mut self,
154 message: &HandshakeStartMessage,
155 ) -> Result<(), ReadError> {
156 let mut buf = [0u8; super::NOISE_MAX_MESSAGE_LEN];
157 self.state
158 .read_message(&message.noise_frame, &mut buf)
159 .map_err(|_| ReadError)?;
160 Ok(())
161 }
162
163 pub(crate) fn write_response_message(&mut self) -> Result<HandshakeFinishMessage, WriteError> {
164 let mut buf = [0u8; super::NOISE_MAX_MESSAGE_LEN];
165 let len = self
166 .state
167 .write_message(&[], &mut buf)
168 .map_err(|_| WriteError)?;
169 Ok(HandshakeFinishMessage {
170 noise_frame: buf[..len].to_vec(),
171 })
172 }
173}
174
175impl From<&mut HandshakeResponder> for PersistentTransportState {
176 fn from(responder: &mut HandshakeResponder) -> Self {
177 let (i2r, r2i) = responder.state.dangerously_get_raw_split();
178 PersistentTransportState::new(
179 SymmetricKey(r2i),
180 SymmetricKey(i2r),
181 responder.ciphersuite.transport_cipher(),
182 )
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189 use crate::crypto_provider::noise::transport_state::assert_matching_pair;
190
191 #[test]
192 fn test_handshake() {
193 let mut initiator = HandshakeInitiator::new(&CipherSuite::default());
194 let mut responder = HandshakeResponder::new(&CipherSuite::default());
195
196 let init_message = initiator.write_start_message().unwrap();
197 responder.read_start_message(&init_message).unwrap();
198 let response_message = responder.write_response_message().unwrap();
199 initiator.read_response_message(&response_message).unwrap();
200
201 let initiator_transport_state = (&mut initiator).into();
202 let responder_transport_state = (&mut responder).into();
203 assert_matching_pair(&initiator_transport_state, &responder_transport_state);
204 }
205}