From aa6e1c36f880002ceb56f99a64d19e0503e0bec7 Mon Sep 17 00:00:00 2001 From: John Howard Date: Tue, 26 Mar 2024 15:37:00 -0700 Subject: [PATCH] Update to rustls 0.23 --- Cargo.toml | 4 +- boring-rustls-provider/src/aead.rs | 136 +++++++++++++++----- boring-rustls-provider/src/aead/aes.rs | 6 + boring-rustls-provider/src/aead/chacha20.rs | 3 + boring-rustls-provider/src/tls12.rs | 6 - boring-rustls-provider/src/tls13.rs | 3 - examples/Cargo.toml | 2 +- 7 files changed, 116 insertions(+), 44 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dfc9608..5bda8df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,9 +19,9 @@ resolver = "2" [workspace.dependencies] boring = { 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-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-roots = { version = "0.26" } diff --git a/boring-rustls-provider/src/aead.rs b/boring-rustls-provider/src/aead.rs index 800b487..b3cc1ba 100644 --- a/boring-rustls-provider/src/aead.rs +++ b/boring-rustls-provider/src/aead.rs @@ -1,9 +1,11 @@ use std::marker::PhantomData; -use aead::{AeadCore, AeadInPlace, Nonce, Tag}; +use aead::{AeadCore, AeadInPlace, Buffer, Nonce, Tag}; use boring::error::ErrorStack; 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 crate::helper::log_and_map; @@ -25,6 +27,12 @@ pub(crate) trait BoringCipher { /// The length of the authentication tag 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 fn new_cipher() -> Algorithm; @@ -123,11 +131,10 @@ where { fn encrypt( &mut self, - msg: cipher::BorrowedPlainMessage, + msg: cipher::OutboundPlainMessage, seq: u64, - ) -> Result { + ) -> Result { let nonce = cipher::Nonce::new(&self.iv, seq); - match self.tls_version { #[cfg(feature = "tls12")] ProtocolVersion::TLSv1_2 => { @@ -136,37 +143,41 @@ where 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(msg.payload); + full_payload.extend_from_chunks(&msg.payload); 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 aad = cipher::make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()); self.crypter .seal_in_place(&nonce.0, &aad, payload, tag) .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 => { let total_len = self.encrypted_payload_len(msg.payload.len()); - let mut payload = Vec::with_capacity(total_len); - payload.extend_from_slice(msg.payload); - payload.push(msg.typ.get_u8()); + let mut payload = PrefixedPayload::with_capacity(total_len); + payload.extend_from_chunks(&msg.payload); + payload.extend_from_slice(&msg.typ.to_array()); let aad = cipher::make_tls13_aad(total_len); - self.encrypt_in_place(Nonce::::from_slice(&nonce.0), &aad, &mut payload) - .map_err(|_| rustls::Error::EncryptError) - .map(|_| { - cipher::OpaqueMessage::new( - ContentType::ApplicationData, - ProtocolVersion::TLSv1_2, - payload, - ) - }) + self.encrypt_in_place( + Nonce::::from_slice(&nonce.0), + &aad, + &mut EncryptBufferAdapter(&mut payload), + ) + .map_err(|_| rustls::Error::EncryptError) + .map(|_| { + cipher::OutboundOpaqueMessage::new( + ContentType::ApplicationData, + ProtocolVersion::TLSv1_2, + payload, + ) + }) } _ => unimplemented!(), } @@ -187,11 +198,11 @@ impl cipher::MessageDecrypter for BoringAeadCrypter where T: BoringAead, { - fn decrypt( + fn decrypt<'a>( &mut self, - mut m: cipher::OpaqueMessage, + mut m: cipher::InboundOpaqueMessage<'a>, seq: u64, - ) -> Result { + ) -> Result, rustls::Error> { match self.tls_version { #[cfg(feature = "tls12")] ProtocolVersion::TLSv1_2 => { @@ -199,11 +210,11 @@ where // payload is: [nonce] | [ciphertext] | [auth tag] 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 payload = m.payload_mut(); + let payload = &mut m.payload; // get the nonce 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(|_| { // 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 - m.payload_mut().truncate(actual_payload_length); + m.payload.truncate(actual_payload_length); m.into_plain_message() }) } ProtocolVersion::TLSv1_3 => { let nonce = cipher::Nonce::new(&self.iv, seq); - let aad = make_tls13_aad(m.payload().len()); - self.decrypt_in_place(Nonce::::from_slice(&nonce.0), &aad, m.payload_mut()) - .map_err(|_| rustls::Error::DecryptError) - .and_then(|_| m.into_tls13_unpadded_message()) + let aad = make_tls13_aad(m.payload.len()); + self.decrypt_in_place( + Nonce::::from_slice(&nonce.0), + &aad, + &mut DecryptBufferAdapter(&mut m.payload), + ) + .map_err(|_| rustls::Error::DecryptError) + .and_then(|_| m.into_tls13_unpadded_message()) } _ => unimplemented!(), } @@ -290,6 +305,14 @@ where fn tag_len(&self) -> usize { ::TAG_LEN } + + fn confidentiality_limit(&self) -> u64 { + ::CONFIDENTIALITY_LIMIT + } + + fn integrity_limit(&self) -> u64 { + ::INTEGRITY_LIMIT + } } pub(crate) struct Aead(PhantomData); @@ -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)] mod tests { use hex_literal::hex; diff --git a/boring-rustls-provider/src/aead/aes.rs b/boring-rustls-provider/src/aead/aes.rs index 712d6ce..6a5e2af 100644 --- a/boring-rustls-provider/src/aead/aes.rs +++ b/boring-rustls-provider/src/aead/aes.rs @@ -17,6 +17,9 @@ impl BoringCipher for Aes128 { const TAG_LEN: usize = 16; + const INTEGRITY_LIMIT: u64 = 1 << 52; + const CONFIDENTIALITY_LIMIT: u64 = 1 << 23; + fn new_cipher() -> Algorithm { Algorithm::aes_128_gcm() } @@ -58,6 +61,9 @@ impl BoringCipher for Aes256 { const TAG_LEN: usize = 16; + const INTEGRITY_LIMIT: u64 = 1 << 52; + const CONFIDENTIALITY_LIMIT: u64 = 1 << 23; + fn new_cipher() -> Algorithm { Algorithm::aes_256_gcm() } diff --git a/boring-rustls-provider/src/aead/chacha20.rs b/boring-rustls-provider/src/aead/chacha20.rs index 0681fc7..2590aab 100644 --- a/boring-rustls-provider/src/aead/chacha20.rs +++ b/boring-rustls-provider/src/aead/chacha20.rs @@ -20,6 +20,9 @@ impl BoringCipher for ChaCha20Poly1305 { const TAG_LEN: usize = 16; + const INTEGRITY_LIMIT: u64 = 1 << 36; + const CONFIDENTIALITY_LIMIT: u64 = u64::MAX; + fn new_cipher() -> Algorithm { Algorithm::chacha20_poly1305() } diff --git a/boring-rustls-provider/src/tls12.rs b/boring-rustls-provider/src/tls12.rs index 677389e..caef421 100644 --- a/boring-rustls-provider/src/tls12.rs +++ b/boring-rustls-provider/src/tls12.rs @@ -27,7 +27,6 @@ pub static ECDHE_ECDSA_AES128_GCM_SHA256: Tls12CipherSuite = Tls12CipherSuite { suite: rustls::CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, hash_provider: hash::SHA256, confidentiality_limit: 1 << 23, - integrity_limit: 1 << 52, }, aead_alg: &aead::Aead::::DEFAULT, 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, hash_provider: hash::SHA256, confidentiality_limit: 1 << 23, - integrity_limit: 1 << 52, }, aead_alg: &aead::Aead::::DEFAULT, 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, hash_provider: hash::SHA384, confidentiality_limit: 1 << 23, - integrity_limit: 1 << 52, }, aead_alg: &aead::Aead::::DEFAULT, 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, hash_provider: hash::SHA384, confidentiality_limit: 1 << 23, - integrity_limit: 1 << 52, }, aead_alg: &aead::Aead::::DEFAULT, 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, hash_provider: hash::SHA256, confidentiality_limit: u64::MAX, - integrity_limit: 1 << 36, }, aead_alg: &aead::Aead::::DEFAULT, 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, hash_provider: hash::SHA256, confidentiality_limit: u64::MAX, - integrity_limit: 1 << 36, }, aead_alg: &aead::Aead::::DEFAULT, prf_provider: &PRF_SHA256, diff --git a/boring-rustls-provider/src/tls13.rs b/boring-rustls-provider/src/tls13.rs index 81bdc23..e2a45c8 100644 --- a/boring-rustls-provider/src/tls13.rs +++ b/boring-rustls-provider/src/tls13.rs @@ -7,7 +7,6 @@ pub static AES_128_GCM_SHA256: Tls13CipherSuite = Tls13CipherSuite { suite: rustls::CipherSuite::TLS13_AES_128_GCM_SHA256, hash_provider: hash::SHA256, confidentiality_limit: 1 << 23, - integrity_limit: 1 << 52, }, hkdf_provider: &hkdf::Hkdf::::DEFAULT, aead_alg: &aead::Aead::::DEFAULT, @@ -19,7 +18,6 @@ pub static AES_256_GCM_SHA384: Tls13CipherSuite = Tls13CipherSuite { suite: rustls::CipherSuite::TLS13_AES_256_GCM_SHA384, hash_provider: hash::SHA384, confidentiality_limit: 1 << 23, - integrity_limit: 1 << 52, }, hkdf_provider: &hkdf::Hkdf::::DEFAULT, aead_alg: &aead::Aead::::DEFAULT, @@ -31,7 +29,6 @@ pub static CHACHA20_POLY1305_SHA256: Tls13CipherSuite = Tls13CipherSuite { suite: rustls::CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, hash_provider: hash::SHA256, confidentiality_limit: u64::MAX, - integrity_limit: 1 << 36, }, hkdf_provider: &hkdf::Hkdf::::DEFAULT, diff --git a/examples/Cargo.toml b/examples/Cargo.toml index d2e4700..9d2084d 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -13,7 +13,7 @@ log = { version = "0.4.4" } mio = { version = "0.8", features = ["net", "os-poll"] } pki-types = { package = "rustls-pki-types", version = "0.2" } 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"] } rustls-pemfile = { workspace = true } serde = "1.0"