Update to rustls 0.23

This commit is contained in:
John Howard 2024-03-26 15:37:00 -07:00 committed by Jan
commit aa6e1c36f8
7 changed files with 116 additions and 44 deletions

View file

@ -19,9 +19,9 @@ resolver = "2"
[workspace.dependencies] [workspace.dependencies]
boring = { version = "4", default-features = false } boring = { version = "4", default-features = false }
boring-sys = { version = "4", default-features = false } boring-sys = { version = "4", default-features = false }
rustls = { version = "0.22", default-features = false } rustls = { version = "0.23", default-features = false }
rustls-pemfile = { version = "2" } rustls-pemfile = { version = "2" }
rustls-pki-types = { version = "1" } rustls-pki-types = { version = "1" }
tokio-rustls = { version = "0.25" } tokio-rustls = { version = "0.26", default-features = false }
webpki = { package = "rustls-webpki", version = "0.102", default-features = false } webpki = { package = "rustls-webpki", version = "0.102", default-features = false }
webpki-roots = { version = "0.26" } webpki-roots = { version = "0.26" }

View file

@ -1,9 +1,11 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use aead::{AeadCore, AeadInPlace, Nonce, Tag}; use aead::{AeadCore, AeadInPlace, Buffer, Nonce, Tag};
use boring::error::ErrorStack; use boring::error::ErrorStack;
use boring_additions::aead::Algorithm; use boring_additions::aead::Algorithm;
use rustls::crypto::cipher::{self, make_tls12_aad, make_tls13_aad, Iv}; use rustls::crypto::cipher::{
self, make_tls12_aad, make_tls13_aad, BorrowedPayload, Iv, PrefixedPayload,
};
use rustls::{ConnectionTrafficSecrets, ContentType, ProtocolVersion}; use rustls::{ConnectionTrafficSecrets, ContentType, ProtocolVersion};
use crate::helper::log_and_map; use crate::helper::log_and_map;
@ -25,6 +27,12 @@ pub(crate) trait BoringCipher {
/// The length of the authentication tag /// The length of the authentication tag
const TAG_LEN: usize; const TAG_LEN: usize;
/// integrity limit
const INTEGRITY_LIMIT: u64;
/// confidentiality limit
const CONFIDENTIALITY_LIMIT: u64;
/// Constructs a new instance of this cipher as an AEAD algorithm /// Constructs a new instance of this cipher as an AEAD algorithm
fn new_cipher() -> Algorithm; fn new_cipher() -> Algorithm;
@ -123,11 +131,10 @@ where
{ {
fn encrypt( fn encrypt(
&mut self, &mut self,
msg: cipher::BorrowedPlainMessage, msg: cipher::OutboundPlainMessage,
seq: u64, seq: u64,
) -> Result<cipher::OpaqueMessage, rustls::Error> { ) -> Result<cipher::OutboundOpaqueMessage, rustls::Error> {
let nonce = cipher::Nonce::new(&self.iv, seq); let nonce = cipher::Nonce::new(&self.iv, seq);
match self.tls_version { match self.tls_version {
#[cfg(feature = "tls12")] #[cfg(feature = "tls12")]
ProtocolVersion::TLSv1_2 => { ProtocolVersion::TLSv1_2 => {
@ -136,37 +143,41 @@ where
let total_len = self.encrypted_payload_len(msg.payload.len()); let total_len = self.encrypted_payload_len(msg.payload.len());
let mut full_payload = Vec::with_capacity(total_len); let mut full_payload = PrefixedPayload::with_capacity(total_len);
full_payload.extend_from_slice(&nonce.0.as_ref()[fixed_iv_len..]); full_payload.extend_from_slice(&nonce.0.as_ref()[fixed_iv_len..]);
full_payload.extend_from_slice(msg.payload); full_payload.extend_from_chunks(&msg.payload);
full_payload.extend_from_slice(&vec![0u8; self.crypter.max_overhead()]); full_payload.extend_from_slice(&vec![0u8; self.crypter.max_overhead()]);
let (_, payload) = full_payload.split_at_mut(explicit_nonce_len); let (_, payload) = full_payload.as_mut().split_at_mut(explicit_nonce_len);
let (payload, tag) = payload.split_at_mut(msg.payload.len()); let (payload, tag) = payload.split_at_mut(msg.payload.len());
let aad = cipher::make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()); let aad = cipher::make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len());
self.crypter self.crypter
.seal_in_place(&nonce.0, &aad, payload, tag) .seal_in_place(&nonce.0, &aad, payload, tag)
.map_err(|_| rustls::Error::EncryptError) .map_err(|_| rustls::Error::EncryptError)
.map(|_| cipher::OpaqueMessage::new(msg.typ, msg.version, full_payload)) .map(|_| cipher::OutboundOpaqueMessage::new(msg.typ, msg.version, full_payload))
} }
ProtocolVersion::TLSv1_3 => { ProtocolVersion::TLSv1_3 => {
let total_len = self.encrypted_payload_len(msg.payload.len()); let total_len = self.encrypted_payload_len(msg.payload.len());
let mut payload = Vec::with_capacity(total_len); let mut payload = PrefixedPayload::with_capacity(total_len);
payload.extend_from_slice(msg.payload); payload.extend_from_chunks(&msg.payload);
payload.push(msg.typ.get_u8()); payload.extend_from_slice(&msg.typ.to_array());
let aad = cipher::make_tls13_aad(total_len); let aad = cipher::make_tls13_aad(total_len);
self.encrypt_in_place(Nonce::<T>::from_slice(&nonce.0), &aad, &mut payload) self.encrypt_in_place(
.map_err(|_| rustls::Error::EncryptError) Nonce::<T>::from_slice(&nonce.0),
.map(|_| { &aad,
cipher::OpaqueMessage::new( &mut EncryptBufferAdapter(&mut payload),
ContentType::ApplicationData, )
ProtocolVersion::TLSv1_2, .map_err(|_| rustls::Error::EncryptError)
payload, .map(|_| {
) cipher::OutboundOpaqueMessage::new(
}) ContentType::ApplicationData,
ProtocolVersion::TLSv1_2,
payload,
)
})
} }
_ => unimplemented!(), _ => unimplemented!(),
} }
@ -187,11 +198,11 @@ impl<T> cipher::MessageDecrypter for BoringAeadCrypter<T>
where where
T: BoringAead, T: BoringAead,
{ {
fn decrypt( fn decrypt<'a>(
&mut self, &mut self,
mut m: cipher::OpaqueMessage, mut m: cipher::InboundOpaqueMessage<'a>,
seq: u64, seq: u64,
) -> Result<cipher::PlainMessage, rustls::Error> { ) -> Result<cipher::InboundPlainMessage<'a>, rustls::Error> {
match self.tls_version { match self.tls_version {
#[cfg(feature = "tls12")] #[cfg(feature = "tls12")]
ProtocolVersion::TLSv1_2 => { ProtocolVersion::TLSv1_2 => {
@ -199,11 +210,11 @@ where
// payload is: [nonce] | [ciphertext] | [auth tag] // payload is: [nonce] | [ciphertext] | [auth tag]
let actual_payload_length = let actual_payload_length =
m.payload().len() - self.crypter.max_overhead() - explicit_nonce_len; m.payload.len() - self.crypter.max_overhead() - explicit_nonce_len;
let aad = make_tls12_aad(seq, m.typ, m.version, actual_payload_length); let aad = make_tls12_aad(seq, m.typ, m.version, actual_payload_length);
let payload = m.payload_mut(); let payload = &mut m.payload;
// get the nonce // get the nonce
let (explicit_nonce, payload) = payload.split_at_mut(explicit_nonce_len); let (explicit_nonce, payload) = payload.split_at_mut(explicit_nonce_len);
@ -230,20 +241,24 @@ where
.map_err(|e| log_and_map("open_in_place", e, rustls::Error::DecryptError)) .map_err(|e| log_and_map("open_in_place", e, rustls::Error::DecryptError))
.map(|_| { .map(|_| {
// rotate the nonce to the end // rotate the nonce to the end
m.payload_mut().rotate_left(explicit_nonce_len); m.payload.rotate_left(explicit_nonce_len);
// truncate buffer to the actual payload // truncate buffer to the actual payload
m.payload_mut().truncate(actual_payload_length); m.payload.truncate(actual_payload_length);
m.into_plain_message() m.into_plain_message()
}) })
} }
ProtocolVersion::TLSv1_3 => { ProtocolVersion::TLSv1_3 => {
let nonce = cipher::Nonce::new(&self.iv, seq); let nonce = cipher::Nonce::new(&self.iv, seq);
let aad = make_tls13_aad(m.payload().len()); let aad = make_tls13_aad(m.payload.len());
self.decrypt_in_place(Nonce::<T>::from_slice(&nonce.0), &aad, m.payload_mut()) self.decrypt_in_place(
.map_err(|_| rustls::Error::DecryptError) Nonce::<T>::from_slice(&nonce.0),
.and_then(|_| m.into_tls13_unpadded_message()) &aad,
&mut DecryptBufferAdapter(&mut m.payload),
)
.map_err(|_| rustls::Error::DecryptError)
.and_then(|_| m.into_tls13_unpadded_message())
} }
_ => unimplemented!(), _ => unimplemented!(),
} }
@ -290,6 +305,14 @@ where
fn tag_len(&self) -> usize { fn tag_len(&self) -> usize {
<T as BoringCipher>::TAG_LEN <T as BoringCipher>::TAG_LEN
} }
fn confidentiality_limit(&self) -> u64 {
<T as BoringCipher>::CONFIDENTIALITY_LIMIT
}
fn integrity_limit(&self) -> u64 {
<T as BoringCipher>::INTEGRITY_LIMIT
}
} }
pub(crate) struct Aead<T>(PhantomData<T>); pub(crate) struct Aead<T>(PhantomData<T>);
@ -494,6 +517,55 @@ where
} }
} }
struct DecryptBufferAdapter<'a, 'p>(&'a mut BorrowedPayload<'p>);
impl AsRef<[u8]> for DecryptBufferAdapter<'_, '_> {
fn as_ref(&self) -> &[u8] {
self.0
}
}
impl AsMut<[u8]> for DecryptBufferAdapter<'_, '_> {
fn as_mut(&mut self) -> &mut [u8] {
self.0
}
}
impl Buffer for DecryptBufferAdapter<'_, '_> {
fn extend_from_slice(&mut self, _: &[u8]) -> aead::Result<()> {
unreachable!("not used by `AeadInPlace::decrypt_in_place`")
}
fn truncate(&mut self, len: usize) {
self.0.truncate(len)
}
}
struct EncryptBufferAdapter<'a>(&'a mut PrefixedPayload);
impl AsRef<[u8]> for EncryptBufferAdapter<'_> {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl AsMut<[u8]> for EncryptBufferAdapter<'_> {
fn as_mut(&mut self) -> &mut [u8] {
self.0.as_mut()
}
}
impl Buffer for EncryptBufferAdapter<'_> {
fn extend_from_slice(&mut self, other: &[u8]) -> aead::Result<()> {
self.0.extend_from_slice(other);
Ok(())
}
fn truncate(&mut self, len: usize) {
self.0.truncate(len)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use hex_literal::hex; use hex_literal::hex;

View file

@ -17,6 +17,9 @@ impl BoringCipher for Aes128 {
const TAG_LEN: usize = 16; const TAG_LEN: usize = 16;
const INTEGRITY_LIMIT: u64 = 1 << 52;
const CONFIDENTIALITY_LIMIT: u64 = 1 << 23;
fn new_cipher() -> Algorithm { fn new_cipher() -> Algorithm {
Algorithm::aes_128_gcm() Algorithm::aes_128_gcm()
} }
@ -58,6 +61,9 @@ impl BoringCipher for Aes256 {
const TAG_LEN: usize = 16; const TAG_LEN: usize = 16;
const INTEGRITY_LIMIT: u64 = 1 << 52;
const CONFIDENTIALITY_LIMIT: u64 = 1 << 23;
fn new_cipher() -> Algorithm { fn new_cipher() -> Algorithm {
Algorithm::aes_256_gcm() Algorithm::aes_256_gcm()
} }

View file

@ -20,6 +20,9 @@ impl BoringCipher for ChaCha20Poly1305 {
const TAG_LEN: usize = 16; const TAG_LEN: usize = 16;
const INTEGRITY_LIMIT: u64 = 1 << 36;
const CONFIDENTIALITY_LIMIT: u64 = u64::MAX;
fn new_cipher() -> Algorithm { fn new_cipher() -> Algorithm {
Algorithm::chacha20_poly1305() Algorithm::chacha20_poly1305()
} }

View file

@ -27,7 +27,6 @@ pub static ECDHE_ECDSA_AES128_GCM_SHA256: Tls12CipherSuite = Tls12CipherSuite {
suite: rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, suite: rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
hash_provider: hash::SHA256, hash_provider: hash::SHA256,
confidentiality_limit: 1 << 23, confidentiality_limit: 1 << 23,
integrity_limit: 1 << 52,
}, },
aead_alg: &aead::Aead::<aead::aes::Aes128>::DEFAULT, aead_alg: &aead::Aead::<aead::aes::Aes128>::DEFAULT,
prf_provider: &PRF_SHA256, prf_provider: &PRF_SHA256,
@ -40,7 +39,6 @@ pub static ECDHE_RSA_AES128_GCM_SHA256: Tls12CipherSuite = Tls12CipherSuite {
suite: rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, suite: rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
hash_provider: hash::SHA256, hash_provider: hash::SHA256,
confidentiality_limit: 1 << 23, confidentiality_limit: 1 << 23,
integrity_limit: 1 << 52,
}, },
aead_alg: &aead::Aead::<aead::aes::Aes128>::DEFAULT, aead_alg: &aead::Aead::<aead::aes::Aes128>::DEFAULT,
prf_provider: &PRF_SHA256, prf_provider: &PRF_SHA256,
@ -53,7 +51,6 @@ pub static ECDHE_ECDSA_AES256_GCM_SHA384: Tls12CipherSuite = Tls12CipherSuite {
suite: rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, suite: rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
hash_provider: hash::SHA384, hash_provider: hash::SHA384,
confidentiality_limit: 1 << 23, confidentiality_limit: 1 << 23,
integrity_limit: 1 << 52,
}, },
aead_alg: &aead::Aead::<aead::aes::Aes256>::DEFAULT, aead_alg: &aead::Aead::<aead::aes::Aes256>::DEFAULT,
prf_provider: &PRF_SHA384, prf_provider: &PRF_SHA384,
@ -66,7 +63,6 @@ pub static ECDHE_RSA_AES256_GCM_SHA384: Tls12CipherSuite = Tls12CipherSuite {
suite: rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, suite: rustls::CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
hash_provider: hash::SHA384, hash_provider: hash::SHA384,
confidentiality_limit: 1 << 23, confidentiality_limit: 1 << 23,
integrity_limit: 1 << 52,
}, },
aead_alg: &aead::Aead::<aead::aes::Aes256>::DEFAULT, aead_alg: &aead::Aead::<aead::aes::Aes256>::DEFAULT,
prf_provider: &PRF_SHA384, prf_provider: &PRF_SHA384,
@ -79,7 +75,6 @@ pub static ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: Tls12CipherSuite = Tls12Ci
suite: rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, suite: rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
hash_provider: hash::SHA256, hash_provider: hash::SHA256,
confidentiality_limit: u64::MAX, confidentiality_limit: u64::MAX,
integrity_limit: 1 << 36,
}, },
aead_alg: &aead::Aead::<aead::chacha20::ChaCha20Poly1305>::DEFAULT, aead_alg: &aead::Aead::<aead::chacha20::ChaCha20Poly1305>::DEFAULT,
prf_provider: &PRF_SHA256, prf_provider: &PRF_SHA256,
@ -92,7 +87,6 @@ pub static ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: Tls12CipherSuite = Tls12Ciph
suite: rustls::CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, suite: rustls::CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
hash_provider: hash::SHA256, hash_provider: hash::SHA256,
confidentiality_limit: u64::MAX, confidentiality_limit: u64::MAX,
integrity_limit: 1 << 36,
}, },
aead_alg: &aead::Aead::<aead::chacha20::ChaCha20Poly1305>::DEFAULT, aead_alg: &aead::Aead::<aead::chacha20::ChaCha20Poly1305>::DEFAULT,
prf_provider: &PRF_SHA256, prf_provider: &PRF_SHA256,

View file

@ -7,7 +7,6 @@ pub static AES_128_GCM_SHA256: Tls13CipherSuite = Tls13CipherSuite {
suite: rustls::CipherSuite::TLS13_AES_128_GCM_SHA256, suite: rustls::CipherSuite::TLS13_AES_128_GCM_SHA256,
hash_provider: hash::SHA256, hash_provider: hash::SHA256,
confidentiality_limit: 1 << 23, confidentiality_limit: 1 << 23,
integrity_limit: 1 << 52,
}, },
hkdf_provider: &hkdf::Hkdf::<hkdf::Sha256>::DEFAULT, hkdf_provider: &hkdf::Hkdf::<hkdf::Sha256>::DEFAULT,
aead_alg: &aead::Aead::<aead::aes::Aes128>::DEFAULT, aead_alg: &aead::Aead::<aead::aes::Aes128>::DEFAULT,
@ -19,7 +18,6 @@ pub static AES_256_GCM_SHA384: Tls13CipherSuite = Tls13CipherSuite {
suite: rustls::CipherSuite::TLS13_AES_256_GCM_SHA384, suite: rustls::CipherSuite::TLS13_AES_256_GCM_SHA384,
hash_provider: hash::SHA384, hash_provider: hash::SHA384,
confidentiality_limit: 1 << 23, confidentiality_limit: 1 << 23,
integrity_limit: 1 << 52,
}, },
hkdf_provider: &hkdf::Hkdf::<hkdf::Sha384>::DEFAULT, hkdf_provider: &hkdf::Hkdf::<hkdf::Sha384>::DEFAULT,
aead_alg: &aead::Aead::<aead::aes::Aes256>::DEFAULT, aead_alg: &aead::Aead::<aead::aes::Aes256>::DEFAULT,
@ -31,7 +29,6 @@ pub static CHACHA20_POLY1305_SHA256: Tls13CipherSuite = Tls13CipherSuite {
suite: rustls::CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, suite: rustls::CipherSuite::TLS13_CHACHA20_POLY1305_SHA256,
hash_provider: hash::SHA256, hash_provider: hash::SHA256,
confidentiality_limit: u64::MAX, confidentiality_limit: u64::MAX,
integrity_limit: 1 << 36,
}, },
hkdf_provider: &hkdf::Hkdf::<hkdf::Sha256>::DEFAULT, hkdf_provider: &hkdf::Hkdf::<hkdf::Sha256>::DEFAULT,

View file

@ -13,7 +13,7 @@ log = { version = "0.4.4" }
mio = { version = "0.8", features = ["net", "os-poll"] } mio = { version = "0.8", features = ["net", "os-poll"] }
pki-types = { package = "rustls-pki-types", version = "0.2" } pki-types = { package = "rustls-pki-types", version = "0.2" }
rcgen = { version = "0.11.3", features = ["pem"], default-features = false } rcgen = { version = "0.11.3", features = ["pem"], default-features = false }
rustls = { workspace = true, features = [ "logging" ]} rustls = { workspace = true, features = [ "logging", "std" ]}
boring-rustls-provider = { path = "../boring-rustls-provider", features = ["logging"] } boring-rustls-provider = { path = "../boring-rustls-provider", features = ["logging"] }
rustls-pemfile = { workspace = true } rustls-pemfile = { workspace = true }
serde = "1.0" serde = "1.0"