1#[cfg(feature = "alloc")]
8use alloc::vec::Vec;
9
10use super::{
11 cipher::{
12 constant_time_eq, derive_secret, hkdf_expand_label, hkdf_extract, hmac_sha256,
13 x25519_keypair, x25519_shared_secret,
14 },
15 CipherSuite, HASH_LEN, TLS_13_VERSION, TLS_LEGACY_VERSION, X25519_KEY_LEN,
16};
17use crate::crypto::hash::{sha256, Hash256};
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25#[repr(u8)]
26pub enum HandshakeType {
27 ClientHello = 1,
28 ServerHello = 2,
29 EncryptedExtensions = 8,
30 Certificate = 11,
31 CertificateVerify = 15,
32 Finished = 20,
33 NewSessionTicket = 4,
34}
35
36impl HandshakeType {
37 pub(crate) fn from_u8(v: u8) -> Option<Self> {
38 match v {
39 1 => Some(Self::ClientHello),
40 2 => Some(Self::ServerHello),
41 8 => Some(Self::EncryptedExtensions),
42 11 => Some(Self::Certificate),
43 15 => Some(Self::CertificateVerify),
44 20 => Some(Self::Finished),
45 4 => Some(Self::NewSessionTicket),
46 _ => None,
47 }
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53#[repr(u16)]
54pub enum SignatureScheme {
55 EcdsaSecp256r1Sha256 = 0x0403,
56 RsaPssRsaeSha256 = 0x0804,
57 Ed25519 = 0x0807,
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62#[repr(u16)]
63pub enum NamedGroup {
64 X25519 = 0x001D,
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub enum HandshakeState {
70 Start,
72 WaitServerHello,
74 WaitEncryptedExtensions,
76 WaitCertificate,
78 WaitCertificateVerify,
80 WaitFinished,
82 Connected,
84 Error,
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90#[repr(u16)]
91enum ExtensionType {
92 SupportedVersions = 43,
93 KeyShare = 51,
94 SignatureAlgorithms = 13,
95 SupportedGroups = 10,
96 PreSharedKey = 41,
97 EarlyData = 42,
98}
99
100pub struct ClientHello {
106 pub random: [u8; 32],
107 pub session_id: [u8; 32],
108 pub cipher_suites: Vec<CipherSuite>,
109 pub key_share_public: [u8; X25519_KEY_LEN],
110}
111
112impl ClientHello {
113 pub fn encode(&self) -> Vec<u8> {
115 let mut msg = Vec::with_capacity(256);
116
117 msg.push(HandshakeType::ClientHello as u8);
119 msg.extend_from_slice(&[0, 0, 0]); msg.extend_from_slice(&TLS_LEGACY_VERSION.to_be_bytes());
123
124 msg.extend_from_slice(&self.random);
126
127 msg.push(32);
129 msg.extend_from_slice(&self.session_id);
130
131 let cs_len = (self.cipher_suites.len() * 2) as u16;
133 msg.extend_from_slice(&cs_len.to_be_bytes());
134 for cs in &self.cipher_suites {
135 msg.extend_from_slice(&cs.code().to_be_bytes());
136 }
137
138 msg.push(1); msg.push(0); let ext_start = msg.len();
144 msg.extend_from_slice(&[0, 0]); msg.extend_from_slice(&(ExtensionType::SupportedVersions as u16).to_be_bytes());
148 msg.extend_from_slice(&3u16.to_be_bytes()); msg.push(2); msg.extend_from_slice(&TLS_13_VERSION.to_be_bytes());
151
152 msg.extend_from_slice(&(ExtensionType::SupportedGroups as u16).to_be_bytes());
154 msg.extend_from_slice(&4u16.to_be_bytes()); msg.extend_from_slice(&2u16.to_be_bytes()); msg.extend_from_slice(&(NamedGroup::X25519 as u16).to_be_bytes());
157
158 msg.extend_from_slice(&(ExtensionType::SignatureAlgorithms as u16).to_be_bytes());
160 msg.extend_from_slice(&8u16.to_be_bytes()); msg.extend_from_slice(&6u16.to_be_bytes()); msg.extend_from_slice(&(SignatureScheme::EcdsaSecp256r1Sha256 as u16).to_be_bytes());
163 msg.extend_from_slice(&(SignatureScheme::RsaPssRsaeSha256 as u16).to_be_bytes());
164 msg.extend_from_slice(&(SignatureScheme::Ed25519 as u16).to_be_bytes());
165
166 let _ks_ext_len = 2 + 2 + 1 + X25519_KEY_LEN; let ks_entry_len = 2 + 2 + X25519_KEY_LEN; msg.extend_from_slice(&(ExtensionType::KeyShare as u16).to_be_bytes());
171 msg.extend_from_slice(&((2 + ks_entry_len) as u16).to_be_bytes()); msg.extend_from_slice(&(ks_entry_len as u16).to_be_bytes()); msg.extend_from_slice(&(NamedGroup::X25519 as u16).to_be_bytes());
174 msg.extend_from_slice(&(X25519_KEY_LEN as u16).to_be_bytes());
175 msg.extend_from_slice(&self.key_share_public);
176
177 let ext_len = (msg.len() - ext_start - 2) as u16;
179 msg[ext_start..ext_start + 2].copy_from_slice(&ext_len.to_be_bytes());
180
181 let hs_len = msg.len() - 4;
183 msg[1] = ((hs_len >> 16) & 0xFF) as u8;
184 msg[2] = ((hs_len >> 8) & 0xFF) as u8;
185 msg[3] = (hs_len & 0xFF) as u8;
186
187 msg
188 }
189}
190
191#[derive(Debug, Clone)]
193pub struct ServerHello {
194 pub random: [u8; 32],
195 pub session_id: Vec<u8>,
196 pub cipher_suite: CipherSuite,
197 pub key_share_public: [u8; X25519_KEY_LEN],
198}
199
200impl ServerHello {
201 pub fn decode(data: &[u8]) -> Option<Self> {
203 if data.len() < 4 {
204 return None;
205 }
206 let payload = &data[4..];
208 if payload.len() < 2 + 32 + 1 {
209 return None;
210 }
211
212 let mut pos = 0;
213
214 pos += 2;
216
217 let mut random = [0u8; 32];
219 random.copy_from_slice(&payload[pos..pos + 32]);
220 pos += 32;
221
222 let sid_len = payload[pos] as usize;
224 pos += 1;
225 if pos + sid_len > payload.len() {
226 return None;
227 }
228 let session_id = payload[pos..pos + sid_len].to_vec();
229 pos += sid_len;
230
231 if pos + 2 > payload.len() {
233 return None;
234 }
235 let cs_code = u16::from_be_bytes([payload[pos], payload[pos + 1]]);
236 let cipher_suite = CipherSuite::from_code(cs_code)?;
237 pos += 2;
238
239 if pos >= payload.len() {
241 return None;
242 }
243 pos += 1;
244
245 if pos + 2 > payload.len() {
247 return None;
248 }
249 let ext_len = u16::from_be_bytes([payload[pos], payload[pos + 1]]) as usize;
250 pos += 2;
251
252 let ext_end = pos + ext_len;
253 if ext_end > payload.len() {
254 return None;
255 }
256
257 let mut key_share_public = [0u8; X25519_KEY_LEN];
258 let mut found_key_share = false;
259
260 while pos + 4 <= ext_end {
262 let ext_type = u16::from_be_bytes([payload[pos], payload[pos + 1]]);
263 let ext_data_len = u16::from_be_bytes([payload[pos + 2], payload[pos + 3]]) as usize;
264 pos += 4;
265
266 if pos + ext_data_len > ext_end {
267 break;
268 }
269
270 if ext_type == ExtensionType::KeyShare as u16 {
271 if ext_data_len >= 4 + X25519_KEY_LEN {
273 let _group = u16::from_be_bytes([payload[pos], payload[pos + 1]]);
274 let kx_len = u16::from_be_bytes([payload[pos + 2], payload[pos + 3]]) as usize;
275 if kx_len == X25519_KEY_LEN && pos + 4 + kx_len <= ext_end {
276 key_share_public.copy_from_slice(&payload[pos + 4..pos + 4 + kx_len]);
277 found_key_share = true;
278 }
279 }
280 }
281 pos += ext_data_len;
285 }
286
287 if !found_key_share {
288 return None;
289 }
290
291 Some(Self {
292 random,
293 session_id,
294 cipher_suite,
295 key_share_public,
296 })
297 }
298}
299
300pub struct HandshakeEngine {
306 pub state: HandshakeState,
307 transcript: Vec<u8>,
309 pub cipher_suite: Option<CipherSuite>,
311 client_private_key: [u8; X25519_KEY_LEN],
313 client_public_key: [u8; X25519_KEY_LEN],
315 server_public_key: Option<[u8; X25519_KEY_LEN]>,
317 pub handshake_secret: Option<[u8; HASH_LEN]>,
319 pub client_hs_traffic_secret: Option<[u8; HASH_LEN]>,
321 pub server_hs_traffic_secret: Option<[u8; HASH_LEN]>,
323 pub client_app_traffic_secret: Option<[u8; HASH_LEN]>,
325 pub server_app_traffic_secret: Option<[u8; HASH_LEN]>,
327 pub peer_certificate: Option<Vec<u8>>,
329}
330
331impl Default for HandshakeEngine {
332 fn default() -> Self {
333 Self::new()
334 }
335}
336
337impl HandshakeEngine {
338 pub fn new() -> Self {
340 let (private_key, public_key) = x25519_keypair();
341 Self {
342 state: HandshakeState::Start,
343 transcript: Vec::new(),
344 cipher_suite: None,
345 client_private_key: private_key,
346 client_public_key: public_key,
347 server_public_key: None,
348 handshake_secret: None,
349 client_hs_traffic_secret: None,
350 server_hs_traffic_secret: None,
351 client_app_traffic_secret: None,
352 server_app_traffic_secret: None,
353 peer_certificate: None,
354 }
355 }
356
357 pub fn build_client_hello(&mut self, random: [u8; 32]) -> Option<Vec<u8>> {
359 if self.state != HandshakeState::Start {
360 return None;
361 }
362
363 let ch = ClientHello {
364 random,
365 session_id: [0u8; 32], cipher_suites: alloc::vec![
367 CipherSuite::Aes128GcmSha256,
368 CipherSuite::ChaCha20Poly1305Sha256,
369 ],
370 key_share_public: self.client_public_key,
371 };
372
373 let msg = ch.encode();
374 self.transcript.extend_from_slice(&msg);
375 self.state = HandshakeState::WaitServerHello;
376 Some(msg)
377 }
378
379 pub fn process_server_hello(&mut self, data: &[u8]) -> Option<()> {
381 if self.state != HandshakeState::WaitServerHello {
382 return None;
383 }
384
385 let sh = ServerHello::decode(data)?;
386 self.transcript.extend_from_slice(data);
387 self.cipher_suite = Some(sh.cipher_suite);
388 self.server_public_key = Some(sh.key_share_public);
389
390 let shared_secret = x25519_shared_secret(&self.client_private_key, &sh.key_share_public);
392
393 let early_secret = hkdf_extract(&[0u8; HASH_LEN], &[0u8; HASH_LEN]);
395
396 let derived_secret = derive_secret(&early_secret, b"derived", &sha256(&[]).0);
398
399 let handshake_secret = hkdf_extract(&derived_secret, &shared_secret);
401 self.handshake_secret = Some(handshake_secret);
402
403 let transcript_hash = sha256(&self.transcript);
405
406 self.client_hs_traffic_secret = Some(derive_secret(
408 &handshake_secret,
409 b"c hs traffic",
410 &transcript_hash.0,
411 ));
412
413 self.server_hs_traffic_secret = Some(derive_secret(
415 &handshake_secret,
416 b"s hs traffic",
417 &transcript_hash.0,
418 ));
419
420 self.state = HandshakeState::WaitEncryptedExtensions;
421 Some(())
422 }
423
424 pub fn process_encrypted_extensions(&mut self, data: &[u8]) -> Option<()> {
426 if self.state != HandshakeState::WaitEncryptedExtensions {
427 return None;
428 }
429 if data.len() < 6 {
431 return None;
432 }
433 if data[0] != HandshakeType::EncryptedExtensions as u8 {
434 return None;
435 }
436 self.transcript.extend_from_slice(data);
437 self.state = HandshakeState::WaitCertificate;
438 Some(())
439 }
440
441 pub fn process_certificate(&mut self, data: &[u8]) -> Option<()> {
443 if self.state != HandshakeState::WaitCertificate {
444 return None;
445 }
446 if data.len() < 4 {
447 return None;
448 }
449 if data[0] != HandshakeType::Certificate as u8 {
450 return None;
451 }
452 let payload = &data[4..];
455 if !payload.is_empty() {
456 let ctx_len = payload[0] as usize;
458 let pos = 1 + ctx_len;
459 if pos + 3 <= payload.len() {
460 let certs_len = ((payload[pos] as usize) << 16)
461 | ((payload[pos + 1] as usize) << 8)
462 | (payload[pos + 2] as usize);
463 let certs_start = pos + 3;
464 if certs_start + 3 <= payload.len() && certs_len > 3 {
465 let cert_len = ((payload[certs_start] as usize) << 16)
466 | ((payload[certs_start + 1] as usize) << 8)
467 | (payload[certs_start + 2] as usize);
468 let cert_start = certs_start + 3;
469 if cert_start + cert_len <= payload.len() {
470 self.peer_certificate =
471 Some(payload[cert_start..cert_start + cert_len].to_vec());
472 }
473 }
474 }
475 }
476 self.transcript.extend_from_slice(data);
477 self.state = HandshakeState::WaitCertificateVerify;
478 Some(())
479 }
480
481 pub fn process_certificate_verify(&mut self, data: &[u8]) -> Option<()> {
483 if self.state != HandshakeState::WaitCertificateVerify {
484 return None;
485 }
486 if data.len() < 4 {
487 return None;
488 }
489 if data[0] != HandshakeType::CertificateVerify as u8 {
490 return None;
491 }
492 self.transcript.extend_from_slice(data);
495 self.state = HandshakeState::WaitFinished;
496 Some(())
497 }
498
499 pub fn process_finished(&mut self, data: &[u8]) -> Option<()> {
501 if self.state != HandshakeState::WaitFinished {
502 return None;
503 }
504 if data.len() < 4 {
505 return None;
506 }
507 if data[0] != HandshakeType::Finished as u8 {
508 return None;
509 }
510
511 let server_hs_secret = self.server_hs_traffic_secret.as_ref()?;
513 let finished_key = hkdf_expand_label(server_hs_secret, b"finished", &[], HASH_LEN);
514 let transcript_hash = sha256(&self.transcript);
515 let expected_verify = hmac_sha256(&finished_key, &transcript_hash.0);
516
517 if data.len() < 4 + HASH_LEN {
519 return None;
520 }
521 let verify_data = &data[4..4 + HASH_LEN];
522 if !constant_time_eq(verify_data, &expected_verify) {
523 self.state = HandshakeState::Error;
524 return None;
525 }
526
527 self.transcript.extend_from_slice(data);
528
529 let handshake_secret = self.handshake_secret.as_ref()?;
531 let derived = derive_secret(handshake_secret, b"derived", &sha256(&[]).0);
532 let master_secret = hkdf_extract(&derived, &[0u8; HASH_LEN]);
533
534 let transcript_hash_final = sha256(&self.transcript);
535
536 self.client_app_traffic_secret = Some(derive_secret(
537 &master_secret,
538 b"c ap traffic",
539 &transcript_hash_final.0,
540 ));
541 self.server_app_traffic_secret = Some(derive_secret(
542 &master_secret,
543 b"s ap traffic",
544 &transcript_hash_final.0,
545 ));
546
547 self.state = HandshakeState::Connected;
548 Some(())
549 }
550
551 pub fn build_client_finished(&self) -> Option<Vec<u8>> {
553 let client_hs_secret = self.client_hs_traffic_secret.as_ref()?;
554 let finished_key = hkdf_expand_label(client_hs_secret, b"finished", &[], HASH_LEN);
555 let transcript_hash = sha256(&self.transcript);
556 let verify_data = hmac_sha256(&finished_key, &transcript_hash.0);
557
558 let mut msg = Vec::with_capacity(4 + HASH_LEN);
559 msg.push(HandshakeType::Finished as u8);
560 let len = HASH_LEN;
561 msg.push(((len >> 16) & 0xFF) as u8);
562 msg.push(((len >> 8) & 0xFF) as u8);
563 msg.push((len & 0xFF) as u8);
564 msg.extend_from_slice(&verify_data);
565 Some(msg)
566 }
567
568 pub(crate) fn transcript_hash(&self) -> Hash256 {
570 sha256(&self.transcript)
571 }
572}