From ca252cae74434bb72050988ac22b5594dbfc2c07 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 11 Jan 2022 14:03:09 -0500 Subject: [PATCH] Build fixes, more testing for identity. --- allthethings/src/config.rs | 2 +- allthethings/src/link.rs | 4 +- allthethings/src/protocol.rs | 18 +- .../src/util/buffer.rs | 39 +-- zerotier-network-hypervisor/src/util/pool.rs | 1 - .../src/vl1/endpoint.rs | 232 ++++++------------ .../src/vl1/identity.rs | 129 +++++++--- zerotier-network-hypervisor/src/vl1/path.rs | 6 +- .../src/vl1/protocol.rs | 2 +- 9 files changed, 206 insertions(+), 227 deletions(-) diff --git a/allthethings/src/config.rs b/allthethings/src/config.rs index ee833352c..bb7ae73bf 100644 --- a/allthethings/src/config.rs +++ b/allthethings/src/config.rs @@ -27,7 +27,7 @@ pub struct Config { impl Default for Config { fn default() -> Self { Self { - max_message_size: 1024 * 1024, // 1MiB + max_message_size: 1024 * 256, // 256KiB tcp_port: 19993, io_timeout: 300, // 5 minutes domain: String::new(), diff --git a/allthethings/src/link.rs b/allthethings/src/link.rs index 7c052b6bf..023f37161 100644 --- a/allthethings/src/link.rs +++ b/allthethings/src/link.rs @@ -245,7 +245,7 @@ impl<'e, S: Store + 'static> Link<'e, S> { MESSAGE_TYPE_OBJECTS => self.do_objects(message_buf).await?, MESSAGE_TYPE_HAVE_OBJECTS => self.do_have_objects(&mut tmp_buf, message_buf).await?, MESSAGE_TYPE_WANT_OBJECTS => self.do_want_objects(message_buf).await?, - MESSAGE_TYPE_SYNC_REQUEST => self.do_sync_request(decode_msgpack(message_buf)?).await?, + MESSAGE_TYPE_STATE => self.do_sync_request(decode_msgpack(message_buf)?).await?, MESSAGE_TYPE_IBLT_SYNC_DIGEST => self.do_iblt_sync_digest(decode_msgpack(message_buf)?).await?, _ => {}, } @@ -336,7 +336,7 @@ impl<'e, S: Store + 'static> Link<'e, S> { } } - async fn do_sync_request(&self, sr: SyncRequest<'_>) -> smol::io::Result<()> { + async fn do_sync_request(&self, sr: State<'_>) -> smol::io::Result<()> { Ok(()) } diff --git a/allthethings/src/protocol.rs b/allthethings/src/protocol.rs index 2b4ed5fac..dfc718ad9 100644 --- a/allthethings/src/protocol.rs +++ b/allthethings/src/protocol.rs @@ -63,8 +63,8 @@ pub const MESSAGE_TYPE_HAVE_OBJECTS: u8 = 3; /// A series of identity hashes concatenated together of objects being requested. pub const MESSAGE_TYPE_WANT_OBJECTS: u8 = 4; -/// Request IBLT synchronization, payload is IBLTSyncRequest. -pub const MESSAGE_TYPE_SYNC_REQUEST: u8 = 5; +/// Report state, requesting possible sync response. +pub const MESSAGE_TYPE_STATE: u8 = 5; /// IBLT sync digest, payload is IBLTSyncDigest. pub const MESSAGE_TYPE_IBLT_SYNC_DIGEST: u8 = 6; @@ -93,13 +93,13 @@ pub struct Hello<'a> { /// Sent in response to Hello and contains an acknowledgement HMAC for the shared key. #[derive(Deserialize, Serialize)] pub struct HelloAck<'a> { - /// HMAC-SHA384(KBKDF(key, KBKDF_LABEL_HELLO_ACK_HMAC), SHA384(original raw Hello)) + /// HMAC-SHA384(KBKDF(ack key, KBKDF_LABEL_HELLO_ACK_HMAC), SHA384(original raw Hello)) pub ack: &'a [u8], /// Value of clock in original hello, for measuring latency. pub clock_echo: u64, } -/// Request an IBLT set digest to assist with synchronization. +/// Report the state of the sender's data set. /// /// The peer may respond in one of three ways: /// @@ -121,14 +121,8 @@ pub struct HelloAck<'a> { /// simple calculation to be made with the sending node's total count to /// estimate set difference density across the entire hash range. #[derive(Deserialize, Serialize)] -pub struct SyncRequest<'a> { - /// Start of range. Right-pad with zeroes if too short. - pub range_start: &'a [u8], - /// End of range. Right-pad with zeroes if too short. - pub range_end: &'a [u8], - /// Total number of hashes in range. - pub count: u64, - /// Total number of hashes in entire data set. +pub struct State<'a> { + /// Total number of hashes in the entire data set. pub total_count: u64, /// Our clock to use as a reference time for filtering the data set (if applicable). pub reference_time: u64, diff --git a/zerotier-network-hypervisor/src/util/buffer.rs b/zerotier-network-hypervisor/src/util/buffer.rs index 4a3f1177f..724b33734 100644 --- a/zerotier-network-hypervisor/src/util/buffer.rs +++ b/zerotier-network-hypervisor/src/util/buffer.rs @@ -220,14 +220,14 @@ impl Buffer { let end = ptr + 2; if end <= L { self.0 = end; - unsafe { *self.1.as_mut_ptr().add(ptr).cast::() = i }; + unsafe { *self.1.as_mut_ptr().add(ptr).cast::() = i.to_be() }; Ok(()) } else { Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG)) } } - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))] + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64")))] #[inline(always)] pub fn append_u16(&mut self, i: u16) -> std::io::Result<()> { let ptr = self.0; @@ -241,21 +241,21 @@ impl Buffer { } } - #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))] + #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64"))] #[inline(always)] pub fn append_u32(&mut self, i: u32) -> std::io::Result<()> { let ptr = self.0; let end = ptr + 4; if end <= L { self.0 = end; - unsafe { *self.1.as_mut_ptr().add(ptr).cast::() = i }; + unsafe { *self.1.as_mut_ptr().add(ptr).cast::() = i.to_be() }; Ok(()) } else { Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG)) } } - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))] + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64")))] #[inline(always)] pub fn append_u32(&mut self, i: u32) -> std::io::Result<()> { let ptr = self.0; @@ -269,21 +269,21 @@ impl Buffer { } } - #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))] + #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64"))] #[inline(always)] pub fn append_u64(&mut self, i: u64) -> std::io::Result<()> { let ptr = self.0; let end = ptr + 8; if end <= L { self.0 = end; - unsafe { *self.1.as_mut_ptr().add(ptr).cast::() = i }; + unsafe { *self.1.as_mut_ptr().add(ptr).cast::() = i.to_be() }; Ok(()) } else { Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG)) } } - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))] + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64")))] #[inline(always)] pub fn append_u64(&mut self, i: u64) -> std::io::Result<()> { let ptr = self.0; @@ -409,13 +409,13 @@ impl Buffer { debug_assert!(end <= L); if end <= self.0 { *cursor = end; - Ok((unsafe { *self.1.as_ptr().add(ptr).cast::() }).to_be()) + Ok(u16::from_be(unsafe { *self.1.as_ptr().add(ptr).cast::() })) } else { Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG)) } } - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))] + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64")))] #[inline(always)] pub fn read_u16(&self, cursor: &mut usize) -> std::io::Result { let ptr = *cursor; @@ -429,7 +429,7 @@ impl Buffer { } } - #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))] + #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64"))] #[inline(always)] pub fn read_u32(&self, cursor: &mut usize) -> std::io::Result { let ptr = *cursor; @@ -437,13 +437,13 @@ impl Buffer { debug_assert!(end <= L); if end <= self.0 { *cursor = end; - Ok((unsafe { *self.1.as_ptr().add(ptr).cast::() }).to_be()) + Ok(u32::from_be(unsafe { *self.1.as_ptr().add(ptr).cast::() })) } else { Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG)) } } - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))] + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64")))] #[inline(always)] pub fn read_u32(&self, cursor: &mut usize) -> std::io::Result { let ptr = *cursor; @@ -457,7 +457,7 @@ impl Buffer { } } - #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64"))] + #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64"))] #[inline(always)] pub fn read_u64(&self, cursor: &mut usize) -> std::io::Result { let ptr = *cursor; @@ -465,13 +465,13 @@ impl Buffer { debug_assert!(end <= L); if end <= self.0 { *cursor = end; - Ok((unsafe { *self.1.as_ptr().add(ptr).cast::() }).to_be()) + Ok(u64::from_be(unsafe { *self.1.as_ptr().add(ptr).cast::() })) } else { Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, OVERFLOW_ERR_MSG)) } } - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))] + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64")))] #[inline(always)] pub fn read_u64(&self, cursor: &mut usize) -> std::io::Result { let ptr = *cursor; @@ -486,6 +486,13 @@ impl Buffer { } } +impl PartialEq for Buffer { + #[inline(always)] + fn eq(&self, other: &Self) -> bool { self.1[0..self.0].eq(&other.1[0..other.0]) } +} + +impl Eq for Buffer {} + impl Write for Buffer { #[inline(always)] fn write(&mut self, buf: &[u8]) -> std::io::Result { diff --git a/zerotier-network-hypervisor/src/util/pool.rs b/zerotier-network-hypervisor/src/util/pool.rs index 2b72dc284..8b75c7180 100644 --- a/zerotier-network-hypervisor/src/util/pool.rs +++ b/zerotier-network-hypervisor/src/util/pool.rs @@ -8,7 +8,6 @@ use std::ptr::NonNull; use std::sync::{Arc, Weak}; -use std::sync::atomic::{AtomicIsize, Ordering}; use parking_lot::Mutex; diff --git a/zerotier-network-hypervisor/src/vl1/endpoint.rs b/zerotier-network-hypervisor/src/vl1/endpoint.rs index 46b1ca4d3..2d2fe8176 100644 --- a/zerotier-network-hypervisor/src/vl1/endpoint.rs +++ b/zerotier-network-hypervisor/src/vl1/endpoint.rs @@ -8,41 +8,28 @@ use std::cmp::Ordering; use std::hash::{Hash, Hasher}; +use zerotier_core_crypto::hash::SHA384_HASH_SIZE; use crate::vl1::{Address, MAC}; use crate::vl1::inetaddress::InetAddress; use crate::util::buffer::Buffer; -const TYPE_NIL: u8 = 0; -const TYPE_ZEROTIER: u8 = 1; -const TYPE_ETHERNET: u8 = 2; -const TYPE_WIFIDIRECT: u8 = 3; -const TYPE_BLUETOOTH: u8 = 4; -const TYPE_IP: u8 = 5; -const TYPE_IPUDP: u8 = 6; -const TYPE_IPTCP: u8 = 7; -const TYPE_HTTP: u8 = 8; -const TYPE_WEBRTC: u8 = 9; - -#[derive(Clone, Copy, PartialEq, Eq)] -#[repr(u8)] -pub enum Type { - Nil = TYPE_NIL, - ZeroTier = TYPE_ZEROTIER, - Ethernet = TYPE_ETHERNET, - WifiDirect = TYPE_WIFIDIRECT, - Bluetooth = TYPE_BLUETOOTH, - Ip = TYPE_IP, - IpUdp = TYPE_IPUDP, - IpTcp = TYPE_IPTCP, - Http = TYPE_HTTP, - WebRTC = TYPE_WEBRTC, -} +pub const TYPE_NIL: u8 = 0; +pub const TYPE_ZEROTIER: u8 = 1; +pub const TYPE_ETHERNET: u8 = 2; +pub const TYPE_WIFIDIRECT: u8 = 3; +pub const TYPE_BLUETOOTH: u8 = 4; +pub const TYPE_IP: u8 = 5; +pub const TYPE_IPUDP: u8 = 6; +pub const TYPE_IPTCP: u8 = 7; +pub const TYPE_HTTP: u8 = 8; +pub const TYPE_WEBRTC: u8 = 9; +pub const TYPE_ZEROTIER_ENCAP: u8 = 10; #[derive(Clone, PartialEq, Eq)] pub enum Endpoint { Nil, - ZeroTier(Address), + ZeroTier(Address, [u8; SHA384_HASH_SIZE]), Ethernet(MAC), WifiDirect(MAC), Bluetooth(MAC), @@ -51,6 +38,7 @@ pub enum Endpoint { IpTcp(InetAddress), Http(String), WebRTC(Vec), + ZeroTierEncap(Address, [u8; SHA384_HASH_SIZE]), } impl Default for Endpoint { @@ -60,28 +48,28 @@ impl Default for Endpoint { impl Endpoint { #[inline(always)] - pub fn ep_type(&self) -> Type { + pub fn ip(&self) -> Option<(&InetAddress, u8)> { match self { - Endpoint::Nil => Type::Nil, - Endpoint::ZeroTier(_) => Type::ZeroTier, - Endpoint::Ethernet(_) => Type::Ethernet, - Endpoint::WifiDirect(_) => Type::WifiDirect, - Endpoint::Bluetooth(_) => Type::Bluetooth, - Endpoint::Ip(_) => Type::Ip, - Endpoint::IpUdp(_) => Type::IpUdp, - Endpoint::IpTcp(_) => Type::IpTcp, - Endpoint::Http(_) => Type::Http, - Endpoint::WebRTC(_) => Type::WebRTC, + Endpoint::Ip(ip) => Some((&ip, TYPE_IP)), + Endpoint::IpUdp(ip) => Some((&ip, TYPE_IPUDP)), + Endpoint::IpTcp(ip) => Some((&ip, TYPE_IPTCP)), + _ => None } } - #[inline(always)] - pub fn ip(&self) -> Option<(&InetAddress, Type)> { + pub fn type_id(&self) -> u8 { match self { - Endpoint::Ip(ip) => Some((&ip, Type::Ip)), - Endpoint::IpUdp(ip) => Some((&ip, Type::IpUdp)), - Endpoint::IpTcp(ip) => Some((&ip, Type::IpTcp)), - _ => None + Endpoint::Nil => TYPE_NIL, + Endpoint::ZeroTier(_, _) => TYPE_ZEROTIER, + Endpoint::Ethernet(_) => TYPE_ETHERNET, + Endpoint::WifiDirect(_) => TYPE_WIFIDIRECT, + Endpoint::Bluetooth(_) => TYPE_BLUETOOTH, + Endpoint::Ip(_) => TYPE_IP, + Endpoint::IpUdp(_) => TYPE_IPUDP, + Endpoint::IpTcp(_) => TYPE_IPTCP, + Endpoint::Http(_) => TYPE_HTTP, + Endpoint::WebRTC(_) => TYPE_WEBRTC, + Endpoint::ZeroTierEncap(_, _) => TYPE_ZEROTIER_ENCAP, } } @@ -90,9 +78,10 @@ impl Endpoint { Endpoint::Nil => { buf.append_u8(TYPE_NIL) } - Endpoint::ZeroTier(a) => { + Endpoint::ZeroTier(a, h) => { buf.append_u8(16 + TYPE_ZEROTIER)?; - buf.append_bytes_fixed(&a.to_bytes()) + buf.append_bytes_fixed(&a.to_bytes())?; + buf.append_bytes_fixed(h) } Endpoint::Ethernet(m) => { buf.append_u8(16 + TYPE_ETHERNET)?; @@ -134,6 +123,11 @@ impl Endpoint { buf.append_varint(b.len() as u64)?; buf.append_bytes(b) } + Endpoint::ZeroTierEncap(a, h) => { + buf.append_u8(16 + TYPE_ZEROTIER_ENCAP)?; + buf.append_bytes_fixed(&a.to_bytes())?; + buf.append_bytes_fixed(h) + } } } @@ -164,7 +158,8 @@ impl Endpoint { TYPE_ZEROTIER => { let zt = Address::unmarshal(buf, cursor)?; if zt.is_some() { - Ok(Endpoint::ZeroTier(zt.unwrap())) + let h = buf.read_bytes_fixed::(cursor)?; + Ok(Endpoint::ZeroTier(zt.unwrap(), h.clone())) } else { Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid ZeroTier address")) } @@ -177,6 +172,15 @@ impl Endpoint { TYPE_IPTCP => Ok(Endpoint::IpTcp(InetAddress::unmarshal(buf, cursor)?)), TYPE_HTTP => Ok(Endpoint::Http(String::from_utf8_lossy(buf.read_bytes(buf.read_varint(cursor)? as usize, cursor)?).to_string())), TYPE_WEBRTC => Ok(Endpoint::WebRTC(buf.read_bytes(buf.read_varint(cursor)? as usize, cursor)?.to_vec())), + TYPE_ZEROTIER_ENCAP => { + let zt = Address::unmarshal(buf, cursor)?; + if zt.is_some() { + let h = buf.read_bytes_fixed::(cursor)?; + Ok(Endpoint::ZeroTierEncap(zt.unwrap(), h.clone())) + } else { + Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid ZeroTier address")) + } + }, _ => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "unrecognized endpoint type in stream")) } } @@ -189,7 +193,7 @@ impl Hash for Endpoint { Endpoint::Nil => { state.write_u8(TYPE_NIL); } - Endpoint::ZeroTier(a) => { + Endpoint::ZeroTier(a, _) => { state.write_u8(TYPE_ZEROTIER); state.write_u64(a.to_u64()) } @@ -225,6 +229,29 @@ impl Hash for Endpoint { state.write_u8(TYPE_WEBRTC); offer.hash(state); } + Endpoint::ZeroTierEncap(a, _) => { + state.write_u8(TYPE_ZEROTIER_ENCAP); + state.write_u64(a.to_u64()) + } + } + } +} + +impl Ord for Endpoint { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + (Endpoint::Nil, Endpoint::Nil) => Ordering::Equal, + (Endpoint::ZeroTier(a, ah), Endpoint::ZeroTier(b, bh)) => a.cmp(b).then_with(|| ah.cmp(bh)), + (Endpoint::Ethernet(a), Endpoint::Ethernet(b)) => a.cmp(b), + (Endpoint::WifiDirect(a), Endpoint::WifiDirect(b)) => a.cmp(b), + (Endpoint::Bluetooth(a), Endpoint::Bluetooth(b)) => a.cmp(b), + (Endpoint::Ip(a), Endpoint::Ip(b)) => a.cmp(b), + (Endpoint::IpUdp(a), Endpoint::IpUdp(b)) => a.cmp(b), + (Endpoint::IpTcp(a), Endpoint::IpTcp(b)) => a.cmp(b), + (Endpoint::Http(a), Endpoint::Http(b)) => a.cmp(b), + (Endpoint::WebRTC(a), Endpoint::WebRTC(b)) => a.cmp(b), + (Endpoint::ZeroTierEncap(a, ah), Endpoint::ZeroTierEncap(b, bh)) => a.cmp(b).then_with(|| ah.cmp(bh)), + _ => self.type_id().cmp(&other.type_id()) } } } @@ -234,117 +261,11 @@ impl PartialOrd for Endpoint { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -// We manually implement Ord and PartialOrd to ensure that ordering is always the same, since I'm not -// sure if Rust's derivations for this are guaranteed to remain constant forever. Endpoint ordering -// is important in the reproducibility of digital signatures any time one is signing a vector of them. -impl Ord for Endpoint { - fn cmp(&self, other: &Self) -> Ordering { - match self { - Endpoint::Nil => { - match other { - Endpoint::Nil => Ordering::Equal, - _ => Ordering::Greater, - } - } - Endpoint::ZeroTier(a) => { - match other { - Endpoint::Nil => Ordering::Less, - Endpoint::ZeroTier(b) => a.cmp(b), - _ => Ordering::Greater, - } - } - Endpoint::Ethernet(a) => { - match other { - Endpoint::Nil => Ordering::Less, - Endpoint::ZeroTier(_) => Ordering::Less, - Endpoint::Ethernet(b) => a.cmp(b), - _ => Ordering::Greater, - } - } - Endpoint::WifiDirect(a) => { - match other { - Endpoint::Nil => Ordering::Less, - Endpoint::ZeroTier(_) => Ordering::Less, - Endpoint::Ethernet(_) => Ordering::Less, - Endpoint::WifiDirect(b) => a.cmp(b), - _ => Ordering::Greater, - } - } - Endpoint::Bluetooth(a) => { - match other { - Endpoint::Nil => Ordering::Less, - Endpoint::ZeroTier(_) => Ordering::Less, - Endpoint::Ethernet(_) => Ordering::Less, - Endpoint::WifiDirect(_) => Ordering::Less, - Endpoint::Bluetooth(b) => a.cmp(b), - _ => Ordering::Greater, - } - } - Endpoint::Ip(a) => { - match other { - Endpoint::Nil => Ordering::Less, - Endpoint::ZeroTier(_) => Ordering::Less, - Endpoint::Ethernet(_) => Ordering::Less, - Endpoint::WifiDirect(_) => Ordering::Less, - Endpoint::Bluetooth(_) => Ordering::Less, - Endpoint::Ip(b) => a.cmp(b), - _ => Ordering::Greater, - } - } - Endpoint::IpUdp(a) => { - match other { - Endpoint::Nil => Ordering::Less, - Endpoint::ZeroTier(_) => Ordering::Less, - Endpoint::Ethernet(_) => Ordering::Less, - Endpoint::WifiDirect(_) => Ordering::Less, - Endpoint::Bluetooth(_) => Ordering::Less, - Endpoint::Ip(_) => Ordering::Less, - Endpoint::IpUdp(b) => a.cmp(b), - _ => Ordering::Greater, - } - } - Endpoint::IpTcp(a) => { - match other { - Endpoint::Nil => Ordering::Less, - Endpoint::ZeroTier(_) => Ordering::Less, - Endpoint::Ethernet(_) => Ordering::Less, - Endpoint::WifiDirect(_) => Ordering::Less, - Endpoint::Bluetooth(_) => Ordering::Less, - Endpoint::Ip(_) => Ordering::Less, - Endpoint::IpUdp(_) => Ordering::Less, - Endpoint::IpTcp(b) => a.cmp(b), - _ => Ordering::Greater, - } - } - Endpoint::Http(a) => { - match other { - Endpoint::Nil => Ordering::Less, - Endpoint::ZeroTier(_) => Ordering::Less, - Endpoint::Ethernet(_) => Ordering::Less, - Endpoint::WifiDirect(_) => Ordering::Less, - Endpoint::Bluetooth(_) => Ordering::Less, - Endpoint::Ip(_) => Ordering::Less, - Endpoint::IpUdp(_) => Ordering::Less, - Endpoint::IpTcp(_) => Ordering::Less, - Endpoint::Http(b) => a.cmp(b), - _ => Ordering::Greater, - } - } - Endpoint::WebRTC(a) => { - match other { - Endpoint::WebRTC(b) => a.cmp(b), - _ => Ordering::Less, - } - } - } - } -} - impl ToString for Endpoint { fn to_string(&self) -> String { match self { Endpoint::Nil => format!("nil"), - Endpoint::ZeroTier(a) => format!("zt:{}", a.to_string()), + Endpoint::ZeroTier(a, ah) => format!("zt:{}-{}", a.to_string(), base64::encode_config(ah, base64::URL_SAFE_NO_PAD)), Endpoint::Ethernet(m) => format!("eth:{}", m.to_string()), Endpoint::WifiDirect(m) => format!("wifip2p:{}", m.to_string()), Endpoint::Bluetooth(m) => format!("bt:{}", m.to_string()), @@ -352,7 +273,8 @@ impl ToString for Endpoint { Endpoint::IpUdp(ip) => format!("udp:{}", ip.to_string()), Endpoint::IpTcp(ip) => format!("tcp:{}", ip.to_string()), Endpoint::Http(url) => url.clone(), - Endpoint::WebRTC(offer) => format!("webrtc:{}", base64::encode(offer.as_slice())), + Endpoint::WebRTC(offer) => format!("webrtc:{}", base64::encode_config(offer.as_slice(), base64::URL_SAFE_NO_PAD)), + Endpoint::ZeroTierEncap(a, ah) => format!("zte:{}-{}", a.to_string(), base64::encode_config(ah, base64::URL_SAFE_NO_PAD)), } } } diff --git a/zerotier-network-hypervisor/src/vl1/identity.rs b/zerotier-network-hypervisor/src/vl1/identity.rs index 3cf3b1708..d92b8582a 100644 --- a/zerotier-network-hypervisor/src/vl1/identity.rs +++ b/zerotier-network-hypervisor/src/vl1/identity.rs @@ -9,6 +9,7 @@ use std::alloc::{alloc, dealloc, Layout}; use std::cmp::Ordering; use std::convert::TryInto; +use std::hash::{Hash, Hasher}; use std::io::Write; use std::mem::MaybeUninit; use std::ops::Deref; @@ -64,6 +65,9 @@ pub const IDENTITY_CIPHER_SUITE_EC_NIST_P521: u8 = 0x03; /// Mask for functions that take a cipher mask to use all available ciphers or the best available cipher. pub const IDENTITY_CIPHER_SUITE_INCLUDE_ALL: u8 = 0xff; +/// Current sanity limit for the size of a marshaled Identity (can be increased if needed). +pub const MAX_MARSHAL_SIZE: usize = ADDRESS_SIZE + C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + C25519_SECRET_KEY_SIZE + ED25519_SECRET_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE + P521_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE + 16; + #[derive(Clone)] pub struct IdentityP521Secret { pub ecdh: P521KeyPair, @@ -150,13 +154,16 @@ impl Identity { let p521_ecdh_pub = p521_ecdh.public_key_bytes().clone(); let p521_ecdsa_pub = p521_ecdsa.public_key_bytes().clone(); - let mut self_sign_buf: Vec = Vec::with_capacity(ADDRESS_SIZE + 1 + C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + 1 + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE); + let mut self_sign_buf: Vec = Vec::with_capacity(ADDRESS_SIZE + 4 + C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE); let _ = self_sign_buf.write_all(&address.to_bytes()); - self_sign_buf.push(IDENTITY_CIPHER_SUITE_X25519 | IDENTITY_CIPHER_SUITE_EC_NIST_P521); + self_sign_buf.push(IDENTITY_CIPHER_SUITE_X25519); let _ = self_sign_buf.write_all(&c25519_pub); let _ = self_sign_buf.write_all(&ed25519_pub); + self_sign_buf.push(IDENTITY_CIPHER_SUITE_X25519); + self_sign_buf.push(IDENTITY_CIPHER_SUITE_EC_NIST_P521); let _ = self_sign_buf.write_all(&p521_ecdh_pub); let _ = self_sign_buf.write_all(&p521_ecdsa_pub); + self_sign_buf.push(IDENTITY_CIPHER_SUITE_EC_NIST_P521); Self { address, @@ -166,7 +173,7 @@ impl Identity { ecdh: p521_ecdh_pub, ecdsa: p521_ecdsa_pub, ecdsa_self_signature: p521_ecdsa.sign(self_sign_buf.as_slice()).expect("NIST P-521 signature failed in identity generation"), - ed25519_self_signature: ed25519.sign(self_sign_buf.as_slice()) + ed25519_self_signature: ed25519.sign(self_sign_buf.as_slice()), }), secret: Some(IdentitySecret { c25519, @@ -194,7 +201,7 @@ impl Identity { pub fn hash(&self) -> [u8; SHA384_HASH_SIZE] { let mut sha = SHA384::new(); sha.update(&self.address.to_bytes()); - // don't prefix x25519 with cipher suite 0 for backward compatibility + // don't prefix x25519 with cipher suite for backward compatibility sha.update(&self.c25519); sha.update(&self.ed25519); let _ = self.p521.as_ref().map(|p521| { @@ -202,6 +209,7 @@ impl Identity { sha.update(&p521.ecdh); sha.update(&p521.ecdsa); sha.update(&p521.ecdsa_self_signature); + sha.update(&[IDENTITY_CIPHER_SUITE_EC_NIST_P521]); }); sha.finish() } @@ -212,13 +220,16 @@ impl Identity { pub fn validate_identity(&self) -> bool { let pow_threshold = if self.p521.is_some() { let p521 = self.p521.as_ref().unwrap(); - let mut self_sign_buf: Vec = Vec::with_capacity(ADDRESS_SIZE + 1 + C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE); + let mut self_sign_buf: Vec = Vec::with_capacity(ADDRESS_SIZE + 4 + C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE); let _ = self_sign_buf.write_all(&self.address.to_bytes()); - self_sign_buf.push(IDENTITY_CIPHER_SUITE_X25519 | IDENTITY_CIPHER_SUITE_EC_NIST_P521); + self_sign_buf.push(IDENTITY_CIPHER_SUITE_X25519); let _ = self_sign_buf.write_all(&self.c25519); let _ = self_sign_buf.write_all(&self.ed25519); + self_sign_buf.push(IDENTITY_CIPHER_SUITE_X25519); + self_sign_buf.push(IDENTITY_CIPHER_SUITE_EC_NIST_P521); let _ = self_sign_buf.write_all(&p521.ecdh); let _ = self_sign_buf.write_all(&p521.ecdsa); + self_sign_buf.push(IDENTITY_CIPHER_SUITE_EC_NIST_P521); if !P521PublicKey::from_bytes(&p521.ecdsa).map_or(false, |ecdsa_pub| ecdsa_pub.verify(self_sign_buf.as_slice(), &p521.ecdsa_self_signature)) { return false; @@ -292,6 +303,13 @@ impl Identity { } } + #[inline(always)] + pub fn to_bytes(&self, include_cipher_suites: u8, include_private: bool) -> Buffer { + let mut b: Buffer = Buffer::new(); + self.marshal(&mut b, include_cipher_suites, include_private).expect("internal error marshaling Identity"); + b + } + pub fn marshal(&self, buf: &mut Buffer, include_cipher_suites: u8, include_private: bool) -> std::io::Result<()> { let cipher_suites = self.cipher_suites() & include_cipher_suites; let secret = self.secret.as_ref(); @@ -362,11 +380,11 @@ impl Identity { } else if sec_size != 0 { return std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid x25519 secret")); } - }, + } IDENTITY_CIPHER_SUITE_EC_NIST_P521 => { let size = buf.read_u16(cursor)?; if size < (P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE) as u16 { - return std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid p521 key")); + return std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid p521 public key")); } let a = buf.read_bytes_fixed::(cursor)?; let b = buf.read_bytes_fixed::(cursor)?; @@ -375,13 +393,13 @@ impl Identity { let _ = p521_ecdh_ecdsa_public.replace((a.clone(), b.clone(), c.clone(), d.clone())); if size > (P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE) as u16 { if size != (P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE + P521_SECRET_KEY_SIZE + P521_SECRET_KEY_SIZE) as u16 { - return std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid p521 key")); + return std::io::Result::Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid p521 secret key")); } let a = buf.read_bytes_fixed::(cursor)?; let b = buf.read_bytes_fixed::(cursor)?; let _ = p521_ecdh_ecdsa_secret.replace((a.clone(), b.clone())); } - }, + } _ => { // Skip any unrecognized cipher suites, all of which will be prefixed by a size. *cursor += buf.read_u16(cursor)? as usize; @@ -406,7 +424,7 @@ impl Identity { ecdh: p521_ecdh_ecdsa_public.0.clone(), ecdsa: p521_ecdh_ecdsa_public.1.clone(), ecdsa_self_signature: p521_ecdh_ecdsa_public.2.clone(), - ed25519_self_signature: p521_ecdh_ecdsa_public.3.clone() + ed25519_self_signature: p521_ecdh_ecdsa_public.3.clone(), }) } else { None @@ -431,15 +449,15 @@ impl Identity { } Some(IdentityP521Secret { ecdh: p521_ecdh_secret.unwrap(), - ecdsa: p521_ecdsa_secret.unwrap() + ecdsa: p521_ecdsa_secret.unwrap(), }) } else { None - } + }, }) } else { None - } + }, }) } @@ -506,12 +524,12 @@ impl FromStr for Identity { return Err(InvalidFormatError); } state = 1; - }, + } 1 | 2 => { let _ = keys[key_ptr].replace(fields[ptr]); key_ptr += 1; state = (state + 1) % 3; - }, + } _ => { return Err(InvalidFormatError); } @@ -584,26 +602,18 @@ impl FromStr for Identity { return Err(InvalidFormatError); } tmp.unwrap() - } + }, }) - } + }, }) - } + }, }) } } impl PartialEq for Identity { - fn eq(&self, other: &Self) -> bool { - self.address == other.address && - self.c25519 == other.c25519 && - self.ed25519 == other.ed25519 && - self.p521.as_ref().map_or(other.p521.is_none(), |p521| { - other.p521.as_ref().map_or(false, |other_p521| { - p521.ecdh == other_p521.ecdh && p521.ecdsa == other_p521.ecdsa - }) - }) - } + #[inline(always)] + fn eq(&self, other: &Self) -> bool { self.address == other.address && self.c25519 == other.c25519 } } impl Eq for Identity {} @@ -623,6 +633,11 @@ impl PartialOrd for Identity { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } +impl Hash for Identity { + #[inline(always)] + fn hash(&self, state: &mut H) { state.write_u64(self.address.to_u64()) } +} + const ADDRESS_DERIVATION_HASH_MEMORY_SIZE: usize = 2097152; /// This is a compound hasher used for the work function that derives an address. @@ -665,8 +680,6 @@ fn zt_address_derivation_memory_intensive_hash(digest: &mut [u8; 64], genmem_poo #[repr(transparent)] struct AddressDerivationMemory(*mut u8); -struct AddressDerivationMemoryFactory; - impl AddressDerivationMemory { #[inline(always)] fn get_memory(&mut self) -> *mut u8 { self.0 } @@ -677,6 +690,8 @@ impl Drop for AddressDerivationMemory { fn drop(&mut self) { unsafe { dealloc(self.0, Layout::from_size_align(ADDRESS_DERIVATION_HASH_MEMORY_SIZE, 8).unwrap()) }; } } +struct AddressDerivationMemoryFactory; + impl PoolFactory for AddressDerivationMemoryFactory { #[inline(always)] fn create(&self) -> AddressDerivationMemory { AddressDerivationMemory(unsafe { alloc(Layout::from_size_align(ADDRESS_DERIVATION_HASH_MEMORY_SIZE, 8).unwrap()) }) } @@ -699,22 +714,62 @@ pub(crate) fn purge_verification_memory_pool() { #[cfg(test)] mod tests { + use std::str::FromStr; + use std::time::{Duration, SystemTime}; use crate::vl1::Identity; + use crate::vl1::identity::IDENTITY_CIPHER_SUITE_INCLUDE_ALL; + + const GOOD_V1_IDENTITIES: [&'static str; 10] = [ + "f0beef83d5:0:c770a89f8b4c389bbbfbb15f3efa38be12aed830500b12c6b14d235ce4cd976477706b78cc649eae282e590c2bff0a00c2bcd48c6a2e11f75bd447e5c460e6c1:200152c9bc35d6ce4984e67a508cb255a984a47f377747a12465a7f18759904a84e5ef259eb8aa1988e1e3e40317c4ec72445d2c8731f12c3c0f71025beb28e5:1:AHFabiyRt7hZM3UHLQPR3ZnqUDwIsbYINPegBuwazzH6ARy8ajtaDNg8bZn6Y2TEKb7ov1DiedkLEkLwpEnbfqwfAE0BiJebWrTDqcZMGjY0OGbDIeT0U0ZH4cmxWGbn-DRjNuiVqltMxwAQCjahhIXkhLueYj3YOHvKPXBykm4m_5sGAKQog2m-4N7WHpO3dIi0HFbPkaibsSGYk4_ZE7Z4R_j8mxHeQhqnm97krXWMJec6MSzXIXnfQ9-aVSaRSa0ZXBCcALVbWN-N3vMMiEHK0I2DUP1UAFec9FUjxsqEAXGGLJ0dtVTO8dO-fTpi5REsblxdapjiNbMUmwNYuK8iBkV_kYnbAP2Zv5ndxZlXhr5wPsKudP_LGpuGS1BltS8gZDELq8zhOa7U7L3qvFiK68OJWZGgrZZrYjO-tU1UU18qxtgT_VZBAQWNnr6nWVq7eIL4kvASAgttNNe0_9Qb6iOvzEvvXobf0ZgsWUy4NRyFlHKIYH6dOWMZdMekMKAgGSZmLn07RhYKUCe6JqfjI-UQR49tr-JB-H_t1OKYO2wFiKixpdZKh33erUvkxBcVfHOwvJmlykedkQNiCQpHcWInCSzkV19VCw:AF6BKY6fEVmNyg4UxSuUPnG5p011f3-vGF2V3SZjNg6qAI2GIzk-d_DNpeUjAz9u2NQX4gCKb9Xgr1JePQwaSvmCAPiBW5GX3JwJXbYu025q36yFA1e93DEMGnITHjbzIc7jiDk_pZ7n5B_LDUjjqpHQcokl9b5qjr3d0riF-9PQ8-8k", + "26d8a4c162:0:666dcd76f39de286f7d816af1feeb54ba327874472cfcd88d717e0e551048a78d342a06aee4c6766bd41c54a5bf7b44153aaa4329846988f807146459cd62d6c:90461e88fec66b82b00745840f1f304bee25d442ebf93b21033a3000219f6f6bfd5604557ca27a9bcc6f7f5c10db15262d7145a1884adfce32eae4c5cb77d1c4:1:AdHlp0cmj4KRWQN3oOM6AQjLJSv3_KSXSOftv0TVIUrdtFmAPGf6Duecb9Vtu5WaWOwoN-3WY_YmDES-sfJveioBAJhZhuyqS-wj-pQ0ppQ5u_HP9eAtuDtUIrrtF6wDGNrNsNc9F9SATZho6jVEan7ccjZFeLBd-HOmErj_LfVC66ptAWmAn18CHjNxPUcn-E9D2nVpIN34mM_mHyc2uMLm80aRjqndFll8MPKkYZGz1TPEUjJUfwNT9SdecbBSvqK7gPdzAKY8kohNau9j27vMaUGcf-TTkfHBSmOmoz-X-C_GSGwD7KIyyVQe1xMfKQjdjqPRlK94AWAuX3L5Gb_ywdGjR6_SACDCdVisQFP0HzSWkHVPxbY5Ab1yJme73hlbpm64vK5htiSmdC5JxXGSiQuAIdjWMH_pfL4LgFCmZQjTWLEX0-n_AAjk9A3DjZDkQeBn8gP9z2xlpPKzOAOlqFoVlxSlyRc7Sra--go947886vBN3dpcm8fhTuO4HtlnPdiKdk1NsvyzuvZ4XIvTa6pGV4zhYZRIpn7rn9yDVOLYskEx2I6SxHrovuG--_Yn5pERP4jdA6oGMKR3ZSIROTCTyUuCkQMXBw:AK-hGoppimiEx-4-9up25uWcnSeD4lIl8VL_ufIJGv41NsLFgJkRQ7EQ-4zd_NrB_E42ju24ZKIR-eJOn-eOKTUzAJmuBUCsMXzCzgTPwbW3OBRhCHjDbaz27JDV4HWVRM_bbhQLF6rzJTBioDex-E74HOTIDKS87vTCZ2qujRjhw07V", + "7e94a163bd:0:72a1fa41c906c7c111798b2f062a695316a41e9e8043ca14c1f7878f20f0ba170d0a2c8442a6eddbe4ba6c29847d8460a2754ca6c5c465cf756619749fd18460:989c4bb4719bc7cc4d1f59810a6a64746d04b3a46d894844c1bfe01d359e086a7cd0f5aafc1936bc4475937b14f02ccf25ca78b77c65d0b34be0aa8bc138f45a:1:ATvs4irZ_1FjoYJojInI5DPuqDMrk8Ost4r41QaqSiTgCONEHRiNtSoQJXgcsfhsbz5AWaG5S0H1Q0irHHF2paAYABBQ8C8DJLG_IQWnZYYH2OOdcMVdA1llQRr1odUDJdwv862fO0dUzMct1qmB7RZiiZW_DyIhmv5ZPayeeyQ0NBDeAEeCvA_J0hvBSDeBPxUr5meAzVizAArotFO58JwvqKjfXin99heJFXnBemlJx1Ec-v3WGcbRN6ikLZYw6uetXS0HAOt3hJlu1-MQXXpUMSQ2fNeE6HrM_bH-JDmFu5jTzpls2end1u6fKtVPW2TCs1pHc8nC6Km3J6Kb60_rqgtESVo4AazOlfiwaC40t-kEDXPbNTxOfAHgm9NimCkEmh4FwTYXTv7hD7koTU5ZtFVBCospRcW5A2Q39keKDawM67isFMnrAcd4CEx5FLvNmJ9aoItyeBzjcP6Nn8RWmEFYObMqNlEH1d2KSGFYYFKp8fWi4zNnEe41H5qQ5xj-fFEiP9bod1g0sV8Vbyo3uj7VoCeabZ96KQwAhWFe-TEdc393Aha65sjoXNEuOeCq7XMtfIrQ2rmMBcMhymy_K89WN1E_iuNRAQ:AcjIXa4COvSKkaU517m3eKzAvmEjTHMWcLN-6gFY9h2-1nNJO6bazeq5jyWqdifOsllksAyKlp4lgFmuvb5oUTdAAFTfsfMwo8eH9K6zvzgbuyxud4ldX3wlZv18brdJW7C05QNM3qYNPWTB1bCwbEBbBmtNR4Qdfe7YDJAqDiSo9t6i", + "8d7f396a1e:0:5486bc9a8c092fbbc4c447d44ab7e07419ea926cd606af45c3333dc65956261dba09d1160975c4f3a536664c00cfca3a54219a47254831e084b7edbf3251295a:7006dd1e43e7bc362ddd00f6f495dac4c5655f7e2c27abf133b3e9995b78605b1f8dcceaf8a3b3c98fff103f3d7a0a4af35ee59b34be229f434928523d39d879:1:AXUfrrngWX0AKkrDljhBpAGzYnCgap1Y3mnS-BccP5ipIUx6PWDxCZIZQ_H0PTCWP4sysDjZA7KcgmmOlrKVr9hRAJgWy1ljt-Vr-ybYm65xG70jV4dR_q_y8u5fYH9g6_FhFKn-ef8npze5SNKfDbroi_1RtIG8IIqACBTEMm5r8pfsAJ_U9SlPxpDlg6R8VO7sKt8kGwQtVytXsXuZ-Kxvnb_8crYAg5ObaJYVlJlsRvHbpwk6f5FRp_KoNMAE5LNIdvMrAKoTSLa_H37Tb42JraVpRRvj2D04NsNrp9AOus9mDMfrn9XZXX677sbCfN507KdWEQnYd24njnCSGIktEf4bhOmQALXUiArWmEm6g08skjyKs6_ukmsxnZHMaWih6FCkoU04oc2qSOmSC_LsnDjBhqQ7qo6_EkJnX5roiVGv2BjWZSfkAFPRxdxqNVJyNVXoCl-ZJlBXePipjH1Rk3yVuX2WfAMXQ2MoL8eP7vnfHUpBrzJmfImOqYgLZx2dstj-f_X6m1UZ4N9E4xYvyqo3vyzdFDI_YSFJZOZNk4Vz9CBE-WxOGPOklHgCNU2xcewysAw-jTHiHQ-lhoXWfxIBiMwE06nnCw:AYjHjcdewyL08Q3ddXFzdhrTijiAQYnbkbL5oC87GKkZ1S62p5Ny-UrHnOt37F0k65aDOwtvldGVvU8VHVDZAti5AIfl7mNhf6b4MF1LoROulO2j-Ygoc5ixbTuEQaJGSD-NumLvdbZbv2Ik0pJUc61izpwCxVHoYOkUlc167eD1G2li", + "9eb06e21bb:0:76a7f820f7af06d10a42bd7369b9e4cc96318e535909eb9840d064b1a21cf967826a3da6c0950d5ad68e095af6d2dd648fbef052b13e7876926cde591f5007c4:202df0941105495c8e482e2ebc5551c6fd23f668b387bc0bdcaa8ddc6ad03f5c2871a4263b5ba5bf3ed1cea348fdb88f706f3f2a628926a22828f7209b5fc7c1:1:AcUH-dmXHK75fjCV32witg1HZSj4M27N6w4BF9hnWXY8lSYdgbeN3AuMGnYqQcqu7vPoqrpT2AkIJ-gJI7fGe9jOAO9CcyfSieBeDgaFDW9oAmtJGNRdL-E32-K8kqlmyhkt-r0In-eOYuBWAe0hcQR0pXbTaAvBUB-WNa2Hab2JKVnTAThDvqzCmV57BecsfTtP-TS-Kz3BqZuQfIF0o5EOqDdP0Jib8G8TM7huXO6qrd2JZLGQzZ0uAF2ex6hmdD_obZJfAIpuhUgrgvVB9LFApQWE7Ys5aJXMrYYEtXAuqutGS9NV8yLsshD6uV0OzwqU8R2L-KPNsrOBccwj6E1Cyy7v22XMAPhMWA4oUlwZXuWWVPzYPq8lh-YxPlOFq583AZa2LZC0NUL0jkmzEQwvylctTVjhgaybqtRasM5PRyoRQWg5xAyKALASLfqRw5f1tJksf1JR7bz-WZH_Pngot8YOQLGjdjFxYwZD0CTXoV3v9Muc8bNEByiVTk_MXgeghi4ZWuV5N3jcy58eIbgS_GK_HNFRDDDS5_DtxFoQRxI5vL__wtej5Xl2Iqh0-4rmuUxbAP8fv_fhq9SFK3zoul-uy2cseQbeBw:AUwxKKt2MFKRzzWWwqMOcXBj23hUFZGjoO25vnMsEWTb8RT04oQc3ChRc13WrEGIPUOHuRXoRxSYVbfW7WIFhj1uAJY5zDiN9blmxKHmTj0UB84QMYlFnjok-AT3r8FB8Pj09HTborzJQqwgOtZ54G-UZ-Cn5RYzyWMQnERxQLiC525G", + "6362ad160b:0:9ea5ae5ecf18e8048e3f425845b12e462f3c6111e6078e97e17c56592cbc5d65e7ac6b2906739f8d6632e2a4323763ca4f33d7357efbbca0a6a7cec783067154:9078565f47bcfc7e4487f70b6c57e30e2863ce737a7997ae4f7a0f3a28e62971b1d42c4b0a7bf8008a18efd820fe40d5083809fbd5c1f63c83efb432b2c469b3:1:ACSRqDRinlje3ob1z2Uied0SyhSJ72KgGWaczFtk5pgR8lFA3OwIQT2UeqVVEwNuFyizM0vVA6eARJtM0fYY4OtlADMuUgs20w-nSHyPpWaYiZpGzIJT1QloiiuMnLaPA4XFPRQ8kNq3zBwVQHCsCTgAp92Y16_Yjkc4wCF4DZkFB_ROAObyJ-tzrC4VdNQKrbPFmTinyyhx0vroRBinX71KTHCL1MvNZK4ubSmgf0MSqjs-DLUo-dBjUvTC6u2F3P-6j60OAACKc3Vf6hVVlaivjeINVY-9W1rv2YfeIVF_EZQooDnZr8ZEn-T0DUq17apsacppvAQ5zLc1WtKYRhYI1ZRhUNI7AUtVCOdph5oHlmlP1a9xLWAiahTzb2Jo55KJ5kaF7DyRkcZCV3Kv6IUNZP4sZ6KO7_g7jLTq5kw57utzA7ntcBu4APl3hahoPWXqxTlbzwaKVb5a4yDV_enbeP04NvoEbR2M6F67olmrO_1-WJP3IpNP9-jYvw6l25qzdMhuiRBfoWD-amN1m9CptAta1zHhNKD4Q24M9_0sxA5brph76tIZEISHIMT7wzWY4S4lT35ZztHuXdWlcAo2sU4pbeItff7BBw:ATBDv_-t-jYfiTgk0nLNo7W4glfaFkig42HUeerp6k6Hi3OJ7OGv6ZPKbBefa8by8weJBgkBX0PK5seL-3IypJ_vAXm9q9xbAP7GHreku8ZSOnwZACDvlJgGXRrPGhjP672lC-t8kFScyttjruyfyXNme1M1nKux8mq2hwtt-JyajlPj", + "68cc2f8e77:0:14db37ff42c15aa305951911d3ac65748367d1c284ce18c5ba400899d6ce333f9c35ad162464935ab6f4fe94715a8c4f27706f6270a44f46aa46d2539d2e7334:d0c6e6e8779e7a4b2462e74ff097070f8cf325c38de09eac3c5fe7a8216afa7b44f92a6bc9bd38af780b2ec529f80cddb1f733a805a05a89f7149b873dfc98d0:1:AKAzMbwTh1QxdqHB8_TlY7ulKqRCp05PgYxtFPDH-m38mOFHBH4q2kcw7BMbsbODfiNDG8UUmKvW1BJhk1muvA2XAHjiPjWY8jVXHJAXWp1iqmguj93BBDoCJJoSAp7fXthTz5TPViB8_EcnOedfASJUMMODn6iECE80vy_N7sxQQzBJAYAiSD6PGcO8lxHiS2clee1Twbf2PJU35CTaDPOy7yoEi8y8HMpDB8i-FYNrcDuWhO506r8JSNvAgttFmsUHyPB6AAOVEQQHqTnidrpqXnI4pDJXFhopjXkO2WtTub8zjFLwHA73Rgw0U54Q8Ya8uWm2bnhoLOTVgQ51sfV1VP4orH5ZAVo_p_s5_tl-X5PeIc1mGbfXIq5EZ4Cu7D-Gu08gDqxajJov51p1gi9A36NPoxDcDPZrvfhin122VkFrs1NN-ThzAZLqZWHeX7CNAZ_jbD110l-gxP8FkfPpGSmVB9dsXqj_LQxVzEEie13CZSovd0BIscfNcQvPAQn9lD4X-ZtY5DIXluHcve-kFDzNGu15NYQCD5qxDmy8paFigJ83Ad8V1ScsEISR3DNeNocB0uBP6aVlQUNwtaTo20EH1I_gE0oBDQ:AE0E5BpSDnLWor443T0RrfMx0Shel5C73P9ZdFZR58-txJYser1Qn_GFAzsN9wVjHZSSgbks6JAAucNF62S75rbTAbEBtbdm6AhyLveV2LsJ_GxnK1eA2q3DpG97gVCdaLm-6P_b7bRDKhKV0xqbEFCG4rdSjNPI55Nst76IdfRC-YUw", + "a8dca71e98:0:ae3174d41b37ffcd575be3fedfbbb7014622b61afdae1b4fbbbc880427f7e34841117d09883b575f11aa9b0069a188b9ab496b1fd72dbb95e2b347c07f360174:70ce0bb0899196c1794660266bac0b06c50aca60de42410f12152e5395b7c6717d2acf315f19bbe360ffc94fbac9e59cb1386ecf3ad7a655498caba5dda4d4e8:1:AZUGXrLYWPIDJDbieUC0KIyR4s3Ny3MetrlC72y8LEo7AOAq-B2Zl7qf9G8ECV7pzbjNtOsRl_br6gemO8ju-Y4-AHSVyu3EZJIA-_ff8aqGWO7Qrn7R7BVmGwEPsEIVdIA1p1wNPcRquacSmGVteOMLNXViFDJsEnZbuixFoqwaHOniAfkWV2AX0riULmS83Td89ov3MwWDegRtJHhEBRJEUTGbA0-Lgm6_c1Qsl1ZmOns0rGyQDPu2UY60NTUtNrI-6GS3AL_JcuI8ILqB53F4TNXlDx3kHpwOUQgcipJFYgwaCyRj9CDIah5I3kyfayn09gznro6DsQCQq0QZ_7IYw0nglcTYAI0s8XTChwmz9Sp9yAsbnHnwVLJJWKIpflD2tPxBu4Dmuw-zsMv2mZvF8aSyz6McbaPTVqrFPtqsWbhGrymkDfV_AB2Os-9eoQawvF0Jlu3e8HESXMd7Hm7o68WttF88eIiQoQbwnyQfroiDAb9SkLhPlkO3b6lHH0rUo1cVPtrv7kUx6q2dr1vdrOItINTDFQD8StMEWRWiOyfNw9qDRUF2vj2iYpyi8bQ4z_MlUeAm4pHwg2lK1cfa7W949UbeaNDpAQ:AMudL3SxwtAYlrM8yir2dfOXjcBCe5UaVvW5geQGGUS3CQUgTyyAix_mKCnIHsc2_Sa5wc7tCd8Or2WawPcYjYDuAbTQbuXB1ZZtucGnze_vPRP4yJ9mlSRWlyu10bzBlOAuKofiCd_WYmQwmhLgGhDrun8AIu3_7yx5xOv5VQB_pvJM", + "ef9bf07932:0:debf307a91682f407ef0656db48beed39edff72280549f2188148fca1320c60efdff2f3279033a67ad6c8fbf10836d992e17f1796b690f715c8f74b286210e36:0016b7da07340bdd71e3922b29feae47884c4d42fa4e41997d9a6f2f6186775321250d014baa16a6c440960189493d1f61d5637ef2bf52f1bc4699b10b70394a:1:AZk47482_xHQyM-4zBVMyDeyPtzXKpuCRtCEc6qr6Nvycqw1LsKwaBxZIVW0S072c33BN7bDBJq3j0FssGVUK2mIAFDQa1BQfEexXkn3BU078B3TOuMLNIWS9SEyixt4jDKeELU8nh9QgIrMH9eL_6Pl-QABF2F8xgb2AJX-Q3zzcdvdAS-Bz4OeCkn1q2h8q9pKUPS8JOVdzByUqP3WPcYfYHA6PY1FumohaEgqjnuIwYFdHg7yFqX2MQBfPZD-j42Efjo2AP1hiR_WOJKjRIMYA63UPjFFk6i5Zr7TipsT473a1rDjLxoniJlsH2Ss7m79Rckq3R89wbWHcZ-MhpW4NpSeOeYQAQHv8jjPeApQE9bq88WOKQ_JbygYhlHv2gOTQdiMjzL9TMDkFJAIkw1RvWa6xOxi4aZzAsk0ns2MM51b2HPwNesmAPYVZd33eXTT7carfOo3g-MvvE3aXyKica7lDGa2mi8fAb5OwmIOBa3U-NhzpjNzwgrCsMx7dRxm7fZKqaMLe2gitFdpqWK0McLowM8S3Ft7CRyHGhm9w9wB4-TAHcepplR3Ahrl-VCn2DzCBJsnSpgWVFzfXYq2uZMlSc6J6InMDg:AT4JX87uzP1OOxkq7eHpEpBItbtIFkC8_X7QjFF5R-cclN64DJAR9RuKYoAOnYc2wmbFdQ-NgYQR2PXgA-sPBJxtAPPpSw0PSg36cbtESzKemq03QLcDg6F9hh0N0stM3uJsgbRApPI-HQN4RNM1AI9-zmezJDzR8hREvLiQoY6DDxua", + "3710a2e191:0:d4d3f16f6a59b758895b50bd540e68535a3b7803b61a217f437a096937763f7e3537c475bfd107b7ca8c39e3bf37f33e078cecc2fcebc2a66abfd474e47a8acc:e025c2a133160c77cdfdb0b9a8f408bc9d99882da8f2854f9ddf8bfd36cb7a7de72d71edf6d2f5f37e313e700f27550c9b2a5a2c5e226ca8a14797eebb95c34c:1:AVUSQxAMkXFHeAlu_ZLQHUHoXi2zeYd0OqUaY88IJfUwyhZuuJUB1i4l9YAmxRCmvA4W9-0zBMs5VIaRe4BLZwgAAO0ww08FS4mWLwcH-NptOTy8eCitJ89MN6Zt0EQHifyOzxxLWIgY6OZJiKiSeRLrWr1_ZRpeHJJLcF7Zdnr_8f7MAPtBybUcan4kIdL5yI91FpE8CgmjM5Pmx4EWiJC33C3Iu4aV2GEdxPWutP8-XRGNpADwnHqE3XaNV_6rstC9Fu7kALdEb3WgqszTsf_elgCJbZ6IunXZBZrF8FGoAqeGWvV86lUw3vp7hwCUEQ52X4r8imKuqCtIdeYegoBfcEcyq3zDAJEScanA8YjU0y4k2FLyVBCrRjxsZDkyP9ZJXM2p3_5m27NhjzxDDLcb75Sb8Pn9K_CgwOafZw8yGIIK5OTkuEKQAGH6yMdspiUHTYTiEGSVAlJyRWz-Ifo9skohOlV6aQp1LufpNhonjbR3zXcAHo1s0yIkqivM_RXbVfe3QViNx3xeBpBLuxSj05hoiFrGEUuA-Q3tTtnGgbgtEEgzaiKeTu3Sclfd6EaZJc3T35DMl3U9wLlx6_BJsVS3SpfKIZv8AA:AePjhNHvnJr-FqsiI7y7QCI1OXUbG9iK98U8caTUb9VcezhHtMbEjzFehucOrafEnAZXROT6noHrztYxDEzJIfGmAEfPrbP6VYrCGo2fk6MsyzyCK24OJfFU3Z7mnSNZHpN55_P1LBlHoGQUyCAwcKzp8WCY_ceQkxTNNjdkAdq1zB4o" + ]; #[test] - fn v0() { - } + fn v0() {} #[test] fn v1() { + for id_str in GOOD_V1_IDENTITIES { + let id = Identity::from_str(id_str).unwrap(); + assert!(id.validate_identity()); + assert!(id.p521.is_some()); + let idb = id.to_bytes(IDENTITY_CIPHER_SUITE_INCLUDE_ALL, true); + let mut cursor = 0; + let id_unmarshal = Identity::unmarshal(&idb, &mut cursor).expect("unmarshal failed"); + assert!(id == id_unmarshal); + assert!(id_unmarshal.secret.is_some()); + let idb2 = id_unmarshal.to_bytes(IDENTITY_CIPHER_SUITE_INCLUDE_ALL, true); + assert!(idb == idb2); + let sig = id.sign(&[1, 2, 3, 4, 5], IDENTITY_CIPHER_SUITE_INCLUDE_ALL).unwrap(); + assert!(id_unmarshal.verify(&[1, 2, 3, 4, 5], sig.as_slice())); + } } #[test] - fn generate() { - let count = 64; - for _ in 0..count { + fn benchmark_generate() { + let mut count = 0; + let run_time = Duration::from_secs(5); + let start = SystemTime::now(); + let mut end; + let mut duration; + loop { let id = Identity::generate(); - println!("{}", id.to_secret_string()); + //println!("{}", id.to_secret_string()); + end = SystemTime::now(); + duration = end.duration_since(start).unwrap(); + count += 1; + if duration >= run_time { + break; + } } + println!("benchmark: V1 identity generation: {} ms / identity (average)", (duration.as_millis() as f64) / (count as f64)); } } diff --git a/zerotier-network-hypervisor/src/vl1/path.rs b/zerotier-network-hypervisor/src/vl1/path.rs index 2f61c27a7..f8937777c 100644 --- a/zerotier-network-hypervisor/src/vl1/path.rs +++ b/zerotier-network-hypervisor/src/vl1/path.rs @@ -16,9 +16,10 @@ use std::sync::atomic::{AtomicI64, Ordering}; use arc_swap::ArcSwap; use highway::HighwayHash; use parking_lot::Mutex; +use zerotier_core_crypto::hash::SHA384_HASH_SIZE; use crate::PacketBuffer; -use crate::util::{highwayhasher, U64NoOpHasher}; +use crate::util::{array_range, highwayhasher, U64NoOpHasher}; use crate::vl1::Endpoint; use crate::vl1::fragmentedpacket::FragmentedPacket; use crate::vl1::node::VL1SystemInterface; @@ -55,7 +56,7 @@ impl Path { let lsi = (local_socket as u128).wrapping_shl(64) | (local_interface as u128); match endpoint { Endpoint::Nil => 0, - Endpoint::ZeroTier(a) => a.to_u64() as u128, + Endpoint::ZeroTier(_, h) => u128::from_ne_bytes(*array_range::(h)), Endpoint::Ethernet(m) => (m.to_u64() | 0x0100000000000000) as u128 ^ lsi, Endpoint::WifiDirect(m) => (m.to_u64() | 0x0200000000000000) as u128 ^ lsi, Endpoint::Bluetooth(m) => (m.to_u64() | 0x0400000000000000) as u128 ^ lsi, @@ -76,6 +77,7 @@ impl Path { let _ = hh.write_all(b.as_slice()); u128::from_ne_bytes(unsafe { *hh.finalize128().as_ptr().cast() }) } + Endpoint::ZeroTierEncap(_, h) => u128::from_ne_bytes(*array_range::(h)), } } diff --git a/zerotier-network-hypervisor/src/vl1/protocol.rs b/zerotier-network-hypervisor/src/vl1/protocol.rs index b1969f8bf..e41f24e13 100644 --- a/zerotier-network-hypervisor/src/vl1/protocol.rs +++ b/zerotier-network-hypervisor/src/vl1/protocol.rs @@ -180,7 +180,7 @@ pub const IDENTITY_V0_POW_THRESHOLD: u8 = 17; /// Proof of work difficulty (threshold) for new v1 identities. /// This is lower than the V0 threshold, causing the V0 part of V1 identities to /// verify on old nodes. -pub const IDENTITY_V1_POW_THRESHOLD: u8 = 5; +pub const IDENTITY_V1_POW_THRESHOLD: u8 = 9; #[derive(Clone, Copy)] #[repr(u8)]