From d2e19c889f05e407324c777598a54988206eea1a Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 23 Aug 2021 14:46:34 -0400 Subject: [PATCH] Formatting. --- PROTOCOL.md | 6 +- network-hypervisor/src/crypto/c25519.rs | 16 +--- network-hypervisor/src/crypto/hash.rs | 24 ++--- network-hypervisor/src/crypto/p521.rs | 20 +--- network-hypervisor/src/crypto/secret.rs | 43 ++------- network-hypervisor/src/vl1/address.rs | 5 +- network-hypervisor/src/vl1/buffer.rs | 10 +- network-hypervisor/src/vl1/endpoint.rs | 4 +- network-hypervisor/src/vl1/identity.rs | 106 ++++++++-------------- network-hypervisor/src/vl1/inetaddress.rs | 13 +-- network-hypervisor/src/vl1/locator.rs | 6 +- network-hypervisor/src/vl1/mac.rs | 15 +-- network-hypervisor/src/vl1/mod.rs | 1 + network-hypervisor/src/vl1/node.rs | 21 ++--- network-hypervisor/src/vl1/path.rs | 2 +- network-hypervisor/src/vl1/peer.rs | 101 +++++++++++++++------ network-hypervisor/src/vl1/protocol.rs | 28 +++++- network-hypervisor/src/vl1/rootset.rs | 12 +-- network-hypervisor/src/vl1/whois.rs | 16 +--- 19 files changed, 210 insertions(+), 239 deletions(-) diff --git a/PROTOCOL.md b/PROTOCOL.md index 326e373a2..a78113a4e 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -66,6 +66,8 @@ NOP, as the name suggests, does nothing. Any payload is ignored. | [2] u16 | Length of encrypted Dictionary in bytes | | Dictionary | Key/value dictionary containing additional fields | | -- | -- END of AES-256-CTR encrypted section -- | +| [2] u16 | Length of unencrypted Dictionary in bytes | +| Dictionary | Unencrypted dictionary (not currently used) | HELLO establishes a full session with another peer and carries information such as protocol and software versions, the full identity of the peer, and ephemeral keys for forward secrecy. Without a HELLO exchange only limited communication with the most conservative assumptions is possible, and communication without a session may be completely removed in the future. (It's only allowed now for backward compatibility with ZeroTier 1.x, and must be disabled in FIPS mode.) @@ -91,7 +93,7 @@ OK(HELLO) response payload, which must be sent if the HELLO receipient wishes to | [2] u16 | Length of encrypted Dictionary in bytes | | Dictionary | Key/value dictionary containing additional fields | -Recommended dictionary fields in both HELLO and OK(HELLO): +The unencrypted dictionary is not currently used. The encrypted dictionary can contain the following fields in both HELLO and OK(HELLO): | Name | Key | Type | Description | | -------------------- | --- | ------------ | ------------------------------------------------ | @@ -120,7 +122,7 @@ Optional dictionary fields that can be included in either HELLO or OK(HELLO): | VENDOR | `V` | string | Node software vendor if not ZeroTier, Inc. | | FLAGS | `+` | string | Flags (see below) | -FLAGS is a string that can contain the following boolean flags: `F` to indicate that the node is running in FIPS compliant mode, and `w` to indicate that the node is a "wimp." "Wimpy" nodes are things like mobile phones, and this flag can be used to exempt these devices from selection for any intensive role (such as use in VL2 to propagate multicasts). +FLAGS is a string that can contain the following boolean flags: `F` to indicate that the node is running in FIPS compliant mode. System information such as OS_NAME is currently only sent to roots and not to any other node. This allows roots to collect a bit of very generic statistical and diagnostic telemtry about the nodes using them. diff --git a/network-hypervisor/src/crypto/c25519.rs b/network-hypervisor/src/crypto/c25519.rs index 64b88f67d..ae4209c38 100644 --- a/network-hypervisor/src/crypto/c25519.rs +++ b/network-hypervisor/src/crypto/c25519.rs @@ -38,14 +38,10 @@ impl C25519KeyPair { } #[inline(always)] - pub fn public_bytes(&self) -> [u8; C25519_PUBLIC_KEY_SIZE] { - self.1.to_bytes() - } + pub fn public_bytes(&self) -> [u8; C25519_PUBLIC_KEY_SIZE] { self.1.to_bytes() } #[inline(always)] - pub fn secret_bytes(&self) -> Secret<{ C25519_SECRET_KEY_SIZE }> { - Secret(self.0.to_bytes()) - } + pub fn secret_bytes(&self) -> Secret<{ C25519_SECRET_KEY_SIZE }> { Secret(self.0.to_bytes()) } /// Execute ECDH agreement and return a raw (un-hashed) shared secret key. #[inline(always)] @@ -86,14 +82,10 @@ impl Ed25519KeyPair { } #[inline(always)] - pub fn public_bytes(&self) -> [u8; ED25519_PUBLIC_KEY_SIZE] { - self.0.public.to_bytes() - } + pub fn public_bytes(&self) -> [u8; ED25519_PUBLIC_KEY_SIZE] { self.0.public.to_bytes() } #[inline(always)] - pub fn secret_bytes(&self) -> Secret<{ ED25519_SECRET_KEY_SIZE }> { - Secret(self.0.secret.to_bytes()) - } + pub fn secret_bytes(&self) -> Secret<{ ED25519_SECRET_KEY_SIZE }> { Secret(self.0.secret.to_bytes()) } #[inline(always)] pub fn sign(&self, msg: &[u8]) -> [u8; ED25519_SIGNATURE_SIZE] { diff --git a/network-hypervisor/src/crypto/hash.rs b/network-hypervisor/src/crypto/hash.rs index 6469001a0..955424e12 100644 --- a/network-hypervisor/src/crypto/hash.rs +++ b/network-hypervisor/src/crypto/hash.rs @@ -26,19 +26,13 @@ impl SHA512 { } #[inline(always)] - pub fn new() -> Self { - Self(gcrypt::digest::MessageDigest::new(gcrypt::digest::Algorithm::Sha512).unwrap()) - } + pub fn new() -> Self { Self(gcrypt::digest::MessageDigest::new(gcrypt::digest::Algorithm::Sha512).unwrap()) } #[inline(always)] - pub fn reset(&mut self) { - self.0.reset(); - } + pub fn reset(&mut self) { self.0.reset(); } #[inline(always)] - pub fn update(&mut self, b: &[u8]) { - self.0.update(b); - } + pub fn update(&mut self, b: &[u8]) { self.0.update(b); } #[inline(always)] pub fn finish(&mut self) -> [u8; SHA512_HASH_SIZE] { @@ -87,19 +81,13 @@ impl SHA384 { } #[inline(always)] - pub fn new() -> Self { - Self(gcrypt::digest::MessageDigest::new(gcrypt::digest::Algorithm::Sha384).unwrap()) - } + pub fn new() -> Self { Self(gcrypt::digest::MessageDigest::new(gcrypt::digest::Algorithm::Sha384).unwrap()) } #[inline(always)] - pub fn reset(&mut self) { - self.0.reset(); - } + pub fn reset(&mut self) { self.0.reset(); } #[inline(always)] - pub fn update(&mut self, b: &[u8]) { - self.0.update(b); - } + pub fn update(&mut self, b: &[u8]) { self.0.update(b); } #[inline(always)] pub fn finish(&mut self) -> [u8; SHA384_HASH_SIZE] { diff --git a/network-hypervisor/src/crypto/p521.rs b/network-hypervisor/src/crypto/p521.rs index a6536b842..7dafe5d0c 100644 --- a/network-hypervisor/src/crypto/p521.rs +++ b/network-hypervisor/src/crypto/p521.rs @@ -130,23 +130,17 @@ impl P521KeyPair { } #[inline(always)] - pub fn public_key(&self) -> &P521PublicKey { - &self.public_key - } + pub fn public_key(&self) -> &P521PublicKey { &self.public_key } /// Get the raw ECC public "q" point for this key pair. /// The returned point is not compressed. To use this with other interfaces that expect a format /// prefix, prepend 0x04 to the beginning of this public key. This prefix is always the same in /// our system and so is omitted. #[inline(always)] - pub fn public_key_bytes(&self) -> &[u8; P521_PUBLIC_KEY_SIZE] { - &self.public_key.public_key_bytes - } + pub fn public_key_bytes(&self) -> &[u8; P521_PUBLIC_KEY_SIZE] { &self.public_key.public_key_bytes } #[inline(always)] - pub fn secret_key_bytes(&self) -> &Secret<{ P521_SECRET_KEY_SIZE }> { - &self.secret_key_bytes - } + pub fn secret_key_bytes(&self) -> &Secret<{ P521_SECRET_KEY_SIZE }> { &self.secret_key_bytes } /// Create an ECDSA signature of the input message. /// Message data does not need to be pre-hashed. @@ -213,17 +207,13 @@ impl P521PublicKey { impl PartialEq for P521PublicKey { #[inline(always)] - fn eq(&self, other: &Self) -> bool { - self.public_key_bytes.eq(&other.public_key_bytes) - } + fn eq(&self, other: &Self) -> bool { self.public_key_bytes.eq(&other.public_key_bytes) } } impl Eq for P521PublicKey {} impl Clone for P521PublicKey { - fn clone(&self) -> Self { - P521PublicKey::from_bytes(&self.public_key_bytes).unwrap() - } + fn clone(&self) -> Self { P521PublicKey::from_bytes(&self.public_key_bytes).unwrap() } } #[cfg(test)] diff --git a/network-hypervisor/src/crypto/secret.rs b/network-hypervisor/src/crypto/secret.rs index f0cded230..cd260a0ca 100644 --- a/network-hypervisor/src/crypto/secret.rs +++ b/network-hypervisor/src/crypto/secret.rs @@ -16,34 +16,21 @@ pub struct Secret(pub(crate) [u8; L]); impl Secret { #[inline(always)] - pub fn new() -> Self { - Self([0_u8; L]) - } + pub fn new() -> Self { Self([0_u8; L]) } /// Copy bytes into secret, will panic if size does not match. #[inline(always)] - pub fn from_bytes(b: &[u8]) -> Self { - Self(b.try_into().unwrap()) - } + pub fn from_bytes(b: &[u8]) -> Self { Self(b.try_into().unwrap()) } #[inline(always)] - pub fn as_bytes(&self) -> &[u8; L] { - return &self.0 - } + pub fn as_bytes(&self) -> &[u8; L] { return &self.0 } } impl Drop for Secret { fn drop(&mut self) { unsafe { - let p = self.0.as_mut_ptr(); - if (L % size_of::()) == 0 { - for i in 0..(L / size_of::()) { - write_volatile(p.cast::().offset(i as isize), 0_usize); - } - } else { - for i in 0..L { - write_volatile(p.offset(i as isize), 0_u8); - } + for i in 0..L { + write_volatile(self.0.as_mut_ptr().offset(i as isize), 0_u8); } } } @@ -51,35 +38,25 @@ impl Drop for Secret { impl Default for Secret { #[inline(always)] - fn default() -> Self { - Self([0_u8; L]) - } + fn default() -> Self { Self([0_u8; L]) } } impl AsRef<[u8]> for Secret { #[inline(always)] - fn as_ref(&self) -> &[u8] { - &self.0 - } + fn as_ref(&self) -> &[u8] { &self.0 } } impl AsRef<[u8; L]> for Secret { #[inline(always)] - fn as_ref(&self) -> &[u8; L] { - &self.0 - } + fn as_ref(&self) -> &[u8; L] { &self.0 } } impl AsMut<[u8]> for Secret { #[inline(always)] - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0 - } + fn as_mut(&mut self) -> &mut [u8] { &mut self.0 } } impl AsMut<[u8; L]> for Secret { #[inline(always)] - fn as_mut(&mut self) -> &mut [u8; L] { - &mut self.0 - } + fn as_mut(&mut self) -> &mut [u8; L] { &mut self.0 } } diff --git a/network-hypervisor/src/vl1/address.rs b/network-hypervisor/src/vl1/address.rs index 195fafda3..74d432766 100644 --- a/network-hypervisor/src/vl1/address.rs +++ b/network-hypervisor/src/vl1/address.rs @@ -14,9 +14,10 @@ pub struct Address(NonZeroU64); impl Address { /// Get an address from a 64-bit integer or return None if it is zero or reserved. #[inline(always)] - pub fn from_u64(i: u64) -> Option
{ + pub fn from_u64(mut i: u64) -> Option
{ + i &= 0xffffffffff; if i != 0 && (i >> 32) != ADDRESS_RESERVED_PREFIX as u64 { - Some(Address(unsafe { NonZeroU64::new_unchecked(i & 0xffffffffff) })) + Some(Address(unsafe { NonZeroU64::new_unchecked(i) })) } else { None } diff --git a/network-hypervisor/src/vl1/buffer.rs b/network-hypervisor/src/vl1/buffer.rs index df06a2f84..aa6bc5cfb 100644 --- a/network-hypervisor/src/vl1/buffer.rs +++ b/network-hypervisor/src/vl1/buffer.rs @@ -70,6 +70,14 @@ impl Buffer { #[inline(always)] pub fn is_empty(&self) -> bool { self.0 == 0 } + /// Set the size of this buffer's data. + /// + /// This is marked unsafe because no bounds checking is done here and because it + /// technically violates the assurance that all data in the buffer is valid. Use + /// with care. + #[inline(always)] + pub unsafe fn set_size(&mut self, s: usize) { self.0 = s; } + /// Append a packed structure and call a function to initialize it in place. /// Anything not initialized will be zero. #[inline(always)] @@ -305,7 +313,7 @@ impl Buffer { loop { let b = self.read_u8(cursor)?; if (b & 0x80) == 0 { - i |= (b as u64) << p; + i |= (b as u64).wrapping_shl(p); p += 7; } else { i |= ((b & 0x7f) as u64) << p; diff --git a/network-hypervisor/src/vl1/endpoint.rs b/network-hypervisor/src/vl1/endpoint.rs index 8678a9082..94aa9981b 100644 --- a/network-hypervisor/src/vl1/endpoint.rs +++ b/network-hypervisor/src/vl1/endpoint.rs @@ -47,9 +47,7 @@ pub enum Endpoint { impl Default for Endpoint { #[inline(always)] - fn default() -> Endpoint { - Endpoint::Nil - } + fn default() -> Endpoint { Endpoint::Nil } } impl Endpoint { diff --git a/network-hypervisor/src/vl1/identity.rs b/network-hypervisor/src/vl1/identity.rs index b309d6a92..312f536cf 100644 --- a/network-hypervisor/src/vl1/identity.rs +++ b/network-hypervisor/src/vl1/identity.rs @@ -6,6 +6,8 @@ use std::io::Write; use std::ptr::{slice_from_raw_parts, slice_from_raw_parts_mut}; use std::str::FromStr; +use concat_arrays::concat_arrays; + use crate::crypto::balloon; use crate::crypto::c25519::*; use crate::crypto::hash::*; @@ -17,12 +19,12 @@ use crate::vl1::Address; use crate::vl1::buffer::Buffer; use crate::vl1::protocol::PACKET_SIZE_MAX; -use concat_arrays::concat_arrays; +pub const IDENTITY_TYPE_0_SIGNATURE_SIZE: usize = 96; +pub const IDENTITY_TYPE_1_SIGNATURE_SIZE: usize = P521_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE; -// Memory parameter for V0 address derivation work function. -const V0_IDENTITY_GEN_MEMORY: usize = 2097152; - -// Balloon hash parameters for V1 address derivation work function. +const V0_POW_MEMORY: usize = 2097152; +const V0_POW_THRESHOLD: u8 = 17; +const V1_POW_THRESHOLD: u8 = 5; const V1_BALLOON_SPACE_COST: usize = 16384; const V1_BALLOON_TIME_COST: usize = 3; const V1_BALLOON_DELTA: usize = 3; @@ -30,12 +32,6 @@ const V1_BALLOON_SALT: &'static [u8] = b"zt_id_v1"; const V1_PUBLIC_KEYS_SIGNATURE_AND_POW_SIZE: usize = C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_ECDSA_SIGNATURE_SIZE + SHA384_HASH_SIZE; -pub const IDENTITY_TYPE_0_SIGNATURE_SIZE: usize = 96; -pub const IDENTITY_TYPE_1_SIGNATURE_SIZE: usize = P521_ECDSA_SIGNATURE_SIZE + ED25519_SIGNATURE_SIZE; - -const IDENTITY_V0_POW_THRESHOLD: u8 = 17; -const IDENTITY_V1_POW_THRESHOLD: u8 = 5; - #[derive(Copy, Clone)] #[repr(u8)] pub enum Type { @@ -62,24 +58,24 @@ pub struct Identity { /// Compute result from the bespoke "frankenhash" from the old V0 work function. /// The supplied genmem_ptr must be of size V0_IDENTITY_GEN_MEMORY and aligned to an 8-byte boundary. fn v0_frankenhash(digest: &mut [u8; 64], genmem_ptr: *mut u8) { - let (genmem, genmem_alias_hack) = unsafe { (&mut *slice_from_raw_parts_mut(genmem_ptr, V0_IDENTITY_GEN_MEMORY), &*slice_from_raw_parts(genmem_ptr, V0_IDENTITY_GEN_MEMORY)) }; + let (genmem, genmem_alias_hack) = unsafe { (&mut *slice_from_raw_parts_mut(genmem_ptr, V0_POW_MEMORY), &*slice_from_raw_parts(genmem_ptr, V0_POW_MEMORY)) }; let genmem_u64_ptr = genmem_ptr.cast::(); let mut s20 = Salsa::new(&digest[0..32], &digest[32..40], false).unwrap(); s20.crypt(&crate::util::ZEROES[0..64], &mut genmem[0..64]); let mut i: usize = 64; - while i < V0_IDENTITY_GEN_MEMORY { + while i < V0_POW_MEMORY { let ii = i + 64; s20.crypt(&genmem_alias_hack[(i - 64)..i], &mut genmem[i..ii]); i = ii; } i = 0; - while i < (V0_IDENTITY_GEN_MEMORY / 8) { + while i < (V0_POW_MEMORY / 8) { unsafe { let idx1 = (((*genmem_u64_ptr.offset(i as isize)).to_be() % 8) * 8) as usize; - let idx2 = ((*genmem_u64_ptr.offset((i + 1) as isize)).to_be() % (V0_IDENTITY_GEN_MEMORY as u64 / 8)) as usize; + let idx2 = ((*genmem_u64_ptr.offset((i + 1) as isize)).to_be() % (V0_POW_MEMORY as u64 / 8)) as usize; let genmem_u64_at_idx2_ptr = genmem_u64_ptr.offset(idx2 as isize); let tmp = *genmem_u64_at_idx2_ptr; let digest_u64_ptr = digest.as_mut_ptr().offset(idx1 as isize).cast::(); @@ -93,7 +89,7 @@ fn v0_frankenhash(digest: &mut [u8; 64], genmem_ptr: *mut u8) { impl Identity { fn generate_c25519() -> Identity { - let genmem_layout = Layout::from_size_align(V0_IDENTITY_GEN_MEMORY, 8).unwrap(); + let genmem_layout = Layout::from_size_align(V0_POW_MEMORY, 8).unwrap(); let genmem_ptr = unsafe { alloc(genmem_layout) }; if genmem_ptr.is_null() { panic!("unable to allocate memory for V0 identity generation"); @@ -111,7 +107,7 @@ impl Identity { let mut digest = sha.finish(); v0_frankenhash(&mut digest, genmem_ptr); - if digest[0] < IDENTITY_V0_POW_THRESHOLD { + if digest[0] < V0_POW_THRESHOLD { let addr = Address::from_bytes(&digest[59..64]); if addr.is_some() { unsafe { dealloc(genmem_ptr, genmem_layout) }; @@ -145,7 +141,7 @@ impl Identity { // ECDSA is a randomized signature algorithm, so each signature will be different. let sig = p521_ecdsa.sign(&sign_buf).unwrap(); let bh = balloon::hash::<{ V1_BALLOON_SPACE_COST }, { V1_BALLOON_TIME_COST }, { V1_BALLOON_DELTA }>(&sig, V1_BALLOON_SALT); - if bh[0] < IDENTITY_V1_POW_THRESHOLD { + if bh[0] < V1_POW_THRESHOLD { let addr = Address::from_bytes(&bh[43..48]); if addr.is_some() { let p521_ecdh_pub = p521_ecdh.public_key().clone(); @@ -210,7 +206,7 @@ impl Identity { /// to fully validate than V1 identities. pub fn locally_validate(&self) -> bool { if self.v1.is_none() { - let genmem_layout = Layout::from_size_align(V0_IDENTITY_GEN_MEMORY, 8).unwrap(); + let genmem_layout = Layout::from_size_align(V0_POW_MEMORY, 8).unwrap(); let genmem_ptr = unsafe { alloc(genmem_layout) }; if !genmem_ptr.is_null() { let mut sha = SHA512::new(); @@ -219,7 +215,7 @@ impl Identity { let mut digest = sha.finish(); v0_frankenhash(&mut digest, genmem_ptr); unsafe { dealloc(genmem_ptr, genmem_layout) }; - (digest[0] < IDENTITY_V0_POW_THRESHOLD) && Address::from_bytes(&digest[59..64]).unwrap().eq(&self.address) + (digest[0] < V0_POW_THRESHOLD) && Address::from_bytes(&digest[59..64]).unwrap().eq(&self.address) } else { false } @@ -232,7 +228,7 @@ impl Identity { signing_buf[(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)..(C25519_PUBLIC_KEY_SIZE + ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE)].copy_from_slice((*p521).1.public_key_bytes()); if (*p521).1.verify(&signing_buf, &(*p521).2) { let bh = balloon::hash::<{ V1_BALLOON_SPACE_COST }, { V1_BALLOON_TIME_COST }, { V1_BALLOON_DELTA }>(&(*p521).2, V1_BALLOON_SALT); - (bh[0] < IDENTITY_V1_POW_THRESHOLD) && bh.eq(&(*p521).3) && Address::from_bytes(&bh[43..48]).unwrap().eq(&self.address) + (bh[0] < V1_POW_THRESHOLD) && bh.eq(&(*p521).3) && Address::from_bytes(&bh[43..48]).unwrap().eq(&self.address) } else { false } @@ -247,12 +243,8 @@ impl Identity { pub fn agree(&self, other_identity: &Identity) -> Option> { self.secrets.as_ref().map_or(None, |secrets| { let c25519_secret = || Secret::<48>(SHA384::hash(&secrets.c25519.agree(&other_identity.c25519).as_ref())); - secrets.v1.as_ref().map_or_else(|| { - Some(c25519_secret()) - }, |p521_secret| { - other_identity.v1.as_ref().map_or_else(|| { - Some(c25519_secret()) - }, |other_p521_public| { + secrets.v1.as_ref().map_or_else(|| Some(c25519_secret()), |p521_secret| { + other_identity.v1.as_ref().map_or_else(|| Some(c25519_secret()), |other_p521_public| { p521_secret.0.agree(&other_p521_public.0).map_or(None, |p521_secret| { // // For NIST P-521 key agreement, we use a single step key derivation function to derive @@ -285,25 +277,21 @@ impl Identity { pub fn sign(&self, msg: &[u8]) -> Option> { self.secrets.as_ref().map_or(None, |secrets| { let c25519_sig = secrets.ed25519.sign_zt(msg); - secrets.v1.as_ref().map_or_else(|| { - Some(c25519_sig.to_vec()) - }, |p521_secret| { - p521_secret.1.sign(msg).map_or(None, |p521_sig| { - // - // For type 1 identity signatures we sign with both algorithms and append the Ed25519 - // signature to the NIST P-521 signature. The Ed25519 signature is only checked if the - // P-521 signature validates. Note that we only append the first 64 bytes of sign_zt() - // output. For legacy reasons type 0 signatures include the first 32 bytes of the message - // hash after the signature, but this is not required and isn't included here. - // - // This should once again make both the FIPS people and the people paranoid about NIST - // curves happy. - // - let mut p521_sig = p521_sig.to_vec(); - let _ = p521_sig.write_all(&c25519_sig[0..64]); - Some(p521_sig) - }) - }) + secrets.v1.as_ref().map_or_else(|| Some(c25519_sig.to_vec()), |p521_secret| p521_secret.1.sign(msg).map_or(None, |p521_sig| { + // + // For type 1 identity signatures we sign with both algorithms and append the Ed25519 + // signature to the NIST P-521 signature. The Ed25519 signature is only checked if the + // P-521 signature validates. Note that we only append the first 64 bytes of sign_zt() + // output. For legacy reasons type 0 signatures include the first 32 bytes of the message + // hash after the signature, but this is not required and isn't included here. + // + // This should once again make both the FIPS people and the people paranoid about NIST + // curves happy. + // + let mut p521_sig = p521_sig.to_vec(); + let _ = p521_sig.write_all(&c25519_sig[0..64]); + Some(p521_sig) + })) }) } @@ -312,34 +300,20 @@ impl Identity { self.v1.as_ref().map_or_else(|| { crate::crypto::c25519::ed25519_verify(&self.ed25519, signature, msg) }, |p521| { - if signature.len() == IDENTITY_TYPE_1_SIGNATURE_SIZE { - (*p521).1.verify(msg, &signature[0..P521_ECDSA_SIGNATURE_SIZE]) && crate::crypto::c25519::ed25519_verify(&self.ed25519, &signature[P521_ECDSA_SIGNATURE_SIZE..], msg) - } else { - false - } + signature.len() == IDENTITY_TYPE_1_SIGNATURE_SIZE && (*p521).1.verify(msg, &signature[0..P521_ECDSA_SIGNATURE_SIZE]) && crate::crypto::c25519::ed25519_verify(&self.ed25519, &signature[P521_ECDSA_SIGNATURE_SIZE..], msg) }) } /// Get this identity's type. #[inline(always)] - pub fn id_type(&self) -> Type { - if self.v1.is_some() { - Type::P521 - } else { - Type::C25519 - } - } + pub fn id_type(&self) -> Type { if self.v1.is_some() { Type::P521 } else { Type::C25519 } } /// Returns true if this identity also holds its secret keys. #[inline(always)] - pub fn has_secrets(&self) -> bool { - self.secrets.is_some() - } + pub fn has_secrets(&self) -> bool { self.secrets.is_some() } /// Erase secrets from this identity object, if present. - pub fn forget_secrets(&mut self) { - let _ = self.secrets.take(); - } + pub fn forget_secrets(&mut self) { let _ = self.secrets.take(); } /// Append this in binary format to a buffer. pub fn marshal(&self, buf: &mut Buffer, include_private: bool) -> std::io::Result<()> { @@ -598,9 +572,7 @@ impl Eq for Identity {} impl PartialOrd for Identity { #[inline(always)] - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for Identity { diff --git a/network-hypervisor/src/vl1/inetaddress.rs b/network-hypervisor/src/vl1/inetaddress.rs index b5d63cd53..be60632cf 100644 --- a/network-hypervisor/src/vl1/inetaddress.rs +++ b/network-hypervisor/src/vl1/inetaddress.rs @@ -348,12 +348,8 @@ impl InetAddress { let ip = &*(&self.sin.sin_addr.s_addr as *const u32).cast::<[u8; 4]>(); format!("{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3]) } - AF_INET6 => { - Ipv6Addr::from(*(&(self.sin6.sin6_addr) as *const in6_addr).cast::<[u8; 16]>()).to_string() - } - _ => { - String::from("(null)") - } + AF_INET6 => Ipv6Addr::from(*(&(self.sin6.sin6_addr) as *const in6_addr).cast::<[u8; 16]>()).to_string(), + _ => String::from("(null)") } } } @@ -377,9 +373,7 @@ impl InetAddress { b[18] = *(&self.sin6.sin6_port as *const u16).cast::().offset(1); }) } - _ => { - buf.append_u8(0) - } + _ => buf.append_u8(0) } } } @@ -455,7 +449,6 @@ impl FromStr for InetAddress { } impl PartialEq for InetAddress { - #[inline(always)] fn eq(&self, other: &Self) -> bool { unsafe { if self.sa.sa_family == other.sa.sa_family { diff --git a/network-hypervisor/src/vl1/locator.rs b/network-hypervisor/src/vl1/locator.rs index e136644f1..bcc18ee3e 100644 --- a/network-hypervisor/src/vl1/locator.rs +++ b/network-hypervisor/src/vl1/locator.rs @@ -94,13 +94,13 @@ impl Locator { self.subject.marshal(buf)?; self.signer.marshal(buf)?; buf.append_u64(self.timestamp as u64)?; - buf.append_varint(self.endpoints.len() as u64); + buf.append_varint(self.endpoints.len() as u64)?; for e in self.endpoints.iter() { e.marshal(buf)?; } - buf.append_varint(0); // length of any additional fields + buf.append_varint(0)?; // length of any additional fields if !exclude_signature { - buf.append_varint(self.signature.len() as u64); + buf.append_varint(self.signature.len() as u64)?; buf.append_bytes(self.signature.as_slice())?; } Ok(()) diff --git a/network-hypervisor/src/vl1/mac.rs b/network-hypervisor/src/vl1/mac.rs index b9bd22508..fb7b1d061 100644 --- a/network-hypervisor/src/vl1/mac.rs +++ b/network-hypervisor/src/vl1/mac.rs @@ -11,23 +11,12 @@ pub struct MAC(NonZeroU64); impl MAC { #[inline(always)] - pub fn from_u64(i: u64) -> Option { - if i != 0 { - Some(MAC(unsafe { NonZeroU64::new_unchecked(i & 0xffffffffffff) })) - } else { - None - } - } + pub fn from_u64(i: u64) -> Option { NonZeroU64::new(i & 0xffffffffffff).map_or(None, |i| Some(MAC(i))) } #[inline(always)] pub fn from_bytes(b: &[u8]) -> Option { if b.len() >= 6 { - let i = (b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64; - if i != 0 { - Some(MAC(unsafe { NonZeroU64::new_unchecked(i) })) - } else { - None - } + NonZeroU64::new((b[0] as u64) << 40 | (b[1] as u64) << 32 | (b[2] as u64) << 24 | (b[3] as u64) << 16 as u64 | (b[4] as u64) << 8 | b[5] as u64).map_or(None, |i| Some(MAC(i))) } else { None } diff --git a/network-hypervisor/src/vl1/mod.rs b/network-hypervisor/src/vl1/mod.rs index 8e21845eb..9c7a925f2 100644 --- a/network-hypervisor/src/vl1/mod.rs +++ b/network-hypervisor/src/vl1/mod.rs @@ -6,6 +6,7 @@ pub mod locator; pub mod rootset; // These are either only used inside network-hypervisor or are selectively exported below. +#[allow(unused)] pub(crate) mod protocol; pub(crate) mod buffer; pub(crate) mod node; diff --git a/network-hypervisor/src/vl1/node.rs b/network-hypervisor/src/vl1/node.rs index 8e0ffae71..cc8149631 100644 --- a/network-hypervisor/src/vl1/node.rs +++ b/network-hypervisor/src/vl1/node.rs @@ -86,6 +86,9 @@ pub trait VL1CallerInterface { } /// Trait implemented by VL2 to handle messages after they are unwrapped by VL1. +/// +/// This normally isn't used from outside this crate except for testing or if you want to harness VL1 +/// for some entirely unrelated purpose. pub trait VL1PacketHandler { /// Handle a packet, returning true if the verb was recognized. /// @@ -95,10 +98,10 @@ pub trait VL1PacketHandler { fn handle_packet(&self, peer: &Peer, source_path: &Arc, forward_secrecy: bool, verb: u8, payload: &Buffer<{ PACKET_SIZE_MAX }>) -> bool; /// Handle errors, returning true if the error was recognized. - fn handle_error(&self, peer: &Peer, source_path: &Arc, forward_secrecy: bool, in_re_verb: u8, in_re_packet_id: PacketID, error_code: u8, payload: &Buffer<{ PACKET_SIZE_MAX }>) -> bool; + fn handle_error(&self, peer: &Peer, source_path: &Arc, forward_secrecy: bool, in_re_verb: u8, in_re_packet_id: PacketID, error_code: u8, payload: &Buffer<{ PACKET_SIZE_MAX }>, cursor: &mut usize) -> bool; /// Handle an OK, returing true if the OK was recognized. - fn handle_ok(&self, peer: &Peer, source_path: &Arc, forward_secrecy: bool, in_re_verb: u8, in_re_packet_id: PacketID, payload: &Buffer<{ PACKET_SIZE_MAX }>) -> bool; + fn handle_ok(&self, peer: &Peer, source_path: &Arc, forward_secrecy: bool, in_re_verb: u8, in_re_packet_id: PacketID, payload: &Buffer<{ PACKET_SIZE_MAX }>, cursor: &mut usize) -> bool; } #[derive(Default)] @@ -120,8 +123,7 @@ pub struct Node { whois: WhoisQueue, buffer_pool: Pool, PooledBufferFactory<{ PACKET_SIZE_MAX }>>, secure_prng: SecureRandom, - pub(crate) fips_mode: bool, - pub(crate) wimp: bool, + fips_mode: bool, } impl Node { @@ -164,19 +166,15 @@ impl Node { buffer_pool: Pool::new(64, PooledBufferFactory), secure_prng: SecureRandom::get(), fips_mode: false, - wimp: false, }) } - /// Get address, short for .identity().address() #[inline(always)] pub fn address(&self) -> Address { self.identity.address() } - /// Get identity, which includes secret keys. #[inline(always)] pub fn identity(&self) -> &Identity { &self.identity } - /// Get this node's current locator or None if no locator created. #[inline(always)] pub fn locator(&self) -> Option> { self.locator.lock().clone() } @@ -187,6 +185,9 @@ impl Node { /// Get a peer by address. pub fn peer(&self, a: Address) -> Option> { self.peers.get(&a).map(|peer| peer.value().clone()) } + #[inline(always)] + pub fn fips_mode(&self) -> bool { self.fips_mode } + /// Get all peers currently in the peer cache. pub fn peers(&self) -> Vec> { let mut v: Vec> = Vec::new(); @@ -319,9 +320,7 @@ impl Node { self.paths.get(ep).map_or_else(|| { let p = Arc::new(Path::new(ep.clone(), local_socket, local_interface)); self.paths.insert(ep.clone(), p.clone()).unwrap_or(p) // if another thread added one, return that instead - }, |path| { - path.value().clone() - }) + }, |path| path.value().clone()) } } diff --git a/network-hypervisor/src/vl1/path.rs b/network-hypervisor/src/vl1/path.rs index ee3bfefbe..a44e14669 100644 --- a/network-hypervisor/src/vl1/path.rs +++ b/network-hypervisor/src/vl1/path.rs @@ -36,7 +36,7 @@ impl Path { local_interface, last_send_time_ticks: AtomicI64::new(0), last_receive_time_ticks: AtomicI64::new(0), - fragmented_packets: Mutex::new(HashMap::with_capacity_and_hasher(8, U64PassThroughHasher::new())), + fragmented_packets: Mutex::new(HashMap::with_capacity_and_hasher(4, U64PassThroughHasher::new())), } } diff --git a/network-hypervisor/src/vl1/peer.rs b/network-hypervisor/src/vl1/peer.rs index 67390ace4..e65b5a5f6 100644 --- a/network-hypervisor/src/vl1/peer.rs +++ b/network-hypervisor/src/vl1/peer.rs @@ -10,7 +10,7 @@ use aes_gmac_siv::{AesCtr, AesGmacSiv}; use crate::{VERSION_MAJOR, VERSION_MINOR, VERSION_PROTO, VERSION_REVISION}; use crate::crypto::c25519::C25519KeyPair; -use crate::crypto::hash::SHA384; +use crate::crypto::hash::{SHA384, SHA384_HASH_SIZE}; use crate::crypto::kbkdf::zt_kbkdf_hmac_sha384; use crate::crypto::p521::P521KeyPair; use crate::crypto::poly1305::Poly1305; @@ -31,14 +31,10 @@ struct AesGmacSivPoolFactory(Secret<48>, Secret<48>); impl PoolFactory for AesGmacSivPoolFactory { #[inline(always)] - fn create(&self) -> AesGmacSiv { - AesGmacSiv::new(&self.0.0[0..32], &self.1.0[0..32]) - } + fn create(&self) -> AesGmacSiv { AesGmacSiv::new(&self.0.0[0..32], &self.1.0[0..32]) } #[inline(always)] - fn reset(&self, obj: &mut AesGmacSiv) { - obj.reset(); - } + fn reset(&self, obj: &mut AesGmacSiv) { obj.reset(); } } struct PeerSecret { @@ -92,7 +88,7 @@ pub struct Peer { // Either None or the current ephemeral key pair whose public keys are on offer. ephemeral_pair: Mutex>, - // Paths sorted in ascending order of quality / preference. + // Paths sorted in descending order of quality / preference. paths: Mutex>>, // Local external address most recently reported by this peer (IP transport only). @@ -144,8 +140,7 @@ fn salsa_poly_create(secret: &PeerSecret, header: &PacketHeader, packet_size: us let mut salsa = Salsa::new(&key.0[0..32], header.id_bytes(), true).unwrap(); let mut poly1305_key = [0_u8; 32]; salsa.crypt_in_place(&mut poly1305_key); - let mut poly = Poly1305::new(&poly1305_key).unwrap(); - (salsa, poly) + (salsa, Poly1305::new(&poly1305_key).unwrap()) } impl Peer { @@ -192,9 +187,7 @@ impl Peer { /// Get the next packet ID / IV. #[inline(always)] - pub(crate) fn next_packet_id(&self) -> PacketID { - self.packet_id_counter.fetch_add(1, Ordering::Relaxed) - } + pub(crate) fn next_packet_id(&self) -> PacketID { self.packet_id_counter.fetch_add(1, Ordering::Relaxed) } /// Receive, decrypt, authenticate, and process an incoming packet from this peer. /// If the packet comes in multiple fragments, the fragments slice should contain all @@ -287,15 +280,34 @@ impl Peer { self.total_bytes_received.fetch_add((payload.len() + PACKET_HEADER_SIZE) as u64, Ordering::Relaxed); let _ = payload.u8_at(0).map(|verb| { + let mut extended_authentication = false; + if (verb & VERB_FLAG_EXTENDED_AUTHENTICATION) != 0 { + let auth_bytes = payload.as_bytes(); + if auth_bytes.len() >= (1 + SHA384_HASH_SIZE) { + let packet_hmac_start = auth_bytes.len() - SHA384_HASH_SIZE; + if !SHA384::hmac(self.static_secret_packet_hmac.as_ref(), &auth_bytes[1..packet_hmac_start]).eq(&auth_bytes[packet_hmac_start..]) { + return; + } + extended_authentication = true; + unsafe { payload.set_size(payload.len() - SHA384_HASH_SIZE) }; + } else { + return; + } + } + + if (verb & VERB_FLAG_COMPRESSED) != 0 { + } + + let verb = verb & VERB_MASK; + // For performance reasons we let VL2 handle packets first. It returns false // if it didn't handle the packet, in which case it's handled at VL1. - let verb = verb & VERB_MASK; if !ph.handle_packet(self, source_path, forward_secrecy, verb, &payload) { match verb { //VERB_VL1_NOP => {} VERB_VL1_HELLO => self.receive_hello(ci, node, time_ticks, source_path, &payload), - VERB_VL1_ERROR => self.receive_error(ci, node, time_ticks, source_path, &payload), - VERB_VL1_OK => self.receive_ok(ci, node, time_ticks, source_path, &payload), + VERB_VL1_ERROR => self.receive_error(ci, ph, node, time_ticks, source_path, forward_secrecy, &payload), + VERB_VL1_OK => self.receive_ok(ci, ph, node, time_ticks, source_path, forward_secrecy, &payload), VERB_VL1_WHOIS => self.receive_whois(ci, node, time_ticks, source_path, &payload), VERB_VL1_RENDEZVOUS => self.receive_rendezvous(ci, node, time_ticks, source_path, &payload), VERB_VL1_ECHO => self.receive_echo(ci, node, time_ticks, source_path, &payload), @@ -406,7 +418,7 @@ impl Peer { header.flags_cipher_hops = CIPHER_NOCRYPT_POLY1305; }).is_ok()); debug_assert!(packet.append_and_init_struct(|header: &mut message_component_structs::HelloFixedHeaderFields| { - header.verb = VERB_VL1_HELLO | VERB_FLAG_HMAC; + header.verb = VERB_VL1_HELLO | VERB_FLAG_EXTENDED_AUTHENTICATION; header.version_proto = VERSION_PROTO; header.version_major = VERSION_MAJOR; header.version_minor = VERSION_MINOR; @@ -456,12 +468,9 @@ impl Peer { dict.set_str(HELLO_DICT_KEY_OS_NAME, std::env::consts::OS); } let mut flags = String::new(); - if node.fips_mode { + if node.fips_mode() { flags.push('F'); } - if node.wimp { - flags.push('w'); - } dict.set_str(HELLO_DICT_KEY_FLAGS, flags.as_str()); debug_assert!(dict.write_to(&mut packet).is_ok()); @@ -470,7 +479,9 @@ impl Peer { dict_aes.crypt_in_place(&mut packet.as_bytes_mut()[dict_start_position..]); drop(dict_aes); - debug_assert!(packet.append_bytes_fixed(&SHA384::hmac(self.static_secret_packet_hmac.as_ref(), &packet.as_bytes()[PACKET_HEADER_SIZE + 1..])).is_ok()); + debug_assert!(packet.append_u16(0).is_ok()); + + debug_assert!(packet.append_bytes_fixed(&SHA384::hmac(self.static_secret_packet_hmac.as_ref(), packet.as_bytes_starting_at(PACKET_HEADER_SIZE).unwrap())).is_ok()); let (_, mut poly) = salsa_poly_create(&self.static_secret, packet.struct_at::(0).unwrap(), packet.len()); poly.update(packet.as_bytes_starting_at(PACKET_HEADER_SIZE).unwrap()); @@ -497,10 +508,48 @@ impl Peer { fn receive_hello(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} #[inline(always)] - fn receive_error(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} + fn receive_error(&self, ci: &CI, ph: &PH, node: &Node, time_ticks: i64, source_path: &Arc, forward_secrecy: bool, payload: &Buffer<{ PACKET_SIZE_MAX }>) { + let mut cursor: usize = 0; + let _ = payload.read_struct::(&mut cursor).map(|error_header| { + let in_re_packet_id = error_header.in_re_packet_id; + let current_packet_id_counter = self.packet_id_counter.load(Ordering::Relaxed); + if current_packet_id_counter.checked_sub(in_re_packet_id).map_or_else(|| { + (!in_re_packet_id).wrapping_add(current_packet_id_counter) < PACKET_RESPONSE_COUNTER_DELTA_MAX + }, |packets_ago| { + packets_ago <= PACKET_RESPONSE_COUNTER_DELTA_MAX + }) { + match error_header.in_re_verb { + _ => { + ph.handle_error(self, source_path, forward_secrecy, error_header.in_re_verb, in_re_packet_id, error_header.error_code, payload, &mut cursor); + } + } + } + }); + } #[inline(always)] - fn receive_ok(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} + fn receive_ok(&self, ci: &CI, ph: &PH, node: &Node, time_ticks: i64, source_path: &Arc, forward_secrecy: bool, payload: &Buffer<{ PACKET_SIZE_MAX }>) { + let mut cursor: usize = 0; + let _ = payload.read_struct::(&mut cursor).map(|ok_header| { + let in_re_packet_id = ok_header.in_re_packet_id; + let current_packet_id_counter = self.packet_id_counter.load(Ordering::Relaxed); + if current_packet_id_counter.checked_sub(in_re_packet_id).map_or_else(|| { + (!in_re_packet_id).wrapping_add(current_packet_id_counter) < PACKET_RESPONSE_COUNTER_DELTA_MAX + }, |packets_ago| { + packets_ago <= PACKET_RESPONSE_COUNTER_DELTA_MAX + }) { + match ok_header.in_re_verb { + VERB_VL1_HELLO => { + } + VERB_VL1_WHOIS => { + } + _ => { + ph.handle_ok(self, source_path, forward_secrecy, ok_header.in_re_verb, in_re_packet_id, payload, &mut cursor); + } + } + } + }); + } #[inline(always)] fn receive_whois(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} @@ -518,9 +567,7 @@ impl Peer { fn receive_user_message(&self, ci: &CI, node: &Node, time_ticks: i64, source_path: &Arc, payload: &Buffer<{ PACKET_SIZE_MAX }>) {} /// Get current best path or None if there are no direct paths to this peer. - pub fn direct_path(&self) -> Option> { - self.paths.lock().last().map(|p| p.clone()) - } + pub fn direct_path(&self) -> Option> { self.paths.lock().first().map(|p| p.clone()) } /// Get either the current best direct path or an indirect path. pub fn path(&self, node: &Node) -> Option> { diff --git a/network-hypervisor/src/vl1/protocol.rs b/network-hypervisor/src/vl1/protocol.rs index e13f6db00..744fd81e7 100644 --- a/network-hypervisor/src/vl1/protocol.rs +++ b/network-hypervisor/src/vl1/protocol.rs @@ -131,8 +131,8 @@ pub const FRAGMENT_INDICATOR: u8 = 0xff; /// Verb (inner) flag indicating that the packet's payload (after the verb) is LZ4 compressed. pub const VERB_FLAG_COMPRESSED: u8 = 0x80; -/// Verb (inner) flag indicating that payload after verb is authenticated with HMAC-SHA384. -pub const VERB_FLAG_HMAC: u8 = 0x40; +/// Verb (inner) flag indicating that payload is authenticated with HMAC-SHA384. +pub const VERB_FLAG_EXTENDED_AUTHENTICATION: u8 = 0x40; /// Mask to get only the verb from the verb + verb flags byte. pub const VERB_MASK: u8 = 0x1f; @@ -146,8 +146,8 @@ pub const PROTOCOL_MAX_HOPS: u8 = 7; /// Maximum number of hops to allow. pub const FORWARD_MAX_HOPS: u8 = 3; -/// Maximum difference between an OK in-re packet ID and the current packet ID counter. -pub const OK_PACKET_SEQUENCE_CUTOFF: u64 = 1000; +/// Maximum difference between current packet ID counter and OK/ERROR in-re packet ID. +pub const PACKET_RESPONSE_COUNTER_DELTA_MAX: u64 = 1024; /// Frequency for WHOIS retries pub const WHOIS_RETRY_INTERVAL: i64 = 1000; @@ -267,6 +267,24 @@ impl FragmentHeader { pub(crate) mod message_component_structs { use crate::vl1::buffer::RawObject; + use crate::vl1::protocol::PacketID; + + #[repr(packed)] + pub struct OkHeader { + pub in_re_verb: u8, + pub in_re_packet_id: PacketID, + } + + unsafe impl RawObject for OkHeader {} + + #[repr(packed)] + pub struct ErrorHeader { + pub in_re_verb: u8, + pub in_re_packet_id: PacketID, + pub error_code: u8, + } + + unsafe impl RawObject for ErrorHeader {} #[repr(packed)] pub struct HelloFixedHeaderFields { @@ -300,6 +318,8 @@ mod tests { #[test] fn representation() { + assert_eq!(size_of::(), 9); + assert_eq!(size_of::(), 10); assert_eq!(size_of::(), PACKET_HEADER_SIZE); assert_eq!(size_of::(), FRAGMENT_HEADER_SIZE); diff --git a/network-hypervisor/src/vl1/rootset.rs b/network-hypervisor/src/vl1/rootset.rs index e4e6e388f..2cd51dcc3 100644 --- a/network-hypervisor/src/vl1/rootset.rs +++ b/network-hypervisor/src/vl1/rootset.rs @@ -103,10 +103,10 @@ pub struct Root { /// as at least one of the old roots is up to distribute the new ones. #[derive(PartialEq, Eq)] pub struct RootSet { - pub timestamp: i64, - pub name: String, - pub contact: String, - pub roots: BTreeSet, + timestamp: i64, + name: String, + contact: String, + roots: BTreeSet, signer: Vec, signature: Vec, root_set_type: Type, @@ -185,9 +185,9 @@ impl RootSet { buf.append_u8(ROOT_SET_TYPE_ED25519_P521)?; buf.append_u64(self.timestamp as u64)?; buf.append_u8(name.len() as u8)?; - buf.append_bytes(name); + buf.append_bytes(name)?; buf.append_u8(contact.len() as u8)?; - buf.append_bytes(contact); + buf.append_bytes(contact)?; if self.signer.len() != (ED25519_PUBLIC_KEY_SIZE + P521_PUBLIC_KEY_SIZE) { return Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "signer can only be 164 bytes")); } diff --git a/network-hypervisor/src/vl1/whois.rs b/network-hypervisor/src/vl1/whois.rs index 2f0b8ad92..36f17f0c2 100644 --- a/network-hypervisor/src/vl1/whois.rs +++ b/network-hypervisor/src/vl1/whois.rs @@ -19,21 +19,15 @@ struct WhoisQueueItem { retry_count: u16, } -pub(crate) struct WhoisQueue { - queue: Mutex> -} +pub(crate) struct WhoisQueue(Mutex>); impl WhoisQueue { pub(crate) const INTERVAL: i64 = WHOIS_RETRY_INTERVAL; - pub fn new() -> Self { - Self { - queue: Mutex::new(HashMap::new()) - } - } + pub fn new() -> Self { Self(Mutex::new(HashMap::new())) } pub fn query(&self, node: &Node, ci: &CI, target: Address, packet: Option) { - let mut q = self.queue.lock(); + let mut q = self.0.lock(); let qi = q.entry(target).or_insert_with(|| WhoisQueueItem { packet_queue: LinkedList::new(), @@ -55,14 +49,14 @@ impl WhoisQueue { /// Remove a WHOIS request from the queue and call the supplied function for all queued packets. pub fn response_received_get_packets(&self, address: Address, packet_handler: F) { - let mut qi = self.queue.lock().remove(&address); + let mut qi = self.0.lock().remove(&address); let _ = qi.map(|mut qi| qi.packet_queue.iter_mut().for_each(packet_handler)); } /// Called every INTERVAL during background tasks. pub fn on_interval(&self, node: &Node, ci: &CI, time_ticks: i64) { let mut targets: Vec
= Vec::new(); - self.queue.lock().retain(|target, qi| { + self.0.lock().retain(|target, qi| { if qi.retry_count < WHOIS_RETRY_MAX { if qi.retry_gate.gate(time_ticks) { qi.retry_count += 1;