use std::prelude::v1::*; use std::vec; use super::ServerConnectionData; use crate::common_state::Context; use crate::enums::{CipherSuite, SignatureScheme}; use crate::msgs::base::PayloadU16; use crate::msgs::enums::{Compression, NamedGroup}; use crate::msgs::handshake::{ ClientExtensions, ClientHelloPayload, HandshakeMessagePayload, HandshakePayload, KeyShareEntry, Random, ServerNamePayload, SessionId, SupportedProtocolVersions, }; use crate::msgs::message::{Message, MessagePayload}; use crate::{CommonState, Error, PeerIncompatible, PeerMisbehaved, ProtocolVersion, Side}; #[test] fn null_compression_required() { assert_eq!( test_process_client_hello(ClientHelloPayload { compression_methods: vec![], ..minimal_client_hello() }), Err(PeerIncompatible::NullCompressionRequired.into()), ); } #[test] fn server_ignores_sni_with_ip_address() { let mut ch = minimal_client_hello(); ch.extensions.server_name = Some(ServerNamePayload::IpAddress); std::println!("{:?}", ch.extensions); assert_eq!(test_process_client_hello(ch), Ok(())); } #[test] fn server_rejects_sni_with_illegal_dns_name() { let mut ch = minimal_client_hello(); ch.extensions.server_name = Some(ServerNamePayload::Invalid); std::println!("{:?}", ch.extensions); assert_eq!( test_process_client_hello(ch), Err(PeerMisbehaved::ServerNameMustContainOneHostName.into()) ); } fn test_process_client_hello(hello: ClientHelloPayload) -> Result<(), Error> { let m = Message { version: ProtocolVersion::TLSv1_2, payload: MessagePayload::handshake(HandshakeMessagePayload(HandshakePayload::ClientHello( hello, ))), }; super::hs::process_client_hello( &m, false, &mut Context { common: &mut CommonState::new(Side::Server), data: &mut ServerConnectionData::default(), sendable_plaintext: None, }, ) .map(|_| ()) } #[macro_rules_attribute::apply(test_for_each_provider)] mod tests { use super::super::*; use crate::common_state::KxState; use crate::crypto::{ ActiveKeyExchange, CryptoProvider, KeyExchangeAlgorithm, SupportedKxGroup, }; use crate::enums::CertificateType; use crate::pki_types::pem::PemObject; use crate::pki_types::{CertificateDer, PrivateKeyDer}; use crate::server::{AlwaysResolvesServerRawPublicKeys, ServerConfig, ServerConnection}; use crate::sign::CertifiedKey; use crate::sync::Arc; use crate::{CipherSuiteCommon, SupportedCipherSuite, Tls12CipherSuite, version}; #[cfg(feature = "tls12")] #[test] fn test_server_rejects_no_extended_master_secret_extension_when_require_ems_or_fips() { let provider = super::provider::default_provider(); let mut config = ServerConfig::builder_with_provider(provider.into()) .with_protocol_versions(&[&version::TLS12]) .unwrap() .with_no_client_auth() .with_single_cert(server_cert(), server_key()) .unwrap(); if config.provider.fips() { assert!(config.require_ems); } else { config.require_ems = true; } let mut conn = ServerConnection::new(config.into()).unwrap(); let mut ch = minimal_client_hello(); ch.extensions .extended_master_secret_request .take(); let ch = Message { version: ProtocolVersion::TLSv1_3, payload: MessagePayload::handshake(HandshakeMessagePayload( HandshakePayload::ClientHello(ch), )), }; conn.read_tls(&mut ch.into_wire_bytes().as_slice()) .unwrap(); assert_eq!( conn.process_new_packets(), Err(Error::PeerIncompatible( PeerIncompatible::ExtendedMasterSecretExtensionRequired )) ); } #[cfg(feature = "tls12")] #[test] fn server_picks_ffdhe_group_when_clienthello_has_no_ffdhe_group_in_groups_ext() { let config = ServerConfig::builder_with_provider(ffdhe_provider().into()) .with_protocol_versions(&[&version::TLS12]) .unwrap() .with_no_client_auth() .with_single_cert(server_cert(), server_key()) .unwrap(); let mut ch = minimal_client_hello(); ch.cipher_suites .push(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256.suite()); server_chooses_ffdhe_group_for_client_hello( ServerConnection::new(config.into()).unwrap(), ch, ); } #[cfg(feature = "tls12")] #[test] fn server_picks_ffdhe_group_when_clienthello_has_no_groups_ext() { let config = ServerConfig::builder_with_provider(ffdhe_provider().into()) .with_protocol_versions(&[&version::TLS12]) .unwrap() .with_no_client_auth() .with_single_cert(server_cert(), server_key()) .unwrap(); let mut ch = minimal_client_hello(); ch.cipher_suites .push(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256.suite()); ch.extensions.named_groups.take(); server_chooses_ffdhe_group_for_client_hello( ServerConnection::new(config.into()).unwrap(), ch, ); } #[cfg(feature = "tls12")] #[test] fn server_accepts_client_with_no_ecpoints_extension_and_only_ffdhe_cipher_suites() { let config = ServerConfig::builder_with_provider(ffdhe_provider().into()) .with_protocol_versions(&[&version::TLS12]) .unwrap() .with_no_client_auth() .with_single_cert(server_cert(), server_key()) .unwrap(); let mut ch = minimal_client_hello(); ch.cipher_suites .push(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256.suite()); ch.extensions.ec_point_formats.take(); server_chooses_ffdhe_group_for_client_hello( ServerConnection::new(config.into()).unwrap(), ch, ); } fn server_chooses_ffdhe_group_for_client_hello( mut conn: ServerConnection, client_hello: ClientHelloPayload, ) { let ch = Message { version: ProtocolVersion::TLSv1_3, payload: MessagePayload::handshake(HandshakeMessagePayload( HandshakePayload::ClientHello(client_hello), )), }; conn.read_tls(&mut ch.into_wire_bytes().as_slice()) .unwrap(); conn.process_new_packets().unwrap(); let KxState::Start(skxg) = &conn.kx_state else { panic!("unexpected kx_state"); }; assert_eq!(skxg.name(), FAKE_FFDHE_GROUP.name()); } #[test] fn test_server_requiring_rpk_client_rejects_x509_client() { let mut ch = minimal_client_hello(); ch.extensions.client_certificate_types = Some(vec![CertificateType::X509]); let ch = Message { version: ProtocolVersion::TLSv1_3, payload: MessagePayload::handshake(HandshakeMessagePayload( HandshakePayload::ClientHello(ch), )), }; let mut conn = ServerConnection::new(server_config_for_rpk().into()).unwrap(); conn.read_tls(&mut ch.into_wire_bytes().as_slice()) .unwrap(); assert_eq!( conn.process_new_packets().unwrap_err(), PeerIncompatible::IncorrectCertificateTypeExtension.into(), ); } #[test] fn test_rpk_only_server_rejects_x509_only_client() { let mut ch = minimal_client_hello(); ch.extensions.server_certificate_types = Some(vec![CertificateType::X509]); let ch = Message { version: ProtocolVersion::TLSv1_3, payload: MessagePayload::handshake(HandshakeMessagePayload( HandshakePayload::ClientHello(ch), )), }; let mut conn = ServerConnection::new(server_config_for_rpk().into()).unwrap(); conn.read_tls(&mut ch.into_wire_bytes().as_slice()) .unwrap(); assert_eq!( conn.process_new_packets().unwrap_err(), PeerIncompatible::IncorrectCertificateTypeExtension.into(), ); } fn server_config_for_rpk() -> ServerConfig { let x25519_provider = CryptoProvider { kx_groups: vec![super::provider::kx_group::X25519], ..super::provider::default_provider() }; ServerConfig::builder_with_provider(x25519_provider.into()) .with_protocol_versions(&[&version::TLS13]) .unwrap() .with_no_client_auth() .with_cert_resolver(Arc::new(AlwaysResolvesServerRawPublicKeys::new(Arc::new( server_certified_key(), )))) } fn server_certified_key() -> CertifiedKey { let key = super::provider::default_provider() .key_provider .load_private_key(server_key()) .unwrap(); let public_key_as_cert = vec![CertificateDer::from( key.public_key() .unwrap() .as_ref() .to_vec(), )]; CertifiedKey::new(public_key_as_cert, key) } fn server_key() -> PrivateKeyDer<'static> { PrivateKeyDer::from_pem_reader( &mut include_bytes!("../../../test-ca/rsa-2048/end.key").as_slice(), ) .unwrap() } fn server_cert() -> Vec> { vec![ CertificateDer::from(&include_bytes!("../../../test-ca/rsa-2048/end.der")[..]), CertificateDer::from(&include_bytes!("../../../test-ca/rsa-2048/inter.der")[..]), ] } fn ffdhe_provider() -> CryptoProvider { CryptoProvider { kx_groups: vec![FAKE_FFDHE_GROUP], cipher_suites: vec![TLS_DHE_RSA_WITH_AES_128_GCM_SHA256], ..super::provider::default_provider() } } static FAKE_FFDHE_GROUP: &'static dyn SupportedKxGroup = &FakeFfdheGroup; #[derive(Debug)] struct FakeFfdheGroup; impl SupportedKxGroup for FakeFfdheGroup { fn name(&self) -> NamedGroup { NamedGroup::FFDHE2048 } fn start(&self) -> Result, Error> { Ok(Box::new(ActiveFakeFfdhe)) } } #[derive(Debug)] struct ActiveFakeFfdhe; impl ActiveKeyExchange for ActiveFakeFfdhe { #[cfg_attr(coverage_nightly, coverage(off))] fn complete( self: Box, _peer_pub_key: &[u8], ) -> Result { todo!() } fn pub_key(&self) -> &[u8] { b"ActiveFakeFfdhe pub key" } fn group(&self) -> NamedGroup { NamedGroup::FFDHE2048 } } static TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = SupportedCipherSuite::Tls12(&TLS12_DHE_RSA_WITH_AES_128_GCM_SHA256); static TLS12_DHE_RSA_WITH_AES_128_GCM_SHA256: Tls12CipherSuite = match &super::provider::cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 { SupportedCipherSuite::Tls12(provider) => Tls12CipherSuite { common: CipherSuiteCommon { suite: CipherSuite::TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, ..provider.common }, kx: KeyExchangeAlgorithm::DHE, ..**provider }, _ => unreachable!(), }; } fn minimal_client_hello() -> ClientHelloPayload { ClientHelloPayload { client_version: ProtocolVersion::TLSv1_3, random: Random::from([0u8; 32]), session_id: SessionId::empty(), cipher_suites: vec![ CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, CipherSuite::TLS13_AES_128_GCM_SHA256, ], compression_methods: vec![Compression::Null], extensions: Box::new(ClientExtensions { signature_schemes: Some(vec![SignatureScheme::RSA_PSS_SHA256]), named_groups: Some(vec![NamedGroup::X25519, NamedGroup::secp256r1]), supported_versions: Some(SupportedProtocolVersions { tls12: true, tls13: true, }), key_shares: Some(vec![KeyShareEntry { group: NamedGroup::X25519, payload: PayloadU16::new(vec![0xab; 32]), }]), extended_master_secret_request: Some(()), ..ClientExtensions::default() }), } }