Add both Valid and Verified typestates.

This commit is contained in:
Adam Ierymenko 2023-01-03 17:58:28 -05:00
parent 382688d251
commit ec600f994a
6 changed files with 127 additions and 19 deletions

View file

@ -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)
}
}

View file

@ -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
};

View file

@ -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) {

View file

@ -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.

View file

@ -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;

View file

@ -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 {