mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-07 21:13:44 +02:00
Add both Valid and Verified typestates.
This commit is contained in:
parent
382688d251
commit
ec600f994a
6 changed files with 127 additions and 19 deletions
|
@ -96,20 +96,128 @@ where
|
|||
{
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("Verified").field(&self.0).finish()
|
||||
f.debug_tuple("Valid").field(&self.0).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Valid<T> {
|
||||
/// Strip the Verified typestate off this object.
|
||||
#[inline(always)]
|
||||
pub fn unwrap(self) -> T {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Set Verified typestate on an object.
|
||||
#[inline(always)]
|
||||
pub fn assume_verified(o: T) -> Self {
|
||||
pub fn wrap(o: T) -> Self {
|
||||
Self(o)
|
||||
}
|
||||
}
|
||||
|
||||
/// Typestate indicating that a credential or other object has been externally validated.
|
||||
///
|
||||
/// This is more appropriate for certificates signed by an external authority.
|
||||
#[repr(transparent)]
|
||||
pub struct Verified<T>(T);
|
||||
|
||||
impl<T> AsRef<T> for Verified<T> {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsMut<T> for Verified<T> {
|
||||
#[inline(always)]
|
||||
fn as_mut(&mut self) -> &mut T {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for Verified<T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for Verified<T> {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Verified<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialEq for Verified<T>
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.eq(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Eq for Verified<T> where T: Eq {}
|
||||
|
||||
impl<T> Ord for Verified<T>
|
||||
where
|
||||
T: Ord,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.0.cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialOrd for Verified<T>
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
self.0.partial_cmp(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Hash for Verified<T>
|
||||
where
|
||||
T: Hash,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Debug for Verified<T>
|
||||
where
|
||||
T: Debug,
|
||||
{
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("Valid").field(&self.0).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Verified<T> {
|
||||
#[inline(always)]
|
||||
pub fn unwrap(self) -> T {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn wrap(o: T) -> Self {
|
||||
Self(o)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -206,7 +206,7 @@ impl Identity {
|
|||
assert!(id.upgrade().is_ok());
|
||||
assert!(id.p384.is_some() && id.secret.as_ref().unwrap().p384.is_some());
|
||||
|
||||
Valid::assume_verified(id)
|
||||
Valid::wrap(id)
|
||||
}
|
||||
|
||||
/// Upgrade older x25519-only identities to hybrid identities with both x25519 and NIST P-384 curves.
|
||||
|
@ -321,7 +321,7 @@ impl Identity {
|
|||
zt_address_derivation_work_function(&mut digest);
|
||||
|
||||
return if digest[0] < IDENTITY_POW_THRESHOLD && Address::from_bytes(&digest[59..64]).map_or(false, |a| a == self.address) {
|
||||
Some(Valid::assume_verified(self))
|
||||
Some(Valid::wrap(self))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
|
@ -17,9 +17,9 @@ use crate::vl1::identity::Identity;
|
|||
use crate::vl1::path::{Path, PathServiceResult};
|
||||
use crate::vl1::peer::Peer;
|
||||
use crate::vl1::rootset::RootSet;
|
||||
use crate::vl1::Valid;
|
||||
|
||||
use zerotier_crypto::random;
|
||||
use zerotier_crypto::typestate::{Valid, Verified};
|
||||
use zerotier_utils::error::InvalidParameterError;
|
||||
use zerotier_utils::gate::IntervalGate;
|
||||
use zerotier_utils::hex;
|
||||
|
@ -207,7 +207,7 @@ pub trait InnerProtocolLayer: Sync + Send {
|
|||
|
||||
struct RootInfo {
|
||||
/// Root sets to which we are a member.
|
||||
sets: HashMap<String, Valid<RootSet>>,
|
||||
sets: HashMap<String, Verified<RootSet>>,
|
||||
|
||||
/// Root peers and their statically defined endpoints (from root sets).
|
||||
roots: HashMap<Arc<Peer>, Vec<Endpoint>>,
|
||||
|
@ -352,7 +352,7 @@ impl Node {
|
|||
|
||||
/// Add a new root set or update the existing root set if the new root set is newer and otherwise matches.
|
||||
#[inline]
|
||||
pub fn add_update_root_set(&self, rs: Valid<RootSet>) -> bool {
|
||||
pub fn add_update_root_set(&self, rs: Verified<RootSet>) -> bool {
|
||||
let mut roots = self.roots.write().unwrap();
|
||||
if let Some(entry) = roots.sets.get_mut(&rs.name) {
|
||||
if rs.should_replace(entry) {
|
||||
|
@ -468,7 +468,7 @@ impl Node {
|
|||
if let Some(peer) = peers.get(&m.identity.address) {
|
||||
new_roots.insert(peer.clone(), m.endpoints.as_ref().unwrap().iter().cloned().collect());
|
||||
} else {
|
||||
if let Some(peer) = Peer::new(&self.identity, Valid::assume_verified(m.identity.clone()), time_ticks) {
|
||||
if let Some(peer) = Peer::new(&self.identity, Valid::wrap(m.identity.clone()), time_ticks) {
|
||||
drop(peers);
|
||||
new_roots.insert(
|
||||
self.peers
|
||||
|
@ -967,7 +967,7 @@ impl Node {
|
|||
/// This will only replace an existing root set with a newer one. It won't add a new root set, which must be
|
||||
/// done by an authorized user or administrator not just by a root.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn on_remote_update_root_set(&self, received_from: &Identity, rs: Valid<RootSet>) {
|
||||
pub(crate) fn on_remote_update_root_set(&self, received_from: &Identity, rs: Verified<RootSet>) {
|
||||
let mut roots = self.roots.write().unwrap();
|
||||
if let Some(entry) = roots.sets.get_mut(&rs.name) {
|
||||
if entry.members.iter().any(|m| m.identity.eq(received_from)) && rs.should_replace(entry) {
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::io::Write;
|
|||
use crate::vl1::identity::{Identity, IDENTITY_MAX_SIGNATURE_SIZE};
|
||||
use crate::vl1::Endpoint;
|
||||
|
||||
use zerotier_crypto::typestate::Valid;
|
||||
use zerotier_crypto::typestate::{Valid, Verified};
|
||||
use zerotier_utils::arrayvec::ArrayVec;
|
||||
use zerotier_utils::buffer::Buffer;
|
||||
use zerotier_utils::marshalable::{Marshalable, UnmarshalError};
|
||||
|
@ -91,7 +91,7 @@ impl RootSet {
|
|||
}
|
||||
|
||||
/// Get the ZeroTier default root set, which contains roots run by ZeroTier Inc.
|
||||
pub fn zerotier_default() -> Valid<Self> {
|
||||
pub fn zerotier_default() -> Verified<Self> {
|
||||
let mut cursor = 0;
|
||||
let rs = include_bytes!("../../default-rootset/root.zerotier.com.bin");
|
||||
//let rs = include_bytes!("../../default-rootset/test-root.bin");
|
||||
|
@ -107,7 +107,7 @@ impl RootSet {
|
|||
}
|
||||
|
||||
/// Verify signatures present in this root cluster definition.
|
||||
pub fn verify(self) -> Option<Valid<Self>> {
|
||||
pub fn verify(self) -> Option<Verified<Self>> {
|
||||
if self.members.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ impl RootSet {
|
|||
}
|
||||
}
|
||||
|
||||
return Some(Valid::assume_verified(self));
|
||||
return Some(Verified::wrap(self));
|
||||
}
|
||||
|
||||
/// Add a member to this definition, replacing any current entry with this address.
|
||||
|
|
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use zerotier_crypto::hash::SHA384;
|
||||
use zerotier_crypto::secure_eq;
|
||||
use zerotier_crypto::typestate::Valid;
|
||||
use zerotier_crypto::typestate::Verified;
|
||||
use zerotier_utils::arrayvec::ArrayVec;
|
||||
use zerotier_utils::blob::Blob;
|
||||
use zerotier_utils::error::InvalidParameterError;
|
||||
|
@ -171,13 +171,13 @@ impl CertificateOfMembership {
|
|||
}
|
||||
|
||||
/// Verify this certificate of membership.
|
||||
pub fn verify(self, issuer: &Identity, expect_issued_to: &Identity) -> Option<Valid<Self>> {
|
||||
pub fn verify(self, issuer: &Identity, expect_issued_to: &Identity) -> Option<Verified<Self>> {
|
||||
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(Valid::assume_verified(self));
|
||||
return Some(Verified::wrap(self));
|
||||
}
|
||||
}
|
||||
return None;
|
||||
|
|
|
@ -31,7 +31,7 @@ pub fn load_node_identity(base_path: &Path) -> Option<Valid<Identity>> {
|
|||
if id_data.is_err() {
|
||||
return None;
|
||||
}
|
||||
Some(Valid::assume_verified(id_data.unwrap()))
|
||||
Some(Valid::wrap(id_data.unwrap()))
|
||||
}
|
||||
|
||||
pub fn save_node_identity(base_path: &Path, id: &Valid<Identity>) -> bool {
|
||||
|
|
Loading…
Add table
Reference in a new issue