diff --git a/controller/src/controller.rs b/controller/src/controller.rs index acc07024b..26079a107 100644 --- a/controller/src/controller.rs +++ b/controller/src/controller.rs @@ -6,6 +6,7 @@ use std::sync::{Arc, Mutex, RwLock, Weak}; use tokio::time::{Duration, Instant}; +use zerotier_crypto::secure_eq; use zerotier_network_hypervisor::protocol; use zerotier_network_hypervisor::protocol::{PacketBuffer, DEFAULT_MULTICAST_LIMIT, ZEROTIER_VIRTUAL_NETWORK_DEFAULT_MTU}; use zerotier_network_hypervisor::vl1::*; @@ -292,7 +293,7 @@ impl Controller { } if let Some(pinned_fingerprint) = member.identity_fingerprint.as_ref() { - if pinned_fingerprint.as_bytes().eq(&source_identity.fingerprint) { + if secure_eq(pinned_fingerprint.as_bytes(), &source_identity.fingerprint) { if member.identity.is_none() { // Learn the FULL identity if the fingerprint is pinned and they match. This // lets us add members by address/fingerprint with full SHA384 identity @@ -370,12 +371,12 @@ impl Controller { // Make sure these agree. It should be impossible to end up with a member that's authorized and // whose identity and identity fingerprint don't match. - if !member + if !secure_eq(&member .identity .as_ref() .unwrap() - .fingerprint - .eq(member.identity_fingerprint.as_ref().unwrap().as_bytes()) + .fingerprint, + member.identity_fingerprint.as_ref().unwrap().as_bytes()) { debug_assert!(false); return Ok((AuthenticationResult::RejectedDueToError, None)); diff --git a/controller/src/database.rs b/controller/src/database.rs index d7d37bc23..74fde0118 100644 --- a/controller/src/database.rs +++ b/controller/src/database.rs @@ -1,5 +1,6 @@ use async_trait::async_trait; +use zerotier_crypto::secure_eq; use zerotier_network_hypervisor::vl1::{Address, InetAddress, NodeStorage}; use zerotier_network_hypervisor::vl2::NetworkId; @@ -70,7 +71,7 @@ pub trait Database: Sync + Send + NodeStorage + 'static { let members = self.list_members(network_id).await?; for a in members.iter() { if let Some(m) = self.get_member(network_id, *a).await? { - if m.ip_assignments.iter().any(|ip2| ip2.ip_bytes().eq(ip.ip_bytes())) { + if m.ip_assignments.iter().any(|ip2| secure_eq(ip2.ip_bytes(), ip.ip_bytes())) { return Ok(true); } } diff --git a/controller/src/postgresdatabase.rs b/controller/src/postgresdatabase.rs index 94de12de8..94f208b08 100644 --- a/controller/src/postgresdatabase.rs +++ b/controller/src/postgresdatabase.rs @@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize}; use tokio_postgres::types::Type; use tokio_postgres::{Client, Statement}; +use zerotier_crypto::secure_eq; use zerotier_crypto::verified::Verified; use zerotier_network_hypervisor::vl1::{Address, Identity, InetAddress, NodeStorage}; @@ -434,7 +435,7 @@ impl Database for PostgresDatabase { let members = self.list_members(network_id).await?; for a in members.iter() { if let Some(m) = self.get_member(network_id, *a).await? { - if m.ip_assignments.iter().any(|ip2| ip2.ip_bytes().eq(ip.ip_bytes())) { + if m.ip_assignments.iter().any(|ip2| secure_eq(ip2.ip_bytes(), ip.ip_bytes())) { return Ok(true); } } diff --git a/crypto/src/aes.rs b/crypto/src/aes.rs index 3a8f9d142..37446dfb3 100644 --- a/crypto/src/aes.rs +++ b/crypto/src/aes.rs @@ -6,6 +6,8 @@ mod fruit_flavored { use std::os::raw::{c_int, c_void}; use std::ptr::{null, null_mut}; + use crate::secure_eq; + #[allow(non_upper_case_globals, unused)] const kCCModeECB: i32 = 1; #[allow(non_upper_case_globals, unused)] @@ -288,7 +290,7 @@ mod fruit_flavored { #[inline(always)] pub fn finish_decrypt(&mut self, expected_tag: &[u8]) -> bool { - self.finish_encrypt().eq(expected_tag) + secure_eq(&self.finish_encrypt(), expected_tag) } } diff --git a/crypto/src/p384.rs b/crypto/src/p384.rs index dcf5c48ab..4baea80d9 100644 --- a/crypto/src/p384.rs +++ b/crypto/src/p384.rs @@ -32,6 +32,7 @@ mod openssl_based { use crate::hash::SHA384; use crate::secret::Secret; + use crate::secure_eq; use super::{P384_ECDH_SHARED_SECRET_SIZE, P384_ECDSA_SIGNATURE_SIZE, P384_PUBLIC_KEY_SIZE, P384_SECRET_KEY_SIZE}; @@ -213,7 +214,7 @@ mod openssl_based { impl PartialEq for P384KeyPair { fn eq(&self, other: &Self) -> bool { - self.pair.private_key().eq(other.pair.private_key()) && self.public.bytes.eq(&other.public.bytes) + self.pair.private_key().eq(other.pair.private_key()) && secure_eq(&self.public.bytes, &other.public.bytes) } } @@ -1355,7 +1356,7 @@ pub use openssl_based::*; #[cfg(test)] mod tests { - use crate::p384::P384KeyPair; + use crate::{p384::P384KeyPair, secure_eq}; #[test] fn generate_sign_verify_agree() { @@ -1372,7 +1373,7 @@ mod tests { let sec0 = kp.agree(kp2.public_key()).unwrap(); let sec1 = kp2.agree(kp.public_key()).unwrap(); - if !sec0.eq(&sec1) { + if !secure_eq(&sec0, &sec1) { panic!("ECDH secrets do not match"); } diff --git a/network-hypervisor/src/vl1/identity.rs b/network-hypervisor/src/vl1/identity.rs index 0a7d5fdea..c28033b2b 100644 --- a/network-hypervisor/src/vl1/identity.rs +++ b/network-hypervisor/src/vl1/identity.rs @@ -9,7 +9,7 @@ use std::str::FromStr; use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use zerotier_crypto::hash::*; +use zerotier_crypto::{hash::*, secure_eq}; use zerotier_crypto::p384::*; use zerotier_crypto::salsa::Salsa; use zerotier_crypto::secret::Secret; @@ -801,7 +801,7 @@ impl Marshalable for Identity { impl PartialEq for Identity { #[inline(always)] fn eq(&self, other: &Self) -> bool { - self.fingerprint.eq(&other.fingerprint) + secure_eq(&self.fingerprint, &other.fingerprint) } } @@ -904,17 +904,17 @@ mod tests { ) .unwrap().validate().unwrap(); let self_agree = id.agree(&id).unwrap(); - assert!(self_agree_expected.as_slice().eq(&self_agree.as_bytes()[..48])); + debug_assert!(self_agree_expected.as_slice().eq(&self_agree.as_bytes()[..48])); // Identity should be upgradable. let mut upgraded = id.clone(); - assert!(upgraded.upgrade().unwrap()); + debug_assert!(upgraded.upgrade().unwrap()); // Upgraded identity should generate the same result when agreeing with the old non-upgraded identity. let self_agree = id.agree(&upgraded).unwrap(); - assert!(self_agree_expected.as_slice().eq(&self_agree.as_bytes()[..48])); + debug_assert!(self_agree_expected.as_slice().eq(&self_agree.as_bytes()[..48])); let self_agree = upgraded.agree(&id).unwrap(); - assert!(self_agree_expected.as_slice().eq(&self_agree.as_bytes()[..48])); + debug_assert!(self_agree_expected.as_slice().eq(&self_agree.as_bytes()[..48])); } const GOOD_V0_IDENTITIES: [&'static str; 4] = [ @@ -936,7 +936,7 @@ mod tests { assert!(gen.agree(&gen).is_some()); let bytes = gen.to_secret_bytes().unwrap(); let string = gen.to_secret_string(); - assert!(Identity::from_str(string.as_str()).unwrap().eq(&gen)); + debug_assert!(Identity::from_str(string.as_str()).unwrap().eq(&gen)); let gen_unmarshaled = Identity::from_bytes(bytes.as_bytes()).unwrap(); assert!(gen_unmarshaled.secret.is_some()); diff --git a/network-hypervisor/src/vl2/v1/certificateofmembership.rs b/network-hypervisor/src/vl2/v1/certificateofmembership.rs index eb24a888e..7c0261088 100644 --- a/network-hypervisor/src/vl2/v1/certificateofmembership.rs +++ b/network-hypervisor/src/vl2/v1/certificateofmembership.rs @@ -7,6 +7,7 @@ use crate::vl2::NetworkId; use serde::{Deserialize, Serialize}; use zerotier_crypto::hash::SHA384; +use zerotier_crypto::secure_eq; use zerotier_crypto::verified::Verified; use zerotier_utils::arrayvec::ArrayVec; use zerotier_utils::blob::Blob; @@ -171,7 +172,7 @@ impl CertificateOfMembership { /// Verify this certificate of membership. pub fn verify(self, issuer: &Identity, expect_issued_to: &Identity) -> Option> { - if Self::v1_proto_issued_to_fingerprint(expect_issued_to).eq(&self.issued_to_fingerprint.as_bytes()[..32]) { + if secure_eq(&Self::v1_proto_issued_to_fingerprint(expect_issued_to), &self.issued_to_fingerprint.as_bytes()[..32]) { if issuer.verify(&self.v1_proto_get_qualifier_bytes(), self.signature.as_bytes()) { return Some(Verified::assume_verified(self)); }