Skip to content

Commit

Permalink
feat(s2n-quic-rustls): update rustls from 0.21 to 0.23
Browse files Browse the repository at this point in the history
  • Loading branch information
toidiu committed Mar 5, 2024
1 parent 670b7ad commit b8984b4
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 84 deletions.
3 changes: 1 addition & 2 deletions quic/s2n-quic-qns/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ http = "1.0"
humansize = "2"
lru = "0.10"
rand = "0.8"
# dangerous_configuration is used to allow for cert verification to be disabled for the amplification limit interop test
rustls = { version = "0.21", features = ["dangerous_configuration", "quic"] }
rustls = { version = "0.23", features = ["std", "aws_lc_rs"] }
s2n-codec = { path = "../../common/s2n-codec" }
s2n-quic-core = { path = "../s2n-quic-core", features = ["testing"] }
s2n-quic-h3 = { path = "../s2n-quic-h3" }
Expand Down
78 changes: 61 additions & 17 deletions quic/s2n-quic-qns/src/tls.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use crate::Result;
use crate::{tls::rustls::DisabledVerifier, Result};
use s2n_quic::provider::tls::rustls::{default_crypto_provider, TLS13_PROTOCOL_VERSIONS};
use std::{path::PathBuf, str::FromStr};
use structopt::StructOpt;

Expand Down Expand Up @@ -113,15 +114,16 @@ impl Client {

pub fn build_rustls(&self, alpns: &[String]) -> Result<rustls::Client> {
let tls = if self.disable_cert_verification {
use ::rustls::{version, ClientConfig, KeyLogFile};
use ::rustls::{ClientConfig, KeyLogFile};
use std::sync::Arc;

let mut config = ClientConfig::builder()
.with_cipher_suites(rustls::DEFAULT_CIPHERSUITES)
.with_safe_default_kx_groups()
.with_protocol_versions(&[&version::TLS13])?
.with_custom_certificate_verifier(Arc::new(rustls::DisabledVerifier))
.with_no_client_auth();
let tls13_cipher_suite_crypto_provider = default_crypto_provider()?;
let mut config =
ClientConfig::builder_with_provider(tls13_cipher_suite_crypto_provider.into())
.with_protocol_versions(TLS13_PROTOCOL_VERSIONS)?
.dangerous()
.with_custom_certificate_verifier(Arc::new(DisabledVerifier))
.with_no_client_auth();
config.max_fragment_size = None;
config.alpn_protocols = alpns.iter().map(|p| p.as_bytes().to_vec()).collect();
config.key_log = Arc::new(KeyLogFile::new());
Expand Down Expand Up @@ -265,9 +267,16 @@ pub mod s2n_tls {

pub mod rustls {
use super::*;
use ::rustls::{
client::danger,
crypto,
pki_types::{ServerName, UnixTime},
DigitallySignedStruct, Error, SignatureScheme,
};
use s2n_quic::provider::tls::rustls::CertificateDer;
pub use s2n_quic::provider::tls::rustls::{
certificate::{Certificate, IntoCertificate, IntoPrivateKey, PrivateKey},
Client, Server, DEFAULT_CIPHERSUITES,
Client, Server,
};

pub fn ca(ca: Option<&PathBuf>) -> Result<Certificate> {
Expand All @@ -286,19 +295,54 @@ pub mod rustls {
})
}

#[derive(Debug)]
pub struct DisabledVerifier;

impl ::rustls::client::ServerCertVerifier for DisabledVerifier {
impl danger::ServerCertVerifier for DisabledVerifier {
fn verify_server_cert(
&self,
_end_entity: &::rustls::Certificate,
_intermediates: &[::rustls::Certificate],
_server_name: &::rustls::ServerName,
_scts: &mut dyn Iterator<Item = &[u8]>,
_end_entity: &CertificateDer<'_>,
_intermediates: &[CertificateDer<'_>],
_server_name: &ServerName,
_ocsp_response: &[u8],
_now: std::time::SystemTime,
) -> Result<::rustls::client::ServerCertVerified, ::rustls::Error> {
Ok(::rustls::client::ServerCertVerified::assertion())
_now: UnixTime,
) -> Result<danger::ServerCertVerified, Error> {
Ok(danger::ServerCertVerified::assertion())
}

fn verify_tls12_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &rustls::DigitallySignedStruct,
) -> Result<danger::HandshakeSignatureValid, rustls::Error> {
crypto::verify_tls12_signature(
message,
cert,
dss,
&default_crypto_provider()?.signature_verification_algorithms,
)
}

fn verify_tls13_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &rustls::DigitallySignedStruct,
) -> Result<danger::HandshakeSignatureValid, rustls::Error> {
rustls::crypto::verify_tls13_signature(
message,
cert,
dss,
&default_crypto_provider()?.signature_verification_algorithms,
)
}

fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
default_crypto_provider()
.unwrap()
.signature_verification_algorithms
.supported_schemes()
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion quic/s2n-quic-rustls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ exclude = ["corpus.tar.gz"]

[dependencies]
bytes = { version = "1", default-features = false }
rustls = { version = "0.21", features = ["quic"] }
rustls = { version = "0.23", features = ["std", "aws_lc_rs"] }
rustls-pemfile = "1"
s2n-codec = { version = "=0.33.0", path = "../../common/s2n-codec", default-features = false, features = ["alloc"] }
s2n-quic-core = { version = "=0.33.0", path = "../s2n-quic-core", default-features = false, features = ["alloc"] }
Expand Down
79 changes: 48 additions & 31 deletions quic/s2n-quic-rustls/src/certificate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,69 +76,86 @@ cert_type!(
PrivateKey,
IntoPrivateKey,
into_private_key,
rustls::PrivateKey
rustls::pki_types::PrivateKeyDer<'static>
);
cert_type!(
Certificate,
IntoCertificate,
into_certificate,
Vec<rustls::Certificate>
Vec<rustls::pki_types::CertificateDer<'static>>
);

mod pem {
use super::*;
use rustls::{
pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs1KeyDer, PrivatePkcs8KeyDer},
Error,
};

pub fn into_certificate(contents: &[u8]) -> Result<Vec<rustls::Certificate>, Error> {
pub fn into_certificate(contents: &[u8]) -> Result<Vec<CertificateDer<'static>>, Error> {
let mut cursor = std::io::Cursor::new(contents);
let certs = rustls_pemfile::certs(&mut cursor)
.map(|certs| certs.into_iter().map(rustls::Certificate).collect())
.map(|certs| certs.into_iter().map(CertificateDer::from).collect())
.map_err(|_| Error::General("Could not read certificate".to_string()))?;
Ok(certs)
}

pub fn into_private_key(contents: &[u8]) -> Result<rustls::PrivateKey, Error> {
let mut cursor = std::io::Cursor::new(contents);
fn construct_pkcs1_key(key: Vec<u8>) -> Result<PrivateKeyDer<'static>, Error> {
Ok(PrivateKeyDer::Pkcs1(PrivatePkcs1KeyDer::from(key)))
}

let parsers = [
rustls_pemfile::rsa_private_keys,
rustls_pemfile::pkcs8_private_keys,
];
fn construct_pkcs8_key(key: Vec<u8>) -> Result<PrivateKeyDer<'static>, Error> {
Ok(PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(key)))
}

for parser in parsers.iter() {
cursor.set_position(0);
pub fn into_private_key(contents: &[u8]) -> Result<PrivateKeyDer<'static>, Error> {
let mut cursor = std::io::Cursor::new(contents);

match parser(&mut cursor) {
Ok(keys) if keys.is_empty() => continue,
Ok(mut keys) if keys.len() == 1 => {
return Ok(rustls::PrivateKey(keys.pop().unwrap()))
}
Ok(keys) => {
return Err(Error::General(format!(
"Unexpected number of keys: {} (only 1 supported)",
keys.len()
)));
macro_rules! parse_key {
($parser:ident, $constructor:ident) => {
cursor.set_position(0);

match rustls_pemfile::$parser(&mut cursor) {
// try the next parser
Err(_) => (),
// try the next parser
Ok(keys) if keys.is_empty() => (),
Ok(mut keys) if keys.len() == 1 => {
return $constructor(keys.pop().unwrap());
}
Ok(keys) => {
return Err(Error::General(format!(
"Unexpected number of keys: {} (only 1 supported)",
keys.len()
)));
}
}
// try the next parser
Err(_) => continue,
}
};
}

// attempt to parse PKCS8 encoded key
parse_key!(pkcs8_private_keys, construct_pkcs8_key);
// attempt to parse RSA key
parse_key!(rsa_private_keys, construct_pkcs1_key);

Err(Error::General(
"could not load any valid private keys".to_string(),
))
}
}

mod der {
use super::*;
use rustls::{
pki_types::{CertificateDer, PrivateKeyDer},
Error,
};

pub fn into_certificate(contents: Vec<u8>) -> Result<Vec<rustls::Certificate>, Error> {
pub fn into_certificate(contents: Vec<u8>) -> Result<Vec<CertificateDer<'static>>, Error> {
// der files only have a single cert
Ok(vec![rustls::Certificate(contents)])
Ok(vec![CertificateDer::from(contents)])
}

pub fn into_private_key(contents: Vec<u8>) -> Result<rustls::PrivateKey, Error> {
Ok(rustls::PrivateKey(contents))
pub fn into_private_key(contents: Vec<u8>) -> Result<PrivateKeyDer<'static>, Error> {
Ok(PrivateKeyDer::Pkcs8(contents.into()))
}
}

Expand Down
24 changes: 17 additions & 7 deletions quic/s2n-quic-rustls/src/cipher_suite.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use rustls::{cipher_suite as ciphers, quic, CipherSuite, SupportedCipherSuite};
use rustls::{
crypto::{aws_lc_rs, CryptoProvider},
quic, CipherSuite, SupportedCipherSuite,
};
use s2n_codec::Encoder;
use s2n_quic_core::crypto::{self, packet_protection, scatter, tls, HeaderProtectionMask, Key};

pub fn default_crypto_provider() -> Result<CryptoProvider, rustls::Error> {
Ok(CryptoProvider {
cipher_suites: DEFAULT_CIPHERSUITES.to_vec(),
..aws_lc_rs::default_provider()
})
}

pub struct PacketKey {
key: quic::PacketKey,
key: Box<dyn quic::PacketKey>,
cipher_suite: tls::CipherSuite,
}

Expand Down Expand Up @@ -159,7 +169,7 @@ impl crypto::Key for PacketKeys {

impl crypto::HandshakeKey for PacketKeys {}

pub struct HeaderProtectionKey(quic::HeaderProtectionKey);
pub struct HeaderProtectionKey(Box<dyn quic::HeaderProtectionKey>);

impl HeaderProtectionKey {
/// Returns the header protection mask for the given ciphertext sample
Expand Down Expand Up @@ -331,10 +341,10 @@ impl crypto::OneRttKey for OneRttKey {
//# negotiated unless a header protection scheme is defined for the
//# cipher suite.
// All of the cipher_suites from the current exported list have HP schemes for QUIC
pub static DEFAULT_CIPHERSUITES: &[SupportedCipherSuite] = &[
ciphers::TLS13_AES_128_GCM_SHA256,
ciphers::TLS13_AES_256_GCM_SHA384,
ciphers::TLS13_CHACHA20_POLY1305_SHA256,
static DEFAULT_CIPHERSUITES: &[SupportedCipherSuite] = &[
aws_lc_rs::cipher_suite::TLS13_AES_128_GCM_SHA256,
aws_lc_rs::cipher_suite::TLS13_AES_256_GCM_SHA384,
aws_lc_rs::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256,
];

#[test]
Expand Down
22 changes: 11 additions & 11 deletions quic/s2n-quic-rustls/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use crate::{certificate, session::Session};
use crate::{certificate, cipher_suite::default_crypto_provider, session::Session};
use core::convert::TryFrom;
use rustls::ClientConfig;
use rustls::{pki_types as rustls_pki_types, ClientConfig};
use s2n_codec::EncoderValue;
use s2n_quic_core::{application::ServerName, crypto::tls};
use std::sync::Arc;
Expand Down Expand Up @@ -65,8 +65,8 @@ impl tls::Endpoint for Client {
//# Endpoints MUST send the quic_transport_parameters extension;
let transport_parameters = transport_parameters.encode_to_vec();

let rustls_server_name =
rustls::ServerName::try_from(server_name.as_ref()).expect("invalid server name");
let rustls_server_name = rustls_pki_types::ServerName::try_from(server_name.to_string())
.expect("invalid server name");

let session = rustls::quic::ClientConnection::new(
self.config.clone(),
Expand Down Expand Up @@ -114,7 +114,7 @@ impl Builder {
rustls::Error::General("Certificate chain needs to have at least one entry".to_string())
})?;
self.cert_store
.add(root_certificate)
.add(root_certificate.to_owned())
.map_err(|err| rustls::Error::General(err.to_string()))?;
Ok(self)
}
Expand Down Expand Up @@ -148,12 +148,12 @@ impl Builder {
));
}

let mut config = ClientConfig::builder()
.with_cipher_suites(crate::cipher_suite::DEFAULT_CIPHERSUITES)
.with_safe_default_kx_groups()
.with_protocol_versions(crate::PROTOCOL_VERSIONS)?
.with_root_certificates(self.cert_store)
.with_no_client_auth();
let tls13_cipher_suite_crypto_provider = default_crypto_provider()?;
let mut config =
ClientConfig::builder_with_provider(tls13_cipher_suite_crypto_provider.into())
.with_protocol_versions(crate::TLS13_PROTOCOL_VERSIONS)?
.with_root_certificates(self.cert_store)
.with_no_client_auth();

config.max_fragment_size = None;
config.alpn_protocols = self.application_protocols;
Expand Down
7 changes: 6 additions & 1 deletion quic/s2n-quic-rustls/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@ pub fn reason(error: rustls::Error) -> &'static str {
Error::DecryptError => "cannot decrypt peer's message",
Error::EncryptError => "cannot encrypt local message",
Error::AlertReceived(_) => "received fatal alert",
Error::InvalidSct(_) => "invalid certificate timestamp",
Error::FailedToGetCurrentTime => "failed to get current time",
Error::FailedToGetRandomBytes => "failed to get random bytes",
Error::HandshakeNotComplete => "handshake not complete",
Error::PeerSentOversizedRecord => "peer sent excess record size",
Error::NoApplicationProtocol => "peer doesn't support any known protocol",
Error::BadMaxFragmentSize => "bad max fragment size",
Error::General(_) => "unexpected error",
Error::InvalidMessage(_) => "invalid message received",
Error::PeerIncompatible(_) => "peer doesn't support a protocol version/feature",
Error::PeerMisbehaved(_) => "peer TLS protocol error",
Error::InvalidCertificate(_) => "invalid certificate",
Error::InvalidCertRevocationList(_) => "invalid crl",
Error::Other(_) => "an unspecific error",
// rustls may add a new variant in the future that breaks us so do a wildcard
#[allow(unreachable_patterns)]
_ => "unexpected error",
Expand Down
Loading

0 comments on commit b8984b4

Please sign in to comment.