we (web engine): Experimental web browser project to understand the limits of Claude
at js-bytecode 1395 lines 49 kB view raw
1//! TLS 1.3 handshake client (RFC 8446). 2//! 3//! Implements the full TLS 1.3 client handshake including: 4//! - ClientHello with required extensions 5//! - ServerHello processing and ECDHE key exchange 6//! - Encrypted handshake message processing 7//! - Certificate verification 8//! - Finished message exchange 9//! - TlsStream for application data 10 11use std::io::{self, Read, Write}; 12 13use we_crypto::sha2::{sha256, sha384}; 14use we_crypto::x25519::{x25519, x25519_base}; 15use we_crypto::x509::{self, Certificate, DateTime}; 16 17use super::key_schedule::{KeySchedule, TranscriptHash}; 18use super::record::{ 19 CipherSuite, ContentType, RecordCryptoState, RecordLayer, TlsError, TlsRecord, 20}; 21 22// --------------------------------------------------------------------------- 23// Constants 24// --------------------------------------------------------------------------- 25 26/// TLS 1.2 legacy version (used in ClientHello). 27const LEGACY_VERSION: [u8; 2] = [0x03, 0x03]; 28 29/// TLS 1.3 version identifier for supported_versions extension. 30const TLS13_VERSION: [u8; 2] = [0x03, 0x04]; 31 32// Handshake message types (RFC 8446 §4) 33const HANDSHAKE_CLIENT_HELLO: u8 = 1; 34const HANDSHAKE_SERVER_HELLO: u8 = 2; 35const HANDSHAKE_ENCRYPTED_EXTENSIONS: u8 = 8; 36const HANDSHAKE_CERTIFICATE: u8 = 11; 37const HANDSHAKE_CERTIFICATE_VERIFY: u8 = 15; 38const HANDSHAKE_FINISHED: u8 = 20; 39 40// Extension types (RFC 8446 §4.2) 41const EXT_SERVER_NAME: u16 = 0; 42const EXT_SUPPORTED_GROUPS: u16 = 10; 43const EXT_SIGNATURE_ALGORITHMS: u16 = 13; 44const EXT_SUPPORTED_VERSIONS: u16 = 43; 45const EXT_KEY_SHARE: u16 = 51; 46 47// Named groups 48const GROUP_X25519: u16 = 0x001d; 49 50// Signature schemes (RFC 8446 §4.2.3) 51const SIG_RSA_PKCS1_SHA256: u16 = 0x0401; 52const SIG_RSA_PKCS1_SHA384: u16 = 0x0501; 53const SIG_RSA_PKCS1_SHA512: u16 = 0x0601; 54const SIG_ECDSA_SECP256R1_SHA256: u16 = 0x0403; 55const SIG_ECDSA_SECP384R1_SHA384: u16 = 0x0503; 56const SIG_RSA_PSS_RSAE_SHA256: u16 = 0x0804; 57const SIG_RSA_PSS_RSAE_SHA384: u16 = 0x0805; 58 59// Cipher suite wire values (RFC 8446 §B.4) 60const CS_AES_128_GCM_SHA256: [u8; 2] = [0x13, 0x01]; 61const CS_AES_256_GCM_SHA384: [u8; 2] = [0x13, 0x02]; 62const CS_CHACHA20_POLY1305_SHA256: [u8; 2] = [0x13, 0x03]; 63 64// CertificateVerify context string (RFC 8446 §4.4.3) 65const CV_SERVER_CONTEXT: &[u8] = b"TLS 1.3, server CertificateVerify"; 66 67// --------------------------------------------------------------------------- 68// Error types 69// --------------------------------------------------------------------------- 70 71/// Handshake-specific errors. 72#[derive(Debug)] 73pub enum HandshakeError { 74 /// TLS record layer error. 75 Tls(TlsError), 76 /// Unexpected handshake message type. 77 UnexpectedMessage(u8), 78 /// Server selected unsupported cipher suite. 79 UnsupportedCipherSuite, 80 /// Server selected unsupported version. 81 UnsupportedVersion, 82 /// Server did not provide a key share. 83 MissingKeyShare, 84 /// Server key share uses unsupported group. 85 UnsupportedGroup, 86 /// Missing required extension. 87 MissingExtension(&'static str), 88 /// Certificate chain is empty. 89 EmptyCertificateChain, 90 /// Certificate verification failed. 91 CertificateError(String), 92 /// CertificateVerify signature verification failed. 93 SignatureVerificationFailed, 94 /// Finished verify data mismatch. 95 FinishedMismatch, 96 /// Message too short or malformed. 97 Malformed(&'static str), 98 /// I/O error. 99 Io(io::Error), 100} 101 102impl std::fmt::Display for HandshakeError { 103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 104 match self { 105 Self::Tls(e) => write!(f, "TLS error: {e}"), 106 Self::UnexpectedMessage(t) => write!(f, "unexpected handshake message type: {t}"), 107 Self::UnsupportedCipherSuite => write!(f, "unsupported cipher suite"), 108 Self::UnsupportedVersion => write!(f, "unsupported TLS version"), 109 Self::MissingKeyShare => write!(f, "server did not provide key share"), 110 Self::UnsupportedGroup => write!(f, "unsupported key exchange group"), 111 Self::MissingExtension(ext) => write!(f, "missing extension: {ext}"), 112 Self::EmptyCertificateChain => write!(f, "empty certificate chain"), 113 Self::CertificateError(e) => write!(f, "certificate error: {e}"), 114 Self::SignatureVerificationFailed => write!(f, "signature verification failed"), 115 Self::FinishedMismatch => write!(f, "finished verify data mismatch"), 116 Self::Malformed(msg) => write!(f, "malformed message: {msg}"), 117 Self::Io(e) => write!(f, "I/O error: {e}"), 118 } 119 } 120} 121 122impl From<TlsError> for HandshakeError { 123 fn from(err: TlsError) -> Self { 124 HandshakeError::Tls(err) 125 } 126} 127 128impl From<io::Error> for HandshakeError { 129 fn from(err: io::Error) -> Self { 130 HandshakeError::Io(err) 131 } 132} 133 134type Result<T> = std::result::Result<T, HandshakeError>; 135 136// --------------------------------------------------------------------------- 137// Encoding helpers 138// --------------------------------------------------------------------------- 139 140fn push_u8(buf: &mut Vec<u8>, val: u8) { 141 buf.push(val); 142} 143 144fn push_u16(buf: &mut Vec<u8>, val: u16) { 145 buf.extend_from_slice(&val.to_be_bytes()); 146} 147 148fn push_u24(buf: &mut Vec<u8>, val: u32) { 149 buf.push((val >> 16) as u8); 150 buf.push((val >> 8) as u8); 151 buf.push(val as u8); 152} 153 154fn push_bytes(buf: &mut Vec<u8>, data: &[u8]) { 155 buf.extend_from_slice(data); 156} 157 158fn read_u8(data: &[u8], offset: &mut usize) -> Result<u8> { 159 if *offset >= data.len() { 160 return Err(HandshakeError::Malformed("unexpected end of data")); 161 } 162 let val = data[*offset]; 163 *offset += 1; 164 Ok(val) 165} 166 167fn read_u16(data: &[u8], offset: &mut usize) -> Result<u16> { 168 if *offset + 2 > data.len() { 169 return Err(HandshakeError::Malformed("unexpected end of data")); 170 } 171 let val = u16::from_be_bytes([data[*offset], data[*offset + 1]]); 172 *offset += 2; 173 Ok(val) 174} 175 176fn read_u24(data: &[u8], offset: &mut usize) -> Result<u32> { 177 if *offset + 3 > data.len() { 178 return Err(HandshakeError::Malformed("unexpected end of data")); 179 } 180 let val = 181 (data[*offset] as u32) << 16 | (data[*offset + 1] as u32) << 8 | data[*offset + 2] as u32; 182 *offset += 3; 183 Ok(val) 184} 185 186fn read_bytes<'a>(data: &'a [u8], offset: &mut usize, len: usize) -> Result<&'a [u8]> { 187 if *offset + len > data.len() { 188 return Err(HandshakeError::Malformed("unexpected end of data")); 189 } 190 let slice = &data[*offset..*offset + len]; 191 *offset += len; 192 Ok(slice) 193} 194 195// --------------------------------------------------------------------------- 196// Random bytes generation (using std for now) 197// --------------------------------------------------------------------------- 198 199fn random_bytes(buf: &mut [u8]) { 200 // Read from /dev/urandom for random bytes. 201 // This is available on macOS (which is our only target). 202 let mut f = std::fs::File::open("/dev/urandom").expect("failed to open /dev/urandom"); 203 f.read_exact(buf).expect("failed to read /dev/urandom"); 204} 205 206// --------------------------------------------------------------------------- 207// ClientHello construction 208// --------------------------------------------------------------------------- 209 210/// Build a ClientHello handshake message. 211/// 212/// Returns (handshake_message, x25519_private_key). 213fn build_client_hello(server_name: &str) -> (Vec<u8>, [u8; 32]) { 214 // Generate X25519 ephemeral keypair 215 let mut private_key = [0u8; 32]; 216 random_bytes(&mut private_key); 217 let public_key = x25519_base(&private_key); 218 219 // Generate random 220 let mut client_random = [0u8; 32]; 221 random_bytes(&mut client_random); 222 223 // Generate legacy session ID (32 random bytes) 224 let mut session_id = [0u8; 32]; 225 random_bytes(&mut session_id); 226 227 // Build ClientHello body 228 let mut body = Vec::with_capacity(512); 229 230 // Protocol version: TLS 1.2 (legacy) 231 push_bytes(&mut body, &LEGACY_VERSION); 232 233 // Random (32 bytes) 234 push_bytes(&mut body, &client_random); 235 236 // Legacy session ID (length-prefixed) 237 push_u8(&mut body, 32); 238 push_bytes(&mut body, &session_id); 239 240 // Cipher suites 241 push_u16(&mut body, 6); // 3 suites * 2 bytes 242 push_bytes(&mut body, &CS_AES_128_GCM_SHA256); 243 push_bytes(&mut body, &CS_AES_256_GCM_SHA384); 244 push_bytes(&mut body, &CS_CHACHA20_POLY1305_SHA256); 245 246 // Compression methods: only null 247 push_u8(&mut body, 1); // length 248 push_u8(&mut body, 0); // null 249 250 // Extensions 251 let extensions = build_extensions(server_name, &public_key); 252 push_u16(&mut body, extensions.len() as u16); 253 push_bytes(&mut body, &extensions); 254 255 // Wrap in handshake header 256 let mut msg = Vec::with_capacity(4 + body.len()); 257 push_u8(&mut msg, HANDSHAKE_CLIENT_HELLO); 258 push_u24(&mut msg, body.len() as u32); 259 push_bytes(&mut msg, &body); 260 261 (msg, private_key) 262} 263 264fn build_extensions(server_name: &str, x25519_public: &[u8; 32]) -> Vec<u8> { 265 let mut exts = Vec::with_capacity(256); 266 267 // SNI extension (server_name) 268 { 269 let name_bytes = server_name.as_bytes(); 270 // ServerNameList: list_length(2) + type(1) + name_length(2) + name 271 let sni_data_len = 2 + 1 + 2 + name_bytes.len(); 272 push_u16(&mut exts, EXT_SERVER_NAME); 273 push_u16(&mut exts, sni_data_len as u16); 274 // ServerNameList length 275 push_u16(&mut exts, (1 + 2 + name_bytes.len()) as u16); 276 push_u8(&mut exts, 0); // host_name type 277 push_u16(&mut exts, name_bytes.len() as u16); 278 push_bytes(&mut exts, name_bytes); 279 } 280 281 // supported_versions extension 282 { 283 push_u16(&mut exts, EXT_SUPPORTED_VERSIONS); 284 push_u16(&mut exts, 3); // extension data length 285 push_u8(&mut exts, 2); // list length 286 push_bytes(&mut exts, &TLS13_VERSION); 287 } 288 289 // supported_groups extension 290 { 291 push_u16(&mut exts, EXT_SUPPORTED_GROUPS); 292 push_u16(&mut exts, 4); // extension data length 293 push_u16(&mut exts, 2); // list length 294 push_u16(&mut exts, GROUP_X25519); 295 } 296 297 // key_share extension 298 { 299 // KeyShareEntry: group(2) + key_length(2) + key(32) 300 let entry_len = 2 + 2 + 32; 301 push_u16(&mut exts, EXT_KEY_SHARE); 302 push_u16(&mut exts, (2 + entry_len) as u16); // extension data length 303 push_u16(&mut exts, entry_len as u16); // client_shares length 304 push_u16(&mut exts, GROUP_X25519); 305 push_u16(&mut exts, 32); 306 push_bytes(&mut exts, x25519_public); 307 } 308 309 // signature_algorithms extension 310 { 311 let sig_algs = [ 312 SIG_ECDSA_SECP256R1_SHA256, 313 SIG_ECDSA_SECP384R1_SHA384, 314 SIG_RSA_PSS_RSAE_SHA256, 315 SIG_RSA_PSS_RSAE_SHA384, 316 SIG_RSA_PKCS1_SHA256, 317 SIG_RSA_PKCS1_SHA384, 318 SIG_RSA_PKCS1_SHA512, 319 ]; 320 let list_len = sig_algs.len() * 2; 321 push_u16(&mut exts, EXT_SIGNATURE_ALGORITHMS); 322 push_u16(&mut exts, (2 + list_len) as u16); 323 push_u16(&mut exts, list_len as u16); 324 for alg in sig_algs { 325 push_u16(&mut exts, alg); 326 } 327 } 328 329 exts 330} 331 332// --------------------------------------------------------------------------- 333// ServerHello parsing 334// --------------------------------------------------------------------------- 335 336struct ServerHelloResult { 337 cipher_suite: CipherSuite, 338 server_x25519_public: [u8; 32], 339} 340 341fn parse_server_hello(data: &[u8]) -> Result<ServerHelloResult> { 342 let mut offset = 0; 343 344 // legacy_version (2) 345 let _legacy_version = read_bytes(data, &mut offset, 2)?; 346 347 // random (32) 348 let _random = read_bytes(data, &mut offset, 32)?; 349 350 // legacy_session_id_echo 351 let session_id_len = read_u8(data, &mut offset)? as usize; 352 let _session_id = read_bytes(data, &mut offset, session_id_len)?; 353 354 // cipher_suite (2) 355 let cs_bytes = read_bytes(data, &mut offset, 2)?; 356 let cipher_suite = match [cs_bytes[0], cs_bytes[1]] { 357 CS_AES_128_GCM_SHA256 => CipherSuite::Aes128Gcm, 358 CS_AES_256_GCM_SHA384 => CipherSuite::Aes256Gcm, 359 CS_CHACHA20_POLY1305_SHA256 => CipherSuite::Chacha20Poly1305, 360 _ => return Err(HandshakeError::UnsupportedCipherSuite), 361 }; 362 363 // legacy_compression_method (1) 364 let _compression = read_u8(data, &mut offset)?; 365 366 // Extensions 367 let extensions_len = read_u16(data, &mut offset)? as usize; 368 let extensions_end = offset + extensions_len; 369 370 let mut server_key: Option<[u8; 32]> = None; 371 let mut has_supported_versions = false; 372 373 while offset < extensions_end { 374 let ext_type = read_u16(data, &mut offset)?; 375 let ext_len = read_u16(data, &mut offset)? as usize; 376 let ext_data = read_bytes(data, &mut offset, ext_len)?; 377 378 match ext_type { 379 EXT_KEY_SHARE => { 380 let mut eoff = 0; 381 let group = read_u16(ext_data, &mut eoff)?; 382 if group != GROUP_X25519 { 383 return Err(HandshakeError::UnsupportedGroup); 384 } 385 let key_len = read_u16(ext_data, &mut eoff)? as usize; 386 if key_len != 32 { 387 return Err(HandshakeError::Malformed("invalid x25519 key length")); 388 } 389 let key_data = read_bytes(ext_data, &mut eoff, 32)?; 390 let mut key = [0u8; 32]; 391 key.copy_from_slice(key_data); 392 server_key = Some(key); 393 } 394 EXT_SUPPORTED_VERSIONS => { 395 if ext_data.len() >= 2 && ext_data[0] == 0x03 && ext_data[1] == 0x04 { 396 has_supported_versions = true; 397 } 398 } 399 _ => {} // Ignore unknown extensions 400 } 401 } 402 403 if !has_supported_versions { 404 return Err(HandshakeError::UnsupportedVersion); 405 } 406 407 let server_x25519_public = server_key.ok_or(HandshakeError::MissingKeyShare)?; 408 409 Ok(ServerHelloResult { 410 cipher_suite, 411 server_x25519_public, 412 }) 413} 414 415// --------------------------------------------------------------------------- 416// Encrypted handshake message parsing 417// --------------------------------------------------------------------------- 418 419fn parse_encrypted_extensions(data: &[u8]) -> Result<()> { 420 let mut offset = 0; 421 let _extensions_len = read_u16(data, &mut offset)?; 422 // We don't require any specific encrypted extensions for now. 423 // Just validate the format is parseable. 424 Ok(()) 425} 426 427/// Parse a Certificate handshake message (RFC 8446 §4.4.2). 428/// Returns the list of DER-encoded certificates. 429fn parse_certificate_message(data: &[u8]) -> Result<Vec<Vec<u8>>> { 430 let mut offset = 0; 431 432 // certificate_request_context (opaque <0..255>) 433 let ctx_len = read_u8(data, &mut offset)? as usize; 434 let _ctx = read_bytes(data, &mut offset, ctx_len)?; 435 436 // certificate_list length (3 bytes) 437 let list_len = read_u24(data, &mut offset)? as usize; 438 let list_end = offset + list_len; 439 440 let mut certs = Vec::new(); 441 while offset < list_end { 442 // cert_data length (3 bytes) 443 let cert_len = read_u24(data, &mut offset)? as usize; 444 let cert_data = read_bytes(data, &mut offset, cert_len)?; 445 certs.push(cert_data.to_vec()); 446 447 // extensions length (2 bytes per cert entry) 448 let ext_len = read_u16(data, &mut offset)? as usize; 449 let _ext = read_bytes(data, &mut offset, ext_len)?; 450 } 451 452 if certs.is_empty() { 453 return Err(HandshakeError::EmptyCertificateChain); 454 } 455 456 Ok(certs) 457} 458 459/// Parse and verify a CertificateVerify message (RFC 8446 §4.4.3). 460fn verify_certificate_verify( 461 data: &[u8], 462 cert: &Certificate, 463 transcript_hash: &[u8], 464) -> Result<()> { 465 let mut offset = 0; 466 467 let scheme = read_u16(data, &mut offset)?; 468 let sig_len = read_u16(data, &mut offset)? as usize; 469 let signature = read_bytes(data, &mut offset, sig_len)?; 470 471 // Build the content to verify: 472 // 64 spaces + context string + 0x00 + transcript hash 473 let mut content = Vec::with_capacity(64 + CV_SERVER_CONTEXT.len() + 1 + transcript_hash.len()); 474 content.extend_from_slice(&[0x20u8; 64]); 475 content.extend_from_slice(CV_SERVER_CONTEXT); 476 content.push(0x00); 477 content.extend_from_slice(transcript_hash); 478 479 match scheme { 480 SIG_RSA_PKCS1_SHA256 => { 481 let pubkey = we_crypto::rsa::RsaPublicKey::from_der(&cert.subject_public_key_info) 482 .map_err(|e| HandshakeError::CertificateError(format!("RSA key: {e:?}")))?; 483 pubkey 484 .verify_pkcs1v15(we_crypto::rsa::HashAlgorithm::Sha256, &content, signature) 485 .map_err(|_| HandshakeError::SignatureVerificationFailed)?; 486 } 487 SIG_RSA_PKCS1_SHA384 => { 488 let pubkey = we_crypto::rsa::RsaPublicKey::from_der(&cert.subject_public_key_info) 489 .map_err(|e| HandshakeError::CertificateError(format!("RSA key: {e:?}")))?; 490 pubkey 491 .verify_pkcs1v15(we_crypto::rsa::HashAlgorithm::Sha384, &content, signature) 492 .map_err(|_| HandshakeError::SignatureVerificationFailed)?; 493 } 494 SIG_RSA_PKCS1_SHA512 => { 495 let pubkey = we_crypto::rsa::RsaPublicKey::from_der(&cert.subject_public_key_info) 496 .map_err(|e| HandshakeError::CertificateError(format!("RSA key: {e:?}")))?; 497 pubkey 498 .verify_pkcs1v15(we_crypto::rsa::HashAlgorithm::Sha512, &content, signature) 499 .map_err(|_| HandshakeError::SignatureVerificationFailed)?; 500 } 501 SIG_ECDSA_SECP256R1_SHA256 => { 502 let pubkey = 503 we_crypto::ecdsa::EcdsaPublicKey::from_spki_der(&cert.subject_public_key_info) 504 .map_err(|e| HandshakeError::CertificateError(format!("ECDSA key: {e:?}")))?; 505 let sig = we_crypto::ecdsa::EcdsaSignature::from_der(signature) 506 .map_err(|e| HandshakeError::CertificateError(format!("ECDSA sig: {e:?}")))?; 507 // Hash the content with SHA-256 and verify 508 let hash = sha256(&content); 509 pubkey 510 .verify_prehashed(&hash, &sig) 511 .map_err(|_| HandshakeError::SignatureVerificationFailed)?; 512 } 513 SIG_ECDSA_SECP384R1_SHA384 => { 514 let pubkey = 515 we_crypto::ecdsa::EcdsaPublicKey::from_spki_der(&cert.subject_public_key_info) 516 .map_err(|e| HandshakeError::CertificateError(format!("ECDSA key: {e:?}")))?; 517 let sig = we_crypto::ecdsa::EcdsaSignature::from_der(signature) 518 .map_err(|e| HandshakeError::CertificateError(format!("ECDSA sig: {e:?}")))?; 519 let hash = sha384(&content); 520 pubkey 521 .verify_prehashed(&hash, &sig) 522 .map_err(|_| HandshakeError::SignatureVerificationFailed)?; 523 } 524 SIG_RSA_PSS_RSAE_SHA256 | SIG_RSA_PSS_RSAE_SHA384 => { 525 // RSA-PSS is common in TLS 1.3. For now, we accept the connection 526 // if we can't verify PSS signatures, but we should implement it. 527 // TODO: Implement RSA-PSS signature verification 528 // For now, skip verification for PSS schemes. 529 // This is a known limitation. 530 return Err(HandshakeError::SignatureVerificationFailed); 531 } 532 _ => { 533 return Err(HandshakeError::SignatureVerificationFailed); 534 } 535 } 536 537 Ok(()) 538} 539 540// --------------------------------------------------------------------------- 541// Handshake message reading 542// --------------------------------------------------------------------------- 543 544/// Read the next handshake message from the record layer. 545/// Returns (handshake_type, body_bytes, full_handshake_message). 546fn read_handshake_message<S: Read + Write>( 547 record_layer: &mut RecordLayer<S>, 548) -> Result<(u8, Vec<u8>, Vec<u8>)> { 549 let record = record_layer.read_record()?; 550 551 if record.content_type != ContentType::Handshake { 552 return Err(HandshakeError::Malformed("expected handshake record")); 553 } 554 555 let data = &record.data; 556 if data.len() < 4 { 557 return Err(HandshakeError::Malformed("handshake message too short")); 558 } 559 560 let msg_type = data[0]; 561 let body_len = (data[1] as usize) << 16 | (data[2] as usize) << 8 | data[3] as usize; 562 563 if data.len() < 4 + body_len { 564 return Err(HandshakeError::Malformed( 565 "handshake message body truncated", 566 )); 567 } 568 569 let body = data[4..4 + body_len].to_vec(); 570 let full_msg = data[..4 + body_len].to_vec(); 571 572 Ok((msg_type, body, full_msg)) 573} 574 575// --------------------------------------------------------------------------- 576// TlsStream 577// --------------------------------------------------------------------------- 578 579/// A TLS-encrypted stream over a transport. 580/// 581/// Provides `Read` and `Write` for application data after a successful 582/// TLS 1.3 handshake. 583pub struct TlsStream<S> { 584 record_layer: RecordLayer<S>, 585 read_buffer: Vec<u8>, 586 read_offset: usize, 587} 588 589impl<S: Read + Write> TlsStream<S> { 590 /// Read decrypted application data. 591 pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> { 592 // If we have buffered data, return from that first 593 if self.read_offset < self.read_buffer.len() { 594 let available = &self.read_buffer[self.read_offset..]; 595 let to_copy = available.len().min(buf.len()); 596 buf[..to_copy].copy_from_slice(&available[..to_copy]); 597 self.read_offset += to_copy; 598 if self.read_offset >= self.read_buffer.len() { 599 self.read_buffer.clear(); 600 self.read_offset = 0; 601 } 602 return Ok(to_copy); 603 } 604 605 // Read next record 606 let record = self.record_layer.read_record()?; 607 match record.content_type { 608 ContentType::ApplicationData => { 609 let to_copy = record.data.len().min(buf.len()); 610 buf[..to_copy].copy_from_slice(&record.data[..to_copy]); 611 if to_copy < record.data.len() { 612 self.read_buffer = record.data; 613 self.read_offset = to_copy; 614 } 615 Ok(to_copy) 616 } 617 ContentType::Alert => { 618 if record.data.len() >= 2 && record.data[1] == 0 { 619 // close_notify 620 Ok(0) 621 } else { 622 Err(HandshakeError::Tls(TlsError::DecryptionFailed)) 623 } 624 } 625 _ => Err(HandshakeError::Malformed("unexpected record type")), 626 } 627 } 628 629 /// Write application data. 630 pub fn write(&mut self, data: &[u8]) -> Result<usize> { 631 let record = TlsRecord::new(ContentType::ApplicationData, data.to_vec()); 632 self.record_layer.write_record(&record)?; 633 Ok(data.len()) 634 } 635 636 /// Write all application data. 637 pub fn write_all(&mut self, data: &[u8]) -> Result<()> { 638 let record = TlsRecord::new(ContentType::ApplicationData, data.to_vec()); 639 self.record_layer.write_record(&record)?; 640 Ok(()) 641 } 642 643 /// Send a close_notify alert and shut down the TLS connection. 644 pub fn close(&mut self) -> Result<()> { 645 self.record_layer.send_close_notify()?; 646 Ok(()) 647 } 648 649 /// Get a reference to the underlying stream. 650 pub fn stream(&self) -> &S { 651 self.record_layer.stream() 652 } 653} 654 655// --------------------------------------------------------------------------- 656// Handshake state machine 657// --------------------------------------------------------------------------- 658 659/// Perform a TLS 1.3 handshake over the given stream. 660/// 661/// Returns a `TlsStream` ready for application data. 662pub fn connect<S: Read + Write>(stream: S, server_name: &str) -> Result<TlsStream<S>> { 663 let mut record_layer = RecordLayer::new(stream); 664 665 // Step 1: Build and send ClientHello 666 let (client_hello_msg, x25519_private) = build_client_hello(server_name); 667 668 let ch_record = TlsRecord::new(ContentType::Handshake, client_hello_msg.clone()); 669 record_layer.write_record(&ch_record)?; 670 671 // Step 2: Read ServerHello 672 let (sh_type, sh_body, sh_full) = read_handshake_message(&mut record_layer)?; 673 if sh_type != HANDSHAKE_SERVER_HELLO { 674 return Err(HandshakeError::UnexpectedMessage(sh_type)); 675 } 676 677 let sh = parse_server_hello(&sh_body)?; 678 679 // Step 3: Set up transcript hash and key schedule 680 let mut transcript = TranscriptHash::new(sh.cipher_suite); 681 transcript.update(&client_hello_msg); 682 transcript.update(&sh_full); 683 684 // Compute ECDHE shared secret 685 let shared_secret = x25519(&x25519_private, &sh.server_x25519_public); 686 687 // Derive handshake secrets 688 let mut key_schedule = KeySchedule::new(sh.cipher_suite, None); 689 key_schedule.derive_handshake_secrets(&shared_secret, &transcript.current_hash()); 690 691 // Step 4: Switch to handshake encryption for reading 692 let server_hs_keys = key_schedule.server_handshake_keys(); 693 let server_iv: [u8; 12] = server_hs_keys.iv.try_into().expect("IV must be 12 bytes"); 694 record_layer.set_read_crypto(RecordCryptoState::new( 695 sh.cipher_suite, 696 server_hs_keys.key, 697 server_iv, 698 )); 699 700 // Step 5: Read EncryptedExtensions 701 let (ee_type, ee_body, ee_full) = read_handshake_message(&mut record_layer)?; 702 if ee_type != HANDSHAKE_ENCRYPTED_EXTENSIONS { 703 return Err(HandshakeError::UnexpectedMessage(ee_type)); 704 } 705 parse_encrypted_extensions(&ee_body)?; 706 transcript.update(&ee_full); 707 708 // Step 6: Read Certificate 709 let (cert_type, cert_body, cert_full) = read_handshake_message(&mut record_layer)?; 710 if cert_type != HANDSHAKE_CERTIFICATE { 711 return Err(HandshakeError::UnexpectedMessage(cert_type)); 712 } 713 let cert_ders = parse_certificate_message(&cert_body)?; 714 transcript.update(&cert_full); 715 716 // Parse certificates 717 let mut certs = Vec::with_capacity(cert_ders.len()); 718 for der in &cert_ders { 719 let cert = Certificate::from_der(der) 720 .map_err(|e| HandshakeError::CertificateError(format!("{e:?}")))?; 721 certs.push(cert); 722 } 723 724 // Validate certificate chain 725 let now = current_datetime(); 726 let root_store = x509::root_ca_store() 727 .map_err(|e| HandshakeError::CertificateError(format!("root CA store: {e:?}")))?; 728 x509::validate_chain(&certs, &root_store, &now) 729 .map_err(|e| HandshakeError::CertificateError(format!("{e:?}")))?; 730 731 // Verify server name matches certificate 732 verify_server_name(&certs[0], server_name)?; 733 734 // Step 7: Read CertificateVerify 735 let (cv_type, cv_body, cv_full) = read_handshake_message(&mut record_layer)?; 736 if cv_type != HANDSHAKE_CERTIFICATE_VERIFY { 737 return Err(HandshakeError::UnexpectedMessage(cv_type)); 738 } 739 740 // Verify CertificateVerify against transcript hash up to Certificate 741 let cv_transcript_hash = transcript.current_hash(); 742 verify_certificate_verify(&cv_body, &certs[0], &cv_transcript_hash)?; 743 transcript.update(&cv_full); 744 745 // Step 8: Read server Finished 746 let (fin_type, fin_body, fin_full) = read_handshake_message(&mut record_layer)?; 747 if fin_type != HANDSHAKE_FINISHED { 748 return Err(HandshakeError::UnexpectedMessage(fin_type)); 749 } 750 751 // Verify server Finished 752 let server_finished_hash = transcript.current_hash(); 753 let expected_verify_data = key_schedule.compute_finished_verify_data( 754 key_schedule.server_handshake_traffic_secret().unwrap(), 755 &server_finished_hash, 756 ); 757 758 if fin_body != expected_verify_data { 759 return Err(HandshakeError::FinishedMismatch); 760 } 761 transcript.update(&fin_full); 762 763 // Step 9: Switch write to handshake encryption and send client Finished 764 let client_hs_keys = key_schedule.client_handshake_keys(); 765 let client_hs_iv: [u8; 12] = client_hs_keys.iv.try_into().expect("IV must be 12 bytes"); 766 record_layer.set_write_crypto(RecordCryptoState::new( 767 sh.cipher_suite, 768 client_hs_keys.key, 769 client_hs_iv, 770 )); 771 772 // Compute and send client Finished 773 let client_finished_hash = transcript.current_hash(); 774 let client_verify_data = key_schedule.compute_finished_verify_data( 775 key_schedule.client_handshake_traffic_secret().unwrap(), 776 &client_finished_hash, 777 ); 778 779 let mut client_finished_msg = Vec::with_capacity(4 + client_verify_data.len()); 780 push_u8(&mut client_finished_msg, HANDSHAKE_FINISHED); 781 push_u24(&mut client_finished_msg, client_verify_data.len() as u32); 782 push_bytes(&mut client_finished_msg, &client_verify_data); 783 784 let finished_record = TlsRecord::new(ContentType::Handshake, client_finished_msg.clone()); 785 record_layer.write_record(&finished_record)?; 786 transcript.update(&client_finished_msg); 787 788 // Step 10: Derive application keys 789 // RFC 8446 §7.1: application traffic secrets use the transcript hash through 790 // server Finished (client_finished_hash), NOT including client Finished. 791 key_schedule.derive_app_secrets(&client_finished_hash); 792 793 let client_app_keys = key_schedule.client_app_keys(); 794 let client_app_iv: [u8; 12] = client_app_keys.iv.try_into().expect("IV must be 12 bytes"); 795 record_layer.set_write_crypto(RecordCryptoState::new( 796 sh.cipher_suite, 797 client_app_keys.key, 798 client_app_iv, 799 )); 800 801 let server_app_keys = key_schedule.server_app_keys(); 802 let server_app_iv: [u8; 12] = server_app_keys.iv.try_into().expect("IV must be 12 bytes"); 803 record_layer.set_read_crypto(RecordCryptoState::new( 804 sh.cipher_suite, 805 server_app_keys.key, 806 server_app_iv, 807 )); 808 809 Ok(TlsStream { 810 record_layer, 811 read_buffer: Vec::new(), 812 read_offset: 0, 813 }) 814} 815 816// --------------------------------------------------------------------------- 817// Server name verification 818// --------------------------------------------------------------------------- 819 820fn verify_server_name(cert: &Certificate, server_name: &str) -> Result<()> { 821 // Check Subject Alternative Names first 822 for san in &cert.extensions.subject_alt_names { 823 if let x509::SubjectAltName::DnsName(dns) = san { 824 if matches_hostname(dns, server_name) { 825 return Ok(()); 826 } 827 } 828 } 829 830 // Fall back to Common Name 831 if let Some(cn) = &cert.subject.common_name { 832 if matches_hostname(cn, server_name) { 833 return Ok(()); 834 } 835 } 836 837 Err(HandshakeError::CertificateError(format!( 838 "server name '{server_name}' does not match certificate" 839 ))) 840} 841 842/// Match a hostname against a pattern (supports leading wildcard). 843fn matches_hostname(pattern: &str, hostname: &str) -> bool { 844 let pattern = pattern.to_ascii_lowercase(); 845 let hostname = hostname.to_ascii_lowercase(); 846 847 if pattern == hostname { 848 return true; 849 } 850 851 // Wildcard matching: *.example.com matches foo.example.com 852 if let Some(suffix) = pattern.strip_prefix("*.") { 853 if let Some(rest) = hostname.strip_suffix(suffix) { 854 // The wildcard must match exactly one non-empty label 855 if rest.ends_with('.') && rest.len() > 1 && !rest[..rest.len() - 1].contains('.') { 856 return true; 857 } 858 } 859 } 860 861 false 862} 863 864// --------------------------------------------------------------------------- 865// Utility 866// --------------------------------------------------------------------------- 867 868fn current_datetime() -> DateTime { 869 // We use a fixed recent time since we don't have access to system time 870 // in a portable way without external crates. In practice this would 871 // use std::time::SystemTime. 872 // 873 // For now, use SystemTime to compute the actual date. 874 use std::time::{SystemTime, UNIX_EPOCH}; 875 let duration = SystemTime::now() 876 .duration_since(UNIX_EPOCH) 877 .unwrap_or_default(); 878 let secs = duration.as_secs(); 879 880 // Simple conversion from unix timestamp to date components 881 let days = secs / 86400; 882 let time_of_day = secs % 86400; 883 let hour = (time_of_day / 3600) as u8; 884 let minute = ((time_of_day % 3600) / 60) as u8; 885 let second = (time_of_day % 60) as u8; 886 887 // Days since 1970-01-01 888 let (year, month, day) = days_to_date(days); 889 890 DateTime::new(year, month, day, hour, minute, second) 891} 892 893fn days_to_date(days_since_epoch: u64) -> (u16, u8, u8) { 894 // Algorithm from Howard Hinnant's chrono-compatible date algorithms 895 let z = days_since_epoch + 719468; 896 let era = z / 146097; 897 let doe = z - era * 146097; 898 let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; 899 let y = yoe + era * 400; 900 let doy = doe - (365 * yoe + yoe / 4 - yoe / 100); 901 let mp = (5 * doy + 2) / 153; 902 let d = doy - (153 * mp + 2) / 5 + 1; 903 let m = if mp < 10 { mp + 3 } else { mp - 9 }; 904 let y = if m <= 2 { y + 1 } else { y }; 905 (y as u16, m as u8, d as u8) 906} 907 908// --------------------------------------------------------------------------- 909// Tests 910// --------------------------------------------------------------------------- 911 912#[cfg(test)] 913mod tests { 914 use super::*; 915 916 // -- Encoding helpers -- 917 918 #[test] 919 fn push_u8_works() { 920 let mut buf = Vec::new(); 921 push_u8(&mut buf, 0x42); 922 assert_eq!(buf, vec![0x42]); 923 } 924 925 #[test] 926 fn push_u16_works() { 927 let mut buf = Vec::new(); 928 push_u16(&mut buf, 0x1234); 929 assert_eq!(buf, vec![0x12, 0x34]); 930 } 931 932 #[test] 933 fn push_u24_works() { 934 let mut buf = Vec::new(); 935 push_u24(&mut buf, 0x123456); 936 assert_eq!(buf, vec![0x12, 0x34, 0x56]); 937 } 938 939 #[test] 940 fn read_u8_works() { 941 let data = [0x42, 0x43]; 942 let mut offset = 0; 943 assert_eq!(read_u8(&data, &mut offset).unwrap(), 0x42); 944 assert_eq!(offset, 1); 945 assert_eq!(read_u8(&data, &mut offset).unwrap(), 0x43); 946 assert_eq!(offset, 2); 947 } 948 949 #[test] 950 fn read_u16_works() { 951 let data = [0x12, 0x34]; 952 let mut offset = 0; 953 assert_eq!(read_u16(&data, &mut offset).unwrap(), 0x1234); 954 assert_eq!(offset, 2); 955 } 956 957 #[test] 958 fn read_u24_works() { 959 let data = [0x12, 0x34, 0x56]; 960 let mut offset = 0; 961 assert_eq!(read_u24(&data, &mut offset).unwrap(), 0x123456); 962 assert_eq!(offset, 3); 963 } 964 965 #[test] 966 fn read_past_end_fails() { 967 let data = [0x42]; 968 let mut offset = 0; 969 assert!(read_u16(&data, &mut offset).is_err()); 970 } 971 972 #[test] 973 fn read_bytes_works() { 974 let data = [1, 2, 3, 4, 5]; 975 let mut offset = 1; 976 let slice = read_bytes(&data, &mut offset, 3).unwrap(); 977 assert_eq!(slice, &[2, 3, 4]); 978 assert_eq!(offset, 4); 979 } 980 981 // -- ClientHello construction -- 982 983 #[test] 984 fn client_hello_has_correct_type() { 985 let (msg, _) = build_client_hello("example.com"); 986 assert_eq!(msg[0], HANDSHAKE_CLIENT_HELLO); 987 } 988 989 #[test] 990 fn client_hello_has_valid_length() { 991 let (msg, _) = build_client_hello("example.com"); 992 let body_len = (msg[1] as usize) << 16 | (msg[2] as usize) << 8 | msg[3] as usize; 993 assert_eq!(msg.len(), 4 + body_len); 994 } 995 996 #[test] 997 fn client_hello_starts_with_legacy_version() { 998 let (msg, _) = build_client_hello("example.com"); 999 assert_eq!(msg[4], 0x03); 1000 assert_eq!(msg[5], 0x03); 1001 } 1002 1003 #[test] 1004 fn client_hello_has_32_byte_random() { 1005 let (msg1, _) = build_client_hello("example.com"); 1006 let (msg2, _) = build_client_hello("example.com"); 1007 // Random bytes start at offset 6 (after type(1) + length(3) + version(2)) 1008 let random1 = &msg1[6..38]; 1009 let random2 = &msg2[6..38]; 1010 // They should almost certainly differ (random) 1011 // But in tests /dev/urandom might give same bytes... just check length 1012 assert_eq!(random1.len(), 32); 1013 assert_eq!(random2.len(), 32); 1014 } 1015 1016 #[test] 1017 fn client_hello_has_session_id() { 1018 let (msg, _) = build_client_hello("example.com"); 1019 // session_id_len at offset 38 1020 assert_eq!(msg[38], 32); // 32-byte session ID 1021 } 1022 1023 #[test] 1024 fn client_hello_has_cipher_suites() { 1025 let (msg, _) = build_client_hello("example.com"); 1026 // After version(2) + random(32) + session_id_len(1) + session_id(32) 1027 let cs_offset = 4 + 2 + 32 + 1 + 32; 1028 let cs_len = u16::from_be_bytes([msg[cs_offset], msg[cs_offset + 1]]); 1029 assert_eq!(cs_len, 6); // 3 suites * 2 bytes 1030 } 1031 1032 #[test] 1033 fn client_hello_returns_private_key() { 1034 let (_, private_key) = build_client_hello("example.com"); 1035 assert_eq!(private_key.len(), 32); 1036 } 1037 1038 // -- ServerHello parsing -- 1039 1040 fn build_test_server_hello(suite: [u8; 2], x25519_key: &[u8; 32]) -> Vec<u8> { 1041 let mut body = Vec::new(); 1042 // legacy version 1043 push_bytes(&mut body, &LEGACY_VERSION); 1044 // random 1045 push_bytes(&mut body, &[0u8; 32]); 1046 // session_id echo (empty) 1047 push_u8(&mut body, 0); 1048 // cipher suite 1049 push_bytes(&mut body, &suite); 1050 // compression 1051 push_u8(&mut body, 0); 1052 1053 // Extensions 1054 let mut exts = Vec::new(); 1055 // supported_versions 1056 push_u16(&mut exts, EXT_SUPPORTED_VERSIONS); 1057 push_u16(&mut exts, 2); 1058 push_bytes(&mut exts, &TLS13_VERSION); 1059 // key_share 1060 push_u16(&mut exts, EXT_KEY_SHARE); 1061 push_u16(&mut exts, 36); // group(2) + len(2) + key(32) 1062 push_u16(&mut exts, GROUP_X25519); 1063 push_u16(&mut exts, 32); 1064 push_bytes(&mut exts, x25519_key); 1065 1066 push_u16(&mut body, exts.len() as u16); 1067 push_bytes(&mut body, &exts); 1068 1069 body 1070 } 1071 1072 #[test] 1073 fn parse_server_hello_aes128() { 1074 let key = [0x42u8; 32]; 1075 let body = build_test_server_hello(CS_AES_128_GCM_SHA256, &key); 1076 let result = parse_server_hello(&body).unwrap(); 1077 assert_eq!(result.cipher_suite, CipherSuite::Aes128Gcm); 1078 assert_eq!(result.server_x25519_public, key); 1079 } 1080 1081 #[test] 1082 fn parse_server_hello_aes256() { 1083 let key = [0x43u8; 32]; 1084 let body = build_test_server_hello(CS_AES_256_GCM_SHA384, &key); 1085 let result = parse_server_hello(&body).unwrap(); 1086 assert_eq!(result.cipher_suite, CipherSuite::Aes256Gcm); 1087 assert_eq!(result.server_x25519_public, key); 1088 } 1089 1090 #[test] 1091 fn parse_server_hello_chacha() { 1092 let key = [0x44u8; 32]; 1093 let body = build_test_server_hello(CS_CHACHA20_POLY1305_SHA256, &key); 1094 let result = parse_server_hello(&body).unwrap(); 1095 assert_eq!(result.cipher_suite, CipherSuite::Chacha20Poly1305); 1096 } 1097 1098 #[test] 1099 fn parse_server_hello_unsupported_suite() { 1100 let key = [0x42u8; 32]; 1101 let mut body = build_test_server_hello(CS_AES_128_GCM_SHA256, &key); 1102 // Corrupt cipher suite 1103 let cs_offset = 2 + 32 + 1; 1104 body[cs_offset] = 0xFF; 1105 body[cs_offset + 1] = 0xFF; 1106 assert!(parse_server_hello(&body).is_err()); 1107 } 1108 1109 #[test] 1110 fn parse_server_hello_missing_version() { 1111 let key = [0x42u8; 32]; 1112 let mut body = Vec::new(); 1113 push_bytes(&mut body, &LEGACY_VERSION); 1114 push_bytes(&mut body, &[0u8; 32]); 1115 push_u8(&mut body, 0); 1116 push_bytes(&mut body, &CS_AES_128_GCM_SHA256); 1117 push_u8(&mut body, 0); 1118 // Only key_share, no supported_versions 1119 let mut exts = Vec::new(); 1120 push_u16(&mut exts, EXT_KEY_SHARE); 1121 push_u16(&mut exts, 36); 1122 push_u16(&mut exts, GROUP_X25519); 1123 push_u16(&mut exts, 32); 1124 push_bytes(&mut exts, &key); 1125 push_u16(&mut body, exts.len() as u16); 1126 push_bytes(&mut body, &exts); 1127 assert!(parse_server_hello(&body).is_err()); 1128 } 1129 1130 #[test] 1131 fn parse_server_hello_missing_key_share() { 1132 let mut body = Vec::new(); 1133 push_bytes(&mut body, &LEGACY_VERSION); 1134 push_bytes(&mut body, &[0u8; 32]); 1135 push_u8(&mut body, 0); 1136 push_bytes(&mut body, &CS_AES_128_GCM_SHA256); 1137 push_u8(&mut body, 0); 1138 // Only supported_versions, no key_share 1139 let mut exts = Vec::new(); 1140 push_u16(&mut exts, EXT_SUPPORTED_VERSIONS); 1141 push_u16(&mut exts, 2); 1142 push_bytes(&mut exts, &TLS13_VERSION); 1143 push_u16(&mut body, exts.len() as u16); 1144 push_bytes(&mut body, &exts); 1145 assert!(parse_server_hello(&body).is_err()); 1146 } 1147 1148 // -- Certificate message parsing -- 1149 1150 #[test] 1151 fn parse_empty_certificate_fails() { 1152 // certificate_request_context = empty, certificate_list = empty 1153 let mut data = Vec::new(); 1154 push_u8(&mut data, 0); // empty context 1155 push_u24(&mut data, 0); // empty list 1156 assert!(parse_certificate_message(&data).is_err()); 1157 } 1158 1159 #[test] 1160 fn parse_certificate_message_single_cert() { 1161 let fake_cert = vec![0x30, 0x82, 0x01, 0x00]; // fake DER 1162 let mut data = Vec::new(); 1163 push_u8(&mut data, 0); // empty context 1164 // certificate list 1165 let entry_len = 3 + fake_cert.len() + 2; // cert_len(3) + cert + ext_len(2) 1166 push_u24(&mut data, entry_len as u32); 1167 push_u24(&mut data, fake_cert.len() as u32); 1168 push_bytes(&mut data, &fake_cert); 1169 push_u16(&mut data, 0); // no extensions 1170 1171 let certs = parse_certificate_message(&data).unwrap(); 1172 assert_eq!(certs.len(), 1); 1173 assert_eq!(certs[0], fake_cert); 1174 } 1175 1176 #[test] 1177 fn parse_certificate_message_two_certs() { 1178 let cert1 = vec![0x30, 0x01]; 1179 let cert2 = vec![0x30, 0x02, 0x03]; 1180 let mut data = Vec::new(); 1181 push_u8(&mut data, 0); // empty context 1182 1183 let entry1_len = 3 + cert1.len() + 2; 1184 let entry2_len = 3 + cert2.len() + 2; 1185 push_u24(&mut data, (entry1_len + entry2_len) as u32); 1186 1187 push_u24(&mut data, cert1.len() as u32); 1188 push_bytes(&mut data, &cert1); 1189 push_u16(&mut data, 0); 1190 1191 push_u24(&mut data, cert2.len() as u32); 1192 push_bytes(&mut data, &cert2); 1193 push_u16(&mut data, 0); 1194 1195 let certs = parse_certificate_message(&data).unwrap(); 1196 assert_eq!(certs.len(), 2); 1197 assert_eq!(certs[0], cert1); 1198 assert_eq!(certs[1], cert2); 1199 } 1200 1201 // -- EncryptedExtensions parsing -- 1202 1203 #[test] 1204 fn parse_encrypted_extensions_empty() { 1205 let mut data = Vec::new(); 1206 push_u16(&mut data, 0); // empty extensions 1207 assert!(parse_encrypted_extensions(&data).is_ok()); 1208 } 1209 1210 // -- Hostname matching -- 1211 1212 #[test] 1213 fn exact_hostname_match() { 1214 assert!(matches_hostname("example.com", "example.com")); 1215 assert!(matches_hostname("Example.COM", "example.com")); 1216 } 1217 1218 #[test] 1219 fn hostname_mismatch() { 1220 assert!(!matches_hostname("example.com", "other.com")); 1221 assert!(!matches_hostname("example.com", "sub.example.com")); 1222 } 1223 1224 #[test] 1225 fn wildcard_hostname_match() { 1226 assert!(matches_hostname("*.example.com", "www.example.com")); 1227 assert!(matches_hostname("*.example.com", "mail.example.com")); 1228 } 1229 1230 #[test] 1231 fn wildcard_no_deep_match() { 1232 // Wildcard should match only one label 1233 assert!(!matches_hostname("*.example.com", "a.b.example.com")); 1234 } 1235 1236 #[test] 1237 fn wildcard_no_bare_match() { 1238 assert!(!matches_hostname("*.example.com", "example.com")); 1239 } 1240 1241 // -- Date conversion -- 1242 1243 #[test] 1244 fn days_to_date_epoch() { 1245 let (y, m, d) = days_to_date(0); 1246 assert_eq!((y, m, d), (1970, 1, 1)); 1247 } 1248 1249 #[test] 1250 fn days_to_date_known() { 1251 // 2026-03-12 = 20524 days since epoch 1252 let (y, m, d) = days_to_date(20524); 1253 assert_eq!((y, m, d), (2026, 3, 12)); 1254 } 1255 1256 #[test] 1257 fn days_to_date_2000() { 1258 // 2000-01-01 = 10957 days since epoch 1259 let (y, m, d) = days_to_date(10957); 1260 assert_eq!((y, m, d), (2000, 1, 1)); 1261 } 1262 1263 // -- Error display -- 1264 1265 #[test] 1266 fn handshake_error_display() { 1267 let err = HandshakeError::UnsupportedCipherSuite; 1268 assert_eq!(err.to_string(), "unsupported cipher suite"); 1269 } 1270 1271 #[test] 1272 fn handshake_error_from_tls() { 1273 let tls_err = TlsError::RecordOverflow; 1274 let hs_err = HandshakeError::from(tls_err); 1275 assert!(matches!(hs_err, HandshakeError::Tls(_))); 1276 } 1277 1278 #[test] 1279 fn handshake_error_from_io() { 1280 let io_err = io::Error::new(io::ErrorKind::BrokenPipe, "broken"); 1281 let hs_err = HandshakeError::from(io_err); 1282 assert!(matches!(hs_err, HandshakeError::Io(_))); 1283 } 1284 1285 // -- Extensions building -- 1286 1287 #[test] 1288 fn extensions_contain_sni() { 1289 let key = [0u8; 32]; 1290 let exts = build_extensions("example.com", &key); 1291 // First extension should be SNI (type 0x0000) 1292 assert_eq!(exts[0], 0x00); 1293 assert_eq!(exts[1], 0x00); 1294 } 1295 1296 #[test] 1297 fn extensions_contain_supported_versions() { 1298 let key = [0u8; 32]; 1299 let exts = build_extensions("example.com", &key); 1300 // Search for supported_versions extension type (0x002b = 43) 1301 let mut found = false; 1302 let mut i = 0; 1303 while i + 4 <= exts.len() { 1304 let ext_type = u16::from_be_bytes([exts[i], exts[i + 1]]); 1305 let ext_len = u16::from_be_bytes([exts[i + 2], exts[i + 3]]) as usize; 1306 if ext_type == EXT_SUPPORTED_VERSIONS { 1307 found = true; 1308 break; 1309 } 1310 i += 4 + ext_len; 1311 } 1312 assert!(found, "supported_versions extension not found"); 1313 } 1314 1315 #[test] 1316 fn extensions_contain_key_share() { 1317 let key = [0x42u8; 32]; 1318 let exts = build_extensions("example.com", &key); 1319 let mut found = false; 1320 let mut i = 0; 1321 while i + 4 <= exts.len() { 1322 let ext_type = u16::from_be_bytes([exts[i], exts[i + 1]]); 1323 let ext_len = u16::from_be_bytes([exts[i + 2], exts[i + 3]]) as usize; 1324 if ext_type == EXT_KEY_SHARE { 1325 found = true; 1326 // Verify the key is in there 1327 // ext_data: list_len(2) + group(2) + key_len(2) + key(32) 1328 let key_start = i + 4 + 2 + 2 + 2; 1329 assert_eq!(&exts[key_start..key_start + 32], &key); 1330 break; 1331 } 1332 i += 4 + ext_len; 1333 } 1334 assert!(found, "key_share extension not found"); 1335 } 1336 1337 #[test] 1338 fn extensions_contain_sig_algorithms() { 1339 let key = [0u8; 32]; 1340 let exts = build_extensions("example.com", &key); 1341 let mut found = false; 1342 let mut i = 0; 1343 while i + 4 <= exts.len() { 1344 let ext_type = u16::from_be_bytes([exts[i], exts[i + 1]]); 1345 let ext_len = u16::from_be_bytes([exts[i + 2], exts[i + 3]]) as usize; 1346 if ext_type == EXT_SIGNATURE_ALGORITHMS { 1347 found = true; 1348 break; 1349 } 1350 i += 4 + ext_len; 1351 } 1352 assert!(found, "signature_algorithms extension not found"); 1353 } 1354 1355 // -- Build and parse roundtrip -- 1356 1357 #[test] 1358 fn server_hello_roundtrip_with_session_id() { 1359 let key = [0x55u8; 32]; 1360 let mut body = Vec::new(); 1361 push_bytes(&mut body, &LEGACY_VERSION); 1362 push_bytes(&mut body, &[0xAAu8; 32]); // random 1363 // 32-byte session ID echo 1364 push_u8(&mut body, 32); 1365 push_bytes(&mut body, &[0xBBu8; 32]); 1366 push_bytes(&mut body, &CS_AES_128_GCM_SHA256); 1367 push_u8(&mut body, 0); // compression 1368 // Extensions 1369 let mut exts = Vec::new(); 1370 push_u16(&mut exts, EXT_SUPPORTED_VERSIONS); 1371 push_u16(&mut exts, 2); 1372 push_bytes(&mut exts, &TLS13_VERSION); 1373 push_u16(&mut exts, EXT_KEY_SHARE); 1374 push_u16(&mut exts, 36); 1375 push_u16(&mut exts, GROUP_X25519); 1376 push_u16(&mut exts, 32); 1377 push_bytes(&mut exts, &key); 1378 push_u16(&mut body, exts.len() as u16); 1379 push_bytes(&mut body, &exts); 1380 1381 let result = parse_server_hello(&body).unwrap(); 1382 assert_eq!(result.cipher_suite, CipherSuite::Aes128Gcm); 1383 assert_eq!(result.server_x25519_public, key); 1384 } 1385 1386 // -- current_datetime sanity check -- 1387 1388 #[test] 1389 fn current_datetime_reasonable() { 1390 let dt = current_datetime(); 1391 assert!(dt.year >= 2024); 1392 assert!((1..=12).contains(&dt.month)); 1393 assert!((1..=31).contains(&dt.day)); 1394 } 1395}