use crate::{
credentials::{Credentials, Id},
event,
packet::{secret_control as control, Packet},
path::secret::{open, seal, stateless_reset},
stream::TransportFeatures,
};
use s2n_quic_core::dc;
use std::{net::SocketAddr, sync::Arc};
mod cleaner;
mod entry;
mod handshake;
mod size_of;
mod state;
mod status;
mod store;
#[cfg(test)]
mod event_tests;
use entry::Entry;
use store::Store;
pub use entry::{ApplicationPair, Bidirectional, ControlPair};
pub(crate) use size_of::SizeOf;
pub(crate) use status::Dedup;
#[derive(Clone)]
pub struct Map {
store: Arc<dyn Store>,
}
impl Map {
pub fn new<S: event::Subscriber>(
signer: stateless_reset::Signer,
capacity: usize,
subscriber: S,
) -> Self {
let store = state::State::new(signer, capacity, subscriber);
Self { store }
}
pub fn secrets_len(&self) -> usize {
self.store.secrets_len()
}
pub fn peers_len(&self) -> usize {
self.store.peers_len()
}
pub fn secrets_capacity(&self) -> usize {
self.store.secrets_capacity()
}
pub fn drop_state(&self) {
self.store.drop_state();
}
pub fn contains(&self, peer: SocketAddr) -> bool {
self.store.contains(peer)
}
pub fn seal_once(
&self,
peer: SocketAddr,
) -> Option<(seal::Once, Credentials, dc::ApplicationParams)> {
let entry = self.store.get_by_addr(&peer)?;
let (sealer, credentials) = entry.uni_sealer();
Some((sealer, credentials, entry.parameters()))
}
pub fn seal_once_id(&self, id: Id) -> Option<(seal::Once, Credentials, dc::ApplicationParams)> {
let entry = self.store.get_by_id(&id)?;
let (sealer, credentials) = entry.uni_sealer();
Some((sealer, credentials, entry.parameters()))
}
pub fn open_once(
&self,
credentials: &Credentials,
control_out: &mut Vec<u8>,
) -> Option<open::Once> {
let entry = self.store.pre_authentication(credentials, control_out)?;
let opener = entry.uni_opener(self.clone(), credentials);
Some(opener)
}
pub fn pair_for_peer(
&self,
peer: SocketAddr,
features: &TransportFeatures,
) -> Option<(entry::Bidirectional, dc::ApplicationParams)> {
let entry = self.store.get_by_addr(&peer)?;
let keys = entry.bidi_local(features);
Some((keys, entry.parameters()))
}
pub fn pair_for_credentials(
&self,
credentials: &Credentials,
features: &TransportFeatures,
control_out: &mut Vec<u8>,
) -> Option<(entry::Bidirectional, dc::ApplicationParams)> {
let entry = self.store.pre_authentication(credentials, control_out)?;
let params = entry.parameters();
let keys = entry.bidi_remote(self.clone(), credentials, features);
Some((keys, params))
}
pub fn handle_unexpected_packet(&self, packet: &Packet, peer: &SocketAddr) {
self.store.handle_unexpected_packet(packet, peer);
}
pub fn handle_control_packet(&self, packet: &control::Packet, peer: &SocketAddr) {
self.store.handle_control_packet(packet, peer)
}
#[doc(hidden)]
#[cfg(any(test, feature = "testing"))]
pub fn for_test_with_peers(
peers: Vec<(
crate::path::secret::schedule::Ciphersuite,
dc::Version,
SocketAddr,
)>,
) -> (Self, Vec<Id>) {
use crate::path::secret::{receiver, schedule, sender};
let provider = Self::new(
stateless_reset::Signer::random(),
peers.len() * 3,
event::testing::Subscriber::no_snapshot(),
);
let mut secret = [0; 32];
aws_lc_rs::rand::fill(&mut secret).unwrap();
let mut stateless_reset = [0; control::TAG_LEN];
aws_lc_rs::rand::fill(&mut stateless_reset).unwrap();
let receiver_shared = receiver::Shared::new();
let mut ids = Vec::with_capacity(peers.len());
for (idx, (ciphersuite, version, peer)) in peers.into_iter().enumerate() {
secret[..8].copy_from_slice(&(idx as u64).to_be_bytes()[..]);
stateless_reset[..8].copy_from_slice(&(idx as u64).to_be_bytes()[..]);
let secret = schedule::Secret::new(
ciphersuite,
version,
s2n_quic_core::endpoint::Type::Client,
&secret,
);
ids.push(*secret.id());
let sender = sender::State::new(stateless_reset);
let entry = Entry::new(
peer,
secret,
sender,
receiver_shared.clone().new_receiver(),
dc::testing::TEST_APPLICATION_PARAMS,
dc::testing::TEST_REHANDSHAKE_PERIOD,
);
let entry = Arc::new(entry);
provider.store.test_insert(entry);
}
(provider, ids)
}
#[doc(hidden)]
#[cfg(any(test, feature = "testing"))]
pub fn test_insert(&self, peer: SocketAddr) {
let receiver = self.store.receiver().clone().new_receiver();
let entry = Entry::fake(peer, Some(receiver));
self.store.test_insert(entry);
}
#[cfg(test)]
fn test_insert_pair(
&self,
local_addr: SocketAddr,
peer: &Self,
peer_addr: SocketAddr,
) -> crate::credentials::Id {
use crate::path::secret::{schedule, sender};
use s2n_quic_core::endpoint::Type;
let ciphersuite = schedule::Ciphersuite::AES_GCM_128_SHA256;
let mut secret = [0; 32];
aws_lc_rs::rand::fill(&mut secret).unwrap();
let insert = |map: &Self, peer: &Self, peer_addr, endpoint| {
let secret =
schedule::Secret::new(ciphersuite, dc::SUPPORTED_VERSIONS[0], endpoint, &secret);
let id = *secret.id();
let srt = peer.store.signer().sign(&id);
let sender = sender::State::new(srt);
let entry = Entry::new(
peer_addr,
secret,
sender,
map.store.receiver().clone().new_receiver(),
dc::testing::TEST_APPLICATION_PARAMS,
dc::testing::TEST_REHANDSHAKE_PERIOD,
);
let entry = Arc::new(entry);
map.store.test_insert(entry);
id
};
let client_id = insert(self, peer, peer_addr, Type::Client);
let server_id = insert(peer, self, local_addr, Type::Server);
assert_eq!(client_id, server_id);
client_id
}
}