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]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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> {
|
impl<T> Valid<T> {
|
||||||
/// Strip the Verified typestate off this object.
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn unwrap(self) -> T {
|
pub fn unwrap(self) -> T {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set Verified typestate on an object.
|
|
||||||
#[inline(always)]
|
#[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)
|
Self(o)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,7 +206,7 @@ impl Identity {
|
||||||
assert!(id.upgrade().is_ok());
|
assert!(id.upgrade().is_ok());
|
||||||
assert!(id.p384.is_some() && id.secret.as_ref().unwrap().p384.is_some());
|
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.
|
/// 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);
|
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) {
|
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 {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,9 +17,9 @@ use crate::vl1::identity::Identity;
|
||||||
use crate::vl1::path::{Path, PathServiceResult};
|
use crate::vl1::path::{Path, PathServiceResult};
|
||||||
use crate::vl1::peer::Peer;
|
use crate::vl1::peer::Peer;
|
||||||
use crate::vl1::rootset::RootSet;
|
use crate::vl1::rootset::RootSet;
|
||||||
use crate::vl1::Valid;
|
|
||||||
|
|
||||||
use zerotier_crypto::random;
|
use zerotier_crypto::random;
|
||||||
|
use zerotier_crypto::typestate::{Valid, Verified};
|
||||||
use zerotier_utils::error::InvalidParameterError;
|
use zerotier_utils::error::InvalidParameterError;
|
||||||
use zerotier_utils::gate::IntervalGate;
|
use zerotier_utils::gate::IntervalGate;
|
||||||
use zerotier_utils::hex;
|
use zerotier_utils::hex;
|
||||||
|
@ -207,7 +207,7 @@ pub trait InnerProtocolLayer: Sync + Send {
|
||||||
|
|
||||||
struct RootInfo {
|
struct RootInfo {
|
||||||
/// Root sets to which we are a member.
|
/// 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).
|
/// Root peers and their statically defined endpoints (from root sets).
|
||||||
roots: HashMap<Arc<Peer>, Vec<Endpoint>>,
|
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.
|
/// Add a new root set or update the existing root set if the new root set is newer and otherwise matches.
|
||||||
#[inline]
|
#[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();
|
let mut roots = self.roots.write().unwrap();
|
||||||
if let Some(entry) = roots.sets.get_mut(&rs.name) {
|
if let Some(entry) = roots.sets.get_mut(&rs.name) {
|
||||||
if rs.should_replace(entry) {
|
if rs.should_replace(entry) {
|
||||||
|
@ -468,7 +468,7 @@ impl Node {
|
||||||
if let Some(peer) = peers.get(&m.identity.address) {
|
if let Some(peer) = peers.get(&m.identity.address) {
|
||||||
new_roots.insert(peer.clone(), m.endpoints.as_ref().unwrap().iter().cloned().collect());
|
new_roots.insert(peer.clone(), m.endpoints.as_ref().unwrap().iter().cloned().collect());
|
||||||
} else {
|
} 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);
|
drop(peers);
|
||||||
new_roots.insert(
|
new_roots.insert(
|
||||||
self.peers
|
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
|
/// 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.
|
/// done by an authorized user or administrator not just by a root.
|
||||||
#[allow(unused)]
|
#[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();
|
let mut roots = self.roots.write().unwrap();
|
||||||
if let Some(entry) = roots.sets.get_mut(&rs.name) {
|
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) {
|
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::identity::{Identity, IDENTITY_MAX_SIGNATURE_SIZE};
|
||||||
use crate::vl1::Endpoint;
|
use crate::vl1::Endpoint;
|
||||||
|
|
||||||
use zerotier_crypto::typestate::Valid;
|
use zerotier_crypto::typestate::{Valid, Verified};
|
||||||
use zerotier_utils::arrayvec::ArrayVec;
|
use zerotier_utils::arrayvec::ArrayVec;
|
||||||
use zerotier_utils::buffer::Buffer;
|
use zerotier_utils::buffer::Buffer;
|
||||||
use zerotier_utils::marshalable::{Marshalable, UnmarshalError};
|
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.
|
/// 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 mut cursor = 0;
|
||||||
let rs = include_bytes!("../../default-rootset/root.zerotier.com.bin");
|
let rs = include_bytes!("../../default-rootset/root.zerotier.com.bin");
|
||||||
//let rs = include_bytes!("../../default-rootset/test-root.bin");
|
//let rs = include_bytes!("../../default-rootset/test-root.bin");
|
||||||
|
@ -107,7 +107,7 @@ impl RootSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify signatures present in this root cluster definition.
|
/// 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() {
|
if self.members.is_empty() {
|
||||||
return None;
|
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.
|
/// 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::hash::SHA384;
|
||||||
use zerotier_crypto::secure_eq;
|
use zerotier_crypto::secure_eq;
|
||||||
use zerotier_crypto::typestate::Valid;
|
use zerotier_crypto::typestate::Verified;
|
||||||
use zerotier_utils::arrayvec::ArrayVec;
|
use zerotier_utils::arrayvec::ArrayVec;
|
||||||
use zerotier_utils::blob::Blob;
|
use zerotier_utils::blob::Blob;
|
||||||
use zerotier_utils::error::InvalidParameterError;
|
use zerotier_utils::error::InvalidParameterError;
|
||||||
|
@ -171,13 +171,13 @@ impl CertificateOfMembership {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify this certificate of membership.
|
/// 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(
|
if secure_eq(
|
||||||
&Self::v1_proto_issued_to_fingerprint(expect_issued_to),
|
&Self::v1_proto_issued_to_fingerprint(expect_issued_to),
|
||||||
&self.issued_to_fingerprint.as_bytes()[..32],
|
&self.issued_to_fingerprint.as_bytes()[..32],
|
||||||
) {
|
) {
|
||||||
if issuer.verify(&self.v1_proto_get_qualifier_bytes(), self.signature.as_bytes()) {
|
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;
|
return None;
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub fn load_node_identity(base_path: &Path) -> Option<Valid<Identity>> {
|
||||||
if id_data.is_err() {
|
if id_data.is_err() {
|
||||||
return None;
|
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 {
|
pub fn save_node_identity(base_path: &Path, id: &Valid<Identity>) -> bool {
|
||||||
|
|
Loading…
Add table
Reference in a new issue