mirror of
https://github.com/zerotier/zssp.git
synced 2026-05-22 16:28:40 -07:00
Merge pull request #29 from zerotier/dev
Updated Naming Convention and Ran Cargo Clippy
This commit is contained in:
@@ -166,7 +166,7 @@ fn alice_main(
|
||||
alice_app,
|
||||
|b: &mut [u8]| alice_out.send(b.to_vec()).is_ok(),
|
||||
TEST_MTU,
|
||||
bob_pubkey.clone(),
|
||||
bob_pubkey,
|
||||
0,
|
||||
&[],
|
||||
);
|
||||
|
||||
@@ -136,7 +136,7 @@ fn alice_main(
|
||||
alice_app,
|
||||
|b: &mut [u8]| alice_out.send(alloc(b)).is_ok(),
|
||||
TEST_MTU,
|
||||
bob_pubkey.clone(),
|
||||
bob_pubkey,
|
||||
(),
|
||||
&[],
|
||||
);
|
||||
|
||||
@@ -182,7 +182,7 @@ pub trait CryptoLayer: Sized {
|
||||
///
|
||||
/// Templating ZSSP on this trait lets the code here be almost entirely transport, OS,
|
||||
/// and use case independent.
|
||||
pub trait ApplicationLayer<Crypto: CryptoLayer>: Sized {
|
||||
pub trait ApplicationLayer<C: CryptoLayer>: Sized {
|
||||
/// Should return the current time in milliseconds. Does not have to be monotonic, nor synced
|
||||
/// with remote peers (although both of these properties would help reliability slightly).
|
||||
/// Used to determine if any current handshakes should be resent or timed-out, or if a session
|
||||
@@ -228,7 +228,7 @@ pub trait ApplicationLayer<Crypto: CryptoLayer>: Sized {
|
||||
///
|
||||
/// Corresponds to the "Initiator Disallows Downgrade, π_2" security flag of Transition
|
||||
/// Algorithm 3 within the ZSSP whitepaper.
|
||||
fn initiator_disallows_downgrade(&mut self, session: &Arc<Session<Crypto>>) -> bool;
|
||||
fn initiator_disallows_downgrade(&mut self, session: &Arc<Session<C>>) -> bool;
|
||||
/// Function to accept sessions after final negotiation.
|
||||
///
|
||||
/// The implementor must verify that three arguments, `remote_static_key`, `identity` and
|
||||
@@ -244,10 +244,10 @@ pub trait ApplicationLayer<Crypto: CryptoLayer>: Sized {
|
||||
/// Corresponds to the **Accept** call of Transition Algorithm 4 within the ZSSP whitepaper.
|
||||
fn check_accept_session(
|
||||
&mut self,
|
||||
remote_static_key: &Crypto::PublicKey,
|
||||
remote_static_key: &C::PublicKey,
|
||||
identity: &[u8],
|
||||
fingerprint_data: Option<&Crypto::FingerprintData>,
|
||||
) -> AcceptAction<Crypto>;
|
||||
fingerprint_data: Option<&C::FingerprintData>,
|
||||
) -> AcceptAction<C>;
|
||||
|
||||
/// Lookup a specific ratchet state based on its ratchet fingerprint.
|
||||
/// This function will be called whenever Alice attempts to connect to us with a non-empty
|
||||
@@ -272,7 +272,7 @@ pub trait ApplicationLayer<Crypto: CryptoLayer>: Sized {
|
||||
fn restore_by_fingerprint(
|
||||
&mut self,
|
||||
ratchet_fingerprint: &[u8; RATCHET_SIZE],
|
||||
) -> Result<Option<(RatchetState, Crypto::FingerprintData)>, std::io::Error>;
|
||||
) -> Result<Option<(RatchetState, C::FingerprintData)>, std::io::Error>;
|
||||
/// Lookup the specific ratchet states based on the identity of the peer being communicated with.
|
||||
/// This function will be called whenever Alice attempts to open a session, or Bob attempts
|
||||
/// to verify Alice's identity.
|
||||
@@ -291,9 +291,9 @@ pub trait ApplicationLayer<Crypto: CryptoLayer>: Sized {
|
||||
/// Corresponds to the **Restore** call of Transition Algorithm 1 and 4 within the ZSSP whitepaper.
|
||||
fn restore_by_identity(
|
||||
&mut self,
|
||||
remote_static_key: &Crypto::PublicKey,
|
||||
session_data: &Crypto::SessionData,
|
||||
fingerprint_data: Option<&Crypto::FingerprintData>,
|
||||
remote_static_key: &C::PublicKey,
|
||||
session_data: &C::SessionData,
|
||||
fingerprint_data: Option<&C::FingerprintData>,
|
||||
) -> Result<Option<RatchetStates>, std::io::Error>;
|
||||
/// Atomically commit the update specified by `update_data` to storage, or return an error if
|
||||
/// the update could not be made.
|
||||
@@ -313,8 +313,8 @@ pub trait ApplicationLayer<Crypto: CryptoLayer>: Sized {
|
||||
/// Otherwise, when we restart, we will not be allowed to reconnect.
|
||||
fn save_ratchet_state(
|
||||
&mut self,
|
||||
remote_static_key: &Crypto::PublicKey,
|
||||
session_data: &Crypto::SessionData,
|
||||
remote_static_key: &C::PublicKey,
|
||||
session_data: &C::SessionData,
|
||||
update_data: RatchetUpdate<'_>,
|
||||
) -> Result<(), std::io::Error>;
|
||||
|
||||
@@ -323,7 +323,7 @@ pub trait ApplicationLayer<Crypto: CryptoLayer>: Sized {
|
||||
/// nothing else. Do not base protocol-level decisions upon the events passed to this function.
|
||||
#[cfg(feature = "logging")]
|
||||
#[allow(unused)]
|
||||
fn event_log(&mut self, event: crate::LogEvent<'_, Crypto>) {}
|
||||
fn event_log(&mut self, event: crate::LogEvent<'_, C>) {}
|
||||
}
|
||||
|
||||
/// Possible responses that can be made to Hello packets from an anonymous peer.
|
||||
@@ -350,10 +350,10 @@ pub enum IncomingSessionAction {
|
||||
/// used by Bob, the responder, at the very last stage of the key exchange.
|
||||
///
|
||||
/// Corresponds to the *Accept* callback of Transition Algorithm 4.
|
||||
pub struct AcceptAction<Crypto: CryptoLayer> {
|
||||
pub struct AcceptAction<C: CryptoLayer> {
|
||||
/// The data object to be attached to the session if we successfully connect.
|
||||
/// If this field is None then we will not connect to this remote peer.
|
||||
pub session_data: Option<Crypto::SessionData>,
|
||||
pub session_data: Option<C::SessionData>,
|
||||
/// Whether or not we will accept a connection with the remote peer when they do not have a
|
||||
/// ratchet key that we think they should have.
|
||||
///
|
||||
@@ -385,8 +385,8 @@ pub trait Sender {
|
||||
/// A trait to genericize the process of borrowing the resources necessary to repeatedly
|
||||
/// send packet fragments on some socket or network interface.
|
||||
///
|
||||
/// Is implemented by `FnMut(&Arc<Session<Crypto>>) -> Option<(Sender, usize)>` closures.
|
||||
pub trait SendTo<Crypto: CryptoLayer> {
|
||||
/// Is implemented by `FnMut(&Arc<Session<C>>) -> Option<(Sender, usize)>` closures.
|
||||
pub trait SendTo<C: CryptoLayer> {
|
||||
/// The `Sender` implementation that this `SendTo` implementation will return.
|
||||
///
|
||||
/// It is allowed to have a lifetime that is borrowed from the `SendTo` instance
|
||||
@@ -394,7 +394,7 @@ pub trait SendTo<Crypto: CryptoLayer> {
|
||||
/// in situations where that is more efficient.
|
||||
type Sender<'a>: Sender
|
||||
where
|
||||
Crypto: 'a,
|
||||
C: 'a,
|
||||
Self: 'a;
|
||||
/// Attempt to process and borrow the resources necessary to repeatedly send fragments of a
|
||||
/// packet to the given session.
|
||||
@@ -405,7 +405,7 @@ pub trait SendTo<Crypto: CryptoLayer> {
|
||||
/// only called once.
|
||||
///
|
||||
/// If `None` is returned then sending to this session is cancelled.
|
||||
fn init_send<'a>(&'a mut self, session: &'a Arc<Session<Crypto>>) -> Option<(Self::Sender<'a>, usize)>;
|
||||
fn init_send<'a>(&'a mut self, session: &'a Arc<Session<C>>) -> Option<(Self::Sender<'a>, usize)>;
|
||||
}
|
||||
|
||||
impl<F: FnMut(&mut [u8]) -> bool> Sender for F {
|
||||
@@ -414,9 +414,9 @@ impl<F: FnMut(&mut [u8]) -> bool> Sender for F {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Crypto: CryptoLayer, F: FnMut(&Arc<Session<Crypto>>) -> Option<(S, usize)>, S: Sender> SendTo<Crypto> for F {
|
||||
type Sender<'a> = S where Crypto: 'a, F: 'a;
|
||||
fn init_send<'a>(&'a mut self, session: &'a Arc<Session<Crypto>>) -> Option<(S, usize)> {
|
||||
impl<C: CryptoLayer, F: FnMut(&Arc<Session<C>>) -> Option<(S, usize)>, S: Sender> SendTo<C> for F {
|
||||
type Sender<'a> = S where C: 'a, F: 'a;
|
||||
fn init_send<'a>(&'a mut self, session: &'a Arc<Session<C>>) -> Option<(S, usize)> {
|
||||
self(session)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ pub fn respond_to_challenge_in_place(
|
||||
challenge: &[u8; CHALLENGE_SIZE],
|
||||
pre_response: &mut [u8; CHALLENGE_SIZE],
|
||||
) {
|
||||
if &challenge[POW_START..] == &pre_response[POW_START..] {
|
||||
if challenge[POW_START..] == pre_response[POW_START..] {
|
||||
pre_response.copy_from_slice(challenge);
|
||||
let mut pow = rng.next_u64();
|
||||
let mut work_buf = [0u8; SHA512_HASH_SIZE];
|
||||
@@ -79,7 +79,6 @@ impl ChallengeContext {
|
||||
hasher.write(&c.to_be_bytes());
|
||||
addr.hash(&mut hasher);
|
||||
hasher.write(&self.salt);
|
||||
drop(hasher);
|
||||
|
||||
let mut mac = [0u8; SHA512_HASH_SIZE];
|
||||
hash.finish_and_reset(&mut mac);
|
||||
|
||||
@@ -16,18 +16,18 @@ struct PacketMetadata {
|
||||
creation_time: i64,
|
||||
}
|
||||
|
||||
pub(crate) struct UnassociatedFragCache<Crypto: CryptoLayer> {
|
||||
pub(crate) struct UnassociatedFragCache<C: CryptoLayer> {
|
||||
dos_salt: RandomState,
|
||||
frags_first_unused: usize,
|
||||
frags_unused_size: usize,
|
||||
map: [PacketMetadata; MAX_UNASSOCIATED_PACKETS],
|
||||
frags: [MaybeUninit<Crypto::IncomingPacketBuffer>; MAX_UNASSOCIATED_FRAGMENTS],
|
||||
frags: [MaybeUninit<C::IncomingPacketBuffer>; MAX_UNASSOCIATED_FRAGMENTS],
|
||||
map_idx: [u32; MAX_UNASSOCIATED_FRAGMENTS],
|
||||
}
|
||||
/// A combination of a hash table cache and a ring buffer for unassociated fragments.
|
||||
/// Designed specifically to be extremely DDOS resistant.
|
||||
/// This datastructure takes raw unauthenticated fragments straight from the network.
|
||||
impl<Crypto: CryptoLayer> UnassociatedFragCache<Crypto> {
|
||||
impl<C: CryptoLayer> UnassociatedFragCache<C> {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
dos_salt: RandomState::new(),
|
||||
@@ -53,11 +53,11 @@ impl<Crypto: CryptoLayer> UnassociatedFragCache<Crypto> {
|
||||
nonce: &[u8; AES_GCM_NONCE_SIZE],
|
||||
remote_address: impl Hash,
|
||||
fragment_size: usize,
|
||||
fragment: Crypto::IncomingPacketBuffer,
|
||||
fragment: C::IncomingPacketBuffer,
|
||||
fragment_no: usize,
|
||||
fragment_count: usize,
|
||||
current_time: i64,
|
||||
ret_assembled: &mut Assembled<Crypto::IncomingPacketBuffer>,
|
||||
ret_assembled: &mut Assembled<C::IncomingPacketBuffer>,
|
||||
) -> Option<i64> {
|
||||
debug_assert!(MAX_FRAGMENTS < MAX_UNASSOCIATED_FRAGMENTS);
|
||||
if fragment_no >= fragment_count
|
||||
@@ -95,7 +95,7 @@ impl<Crypto: CryptoLayer> UnassociatedFragCache<Crypto> {
|
||||
} else if self.map[idx0].key == 0 || self.map[idx1].key == 0 {
|
||||
if fragment_count > self.frags_unused_size {
|
||||
// There are not enough free fragment slots so attempt to expire a bunch of entries.
|
||||
let _ = self.check_for_expiry_inner(Crypto::SETTINGS.resend_time as i64, current_time);
|
||||
let _ = self.check_for_expiry_inner(C::SETTINGS.resend_time as i64, current_time);
|
||||
}
|
||||
if self.map[idx0].key == 0 {
|
||||
idx0
|
||||
@@ -104,7 +104,7 @@ impl<Crypto: CryptoLayer> UnassociatedFragCache<Crypto> {
|
||||
}
|
||||
} else {
|
||||
// No room for a new entry so attempt to expire a bunch of entries.
|
||||
let _ = self.check_for_expiry_inner(Crypto::SETTINGS.resend_time as i64, current_time);
|
||||
let _ = self.check_for_expiry_inner(C::SETTINGS.resend_time as i64, current_time);
|
||||
if self.map[idx0].key == 0 {
|
||||
idx0
|
||||
} else if self.map[idx1].key == 0 {
|
||||
@@ -118,7 +118,7 @@ impl<Crypto: CryptoLayer> UnassociatedFragCache<Crypto> {
|
||||
if self.map[idx].key == 0 {
|
||||
// This is a new entry so initialize it.
|
||||
if fragment_count <= self.frags_unused_size {
|
||||
new_expiry = Some(current_time + Crypto::SETTINGS.fragment_assembly_timeout as i64);
|
||||
new_expiry = Some(current_time + C::SETTINGS.fragment_assembly_timeout as i64);
|
||||
let entry = &mut self.map[idx];
|
||||
entry.key = key;
|
||||
entry.frags_idx = self.frags_first_unused as u32;
|
||||
@@ -166,7 +166,7 @@ impl<Crypto: CryptoLayer> UnassociatedFragCache<Crypto> {
|
||||
}
|
||||
/// Returns the timestamp at which this function should be called again.
|
||||
pub(crate) fn check_for_expiry(&mut self, current_time: i64) -> i64 {
|
||||
self.check_for_expiry_inner(Crypto::SETTINGS.fragment_assembly_timeout as i64, current_time)
|
||||
self.check_for_expiry_inner(C::SETTINGS.fragment_assembly_timeout as i64, current_time)
|
||||
}
|
||||
fn check_for_expiry_inner(&mut self, timeout: i64, current_time: i64) -> i64 {
|
||||
while self.frags_unused_size < self.frags.len() {
|
||||
@@ -219,7 +219,7 @@ impl<Crypto: CryptoLayer> UnassociatedFragCache<Crypto> {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<Crypto: CryptoLayer> Drop for UnassociatedFragCache<Crypto> {
|
||||
impl<C: CryptoLayer> Drop for UnassociatedFragCache<C> {
|
||||
fn drop(&mut self) {
|
||||
for i in 0..self.map.len() {
|
||||
if self.map[i].key != 0 {
|
||||
@@ -243,8 +243,8 @@ fn test_cache() {
|
||||
r.wrapping_mul(0x2545F4914F6CDD1Du64)
|
||||
}
|
||||
use crate::crypto_impl::*;
|
||||
struct Crypto {}
|
||||
impl CryptoLayer for Crypto {
|
||||
struct C {}
|
||||
impl CryptoLayer for C {
|
||||
type Rng = rand_core::OsRng;
|
||||
type PrpEnc = OpenSSLAes256Enc;
|
||||
type PrpDec = OpenSSLAes256Dec;
|
||||
@@ -261,7 +261,7 @@ fn test_cache() {
|
||||
type IncomingPacketBuffer = Vec<u8>;
|
||||
}
|
||||
|
||||
let mut cache = UnassociatedFragCache::<Crypto>::new();
|
||||
let mut cache = UnassociatedFragCache::<C>::new();
|
||||
let mut assembled = Assembled::new();
|
||||
|
||||
let mut time = 0;
|
||||
@@ -317,39 +317,37 @@ fn test_cache() {
|
||||
assert!(assembled.is_empty(), "Cache returned an incomplete packet");
|
||||
}
|
||||
}
|
||||
if r > 200 {
|
||||
if in_progress.len() > 0 {
|
||||
let to_remain = (xorshift64_random() as usize % in_progress_fragments) + 16;
|
||||
while in_progress_fragments > to_remain {
|
||||
let (id, fragment_count, mut packet) =
|
||||
in_progress.swap_remove(xorshift64_random() as usize % in_progress.len());
|
||||
for _ in 0..((xorshift64_random() as usize % packet.len()) + 1) {
|
||||
let (no, fragment) = packet.swap_remove(xorshift64_random() as usize % packet.len());
|
||||
if r > 200 && !in_progress.is_empty() {
|
||||
let to_remain = (xorshift64_random() as usize % in_progress_fragments) + 16;
|
||||
while in_progress_fragments > to_remain {
|
||||
let (id, fragment_count, mut packet) =
|
||||
in_progress.swap_remove(xorshift64_random() as usize % in_progress.len());
|
||||
for _ in 0..((xorshift64_random() as usize % packet.len()) + 1) {
|
||||
let (no, fragment) = packet.swap_remove(xorshift64_random() as usize % packet.len());
|
||||
|
||||
assembled.clear();
|
||||
let mut nonce = [0; 12];
|
||||
nonce[..4].copy_from_slice(&id.to_be_bytes());
|
||||
cache.assemble(
|
||||
&nonce,
|
||||
0,
|
||||
fragment.len(),
|
||||
fragment,
|
||||
no as usize,
|
||||
fragment_count as usize,
|
||||
time,
|
||||
&mut assembled,
|
||||
);
|
||||
time += 200;
|
||||
in_progress_fragments -= 1;
|
||||
assembled.clear();
|
||||
let mut nonce = [0; 12];
|
||||
nonce[..4].copy_from_slice(&id.to_be_bytes());
|
||||
cache.assemble(
|
||||
&nonce,
|
||||
0,
|
||||
fragment.len(),
|
||||
fragment,
|
||||
no as usize,
|
||||
fragment_count as usize,
|
||||
time,
|
||||
&mut assembled,
|
||||
);
|
||||
time += 200;
|
||||
in_progress_fragments -= 1;
|
||||
|
||||
if packet.len() > 0 {
|
||||
assert!(assembled.is_empty(), "Cache returned an incomplete packet");
|
||||
}
|
||||
}
|
||||
if packet.len() > 0 {
|
||||
in_progress.push((id, fragment_count, packet));
|
||||
if !packet.is_empty() {
|
||||
assert!(assembled.is_empty(), "Cache returned an incomplete packet");
|
||||
}
|
||||
}
|
||||
if !packet.is_empty() {
|
||||
in_progress.push((id, fragment_count, packet));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ pub(crate) struct UnassociatedHandshakeCache<Application: CryptoLayer> {
|
||||
cache: RwLock<CacheInner<Application>>,
|
||||
}
|
||||
/// SoA format
|
||||
struct CacheInner<Crypto: CryptoLayer> {
|
||||
struct CacheInner<C: CryptoLayer> {
|
||||
local_ids: [Option<NonZeroU32>; MAX_UNASSOCIATED_HANDSHAKE_STATES],
|
||||
expiries: [i64; MAX_UNASSOCIATED_HANDSHAKE_STATES],
|
||||
handshakes: [Option<Arc<StateB2<Crypto>>>; MAX_UNASSOCIATED_HANDSHAKE_STATES],
|
||||
handshakes: [Option<Arc<StateB2<C>>>; MAX_UNASSOCIATED_HANDSHAKE_STATES],
|
||||
}
|
||||
|
||||
/// Linear-search cache for capping the memory consumption of handshake data.
|
||||
|
||||
@@ -31,7 +31,11 @@ pub struct IndexedBinaryHeap<T, P> {
|
||||
data: Vec<(T, P, usize)>,
|
||||
map: Vec<(usize, u64)>,
|
||||
}
|
||||
|
||||
impl<T, P: Ord> Default for IndexedBinaryHeap<T, P> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
impl<T, P: Ord> IndexedBinaryHeap<T, P> {
|
||||
/// Create a new, empty binary heap.
|
||||
pub fn new() -> Self {
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
//! - **AES-256**: Single block encryption of header to harden packet fragmentation protocol
|
||||
//! - **AES-256-GCM**: Authenticated encryption
|
||||
//#![warn(missing_docs, rust_2018_idioms)]
|
||||
#![allow(clippy::too_many_arguments, clippy::type_complexity, clippy::assertions_on_constants)]
|
||||
pub mod crypto;
|
||||
pub mod crypto_impl;
|
||||
|
||||
|
||||
@@ -5,19 +5,19 @@ use crate::zeta::Session;
|
||||
|
||||
/// ZSSP events that might be interesting to log or aggregate into metrics.
|
||||
#[allow(missing_docs)]
|
||||
pub enum LogEvent<'a, Crypto: CryptoLayer> {
|
||||
ResentX1(&'a Arc<Session<Crypto>>),
|
||||
TimeoutX1(&'a Arc<Session<Crypto>>),
|
||||
pub enum LogEvent<'a, C: CryptoLayer> {
|
||||
ResentX1(&'a Arc<Session<C>>),
|
||||
TimeoutX1(&'a Arc<Session<C>>),
|
||||
TimeoutX2,
|
||||
ResentX3(&'a Arc<Session<Crypto>>),
|
||||
TimeoutX3(&'a Arc<Session<Crypto>>),
|
||||
ResentKeyConfirm(&'a Arc<Session<Crypto>>),
|
||||
TimeoutKeyConfirm(&'a Arc<Session<Crypto>>),
|
||||
StartedRekeyingSentK1(&'a Arc<Session<Crypto>>),
|
||||
ResentK1(&'a Arc<Session<Crypto>>),
|
||||
TimeoutK1(&'a Arc<Session<Crypto>>),
|
||||
ResentK2(&'a Arc<Session<Crypto>>),
|
||||
TimeoutK2(&'a Arc<Session<Crypto>>),
|
||||
ResentX3(&'a Arc<Session<C>>),
|
||||
TimeoutX3(&'a Arc<Session<C>>),
|
||||
ResentKeyConfirm(&'a Arc<Session<C>>),
|
||||
TimeoutKeyConfirm(&'a Arc<Session<C>>),
|
||||
StartedRekeyingSentK1(&'a Arc<Session<C>>),
|
||||
ResentK1(&'a Arc<Session<C>>),
|
||||
TimeoutK1(&'a Arc<Session<C>>),
|
||||
ResentK2(&'a Arc<Session<C>>),
|
||||
TimeoutK2(&'a Arc<Session<C>>),
|
||||
/// `(packet_type, packet_counter, fragment_no, fragment_count)`
|
||||
ReceivedRawFragment(u8, u64, usize, usize),
|
||||
ReceivedRawX1,
|
||||
@@ -25,24 +25,24 @@ pub enum LogEvent<'a, Crypto: CryptoLayer> {
|
||||
X1SucceededChallenge,
|
||||
X1IsAuthSentX2,
|
||||
ReceivedRawChallenge,
|
||||
ChallengeIsAuth(&'a Arc<Session<Crypto>>),
|
||||
ChallengeIsAuth(&'a Arc<Session<C>>),
|
||||
ReceivedRawX2,
|
||||
X2IsAuthSentX3(&'a Arc<Session<Crypto>>),
|
||||
X2IsAuthSentX3(&'a Arc<Session<C>>),
|
||||
ReceivedRawX3,
|
||||
X3IsAuthSentKeyConfirm(&'a Arc<Session<Crypto>>),
|
||||
X3IsAuthSentKeyConfirm(&'a Arc<Session<C>>),
|
||||
ReceivedRawKeyConfirm,
|
||||
KeyConfirmIsAuthSentAck(&'a Arc<Session<Crypto>>),
|
||||
KeyConfirmIsAuthSentAck(&'a Arc<Session<C>>),
|
||||
ReceivedRawAck,
|
||||
AckIsAuth(&'a Arc<Session<Crypto>>),
|
||||
AckIsAuth(&'a Arc<Session<C>>),
|
||||
ReceivedRawK1,
|
||||
K1IsAuthSentK2(&'a Arc<Session<Crypto>>),
|
||||
K1IsAuthSentK2(&'a Arc<Session<C>>),
|
||||
ReceivedRawK2,
|
||||
K2IsAuthSentKeyConfirm(&'a Arc<Session<Crypto>>),
|
||||
K2IsAuthSentKeyConfirm(&'a Arc<Session<C>>),
|
||||
ReceivedRawD,
|
||||
DIsAuthClosedSession(&'a Arc<Session<Crypto>>),
|
||||
DIsAuthClosedSession(&'a Arc<Session<C>>),
|
||||
}
|
||||
|
||||
impl<'a, Crypto: CryptoLayer> std::fmt::Debug for LogEvent<'a, Crypto> {
|
||||
impl<'a, C: CryptoLayer> std::fmt::Debug for LogEvent<'a, C> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::ResentX1(_) => f.debug_tuple("ResentX1").finish(),
|
||||
|
||||
+23
-23
@@ -46,7 +46,7 @@ pub enum SendError {
|
||||
/// Therefore it is no longer capable of sending, receiving or being serviced,
|
||||
/// so it should be dropped.
|
||||
#[derive(Clone)]
|
||||
pub struct ExpiredError<Crypto: CryptoLayer>(pub Arc<Session<Crypto>>);
|
||||
pub struct ExpiredError<C: CryptoLayer>(pub Arc<Session<C>>);
|
||||
|
||||
/// A type of fault occurred because we received a bad packet.
|
||||
///
|
||||
@@ -78,12 +78,12 @@ pub enum FaultType {
|
||||
/// Because an unauthenticated remote peer can force these to occur with specific
|
||||
/// contained information, it is recommended in production to either drop these
|
||||
/// immediately, or log them safely to a local output stream and then drop them.
|
||||
pub struct ByzantineFault<Crypto: CryptoLayer> {
|
||||
pub struct ByzantineFault<C: CryptoLayer> {
|
||||
/// The session associated with this fault, if there was one.
|
||||
///
|
||||
/// The sender specified this session within their packet, but they were not authenticated,
|
||||
/// so the sender could theoretically be anyone.
|
||||
pub session: Option<Arc<Session<Crypto>>>,
|
||||
pub session: Option<Arc<Session<C>>>,
|
||||
/// This field is true if this fault caused the session it was attached to to expire.
|
||||
/// An expired session is no longer "owned" by the ZSSP context.
|
||||
/// Therefore it is no longer capable of sending, receiving or being serviced,
|
||||
@@ -123,7 +123,7 @@ pub struct ByzantineFault<Crypto: CryptoLayer> {
|
||||
/// Keep in mind that when one of these occurs it inherently means that the packet from the remote
|
||||
/// peer has either not been authenticated or has failed authentication. As such, an attacker could
|
||||
/// trigger any of these. These errors should only be used for debugging and tracing.
|
||||
pub enum ReceiveError<Crypto: CryptoLayer> {
|
||||
pub enum ReceiveError<C: CryptoLayer> {
|
||||
/// A type of fault that can occur because a remote peer sent us a bad packet.
|
||||
/// Such packets will be ignored by ZSSP but a user of ZSSP might want to log
|
||||
/// them for debugging or tracing.
|
||||
@@ -131,11 +131,11 @@ pub enum ReceiveError<Crypto: CryptoLayer> {
|
||||
/// Because an unauthenticated remote peer can force these to occur with specific
|
||||
/// contained information, it is recommended in production to either drop these
|
||||
/// immediately, or log them safely to a local output stream and then drop them.
|
||||
ByzantineFault(ByzantineFault<Crypto>),
|
||||
ByzantineFault(ByzantineFault<C>),
|
||||
|
||||
/// Rekeying failed and session secret has reached its hard usage count limit.
|
||||
/// The associated session will no longer function and has to be dropped.
|
||||
MaxKeyLifetimeExceeded(Arc<Session<Crypto>>),
|
||||
MaxKeyLifetimeExceeded(Arc<Session<C>>),
|
||||
|
||||
/// Either the `ApplicationLayer::incoming_session` or `ApplicationLayer::check_accept_session`
|
||||
/// callback rejected the remote peer's attempt to establish a new session.
|
||||
@@ -147,7 +147,7 @@ pub enum ReceiveError<Crypto: CryptoLayer> {
|
||||
|
||||
/// An error was returned by the `output_buffer` passed to receive.
|
||||
/// The received packet was dropped.
|
||||
WriteError(std::io::Error, Arc<Session<Crypto>>),
|
||||
WriteError(std::io::Error, Arc<Session<C>>),
|
||||
}
|
||||
|
||||
macro_rules! fault {
|
||||
@@ -183,18 +183,18 @@ pub(crate) use fault;
|
||||
|
||||
/// Result generated by the context packet receive function, with possible payloads.
|
||||
#[derive(Clone)]
|
||||
pub enum ReceiveOk<Crypto: CryptoLayer> {
|
||||
pub enum ReceiveOk<C: CryptoLayer> {
|
||||
/// The received packet superficially appeared valid but is not associated with a session yet.
|
||||
/// This can occur because the packet was only a fragment of a larger packet,
|
||||
/// or if it was a control packet that does not go through full Noise authentication.
|
||||
Unassociated,
|
||||
/// The received packet was authentic and belongs to this specific session.
|
||||
Associated(Arc<Session<Crypto>>, SessionEvent),
|
||||
Associated(Arc<Session<C>>, SessionEvent),
|
||||
/// The received packet was a fragment of a larger packet.
|
||||
///
|
||||
/// ***The authenticity of this fragment cannot be fully known yet.***
|
||||
/// This return value should only be used for debugging and tracing purposes.
|
||||
Fragment(Arc<Session<Crypto>>),
|
||||
Fragment(Arc<Session<C>>),
|
||||
}
|
||||
/// Something that can occur to an associated session when a packet is received successfully,
|
||||
/// including receiving a payload of decrypted, authenticated data.
|
||||
@@ -270,20 +270,20 @@ impl fmt::Display for SendError {
|
||||
}
|
||||
impl Error for SendError {}
|
||||
|
||||
impl<Crypto: CryptoLayer> fmt::Debug for ExpiredError<Crypto>
|
||||
impl<C: CryptoLayer> fmt::Debug for ExpiredError<C>
|
||||
where
|
||||
Session<Crypto>: fmt::Debug,
|
||||
Session<C>: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("ExpiredError").field(&self.0).finish()
|
||||
}
|
||||
}
|
||||
impl<Crypto: CryptoLayer> fmt::Display for ExpiredError<Crypto> {
|
||||
impl<C: CryptoLayer> fmt::Display for ExpiredError<C> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "session expired")
|
||||
}
|
||||
}
|
||||
impl<Crypto: CryptoLayer> Error for ExpiredError<Crypto> where Session<Crypto>: fmt::Debug {}
|
||||
impl<C: CryptoLayer> Error for ExpiredError<C> where Session<C>: fmt::Debug {}
|
||||
|
||||
impl fmt::Display for FaultType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
@@ -301,7 +301,7 @@ impl Error for FaultType {}
|
||||
|
||||
// I don't like getter methods but in this case they are the only way to implement
|
||||
// conditionally compiled struct fields without the feature flag causing breaking changes.
|
||||
impl<Crypto: CryptoLayer> ByzantineFault<Crypto> {
|
||||
impl<C: CryptoLayer> ByzantineFault<C> {
|
||||
/// The file of this implementation of ZSSP from which this error was generated.
|
||||
#[cfg(feature = "debug")]
|
||||
pub fn file(&self) -> &'static str {
|
||||
@@ -316,9 +316,9 @@ impl<Crypto: CryptoLayer> ByzantineFault<Crypto> {
|
||||
self.line
|
||||
}
|
||||
}
|
||||
impl<Crypto: CryptoLayer> fmt::Debug for ByzantineFault<Crypto>
|
||||
impl<C: CryptoLayer> fmt::Debug for ByzantineFault<C>
|
||||
where
|
||||
Session<Crypto>: fmt::Debug,
|
||||
Session<C>: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ByzantineFault")
|
||||
@@ -331,7 +331,7 @@ where
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
impl<Crypto: CryptoLayer> fmt::Display for ByzantineFault<Crypto> {
|
||||
impl<C: CryptoLayer> fmt::Display for ByzantineFault<C> {
|
||||
#[cfg(feature = "debug")]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{} ({}:{})", self.error, self.file, self.line)
|
||||
@@ -341,11 +341,11 @@ impl<Crypto: CryptoLayer> fmt::Display for ByzantineFault<Crypto> {
|
||||
self.error.fmt(f)
|
||||
}
|
||||
}
|
||||
impl<Crypto: CryptoLayer> Error for ByzantineFault<Crypto> where Session<Crypto>: fmt::Debug {}
|
||||
impl<C: CryptoLayer> Error for ByzantineFault<C> where Session<C>: fmt::Debug {}
|
||||
|
||||
impl<Crypto: CryptoLayer> fmt::Debug for ReceiveError<Crypto>
|
||||
impl<C: CryptoLayer> fmt::Debug for ReceiveError<C>
|
||||
where
|
||||
Crypto::SessionData: fmt::Debug,
|
||||
C::SessionData: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
@@ -357,7 +357,7 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<Crypto: CryptoLayer> fmt::Display for ReceiveError<Crypto> {
|
||||
impl<C: CryptoLayer> fmt::Display for ReceiveError<C> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ReceiveError::ByzantineFault(e) => e.fmt(f),
|
||||
@@ -368,4 +368,4 @@ impl<Crypto: CryptoLayer> fmt::Display for ReceiveError<Crypto> {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<Crypto: CryptoLayer> Error for ReceiveError<Crypto> where Crypto::SessionData: fmt::Debug {}
|
||||
impl<C: CryptoLayer> Error for ReceiveError<C> where C::SessionData: fmt::Debug {}
|
||||
|
||||
@@ -6,15 +6,15 @@ use crate::application::CryptoLayer;
|
||||
use crate::crypto::*;
|
||||
use crate::proto::*;
|
||||
|
||||
pub struct SymmetricState<Crypto: CryptoLayer> {
|
||||
pub struct SymmetricState<C: CryptoLayer> {
|
||||
k: Zeroizing<[u8; AES_256_KEY_SIZE]>,
|
||||
ck: Zeroizing<[u8; HASHLEN]>,
|
||||
h: [u8; HASHLEN],
|
||||
/// If anyone knows a better way to get rid of the "parameter `App` is never used" error please
|
||||
/// let me know.
|
||||
_app: PhantomData<fn() -> Crypto::SessionData>,
|
||||
_app: PhantomData<fn() -> C::SessionData>,
|
||||
}
|
||||
impl<Crypto: CryptoLayer> Clone for SymmetricState<Crypto> {
|
||||
impl<C: CryptoLayer> Clone for SymmetricState<C> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
k: self.k.clone(),
|
||||
@@ -25,7 +25,7 @@ impl<Crypto: CryptoLayer> Clone for SymmetricState<Crypto> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Crypto: CryptoLayer> SymmetricState<Crypto> {
|
||||
impl<C: CryptoLayer> SymmetricState<C> {
|
||||
/// HMAC-SHA512 key derivation based on KBKDF Counter Mode:
|
||||
/// https://csrc.nist.gov/publications/detail/sp/800-108/rev-1/final.
|
||||
/// Cryptographically this isn't meaningfully different from
|
||||
@@ -40,7 +40,7 @@ impl<Crypto: CryptoLayer> SymmetricState<Crypto> {
|
||||
/// Corresponds to Noise `HKDF`.
|
||||
fn kbkdf(
|
||||
&self,
|
||||
hmac: &mut Crypto::Hmac,
|
||||
hmac: &mut C::Hmac,
|
||||
input_key_material: &[u8],
|
||||
label: &[u8; 4],
|
||||
num_outputs: u16,
|
||||
@@ -86,7 +86,7 @@ impl<Crypto: CryptoLayer> SymmetricState<Crypto> {
|
||||
}
|
||||
}
|
||||
/// Corresponds to Noise `MixKey`.
|
||||
pub fn mix_key(&mut self, hmac: &mut Crypto::Hmac, input_key_material: &[u8]) {
|
||||
pub fn mix_key(&mut self, hmac: &mut C::Hmac, input_key_material: &[u8]) {
|
||||
let mut next_ck = Zeroizing::new([0u8; HASHLEN]);
|
||||
let mut temp_k = Zeroizing::new([0u8; HASHLEN]);
|
||||
|
||||
@@ -104,7 +104,7 @@ impl<Crypto: CryptoLayer> SymmetricState<Crypto> {
|
||||
self.k.clone_from_slice(&temp_k[..AES_256_KEY_SIZE]);
|
||||
}
|
||||
/// Corresponds to Noise `MixKey`.
|
||||
pub fn mix_key_no_init(&mut self, hmac: &mut Crypto::Hmac, input_key_material: &[u8]) {
|
||||
pub fn mix_key_no_init(&mut self, hmac: &mut C::Hmac, input_key_material: &[u8]) {
|
||||
let mut next_ck = Zeroizing::new([0u8; HASHLEN]);
|
||||
|
||||
self.kbkdf(hmac, input_key_material, LABEL_KBKDF_CHAIN, 2, &mut next_ck, None, None);
|
||||
@@ -112,13 +112,13 @@ impl<Crypto: CryptoLayer> SymmetricState<Crypto> {
|
||||
*self.ck = *next_ck;
|
||||
}
|
||||
/// Corresponds to Noise `MixHash`.
|
||||
pub fn mix_hash(&mut self, hash: &mut Crypto::Hash, data: &[u8]) {
|
||||
pub fn mix_hash(&mut self, hash: &mut C::Hash, data: &[u8]) {
|
||||
hash.update(&self.h);
|
||||
hash.update(data);
|
||||
hash.finish_and_reset(&mut self.h);
|
||||
}
|
||||
/// Corresponds to Noise `MixKeyAndHash`.
|
||||
pub fn mix_key_and_hash(&mut self, hash: &mut Crypto::Hash, hmac: &mut Crypto::Hmac, input_key_material: &[u8]) {
|
||||
pub fn mix_key_and_hash(&mut self, hash: &mut C::Hash, hmac: &mut C::Hmac, input_key_material: &[u8]) {
|
||||
let mut next_ck = Zeroizing::new([0u8; HASHLEN]);
|
||||
let mut temp_h = [0u8; HASHLEN];
|
||||
let mut temp_k = Zeroizing::new([0u8; HASHLEN]);
|
||||
@@ -138,12 +138,7 @@ impl<Crypto: CryptoLayer> SymmetricState<Crypto> {
|
||||
self.k.clone_from_slice(&temp_k[..AES_256_KEY_SIZE]);
|
||||
}
|
||||
/// Corresponds to Noise `MixKeyAndHash`.
|
||||
pub fn mix_key_and_hash_no_init(
|
||||
&mut self,
|
||||
hash: &mut Crypto::Hash,
|
||||
hmac: &mut Crypto::Hmac,
|
||||
input_key_material: &[u8],
|
||||
) {
|
||||
pub fn mix_key_and_hash_no_init(&mut self, hash: &mut C::Hash, hmac: &mut C::Hmac, input_key_material: &[u8]) {
|
||||
let mut next_ck = Zeroizing::new([0u8; HASHLEN]);
|
||||
let mut temp_h = [0u8; HASHLEN];
|
||||
|
||||
@@ -164,11 +159,11 @@ impl<Crypto: CryptoLayer> SymmetricState<Crypto> {
|
||||
#[must_use]
|
||||
pub fn encrypt_and_hash_in_place(
|
||||
&mut self,
|
||||
hash: &mut Crypto::Hash,
|
||||
hash: &mut C::Hash,
|
||||
iv: [u8; AES_GCM_NONCE_SIZE],
|
||||
data: &mut [u8],
|
||||
) -> [u8; AES_GCM_TAG_SIZE] {
|
||||
let tag = Crypto::Aead::encrypt_in_place(&self.k, &iv, &self.h, data);
|
||||
let tag = C::Aead::encrypt_in_place(&self.k, &iv, &self.h, data);
|
||||
hash.update(&self.h);
|
||||
hash.update(data);
|
||||
hash.update(&tag);
|
||||
@@ -179,7 +174,7 @@ impl<Crypto: CryptoLayer> SymmetricState<Crypto> {
|
||||
#[must_use]
|
||||
pub fn decrypt_and_hash_in_place(
|
||||
&mut self,
|
||||
hash: &mut Crypto::Hash,
|
||||
hash: &mut C::Hash,
|
||||
iv: [u8; AES_GCM_NONCE_SIZE],
|
||||
data: &mut [u8],
|
||||
tag: [u8; AES_GCM_TAG_SIZE],
|
||||
@@ -187,25 +182,19 @@ impl<Crypto: CryptoLayer> SymmetricState<Crypto> {
|
||||
hash.update(&self.h);
|
||||
hash.update(data);
|
||||
hash.update(&tag);
|
||||
let is_auth = Crypto::Aead::decrypt_in_place(&self.k, &iv, &self.h, data, tag.as_ref().try_into().unwrap());
|
||||
let is_auth = C::Aead::decrypt_in_place(&self.k, &iv, &self.h, data, tag.as_ref().try_into().unwrap());
|
||||
hash.finish_and_reset(&mut self.h);
|
||||
is_auth
|
||||
}
|
||||
/// Corresponds to Noise `Split`.
|
||||
pub fn split(self, hmac: &mut Crypto::Hmac, key1: &mut [u8; HASHLEN], key2: &mut [u8; HASHLEN]) {
|
||||
pub fn split(self, hmac: &mut C::Hmac, key1: &mut [u8; HASHLEN], key2: &mut [u8; HASHLEN]) {
|
||||
self.kbkdf(hmac, &[], LABEL_KBKDF_CHAIN, 2, key1, Some(key2), None);
|
||||
}
|
||||
/// Get an additional symmetric key (ASK) that is a collision resistant hash of the transcript,
|
||||
/// is forward secrect and is cryptographically independent from all other produced keys.
|
||||
/// Based on Noise's unstable ASK mechanism, using KBKDF instead of HKDF.
|
||||
/// https://github.com/noiseprotocol/noise_wiki/wiki/Additional-Symmetric-Keys.
|
||||
pub fn get_ask(
|
||||
&self,
|
||||
hmac: &mut Crypto::Hmac,
|
||||
label: &[u8; 4],
|
||||
key1: &mut [u8; HASHLEN],
|
||||
key2: &mut [u8; HASHLEN],
|
||||
) {
|
||||
pub fn get_ask(&self, hmac: &mut C::Hmac, label: &[u8; 4], key1: &mut [u8; HASHLEN], key2: &mut [u8; HASHLEN]) {
|
||||
self.kbkdf(hmac, &self.h, label, 2, key1, Some(key2), None);
|
||||
}
|
||||
/// Used for internally debugging a key exchange.
|
||||
|
||||
+191
-200
File diff suppressed because it is too large
Load Diff
+37
-37
@@ -37,43 +37,43 @@ pub(crate) use log;
|
||||
/// defragment incoming packets that are not yet associated with a session.
|
||||
///
|
||||
/// Internally this is just a clonable Arc, so it can be safely shared with multiple threads.
|
||||
pub struct Context<Crypto: CryptoLayer>(pub Arc<ContextInner<Crypto>>);
|
||||
impl<Crypto: CryptoLayer> Clone for Context<Crypto> {
|
||||
pub struct Context<C: CryptoLayer>(pub Arc<ContextInner<C>>);
|
||||
impl<C: CryptoLayer> Clone for Context<C> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type SessionMap<Crypto> = RwLock<HashMap<NonZeroU32, Weak<Session<Crypto>>>>;
|
||||
pub(crate) type SessionMap<C> = RwLock<HashMap<NonZeroU32, Weak<Session<C>>>>;
|
||||
|
||||
pub(crate) type SessionQueue<Crypto> = IndexedBinaryHeap<Weak<Session<Crypto>>, Reverse<i64>>;
|
||||
pub(crate) type SessionQueue<C> = IndexedBinaryHeap<Weak<Session<C>>, Reverse<i64>>;
|
||||
|
||||
/// The internal memory of the ZSSP context.
|
||||
/// One of these is allocated as an `Arc` to initialize this implementation of ZSSP.
|
||||
/// See `Context::new`.
|
||||
pub struct ContextInner<Crypto: CryptoLayer> {
|
||||
pub struct ContextInner<C: CryptoLayer> {
|
||||
/// The `CryptoRng` instance that was passed to ZSSP when this context was created.
|
||||
pub rng: Mutex<Crypto::Rng>,
|
||||
pub rng: Mutex<C::Rng>,
|
||||
pub(crate) next_service_time: AtomicI64,
|
||||
pub(crate) s_secret: Crypto::KeyPair,
|
||||
pub(crate) s_secret: C::KeyPair,
|
||||
/// `session_queue -> state_machine_lock -> state -> session_map`
|
||||
pub(crate) session_queue: Mutex<SessionQueue<Crypto>>,
|
||||
pub(crate) session_queue: Mutex<SessionQueue<C>>,
|
||||
/// `session_queue -> state_machine_lock -> state -> session_map`
|
||||
pub(crate) session_map: SessionMap<Crypto>,
|
||||
pub(crate) unassociated_defrag_cache: Mutex<UnassociatedFragCache<Crypto>>,
|
||||
pub(crate) unassociated_handshake_states: UnassociatedHandshakeCache<Crypto>,
|
||||
pub(crate) session_map: SessionMap<C>,
|
||||
pub(crate) unassociated_defrag_cache: Mutex<UnassociatedFragCache<C>>,
|
||||
pub(crate) unassociated_handshake_states: UnassociatedHandshakeCache<C>,
|
||||
|
||||
pub(crate) challenge: ChallengeContext,
|
||||
}
|
||||
impl<Crypto: CryptoLayer> ContextInner<Crypto> {
|
||||
impl<C: CryptoLayer> ContextInner<C> {
|
||||
pub(crate) fn reduce_next_service_time(&self, time: i64) -> Option<i64> {
|
||||
(self.next_service_time.fetch_min(time, Ordering::Relaxed) > time).then_some(time)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_fragment_header<Crypto: CryptoLayer>(
|
||||
fn parse_fragment_header<C: CryptoLayer>(
|
||||
incoming_fragment: &[u8],
|
||||
) -> Result<(usize, usize, [u8; AES_GCM_NONCE_SIZE]), ReceiveError<Crypto>> {
|
||||
) -> Result<(usize, usize, [u8; AES_GCM_NONCE_SIZE]), ReceiveError<C>> {
|
||||
let fragment_no = incoming_fragment[FRAGMENT_NO_IDX] as usize;
|
||||
let fragment_count = incoming_fragment[FRAGMENT_COUNT_IDX] as usize;
|
||||
if fragment_no >= fragment_count || fragment_count > MAX_FRAGMENTS {
|
||||
@@ -122,9 +122,9 @@ fn send_with_fragmentation<PrpEnc: Aes256Enc>(
|
||||
true
|
||||
}
|
||||
|
||||
impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
impl<C: CryptoLayer> Context<C> {
|
||||
/// Create a new session context.
|
||||
pub fn new(static_secret_key: Crypto::KeyPair, mut rng: Crypto::Rng) -> Self {
|
||||
pub fn new(static_secret_key: C::KeyPair, mut rng: C::Rng) -> Self {
|
||||
let challenge = ChallengeContext::new(&mut rng);
|
||||
Self(Arc::new(ContextInner {
|
||||
rng: Mutex::new(rng),
|
||||
@@ -160,15 +160,15 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
/// object
|
||||
/// * `identity` - Payload to be sent to Bob that contains the information necessary
|
||||
/// for the upper protocol to authenticate and approve of Alice's identity.
|
||||
pub fn open<App: ApplicationLayer<Crypto>>(
|
||||
pub fn open<App: ApplicationLayer<C>>(
|
||||
&self,
|
||||
app: App,
|
||||
send: impl Sender,
|
||||
mut mtu: usize,
|
||||
static_remote_key: Crypto::PublicKey,
|
||||
session_data: Crypto::SessionData,
|
||||
static_remote_key: C::PublicKey,
|
||||
session_data: C::SessionData,
|
||||
identity: &[u8],
|
||||
) -> Result<(Arc<Session<Crypto>>, Option<i64>), OpenError> {
|
||||
) -> Result<(Arc<Session<C>>, Option<i64>), OpenError> {
|
||||
mtu = mtu.max(MIN_TRANSPORT_MTU);
|
||||
if identity.len() > IDENTITY_MAX_SIZE {
|
||||
return Err(OpenError::IdentityTooLarge);
|
||||
@@ -199,16 +199,16 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
/// * `remote_address` - Whatever the remote address is, as long as you can Hash it
|
||||
/// * `incoming_fragment_buf` - Buffer containing incoming wire packet (the context takes ownership)
|
||||
/// * `output_buffer` - Buffer to receive decrypted and authenticated object data
|
||||
pub fn receive<'a, App: ApplicationLayer<Crypto>>(
|
||||
pub fn receive<App: ApplicationLayer<C>>(
|
||||
&self,
|
||||
mut app: App,
|
||||
mut send_unassociated_reply: impl Sender,
|
||||
mut send_unassociated_mtu: usize,
|
||||
mut send_to: impl SendTo<Crypto>,
|
||||
mut send_to: impl SendTo<C>,
|
||||
remote_address: &impl Hash,
|
||||
mut incoming_fragment_buf: Crypto::IncomingPacketBuffer,
|
||||
mut incoming_fragment_buf: C::IncomingPacketBuffer,
|
||||
output_buffer: impl Write,
|
||||
) -> Result<(ReceiveOk<Crypto>, Option<i64>), ReceiveError<Crypto>> {
|
||||
) -> Result<(ReceiveOk<C>, Option<i64>), ReceiveError<C>> {
|
||||
use crate::result::FaultType::*;
|
||||
let ctx = &self.0;
|
||||
send_unassociated_mtu = send_unassociated_mtu.max(MIN_TRANSPORT_MTU);
|
||||
@@ -324,7 +324,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
&mut incoming_fragment_buf.as_mut()[HEADER_SIZE..]
|
||||
};
|
||||
|
||||
let send_associated = |packet: &mut [u8], hk_send: Option<&Crypto::PrpEnc>| {
|
||||
let send_associated = |packet: &mut [u8], hk_send: Option<&C::PrpEnc>| {
|
||||
if let Some((sender, mut mtu)) = send_to.init_send(&session) {
|
||||
mtu = mtu.max(MIN_TRANSPORT_MTU);
|
||||
send_with_fragmentation(sender, mtu, packet, hk_send);
|
||||
@@ -416,7 +416,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
// Check for and handle PACKET_TYPE_ALICE_NOISE_XK_PATTERN_3
|
||||
let zeta = self.0.unassociated_handshake_states.get(kid_recv);
|
||||
if let Some(zeta) = zeta {
|
||||
Crypto::PrpDec::new(&zeta.hk_recv).decrypt_in_place(
|
||||
C::PrpDec::new(&zeta.hk_recv).decrypt_in_place(
|
||||
(&mut incoming_fragment[HEADER_AUTH_START..HEADER_AUTH_END])
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
@@ -535,7 +535,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
}
|
||||
// Process recv challenge layer.
|
||||
let challenge_start = assembled_packet.len() - CHALLENGE_SIZE;
|
||||
let hash = &mut Crypto::Hash::new();
|
||||
let hash = &mut C::Hash::new();
|
||||
match app.incoming_session() {
|
||||
IncomingSessionAction::Allow => {}
|
||||
IncomingSessionAction::Challenge => {
|
||||
@@ -616,7 +616,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
/// * `data` - Data to send
|
||||
pub fn send(
|
||||
&self,
|
||||
session: &Session<Crypto>,
|
||||
session: &Session<C>,
|
||||
send: impl Sender,
|
||||
mtu_sized_buffer: &mut [u8],
|
||||
data: &[u8],
|
||||
@@ -631,7 +631,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
///
|
||||
/// * `app` - Interface to application using ZSSP
|
||||
/// * `send_to` - Function to get a sender and an MTU to send something over an active session
|
||||
pub fn service<App: ApplicationLayer<Crypto>>(&self, mut app: App, mut send_to: impl SendTo<Crypto>) -> i64 {
|
||||
pub fn service<App: ApplicationLayer<C>>(&self, mut app: App, mut send_to: impl SendTo<C>) -> i64 {
|
||||
let current_time = app.time();
|
||||
let next_service_time = loop {
|
||||
match self.service_inner(&mut app, send_to, current_time) {
|
||||
@@ -639,10 +639,10 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
Err((_, s)) => send_to = s,
|
||||
}
|
||||
};
|
||||
let max_interval = Crypto::SETTINGS
|
||||
let max_interval = C::SETTINGS
|
||||
.fragment_assembly_timeout
|
||||
.min(Crypto::SETTINGS.rekey_timeout)
|
||||
.min(Crypto::SETTINGS.initial_offer_timeout);
|
||||
.min(C::SETTINGS.rekey_timeout)
|
||||
.min(C::SETTINGS.initial_offer_timeout);
|
||||
|
||||
(next_service_time - current_time).min(max_interval as i64)
|
||||
}
|
||||
@@ -667,20 +667,20 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
///
|
||||
/// * `app` - Interface to application using ZSSP
|
||||
/// * `send_to` - Function to get a sender and an MTU to send something over an active session
|
||||
pub fn service_scheduled<App: ApplicationLayer<Crypto>>(
|
||||
pub fn service_scheduled<App: ApplicationLayer<C>>(
|
||||
&self,
|
||||
mut app: App,
|
||||
send_to: impl SendTo<Crypto>,
|
||||
) -> Result<i64, ExpiredError<Crypto>> {
|
||||
send_to: impl SendTo<C>,
|
||||
) -> Result<i64, ExpiredError<C>> {
|
||||
let current_time = app.time();
|
||||
self.service_inner(&mut app, send_to, current_time).map_err(|e| e.0)
|
||||
}
|
||||
fn service_inner<App: ApplicationLayer<Crypto>, F: SendTo<Crypto>>(
|
||||
fn service_inner<App: ApplicationLayer<C>, F: SendTo<C>>(
|
||||
&self,
|
||||
app: &mut App,
|
||||
mut send_to: F,
|
||||
current_time: i64,
|
||||
) -> Result<i64, (ExpiredError<Crypto>, F)> {
|
||||
) -> Result<i64, (ExpiredError<C>, F)> {
|
||||
let ctx = &self.0;
|
||||
let mut session_queue = ctx.session_queue.lock().unwrap();
|
||||
let mut queue_service_time = i64::MAX;
|
||||
|
||||
@@ -3,7 +3,7 @@ authors = ["ZeroTier, Inc. <contact@zerotier.com>", "Adam Ierymenko <adam.ieryme
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
name = "zssp-proto"
|
||||
version = "0.1.0"
|
||||
version = "0.3.0"
|
||||
|
||||
[lib]
|
||||
name = "zssp_proto"
|
||||
|
||||
@@ -65,9 +65,7 @@ impl CryptoLayer for TestApplication {
|
||||
type SessionData = u128;
|
||||
}
|
||||
#[allow(unused)]
|
||||
impl ApplicationLayer for &mut TestApplication {
|
||||
type Crypto = TestApplication;
|
||||
|
||||
impl ApplicationLayer<TestApplication> for &mut TestApplication {
|
||||
fn hello_requires_recognized_ratchet(&mut self) -> bool {
|
||||
false
|
||||
}
|
||||
@@ -159,7 +157,7 @@ fn alice_main(
|
||||
&mut alice_app,
|
||||
|b| alice_out.send(b).is_ok(),
|
||||
TEST_MTU,
|
||||
bob_pubkey.clone(),
|
||||
bob_pubkey,
|
||||
0,
|
||||
Vec::new(),
|
||||
)
|
||||
|
||||
@@ -44,9 +44,7 @@ impl CryptoLayer for MyApp {
|
||||
/// In this example for simplicity we won't be hooking up ratchet keys to a filesystem backend.
|
||||
/// They are dropped and peers ignore if they are missing.
|
||||
#[allow(unused)]
|
||||
impl ApplicationLayer for &mut MyApp {
|
||||
type Crypto = MyApp;
|
||||
|
||||
impl ApplicationLayer<MyApp> for &mut MyApp {
|
||||
fn hello_requires_recognized_ratchet(&mut self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
@@ -139,10 +139,7 @@ pub trait CryptoLayer: Sized {
|
||||
///
|
||||
/// Templating ZSSP on this trait lets the code here be almost entirely transport, OS,
|
||||
/// and use case independent.
|
||||
pub trait ApplicationLayer: Sized {
|
||||
/// Specifies which concrete set of cryptography types will be used by this application.
|
||||
type Crypto: CryptoLayer;
|
||||
|
||||
pub trait ApplicationLayer<C: CryptoLayer>: Sized {
|
||||
/// Should return the current time in milliseconds. Does not have to be monotonic, nor synced
|
||||
/// with remote peers (although both of these properties would help reliability slightly).
|
||||
/// Used to determine if any current handshakes should be resent or timed-out, or if a session
|
||||
@@ -174,7 +171,7 @@ pub trait ApplicationLayer: Sized {
|
||||
/// least one party is misconfigured and got their ratchet keys corrupted or lost, or Bob has
|
||||
/// been compromised and is being impersonated. An attacker must at least have Bob's private
|
||||
/// static key to be able to ask Alice to downgrade.
|
||||
fn initiator_disallows_downgrade(&mut self, session: &Arc<Session<Self::Crypto>>) -> bool;
|
||||
fn initiator_disallows_downgrade(&mut self, session: &Arc<Session<C>>) -> bool;
|
||||
/// Function to accept sessions after final negotiation.
|
||||
/// The second argument is the identity that the remote peer sent us. The application
|
||||
/// must verify this identity is associated with the remote peer's static key.
|
||||
@@ -183,9 +180,9 @@ pub trait ApplicationLayer: Sized {
|
||||
/// before returning.
|
||||
fn check_accept_session(
|
||||
&mut self,
|
||||
remote_static_key: &<Self::Crypto as CryptoLayer>::PublicKey,
|
||||
remote_static_key: &<C as CryptoLayer>::PublicKey,
|
||||
identity: &[u8],
|
||||
) -> AcceptAction<Self::Crypto>;
|
||||
) -> AcceptAction<C>;
|
||||
|
||||
/// Lookup a specific ratchet state based on its ratchet fingerprint.
|
||||
/// This function will be called whenever Alice attempts to connect to us with a non-empty
|
||||
@@ -213,8 +210,8 @@ pub trait ApplicationLayer: Sized {
|
||||
/// function `ApplicationLayer::check_accept_session`.
|
||||
fn restore_by_identity(
|
||||
&mut self,
|
||||
remote_static_key: &<Self::Crypto as CryptoLayer>::PublicKey,
|
||||
session_data: &<Self::Crypto as CryptoLayer>::SessionData,
|
||||
remote_static_key: &<C as CryptoLayer>::PublicKey,
|
||||
session_data: &<C as CryptoLayer>::SessionData,
|
||||
) -> Result<Option<RatchetStates>, std::io::Error>;
|
||||
/// Atomically commit the update specified by `update_data` to storage, or return an error if
|
||||
/// the update could not be made.
|
||||
@@ -234,8 +231,8 @@ pub trait ApplicationLayer: Sized {
|
||||
/// Otherwise, when we restart, we will not be allowed to reconnect.
|
||||
fn save_ratchet_state(
|
||||
&mut self,
|
||||
remote_static_key: &<Self::Crypto as CryptoLayer>::PublicKey,
|
||||
session_data: &<Self::Crypto as CryptoLayer>::SessionData,
|
||||
remote_static_key: &<C as CryptoLayer>::PublicKey,
|
||||
session_data: &<C as CryptoLayer>::SessionData,
|
||||
update_data: RatchetUpdate<'_>,
|
||||
) -> Result<(), std::io::Error>;
|
||||
|
||||
@@ -244,7 +241,7 @@ pub trait ApplicationLayer: Sized {
|
||||
/// nothing else. Do not base protocol-level decisions upon the events passed to this function.
|
||||
#[cfg(feature = "logging")]
|
||||
#[allow(unused)]
|
||||
fn event_log(&mut self, event: LogEvent<'_, Self::Crypto>) {}
|
||||
fn event_log(&mut self, event: LogEvent<'_, C>) {}
|
||||
}
|
||||
|
||||
/// A collection of fields specifying how to complete the key exchange with a specific remote peer,
|
||||
|
||||
@@ -24,7 +24,7 @@ pub fn respond_to_challenge_in_place<Rng: RngCore + CryptoRng, Hash: Sha512Hash>
|
||||
challenge: &[u8; CHALLENGE_SIZE],
|
||||
pre_response: &mut [u8; CHALLENGE_SIZE],
|
||||
) {
|
||||
if &challenge[POW_START..] == &pre_response[POW_START..] {
|
||||
if challenge[POW_START..] == pre_response[POW_START..] {
|
||||
pre_response.copy_from_slice(challenge);
|
||||
let mut pow = rng.next_u64();
|
||||
loop {
|
||||
@@ -80,7 +80,6 @@ impl ChallengeContext {
|
||||
hasher.write(&c.to_be_bytes());
|
||||
addr.hash(&mut hasher);
|
||||
hasher.write(&self.salt);
|
||||
drop(hasher);
|
||||
|
||||
let mac = h.finish();
|
||||
mac[..MAC_SIZE].try_into().unwrap()
|
||||
|
||||
+44
-53
@@ -31,21 +31,21 @@ pub(crate) use log;
|
||||
/// defragment incoming packets that are not yet associated with a session.
|
||||
///
|
||||
/// Internally this is just a clonable Arc, so it can be safely shared with multiple threads.
|
||||
pub struct Context<Crypto: CryptoLayer>(Arc<ContextInner<Crypto>>);
|
||||
impl<Crypto: CryptoLayer> Clone for Context<Crypto> {
|
||||
pub struct Context<C: CryptoLayer>(Arc<ContextInner<C>>);
|
||||
impl<C: CryptoLayer> Clone for Context<C> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type SessionMap<Crypto> = RefCell<HashMap<NonZeroU32, Weak<Session<Crypto>>>>;
|
||||
pub(crate) type SessionMap<C> = RefCell<HashMap<NonZeroU32, Weak<Session<C>>>>;
|
||||
|
||||
pub(crate) struct ContextInner<Crypto: CryptoLayer> {
|
||||
pub(crate) rng: RefCell<Crypto::Rng>,
|
||||
pub(crate) s_secret: Crypto::KeyPair,
|
||||
pub(crate) session_map: SessionMap<Crypto>,
|
||||
pub(crate) sessions: RefCell<HashMap<*const Session<Crypto>, Weak<Session<Crypto>>>>,
|
||||
pub(crate) b2_map: RefCell<HashMap<NonZeroU32, StateB2<Crypto>>>,
|
||||
pub(crate) struct ContextInner<C: CryptoLayer> {
|
||||
pub(crate) rng: RefCell<C::Rng>,
|
||||
pub(crate) s_secret: C::KeyPair,
|
||||
pub(crate) session_map: SessionMap<C>,
|
||||
pub(crate) sessions: RefCell<HashMap<*const Session<C>, Weak<Session<C>>>>,
|
||||
pub(crate) b2_map: RefCell<HashMap<NonZeroU32, StateB2<C>>>,
|
||||
|
||||
hello_defrag: RefCell<DefragBuffer>,
|
||||
challenge: RefCell<ChallengeContext>,
|
||||
@@ -62,9 +62,9 @@ fn to_packet_nonce(n: &[u8; AES_GCM_NONCE_SIZE]) -> &[u8; PACKET_NONCE_SIZE] {
|
||||
(&n[n.len() - PACKET_NONCE_SIZE..]).try_into().unwrap()
|
||||
}
|
||||
|
||||
impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
impl<C: CryptoLayer> Context<C> {
|
||||
/// Create a new session context.
|
||||
pub fn new(static_secret_key: Crypto::KeyPair, mut rng: Crypto::Rng) -> Self {
|
||||
pub fn new(static_secret_key: C::KeyPair, mut rng: C::Rng) -> Self {
|
||||
let challenge = ChallengeContext::new(&mut rng);
|
||||
Self(Arc::new(ContextInner {
|
||||
rng: RefCell::new(rng),
|
||||
@@ -93,18 +93,15 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
/// object
|
||||
/// * `identity` - Payload to be sent to Bob that contains the information necessary
|
||||
/// for the upper protocol to authenticate and approve of Alice's identity
|
||||
pub fn open<App: ApplicationLayer>(
|
||||
pub fn open<App: ApplicationLayer<C>>(
|
||||
&mut self,
|
||||
app: App,
|
||||
send: impl FnMut(Vec<u8>) -> bool,
|
||||
mut mtu: usize,
|
||||
static_remote_key: Crypto::PublicKey,
|
||||
session_data: Crypto::SessionData,
|
||||
static_remote_key: C::PublicKey,
|
||||
session_data: C::SessionData,
|
||||
identity: Vec<u8>,
|
||||
) -> Result<Arc<Session<Crypto>>, OpenError>
|
||||
where
|
||||
App: ApplicationLayer<Crypto = Crypto>,
|
||||
{
|
||||
) -> Result<Arc<Session<C>>, OpenError> {
|
||||
mtu = mtu.max(MIN_TRANSPORT_MTU);
|
||||
if identity.len() > IDENTITY_MAX_SIZE {
|
||||
return Err(OpenError::IdentityTooLarge);
|
||||
@@ -120,7 +117,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
identity,
|
||||
|Packet(kid, nonce, payload): &Packet| {
|
||||
// Process fragmentation layer.
|
||||
let _ = send_with_fragmentation::<Crypto>(send, mtu, *kid, to_packet_nonce(&nonce), payload, None);
|
||||
let _ = send_with_fragmentation::<C>(send, mtu, *kid, to_packet_nonce(nonce), payload, None);
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -133,18 +130,15 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
/// * `send_to` - Function to get senders for existing sessions, permitting MTU and path lookup
|
||||
/// * `remote_address` - Whatever the remote address is, as long as you can Hash it
|
||||
/// * `raw_fragment` - Buffer containing incoming wire packet
|
||||
pub fn receive<App, SendFn: FnMut(Vec<u8>) -> bool>(
|
||||
pub fn receive<App: ApplicationLayer<C>, SendFn: FnMut(Vec<u8>) -> bool>(
|
||||
&mut self,
|
||||
mut app: App,
|
||||
send_unassociated_reply: impl FnMut(Vec<u8>) -> bool,
|
||||
mut send_unassociated_mtu: usize,
|
||||
send_to: impl FnOnce(&Arc<Session<Crypto>>) -> Option<(SendFn, usize)>,
|
||||
send_to: impl FnOnce(&Arc<Session<C>>) -> Option<(SendFn, usize)>,
|
||||
remote_address: &impl Hash,
|
||||
raw_fragment: Vec<u8>,
|
||||
) -> Result<ReceiveOk<Crypto>, ReceiveError>
|
||||
where
|
||||
App: ApplicationLayer<Crypto = Crypto>,
|
||||
{
|
||||
) -> Result<ReceiveOk<C>, ReceiveError> {
|
||||
use crate::result::FaultType::*;
|
||||
send_unassociated_mtu = send_unassociated_mtu.max(MIN_TRANSPORT_MTU);
|
||||
let ctx = &self.0;
|
||||
@@ -158,7 +152,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
let mut zeta = session.0.borrow_mut();
|
||||
let result =
|
||||
zeta.defrag
|
||||
.received_fragment::<App>(raw_fragment, app.time(), |n, frag_no, frag_count| {
|
||||
.received_fragment::<C>(raw_fragment, app.time(), |n, frag_no, frag_count| {
|
||||
let (p, c) = from_nonce(n);
|
||||
if p != PACKET_TYPE_DATA {
|
||||
log!(app, ReceivedRawFragment(p, c, frag_no, frag_count));
|
||||
@@ -193,11 +187,11 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
|Packet(kid, nonce, payload): &Packet, hk: Option<&[u8; AES_256_KEY_SIZE]>| {
|
||||
if let Some((send_fragment, mut mtu)) = send_to(&session) {
|
||||
mtu = mtu.max(MIN_TRANSPORT_MTU);
|
||||
let _ = send_with_fragmentation::<Crypto>(
|
||||
let _ = send_with_fragmentation::<C>(
|
||||
send_fragment,
|
||||
mtu,
|
||||
*kid,
|
||||
to_packet_nonce(&nonce),
|
||||
to_packet_nonce(nonce),
|
||||
payload,
|
||||
hk,
|
||||
);
|
||||
@@ -207,7 +201,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
let (p, _) = from_nonce(&pn);
|
||||
let ret = match p {
|
||||
PACKET_TYPE_DATA => {
|
||||
received_payload_in_place::<App>(
|
||||
received_payload_in_place::<C>(
|
||||
&mut zeta,
|
||||
kid_recv,
|
||||
to_aes_nonce(&pn),
|
||||
@@ -221,7 +215,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
&mut zeta,
|
||||
&session,
|
||||
&mut app,
|
||||
&ctx,
|
||||
ctx,
|
||||
kid_recv,
|
||||
to_aes_nonce(&pn),
|
||||
assembled_packet,
|
||||
@@ -297,7 +291,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
}
|
||||
PACKET_TYPE_SESSION_REJECTED => {
|
||||
log!(app, ReceivedRawD);
|
||||
received_d_trans::<App>(&mut zeta, kid_recv, to_aes_nonce(&pn), assembled_packet)?;
|
||||
received_d_trans::<C>(&mut zeta, kid_recv, to_aes_nonce(&pn), assembled_packet)?;
|
||||
log!(app, DIsAuthClosedSession(&session));
|
||||
SessionEvent::Rejected
|
||||
}
|
||||
@@ -315,7 +309,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
// Process recv fragmentation layer.
|
||||
let result =
|
||||
zeta.defrag
|
||||
.received_fragment::<App>(raw_fragment, app.time(), |n, frag_no, frag_count| {
|
||||
.received_fragment::<C>(raw_fragment, app.time(), |n, frag_no, frag_count| {
|
||||
let (p, c) = from_nonce(n);
|
||||
log!(app, ReceivedRawFragment(p, c, frag_no, frag_count));
|
||||
if p == PACKET_TYPE_HANDSHAKE_COMPLETION && c == 0 {
|
||||
@@ -334,11 +328,11 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
kid_recv,
|
||||
assembled_packet,
|
||||
|Packet(kid, nonce, payload), hk| {
|
||||
let _ = send_with_fragmentation::<Crypto>(
|
||||
let _ = send_with_fragmentation::<C>(
|
||||
send_unassociated_reply,
|
||||
send_unassociated_mtu,
|
||||
*kid,
|
||||
to_packet_nonce(&nonce),
|
||||
to_packet_nonce(nonce),
|
||||
payload,
|
||||
hk,
|
||||
);
|
||||
@@ -362,7 +356,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
}
|
||||
} else {
|
||||
// Process recv fragmentation layer.
|
||||
let result = ctx.hello_defrag.borrow_mut().received_fragment::<App>(
|
||||
let result = ctx.hello_defrag.borrow_mut().received_fragment::<C>(
|
||||
raw_fragment,
|
||||
app.time(),
|
||||
|n, frag_no, frag_count| {
|
||||
@@ -381,7 +375,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
log!(app, ReceivedRawX1);
|
||||
// Process recv challenge layer.
|
||||
let challenge_start = assembled_packet.len() - CHALLENGE_SIZE;
|
||||
let result = ctx.challenge.borrow_mut().process_hello::<Crypto::Hash>(
|
||||
let result = ctx.challenge.borrow_mut().process_hello::<C::Hash>(
|
||||
remote_address,
|
||||
(&assembled_packet[challenge_start..]).try_into().unwrap(),
|
||||
);
|
||||
@@ -391,7 +385,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
challenge_packet.extend(&assembled_packet[..KID_SIZE]);
|
||||
challenge_packet.extend(&challenge);
|
||||
let nonce = to_nonce(PACKET_TYPE_CHALLENGE, ctx.rng.borrow_mut().next_u64());
|
||||
let _ = send_with_fragmentation::<Crypto>(
|
||||
let _ = send_with_fragmentation::<C>(
|
||||
send_unassociated_reply,
|
||||
send_unassociated_mtu,
|
||||
0,
|
||||
@@ -409,15 +403,15 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
// Process recv zeta layer.
|
||||
received_x1_trans(
|
||||
&mut app,
|
||||
&ctx,
|
||||
ctx,
|
||||
to_aes_nonce(&n),
|
||||
assembled_packet,
|
||||
|Packet(kid, nonce, payload), hk| {
|
||||
let _ = send_with_fragmentation::<Crypto>(
|
||||
let _ = send_with_fragmentation::<C>(
|
||||
send_unassociated_reply,
|
||||
send_unassociated_mtu,
|
||||
*kid,
|
||||
to_packet_nonce(&nonce),
|
||||
to_packet_nonce(nonce),
|
||||
payload,
|
||||
Some(hk),
|
||||
);
|
||||
@@ -436,7 +430,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
{
|
||||
if let Some(Some(session)) = ctx.session_map.borrow_mut().get(&kid_recv).map(|r| r.upgrade()) {
|
||||
let mut zeta = session.0.borrow_mut();
|
||||
respond_to_challenge::<App>(
|
||||
respond_to_challenge::<C>(
|
||||
&mut zeta,
|
||||
&ctx.rng,
|
||||
&assembled_packet[KID_SIZE..].try_into().unwrap(),
|
||||
@@ -466,7 +460,7 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
/// * `payload` - Data to send
|
||||
pub fn send(
|
||||
&mut self,
|
||||
session: &Arc<Session<Crypto>>,
|
||||
session: &Arc<Session<C>>,
|
||||
send: impl FnMut(Vec<u8>) -> bool,
|
||||
mut mtu: usize,
|
||||
payload: Vec<u8>,
|
||||
@@ -474,8 +468,8 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
debug_assert_eq!(session.0.borrow().ctx.as_ptr(), Arc::as_ptr(&self.0));
|
||||
mtu = mtu.max(MIN_TRANSPORT_MTU);
|
||||
let mut zeta = session.0.borrow_mut();
|
||||
send_payload::<Crypto>(&mut zeta, payload, |Packet(kid, nonce, payload), hk| {
|
||||
let result = send_with_fragmentation::<Crypto>(send, mtu, *kid, to_packet_nonce(nonce), &payload, hk);
|
||||
send_payload::<C>(&mut zeta, payload, |Packet(kid, nonce, payload), hk| {
|
||||
let result = send_with_fragmentation::<C>(send, mtu, *kid, to_packet_nonce(nonce), payload, hk);
|
||||
if matches!(result, Err(true)) {
|
||||
return Err(SendError::DataTooLarge);
|
||||
}
|
||||
@@ -490,14 +484,11 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
/// a problem. It is completely fine to call this function more often than the returned interval.
|
||||
///
|
||||
/// * `send_to` - Function to get a sender and an MTU to send something over an active session
|
||||
pub fn service<App, SendFn: FnMut(Vec<u8>) -> bool>(
|
||||
pub fn service<App: ApplicationLayer<C>, SendFn: FnMut(Vec<u8>) -> bool>(
|
||||
&mut self,
|
||||
mut app: App,
|
||||
mut send_to: impl FnMut(&Arc<Session<Crypto>>) -> Option<(SendFn, usize)>,
|
||||
) -> i64
|
||||
where
|
||||
App: ApplicationLayer<Crypto = Crypto>,
|
||||
{
|
||||
mut send_to: impl FnMut(&Arc<Session<C>>) -> Option<(SendFn, usize)>,
|
||||
) -> i64 {
|
||||
let ctx = &self.0;
|
||||
let sessions = ctx.sessions.borrow_mut();
|
||||
let current_time = app.time();
|
||||
@@ -514,11 +505,11 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
|Packet(kid, nonce, payload): &Packet, hk| {
|
||||
if let Some((send_fragment, mut mtu)) = send_to(&session) {
|
||||
mtu = mtu.max(MIN_TRANSPORT_MTU);
|
||||
let _ = send_with_fragmentation::<Crypto>(
|
||||
let _ = send_with_fragmentation::<C>(
|
||||
send_fragment,
|
||||
mtu,
|
||||
*kid,
|
||||
to_packet_nonce(&nonce),
|
||||
to_packet_nonce(nonce),
|
||||
payload,
|
||||
hk,
|
||||
);
|
||||
@@ -530,6 +521,6 @@ impl<Crypto: CryptoLayer> Context<Crypto> {
|
||||
}
|
||||
}
|
||||
ctx.hello_defrag.borrow_mut().service(current_time);
|
||||
(Crypto::SETTINGS.resend_time as i64).min(next_timer - current_time)
|
||||
(C::SETTINGS.resend_time as i64).min(next_timer - current_time)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ impl AesGcmAead for AesGcmCrate {
|
||||
buffer: &mut [u8],
|
||||
) -> [u8; AES_GCM_TAG_SIZE] {
|
||||
let key = Key::<Aes256Gcm>::from_slice(key);
|
||||
let mut cipher = Aes256Gcm::new(&key);
|
||||
let mut cipher = Aes256Gcm::new(key);
|
||||
cipher
|
||||
.encrypt_in_place_detached(&Nonce::from_slice(iv), aad.unwrap_or(&[]), buffer)
|
||||
.encrypt_in_place_detached(Nonce::from_slice(iv), aad.unwrap_or(&[]), buffer)
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
@@ -45,14 +45,9 @@ impl AesGcmAead for AesGcmCrate {
|
||||
tag: &[u8; AES_GCM_TAG_SIZE],
|
||||
) -> bool {
|
||||
let key = Key::<Aes256Gcm>::from_slice(key);
|
||||
let mut cipher = Aes256Gcm::new(&key);
|
||||
let mut cipher = Aes256Gcm::new(key);
|
||||
cipher
|
||||
.decrypt_in_place_detached(
|
||||
&Nonce::from_slice(iv),
|
||||
aad.unwrap_or(&[]),
|
||||
buffer,
|
||||
&Tag::from_slice(tag),
|
||||
)
|
||||
.decrypt_in_place_detached(Nonce::from_slice(iv), aad.unwrap_or(&[]), buffer, Tag::from_slice(tag))
|
||||
.is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user