⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/net/tls/
handshake.rs

1//! TLS 1.3 Handshake State Machine (RFC 8446 Section 4)
2//!
3//! Implements the full TLS 1.3 handshake flow:
4//! ClientHello -> ServerHello -> EncryptedExtensions -> Certificate ->
5//! CertificateVerify -> Finished -> Application Data
6
7#[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// ============================================================================
20// Handshake Types and Enums
21// ============================================================================
22
23/// TLS 1.3 handshake message types
24#[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/// Signature algorithms advertised in ClientHello
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53#[repr(u16)]
54pub enum SignatureScheme {
55    EcdsaSecp256r1Sha256 = 0x0403,
56    RsaPssRsaeSha256 = 0x0804,
57    Ed25519 = 0x0807,
58}
59
60/// Named groups for key exchange
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62#[repr(u16)]
63pub enum NamedGroup {
64    X25519 = 0x001D,
65}
66
67/// TLS 1.3 handshake state machine states
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub enum HandshakeState {
70    /// Initial state -- ready to send ClientHello
71    Start,
72    /// ClientHello sent, waiting for ServerHello
73    WaitServerHello,
74    /// ServerHello received, waiting for EncryptedExtensions
75    WaitEncryptedExtensions,
76    /// EncryptedExtensions received, waiting for Certificate
77    WaitCertificate,
78    /// Certificate received, waiting for CertificateVerify
79    WaitCertificateVerify,
80    /// CertificateVerify received, waiting for Finished
81    WaitFinished,
82    /// Handshake complete, application data can flow
83    Connected,
84    /// Unrecoverable error occurred
85    Error,
86}
87
88/// TLS 1.3 extension types used in handshake
89#[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
100// ============================================================================
101// ClientHello / ServerHello
102// ============================================================================
103
104/// ClientHello message builder
105pub 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    /// Encode ClientHello to handshake message bytes
114    pub fn encode(&self) -> Vec<u8> {
115        let mut msg = Vec::with_capacity(256);
116
117        // Handshake type + placeholder for length
118        msg.push(HandshakeType::ClientHello as u8);
119        msg.extend_from_slice(&[0, 0, 0]); // length placeholder (3 bytes)
120
121        // Legacy version (TLS 1.2)
122        msg.extend_from_slice(&TLS_LEGACY_VERSION.to_be_bytes());
123
124        // Random (32 bytes)
125        msg.extend_from_slice(&self.random);
126
127        // Legacy session ID (32 bytes with length prefix)
128        msg.push(32);
129        msg.extend_from_slice(&self.session_id);
130
131        // Cipher suites (length-prefixed)
132        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        // Compression methods: only null (0x00)
139        msg.push(1); // length
140        msg.push(0); // null compression
141
142        // Extensions
143        let ext_start = msg.len();
144        msg.extend_from_slice(&[0, 0]); // extensions length placeholder
145
146        // Extension: supported_versions (type 43)
147        msg.extend_from_slice(&(ExtensionType::SupportedVersions as u16).to_be_bytes());
148        msg.extend_from_slice(&3u16.to_be_bytes()); // extension data length
149        msg.push(2); // versions list length
150        msg.extend_from_slice(&TLS_13_VERSION.to_be_bytes());
151
152        // Extension: supported_groups (type 10)
153        msg.extend_from_slice(&(ExtensionType::SupportedGroups as u16).to_be_bytes());
154        msg.extend_from_slice(&4u16.to_be_bytes()); // extension data length
155        msg.extend_from_slice(&2u16.to_be_bytes()); // named groups list length
156        msg.extend_from_slice(&(NamedGroup::X25519 as u16).to_be_bytes());
157
158        // Extension: signature_algorithms (type 13)
159        msg.extend_from_slice(&(ExtensionType::SignatureAlgorithms as u16).to_be_bytes());
160        msg.extend_from_slice(&8u16.to_be_bytes()); // extension data length
161        msg.extend_from_slice(&6u16.to_be_bytes()); // schemes list length
162        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        // Extension: key_share (type 51) -- X25519 public key
167        let _ks_ext_len = 2 + 2 + 1 + X25519_KEY_LEN; // group(2) + key_len(2) + key
168                                                      // Actually: client_shares_len(2) + group(2) + key_exchange_len(2) + key
169        let ks_entry_len = 2 + 2 + X25519_KEY_LEN; // group(2) + key_exchange_length(2) + key
170        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()); // ext data len
172        msg.extend_from_slice(&(ks_entry_len as u16).to_be_bytes()); // client_shares len
173        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        // Fix extensions length
178        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        // Fix handshake message length (3 bytes, big-endian)
182        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/// Parsed ServerHello fields
192#[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    /// Parse ServerHello from handshake message bytes (after type + length)
202    pub fn decode(data: &[u8]) -> Option<Self> {
203        if data.len() < 4 {
204            return None;
205        }
206        // Skip handshake header (type + 3-byte length)
207        let payload = &data[4..];
208        if payload.len() < 2 + 32 + 1 {
209            return None;
210        }
211
212        let mut pos = 0;
213
214        // Legacy version (2 bytes) -- ignored in TLS 1.3
215        pos += 2;
216
217        // Random (32 bytes)
218        let mut random = [0u8; 32];
219        random.copy_from_slice(&payload[pos..pos + 32]);
220        pos += 32;
221
222        // Session ID
223        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        // Cipher suite (2 bytes)
232        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        // Compression method (1 byte, must be 0)
240        if pos >= payload.len() {
241            return None;
242        }
243        pos += 1;
244
245        // Extensions
246        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        // Parse extensions
261        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                // key_share: group(2) + key_exchange_length(2) + key
272                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            // supported_versions extension is parsed but not stored -- we only support TLS
282            // 1.3
283
284            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
300// ============================================================================
301// Handshake Engine
302// ============================================================================
303
304/// Handshake engine managing state transitions and transcript
305pub struct HandshakeEngine {
306    pub state: HandshakeState,
307    /// Transcript hash of all handshake messages
308    transcript: Vec<u8>,
309    /// Negotiated cipher suite
310    pub cipher_suite: Option<CipherSuite>,
311    /// Our ephemeral X25519 private key
312    client_private_key: [u8; X25519_KEY_LEN],
313    /// Our ephemeral X25519 public key
314    client_public_key: [u8; X25519_KEY_LEN],
315    /// Server's X25519 public key from ServerHello
316    server_public_key: Option<[u8; X25519_KEY_LEN]>,
317    /// Derived handshake secrets
318    pub handshake_secret: Option<[u8; HASH_LEN]>,
319    /// Client handshake traffic secret
320    pub client_hs_traffic_secret: Option<[u8; HASH_LEN]>,
321    /// Server handshake traffic secret
322    pub server_hs_traffic_secret: Option<[u8; HASH_LEN]>,
323    /// Client application traffic secret
324    pub client_app_traffic_secret: Option<[u8; HASH_LEN]>,
325    /// Server application traffic secret
326    pub server_app_traffic_secret: Option<[u8; HASH_LEN]>,
327    /// Peer certificate (DER bytes)
328    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    /// Create a new handshake engine with generated ephemeral keys
339    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    /// Build and return the ClientHello message, advancing state
358    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], // Empty for TLS 1.3 but legacy-compatible
366            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    /// Process a received ServerHello message
380    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        // Derive shared secret via X25519
391        let shared_secret = x25519_shared_secret(&self.client_private_key, &sh.key_share_public);
392
393        // Derive handshake secrets using HKDF (RFC 8446 Section 7.1)
394        let early_secret = hkdf_extract(&[0u8; HASH_LEN], &[0u8; HASH_LEN]);
395
396        // derive-secret(early_secret, "derived", "")
397        let derived_secret = derive_secret(&early_secret, b"derived", &sha256(&[]).0);
398
399        // handshake_secret = HKDF-Extract(derived_secret, shared_secret)
400        let handshake_secret = hkdf_extract(&derived_secret, &shared_secret);
401        self.handshake_secret = Some(handshake_secret);
402
403        // Transcript hash at this point (ClientHello + ServerHello)
404        let transcript_hash = sha256(&self.transcript);
405
406        // client_handshake_traffic_secret
407        self.client_hs_traffic_secret = Some(derive_secret(
408            &handshake_secret,
409            b"c hs traffic",
410            &transcript_hash.0,
411        ));
412
413        // server_handshake_traffic_secret
414        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    /// Process EncryptedExtensions message
425    pub fn process_encrypted_extensions(&mut self, data: &[u8]) -> Option<()> {
426        if self.state != HandshakeState::WaitEncryptedExtensions {
427            return None;
428        }
429        // Validate basic structure: type(1) + length(3) + extensions_length(2)
430        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    /// Process Certificate message
442    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        // Extract the first certificate from the chain
453        // Format: type(1) + length(3) + request_context_len(1) + ...
454        let payload = &data[4..];
455        if !payload.is_empty() {
456            // request_context length
457            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    /// Process CertificateVerify message
482    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        // In a full implementation we would verify the signature over the transcript.
493        // For now, accept any structurally valid CertificateVerify.
494        self.transcript.extend_from_slice(data);
495        self.state = HandshakeState::WaitFinished;
496        Some(())
497    }
498
499    /// Process server Finished message and derive application traffic secrets
500    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        // Verify the Finished MAC
512        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        // Extract verify_data from the Finished message (after type + 3-byte length)
518        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        // Derive application traffic secrets (RFC 8446 Section 7.1)
530        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    /// Build the client Finished message
552    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    /// Get the current transcript hash
569    pub(crate) fn transcript_hash(&self) -> Hash256 {
570        sha256(&self.transcript)
571    }
572}