diff --git a/crates/core/src/config/prove.rs b/crates/core/src/config/prove.rs index ce32ab389b..d411734c2d 100644 --- a/crates/core/src/config/prove.rs +++ b/crates/core/src/config/prove.rs @@ -6,7 +6,10 @@ use rangeset::{ }; use serde::{Deserialize, Serialize}; -use crate::transcript::{Direction, Transcript, TranscriptCommitConfig, TranscriptCommitRequest}; +use crate::{ + hash::{Blinder, HashAlgId}, + transcript::{Direction, Transcript, TranscriptCommitConfig, TranscriptCommitRequest}, +}; /// Configuration to prove information to the verifier. #[derive(Debug, Clone, Serialize, Deserialize)] @@ -14,6 +17,11 @@ pub struct ProveConfig { server_identity: bool, reveal: Option<(RangeSet, RangeSet)>, transcript_commit: Option, + /// Prover-local blinders for hash commitments. Never serialized: the + /// verifier learns commitment values from the proving computation, never + /// from the prover's configuration. + #[serde(skip)] + hash_blinders: Vec<(Direction, RangeSet, HashAlgId, Blinder)>, } impl ProveConfig { @@ -38,7 +46,22 @@ impl ProveConfig { self.transcript_commit.as_ref() } + /// Returns the prover-selected blinder for one hash commitment, if any. + pub fn hash_blinder( + &self, + direction: Direction, + idx: &RangeSet, + alg: HashAlgId, + ) -> Option<&Blinder> { + self.hash_blinders + .iter() + .find(|(d, i, a, _)| *d == direction && i == idx && *a == alg) + .map(|(_, _, _, blinder)| blinder) + } + /// Returns a request. + /// + /// Hash blinders stay prover-local and never appear in the request. pub fn to_request(&self) -> ProveRequest { ProveRequest { server_identity: self.server_identity, @@ -58,6 +81,7 @@ pub struct ProveConfigBuilder<'a> { server_identity: bool, reveal: Option<(RangeSet, RangeSet)>, transcript_commit: Option, + hash_blinders: Vec<(Direction, RangeSet, HashAlgId, Blinder)>, } impl<'a> ProveConfigBuilder<'a> { @@ -68,6 +92,7 @@ impl<'a> ProveConfigBuilder<'a> { server_identity: false, reveal: None, transcript_commit: None, + hash_blinders: Vec::new(), } } @@ -83,6 +108,26 @@ impl<'a> ProveConfigBuilder<'a> { self } + /// Uses a caller-supplied blinder for one hash commitment instead of + /// sampling one during proving. + /// + /// The prover can then derive the commitment value locally and start + /// dependent work before the proving phase. The blinder must come from a + /// cryptographically secure source and be used for exactly one + /// commitment. It never leaves the prover: the verifier learns the + /// commitment from the proving computation alone. + pub fn hash_blinder( + &mut self, + direction: Direction, + ranges: impl IntoRangeIterator, + alg: HashAlgId, + blinder: Blinder, + ) -> &mut Self { + self.hash_blinders + .push((direction, RangeSet::from_range_iter(ranges), alg, blinder)); + self + } + /// Reveals the given ranges of the transcript. pub fn reveal( &mut self, @@ -152,6 +197,7 @@ impl<'a> ProveConfigBuilder<'a> { server_identity: self.server_identity, reveal: self.reveal, transcript_commit: self.transcript_commit, + hash_blinders: self.hash_blinders, }) } } diff --git a/crates/core/src/hash.rs b/crates/core/src/hash.rs index d43dc2d6c6..24e155c6b9 100644 --- a/crates/core/src/hash.rs +++ b/crates/core/src/hash.rs @@ -245,6 +245,17 @@ pub struct Blinder([u8; 16]); opaque_debug::implement!(Blinder); impl Blinder { + /// Creates a blinder from caller-supplied randomness. + /// + /// A prover that chooses its own blinder can derive the commitment value + /// locally and start dependent work before the proving phase. The blinder + /// only hides the prover's own pre-image from the verifier, so choosing + /// it early adds no verifier-side assumption; it must still come from a + /// cryptographically secure source and be used for exactly one commitment. + pub fn new(blinder: [u8; 16]) -> Self { + Self(blinder) + } + /// Returns the blinder as a byte slice. pub fn as_bytes(&self) -> &[u8] { &self.0 diff --git a/crates/mpc-tls/src/record_layer/aead/aes_gcm.rs b/crates/mpc-tls/src/record_layer/aead/aes_gcm.rs index 5848a61563..a9a1fb0816 100644 --- a/crates/mpc-tls/src/record_layer/aead/aes_gcm.rs +++ b/crates/mpc-tls/src/record_layer/aead/aes_gcm.rs @@ -97,7 +97,11 @@ impl MpcAesGcm { vm.assign(zero_block, [0u8; 16])?; vm.commit(zero_block)?; - ghash.alloc()?; + // Size GHASH preprocessing to the largest single record this + // allocation admits instead of always paying for a maximum-size TLS + // record. `powers_for_len` clamps to the old bound, so a caller that + // provisions more than one full record is unchanged. + ghash.alloc(super::ghash::powers_for_len(len))?; let ghash_key = self.aes.alloc_block(vm, zero_block)?; let ghash_key_share = OneTimePadShared::<[u8; 16]>::new(self.role, ghash_key, vm)?; diff --git a/crates/mpc-tls/src/record_layer/aead/ghash.rs b/crates/mpc-tls/src/record_layer/aead/ghash.rs index bb6af5c6cf..f63fb48312 100644 --- a/crates/mpc-tls/src/record_layer/aead/ghash.rs +++ b/crates/mpc-tls/src/record_layer/aead/ghash.rs @@ -16,12 +16,25 @@ use serde::{Deserialize, Serialize}; use crate::record_layer::aead::AeadError; /// Maximum exponent used in GHASH. -const MAX_POWER: usize = 1026; +/// +/// A maximum-size TLS record needs 1024 ciphertext blocks plus one AAD block +/// and one length block, so no single record can need more powers than this. +pub(crate) const MAX_POWER: usize = 1026; + +/// Highest exponent a GHASH input of `len` bytes can need. +/// +/// One AAD block and one length block accompany the padded ciphertext. The +/// result is clamped to [`MAX_POWER`], so a caller that provisions more than +/// one maximum-size record still allocates exactly the old amount, and is +/// rounded up to an even value because odd powers are converted in pairs. +pub(crate) fn powers_for_len(len: usize) -> usize { + (len.div_ceil(16) + 2).min(MAX_POWER).next_multiple_of(2) +} #[async_trait] pub(crate) trait Ghash { - /// Allocates resources needed for GHASH. - fn alloc(&mut self) -> Result<(), GhashError>; + /// Allocates resources needed for GHASH up to `max_power` exponents. + fn alloc(&mut self, max_power: usize) -> Result<(), GhashError>; /// Preprocesses GHASH. async fn preprocess(&mut self, ctx: &mut Context) -> Result<(), GhashError>; @@ -41,6 +54,10 @@ pub(crate) struct MpcGhash { state: State, converter: C, alloc: bool, + /// Exponent bound fixed by [`Ghash::alloc`]; `setup` and `compute` must + /// use this same value or the share vector and the block offset in + /// `compute` disagree and produce a wrong tag share without an error. + max_power: usize, } #[derive(Debug)] @@ -68,6 +85,7 @@ impl MpcGhash { state: State::Init, converter, alloc: false, + max_power: MAX_POWER, } } } @@ -78,8 +96,15 @@ where C: AdditiveToMultiplicative + Flush + Send, C: MultiplicativeToAdditive + Flush + Send, { - fn alloc(&mut self) -> Result<(), GhashError> { + fn alloc(&mut self, max_power: usize) -> Result<(), GhashError> { if !self.alloc { + if max_power < 2 || max_power > MAX_POWER || max_power % 2 != 0 { + return Err(GhashError::state(format!( + "max_power must be even and in 2..={MAX_POWER}, got {max_power}" + ))); + } + self.max_power = max_power; + // Odd powers are computed using M2A, even powers are computed // locally. We need one extra A2M conversion in the beginning. // Both M2A and A2M, each require a single OLE. @@ -87,7 +112,7 @@ where .map_err(GhashError::conversion)?; // -1 because the odd power H^1 is already known at this point. - MultiplicativeToAdditive::::alloc(&mut self.converter, (MAX_POWER / 2) - 1) + MultiplicativeToAdditive::::alloc(&mut self.converter, (max_power / 2) - 1) .map_err(GhashError::conversion)?; self.alloc = true; @@ -150,8 +175,9 @@ where // Compute the odd powers of the multiplicative key share. // - // Resulting vector contains odd powers of H from H^3 to H^1025. - let odd_shares: Vec<_> = (0..MAX_POWER) + // Resulting vector contains odd powers of H from H^3 to + // H^(max_power - 1). + let odd_shares: Vec<_> = (0..self.max_power) .scan(mult_key, |acc, _| { let power_n = *acc; *acc = power_n * mult_key; @@ -180,7 +206,7 @@ where .expect("share should be computed") .shares; - let shares = compute_shares(add_key, &add_shares_odd); + let shares = compute_shares(add_key, &add_shares_odd, self.max_power); self.state = State::Ready { shares }; @@ -195,10 +221,10 @@ where // Divide by block length and round up. let block_count = input.len() / 16 + !input.len().is_multiple_of(16) as usize; - if block_count > MAX_POWER { + if block_count > self.max_power { return Err(ErrorRepr::InputLength { len: block_count, - max: MAX_POWER * 16, + max: self.max_power * 16, } .into()); } @@ -237,14 +263,17 @@ where /// /// * `key` - Additive share of H. /// * `odd_powers` - Additive shares of odd powers of H starting at H^3. -fn compute_shares(key: Gf2_128, odd_powers: &[Gf2_128]) -> Vec { - let mut shares = Vec::with_capacity(MAX_POWER); +/// * `max_power` - Highest power to compute; must equal the value passed to +/// [`Ghash::alloc`], because `compute` derives its block offset from the +/// length of the returned vector. +fn compute_shares(key: Gf2_128, odd_powers: &[Gf2_128], max_power: usize) -> Vec { + let mut shares = Vec::with_capacity(max_power); // H^1 shares.push(key); let mut odd_idx = 0; - for i in 2..=MAX_POWER { + for i in 2..=max_power { if i % 2 == 0 { // Even power, compute by squaring the square root power. let base = shares[i / 2 - 1]; @@ -351,12 +380,21 @@ mod tests { fn create_pair() -> ( MpcGhash>, MpcGhash>, + ) { + create_pair_with(MAX_POWER) + } + + fn create_pair_with( + max_power: usize, + ) -> ( + MpcGhash>, + MpcGhash>, ) { let (convert_a, convert_b) = ideal_share_convert(Block::ZERO); let (mut sender, mut receiver) = (MpcGhash::new(convert_a), MpcGhash::new(convert_b)); - sender.alloc().unwrap(); - receiver.alloc().unwrap(); + sender.alloc(max_power).unwrap(); + receiver.alloc(max_power).unwrap(); (sender, receiver) } @@ -381,11 +419,91 @@ mod tests { .cloned() .collect::>(); - let powers = compute_shares(key, &odd_powers); + let powers = compute_shares(key, &odd_powers, MAX_POWER); assert_eq!(powers, expected_powers); } + #[test] + fn bounded_shares_match_the_unbounded_prefix() { + let mut rng = StdRng::seed_from_u64(0); + let key = Gf2_128::rand(&mut rng); + let all: Vec<_> = (0..MAX_POWER) + .scan(key, |acc, _| { + let power_n = *acc; + *acc = power_n * key; + Some(power_n) + }) + .collect(); + let odd: Vec<_> = all.iter().skip(2).step_by(2).cloned().collect(); + + for max_power in [2, 4, 56, 1026] { + let bounded = compute_shares(key, &odd[..(max_power / 2) - 1], max_power); + assert_eq!(bounded.len(), max_power); + assert_eq!(bounded, all[..max_power]); + } + } + + #[test] + fn powers_for_len_covers_the_input_and_clamps() { + // One AAD block and one length block accompany the padded ciphertext. + assert_eq!(powers_for_len(0), 2); + assert_eq!(powers_for_len(16), 4); + assert_eq!(powers_for_len(17), 4); + assert_eq!(powers_for_len(33), 6); + assert_eq!(powers_for_len(855), 56); + assert_eq!(powers_for_len(16 * 1024), 1026); + assert_eq!(powers_for_len(usize::MAX / 2), MAX_POWER); + for len in [0, 1, 15, 16, 17, 64, 855, 4096] { + assert!(powers_for_len(len) >= len.div_ceil(16) + 2); + assert_eq!(powers_for_len(len) % 2, 0); + } + } + + #[test] + fn alloc_rejects_bounds_it_cannot_honor() { + let (convert_a, _) = ideal_share_convert(Block::ZERO); + let mut ghash = MpcGhash::new(convert_a); + assert!(ghash.alloc(0).is_err()); + assert!(ghash.alloc(3).is_err()); + assert!(ghash.alloc(MAX_POWER + 2).is_err()); + ghash.alloc(56).unwrap(); + } + + #[tokio::test] + async fn bounded_ghash_accepts_its_limit_and_rejects_one_block_more() { + let (mut ctx_a, mut ctx_b) = test_st_context(8); + let mut rng = StdRng::seed_from_u64(7); + let h: u128 = rng.random(); + let sender_key: u128 = rng.random(); + let receiver_key: u128 = h ^ sender_key; + + // Four powers cover an input of two 16-byte blocks plus the AAD and + // length blocks that a real record adds. + let max_power = 4; + let (mut sender, mut receiver) = create_pair_with(max_power); + sender.set_key(sender_key.to_be_bytes().to_vec()).unwrap(); + receiver + .set_key(receiver_key.to_be_bytes().to_vec()) + .unwrap(); + tokio::try_join!(sender.setup(&mut ctx_a), receiver.setup(&mut ctx_b)).unwrap(); + + let at_limit: Vec = (0..16 * max_power).map(|_| rng.random()).collect(); + let sender_share = sender.compute(&at_limit).unwrap(); + let receiver_share = receiver.compute(&at_limit).unwrap(); + let combined: Vec = sender_share + .iter() + .zip(receiver_share.iter()) + .map(|(a, b)| a ^ b) + .collect(); + assert_eq!(combined, ghash_reference_impl(h, &at_limit)); + + let mut over_limit = at_limit; + over_limit.push(0); + assert!(sender.compute(&over_limit).is_err()); + assert!(receiver.compute(&over_limit).is_err()); + } + #[tokio::test] async fn test_ghash_output() { let (mut ctx_a, mut ctx_b) = test_st_context(8); diff --git a/crates/tls/client/examples/internal/bench.rs b/crates/tls/client/examples/internal/bench.rs index 8ed211f486..5597117cd0 100644 --- a/crates/tls/client/examples/internal/bench.rs +++ b/crates/tls/client/examples/internal/bench.rs @@ -4,12 +4,12 @@ // etc. because it's unstable at the time of writing. use rustls::{ + ClientConfig, ClientConnection, ConnectionCommon, RootCertStore, ServerConfig, + ServerConnection, SideData, Ticketer, client::{ClientSessionMemoryCache, NoClientSessionStorage}, server::{ AllowAnyAuthenticatedClient, NoClientAuth, NoServerSessionStorage, ServerSessionMemoryCache, }, - ClientConfig, ClientConnection, ConnectionCommon, RootCertStore, ServerConfig, - ServerConnection, SideData, Ticketer, }; use std::{ convert::TryInto, diff --git a/crates/tls/client/src/backend/standard.rs b/crates/tls/client/src/backend/standard.rs index f3b00a7714..3b02ec50f9 100644 --- a/crates/tls/client/src/backend/standard.rs +++ b/crates/tls/client/src/backend/standard.rs @@ -2,12 +2,12 @@ use super::{Backend, BackendError}; use crate::{DecryptMode, EncryptMode, Error}; #[allow(deprecated)] use aes_gcm::{ - aead::{generic_array::GenericArray, Aead, NewAead, Payload}, Aes128Gcm, + aead::{Aead, NewAead, Payload, generic_array::GenericArray}, }; use async_trait::async_trait; -use p256::{ecdh::EphemeralSecret, EncodedPoint, PublicKey as ECDHPublicKey}; -use rand::{rng, rngs::OsRng, Rng}; +use p256::{EncodedPoint, PublicKey as ECDHPublicKey, ecdh::EphemeralSecret}; +use rand::{Rng, rng, rngs::OsRng}; use digest::Digest; use rand06_compat::Rand0_6CompatExt; @@ -336,7 +336,7 @@ impl Backend for RustCryptoBackend { _ => { return Err(BackendError::InvalidState( "Client_random and/or server_random not set".to_string(), - )) + )); } }; diff --git a/crates/tls/client/src/builder.rs b/crates/tls/client/src/builder.rs index 9eefd5e405..2dfc3d3f76 100644 --- a/crates/tls/client/src/builder.rs +++ b/crates/tls/client/src/builder.rs @@ -1,9 +1,9 @@ use crate::{ error::Error, - kx::{SupportedKxGroup, ALL_KX_GROUPS}, + kx::{ALL_KX_GROUPS, SupportedKxGroup}, }; use tls_core::{ - suites::{SupportedCipherSuite, DEFAULT_CIPHER_SUITES}, + suites::{DEFAULT_CIPHER_SUITES, SupportedCipherSuite}, versions, }; diff --git a/crates/tls/client/src/client/builder.rs b/crates/tls/client/src/client/builder.rs index 8ae975ff18..a0d4e0b346 100644 --- a/crates/tls/client/src/client/builder.rs +++ b/crates/tls/client/src/client/builder.rs @@ -1,11 +1,10 @@ use crate::{ - anchors, + NoKeyLog, anchors, builder::{ConfigBuilder, WantsVerifier}, - client::{handy, ClientConfig, ResolvesClientCert}, + client::{ClientConfig, ResolvesClientCert, handy}, error::Error, kx::SupportedKxGroup, verify::{self, CertificateTransparencyPolicy}, - NoKeyLog, }; use std::sync::Arc; use tls_core::{key, suites::SupportedCipherSuite, versions}; diff --git a/crates/tls/client/src/client/client_conn.rs b/crates/tls/client/src/client/client_conn.rs index 227e9b51e7..f6df3d9446 100644 --- a/crates/tls/client/src/client/client_conn.rs +++ b/crates/tls/client/src/client/client_conn.rs @@ -4,11 +4,12 @@ use super::hs; #[cfg(feature = "logging")] use crate::log::trace; use crate::{ + Backend, KeyLog, builder::{ConfigBuilder, WantsCipherSuites}, conn::{CommonState, ConnectionCommon, Protocol, Side, State}, error::Error, kx::SupportedKxGroup, - sign, verify, Backend, KeyLog, + sign, verify, }; use std::{ convert::TryFrom, diff --git a/crates/tls/client/src/client/common.rs b/crates/tls/client/src/client/common.rs index a24e310de5..680878d7fc 100644 --- a/crates/tls/client/src/client/common.rs +++ b/crates/tls/client/src/client/common.rs @@ -1,7 +1,7 @@ use super::ResolvesClientCert; #[cfg(feature = "logging")] use crate::log::{debug, trace}; -use crate::{sign, DistinguishedNames, SignatureScheme}; +use crate::{DistinguishedNames, SignatureScheme, sign}; use std::sync::Arc; pub use tls_core::cert::ServerCertDetails; use tls_core::msgs::{ diff --git a/crates/tls/client/src/client/hs.rs b/crates/tls/client/src/client/hs.rs index 2032d99b08..8cd3aabba5 100644 --- a/crates/tls/client/src/client/hs.rs +++ b/crates/tls/client/src/client/hs.rs @@ -32,7 +32,7 @@ use tls_core::{ #[cfg(feature = "tls12")] use super::tls12; use crate::client::{ - client_conn::ClientConnectionData, common::ClientHelloDetails, tls13, ClientConfig, ServerName, + ClientConfig, ServerName, client_conn::ClientConnectionData, common::ClientHelloDetails, tls13, }; use async_trait::async_trait; use std::sync::Arc; diff --git a/crates/tls/client/src/client/tls12.rs b/crates/tls/client/src/client/tls12.rs index 7adeaff3d2..a87b7bdef1 100644 --- a/crates/tls/client/src/client/tls12.rs +++ b/crates/tls/client/src/client/tls12.rs @@ -4,8 +4,9 @@ use crate::log::{debug, trace}; use crate::{ check::{inappropriate_handshake_message, inappropriate_message}, client::{ + ClientConfig, ServerName, common::{ClientAuthDetails, ServerCertDetails}, - hs, ClientConfig, ServerName, + hs, }, conn::{CommonState, ConnectionRandoms, State}, error::Error, @@ -33,7 +34,7 @@ use tls_core::{ }, message::{Message, MessagePayload}, }, - suites::{tls12, SupportedCipherSuite, Tls12CipherSuite}, + suites::{SupportedCipherSuite, Tls12CipherSuite, tls12}, }; pub(super) use server_hello::CompleteServerHelloHandling; @@ -720,7 +721,7 @@ impl State for ExpectServerDone { ) { Ok(sig_verified) => sig_verified, Err(e) => { - return Err(hs::send_cert_error_alert(cx.common, Error::CoreError(e)).await?) + return Err(hs::send_cert_error_alert(cx.common, Error::CoreError(e)).await?); } } }; diff --git a/crates/tls/client/src/client/tls13.rs b/crates/tls/client/src/client/tls13.rs index c9263d03a5..e0a7236d86 100644 --- a/crates/tls/client/src/client/tls13.rs +++ b/crates/tls/client/src/client/tls13.rs @@ -2,16 +2,18 @@ use super::{client_conn::ClientConnectionData, hs::ClientContext}; #[cfg(feature = "logging")] use crate::log::{debug, trace, warn}; use crate::{ + KeyLog, backend::{DecryptMode, EncryptMode}, check::inappropriate_handshake_message, client::{ + ClientConfig, ServerName, StoresClientSessions, common::{ClientAuthDetails, ClientHelloDetails, ServerCertDetails}, - hs, ClientConfig, ServerName, StoresClientSessions, + hs, }, conn::{CommonState, ConnectionRandoms, State}, error::Error, hash_hs::{HandshakeHash, HandshakeHashBuffer}, - sign, verify, KeyLog, + sign, verify, }; #[allow(deprecated)] use ring::constant_time; diff --git a/crates/tls/client/src/error.rs b/crates/tls/client/src/error.rs index e5c36cd2c3..4c2d6c9b29 100644 --- a/crates/tls/client/src/error.rs +++ b/crates/tls/client/src/error.rs @@ -1,8 +1,8 @@ use crate::{backend::BackendError, rand}; use std::{error::Error as StdError, fmt, time::SystemTimeError}; use tls_core::{ - msgs::enums::{AlertDescription, ContentType, HandshakeType}, Error as CoreError, + msgs::enums::{AlertDescription, ContentType, HandshakeType}, }; /// rustls reports protocol errors using this type. diff --git a/crates/tls/client/src/key_log_file.rs b/crates/tls/client/src/key_log_file.rs index c28f0604f5..e76d5d7017 100644 --- a/crates/tls/client/src/key_log_file.rs +++ b/crates/tls/client/src/key_log_file.rs @@ -1,6 +1,6 @@ +use crate::KeyLog; #[cfg(feature = "logging")] use crate::log::warn; -use crate::KeyLog; use std::{ env, fs::{File, OpenOptions}, diff --git a/crates/tls/client/src/lib.rs b/crates/tls/client/src/lib.rs index 389995b7dc..cada2097ef 100644 --- a/crates/tls/client/src/lib.rs +++ b/crates/tls/client/src/lib.rs @@ -332,7 +332,7 @@ pub use crate::{ error::Error, key_log::{KeyLog, NoKeyLog}, key_log_file::KeyLogFile, - kx::{SupportedKxGroup, ALL_KX_GROUPS}, + kx::{ALL_KX_GROUPS, SupportedKxGroup}, }; pub use backend::{ Backend, BackendError, BackendNotifier, BackendNotify, DecryptMode, EncryptMode, @@ -345,8 +345,8 @@ pub use tls_core::{ enums::{CipherSuite, ProtocolVersion, SignatureScheme}, handshake::DistinguishedNames, }, - suites::{SupportedCipherSuite, ALL_CIPHER_SUITES}, - versions::{SupportedProtocolVersion, ALL_VERSIONS}, + suites::{ALL_CIPHER_SUITES, SupportedCipherSuite}, + versions::{ALL_VERSIONS, SupportedProtocolVersion}, }; /// Items for use in a client. diff --git a/crates/tls/client/src/limited_cache.rs b/crates/tls/client/src/limited_cache.rs index 57e5448cc9..2df289a004 100644 --- a/crates/tls/client/src/limited_cache.rs +++ b/crates/tls/client/src/limited_cache.rs @@ -1,6 +1,6 @@ use std::{ borrow::Borrow, - collections::{hash_map::Entry, HashMap, VecDeque}, + collections::{HashMap, VecDeque, hash_map::Entry}, hash::Hash, }; diff --git a/crates/tls/client/src/record_layer.rs b/crates/tls/client/src/record_layer.rs index 7dafd6088d..774f1419d9 100644 --- a/crates/tls/client/src/record_layer.rs +++ b/crates/tls/client/src/record_layer.rs @@ -1,4 +1,4 @@ -use crate::{error::Error, Backend}; +use crate::{Backend, error::Error}; use tls_core::msgs::message::{OpaqueMessage, PlainMessage}; static SEQ_SOFT_LIMIT: u64 = 0xffff_ffff_ffff_0000u64; diff --git a/crates/tls/client/tests/api.rs b/crates/tls/client/tests/api.rs index 7b1d1cb63c..372ca41e74 100644 --- a/crates/tls/client/tests/api.rs +++ b/crates/tls/client/tests/api.rs @@ -9,19 +9,19 @@ use std::{ mem, ops::{Deref, DerefMut}, sync::{ - atomic::{AtomicUsize, Ordering}, Arc, Mutex, + atomic::{AtomicUsize, Ordering}, }, }; use tls_client::{ - client::ResolvesClientCert, sign, CipherSuite, ClientConfig, ClientConnection, Error, KeyLog, - ProtocolVersion, RustCryptoBackend, SignatureScheme, SupportedCipherSuite, ALL_CIPHER_SUITES, + ALL_CIPHER_SUITES, CipherSuite, ClientConfig, ClientConnection, Error, KeyLog, ProtocolVersion, + RustCryptoBackend, SignatureScheme, SupportedCipherSuite, client::ResolvesClientCert, sign, }; use rustls::{ - server::{ClientHello, ResolvesServerCert}, ServerConfig, ServerConnection, + server::{ClientHello, ResolvesServerCert}, }; mod common; @@ -1915,8 +1915,8 @@ async fn servered_write_for_server_handshake_with_half_rtt_data() { assert!(wrlen > 4000); // its pretty big (contains cert chain) assert_eq!(pipe.writevs.len(), 1); // only one writev assert_eq!(pipe.writevs[0].len(), 8); // at least a server - // hello/ccs/cert/serverkx/0.5rtt - // data + // hello/ccs/cert/serverkx/0.5rtt + // data } client.process_new_packets().await.unwrap(); @@ -1950,7 +1950,7 @@ async fn check_half_rtt_does_not_work(server_config: ServerConfig) { assert!(wrlen > 4000); // its pretty big (contains cert chain) assert_eq!(pipe.writevs.len(), 1); // only one writev assert!(pipe.writevs[0].len() >= 6); // at least a server - // hello/ccs/cert/serverkx data + // hello/ccs/cert/serverkx data } // client second flight @@ -2361,9 +2361,11 @@ async fn test_client_config_keyshare_mismatch() { let server_config = make_server_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::X25519]); let (mut client, mut server) = make_pair_for_configs(client_config, server_config).await; - assert!(do_handshake_until_error(&mut client, &mut server) - .await - .is_err()); + assert!( + do_handshake_until_error(&mut client, &mut server) + .await + .is_err() + ); } #[ignore = "needs to be fixed"] @@ -2421,7 +2423,7 @@ async fn test_client_sends_helloretryrequest() { assert!(wrlen > 200); assert_eq!(pipe.writevs.len(), 1); assert!(pipe.writevs[0].len() == 5); // server hello / encrypted exts / - // cert / cert-verify / finished + // cert / cert-verify / finished } do_handshake_until_error(&mut client, &mut server) @@ -2534,9 +2536,11 @@ async fn test_server_mtu_reduction() { server.write_tls(&mut pipe).unwrap(); assert_eq!(pipe.writevs.len(), 1); - assert!(pipe.writevs[0] - .iter() - .all(|x| *x <= 64 + encryption_overhead)); + assert!( + pipe.writevs[0] + .iter() + .all(|x| *x <= 64 + encryption_overhead) + ); } client.process_new_packets().await.unwrap(); @@ -2546,9 +2550,11 @@ async fn test_server_mtu_reduction() { let mut pipe = ClientSession::new(&mut client); server.write_tls(&mut pipe).unwrap(); assert_eq!(pipe.writevs.len(), 1); - assert!(pipe.writevs[0] - .iter() - .all(|x| *x <= 64 + encryption_overhead)); + assert!( + pipe.writevs[0] + .iter() + .all(|x| *x <= 64 + encryption_overhead) + ); } client.process_new_packets().await.unwrap(); diff --git a/crates/tls/client/tests/common/mod.rs b/crates/tls/client/tests/common/mod.rs index 02cb74fa4c..53a8528be4 100644 --- a/crates/tls/client/tests/common/mod.rs +++ b/crates/tls/client/tests/common/mod.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] use futures::{AsyncRead, AsyncWrite}; -use rustls::{server::AllowAnyAuthenticatedClient, ServerConfig, ServerConnection}; +use rustls::{ServerConfig, ServerConnection, server::AllowAnyAuthenticatedClient}; use rustls_pki_types::CertificateDer; use std::{ convert::{TryFrom, TryInto}, @@ -9,12 +9,12 @@ use std::{ sync::Arc, }; use tls_client::{ + Certificate, ClientConfig, ClientConnection, Error, PrivateKey, RootCertStore, + RustCryptoBackend, internal::msgs::{ codec::Reader, message::{Message, OpaqueMessage, PlainMessage}, }, - Certificate, ClientConfig, ClientConnection, Error, PrivateKey, RootCertStore, - RustCryptoBackend, }; use webpki::anchor_from_trusted_cert; diff --git a/crates/tls/core/src/handshake.rs b/crates/tls/core/src/handshake.rs index 8e71318f1b..a0745e5a2c 100644 --- a/crates/tls/core/src/handshake.rs +++ b/crates/tls/core/src/handshake.rs @@ -1,8 +1,8 @@ use web_time::SystemTime; use crate::{ - cert::ServerCertDetails, dns::ServerName, ke::ServerKxDetails, msgs::handshake::Random, - verify::ServerCertVerifier, Error, + Error, cert::ServerCertDetails, dns::ServerName, ke::ServerKxDetails, msgs::handshake::Random, + verify::ServerCertVerifier, }; #[derive(Debug, Clone)] diff --git a/crates/tls/core/src/msgs/deframer.rs b/crates/tls/core/src/msgs/deframer.rs index b3de9444d1..a28d3863c0 100644 --- a/crates/tls/core/src/msgs/deframer.rs +++ b/crates/tls/core/src/msgs/deframer.rs @@ -2,7 +2,7 @@ use crate::msgs::{ codec, message::{MessageError, OpaqueMessage}, }; -use futures::{io::AsyncRead, AsyncReadExt}; +use futures::{AsyncReadExt, io::AsyncRead}; use std::{collections::VecDeque, io}; /// This deframer works to reconstruct TLS messages diff --git a/crates/tls/core/src/msgs/fragmenter.rs b/crates/tls/core/src/msgs/fragmenter.rs index 1c2ea6e5ca..e8cc0e6145 100644 --- a/crates/tls/core/src/msgs/fragmenter.rs +++ b/crates/tls/core/src/msgs/fragmenter.rs @@ -1,10 +1,10 @@ use crate::{ + Error, msgs::{ base::Payload, enums::{ContentType, ProtocolVersion}, message::{BorrowedPlainMessage, PlainMessage}, }, - Error, }; use std::collections::VecDeque; diff --git a/crates/tls/core/src/msgs/handshake.rs b/crates/tls/core/src/msgs/handshake.rs index bd0004e604..d27af9024d 100644 --- a/crates/tls/core/src/msgs/handshake.rs +++ b/crates/tls/core/src/msgs/handshake.rs @@ -1,9 +1,9 @@ use rustls_pki_types as pki_types; use crate::{ - key, + Error, key, msgs::{ - base::{Payload, PayloadU16, PayloadU24, PayloadU8}, + base::{Payload, PayloadU8, PayloadU16, PayloadU24}, codec, codec::{Codec, Reader}, enums::{ @@ -13,7 +13,7 @@ use crate::{ SignatureScheme, }, }, - rand, Error, + rand, }; #[cfg(feature = "logging")] @@ -689,11 +689,7 @@ impl Codec for ClientExtension { _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), }; - if sub.any_left() { - None - } else { - Some(ext) - } + if sub.any_left() { None } else { Some(ext) } } } @@ -833,11 +829,7 @@ impl Codec for ServerExtension { _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), }; - if sub.any_left() { - None - } else { - Some(ext) - } + if sub.any_left() { None } else { Some(ext) } } } @@ -1094,11 +1086,7 @@ impl Codec for HelloRetryExtension { _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), }; - if sub.any_left() { - None - } else { - Some(ext) - } + if sub.any_left() { None } else { Some(ext) } } } @@ -1230,11 +1218,7 @@ impl Codec for ServerHelloPayload { extensions, }; - if r.any_left() { - None - } else { - Some(ret) - } + if r.any_left() { None } else { Some(ret) } } } @@ -1376,11 +1360,7 @@ impl Codec for CertificateExtension { _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), }; - if sub.any_left() { - None - } else { - Some(ext) - } + if sub.any_left() { None } else { Some(ext) } } } @@ -1849,11 +1829,7 @@ impl Codec for CertReqExtension { _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), }; - if sub.any_left() { - None - } else { - Some(ext) - } + if sub.any_left() { None } else { Some(ext) } } } @@ -1977,11 +1953,7 @@ impl Codec for NewSessionTicketExtension { _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), }; - if sub.any_left() { - None - } else { - Some(ext) - } + if sub.any_left() { None } else { Some(ext) } } } diff --git a/crates/tls/core/src/msgs/handshake_test.rs b/crates/tls/core/src/msgs/handshake_test.rs index 81ca310f5d..23b1648f7c 100644 --- a/crates/tls/core/src/msgs/handshake_test.rs +++ b/crates/tls/core/src/msgs/handshake_test.rs @@ -1,8 +1,8 @@ use rustls_pki_types as pki_types; use super::{ - base::{Payload, PayloadU16, PayloadU24, PayloadU8}, - codec::{put_u16, Codec, Reader}, + base::{Payload, PayloadU8, PayloadU16, PayloadU24}, + codec::{Codec, Reader, put_u16}, enums::*, handshake::*, }; @@ -999,11 +999,13 @@ fn can_detect_truncation_of_all_tls12_handshake_payloads() { _ => {} }; - assert!(HandshakeMessagePayload::read_version( - &mut Reader::init(&enc), - ProtocolVersion::TLSv1_2 - ) - .is_none()); + assert!( + HandshakeMessagePayload::read_version( + &mut Reader::init(&enc), + ProtocolVersion::TLSv1_2 + ) + .is_none() + ); assert!(HandshakeMessagePayload::read_bytes(&enc).is_none()); } } @@ -1146,11 +1148,13 @@ fn can_detect_truncation_of_all_tls13_handshake_payloads() { _ => {} }; - assert!(HandshakeMessagePayload::read_version( - &mut Reader::init(&enc), - ProtocolVersion::TLSv1_3 - ) - .is_none()); + assert!( + HandshakeMessagePayload::read_version( + &mut Reader::init(&enc), + ProtocolVersion::TLSv1_3 + ) + .is_none() + ); } } } diff --git a/crates/tls/core/src/rand.rs b/crates/tls/core/src/rand.rs index effef01139..e6df6a7d2c 100644 --- a/crates/tls/core/src/rand.rs +++ b/crates/tls/core/src/rand.rs @@ -1,5 +1,5 @@ -use crate::{msgs::codec, Error}; -use rand::{rng, Rng}; +use crate::{Error, msgs::codec}; +use rand::{Rng, rng}; /// Fill the whole slice with random material. pub fn fill_random(bytes: &mut [u8]) -> Result<(), Error> { diff --git a/crates/tls/core/src/suites/mod.rs b/crates/tls/core/src/suites/mod.rs index 518bcc0cb4..2c5d8a4f42 100644 --- a/crates/tls/core/src/suites/mod.rs +++ b/crates/tls/core/src/suites/mod.rs @@ -23,8 +23,8 @@ pub use tls12::{ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, }; pub use tls13::{ - Tls13CipherSuite, TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, - TLS13_CHACHA20_POLY1305_SHA256, + TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256, + Tls13CipherSuite, }; /// AEAD Algorithm scheme used by a cipher suite. @@ -277,16 +277,20 @@ mod test { #[test] fn test_pref_fails() { - assert!(choose_ciphersuite_preferring_client( - &[CipherSuite::TLS_NULL_WITH_NULL_NULL], - ALL_CIPHER_SUITES - ) - .is_none()); - assert!(choose_ciphersuite_preferring_server( - &[CipherSuite::TLS_NULL_WITH_NULL_NULL], - ALL_CIPHER_SUITES - ) - .is_none()); + assert!( + choose_ciphersuite_preferring_client( + &[CipherSuite::TLS_NULL_WITH_NULL_NULL], + ALL_CIPHER_SUITES + ) + .is_none() + ); + assert!( + choose_ciphersuite_preferring_server( + &[CipherSuite::TLS_NULL_WITH_NULL_NULL], + ALL_CIPHER_SUITES + ) + .is_none() + ); } #[test] diff --git a/crates/tlsn/src/prover/prove.rs b/crates/tlsn/src/prover/prove.rs index 59b313a589..3df9829e47 100644 --- a/crates/tlsn/src/prover/prove.rs +++ b/crates/tlsn/src/prover/prove.rs @@ -84,9 +84,10 @@ pub(crate) async fn prove + Send + Sync>( prove_hash( vm, &transcript_refs, - commit_config - .iter_hash() - .map(|((dir, idx), alg)| (*dir, idx.clone(), *alg)), + commit_config.iter_hash().map(|((dir, idx), alg)| { + let blinder = config.hash_blinder(*dir, idx, *alg).cloned(); + (*dir, idx.clone(), *alg, blinder) + }), ) .map_err(|e| { Error::internal() diff --git a/crates/tlsn/src/transcript_internal/commit/hash.rs b/crates/tlsn/src/transcript_internal/commit/hash.rs index 59b1b5a681..8ac14bb75c 100644 --- a/crates/tlsn/src/transcript_internal/commit/hash.rs +++ b/crates/tlsn/src/transcript_internal/commit/hash.rs @@ -64,14 +64,25 @@ impl HashCommitFuture { pub(crate) fn prove_hash( vm: &mut dyn Vm, refs: &TranscriptRefs, - idxs: impl IntoIterator, HashAlgId)>, + idxs: impl IntoIterator, HashAlgId, Option)>, ) -> Result<(HashCommitFuture, Vec), HashCommitError> { let mut futs = Vec::new(); let mut secrets = Vec::new(); - for (direction, idx, alg, hash_ref, blinder_ref) in + let (idxs, supplied): (Vec<_>, Vec<_>) = idxs + .into_iter() + .map(|(direction, idx, alg, blinder)| ((direction, idx, alg), blinder)) + .unzip(); + for ((direction, idx, alg, hash_ref, blinder_ref), supplied) in hash_commit_inner(vm, Role::Prover, refs, idxs)? + .into_iter() + .zip(supplied) { - let blinder: Blinder = rand::random(); + // A prover may pre-select its own blinder so it can derive the + // commitment value before this phase and start dependent work early. + // The blinder hides only the prover's own pre-image, so its origin + // adds no verifier-side assumption; the verifier still learns the + // commitment solely from this VM computation. + let blinder: Blinder = supplied.unwrap_or_else(rand::random); vm.assign(blinder_ref, blinder.as_bytes().to_vec())?; vm.commit(blinder_ref)?;