mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-07-27 04:32:51 +02:00
Noise makes noise.
This commit is contained in:
parent
f3903144e4
commit
5250d5919e
1 changed files with 151 additions and 111 deletions
|
@ -128,6 +128,9 @@ pub enum Error {
|
||||||
|
|
||||||
/// Rekeying failed and session secret has reached its maximum usage count
|
/// Rekeying failed and session secret has reached its maximum usage count
|
||||||
MaxKeyLifetimeExceeded,
|
MaxKeyLifetimeExceeded,
|
||||||
|
|
||||||
|
/// Attempt to send using session without established key.
|
||||||
|
SessionNotEstablished,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Error {
|
impl std::fmt::Display for Error {
|
||||||
|
@ -140,6 +143,7 @@ impl std::fmt::Display for Error {
|
||||||
Self::NewSessionRejected => f.write_str("NewSessionRejected"),
|
Self::NewSessionRejected => f.write_str("NewSessionRejected"),
|
||||||
Self::Unexpected => f.write_str("OutOfSequence"),
|
Self::Unexpected => f.write_str("OutOfSequence"),
|
||||||
Self::MaxKeyLifetimeExceeded => f.write_str("MaxKeyLifetimeExceeded"),
|
Self::MaxKeyLifetimeExceeded => f.write_str("MaxKeyLifetimeExceeded"),
|
||||||
|
Self::SessionNotEstablished => f.write_str("SessionNotEstablished"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,7 +169,7 @@ impl Obfuscator {
|
||||||
|
|
||||||
pub enum ReceiveResult<'a, O> {
|
pub enum ReceiveResult<'a, O> {
|
||||||
/// Packet is valid and contained a data payload.
|
/// Packet is valid and contained a data payload.
|
||||||
OkData(&'a [u8]),
|
OkData(&'a [u8], u32),
|
||||||
|
|
||||||
/// Packet is valid and the provided reply should be sent back.
|
/// Packet is valid and the provided reply should be sent back.
|
||||||
OkSendReply(&'a [u8]),
|
OkSendReply(&'a [u8]),
|
||||||
|
@ -241,7 +245,7 @@ pub struct Session<O> {
|
||||||
remote_s_public_hash: [u8; 48],
|
remote_s_public_hash: [u8; 48],
|
||||||
psk: Secret<64>,
|
psk: Secret<64>,
|
||||||
ss: Secret<48>,
|
ss: Secret<48>,
|
||||||
pub(self) outgoing_obfuscator: Obfuscator,
|
outgoing_obfuscator: Obfuscator,
|
||||||
state: RwLock<State>,
|
state: RwLock<State>,
|
||||||
remote_s_public_p384: [u8; P384_PUBLIC_KEY_SIZE],
|
remote_s_public_p384: [u8; P384_PUBLIC_KEY_SIZE],
|
||||||
|
|
||||||
|
@ -287,6 +291,23 @@ impl<O> Session<O> {
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a data packet to the other side, returning packet to send.
|
||||||
|
pub fn send<'a, const MAX_PACKET_SIZE: usize>(&self, buffer: &'a mut [u8; MAX_PACKET_SIZE], data: &[u8]) -> Result<&'a [u8], Error> {
|
||||||
|
let state = self.state.read();
|
||||||
|
if let Some(key) = state.keys[0].as_ref() {
|
||||||
|
if let Some(remote_session_id) = state.remote_session_id {
|
||||||
|
let data_len = assemble_and_armor_DATA(buffer, data, PACKET_TYPE_DATA, u64::from(remote_session_id), self.send_counter.next(), &key, &self.outgoing_obfuscator)?;
|
||||||
|
Ok(&buffer[..data_len])
|
||||||
|
} else {
|
||||||
|
unlikely_branch();
|
||||||
|
Err(Error::SessionNotEstablished)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unlikely_branch();
|
||||||
|
Err(Error::SessionNotEstablished)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new session and return this plus an outgoing packet to send to the other end.
|
/// Create a new session and return this plus an outgoing packet to send to the other end.
|
||||||
|
@ -363,14 +384,17 @@ pub fn receive<
|
||||||
let local_session_id = SessionId::new_from_bytes(&buffer[4..10]);
|
let local_session_id = SessionId::new_from_bytes(&buffer[4..10]);
|
||||||
let packet_type = buffer[10];
|
let packet_type = buffer[10];
|
||||||
|
|
||||||
|
debug_assert_eq!(PACKET_TYPE_DATA, 0);
|
||||||
|
debug_assert_eq!(PACKET_TYPE_NOP, 1);
|
||||||
if packet_type <= PACKET_TYPE_NOP {
|
if packet_type <= PACKET_TYPE_NOP {
|
||||||
if let Some(local_session_id) = local_session_id {
|
if let Some(local_session_id) = local_session_id {
|
||||||
if let Some(session) = session_lookup(local_session_id) {
|
if let Some(session) = session_lookup(local_session_id) {
|
||||||
let state = session.state.read();
|
let state = session.state.read();
|
||||||
for ki in 0..2 {
|
for ki in 0..2 {
|
||||||
if let Some(key) = state.keys[ki].as_ref() {
|
if let Some(key) = state.keys[ki].as_ref() {
|
||||||
|
let nonce = get_aes_gcm_nonce(buffer);
|
||||||
let mut c = key.get_receive_cipher();
|
let mut c = key.get_receive_cipher();
|
||||||
c.init(&get_aes_gcm_nonce(buffer));
|
c.init(&nonce);
|
||||||
c.crypt_in_place(&mut buffer[HEADER_SIZE..16]);
|
c.crypt_in_place(&mut buffer[HEADER_SIZE..16]);
|
||||||
let data_len = incoming_packet.len() - AES_GCM_TAG_SIZE;
|
let data_len = incoming_packet.len() - AES_GCM_TAG_SIZE;
|
||||||
c.crypt(&incoming_packet[16..data_len], &mut buffer[16..data_len]);
|
c.crypt(&incoming_packet[16..data_len], &mut buffer[16..data_len]);
|
||||||
|
@ -387,7 +411,7 @@ pub fn receive<
|
||||||
}
|
}
|
||||||
|
|
||||||
if packet_type == PACKET_TYPE_DATA {
|
if packet_type == PACKET_TYPE_DATA {
|
||||||
return Ok(ReceiveResult::OkData(&buffer[HEADER_SIZE..data_len]));
|
return Ok(ReceiveResult::OkData(&buffer[HEADER_SIZE..data_len], u32::from_le_bytes(nonce[..4].try_into().unwrap())));
|
||||||
} else {
|
} else {
|
||||||
unlikely_branch();
|
unlikely_branch();
|
||||||
return Ok(ReceiveResult::Ok);
|
return Ok(ReceiveResult::Ok);
|
||||||
|
@ -824,7 +848,6 @@ impl SessionKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn assemble_and_armor_DATA<const MAX_PACKET_SIZE: usize>(buffer: &mut [u8; MAX_PACKET_SIZE], data: &[u8], packet_type: u8, remote_session_id: u64, counter: CounterValue, key: &SessionKey, outgoing_obfuscator: &Obfuscator) -> Result<usize, Error> {
|
fn assemble_and_armor_DATA<const MAX_PACKET_SIZE: usize>(buffer: &mut [u8; MAX_PACKET_SIZE], data: &[u8], packet_type: u8, remote_session_id: u64, counter: CounterValue, key: &SessionKey, outgoing_obfuscator: &Obfuscator) -> Result<usize, Error> {
|
||||||
buffer[0..4].copy_from_slice(&counter.to_bytes());
|
buffer[0..4].copy_from_slice(&counter.to_bytes());
|
||||||
|
@ -834,17 +857,21 @@ fn assemble_and_armor_DATA<const MAX_PACKET_SIZE: usize>(buffer: &mut [u8; MAX_P
|
||||||
|
|
||||||
let payload_end = HEADER_SIZE + data.len();
|
let payload_end = HEADER_SIZE + data.len();
|
||||||
let tag_end = payload_end + AES_GCM_TAG_SIZE;
|
let tag_end = payload_end + AES_GCM_TAG_SIZE;
|
||||||
|
if tag_end < MAX_PACKET_SIZE {
|
||||||
|
let mut c = key.get_send_cipher(counter)?;
|
||||||
|
buffer[11..16].fill(0);
|
||||||
|
c.init(&buffer[..16]);
|
||||||
|
c.crypt(data, &mut buffer[HEADER_SIZE..payload_end]);
|
||||||
|
buffer[payload_end..tag_end].copy_from_slice(&c.finish());
|
||||||
|
key.return_send_cipher(c);
|
||||||
|
|
||||||
let mut c = key.get_send_cipher(counter)?;
|
outgoing_obfuscator.0.encrypt_block_in_place(&mut buffer[..16]);
|
||||||
buffer[11..16].fill(0);
|
|
||||||
c.init(&buffer[..16]);
|
|
||||||
c.crypt(data, &mut buffer[HEADER_SIZE..payload_end]);
|
|
||||||
buffer[payload_end..tag_end].copy_from_slice(&c.finish());
|
|
||||||
key.return_send_cipher(c);
|
|
||||||
|
|
||||||
outgoing_obfuscator.0.encrypt_block_in_place(&mut buffer[..16]);
|
Ok(tag_end)
|
||||||
|
} else {
|
||||||
Ok(tag_end)
|
unlikely_branch();
|
||||||
|
Err(Error::InvalidParameter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn append_random_padding(b: &mut [u8]) -> &mut [u8] {
|
fn append_random_padding(b: &mut [u8]) -> &mut [u8] {
|
||||||
|
@ -1050,112 +1077,125 @@ mod tests {
|
||||||
// Session FROM Alice, on Bob's side.
|
// Session FROM Alice, on Bob's side.
|
||||||
let mut bob: Option<Rc<Session<u32>>> = None;
|
let mut bob: Option<Rc<Session<u32>>> = None;
|
||||||
|
|
||||||
while !from_alice.is_empty() || !from_bob.is_empty() {
|
for _ in 0..256 {
|
||||||
if let Some(packet) = from_alice.pop() {
|
while !from_alice.is_empty() || !from_bob.is_empty() {
|
||||||
let r = receive(
|
if let Some(packet) = from_alice.pop() {
|
||||||
packet.as_slice(),
|
let r = receive(
|
||||||
&mut b_buffer,
|
packet.as_slice(),
|
||||||
&bob_static_keypair,
|
&mut b_buffer,
|
||||||
&outgoing_obfuscator_to_bob,
|
&bob_static_keypair,
|
||||||
|p: &[u8; P384_PUBLIC_KEY_SIZE]| P384PublicKey::from_bytes(p),
|
&outgoing_obfuscator_to_bob,
|
||||||
|sid| {
|
|p: &[u8; P384_PUBLIC_KEY_SIZE]| P384PublicKey::from_bytes(p),
|
||||||
if let Some(bob) = bob.as_ref() {
|
|sid| {
|
||||||
if sid == bob.id {
|
println!("[noise] [bob] session ID: {}", u64::from(sid));
|
||||||
Some(bob.clone())
|
if let Some(bob) = bob.as_ref() {
|
||||||
|
if sid == bob.id {
|
||||||
|
Some(bob.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
} else {
|
},
|
||||||
None
|
|_: &[u8; P384_PUBLIC_KEY_SIZE]| {
|
||||||
}
|
if bob.is_none() {
|
||||||
},
|
Some((SessionId::new_random(), psk.clone(), 0))
|
||||||
|_: &[u8; P384_PUBLIC_KEY_SIZE]| {
|
} else {
|
||||||
if bob.is_none() {
|
panic!("[noise] [bob] Bob received a second new session request from Alice");
|
||||||
Some((SessionId::new_random(), psk.clone(), 0))
|
}
|
||||||
} else {
|
},
|
||||||
panic!("Bob received a second new session request from Alice");
|
0,
|
||||||
}
|
true,
|
||||||
},
|
);
|
||||||
0,
|
if let Ok(r) = r {
|
||||||
true,
|
match r {
|
||||||
);
|
ReceiveResult::OkData(data, counter) => {
|
||||||
if let Ok(r) = r {
|
println!("[noise] [bob] DATA len=={} counter=={}", data.len(), counter);
|
||||||
match r {
|
}
|
||||||
ReceiveResult::OkData(_) => {
|
ReceiveResult::OkSendReply(p) => {
|
||||||
println!("alice->bob DATA");
|
println!("[noise] [bob] OK (reply: {} bytes)", p.len());
|
||||||
}
|
from_bob.push(p.to_vec());
|
||||||
ReceiveResult::OkSendReply(p) => {
|
}
|
||||||
from_bob.push(p.to_vec());
|
ReceiveResult::OkNewSession(ns, p) => {
|
||||||
}
|
if bob.is_some() {
|
||||||
ReceiveResult::OkNewSession(ns, p) => {
|
panic!("[noise] [bob] attempt to create new session on Bob's side when he already has one");
|
||||||
if bob.is_some() {
|
}
|
||||||
panic!("attempt to create new session on Bob's side when he already has one");
|
let id: u64 = ns.id.into();
|
||||||
|
let _ = bob.replace(Rc::new(ns));
|
||||||
|
from_bob.push(p.to_vec());
|
||||||
|
println!("[noise] [bob] NEW SESSION {}", id);
|
||||||
|
}
|
||||||
|
ReceiveResult::Ok => {
|
||||||
|
println!("[noise] [bob] OK");
|
||||||
|
}
|
||||||
|
ReceiveResult::Duplicate => {
|
||||||
|
println!("[noise] [bob] duplicate packet");
|
||||||
|
}
|
||||||
|
ReceiveResult::Ignored => {
|
||||||
|
println!("[noise] [bob] ignored packet");
|
||||||
}
|
}
|
||||||
let _ = bob.replace(Rc::new(ns));
|
|
||||||
from_bob.push(p.to_vec());
|
|
||||||
println!("alice->bob NEW SESSION established!");
|
|
||||||
}
|
|
||||||
ReceiveResult::Ok => {
|
|
||||||
println!("alice->bob OK");
|
|
||||||
}
|
|
||||||
ReceiveResult::Duplicate => {
|
|
||||||
println!("alice->bob duplicate packet");
|
|
||||||
}
|
|
||||||
ReceiveResult::Ignored => {
|
|
||||||
println!("alice->bob ignored packet");
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
println!("ERROR (bob): {}", r.err().unwrap().to_string());
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(packet) = from_bob.pop() {
|
||||||
|
let r = receive(
|
||||||
|
packet.as_slice(),
|
||||||
|
&mut b_buffer,
|
||||||
|
&alice_static_keypair,
|
||||||
|
&outgoing_obfuscator_to_alice,
|
||||||
|
|p: &[u8; P384_PUBLIC_KEY_SIZE]| P384PublicKey::from_bytes(p),
|
||||||
|
|sid| {
|
||||||
|
println!("[noise] [alice] session ID: {}", u64::from(sid));
|
||||||
|
if sid == alice.id {
|
||||||
|
Some(alice.clone())
|
||||||
|
} else {
|
||||||
|
panic!("[noise] [alice] received from Bob addressed to unknown session ID, not Alice");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|_: &[u8; P384_PUBLIC_KEY_SIZE]| {
|
||||||
|
panic!("[noise] [alice] Alice received an unexpected new session request from Bob");
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
if let Ok(r) = r {
|
||||||
|
match r {
|
||||||
|
ReceiveResult::OkData(data, counter) => {
|
||||||
|
println!("[noise] [alice] DATA len=={} counter=={}", data.len(), counter);
|
||||||
|
}
|
||||||
|
ReceiveResult::OkSendReply(p) => {
|
||||||
|
println!("[noise] [alice] OK (reply: {} bytes)", p.len());
|
||||||
|
from_alice.push(p.to_vec());
|
||||||
|
}
|
||||||
|
ReceiveResult::OkNewSession(_, _) => {
|
||||||
|
panic!("[noise] [alice] attempt to create new session on Alice's side; Bob should not initiate");
|
||||||
|
}
|
||||||
|
ReceiveResult::Ok => {
|
||||||
|
println!("[noise] [alice] OK");
|
||||||
|
}
|
||||||
|
ReceiveResult::Duplicate => {
|
||||||
|
println!("[noise] [alice] duplicate packet");
|
||||||
|
}
|
||||||
|
ReceiveResult::Ignored => {
|
||||||
|
println!("[noise] [alice] ignored packet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("ERROR (alice): {}", r.err().unwrap().to_string());
|
||||||
|
panic!();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
println!("ERROR (alice->bob): {}", r.err().unwrap().to_string());
|
|
||||||
panic!();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(packet) = from_bob.pop() {
|
if (random::next_u32_secure() & 1) == 0 {
|
||||||
let r = receive(
|
from_alice.push(alice.send(&mut a_buffer, &[0_u8; 16]).unwrap().to_vec());
|
||||||
packet.as_slice(),
|
} else if bob.is_some() {
|
||||||
&mut b_buffer,
|
from_bob.push(bob.as_ref().unwrap().send(&mut b_buffer, &[0_u8; 16]).unwrap().to_vec());
|
||||||
&alice_static_keypair,
|
|
||||||
&outgoing_obfuscator_to_alice,
|
|
||||||
|p: &[u8; P384_PUBLIC_KEY_SIZE]| P384PublicKey::from_bytes(p),
|
|
||||||
|sid| {
|
|
||||||
if sid == alice.id {
|
|
||||||
Some(alice.clone())
|
|
||||||
} else {
|
|
||||||
panic!("received from Bob addressed to unknown session ID, not Alice");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|_: &[u8; P384_PUBLIC_KEY_SIZE]| {
|
|
||||||
panic!("Alice received an unexpected new session request from Bob");
|
|
||||||
},
|
|
||||||
0,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
if let Ok(r) = r {
|
|
||||||
match r {
|
|
||||||
ReceiveResult::OkData(_) => {
|
|
||||||
println!("bob->alice DATA");
|
|
||||||
}
|
|
||||||
ReceiveResult::OkSendReply(p) => {
|
|
||||||
from_alice.push(p.to_vec());
|
|
||||||
}
|
|
||||||
ReceiveResult::OkNewSession(_, _) => {
|
|
||||||
panic!("attempt to create new session on Alice's side; Bob should not initiate");
|
|
||||||
}
|
|
||||||
ReceiveResult::Ok => {
|
|
||||||
println!("bob->alice OK");
|
|
||||||
}
|
|
||||||
ReceiveResult::Duplicate => {
|
|
||||||
println!("bob->alice duplicate packet");
|
|
||||||
}
|
|
||||||
ReceiveResult::Ignored => {
|
|
||||||
println!("bob->alice ignored packet");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("ERROR (bob->alice): {}", r.err().unwrap().to_string());
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue