1use crate::{
2 CoreError,
3 auth::{HANDSHAKE_AUTH_ED25519, HANDSHAKE_AUTH_NONE, HandshakeAuth},
4};
5
6const CONTROL_PREFIX: [u8; 4] = *b"FCTL";
7const CONTROL_VERSION: u8 = 0;
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11#[repr(u8)]
12pub enum ControlMessageKind {
13 ClientHello = 1,
15 ServerHello = 2,
17 Rekey = 3,
19 Error = 255,
21}
22
23#[derive(Clone, Debug, Eq, PartialEq)]
25pub enum ControlMessage {
26 ClientHello {
28 eph_public: [u8; 32],
30 session_salt: [u8; 32],
32 transcript_binding: [u8; 32],
34 auth: Option<HandshakeAuth>,
36 },
37 ServerHello {
39 eph_public: [u8; 32],
41 transcript_binding: [u8; 32],
43 auth: Option<HandshakeAuth>,
45 },
46 Rekey {
48 old_key_id: u8,
50 new_key_id: u8,
52 rekey_salt: [u8; 32],
54 transcript_binding: [u8; 32],
56 },
57 Error {
59 code: u16,
61 },
62}
63
64impl ControlMessage {
65 pub fn kind(&self) -> ControlMessageKind {
67 match self {
68 Self::ClientHello { .. } => ControlMessageKind::ClientHello,
69 Self::ServerHello { .. } => ControlMessageKind::ServerHello,
70 Self::Rekey { .. } => ControlMessageKind::Rekey,
71 Self::Error { .. } => ControlMessageKind::Error,
72 }
73 }
74
75 pub fn encode(&self) -> Vec<u8> {
77 let mut out = Vec::with_capacity(4 + 1 + 1 + 128);
78 out.extend_from_slice(&CONTROL_PREFIX);
79 out.push(CONTROL_VERSION);
80 out.push(self.kind() as u8);
81
82 match self {
83 Self::ClientHello {
84 eph_public,
85 session_salt,
86 transcript_binding,
87 auth,
88 } => {
89 out.extend_from_slice(eph_public);
90 out.extend_from_slice(session_salt);
91 out.extend_from_slice(transcript_binding);
92 encode_handshake_auth(&mut out, auth);
93 }
94 Self::ServerHello {
95 eph_public,
96 transcript_binding,
97 auth,
98 } => {
99 out.extend_from_slice(eph_public);
100 out.extend_from_slice(transcript_binding);
101 encode_handshake_auth(&mut out, auth);
102 }
103 Self::Rekey {
104 old_key_id,
105 new_key_id,
106 rekey_salt,
107 transcript_binding,
108 } => {
109 out.push(*old_key_id);
110 out.push(*new_key_id);
111 out.extend_from_slice(rekey_salt);
112 out.extend_from_slice(transcript_binding);
113 }
114 Self::Error { code } => {
115 out.extend_from_slice(&code.to_be_bytes());
116 }
117 }
118
119 out
120 }
121
122 pub fn decode(bytes: &[u8]) -> Result<Self, CoreError> {
124 if bytes.len() < 6 {
125 return Err(CoreError::InvalidControlMessage);
126 }
127 if bytes[0..4] != CONTROL_PREFIX {
128 return Err(CoreError::InvalidControlMessage);
129 }
130 if bytes[4] != CONTROL_VERSION {
131 return Err(CoreError::InvalidControlMessage);
132 }
133
134 let kind = bytes[5];
135 let body = &bytes[6..];
136
137 match kind {
138 x if x == ControlMessageKind::ClientHello as u8 => {
139 if body.len() != 96 && body.len() != 97 && body.len() != 193 {
140 return Err(CoreError::InvalidControlMessage);
141 }
142 let mut eph_public = [0u8; 32];
143 eph_public.copy_from_slice(&body[0..32]);
144 let mut session_salt = [0u8; 32];
145 session_salt.copy_from_slice(&body[32..64]);
146 let mut transcript_binding = [0u8; 32];
147 transcript_binding.copy_from_slice(&body[64..96]);
148 let auth = decode_handshake_auth(&body[96..])?;
149 Ok(Self::ClientHello {
150 eph_public,
151 session_salt,
152 transcript_binding,
153 auth,
154 })
155 }
156 x if x == ControlMessageKind::ServerHello as u8 => {
157 if body.len() != 64 && body.len() != 65 && body.len() != 161 {
158 return Err(CoreError::InvalidControlMessage);
159 }
160 let mut eph_public = [0u8; 32];
161 eph_public.copy_from_slice(&body[0..32]);
162 let mut transcript_binding = [0u8; 32];
163 transcript_binding.copy_from_slice(&body[32..64]);
164 let auth = decode_handshake_auth(&body[64..])?;
165 Ok(Self::ServerHello {
166 eph_public,
167 transcript_binding,
168 auth,
169 })
170 }
171 x if x == ControlMessageKind::Rekey as u8 => {
172 if body.len() != 66 {
173 return Err(CoreError::InvalidControlMessage);
174 }
175 let old_key_id = body[0];
176 let new_key_id = body[1];
177 let mut rekey_salt = [0u8; 32];
178 rekey_salt.copy_from_slice(&body[2..34]);
179 let mut transcript_binding = [0u8; 32];
180 transcript_binding.copy_from_slice(&body[34..66]);
181 Ok(Self::Rekey {
182 old_key_id,
183 new_key_id,
184 rekey_salt,
185 transcript_binding,
186 })
187 }
188 x if x == ControlMessageKind::Error as u8 => {
189 if body.len() != 2 {
190 return Err(CoreError::InvalidControlMessage);
191 }
192 let mut code_bytes = [0u8; 2];
193 code_bytes.copy_from_slice(body);
194 Ok(Self::Error {
195 code: u16::from_be_bytes(code_bytes),
196 })
197 }
198 _ => Err(CoreError::InvalidControlMessage),
199 }
200 }
201}
202
203fn encode_handshake_auth(out: &mut Vec<u8>, auth: &Option<HandshakeAuth>) {
204 match auth {
205 Some(auth) => {
206 out.push(HANDSHAKE_AUTH_ED25519);
207 out.extend_from_slice(&auth.identity_public_key);
208 out.extend_from_slice(&auth.signature);
209 }
210 None => out.push(HANDSHAKE_AUTH_NONE),
211 }
212}
213
214fn decode_handshake_auth(bytes: &[u8]) -> Result<Option<HandshakeAuth>, CoreError> {
215 if bytes.is_empty() {
216 return Ok(None);
217 }
218
219 match bytes[0] {
220 HANDSHAKE_AUTH_NONE if bytes.len() == 1 => Ok(None),
221 HANDSHAKE_AUTH_ED25519 if bytes.len() == 1 + HandshakeAuth::encoded_len() => {
222 let mut identity_public_key = [0u8; 32];
223 identity_public_key.copy_from_slice(&bytes[1..33]);
224 let mut signature = [0u8; 64];
225 signature.copy_from_slice(&bytes[33..97]);
226 Ok(Some(HandshakeAuth {
227 identity_public_key,
228 signature,
229 }))
230 }
231 _ => Err(CoreError::InvalidControlMessage),
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use super::*;
238
239 #[test]
240 fn control_roundtrip() {
241 let msg = ControlMessage::Rekey {
242 old_key_id: 1,
243 new_key_id: 2,
244 rekey_salt: [7u8; 32],
245 transcript_binding: [9u8; 32],
246 };
247 let encoded = msg.encode();
248 let decoded = ControlMessage::decode(&encoded).expect("decode");
249 assert_eq!(decoded, msg);
250 }
251}