From 4a268a8fa26f36f4a940b095ac6b3e67c7d068a2 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Fri, 11 Jun 2021 17:22:12 +0200 Subject: [PATCH] server: reject 1.3 ClientHello with non-1.2 legacy_version --- rustls/src/server/hs.rs | 13 +++++++++ rustls/tests/api.rs | 58 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/rustls/src/server/hs.rs b/rustls/src/server/hs.rs index dcd63462..e65ec251 100644 --- a/rustls/src/server/hs.rs +++ b/rustls/src/server/hs.rs @@ -362,6 +362,19 @@ impl State for ExpectClientHello { ProtocolVersion::TLSv1_2 }; + if version == ProtocolVersion::TLSv1_3 + && client_hello.client_version != ProtocolVersion::TLSv1_2 + { + // RFC 8446 - 4.1.2 + // In TLS 1.3, the client indicates its version preferences in the + // "supported_versions" extension (Section 4.2.1) and the + // legacy_version field MUST be set to 0x0303, which is the version + // number for TLS 1.2. + return Err(Error::PeerMisbehavedError( + "TLS 1.3 ClientHello must set legacy_version to TLS 0x0303".to_string(), + )); + } + cx.common.negotiated_version = Some(version); // --- Common to TLS1.2 and TLS1.3: ciphersuite and certificate selection. diff --git a/rustls/tests/api.rs b/rustls/tests/api.rs index ba1703b0..54334495 100644 --- a/rustls/tests/api.rs +++ b/rustls/tests/api.rs @@ -3293,7 +3293,7 @@ mod test_quic { payload: MessagePayload::Handshake(HandshakeMessagePayload { typ: HandshakeType::ClientHello, payload: HandshakePayload::ClientHello(ClientHelloPayload { - client_version: ProtocolVersion::TLSv1_3, + client_version: ProtocolVersion::TLSv1_2, random, session_id: SessionID::random().unwrap(), cipher_suites: vec![CipherSuite::TLS13_AES_128_GCM_SHA256], @@ -3468,6 +3468,62 @@ fn test_reject_cookie_in_initial_client_hello() { ); } +#[test] +fn test_tls13_reject_client_hello_with_non_tls12_legacy_version() { + let mut server_config = make_server_config(KeyType::ED25519); + server_config + .versions + .replace(&[&rustls::version::TLS13]); + server_config.alpn_protocols = vec!["foo".into()]; + let server_config = Arc::new(server_config); + + let mut server = ServerConnection::new(server_config).unwrap(); + + use ring::rand::SecureRandom; + use rustls::internal::msgs::base::PayloadU16; + use rustls::internal::msgs::enums::{CipherSuite, Compression, HandshakeType}; + use rustls::internal::msgs::handshake::{ + ClientHelloPayload, HandshakeMessagePayload, Random, SessionID, + }; + use rustls::internal::msgs::message::PlainMessage; + + let rng = ring::rand::SystemRandom::new(); + let mut random = [0; 32]; + rng.fill(&mut random).unwrap(); + let random = Random::from(random); + + let client_hello = Message { + version: ProtocolVersion::TLSv1_1, + payload: MessagePayload::Handshake(HandshakeMessagePayload { + typ: HandshakeType::ClientHello, + payload: HandshakePayload::ClientHello(ClientHelloPayload { + client_version: ProtocolVersion::TLSv1_3, + random, + session_id: SessionID::random().unwrap(), + cipher_suites: vec![CipherSuite::TLS13_AES_128_GCM_SHA256], + compression_methods: vec![Compression::Null], + extensions: vec![ + ClientExtension::SupportedVersions(vec![ProtocolVersion::TLSv1_3]), + ClientExtension::Cookie(PayloadU16(b"foo".to_vec())), + ], + }), + }), + }; + + let buf = PlainMessage::from(client_hello) + .into_unencrypted_opaque() + .encode(); + server + .read_tls(&mut buf.as_slice()) + .unwrap(); + assert_eq!( + server.process_new_packets().err(), + Some(Error::PeerMisbehavedError( + "TLS 1.3 ClientHello must set legacy_version to TLS 0x0303".into(), + )), + ); +} + #[test] fn test_client_does_not_offer_sha1() { use rustls::internal::msgs::{