mirror of https://github.com/ctz/rustls
Compare commits
5 Commits
7b8d1dbc1e
...
3633152cc5
Author | SHA1 | Date |
---|---|---|
Daniel McCarney | 3633152cc5 | |
Daniel McCarney | 0baaeba7a8 | |
Daniel McCarney | 6fd691a101 | |
Joseph Birr-Pixton | 6da53375a2 | |
Joseph Birr-Pixton | 75f8857db7 |
|
@ -57,7 +57,7 @@ jobs:
|
|||
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: "1.61"
|
||||
toolchain: "1.63"
|
||||
|
||||
- run: cargo check --lib --all-features -p rustls
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ x86, x86-64, LoongArch64, 32-bit & 64-bit Little Endian MIPS, 32-bit PowerPC (Bi
|
|||
support WebAssembly.
|
||||
For more information, see [the supported `ring` target platforms][ring-target-platforms].
|
||||
|
||||
Rustls requires Rust 1.61 or later.
|
||||
Rustls requires Rust 1.63 or later.
|
||||
|
||||
[ring-target-platforms]: https://github.com/briansmith/ring/blob/2e8363b433fa3b3962c877d9ed2e9145612f3160/include/ring-core/target.h#L18-L64
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
[package]
|
||||
name = "rustls"
|
||||
version = "0.21.11"
|
||||
version = "0.21.12"
|
||||
edition = "2021"
|
||||
rust-version = "1.61"
|
||||
rust-version = "1.63"
|
||||
license = "Apache-2.0 OR ISC OR MIT"
|
||||
readme = "../README.md"
|
||||
description = "Rustls is a modern TLS library written in Rust."
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
//! support WebAssembly.
|
||||
//! For more information, see [the supported `ring` target platforms][ring-target-platforms].
|
||||
//!
|
||||
//! Rustls requires Rust 1.61 or later.
|
||||
//! Rustls requires Rust 1.63 or later.
|
||||
//!
|
||||
//! [ring-target-platforms]: https://github.com/briansmith/ring/blob/2e8363b433fa3b3962c877d9ed2e9145612f3160/include/ring-core/target.h#L18-L64
|
||||
//!
|
||||
|
|
|
@ -16,6 +16,8 @@ use crate::verify::DigitallySignedStruct;
|
|||
|
||||
use std::collections;
|
||||
use std::fmt;
|
||||
use std::net::IpAddr;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// Create a newtype wrapper around a given type.
|
||||
///
|
||||
|
@ -211,6 +213,7 @@ impl TlsListElement for SignatureScheme {
|
|||
#[derive(Clone, Debug)]
|
||||
pub enum ServerNamePayload {
|
||||
HostName(DnsName),
|
||||
IpAddress(PayloadU16),
|
||||
Unknown(Payload),
|
||||
}
|
||||
|
||||
|
@ -221,15 +224,12 @@ impl ServerNamePayload {
|
|||
|
||||
fn read_hostname(r: &mut Reader) -> Result<Self, InvalidMessage> {
|
||||
let raw = PayloadU16::read(r)?;
|
||||
|
||||
match DnsName::try_from_ascii(&raw.0) {
|
||||
Ok(dns_name) => Ok(Self::HostName(dns_name)),
|
||||
Err(_) => {
|
||||
warn!(
|
||||
"Illegal SNI hostname received {:?}",
|
||||
String::from_utf8_lossy(&raw.0)
|
||||
);
|
||||
Err(InvalidMessage::InvalidServerName)
|
||||
let _ = IpAddr::from_str(&String::from_utf8_lossy(&raw.0))
|
||||
.map_err(|_| InvalidMessage::InvalidServerName)?;
|
||||
Ok(Self::IpAddress(raw))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,6 +240,7 @@ impl ServerNamePayload {
|
|||
(name.as_ref().len() as u16).encode(bytes);
|
||||
bytes.extend_from_slice(name.as_ref().as_bytes());
|
||||
}
|
||||
Self::IpAddress(ref r) => r.encode(bytes),
|
||||
Self::Unknown(ref r) => r.encode(bytes),
|
||||
}
|
||||
}
|
||||
|
@ -897,7 +898,23 @@ impl ClientHelloPayload {
|
|||
pub fn get_sni_extension(&self) -> Option<&[ServerName]> {
|
||||
let ext = self.find_extension(ExtensionType::ServerName)?;
|
||||
match *ext {
|
||||
ClientExtension::ServerName(ref req) => Some(req),
|
||||
// Does this comply with RFC6066?
|
||||
//
|
||||
// [RFC6066][] specifies that literal IP addresses are illegal in
|
||||
// `ServerName`s with a `name_type` of `host_name`.
|
||||
//
|
||||
// Some clients incorrectly send such extensions: we choose to
|
||||
// successfully parse these (into `ServerNamePayload::IpAddress`)
|
||||
// but then act like the client sent no `server_name` extension.
|
||||
//
|
||||
// [RFC6066]: https://datatracker.ietf.org/doc/html/rfc6066#section-3
|
||||
ClientExtension::ServerName(ref req)
|
||||
if !req
|
||||
.iter()
|
||||
.any(|name| matches!(name.payload, ServerNamePayload::IpAddress(_))) =>
|
||||
{
|
||||
Some(req)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ fn test_read_fuzz_corpus() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn can_read_safari_client_hello() {
|
||||
fn can_read_safari_client_hello_with_ip_address_in_sni_extension() {
|
||||
let _ = env_logger::Builder::new()
|
||||
.filter(None, log::LevelFilter::Trace)
|
||||
.try_init();
|
||||
|
@ -72,7 +72,7 @@ fn can_read_safari_client_hello() {
|
|||
let mut rd = Reader::init(bytes);
|
||||
let m = OpaqueMessage::read(&mut rd).unwrap();
|
||||
println!("m = {:?}", m);
|
||||
assert!(Message::try_from(m.into_plain_message()).is_err());
|
||||
Message::try_from(m.into_plain_message()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -84,7 +84,7 @@ impl Tls13CipherSuite {
|
|||
|
||||
/// Can a session using suite self resume from suite prev?
|
||||
pub fn can_resume_from(&self, prev: &'static Self) -> Option<&'static Self> {
|
||||
(prev.hash_algorithm() == self.hash_algorithm()).then(|| prev)
|
||||
(prev.hash_algorithm() == self.hash_algorithm()).then_some(prev)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,12 +13,13 @@ use std::sync::Mutex;
|
|||
use rustls::client::{ResolvesClientCert, Resumption};
|
||||
use rustls::internal::msgs::base::Payload;
|
||||
use rustls::internal::msgs::codec::Codec;
|
||||
use rustls::internal::msgs::handshake::ServerName as ServerNameExtensionItem;
|
||||
use rustls::server::{AllowAnyAnonymousOrAuthenticatedClient, ClientHello, ResolvesServerCert};
|
||||
#[cfg(feature = "secret_extraction")]
|
||||
use rustls::ConnectionTrafficSecrets;
|
||||
use rustls::{
|
||||
sign, CertificateError, ConnectionCommon, Error, KeyLog, PeerIncompatible, PeerMisbehaved,
|
||||
SideData,
|
||||
sign, CertificateError, ConnectionCommon, Error, InvalidMessage, KeyLog, PeerIncompatible,
|
||||
PeerMisbehaved, SideData,
|
||||
};
|
||||
use rustls::{CipherSuite, ProtocolVersion, SignatureScheme};
|
||||
use rustls::{ClientConfig, ClientConnection};
|
||||
|
@ -803,6 +804,92 @@ fn client_trims_terminating_dot() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn server_ignores_sni_with_ip_address() {
|
||||
fn insert_ip_address_server_name(msg: &mut Message) -> Altered {
|
||||
alter_sni_extension(
|
||||
msg,
|
||||
|snr| {
|
||||
snr.clear();
|
||||
snr.push(ServerNameExtensionItem::read_bytes(b"\x00\x00\x071.1.1.1").unwrap());
|
||||
},
|
||||
|parsed, _encoded| Payload::new(parsed.get_encoding()),
|
||||
)
|
||||
}
|
||||
|
||||
check_sni_error(
|
||||
insert_ip_address_server_name,
|
||||
Error::General("no server certificate chain resolved".to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn server_rejects_sni_with_illegal_dns_name() {
|
||||
fn insert_illegal_server_name(msg: &mut Message) -> Altered {
|
||||
alter_sni_extension(
|
||||
msg,
|
||||
|_| (),
|
||||
|_, encoded| {
|
||||
// replace "localhost" with invalid DNS name
|
||||
let mut altered = encoded.clone().0;
|
||||
let needle = b"localhost";
|
||||
let index = altered
|
||||
.windows(needle.len())
|
||||
.position(|window| window == needle)
|
||||
.unwrap();
|
||||
altered[index..index + needle.len()].copy_from_slice(b"ab@cd.com");
|
||||
Payload::new(altered)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
check_sni_error(
|
||||
insert_illegal_server_name,
|
||||
Error::InvalidMessage(InvalidMessage::InvalidServerName),
|
||||
);
|
||||
}
|
||||
|
||||
fn alter_sni_extension(
|
||||
msg: &mut Message,
|
||||
alter_inner: impl Fn(&mut Vec<ServerNameExtensionItem>),
|
||||
alter_encoding: impl Fn(&mut HandshakeMessagePayload, &mut Payload) -> Payload,
|
||||
) -> Altered {
|
||||
if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload {
|
||||
if let HandshakePayload::ClientHello(ch) = &mut parsed.payload {
|
||||
for mut ext in ch.extensions.iter_mut() {
|
||||
if let ClientExtension::ServerName(snr) = &mut ext {
|
||||
alter_inner(snr);
|
||||
}
|
||||
}
|
||||
*encoded = alter_encoding(parsed, encoded);
|
||||
}
|
||||
}
|
||||
|
||||
Altered::InPlace
|
||||
}
|
||||
|
||||
fn check_sni_error(alteration: impl Fn(&mut Message) -> Altered, expected_error: Error) {
|
||||
for kt in ALL_KEY_TYPES {
|
||||
let client_config = make_client_config(kt);
|
||||
let mut server_config = make_server_config(kt);
|
||||
|
||||
server_config.cert_resolver = Arc::new(ServerCheckNoSNI {});
|
||||
|
||||
let client = ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap();
|
||||
let server = ServerConnection::new(Arc::new(server_config)).unwrap();
|
||||
let (mut client, mut server) = (client.into(), server.into());
|
||||
|
||||
transfer_altered(&mut client, &alteration, &mut server);
|
||||
assert_eq!(server.process_new_packets(), Err(expected_error.clone()),);
|
||||
|
||||
let server_inner = match server {
|
||||
rustls::Connection::Server(server) => server,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
assert_eq!(None, server_inner.server_name());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "tls12")]
|
||||
fn check_sigalgs_reduced_by_ciphersuite(
|
||||
kt: KeyType,
|
||||
|
@ -4327,6 +4414,7 @@ fn connection_types_are_not_huge() {
|
|||
assert_lt(mem::size_of::<ClientConnection>(), 1600);
|
||||
}
|
||||
|
||||
use rustls::internal::msgs::handshake::HandshakeMessagePayload;
|
||||
use rustls::internal::msgs::{
|
||||
handshake::ClientExtension, handshake::HandshakePayload, message::Message,
|
||||
message::MessagePayload,
|
||||
|
@ -4335,18 +4423,13 @@ use rustls::internal::msgs::{
|
|||
#[test]
|
||||
fn test_server_rejects_duplicate_sni_names() {
|
||||
fn duplicate_sni_payload(msg: &mut Message) -> Altered {
|
||||
if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload {
|
||||
if let HandshakePayload::ClientHello(ch) = &mut parsed.payload {
|
||||
for mut ext in ch.extensions.iter_mut() {
|
||||
if let ClientExtension::ServerName(snr) = &mut ext {
|
||||
snr.push(snr[0].clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*encoded = Payload::new(parsed.get_encoding());
|
||||
}
|
||||
Altered::InPlace
|
||||
alter_sni_extension(
|
||||
msg,
|
||||
|snr| {
|
||||
snr.push(snr[0].clone());
|
||||
},
|
||||
|parsed, _encoded| Payload::new(parsed.get_encoding()),
|
||||
)
|
||||
}
|
||||
|
||||
let (client, server) = make_pair(KeyType::Rsa);
|
||||
|
@ -4363,19 +4446,11 @@ fn test_server_rejects_duplicate_sni_names() {
|
|||
#[test]
|
||||
fn test_server_rejects_empty_sni_extension() {
|
||||
fn empty_sni_payload(msg: &mut Message) -> Altered {
|
||||
if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload {
|
||||
if let HandshakePayload::ClientHello(ch) = &mut parsed.payload {
|
||||
for mut ext in ch.extensions.iter_mut() {
|
||||
if let ClientExtension::ServerName(snr) = &mut ext {
|
||||
snr.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*encoded = Payload::new(parsed.get_encoding());
|
||||
}
|
||||
|
||||
Altered::InPlace
|
||||
alter_sni_extension(
|
||||
msg,
|
||||
|snr| snr.clear(),
|
||||
|parsed, _encoded| Payload::new(parsed.get_encoding()),
|
||||
)
|
||||
}
|
||||
|
||||
let (client, server) = make_pair(KeyType::Rsa);
|
||||
|
|
Loading…
Reference in New Issue