Skip to content

Commit 75f8857

Browse files
ctzcpu
authored andcommitted
Ignore server_name extension containing IP address
This works around quality-of-implementation issues in OpenSSL and Apple SecureTransport: they send `server_name` extensions containing IP addresses. RFC6066 specifically disallows that. It is a similar work-around to that adopted by LibreSSL: ignore SNI contents if they can be parsed as an IP address.
1 parent 7b8d1db commit 75f8857

File tree

2 files changed

+26
-9
lines changed

2 files changed

+26
-9
lines changed

rustls/src/msgs/handshake.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use crate::verify::DigitallySignedStruct;
1616

1717
use std::collections;
1818
use std::fmt;
19+
use std::net::IpAddr;
20+
use std::str::FromStr;
1921

2022
/// Create a newtype wrapper around a given type.
2123
///
@@ -211,6 +213,7 @@ impl TlsListElement for SignatureScheme {
211213
#[derive(Clone, Debug)]
212214
pub enum ServerNamePayload {
213215
HostName(DnsName),
216+
IpAddress(PayloadU16),
214217
Unknown(Payload),
215218
}
216219

@@ -221,15 +224,12 @@ impl ServerNamePayload {
221224

222225
fn read_hostname(r: &mut Reader) -> Result<Self, InvalidMessage> {
223226
let raw = PayloadU16::read(r)?;
224-
225227
match DnsName::try_from_ascii(&raw.0) {
226228
Ok(dns_name) => Ok(Self::HostName(dns_name)),
227229
Err(_) => {
228-
warn!(
229-
"Illegal SNI hostname received {:?}",
230-
String::from_utf8_lossy(&raw.0)
231-
);
232-
Err(InvalidMessage::InvalidServerName)
230+
let _ = IpAddr::from_str(&String::from_utf8_lossy(&raw.0))
231+
.map_err(|_| InvalidMessage::InvalidServerName)?;
232+
Ok(Self::IpAddress(raw))
233233
}
234234
}
235235
}
@@ -240,6 +240,7 @@ impl ServerNamePayload {
240240
(name.as_ref().len() as u16).encode(bytes);
241241
bytes.extend_from_slice(name.as_ref().as_bytes());
242242
}
243+
Self::IpAddress(ref r) => r.encode(bytes),
243244
Self::Unknown(ref r) => r.encode(bytes),
244245
}
245246
}
@@ -897,7 +898,23 @@ impl ClientHelloPayload {
897898
pub fn get_sni_extension(&self) -> Option<&[ServerName]> {
898899
let ext = self.find_extension(ExtensionType::ServerName)?;
899900
match *ext {
900-
ClientExtension::ServerName(ref req) => Some(req),
901+
// Does this comply with RFC6066?
902+
//
903+
// [RFC6066][] specifies that literal IP addresses are illegal in
904+
// `ServerName`s with a `name_type` of `host_name`.
905+
//
906+
// Some clients incorrectly send such extensions: we choose to
907+
// successfully parse these (into `ServerNamePayload::IpAddress`)
908+
// but then act like the client sent no `server_name` extension.
909+
//
910+
// [RFC6066]: https://datatracker.ietf.org/doc/html/rfc6066#section-3
911+
ClientExtension::ServerName(ref req)
912+
if !req
913+
.iter()
914+
.any(|name| matches!(name.payload, ServerNamePayload::IpAddress(_))) =>
915+
{
916+
Some(req)
917+
}
901918
_ => None,
902919
}
903920
}

rustls/src/msgs/message_test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ fn test_read_fuzz_corpus() {
4848
}
4949

5050
#[test]
51-
fn can_read_safari_client_hello() {
51+
fn can_read_safari_client_hello_with_ip_address_in_sni_extension() {
5252
let _ = env_logger::Builder::new()
5353
.filter(None, log::LevelFilter::Trace)
5454
.try_init();
@@ -72,7 +72,7 @@ fn can_read_safari_client_hello() {
7272
let mut rd = Reader::init(bytes);
7373
let m = OpaqueMessage::read(&mut rd).unwrap();
7474
println!("m = {:?}", m);
75-
assert!(Message::try_from(m.into_plain_message()).is_err());
75+
Message::try_from(m.into_plain_message()).unwrap();
7676
}
7777

7878
#[test]

0 commit comments

Comments
 (0)