From 7f909a06b928a065de07e1200667d413e1719337 Mon Sep 17 00:00:00 2001 From: John Smith Date: Thu, 20 Apr 2023 11:47:54 -0400 Subject: [PATCH] refactor rpc validation --- veilid-core/proto/veilid.capnp | 2 +- .../src/crypto/types/crypto_typed_set.rs | 22 ++++ veilid-core/src/crypto/types/mod.rs | 2 + veilid-core/src/network_manager/mod.rs | 4 +- .../tests/test_signed_node_info.rs | 100 +++++++----------- veilid-core/src/routing_table/bucket_entry.rs | 44 +++++--- veilid-core/src/routing_table/mod.rs | 10 +- veilid-core/src/routing_table/node_ref.rs | 8 +- veilid-core/src/routing_table/privacy.rs | 37 ++++++- .../route_spec_store/route_spec_store.rs | 4 +- .../src/routing_table/routing_domains.rs | 57 +++++----- .../src/routing_table/routing_table_inner.rs | 25 +++-- .../routing_table/tasks/relay_management.rs | 4 +- .../src/routing_table/types/node_info.rs | 53 ++++++++-- .../src/routing_table/types/peer_info.rs | 21 +++- .../types/signed_direct_node_info.rs | 47 ++++---- .../routing_table/types/signed_node_info.rs | 31 ++++-- .../types/signed_relayed_node_info.rs | 78 ++++++++++---- .../src/rpc_processor/coders/node_info.rs | 24 ++--- .../rpc_processor/coders/operations/answer.rs | 39 ++++--- .../coders/operations/operation.rs | 37 ++++--- .../coders/operations/operation_app_call.rs | 4 + .../coders/operations/operation_find_block.rs | 5 +- .../coders/operations/operation_find_node.rs | 12 ++- .../coders/operations/operation_get_value.rs | 22 ++-- .../coders/operations/operation_route.rs | 3 +- .../coders/operations/operation_set_value.rs | 3 +- .../coders/operations/operation_signal.rs | 3 +- .../coders/operations/operation_status.rs | 7 ++ .../operations/operation_supply_block.rs | 5 +- .../operations/operation_watch_value.rs | 3 +- .../coders/operations/question.rs | 26 ++++- .../coders/operations/respond_to.rs | 14 ++- .../coders/operations/statement.rs | 25 +++-- .../src/rpc_processor/coders/peer_info.rs | 13 +-- .../coders/private_safety_route.rs | 13 +-- .../src/rpc_processor/coders/signal_info.rs | 5 +- .../coders/signed_direct_node_info.rs | 17 +-- .../rpc_processor/coders/signed_node_info.rs | 6 +- .../coders/signed_relayed_node_info.rs | 38 ++----- .../rpc_processor/coders/signed_value_data.rs | 8 +- .../coders/signed_value_descriptor.rs | 10 +- .../src/rpc_processor/coders/value_detail.rs | 20 +++- veilid-core/src/rpc_processor/mod.rs | 14 ++- .../src/rpc_processor/rpc_find_node.rs | 2 +- veilid-core/src/rpc_processor/rpc_route.rs | 15 ++- veilid-core/src/storage_manager/mod.rs | 30 +++--- veilid-core/src/storage_manager/types/mod.rs | 9 ++ .../{ => types}/signed_value_data.rs | 31 +++--- .../{ => types}/signed_value_descriptor.rs | 27 +++-- .../src/storage_manager/types/value_detail.rs | 77 ++++++++++++++ .../src/storage_manager/value_detail.rs | 43 -------- 52 files changed, 729 insertions(+), 430 deletions(-) create mode 100644 veilid-core/src/storage_manager/types/mod.rs rename veilid-core/src/storage_manager/{ => types}/signed_value_data.rs (83%) rename veilid-core/src/storage_manager/{ => types}/signed_value_descriptor.rs (75%) create mode 100644 veilid-core/src/storage_manager/types/value_detail.rs delete mode 100644 veilid-core/src/storage_manager/value_detail.rs diff --git a/veilid-core/proto/veilid.capnp b/veilid-core/proto/veilid.capnp index fc42116b..5197fe64 100644 --- a/veilid-core/proto/veilid.capnp +++ b/veilid-core/proto/veilid.capnp @@ -367,7 +367,7 @@ struct OperationSetValueQ @0xbac06191ff8bdbc5 { struct OperationSetValueA @0x9378d0732dc95be2 { union { schemaError @0 :Void; # Either the schema is not available at the node, or the data does not match the schema that is there - value @1 :ValueDetail; # the new value if successful, may be a different value than what was set if the seq number was lower or equal + value @1 :ValueDetail; # the new value if successful, may be a different value than what was set if the seq number was lower or equal peers @2 :List(PeerInfo); # returned 'closer peer' information if this node is refusing to store the key } } diff --git a/veilid-core/src/crypto/types/crypto_typed_set.rs b/veilid-core/src/crypto/types/crypto_typed_set.rs index 19932b67..3906d559 100644 --- a/veilid-core/src/crypto/types/crypto_typed_set.rs +++ b/veilid-core/src/crypto/types/crypto_typed_set.rs @@ -282,6 +282,28 @@ where tks } } +impl From<&[CryptoTyped]> for CryptoTypedSet +where + K: Clone + + Copy + + fmt::Debug + + fmt::Display + + FromStr + + PartialEq + + Eq + + PartialOrd + + Ord + + Hash + + RkyvArchive + + Encodable, + ::Archived: Hash + PartialEq + Eq, +{ + fn from(x: &[CryptoTyped]) -> Self { + let mut tks = CryptoTypedSet::::with_capacity(x.len()); + tks.add_all(x); + tks + } +} impl Into>> for CryptoTypedSet where K: Clone diff --git a/veilid-core/src/crypto/types/mod.rs b/veilid-core/src/crypto/types/mod.rs index a7142d8f..0c9b76d2 100644 --- a/veilid-core/src/crypto/types/mod.rs +++ b/veilid-core/src/crypto/types/mod.rs @@ -58,3 +58,5 @@ pub type TypedSignature = CryptoTyped; pub type TypedKeySet = CryptoTypedSet; pub type TypedSecretSet = CryptoTypedSet; +pub type TypedKeyPairSet = CryptoTypedSet; +pub type TypedSignatureSet = CryptoTypedSet; diff --git a/veilid-core/src/network_manager/mod.rs b/veilid-core/src/network_manager/mod.rs index d02bdea3..14e4153c 100644 --- a/veilid-core/src/network_manager/mod.rs +++ b/veilid-core/src/network_manager/mod.rs @@ -463,7 +463,7 @@ impl NetworkManager { will_validate_dial_info: false, }; }; - let own_node_info = own_peer_info.signed_node_info.node_info(); + let own_node_info = own_peer_info.signed_node_info().node_info(); let will_route = own_node_info.can_inbound_relay(); // xxx: eventually this may have more criteria added let will_tunnel = own_node_info.can_inbound_relay(); // xxx: we may want to restrict by battery life and network bandwidth at some point @@ -490,7 +490,7 @@ impl NetworkManager { }; }; - let own_node_info = own_peer_info.signed_node_info.node_info(); + let own_node_info = own_peer_info.signed_node_info().node_info(); let will_relay = own_node_info.can_inbound_relay(); let will_validate_dial_info = own_node_info.can_validate_dial_info(); diff --git a/veilid-core/src/network_manager/tests/test_signed_node_info.rs b/veilid-core/src/network_manager/tests/test_signed_node_info.rs index ff1db400..bab0a6e1 100644 --- a/veilid-core/src/network_manager/tests/test_signed_node_info.rs +++ b/veilid-core/src/network_manager/tests/test_signed_node_info.rs @@ -34,50 +34,39 @@ pub async fn test_signed_node_info() { node_info.clone(), ) .unwrap(); - let mut tks: TypedKeySet = TypedKey::new(ck, keypair.key).into(); + let tks: TypedKeySet = TypedKey::new(ck, keypair.key).into(); let oldtkslen = tks.len(); - let _ = SignedDirectNodeInfo::new( - crypto.clone(), - &mut tks, + let sdni = SignedDirectNodeInfo::new( node_info.clone(), - sni.timestamp, - sni.signatures.clone(), - ) - .unwrap(); - assert_eq!(tks.len(), oldtkslen); - assert_eq!(tks.len(), sni.signatures.len()); + sni.timestamp(), + sni.signatures().to_vec(), + ); + let tks_validated = sdni.validate(&tks, crypto.clone()).unwrap(); + assert_eq!(tks_validated.len(), oldtkslen); + assert_eq!(tks_validated.len(), sni.signatures().len()); // Test incorrect validation let keypair1 = vcrypto.generate_keypair(); - let mut tks1: TypedKeySet = TypedKey::new(ck, keypair1.key).into(); + let tks1: TypedKeySet = TypedKey::new(ck, keypair1.key).into(); let oldtks1len = tks1.len(); - let _ = SignedDirectNodeInfo::new( - crypto.clone(), - &mut tks1, + let sdni = SignedDirectNodeInfo::new( node_info.clone(), - sni.timestamp, - sni.signatures.clone(), - ) - .unwrap_err(); - assert_eq!(tks1.len(), oldtks1len); - assert_eq!(tks1.len(), sni.signatures.len()); + sni.timestamp(), + sni.signatures().to_vec(), + ); + sdni.validate(&tks1, crypto.clone()).unwrap_err(); // Test unsupported cryptosystem validation let fake_crypto_kind: CryptoKind = FourCC::from([0, 1, 2, 3]); let mut tksfake: TypedKeySet = TypedKey::new(fake_crypto_kind, PublicKey::default()).into(); - let mut sigsfake = sni.signatures.clone(); + let mut sigsfake = sni.signatures().to_vec(); sigsfake.push(TypedSignature::new(fake_crypto_kind, Signature::default())); tksfake.add(TypedKey::new(ck, keypair.key)); - let sdnifake = SignedDirectNodeInfo::new( - crypto.clone(), - &mut tksfake, - node_info.clone(), - sni.timestamp, - sigsfake.clone(), - ) - .unwrap(); - assert_eq!(tksfake.len(), 1); - assert_eq!(sdnifake.signatures.len(), sigsfake.len()); + let sdnifake = + SignedDirectNodeInfo::new(node_info.clone(), sni.timestamp(), sigsfake.clone()); + let tksfake_validated = sdnifake.validate(&tksfake, crypto.clone()).unwrap(); + assert_eq!(tksfake_validated.len(), 1); + assert_eq!(sdnifake.signatures().len(), sigsfake.len()); // Test relayed let node_info2 = NodeInfo { @@ -94,7 +83,7 @@ pub async fn test_signed_node_info() { // Test correct validation let keypair2 = vcrypto.generate_keypair(); - let mut tks2: TypedKeySet = TypedKey::new(ck, keypair2.key).into(); + let tks2: TypedKeySet = TypedKey::new(ck, keypair2.key).into(); let oldtks2len = tks2.len(); let sni2 = SignedRelayedNodeInfo::make_signatures( @@ -105,58 +94,49 @@ pub async fn test_signed_node_info() { sni.clone(), ) .unwrap(); - let _ = SignedRelayedNodeInfo::new( - crypto.clone(), - &mut tks2, + let srni = SignedRelayedNodeInfo::new( node_info2.clone(), tks.clone(), sni.clone(), - sni2.timestamp, - sni2.signatures.clone(), - ) - .unwrap(); + sni2.timestamp(), + sni2.signatures().to_vec(), + ); + let tks2_validated = srni.validate(&tks2, crypto.clone()).unwrap(); - assert_eq!(tks2.len(), oldtks2len); - assert_eq!(tks2.len(), sni2.signatures.len()); + assert_eq!(tks2_validated.len(), oldtks2len); + assert_eq!(tks2_validated.len(), sni2.signatures().len()); // Test incorrect validation let keypair3 = vcrypto.generate_keypair(); - let mut tks3: TypedKeySet = TypedKey::new(ck, keypair3.key).into(); + let tks3: TypedKeySet = TypedKey::new(ck, keypair3.key).into(); let oldtks3len = tks3.len(); - let _ = SignedRelayedNodeInfo::new( - crypto.clone(), - &mut tks3, + let srni = SignedRelayedNodeInfo::new( node_info2.clone(), tks.clone(), sni.clone(), - sni2.timestamp, - sni2.signatures.clone(), - ) - .unwrap_err(); - - assert_eq!(tks3.len(), oldtks3len); - assert_eq!(tks3.len(), sni2.signatures.len()); + sni2.timestamp(), + sni2.signatures().to_vec(), + ); + srni.validate(&tks3, crypto.clone()).unwrap_err(); // Test unsupported cryptosystem validation let fake_crypto_kind: CryptoKind = FourCC::from([0, 1, 2, 3]); let mut tksfake3: TypedKeySet = TypedKey::new(fake_crypto_kind, PublicKey::default()).into(); - let mut sigsfake3 = sni2.signatures.clone(); + let mut sigsfake3 = sni2.signatures().to_vec(); sigsfake3.push(TypedSignature::new(fake_crypto_kind, Signature::default())); tksfake3.add(TypedKey::new(ck, keypair2.key)); let srnifake = SignedRelayedNodeInfo::new( - crypto.clone(), - &mut tksfake3, node_info2.clone(), tks.clone(), sni.clone(), - sni2.timestamp, + sni2.timestamp(), sigsfake3.clone(), - ) - .unwrap(); - assert_eq!(tksfake3.len(), 1); - assert_eq!(srnifake.signatures.len(), sigsfake3.len()); + ); + let tksfake3_validated = srnifake.validate(&tksfake3, crypto.clone()).unwrap(); + assert_eq!(tksfake3_validated.len(), 1); + assert_eq!(srnifake.signatures().len(), sigsfake3.len()); } api.shutdown().await; diff --git a/veilid-core/src/routing_table/bucket_entry.rs b/veilid-core/src/routing_table/bucket_entry.rs index c94577dd..92a6dad5 100644 --- a/veilid-core/src/routing_table/bucket_entry.rs +++ b/veilid-core/src/routing_table/bucket_entry.rs @@ -73,7 +73,9 @@ pub struct BucketEntryLocalNetwork { #[archive_attr(repr(C), derive(CheckBytes))] pub struct BucketEntryInner { /// The node ids matching this bucket entry, with the cryptography versions supported by this node as the 'kind' field - node_ids: TypedKeySet, + validated_node_ids: TypedKeySet, + /// The node ids claimed by the remote node that use cryptography versions we do not support + unsupported_node_ids: TypedKeySet, /// The set of envelope versions supported by the node inclusive of the requirements of any relay the node may be using envelope_support: Vec, /// If this node has updated it's SignedNodeInfo since our network @@ -122,9 +124,11 @@ impl BucketEntryInner { self.node_ref_tracks.remove(&track_id); } - /// Get node ids + /// Get all node ids pub fn node_ids(&self) -> TypedKeySet { - self.node_ids.clone() + let mut node_ids = self.validated_node_ids.clone(); + node_ids.add_all(&self.unsupported_node_ids); + node_ids } /// Add a node id for a particular crypto kind. @@ -132,33 +136,39 @@ impl BucketEntryInner { /// Returns Ok(None) if no previous existing node id was associated with that crypto kind /// Results Err() if this operation would add more crypto kinds than we support pub fn add_node_id(&mut self, node_id: TypedKey) -> EyreResult> { - if let Some(old_node_id) = self.node_ids.get(node_id.kind) { + let node_ids = if VALID_CRYPTO_KINDS.contains(&node_id.kind) { + &mut self.validated_node_ids + } else { + &mut self.unsupported_node_ids + }; + + if let Some(old_node_id) = node_ids.get(node_id.kind) { // If this was already there we do nothing if old_node_id == node_id { return Ok(None); } // Won't change number of crypto kinds - self.node_ids.add(node_id); + node_ids.add(node_id); return Ok(Some(old_node_id)); } // Check to ensure we aren't adding more crypto kinds than we support - if self.node_ids.len() == MAX_CRYPTO_KINDS { + if self.validated_node_ids.len() + self.unsupported_node_ids.len() == MAX_CRYPTO_KINDS { bail!("too many crypto kinds for this node"); } - self.node_ids.add(node_id); + node_ids.add(node_id); Ok(None) } pub fn best_node_id(&self) -> TypedKey { - self.node_ids.best().unwrap() + self.validated_node_ids.best().unwrap() } /// Get crypto kinds pub fn crypto_kinds(&self) -> Vec { - self.node_ids.kinds() + self.validated_node_ids.kinds() } /// Compare sets of crypto kinds pub fn common_crypto_kinds(&self, other: &[CryptoKind]) -> Vec { - common_crypto_kinds(&self.node_ids.kinds(), other) + common_crypto_kinds(&self.validated_node_ids.kinds(), other) } @@ -270,7 +280,7 @@ impl BucketEntryInner { } // Update the envelope version support we have to use - let envelope_support = signed_node_info.node_info().envelope_support.clone(); + let envelope_support = signed_node_info.node_info().envelope_support().to_vec(); // Update the signed node info *opt_current_sni = Some(Box::new(signed_node_info)); @@ -333,8 +343,10 @@ impl BucketEntryInner { RoutingDomain::LocalNetwork => &self.local_network.signed_node_info, RoutingDomain::PublicInternet => &self.public_internet.signed_node_info, }; + // Peer info includes all node ids, even unvalidated ones + let node_ids = self.node_ids(); opt_current_sni.as_ref().map(|s| PeerInfo { - node_ids: self.node_ids.clone(), + node_ids, signed_node_info: *s.clone(), }) } @@ -781,11 +793,13 @@ pub struct BucketEntry { impl BucketEntry { pub(super) fn new(first_node_id: TypedKey) -> Self { let now = get_aligned_timestamp(); - let mut node_ids = TypedKeySet::new(); - node_ids.add(first_node_id); + let mut validated_node_ids = TypedKeySet::new(); + let mut unsupported_node_ids = TypedKeySet::new(); + validated_node_ids.add(first_node_id); let inner = BucketEntryInner { - node_ids, + validated_node_ids, + unsupported_node_ids, envelope_support: Vec::new(), updated_since_last_network_change: false, last_connections: BTreeMap::new(), diff --git a/veilid-core/src/routing_table/mod.rs b/veilid-core/src/routing_table/mod.rs index 2c4a3c79..ce165a60 100644 --- a/veilid-core/src/routing_table/mod.rs +++ b/veilid-core/src/routing_table/mod.rs @@ -792,8 +792,8 @@ impl RoutingTable { e.with(rti, |_rti, e| { if let Some(ni) = e.node_info(routing_domain) { let dif = DialInfoFilter::all() - .with_protocol_type_set(ni.outbound_protocols) - .with_address_type_set(ni.address_types); + .with_protocol_type_set(ni.outbound_protocols()) + .with_address_type_set(ni.address_types()); if dial_info.matches_filter(&dif) { return true; } @@ -851,7 +851,7 @@ impl RoutingTable { // does it have some dial info we need? let filter = |n: &NodeInfo| { let mut keep = false; - for did in &n.dial_info_detail_list { + for did in n.dial_info_detail_list() { if matches!(did.dial_info.address_type(), AddressType::IPV4) { for (n, protocol_type) in protocol_types.iter().enumerate() { if nodes_proto_v4[n] < max_per_type @@ -974,12 +974,12 @@ impl RoutingTable { let mut out = Vec::::with_capacity(peers.len()); for p in peers { // Ensure we're getting back nodes we asked for - if !p.node_ids.kinds().contains(&crypto_kind) { + if !p.node_ids().kinds().contains(&crypto_kind) { continue; } // Don't register our own node - if self.matches_own_node_id(&p.node_ids) { + if self.matches_own_node_id(p.node_ids()) { continue; } diff --git a/veilid-core/src/routing_table/node_ref.rs b/veilid-core/src/routing_table/node_ref.rs index bf44ab99..09dd0070 100644 --- a/veilid-core/src/routing_table/node_ref.rs +++ b/veilid-core/src/routing_table/node_ref.rs @@ -174,13 +174,13 @@ pub trait NodeRefBase: Sized { self.operate_mut(|_rti, e| e.set_our_node_info_ts(routing_domain, seen_ts)); } fn network_class(&self, routing_domain: RoutingDomain) -> Option { - self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.network_class)) + self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.network_class())) } fn outbound_protocols(&self, routing_domain: RoutingDomain) -> Option { - self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.outbound_protocols)) + self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.outbound_protocols())) } fn address_types(&self, routing_domain: RoutingDomain) -> Option { - self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.address_types)) + self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.address_types())) } fn node_info_outbound_filter(&self, routing_domain: RoutingDomain) -> DialInfoFilter { let mut dif = DialInfoFilter::all(); @@ -199,7 +199,7 @@ pub trait NodeRefBase: Sized { .and_then(|rpi| { // If relay is ourselves, then return None, because we can't relay through ourselves // and to contact this node we should have had an existing inbound connection - if rti.unlocked_inner.matches_own_node_id(&rpi.node_ids) { + if rti.unlocked_inner.matches_own_node_id(rpi.node_ids()) { return None; } diff --git a/veilid-core/src/routing_table/privacy.rs b/veilid-core/src/routing_table/privacy.rs index e4aa4c34..a05b08db 100644 --- a/veilid-core/src/routing_table/privacy.rs +++ b/veilid-core/src/routing_table/privacy.rs @@ -22,6 +22,19 @@ pub enum RouteNode { } impl RouteNode { + pub fn validate(&self, crypto: Crypto) -> Result<(), VeilidAPIError> { + match self { + RouteNode::NodeId(_) => Ok(()), + RouteNode::PeerInfo(pi) => { + let validated_node_ids = pi.validate(crypto)?; + if validated_node_ids.is_empty() { + apibail_generic!("no validated node ids for route node"); + } + Ok(()) + } + } + } + pub fn node_ref( &self, routing_table: RoutingTable, @@ -48,10 +61,10 @@ impl RouteNode { RouteNode::NodeId(id) => { format!("{}", TypedKey::new(crypto_kind, *id)) } - RouteNode::PeerInfo(pi) => match pi.node_ids.get(crypto_kind) { + RouteNode::PeerInfo(pi) => match pi.node_ids().get(crypto_kind) { Some(id) => format!("{}", id), None => { - format!("({})?{}", crypto_kind, pi.node_ids) + format!("({})?{}", crypto_kind, pi.node_ids()) } }, } @@ -66,6 +79,11 @@ pub struct RouteHop { /// The encrypted blob to pass to the next hop as its data (None for stubs) pub next_hop: Option, } +impl RouteHop { + pub fn validate(&self, crypto: Crypto) -> Result<(), VeilidAPIError> { + self.node.validate(crypto) + } +} /// The kind of hops a private route can have #[derive(Clone, Debug)] @@ -78,6 +96,15 @@ pub enum PrivateRouteHops { Empty, } +impl PrivateRouteHops { + pub fn validate(&self, crypto: Crypto) -> Result<(), VeilidAPIError> { + match self { + PrivateRouteHops::FirstHop(rh) => rh.validate(crypto), + PrivateRouteHops::Data(_) => Ok(()), + PrivateRouteHops::Empty => Ok(()), + } + } +} /// A private route for receiver privacy #[derive(Clone, Debug)] pub struct PrivateRoute { @@ -108,6 +135,10 @@ impl PrivateRoute { } } + pub fn validate(&self, crypto: Crypto) -> Result<(), VeilidAPIError> { + self.hops.validate(crypto) + } + /// Check if this is a stub route pub fn is_stub(&self) -> bool { if let PrivateRouteHops::FirstHop(first_hop) = &self.hops { @@ -155,7 +186,7 @@ impl PrivateRoute { // Get the safety route to use from the spec Some(match &pr_first_hop.node { RouteNode::NodeId(n) => TypedKey::new(self.public_key.kind, *n), - RouteNode::PeerInfo(p) => p.node_ids.get(self.public_key.kind).unwrap(), + RouteNode::PeerInfo(p) => p.node_ids().get(self.public_key.kind).unwrap(), }) } } diff --git a/veilid-core/src/routing_table/route_spec_store/route_spec_store.rs b/veilid-core/src/routing_table/route_spec_store/route_spec_store.rs index 7f5d79ae..134de46c 100644 --- a/veilid-core/src/routing_table/route_spec_store/route_spec_store.rs +++ b/veilid-core/src/routing_table/route_spec_store/route_spec_store.rs @@ -1550,7 +1550,9 @@ impl RouteSpecStore { .get_root::() .map_err(RPCError::internal) .wrap_err("failed to make reader for private_route")?; - let private_route = decode_private_route(&pr_reader, crypto.clone()).wrap_err("failed to decode private route")?; + let private_route = decode_private_route(&pr_reader).wrap_err("failed to decode private route")?; + private_route.validate(crypto.clone()).wrap_err("failed to validate private route")?; + out.push(private_route); } diff --git a/veilid-core/src/routing_table/routing_domains.rs b/veilid-core/src/routing_table/routing_domains.rs index bfd52d88..ca3693c1 100644 --- a/veilid-core/src/routing_table/routing_domains.rs +++ b/veilid-core/src/routing_table/routing_domains.rs @@ -102,14 +102,14 @@ impl RoutingDomainDetailCommon { } fn make_peer_info(&self, rti: &RoutingTableInner) -> PeerInfo { - let node_info = NodeInfo { - network_class: self.network_class.unwrap_or(NetworkClass::Invalid), - outbound_protocols: self.outbound_protocols, - address_types: self.address_types, - envelope_support: VALID_ENVELOPE_VERSIONS.to_vec(), - crypto_support: VALID_CRYPTO_KINDS.to_vec(), - dial_info_detail_list: self.dial_info_details.clone(), - }; + let node_info = NodeInfo::new( + self.network_class.unwrap_or(NetworkClass::Invalid), + self.outbound_protocols, + self.address_types, + VALID_ENVELOPE_VERSIONS.to_vec(), + VALID_CRYPTO_KINDS.to_vec(), + self.dial_info_details.clone() + ); let relay_info = self .relay_node @@ -117,8 +117,9 @@ impl RoutingDomainDetailCommon { .and_then(|rn| { let opt_relay_pi = rn.locked(rti).make_peer_info(self.routing_domain); if let Some(relay_pi) = opt_relay_pi { - match relay_pi.signed_node_info { - SignedNodeInfo::Direct(d) => Some((relay_pi.node_ids, d)), + let (relay_ids, relay_sni) = relay_pi.into_fields(); + match relay_sni { + SignedNodeInfo::Direct(d) => Some((relay_ids, d)), SignedNodeInfo::Relayed(_) => { warn!("relay node should not have a relay itself! if this happens, a relay updated its signed node info and became a relay, which should cause the relay to be dropped"); None @@ -230,8 +231,8 @@ fn first_filtered_dial_info_detail( ) -> Option { let dial_info_filter = dial_info_filter.clone().filtered( &DialInfoFilter::all() - .with_address_type_set(from_node.address_types) - .with_protocol_type_set(from_node.outbound_protocols), + .with_address_type_set(from_node.address_types()) + .with_protocol_type_set(from_node.outbound_protocols()), ); // Get first filtered dialinfo @@ -278,18 +279,18 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail { sequencing: Sequencing, ) -> ContactMethod { // Get the nodeinfos for convenience - let node_a = peer_a.signed_node_info.node_info(); - let node_b = peer_b.signed_node_info.node_info(); + let node_a = peer_a.signed_node_info().node_info(); + let node_b = peer_b.signed_node_info().node_info(); // Get the node ids that would be used between these peers - let cck = common_crypto_kinds(&peer_a.node_ids.kinds(), &peer_b.node_ids.kinds()); + let cck = common_crypto_kinds(&peer_a.node_ids().kinds(), &peer_b.node_ids().kinds()); let Some(best_ck) = cck.first().copied() else { // No common crypto kinds between these nodes, can't contact return ContactMethod::Unreachable; }; - //let node_a_id = peer_a.node_ids.get(best_ck).unwrap(); - let node_b_id = peer_b.node_ids.get(best_ck).unwrap(); + //let node_a_id = peer_a.node_ids().get(best_ck).unwrap(); + let node_b_id = peer_b.node_ids().get(best_ck).unwrap(); // Get the best match dial info for node B if we have it if let Some(target_did) = @@ -302,17 +303,17 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail { } // Get the target's inbound relay, it must have one or it is not reachable - if let Some(node_b_relay) = peer_b.signed_node_info.relay_info() { + if let Some(node_b_relay) = peer_b.signed_node_info().relay_info() { // Note that relay_peer_info could be node_a, in which case a connection already exists // and we only get here if the connection had dropped, in which case node_a is unreachable until // it gets a new relay connection up - if peer_b.signed_node_info.relay_ids().contains_any(&peer_a.node_ids) { + if peer_b.signed_node_info().relay_ids().contains_any(peer_a.node_ids()) { return ContactMethod::Existing; } // Get best node id to contact relay with - let Some(node_b_relay_id) = peer_b.signed_node_info.relay_ids().get(best_ck) else { + let Some(node_b_relay_id) = peer_b.signed_node_info().relay_ids().get(best_ck) else { // No best relay id return ContactMethod::Unreachable; }; @@ -327,7 +328,7 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail { .is_some() { // Can node A receive anything inbound ever? - if matches!(node_a.network_class, NetworkClass::InboundCapable) { + if matches!(node_a.network_class(), NetworkClass::InboundCapable) { ///////// Reverse connection // Get the best match dial info for an reverse inbound connection from node B to node A @@ -390,17 +391,17 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail { } } // If the node B has no direct dial info, it needs to have an inbound relay - else if let Some(node_b_relay) = peer_b.signed_node_info.relay_info() { + else if let Some(node_b_relay) = peer_b.signed_node_info().relay_info() { // Note that relay_peer_info could be node_a, in which case a connection already exists // and we only get here if the connection had dropped, in which case node_a is unreachable until // it gets a new relay connection up - if peer_b.signed_node_info.relay_ids().contains_any(&peer_a.node_ids) { + if peer_b.signed_node_info().relay_ids().contains_any(peer_a.node_ids()) { return ContactMethod::Existing; } // Get best node id to contact relay with - let Some(node_b_relay_id) = peer_b.signed_node_info.relay_ids().get(best_ck) else { + let Some(node_b_relay_id) = peer_b.signed_node_info().relay_ids().get(best_ck) else { // No best relay id return ContactMethod::Unreachable; }; @@ -419,7 +420,7 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail { } // If node A can't reach the node by other means, it may need to use its own relay - if let Some(node_a_relay_id) = peer_a.signed_node_info.relay_ids().get(best_ck) { + if let Some(node_a_relay_id) = peer_a.signed_node_info().relay_ids().get(best_ck) { return ContactMethod::OutboundRelay(node_a_relay_id); } @@ -484,8 +485,8 @@ impl RoutingDomainDetail for LocalNetworkRoutingDomainDetail { // Scope the filter down to protocols node A can do outbound let dial_info_filter = dial_info_filter.filtered( &DialInfoFilter::all() - .with_address_type_set(peer_a.signed_node_info.node_info().address_types) - .with_protocol_type_set(peer_a.signed_node_info.node_info().outbound_protocols), + .with_address_type_set(peer_a.signed_node_info().node_info().address_types()) + .with_protocol_type_set(peer_a.signed_node_info().node_info().outbound_protocols()), ); // Get first filtered dialinfo @@ -509,7 +510,7 @@ impl RoutingDomainDetail for LocalNetworkRoutingDomainDetail { let filter = |did: &DialInfoDetail| did.matches_filter(&dial_info_filter); - let opt_target_did = peer_b.signed_node_info.node_info().first_filtered_dial_info_detail(sort, filter); + let opt_target_did = peer_b.signed_node_info().node_info().first_filtered_dial_info_detail(sort, filter); if let Some(target_did) = opt_target_did { return ContactMethod::Direct(target_did.dial_info); } diff --git a/veilid-core/src/routing_table/routing_table_inner.rs b/veilid-core/src/routing_table/routing_table_inner.rs index de736853..42ec8e96 100644 --- a/veilid-core/src/routing_table/routing_table_inner.rs +++ b/veilid-core/src/routing_table/routing_table_inner.rs @@ -171,11 +171,11 @@ impl RoutingTableInner { node_info: &NodeInfo, ) -> bool { // Should not be passing around nodeinfo with an invalid network class - if matches!(node_info.network_class, NetworkClass::Invalid) { + if matches!(node_info.network_class(), NetworkClass::Invalid) { return false; } // Ensure all of the dial info works in this routing domain - for did in &node_info.dial_info_detail_list { + for did in node_info.dial_info_detail_list() { if !self.ensure_dial_info_is_valid(routing_domain, &did.dial_info) { return false; } @@ -258,7 +258,7 @@ impl RoutingTableInner { } else { Some( rdd.common() - .with_peer_info(self, |pi| pi.signed_node_info.timestamp()), + .with_peer_info(self, |pi| pi.signed_node_info().timestamp()), ) } }) @@ -804,13 +804,16 @@ impl RoutingTableInner { allow_invalid: bool, ) -> Option { // if our own node if is in the list then ignore it, as we don't add ourselves to our own routing table - if self.unlocked_inner.matches_own_node_id(&peer_info.node_ids) { + if self + .unlocked_inner + .matches_own_node_id(peer_info.node_ids()) + { log_rtab!(debug "can't register own node id in routing table"); return None; } // node can not be its own relay - let rids = peer_info.signed_node_info.relay_ids(); + let rids = peer_info.signed_node_info().relay_ids(); if self.unlocked_inner.matches_own_node_id(&rids) { log_rtab!(debug "node can not be its own relay"); return None; @@ -818,22 +821,22 @@ impl RoutingTableInner { if !allow_invalid { // verify signature - if !peer_info.signed_node_info.has_any_signature() { - log_rtab!(debug "signed node info for {:?} has invalid signature", &peer_info.node_ids); + if !peer_info.signed_node_info().has_any_signature() { + log_rtab!(debug "signed node info for {:?} has no valid signature", peer_info.node_ids()); return None; } // verify signed node info is valid in this routing domain if !self.signed_node_info_is_valid_in_routing_domain( routing_domain, - &peer_info.signed_node_info, + peer_info.signed_node_info(), ) { - log_rtab!(debug "signed node info for {:?} not valid in the {:?} routing domain", peer_info.node_ids, routing_domain); + log_rtab!(debug "signed node info for {:?} not valid in the {:?} routing domain", peer_info.node_ids(), routing_domain); return None; } } - self.create_node_ref(outer_self, &peer_info.node_ids, |_rti, e| { - e.update_signed_node_info(routing_domain, peer_info.signed_node_info); + self.create_node_ref(outer_self, peer_info.node_ids(), |_rti, e| { + e.update_signed_node_info(routing_domain, peer_info.into_signed_node_info()); }) .map(|mut nr| { nr.set_filter(Some( diff --git a/veilid-core/src/routing_table/tasks/relay_management.rs b/veilid-core/src/routing_table/tasks/relay_management.rs index ca80b81f..3bc93145 100644 --- a/veilid-core/src/routing_table/tasks/relay_management.rs +++ b/veilid-core/src/routing_table/tasks/relay_management.rs @@ -13,8 +13,8 @@ impl RoutingTable { let Some(own_peer_info) = self.get_own_peer_info(RoutingDomain::PublicInternet) else { return Ok(()); }; - let own_node_info = own_peer_info.signed_node_info.node_info(); - let network_class = own_node_info.network_class; + let own_node_info = own_peer_info.signed_node_info().node_info(); + let network_class = own_node_info.network_class(); // Get routing domain editor let mut editor = self.edit_routing_domain(RoutingDomain::PublicInternet); diff --git a/veilid-core/src/routing_table/types/node_info.rs b/veilid-core/src/routing_table/types/node_info.rs index ecbd709b..ca5cbde8 100644 --- a/veilid-core/src/routing_table/types/node_info.rs +++ b/veilid-core/src/routing_table/types/node_info.rs @@ -1,19 +1,58 @@ use super::*; -#[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)] +#[derive( + Clone, Default, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize, +)] #[archive_attr(repr(C), derive(CheckBytes))] pub struct NodeInfo { - pub network_class: NetworkClass, + network_class: NetworkClass, #[with(RkyvEnumSet)] - pub outbound_protocols: ProtocolTypeSet, + outbound_protocols: ProtocolTypeSet, #[with(RkyvEnumSet)] - pub address_types: AddressTypeSet, - pub envelope_support: Vec, - pub crypto_support: Vec, - pub dial_info_detail_list: Vec, + address_types: AddressTypeSet, + envelope_support: Vec, + crypto_support: Vec, + dial_info_detail_list: Vec, } impl NodeInfo { + pub fn new( + network_class: NetworkClass, + outbound_protocols: ProtocolTypeSet, + address_types: AddressTypeSet, + envelope_support: Vec, + crypto_support: Vec, + dial_info_detail_list: Vec, + ) -> Self { + Self { + network_class, + outbound_protocols, + address_types, + envelope_support, + crypto_support, + dial_info_detail_list, + } + } + + pub fn network_class(&self) -> NetworkClass { + self.network_class + } + pub fn outbound_protocols(&self) -> ProtocolTypeSet { + self.outbound_protocols + } + pub fn address_types(&self) -> AddressTypeSet { + self.address_types + } + pub fn envelope_support(&self) -> &[u8] { + &self.envelope_support + } + pub fn crypto_support(&self) -> &[CryptoKind] { + &self.crypto_support + } + pub fn dial_info_detail_list(&self) -> &[DialInfoDetail] { + &self.dial_info_detail_list + } + pub fn first_filtered_dial_info_detail( &self, sort: Option, diff --git a/veilid-core/src/routing_table/types/peer_info.rs b/veilid-core/src/routing_table/types/peer_info.rs index 0e7e3558..9c91382e 100644 --- a/veilid-core/src/routing_table/types/peer_info.rs +++ b/veilid-core/src/routing_table/types/peer_info.rs @@ -3,8 +3,8 @@ use super::*; #[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)] #[archive_attr(repr(C), derive(CheckBytes))] pub struct PeerInfo { - pub node_ids: TypedKeySet, - pub signed_node_info: SignedNodeInfo, + node_ids: TypedKeySet, + signed_node_info: SignedNodeInfo, } impl PeerInfo { @@ -15,4 +15,21 @@ impl PeerInfo { signed_node_info, } } + + pub fn validate(&self, crypto: Crypto) -> Result { + self.signed_node_info.validate(&self.node_ids, crypto) + } + + pub fn node_ids(&self) -> &TypedKeySet { + &self.node_ids + } + pub fn signed_node_info(&self) -> &SignedNodeInfo { + &self.signed_node_info + } + pub fn into_signed_node_info(self) -> SignedNodeInfo { + self.signed_node_info + } + pub fn into_fields(self) -> (TypedKeySet, SignedNodeInfo) { + (self.node_ids, self.signed_node_info) + } } diff --git a/veilid-core/src/routing_table/types/signed_direct_node_info.rs b/veilid-core/src/routing_table/types/signed_direct_node_info.rs index c04652c7..ea8ae032 100644 --- a/veilid-core/src/routing_table/types/signed_direct_node_info.rs +++ b/veilid-core/src/routing_table/types/signed_direct_node_info.rs @@ -4,36 +4,37 @@ use super::*; #[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)] #[archive_attr(repr(C), derive(CheckBytes))] pub struct SignedDirectNodeInfo { - pub node_info: NodeInfo, - pub timestamp: Timestamp, - pub signatures: Vec, + node_info: NodeInfo, + timestamp: Timestamp, + signatures: Vec, } impl SignedDirectNodeInfo { /// Returns a new SignedDirectNodeInfo that has its signatures validated. /// On success, this will modify the node_ids set to only include node_ids whose signatures validate. /// All signatures are stored however, as this can be passed to other nodes that may be able to validate those signatures. - pub fn new( + pub fn new(node_info: NodeInfo, timestamp: Timestamp, signatures: Vec) -> Self { + Self { + node_info, + timestamp, + signatures, + } + } + + pub fn validate( + &self, + node_ids: &TypedKeySet, crypto: Crypto, - node_ids: &mut TypedKeySet, - node_info: NodeInfo, - timestamp: Timestamp, - typed_signatures: Vec, - ) -> Result { - let node_info_bytes = Self::make_signature_bytes(&node_info, timestamp)?; + ) -> Result { + let node_info_bytes = Self::make_signature_bytes(&self.node_info, self.timestamp)?; // Verify the signatures that we can let validated_node_ids = - crypto.verify_signatures(node_ids, &node_info_bytes, &typed_signatures)?; - *node_ids = validated_node_ids; - if node_ids.len() == 0 { + crypto.verify_signatures(node_ids, &node_info_bytes, &self.signatures)?; + if validated_node_ids.len() == 0 { apibail_generic!("no valid node ids in direct node info"); } - Ok(Self { - node_info, - timestamp, - signatures: typed_signatures, - }) + Ok(validated_node_ids) } pub fn make_signatures( @@ -83,4 +84,14 @@ impl SignedDirectNodeInfo { pub fn has_any_signature(&self) -> bool { !self.signatures.is_empty() } + + pub fn node_info(&self) -> &NodeInfo { + &self.node_info + } + pub fn timestamp(&self) -> Timestamp { + self.timestamp + } + pub fn signatures(&self) -> &[TypedSignature] { + &self.signatures + } } diff --git a/veilid-core/src/routing_table/types/signed_node_info.rs b/veilid-core/src/routing_table/types/signed_node_info.rs index 2137bb27..2a98ceae 100644 --- a/veilid-core/src/routing_table/types/signed_node_info.rs +++ b/veilid-core/src/routing_table/types/signed_node_info.rs @@ -8,6 +8,17 @@ pub enum SignedNodeInfo { } impl SignedNodeInfo { + pub fn validate( + &self, + node_ids: &TypedKeySet, + crypto: Crypto, + ) -> Result { + match self { + SignedNodeInfo::Direct(d) => d.validate(node_ids, crypto), + SignedNodeInfo::Relayed(r) => r.validate(node_ids, crypto), + } + } + pub fn has_any_signature(&self) -> bool { match self { SignedNodeInfo::Direct(d) => d.has_any_signature(), @@ -17,34 +28,34 @@ impl SignedNodeInfo { pub fn timestamp(&self) -> Timestamp { match self { - SignedNodeInfo::Direct(d) => d.timestamp, - SignedNodeInfo::Relayed(r) => r.timestamp, + SignedNodeInfo::Direct(d) => d.timestamp(), + SignedNodeInfo::Relayed(r) => r.timestamp(), } } pub fn node_info(&self) -> &NodeInfo { match self { - SignedNodeInfo::Direct(d) => &d.node_info, - SignedNodeInfo::Relayed(r) => &r.node_info, + SignedNodeInfo::Direct(d) => &d.node_info(), + SignedNodeInfo::Relayed(r) => &r.node_info(), } } pub fn relay_ids(&self) -> TypedKeySet { match self { SignedNodeInfo::Direct(_) => TypedKeySet::new(), - SignedNodeInfo::Relayed(r) => r.relay_ids.clone(), + SignedNodeInfo::Relayed(r) => r.relay_ids().clone(), } } pub fn relay_info(&self) -> Option<&NodeInfo> { match self { SignedNodeInfo::Direct(_) => None, - SignedNodeInfo::Relayed(r) => Some(&r.relay_info.node_info), + SignedNodeInfo::Relayed(r) => Some(r.relay_info().node_info()), } } pub fn relay_peer_info(&self) -> Option { match self { SignedNodeInfo::Direct(_) => None, SignedNodeInfo::Relayed(r) => Some(PeerInfo::new( - r.relay_ids.clone(), - SignedNodeInfo::Direct(r.relay_info.clone()), + r.relay_ids().clone(), + SignedNodeInfo::Direct(r.relay_info().clone()), )), } } @@ -58,7 +69,7 @@ impl SignedNodeInfo { pub fn has_sequencing_matched_dial_info(&self, sequencing: Sequencing) -> bool { // Check our dial info - for did in &self.node_info().dial_info_detail_list { + for did in self.node_info().dial_info_detail_list() { match sequencing { Sequencing::NoPreference | Sequencing::PreferOrdered => return true, Sequencing::EnsureOrdered => { @@ -72,7 +83,7 @@ impl SignedNodeInfo { return self .relay_info() .map(|relay_ni| { - for did in &relay_ni.dial_info_detail_list { + for did in relay_ni.dial_info_detail_list() { match sequencing { Sequencing::NoPreference | Sequencing::PreferOrdered => return true, Sequencing::EnsureOrdered => { diff --git a/veilid-core/src/routing_table/types/signed_relayed_node_info.rs b/veilid-core/src/routing_table/types/signed_relayed_node_info.rs index 4e716eba..3439baf7 100644 --- a/veilid-core/src/routing_table/types/signed_relayed_node_info.rs +++ b/veilid-core/src/routing_table/types/signed_relayed_node_info.rs @@ -4,11 +4,11 @@ use super::*; #[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)] #[archive_attr(repr(C), derive(CheckBytes))] pub struct SignedRelayedNodeInfo { - pub node_info: NodeInfo, - pub relay_ids: TypedKeySet, - pub relay_info: SignedDirectNodeInfo, - pub timestamp: Timestamp, - pub signatures: Vec, + node_info: NodeInfo, + relay_ids: TypedKeySet, + relay_info: SignedDirectNodeInfo, + timestamp: Timestamp, + signatures: Vec, } impl SignedRelayedNodeInfo { @@ -16,30 +16,50 @@ impl SignedRelayedNodeInfo { /// On success, this will modify the node_ids set to only include node_ids whose signatures validate. /// All signatures are stored however, as this can be passed to other nodes that may be able to validate those signatures. pub fn new( - crypto: Crypto, - node_ids: &mut TypedKeySet, node_info: NodeInfo, relay_ids: TypedKeySet, relay_info: SignedDirectNodeInfo, timestamp: Timestamp, - typed_signatures: Vec, - ) -> Result { - let node_info_bytes = - Self::make_signature_bytes(&node_info, &relay_ids, &relay_info, timestamp)?; - let validated_node_ids = - crypto.verify_signatures(node_ids, &node_info_bytes, &typed_signatures)?; - *node_ids = validated_node_ids; - if node_ids.len() == 0 { - apibail_generic!("no valid node ids in relayed node info"); - } - - Ok(Self { + signatures: Vec, + ) -> Self { + Self { node_info, relay_ids, relay_info, timestamp, - signatures: typed_signatures, - }) + signatures, + } + } + + pub fn validate( + &self, + node_ids: &TypedKeySet, + crypto: Crypto, + ) -> Result { + // Ensure the relay info for the node has a superset of the crypto kinds of the node it is relaying + if common_crypto_kinds( + self.node_info.crypto_support(), + self.relay_info.node_info().crypto_support(), + ) + .len() + != self.node_info.crypto_support().len() + { + apibail_generic!("relay should have superset of node crypto kinds"); + } + + // Verify signatures + let node_info_bytes = Self::make_signature_bytes( + &self.node_info, + &self.relay_ids, + &self.relay_info, + self.timestamp, + )?; + let validated_node_ids = + crypto.verify_signatures(node_ids, &node_info_bytes, &self.signatures)?; + if validated_node_ids.len() == 0 { + apibail_generic!("no valid node ids in relayed node info"); + } + Ok(validated_node_ids) } pub fn make_signatures( @@ -103,4 +123,20 @@ impl SignedRelayedNodeInfo { pub fn has_any_signature(&self) -> bool { !self.signatures.is_empty() } + + pub fn node_info(&self) -> &NodeInfo { + &self.node_info + } + pub fn timestamp(&self) -> Timestamp { + self.timestamp + } + pub fn relay_ids(&self) -> &TypedKeySet { + &self.relay_ids + } + pub fn relay_info(&self) -> &SignedDirectNodeInfo { + &self.relay_info + } + pub fn signatures(&self) -> &[TypedSignature] { + &self.signatures + } } diff --git a/veilid-core/src/rpc_processor/coders/node_info.rs b/veilid-core/src/rpc_processor/coders/node_info.rs index 6d2d87c6..874a7e6b 100644 --- a/veilid-core/src/rpc_processor/coders/node_info.rs +++ b/veilid-core/src/rpc_processor/coders/node_info.rs @@ -4,27 +4,27 @@ pub fn encode_node_info( node_info: &NodeInfo, builder: &mut veilid_capnp::node_info::Builder, ) -> Result<(), RPCError> { - builder.set_network_class(encode_network_class(node_info.network_class)); + builder.set_network_class(encode_network_class(node_info.network_class())); let mut ps_builder = builder.reborrow().init_outbound_protocols(); - encode_protocol_type_set(&node_info.outbound_protocols, &mut ps_builder)?; + encode_protocol_type_set(&node_info.outbound_protocols(), &mut ps_builder)?; let mut ats_builder = builder.reborrow().init_address_types(); - encode_address_type_set(&node_info.address_types, &mut ats_builder)?; + encode_address_type_set(&node_info.address_types(), &mut ats_builder)?; let mut es_builder = builder .reborrow() - .init_envelope_support(node_info.envelope_support.len() as u32); + .init_envelope_support(node_info.envelope_support().len() as u32); if let Some(s) = es_builder.as_slice() { - s.clone_from_slice(&node_info.envelope_support); + s.clone_from_slice(&node_info.envelope_support()); } let mut cs_builder = builder .reborrow() - .init_crypto_support(node_info.crypto_support.len() as u32); + .init_crypto_support(node_info.crypto_support().len() as u32); if let Some(s) = cs_builder.as_slice() { let csvec: Vec = node_info - .crypto_support + .crypto_support() .iter() .map(|x| u32::from_be_bytes(x.0)) .collect(); @@ -33,7 +33,7 @@ pub fn encode_node_info( let mut didl_builder = builder.reborrow().init_dial_info_detail_list( node_info - .dial_info_detail_list + .dial_info_detail_list() .len() .try_into() .map_err(RPCError::map_protocol( @@ -41,9 +41,9 @@ pub fn encode_node_info( ))?, ); - for idx in 0..node_info.dial_info_detail_list.len() { + for idx in 0..node_info.dial_info_detail_list().len() { let mut did_builder = didl_builder.reborrow().get(idx as u32); - encode_dial_info_detail(&node_info.dial_info_detail_list[idx], &mut did_builder)?; + encode_dial_info_detail(&node_info.dial_info_detail_list()[idx], &mut did_builder)?; } Ok(()) @@ -131,12 +131,12 @@ pub fn decode_node_info(reader: &veilid_capnp::node_info::Reader) -> Result Self { Self { detail } } + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + self.detail.validate(crypto) + } pub fn into_detail(self) -> RPCAnswerDetail { self.detail } pub fn desc(&self) -> &'static str { self.detail.desc() } - pub fn decode( - reader: &veilid_capnp::answer::Reader, - crypto: Crypto, - ) -> Result { + pub fn decode(reader: &veilid_capnp::answer::Reader) -> Result { let d_reader = reader.get_detail(); - let detail = RPCAnswerDetail::decode(&d_reader, crypto)?; + let detail = RPCAnswerDetail::decode(&d_reader)?; Ok(RPCAnswer { detail }) } pub fn encode(&self, builder: &mut veilid_capnp::answer::Builder) -> Result<(), RPCError> { @@ -60,10 +60,23 @@ impl RPCAnswerDetail { RPCAnswerDetail::CancelTunnelA(_) => "CancelTunnelA", } } - + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + match self { + RPCAnswerDetail::StatusA(r) => r.validate(crypto), + RPCAnswerDetail::FindNodeA(r) => r.validate(crypto), + RPCAnswerDetail::AppCallA(r) => r.validate(crypto), + RPCAnswerDetail::GetValueA(r) => r.validate(crypto), + RPCAnswerDetail::SetValueA(r) => r.validate(crypto), + RPCAnswerDetail::WatchValueA(r) => r.validate(crypto), + RPCAnswerDetail::SupplyBlockA(r) => r.validate(crypto), + RPCAnswerDetail::FindBlockA(r) => r.validate(crypto), + RPCAnswerDetail::StartTunnelA(r) => r.validate(crypto), + RPCAnswerDetail::CompleteTunnelA(r) => r.validate(crypto), + RPCAnswerDetail::CancelTunnelA(r) => r.validate(crypto), + } + } pub fn decode( reader: &veilid_capnp::answer::detail::Reader, - crypto: Crypto, ) -> Result { let which_reader = reader.which().map_err(RPCError::protocol)?; let out = match which_reader { @@ -74,7 +87,7 @@ impl RPCAnswerDetail { } veilid_capnp::answer::detail::FindNodeA(r) => { let op_reader = r.map_err(RPCError::protocol)?; - let out = RPCOperationFindNodeA::decode(&op_reader, crypto)?; + let out = RPCOperationFindNodeA::decode(&op_reader)?; RPCAnswerDetail::FindNodeA(out) } veilid_capnp::answer::detail::AppCallA(r) => { @@ -84,27 +97,27 @@ impl RPCAnswerDetail { } veilid_capnp::answer::detail::GetValueA(r) => { let op_reader = r.map_err(RPCError::protocol)?; - let out = RPCOperationGetValueA::decode(&op_reader, crypto)?; + let out = RPCOperationGetValueA::decode(&op_reader)?; RPCAnswerDetail::GetValueA(out) } veilid_capnp::answer::detail::SetValueA(r) => { let op_reader = r.map_err(RPCError::protocol)?; - let out = RPCOperationSetValueA::decode(&op_reader, crypto)?; + let out = RPCOperationSetValueA::decode(&op_reader)?; RPCAnswerDetail::SetValueA(out) } veilid_capnp::answer::detail::WatchValueA(r) => { let op_reader = r.map_err(RPCError::protocol)?; - let out = RPCOperationWatchValueA::decode(&op_reader, crypto)?; + let out = RPCOperationWatchValueA::decode(&op_reader)?; RPCAnswerDetail::WatchValueA(out) } veilid_capnp::answer::detail::SupplyBlockA(r) => { let op_reader = r.map_err(RPCError::protocol)?; - let out = RPCOperationSupplyBlockA::decode(&op_reader, crypto)?; + let out = RPCOperationSupplyBlockA::decode(&op_reader)?; RPCAnswerDetail::SupplyBlockA(out) } veilid_capnp::answer::detail::FindBlockA(r) => { let op_reader = r.map_err(RPCError::protocol)?; - let out = RPCOperationFindBlockA::decode(&op_reader, crypto)?; + let out = RPCOperationFindBlockA::decode(&op_reader)?; RPCAnswerDetail::FindBlockA(out) } veilid_capnp::answer::detail::StartTunnelA(r) => { diff --git a/veilid-core/src/rpc_processor/coders/operations/operation.rs b/veilid-core/src/rpc_processor/coders/operations/operation.rs index d27b4d88..c0161b6d 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation.rs @@ -16,25 +16,30 @@ impl RPCOperationKind { } } - pub fn decode( - kind_reader: &veilid_capnp::operation::kind::Reader, - crypto: Crypto, - ) -> Result { + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + match self { + RPCOperationKind::Question(r) => r.validate(crypto), + RPCOperationKind::Statement(r) => r.validate(crypto), + RPCOperationKind::Answer(r) => r.validate(crypto), + } + } + + pub fn decode(kind_reader: &veilid_capnp::operation::kind::Reader) -> Result { let which_reader = kind_reader.which().map_err(RPCError::protocol)?; let out = match which_reader { veilid_capnp::operation::kind::Which::Question(r) => { let q_reader = r.map_err(RPCError::protocol)?; - let out = RPCQuestion::decode(&q_reader, crypto)?; + let out = RPCQuestion::decode(&q_reader)?; RPCOperationKind::Question(out) } veilid_capnp::operation::kind::Which::Statement(r) => { let q_reader = r.map_err(RPCError::protocol)?; - let out = RPCStatement::decode(&q_reader, crypto)?; + let out = RPCStatement::decode(&q_reader)?; RPCOperationKind::Statement(out) } veilid_capnp::operation::kind::Which::Answer(r) => { let q_reader = r.map_err(RPCError::protocol)?; - let out = RPCAnswer::decode(&q_reader, crypto)?; + let out = RPCAnswer::decode(&q_reader)?; RPCOperationKind::Answer(out) } }; @@ -93,6 +98,15 @@ impl RPCOperation { } } + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + // Validate sender peer info + if let Some(sender_peer_info) = &self.opt_sender_peer_info { + sender_peer_info.validate(crypto.clone())?; + } + // Validate operation kind + self.kind.validate(crypto) + } + pub fn op_id(&self) -> OperationId { self.op_id } @@ -112,17 +126,14 @@ impl RPCOperation { self.kind } - pub fn decode( - operation_reader: &veilid_capnp::operation::Reader, - crypto: Crypto, - ) -> Result { + pub fn decode(operation_reader: &veilid_capnp::operation::Reader) -> Result { let op_id = OperationId::new(operation_reader.get_op_id()); let sender_peer_info = if operation_reader.has_sender_peer_info() { let pi_reader = operation_reader .get_sender_peer_info() .map_err(RPCError::protocol)?; - let pi = decode_peer_info(&pi_reader, crypto.clone())?; + let pi = decode_peer_info(&pi_reader)?; Some(pi) } else { None @@ -131,7 +142,7 @@ impl RPCOperation { let target_node_info_ts = Timestamp::new(operation_reader.get_target_node_info_ts()); let kind_reader = operation_reader.get_kind(); - let kind = RPCOperationKind::decode(&kind_reader, crypto)?; + let kind = RPCOperationKind::decode(&kind_reader)?; Ok(RPCOperation { op_id, diff --git a/veilid-core/src/rpc_processor/coders/operations/operation_app_call.rs b/veilid-core/src/rpc_processor/coders/operations/operation_app_call.rs index b1360b9a..0015134a 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation_app_call.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation_app_call.rs @@ -6,6 +6,10 @@ pub struct RPCOperationAppCallQ { } impl RPCOperationAppCallQ { + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + xxx length should be checked in decode verify this + Ok(()) + } pub fn decode( reader: &veilid_capnp::operation_app_call_q::Reader, ) -> Result { diff --git a/veilid-core/src/rpc_processor/coders/operations/operation_find_block.rs b/veilid-core/src/rpc_processor/coders/operations/operation_find_block.rs index b5ecab45..6c69457e 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation_find_block.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation_find_block.rs @@ -35,7 +35,6 @@ pub struct RPCOperationFindBlockA { impl RPCOperationFindBlockA { pub fn decode( reader: &veilid_capnp::operation_find_block_a::Reader, - crypto: Crypto, ) -> Result { let data = reader.get_data().map_err(RPCError::protocol)?.to_vec(); @@ -47,7 +46,7 @@ impl RPCOperationFindBlockA { .map_err(RPCError::map_internal("too many suppliers"))?, ); for s in suppliers_reader.iter() { - let peer_info = decode_peer_info(&s, crypto.clone())?; + let peer_info = decode_peer_info(&s)?; suppliers.push(peer_info); } @@ -59,7 +58,7 @@ impl RPCOperationFindBlockA { .map_err(RPCError::map_internal("too many peers"))?, ); for p in peers_reader.iter() { - let peer_info = decode_peer_info(&p, crypto.clone())?; + let peer_info = decode_peer_info(&p)?; peers.push(peer_info); } diff --git a/veilid-core/src/rpc_processor/coders/operations/operation_find_node.rs b/veilid-core/src/rpc_processor/coders/operations/operation_find_node.rs index c3511efa..2ac914ea 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation_find_node.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation_find_node.rs @@ -6,6 +6,9 @@ pub struct RPCOperationFindNodeQ { } impl RPCOperationFindNodeQ { + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + Ok(()) + } pub fn decode( reader: &veilid_capnp::operation_find_node_q::Reader, ) -> Result { @@ -29,9 +32,14 @@ pub struct RPCOperationFindNodeA { } impl RPCOperationFindNodeA { + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + for pi in &self.peers { + pi.validate(crypto.clone()).map_err(RPCError::protocol)?; + } + Ok(()) + } pub fn decode( reader: &veilid_capnp::operation_find_node_a::Reader, - crypto: Crypto, ) -> Result { let peers_reader = reader.get_peers().map_err(RPCError::protocol)?; let mut peers = Vec::::with_capacity( @@ -41,7 +49,7 @@ impl RPCOperationFindNodeA { .map_err(RPCError::map_internal("too many peers"))?, ); for p in peers_reader.iter() { - let peer_info = decode_peer_info(&p, crypto.clone())?; + let peer_info = decode_peer_info(&p)?; peers.push(peer_info); } diff --git a/veilid-core/src/rpc_processor/coders/operations/operation_get_value.rs b/veilid-core/src/rpc_processor/coders/operations/operation_get_value.rs index 5db1f993..8e9ddcb9 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation_get_value.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation_get_value.rs @@ -4,16 +4,22 @@ use super::*; pub struct RPCOperationGetValueQ { pub key: TypedKey, pub subkey: ValueSubkey, + pub want_descriptor: bool, } impl RPCOperationGetValueQ { pub fn decode( reader: &veilid_capnp::operation_get_value_q::Reader, ) -> Result { - let k_reader = reader.get_key().map_err(RPCError::protocol)?; + let k_reader = reader.reborrow().get_key().map_err(RPCError::protocol)?; let key = decode_typed_key(&k_reader)?; - let subkey = reader.get_subkey(); - Ok(RPCOperationGetValueQ { key, subkey }) + let subkey = reader.reborrow().get_subkey(); + let want_descriptor = reader.reborrow().get_want_descriptor(); + Ok(RPCOperationGetValueQ { + key, + subkey, + want_descriptor, + }) } pub fn encode( &self, @@ -22,24 +28,24 @@ impl RPCOperationGetValueQ { let mut k_builder = builder.reborrow().init_key(); encode_typed_key(&self.key, &mut k_builder); builder.set_subkey(self.subkey); + builder.set_want_descriptor(self.want_descriptor); Ok(()) } } #[derive(Debug, Clone)] pub enum RPCOperationGetValueA { - Data(ValueData), + Value(ValueDetail), Peers(Vec), } impl RPCOperationGetValueA { pub fn decode( reader: &veilid_capnp::operation_get_value_a::Reader, - crypto: Crypto, ) -> Result { match reader.which().map_err(RPCError::protocol)? { - veilid_capnp::operation_get_value_a::Which::Data(r) => { - let data = decode_value_data(&r.map_err(RPCError::protocol)?)?; + veilid_capnp::operation_get_value_a::Which::Value(r) => { + let value_detail = decode_value_detail(&r.map_err(RPCError::protocol)?)?; Ok(RPCOperationGetValueA::Data(data)) } veilid_capnp::operation_get_value_a::Which::Peers(r) => { @@ -51,7 +57,7 @@ impl RPCOperationGetValueA { .map_err(RPCError::map_internal("too many peers"))?, ); for p in peers_reader.iter() { - let peer_info = decode_peer_info(&p, crypto.clone())?; + let peer_info = decode_peer_info(&p)?; peers.push(peer_info); } diff --git a/veilid-core/src/rpc_processor/coders/operations/operation_route.rs b/veilid-core/src/rpc_processor/coders/operations/operation_route.rs index 67333819..e7d51ffe 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation_route.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation_route.rs @@ -80,10 +80,9 @@ pub struct RPCOperationRoute { impl RPCOperationRoute { pub fn decode( reader: &veilid_capnp::operation_route::Reader, - crypto: Crypto, ) -> Result { let sr_reader = reader.get_safety_route().map_err(RPCError::protocol)?; - let safety_route = decode_safety_route(&sr_reader, crypto)?; + let safety_route = decode_safety_route(&sr_reader)?; let o_reader = reader.get_operation().map_err(RPCError::protocol)?; let operation = RoutedOperation::decode(&o_reader)?; diff --git a/veilid-core/src/rpc_processor/coders/operations/operation_set_value.rs b/veilid-core/src/rpc_processor/coders/operations/operation_set_value.rs index 4f1c5763..99eed02f 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation_set_value.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation_set_value.rs @@ -40,7 +40,6 @@ pub enum RPCOperationSetValueA { impl RPCOperationSetValueA { pub fn decode( reader: &veilid_capnp::operation_set_value_a::Reader, - crypto: Crypto, ) -> Result { match reader.which().map_err(RPCError::protocol)? { veilid_capnp::operation_set_value_a::Which::Data(r) => { @@ -56,7 +55,7 @@ impl RPCOperationSetValueA { .map_err(RPCError::map_internal("too many peers"))?, ); for p in peers_reader.iter() { - let peer_info = decode_peer_info(&p, crypto.clone())?; + let peer_info = decode_peer_info(&p)?; peers.push(peer_info); } diff --git a/veilid-core/src/rpc_processor/coders/operations/operation_signal.rs b/veilid-core/src/rpc_processor/coders/operations/operation_signal.rs index a414e300..4b8a6fd3 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation_signal.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation_signal.rs @@ -8,9 +8,8 @@ pub struct RPCOperationSignal { impl RPCOperationSignal { pub fn decode( reader: &veilid_capnp::operation_signal::Reader, - crypto: Crypto, ) -> Result { - let signal_info = decode_signal_info(reader, crypto)?; + let signal_info = decode_signal_info(reader)?; Ok(RPCOperationSignal { signal_info }) } pub fn encode( diff --git a/veilid-core/src/rpc_processor/coders/operations/operation_status.rs b/veilid-core/src/rpc_processor/coders/operations/operation_status.rs index 9ab480a8..42202328 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation_status.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation_status.rs @@ -6,6 +6,10 @@ pub struct RPCOperationStatusQ { } impl RPCOperationStatusQ { + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + Ok(()) + } + pub fn decode( reader: &veilid_capnp::operation_status_q::Reader, ) -> Result { @@ -37,6 +41,9 @@ pub struct RPCOperationStatusA { } impl RPCOperationStatusA { + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + Ok(()) + } pub fn decode( reader: &veilid_capnp::operation_status_a::Reader, ) -> Result { diff --git a/veilid-core/src/rpc_processor/coders/operations/operation_supply_block.rs b/veilid-core/src/rpc_processor/coders/operations/operation_supply_block.rs index f68de596..a2d808e5 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation_supply_block.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation_supply_block.rs @@ -34,8 +34,7 @@ pub enum RPCOperationSupplyBlockA { impl RPCOperationSupplyBlockA { pub fn decode( reader: &veilid_capnp::operation_supply_block_a::Reader, - crypto: Crypto, - ) -> Result { += ) -> Result { match reader.which().map_err(RPCError::protocol)? { veilid_capnp::operation_supply_block_a::Which::Expiration(r) => { Ok(RPCOperationSupplyBlockA::Expiration(r)) @@ -49,7 +48,7 @@ impl RPCOperationSupplyBlockA { .map_err(RPCError::map_internal("too many peers"))?, ); for p in peers_reader.iter() { - let peer_info = decode_peer_info(&p, crypto.clone())?; + let peer_info = decode_peer_info(&p)?; peers.push(peer_info); } diff --git a/veilid-core/src/rpc_processor/coders/operations/operation_watch_value.rs b/veilid-core/src/rpc_processor/coders/operations/operation_watch_value.rs index 7812b98b..e2eaee74 100644 --- a/veilid-core/src/rpc_processor/coders/operations/operation_watch_value.rs +++ b/veilid-core/src/rpc_processor/coders/operations/operation_watch_value.rs @@ -80,7 +80,6 @@ pub struct RPCOperationWatchValueA { impl RPCOperationWatchValueA { pub fn decode( reader: &veilid_capnp::operation_watch_value_a::Reader, - crypto: Crypto, ) -> Result { let expiration = reader.get_expiration(); let peers_reader = reader.get_peers().map_err(RPCError::protocol)?; @@ -91,7 +90,7 @@ impl RPCOperationWatchValueA { .map_err(RPCError::map_internal("too many peers"))?, ); for p in peers_reader.iter() { - let peer_info = decode_peer_info(&p, crypto.clone())?; + let peer_info = decode_peer_info(&p)?; peers.push(peer_info); } diff --git a/veilid-core/src/rpc_processor/coders/operations/question.rs b/veilid-core/src/rpc_processor/coders/operations/question.rs index e3f50776..5935b6aa 100644 --- a/veilid-core/src/rpc_processor/coders/operations/question.rs +++ b/veilid-core/src/rpc_processor/coders/operations/question.rs @@ -10,6 +10,10 @@ impl RPCQuestion { pub fn new(respond_to: RespondTo, detail: RPCQuestionDetail) -> Self { Self { respond_to, detail } } + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + self.respond_to.validate(crypto.clone())?; + self.detail.validate(crypto) + } pub fn respond_to(&self) -> &RespondTo { &self.respond_to } @@ -19,12 +23,9 @@ impl RPCQuestion { pub fn desc(&self) -> &'static str { self.detail.desc() } - pub fn decode( - reader: &veilid_capnp::question::Reader, - crypto: Crypto, - ) -> Result { + pub fn decode(reader: &veilid_capnp::question::Reader) -> Result { let rt_reader = reader.get_respond_to(); - let respond_to = RespondTo::decode(&rt_reader, crypto)?; + let respond_to = RespondTo::decode(&rt_reader)?; let d_reader = reader.get_detail(); let detail = RPCQuestionDetail::decode(&d_reader)?; Ok(RPCQuestion { respond_to, detail }) @@ -68,6 +69,21 @@ impl RPCQuestionDetail { RPCQuestionDetail::CancelTunnelQ(_) => "CancelTunnelQ", } } + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + match self { + RPCQuestionDetail::StatusQ(r) => r.validate(crypto), + RPCQuestionDetail::FindNodeQ(r) => r.validate(crypto), + RPCQuestionDetail::AppCallQ(r) => r.validate(crypto), + RPCQuestionDetail::GetValueQ(r) => r.validate(crypto), + RPCQuestionDetail::SetValueQ(r) => r.validate(crypto), + RPCQuestionDetail::WatchValueQ(r) => r.validate(crypto), + RPCQuestionDetail::SupplyBlockQ(r) => r.validate(crypto), + RPCQuestionDetail::FindBlockQ(r) => r.validate(crypto), + RPCQuestionDetail::StartTunnelQ(r) => r.validate(crypto), + RPCQuestionDetail::CompleteTunnelQ(r) => r.validate(crypto), + RPCQuestionDetail::CancelTunnelQ(r) => r.validate(crypto), + } + } pub fn decode( reader: &veilid_capnp::question::detail::Reader, diff --git a/veilid-core/src/rpc_processor/coders/operations/respond_to.rs b/veilid-core/src/rpc_processor/coders/operations/respond_to.rs index 43d6f871..92b7c9ef 100644 --- a/veilid-core/src/rpc_processor/coders/operations/respond_to.rs +++ b/veilid-core/src/rpc_processor/coders/operations/respond_to.rs @@ -7,6 +7,13 @@ pub enum RespondTo { } impl RespondTo { + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + match self { + RespondTo::Sender => Ok(()), + RespondTo::PrivateRoute(pr) => pr.validate(crypto).map_err(RPCError::protocol), + } + } + pub fn encode( &self, builder: &mut veilid_capnp::question::respond_to::Builder, @@ -23,15 +30,12 @@ impl RespondTo { Ok(()) } - pub fn decode( - reader: &veilid_capnp::question::respond_to::Reader, - crypto: Crypto, - ) -> Result { + pub fn decode(reader: &veilid_capnp::question::respond_to::Reader) -> Result { let respond_to = match reader.which().map_err(RPCError::protocol)? { veilid_capnp::question::respond_to::Sender(()) => RespondTo::Sender, veilid_capnp::question::respond_to::PrivateRoute(pr_reader) => { let pr_reader = pr_reader.map_err(RPCError::protocol)?; - let pr = decode_private_route(&pr_reader, crypto)?; + let pr = decode_private_route(&pr_reader)?; RespondTo::PrivateRoute(pr) } }; diff --git a/veilid-core/src/rpc_processor/coders/operations/statement.rs b/veilid-core/src/rpc_processor/coders/operations/statement.rs index 2108b373..cd6b1ecc 100644 --- a/veilid-core/src/rpc_processor/coders/operations/statement.rs +++ b/veilid-core/src/rpc_processor/coders/operations/statement.rs @@ -9,6 +9,9 @@ impl RPCStatement { pub fn new(detail: RPCStatementDetail) -> Self { Self { detail } } + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + self.detail.validate(crypto) + } pub fn detail(&self) -> &RPCStatementDetail { &self.detail } @@ -18,12 +21,9 @@ impl RPCStatement { pub fn desc(&self) -> &'static str { self.detail.desc() } - pub fn decode( - reader: &veilid_capnp::statement::Reader, - crypto: Crypto, - ) -> Result { + pub fn decode(reader: &veilid_capnp::statement::Reader) -> Result { let d_reader = reader.get_detail(); - let detail = RPCStatementDetail::decode(&d_reader, crypto)?; + let detail = RPCStatementDetail::decode(&d_reader)?; Ok(RPCStatement { detail }) } pub fn encode(&self, builder: &mut veilid_capnp::statement::Builder) -> Result<(), RPCError> { @@ -53,9 +53,18 @@ impl RPCStatementDetail { RPCStatementDetail::AppMessage(_) => "AppMessage", } } + pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> { + match self { + RPCStatementDetail::ValidateDialInfo(r) => r.validate(crypto), + RPCStatementDetail::Route(r) => r.validate(crypto), + RPCStatementDetail::ValueChanged(r) => r.validate(crypto), + RPCStatementDetail::Signal(r) => r.validate(crypto), + RPCStatementDetail::ReturnReceipt(r) => r.validate(crypto), + RPCStatementDetail::AppMessage(r) => r.validate(crypto), + } + } pub fn decode( reader: &veilid_capnp::statement::detail::Reader, - crypto: Crypto, ) -> Result { let which_reader = reader.which().map_err(RPCError::protocol)?; let out = match which_reader { @@ -66,7 +75,7 @@ impl RPCStatementDetail { } veilid_capnp::statement::detail::Route(r) => { let op_reader = r.map_err(RPCError::protocol)?; - let out = RPCOperationRoute::decode(&op_reader, crypto)?; + let out = RPCOperationRoute::decode(&op_reader)?; RPCStatementDetail::Route(out) } veilid_capnp::statement::detail::ValueChanged(r) => { @@ -76,7 +85,7 @@ impl RPCStatementDetail { } veilid_capnp::statement::detail::Signal(r) => { let op_reader = r.map_err(RPCError::protocol)?; - let out = RPCOperationSignal::decode(&op_reader, crypto)?; + let out = RPCOperationSignal::decode(&op_reader)?; RPCStatementDetail::Signal(out) } veilid_capnp::statement::detail::ReturnReceipt(r) => { diff --git a/veilid-core/src/rpc_processor/coders/peer_info.rs b/veilid-core/src/rpc_processor/coders/peer_info.rs index 14a1cdd1..b7081aab 100644 --- a/veilid-core/src/rpc_processor/coders/peer_info.rs +++ b/veilid-core/src/rpc_processor/coders/peer_info.rs @@ -7,12 +7,12 @@ pub fn encode_peer_info( // let mut nids_builder = builder.reborrow().init_node_ids( peer_info - .node_ids + .node_ids() .len() .try_into() .map_err(RPCError::map_invalid_format("out of bound error"))?, ); - for (i, nid) in peer_info.node_ids.iter().enumerate() { + for (i, nid) in peer_info.node_ids().iter().enumerate() { encode_typed_key( nid, &mut nids_builder.reborrow().get( @@ -22,15 +22,12 @@ pub fn encode_peer_info( ); } let mut sni_builder = builder.reborrow().init_signed_node_info(); - encode_signed_node_info(&peer_info.signed_node_info, &mut sni_builder)?; + encode_signed_node_info(peer_info.signed_node_info(), &mut sni_builder)?; Ok(()) } -pub fn decode_peer_info( - reader: &veilid_capnp::peer_info::Reader, - crypto: Crypto, -) -> Result { +pub fn decode_peer_info(reader: &veilid_capnp::peer_info::Reader) -> Result { let nids_reader = reader .reborrow() .get_node_ids() @@ -43,7 +40,7 @@ pub fn decode_peer_info( for nid_reader in nids_reader.iter() { node_ids.add(decode_typed_key(&nid_reader)?); } - let signed_node_info = decode_signed_node_info(&sni_reader, crypto, &mut node_ids)?; + let signed_node_info = decode_signed_node_info(&sni_reader)?; if node_ids.len() == 0 { return Err(RPCError::protocol("no verified node ids")); } diff --git a/veilid-core/src/rpc_processor/coders/private_safety_route.rs b/veilid-core/src/rpc_processor/coders/private_safety_route.rs index 86d63d03..504b308d 100644 --- a/veilid-core/src/rpc_processor/coders/private_safety_route.rs +++ b/veilid-core/src/rpc_processor/coders/private_safety_route.rs @@ -67,10 +67,7 @@ pub fn encode_route_hop( Ok(()) } -pub fn decode_route_hop( - reader: &veilid_capnp::route_hop::Reader, - crypto: Crypto, -) -> Result { +pub fn decode_route_hop(reader: &veilid_capnp::route_hop::Reader) -> Result { let n_reader = reader.reborrow().get_node(); let node = match n_reader.which().map_err(RPCError::protocol)? { veilid_capnp::route_hop::node::Which::NodeId(ni) => { @@ -80,7 +77,7 @@ pub fn decode_route_hop( veilid_capnp::route_hop::node::Which::PeerInfo(pi) => { let pi_reader = pi.map_err(RPCError::protocol)?; RouteNode::PeerInfo( - decode_peer_info(&pi_reader, crypto) + decode_peer_info(&pi_reader) .map_err(RPCError::map_protocol("invalid peer info in route hop"))?, ) } @@ -128,7 +125,6 @@ pub fn encode_private_route( pub fn decode_private_route( reader: &veilid_capnp::private_route::Reader, - crypto: Crypto, ) -> Result { let public_key = decode_typed_key(&reader.get_public_key().map_err( RPCError::map_protocol("invalid public key in private route"), @@ -138,7 +134,7 @@ pub fn decode_private_route( let hops = match reader.get_hops().which().map_err(RPCError::protocol)? { veilid_capnp::private_route::hops::Which::FirstHop(rh_reader) => { let rh_reader = rh_reader.map_err(RPCError::protocol)?; - PrivateRouteHops::FirstHop(decode_route_hop(&rh_reader, crypto)?) + PrivateRouteHops::FirstHop(decode_route_hop(&rh_reader)?) } veilid_capnp::private_route::hops::Which::Data(rhd_reader) => { let rhd_reader = rhd_reader.map_err(RPCError::protocol)?; @@ -182,7 +178,6 @@ pub fn encode_safety_route( pub fn decode_safety_route( reader: &veilid_capnp::safety_route::Reader, - crypto: Crypto, ) -> Result { let public_key = decode_typed_key( &reader @@ -197,7 +192,7 @@ pub fn decode_safety_route( } veilid_capnp::safety_route::hops::Which::Private(pr_reader) => { let pr_reader = pr_reader.map_err(RPCError::protocol)?; - SafetyRouteHops::Private(decode_private_route(&pr_reader, crypto)?) + SafetyRouteHops::Private(decode_private_route(&pr_reader)?) } }; diff --git a/veilid-core/src/rpc_processor/coders/signal_info.rs b/veilid-core/src/rpc_processor/coders/signal_info.rs index 0f51257e..5e9edc84 100644 --- a/veilid-core/src/rpc_processor/coders/signal_info.rs +++ b/veilid-core/src/rpc_processor/coders/signal_info.rs @@ -34,7 +34,6 @@ pub fn encode_signal_info( pub fn decode_signal_info( reader: &veilid_capnp::operation_signal::Reader, - crypto: Crypto, ) -> Result { Ok( match reader @@ -53,7 +52,7 @@ pub fn decode_signal_info( let pi_reader = r.get_peer_info().map_err(RPCError::map_protocol( "invalid peer info in hole punch signal info", ))?; - let peer_info = decode_peer_info(&pi_reader, crypto)?; + let peer_info = decode_peer_info(&pi_reader)?; SignalInfo::HolePunch { receipt, peer_info } } @@ -69,7 +68,7 @@ pub fn decode_signal_info( let pi_reader = r.get_peer_info().map_err(RPCError::map_protocol( "invalid peer info in reverse connect signal info", ))?; - let peer_info = decode_peer_info(&pi_reader, crypto)?; + let peer_info = decode_peer_info(&pi_reader)?; SignalInfo::ReverseConnect { receipt, peer_info } } diff --git a/veilid-core/src/rpc_processor/coders/signed_direct_node_info.rs b/veilid-core/src/rpc_processor/coders/signed_direct_node_info.rs index c15ddfb8..4740ea59 100644 --- a/veilid-core/src/rpc_processor/coders/signed_direct_node_info.rs +++ b/veilid-core/src/rpc_processor/coders/signed_direct_node_info.rs @@ -6,20 +6,20 @@ pub fn encode_signed_direct_node_info( ) -> Result<(), RPCError> { // let mut ni_builder = builder.reborrow().init_node_info(); - encode_node_info(&signed_direct_node_info.node_info, &mut ni_builder)?; + encode_node_info(signed_direct_node_info.node_info(), &mut ni_builder)?; builder .reborrow() - .set_timestamp(signed_direct_node_info.timestamp.into()); + .set_timestamp(signed_direct_node_info.timestamp().into()); let mut sigs_builder = builder.reborrow().init_signatures( signed_direct_node_info - .signatures + .signatures() .len() .try_into() .map_err(RPCError::map_invalid_format("out of bound error"))?, ); - for (i, typed_signature) in signed_direct_node_info.signatures.iter().enumerate() { + for (i, typed_signature) in signed_direct_node_info.signatures().iter().enumerate() { encode_typed_signature( typed_signature, &mut sigs_builder.reborrow().get( @@ -34,8 +34,6 @@ pub fn encode_signed_direct_node_info( pub fn decode_signed_direct_node_info( reader: &veilid_capnp::signed_direct_node_info::Reader, - crypto: Crypto, - node_ids: &mut TypedKeySet, ) -> Result { let ni_reader = reader .reborrow() @@ -61,6 +59,9 @@ pub fn decode_signed_direct_node_info( typed_signatures.push(typed_signature); } - SignedDirectNodeInfo::new(crypto, node_ids, node_info, timestamp, typed_signatures) - .map_err(RPCError::protocol) + Ok(SignedDirectNodeInfo::new( + node_info, + timestamp, + typed_signatures, + )) } diff --git a/veilid-core/src/rpc_processor/coders/signed_node_info.rs b/veilid-core/src/rpc_processor/coders/signed_node_info.rs index aeede197..e3ced6ad 100644 --- a/veilid-core/src/rpc_processor/coders/signed_node_info.rs +++ b/veilid-core/src/rpc_processor/coders/signed_node_info.rs @@ -20,8 +20,6 @@ pub fn encode_signed_node_info( pub fn decode_signed_node_info( reader: &veilid_capnp::signed_node_info::Reader, - crypto: Crypto, - node_ids: &mut TypedKeySet, ) -> Result { match reader .which() @@ -29,12 +27,12 @@ pub fn decode_signed_node_info( { veilid_capnp::signed_node_info::Direct(d) => { let d_reader = d.map_err(RPCError::protocol)?; - let sdni = decode_signed_direct_node_info(&d_reader, crypto, node_ids)?; + let sdni = decode_signed_direct_node_info(&d_reader)?; Ok(SignedNodeInfo::Direct(sdni)) } veilid_capnp::signed_node_info::Relayed(r) => { let r_reader = r.map_err(RPCError::protocol)?; - let srni = decode_signed_relayed_node_info(&r_reader, crypto, node_ids)?; + let srni = decode_signed_relayed_node_info(&r_reader)?; Ok(SignedNodeInfo::Relayed(srni)) } } diff --git a/veilid-core/src/rpc_processor/coders/signed_relayed_node_info.rs b/veilid-core/src/rpc_processor/coders/signed_relayed_node_info.rs index 4264e853..e4273e8e 100644 --- a/veilid-core/src/rpc_processor/coders/signed_relayed_node_info.rs +++ b/veilid-core/src/rpc_processor/coders/signed_relayed_node_info.rs @@ -6,16 +6,16 @@ pub fn encode_signed_relayed_node_info( ) -> Result<(), RPCError> { // let mut ni_builder = builder.reborrow().init_node_info(); - encode_node_info(&signed_relayed_node_info.node_info, &mut ni_builder)?; + encode_node_info(signed_relayed_node_info.node_info(), &mut ni_builder)?; let mut rids_builder = builder.reborrow().init_relay_ids( signed_relayed_node_info - .relay_ids + .relay_ids() .len() .try_into() .map_err(RPCError::map_invalid_format("out of bound error"))?, ); - for (i, typed_key) in signed_relayed_node_info.relay_ids.iter().enumerate() { + for (i, typed_key) in signed_relayed_node_info.relay_ids().iter().enumerate() { encode_typed_key( typed_key, &mut rids_builder.reborrow().get( @@ -26,20 +26,20 @@ pub fn encode_signed_relayed_node_info( } let mut ri_builder = builder.reborrow().init_relay_info(); - encode_signed_direct_node_info(&signed_relayed_node_info.relay_info, &mut ri_builder)?; + encode_signed_direct_node_info(signed_relayed_node_info.relay_info(), &mut ri_builder)?; builder .reborrow() - .set_timestamp(signed_relayed_node_info.timestamp.into()); + .set_timestamp(signed_relayed_node_info.timestamp().into()); let mut sigs_builder = builder.reborrow().init_signatures( signed_relayed_node_info - .signatures + .signatures() .len() .try_into() .map_err(RPCError::map_invalid_format("out of bound error"))?, ); - for (i, typed_signature) in signed_relayed_node_info.signatures.iter().enumerate() { + for (i, typed_signature) in signed_relayed_node_info.signatures().iter().enumerate() { encode_typed_signature( typed_signature, &mut sigs_builder.reborrow().get( @@ -54,8 +54,6 @@ pub fn encode_signed_relayed_node_info( pub fn decode_signed_relayed_node_info( reader: &veilid_capnp::signed_relayed_node_info::Reader, - crypto: Crypto, - node_ids: &mut TypedKeySet, ) -> Result { let ni_reader = reader .reborrow() @@ -81,20 +79,7 @@ pub fn decode_signed_relayed_node_info( .reborrow() .get_relay_info() .map_err(RPCError::protocol)?; - let relay_info = decode_signed_direct_node_info(&ri_reader, crypto.clone(), &mut relay_ids)?; - - // Ensure the relay info for the node has a superset of the crypto kinds of the node it is relaying - if common_crypto_kinds( - &node_info.crypto_support, - &relay_info.node_info.crypto_support, - ) - .len() - != node_info.crypto_support.len() - { - return Err(RPCError::protocol( - "relay should have superset of node crypto kinds", - )); - } + let relay_info = decode_signed_direct_node_info(&ri_reader)?; let timestamp = reader.reborrow().get_timestamp().into(); @@ -113,14 +98,11 @@ pub fn decode_signed_relayed_node_info( let typed_signature = decode_typed_signature(&sig_reader)?; typed_signatures.push(typed_signature); } - SignedRelayedNodeInfo::new( - crypto, - node_ids, + Ok(SignedRelayedNodeInfo::new( node_info, relay_ids, relay_info, timestamp, typed_signatures, - ) - .map_err(RPCError::protocol) + )) } diff --git a/veilid-core/src/rpc_processor/coders/signed_value_data.rs b/veilid-core/src/rpc_processor/coders/signed_value_data.rs index 6f65b304..a3d29932 100644 --- a/veilid-core/src/rpc_processor/coders/signed_value_data.rs +++ b/veilid-core/src/rpc_processor/coders/signed_value_data.rs @@ -16,7 +16,7 @@ pub fn encode_signed_value_data( pub fn decode_signed_value_data( reader: &veilid_capnp::signed_value_data::Reader, -) -> Result { +) -> Result { let seq = reader.get_seq(); let data = reader.get_data().map_err(RPCError::protocol)?.to_vec(); let wr = reader.get_writer().map_err(RPCError::protocol)?; @@ -24,8 +24,8 @@ pub fn decode_signed_value_data( let sr = reader.get_signature().map_err(RPCError::protocol)?; let signature = decode_signature512(&sr); - Ok(SignedValueData { - value_data: ValueData { seq, data, writer }, + Ok(SignedValueData::new( + ValueData::new_with_seq(seq, data, writer), signature, - }) + )) } diff --git a/veilid-core/src/rpc_processor/coders/signed_value_descriptor.rs b/veilid-core/src/rpc_processor/coders/signed_value_descriptor.rs index 22be6b5a..c1c93f69 100644 --- a/veilid-core/src/rpc_processor/coders/signed_value_descriptor.rs +++ b/veilid-core/src/rpc_processor/coders/signed_value_descriptor.rs @@ -7,7 +7,7 @@ pub fn encode_signed_value_descriptor( ) -> Result<(), RPCError> { let mut ob = builder.reborrow().init_owner(); encode_key256(signed_value_descriptor.owner(), &mut ob); - builder.set_data(signed_value_descriptor.data()); + builder.set_schema_data(signed_value_descriptor.schema_data()); let mut sb = builder.reborrow().init_signature(); encode_signature512(signed_value_descriptor.signature(), &mut sb); Ok(()) @@ -15,12 +15,14 @@ pub fn encode_signed_value_descriptor( pub fn decode_signed_value_descriptor( reader: &veilid_capnp::signed_value_descriptor::Reader, - vcrypto: CryptoSystemVersion, ) -> Result { let or = reader.get_owner().map_err(RPCError::protocol)?; let owner = decode_key256(&or); - let data = reader.get_data().map_err(RPCError::protocol)?.to_vec(); + let schema_data = reader + .get_schema_data() + .map_err(RPCError::protocol)? + .to_vec(); let sr = reader.get_signature().map_err(RPCError::protocol)?; let signature = decode_signature512(&sr); - Ok(SignedValueDescriptor::new(owner, data, signature, vcrypto).map_err(RPCError::protocol)?) + Ok(SignedValueDescriptor::new(owner, schema_data, signature)) } diff --git a/veilid-core/src/rpc_processor/coders/value_detail.rs b/veilid-core/src/rpc_processor/coders/value_detail.rs index c853861c..4eac9ee6 100644 --- a/veilid-core/src/rpc_processor/coders/value_detail.rs +++ b/veilid-core/src/rpc_processor/coders/value_detail.rs @@ -6,13 +6,31 @@ pub fn encode_value_detail( builder: &mut veilid_capnp::value_detail::Builder, ) -> Result<(), RPCError> { let mut svdb = builder.reborrow().init_signed_value_data(); - + encode_signed_value_data(value_detail.signed_value_data(), &mut svdb)?; + if let Some(descriptor) = value_detail.descriptor() { + let mut db = builder.reborrow().init_descriptor(); + encode_signed_value_descriptor(descriptor, &mut db)?; + } Ok(()) } pub fn decode_value_detail( reader: &veilid_capnp::value_detail::Reader, ) -> Result { + let svdr = reader.get_signed_value_data().map_err(RPCError::protocol)?; + let signed_value_data = decode_signed_value_data(&svdr)?; + + let descriptor = if reader.has_descriptor() { + let dr = reader + .reborrow() + .get_descriptor() + .map_err(RPCError::protocol)?; + let descriptor = decode_signed_value_descriptor(&dr)?; + Some(descriptor) + } else { + None + }; + Ok(ValueDetail { signed_value_data, descriptor, diff --git a/veilid-core/src/rpc_processor/mod.rs b/veilid-core/src/rpc_processor/mod.rs index a1d11478..d24f88f2 100644 --- a/veilid-core/src/rpc_processor/mod.rs +++ b/veilid-core/src/rpc_processor/mod.rs @@ -753,7 +753,7 @@ impl RPCProcessor { }; // Get our node info timestamp - let our_node_info_ts = own_peer_info.signed_node_info.timestamp(); + let our_node_info_ts = own_peer_info.signed_node_info().timestamp(); // If the target has seen our node info already don't send it again if target.has_seen_our_node_info_ts(routing_domain, our_node_info_ts) { @@ -1214,16 +1214,19 @@ impl RPCProcessor { .get_root::() .map_err(RPCError::protocol) .map_err(logthru_rpc!())?; - RPCOperation::decode(&op_reader, self.crypto.clone())? + RPCOperation::decode(&op_reader)? }; + // Validate the RPC operation + operation.validate(self.crypto.clone())?; + // Get the sender noderef, incorporating sender's peer info let mut opt_sender_nr: Option = None; if let Some(sender_peer_info) = operation.sender_peer_info() { // Ensure the sender peer info is for the actual sender specified in the envelope // Sender PeerInfo was specified, update our routing table with it - if !self.filter_node_info(routing_domain, &sender_peer_info.signed_node_info) { + if !self.filter_node_info(routing_domain, sender_peer_info.signed_node_info()) { return Err(RPCError::invalid_format( "sender peerinfo has invalid peer scope", )); @@ -1261,9 +1264,12 @@ impl RPCProcessor { .get_root::() .map_err(RPCError::protocol) .map_err(logthru_rpc!())?; - RPCOperation::decode(&op_reader, self.crypto.clone())? + RPCOperation::decode(&op_reader)? }; + // Validate the RPC operation + operation.validate(self.crypto.clone())?; + // Make the RPC message RPCMessage { header: encoded_msg.header, diff --git a/veilid-core/src/rpc_processor/rpc_find_node.rs b/veilid-core/src/rpc_processor/rpc_find_node.rs index a3a5af6e..18f3053e 100644 --- a/veilid-core/src/rpc_processor/rpc_find_node.rs +++ b/veilid-core/src/rpc_processor/rpc_find_node.rs @@ -52,7 +52,7 @@ impl RPCProcessor { // Verify peers are in the correct peer scope for peer_info in &find_node_a.peers { - if !self.filter_node_info(RoutingDomain::PublicInternet, &peer_info.signed_node_info) { + if !self.filter_node_info(RoutingDomain::PublicInternet, peer_info.signed_node_info()) { return Err(RPCError::invalid_format( "find_node response has invalid peer scope", )); diff --git a/veilid-core/src/rpc_processor/rpc_route.rs b/veilid-core/src/rpc_processor/rpc_route.rs index 14ddccc8..8eb4fb6f 100644 --- a/veilid-core/src/rpc_processor/rpc_route.rs +++ b/veilid-core/src/rpc_processor/rpc_route.rs @@ -341,8 +341,11 @@ impl RPCProcessor { let rh_reader = dec_blob_reader .get_root::() .map_err(RPCError::protocol)?; - decode_route_hop(&rh_reader, self.crypto.clone())? + decode_route_hop(&rh_reader)? }; + + // Validate the RouteHop + route_hop.validate(self.crypto.clone()).map_err(RPCError::protocol)?; // Sign the operation if this is not our last hop // as the last hop is already signed by the envelope @@ -422,8 +425,11 @@ impl RPCProcessor { let pr_reader = dec_blob_reader .get_root::() .map_err(RPCError::protocol)?; - decode_private_route(&pr_reader, self.crypto.clone())? + decode_private_route(&pr_reader)? }; + + // Validate the private route + private_route.validate(self.crypto.clone()).map_err(RPCError::protocol)?; // Switching from full safety route to private route first hop network_result_try!( @@ -440,9 +446,12 @@ impl RPCProcessor { let rh_reader = dec_blob_reader .get_root::() .map_err(RPCError::protocol)?; - decode_route_hop(&rh_reader, self.crypto.clone())? + decode_route_hop(&rh_reader)? }; + // Validate the route hop + route_hop.validate(self.crypto.clone()).map_err(RPCError::protocol)?; + // Continue the full safety route with another hop network_result_try!( self.process_route_safety_route_hop( diff --git a/veilid-core/src/storage_manager/mod.rs b/veilid-core/src/storage_manager/mod.rs index 695d8503..d5b3cfa3 100644 --- a/veilid-core/src/storage_manager/mod.rs +++ b/veilid-core/src/storage_manager/mod.rs @@ -3,9 +3,7 @@ mod record; mod record_data; mod record_store; mod record_store_limits; -mod signed_value_data; -mod signed_value_descriptor; -mod value_detail; +mod types; use keys::*; use record::*; @@ -13,9 +11,7 @@ use record_data::*; use record_store::*; use record_store_limits::*; -pub use signed_value_data::*; -pub use signed_value_descriptor::*; -pub use value_detail::*; +pub use types::*; use super::*; use crate::rpc_processor::*; @@ -174,14 +170,15 @@ impl StorageManager { &self, vcrypto: CryptoSystemVersion, record: Record, - ) -> Result<(), VeilidAPIError> { + ) -> Result { // add value record to record store let mut inner = self.inner.lock(); let Some(local_record_store) = inner.local_record_store.as_mut() else { apibail_generic!("not initialized"); }; let key = self.get_key(vcrypto.clone(), &record); - local_record_store.new_record(key, record).await + local_record_store.new_record(key, record).await?; + Ok(key) } pub async fn create_record( @@ -202,22 +199,27 @@ impl StorageManager { let owner = vcrypto.generate_keypair(); // Make a signed value descriptor for this dht value - let signed_value_descriptor = SignedValueDescriptor::new(owner.key, ) + let signed_value_descriptor = SignedValueDescriptor::make_signature( + owner.key, + schema_data, + vcrypto.clone(), + owner.secret, + )?; // Add new local value record let cur_ts = get_aligned_timestamp(); let record = Record::new( cur_ts, - owner.key, + signed_value_descriptor, Some(owner.secret), - schema, safety_selection, - ); - self.new_local_record(vcrypto.clone(), record) + )?; + let dht_key = self + .new_local_record(vcrypto, record) .await .map_err(VeilidAPIError::internal)?; - Ok(key) + Ok(dht_key) } pub async fn open_record( diff --git a/veilid-core/src/storage_manager/types/mod.rs b/veilid-core/src/storage_manager/types/mod.rs new file mode 100644 index 00000000..9fde6117 --- /dev/null +++ b/veilid-core/src/storage_manager/types/mod.rs @@ -0,0 +1,9 @@ +mod signed_value_data; +mod signed_value_descriptor; +mod value_detail; + +use super::*; + +pub use signed_value_data::*; +pub use signed_value_descriptor::*; +pub use value_detail::*; diff --git a/veilid-core/src/storage_manager/signed_value_data.rs b/veilid-core/src/storage_manager/types/signed_value_data.rs similarity index 83% rename from veilid-core/src/storage_manager/signed_value_data.rs rename to veilid-core/src/storage_manager/types/signed_value_data.rs index 5ca2acba..29c69dce 100644 --- a/veilid-core/src/storage_manager/signed_value_data.rs +++ b/veilid-core/src/storage_manager/types/signed_value_data.rs @@ -24,31 +24,32 @@ pub struct SignedValueData { signature: Signature, } impl SignedValueData { - pub fn new( - value_data: ValueData, - owner: PublicKey, - subkey: ValueSubkey, - signature: Signature, - vcrypto: CryptoSystemVersion, - ) -> Result { - let node_info_bytes = Self::make_signature_bytes(&value_data, &owner, subkey)?; - - // validate signature - vcrypto.verify(&value_data.writer(), &node_info_bytes, &signature)?; - Ok(Self { + pub fn new(value_data: ValueData, signature: Signature) -> Self { + Self { value_data, signature, - }) + } + } + + pub fn validate( + &self, + owner: &PublicKey, + subkey: ValueSubkey, + vcrypto: CryptoSystemVersion, + ) -> Result<(), VeilidAPIError> { + let node_info_bytes = Self::make_signature_bytes(&self.value_data, owner, subkey)?; + // validate signature + vcrypto.verify(&self.value_data.writer(), &node_info_bytes, &self.signature) } pub fn make_signature( value_data: ValueData, - owner: PublicKey, + owner: &PublicKey, subkey: ValueSubkey, vcrypto: CryptoSystemVersion, writer_secret: SecretKey, ) -> Result { - let node_info_bytes = Self::make_signature_bytes(&value_data, &owner, subkey)?; + let node_info_bytes = Self::make_signature_bytes(&value_data, owner, subkey)?; // create signature let signature = vcrypto.sign(&value_data.writer(), &writer_secret, &node_info_bytes)?; diff --git a/veilid-core/src/storage_manager/signed_value_descriptor.rs b/veilid-core/src/storage_manager/types/signed_value_descriptor.rs similarity index 75% rename from veilid-core/src/storage_manager/signed_value_descriptor.rs rename to veilid-core/src/storage_manager/types/signed_value_descriptor.rs index 84442bc4..917d3dfc 100644 --- a/veilid-core/src/storage_manager/signed_value_descriptor.rs +++ b/veilid-core/src/storage_manager/types/signed_value_descriptor.rs @@ -25,20 +25,17 @@ pub struct SignedValueDescriptor { signature: Signature, } impl SignedValueDescriptor { - pub fn new( - owner: PublicKey, - schema_data: Vec, - signature: Signature, - vcrypto: CryptoSystemVersion, - ) -> Result { - // validate signature - vcrypto.verify(&owner, &schema_data, &signature)?; - - Ok(Self { + pub fn new(owner: PublicKey, schema_data: Vec, signature: Signature) -> Self { + Self { owner, schema_data, signature, - }) + } + } + + pub fn validate(&self, vcrypto: CryptoSystemVersion) -> Result<(), VeilidAPIError> { + // validate signature + vcrypto.verify(&self.owner, &self.schema_data, &self.signature) } pub fn owner(&self) -> &PublicKey { @@ -75,4 +72,12 @@ impl SignedValueDescriptor { pub fn total_size(&self) -> usize { mem::size_of::() + self.schema_data.len() } + + pub fn cmp_no_sig(&self, other: &Self) -> cmp::Ordering { + let o = self.owner.cmp(&other.owner); + if o != cmp::Ordering::Equal { + return o; + } + self.schema_data.cmp(&other.schema_data) + } } diff --git a/veilid-core/src/storage_manager/types/value_detail.rs b/veilid-core/src/storage_manager/types/value_detail.rs new file mode 100644 index 00000000..4f633dcc --- /dev/null +++ b/veilid-core/src/storage_manager/types/value_detail.rs @@ -0,0 +1,77 @@ +use super::*; +use rkyv::{Archive as RkyvArchive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; +use serde::*; + +///////////////////////////////////////////////////////////////////////////////////////////////////// +/// + +#[derive( + Clone, + Debug, + PartialOrd, + PartialEq, + Eq, + Ord, + Serialize, + Deserialize, + RkyvArchive, + RkyvSerialize, + RkyvDeserialize, +)] +#[archive_attr(repr(C), derive(CheckBytes))] +pub struct ValueDetail { + signed_value_data: SignedValueData, + descriptor: Option, +} + +impl ValueDetail { + pub fn new( + signed_value_data: SignedValueData, + descriptor: Option, + ) -> Self { + Self { + signed_value_data, + descriptor, + } + } + + pub fn validate( + &self, + last_descriptor: Option<&SignedValueDescriptor>, + subkey: ValueSubkey, + vcrypto: CryptoSystemVersion, + ) -> Result<(), VeilidAPIError> { + // Get descriptor to validate with + let descriptor = if let Some(descriptor) = &self.descriptor { + if let Some(last_descriptor) = last_descriptor { + if descriptor.cmp_no_sig(&last_descriptor) != cmp::Ordering::Equal { + return Err(VeilidAPIError::generic( + "value detail descriptor does not match last descriptor", + )); + } + } + descriptor + } else { + let Some(descriptor) = last_descriptor else { + return Err(VeilidAPIError::generic( + "no last descriptor, requires a descriptor", + )); + }; + descriptor + }; + + // Ensure the descriptor itself validates + descriptor.validate(vcrypto.clone())?; + + // And the signed value data + self.signed_value_data + .validate(descriptor.owner(), subkey, vcrypto) + } + + pub fn signed_value_data(&self) -> &SignedValueData { + &self.signed_value_data + } + pub fn descriptor(&self) -> Option<&SignedValueDescriptor> { + self.descriptor.as_ref() + } +} diff --git a/veilid-core/src/storage_manager/value_detail.rs b/veilid-core/src/storage_manager/value_detail.rs deleted file mode 100644 index 85135f10..00000000 --- a/veilid-core/src/storage_manager/value_detail.rs +++ /dev/null @@ -1,43 +0,0 @@ -use super::*; -use rkyv::{Archive as RkyvArchive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; -use serde::*; - -///////////////////////////////////////////////////////////////////////////////////////////////////// -/// - -#[derive( - Clone, - Debug, - PartialOrd, - PartialEq, - Eq, - Ord, - Serialize, - Deserialize, - RkyvArchive, - RkyvSerialize, - RkyvDeserialize, -)] -#[archive_attr(repr(C), derive(CheckBytes))] -pub struct ValueDetail { - signed_value_data: SignedValueData, - descriptor: Option, -} - -impl ValueDetail { - pub fn new( - signed_value_data: SignedValueData, - descriptor: Option, - ) -> Self { - Self { - signed_value_data, - descriptor, - } - } - pub fn signed_value_data(&self) -> &SignedValueData { - &self.signed_value_data - } - pub fn descriptor(&self) -> Option<&SignedValueDescriptor> { - self.descriptor.as_ref() - } -}