mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-06 17:59:11 +00:00
feat(credential): implement credential peer auth and trust propagation (#1968)
- add credential manager and RPC/CLI for generate/list/revoke - support credential-based Noise authentication and revocation handling - propagate trusted credential metadata through OSPF route sync - classify direct peers by auth level in session maintenance - normalize sender credential flag for legacy non-secure compatibility - add unit/integration tests for credential join, relay and revocation
This commit is contained in:
@@ -43,7 +43,8 @@ use crate::{
|
||||
ListGlobalForeignNetworkResponse,
|
||||
},
|
||||
peer_rpc::{
|
||||
ForeignNetworkRouteInfoEntry, ForeignNetworkRouteInfoKey, RouteForeignNetworkSummary,
|
||||
ForeignNetworkRouteInfoEntry, ForeignNetworkRouteInfoKey, PeerIdentityType,
|
||||
RouteForeignNetworkSummary,
|
||||
},
|
||||
},
|
||||
tunnel::{
|
||||
@@ -374,12 +375,34 @@ impl PeerManager {
|
||||
}
|
||||
|
||||
async fn add_new_peer_conn(&self, peer_conn: PeerConn) -> Result<(), Error> {
|
||||
if self.global_ctx.get_network_identity() != peer_conn.get_network_identity() {
|
||||
let my_identity = self.global_ctx.get_network_identity();
|
||||
let peer_identity = peer_conn.get_network_identity();
|
||||
|
||||
// For credential nodes, network_secret_digest is either None or all-zeros
|
||||
// (all-zeros when received over the wire via handshake).
|
||||
// In this case, only compare network_name.
|
||||
let my_digest_empty = my_identity
|
||||
.network_secret_digest
|
||||
.as_ref()
|
||||
.is_none_or(|d| d.iter().all(|b| *b == 0));
|
||||
let peer_digest_empty = peer_identity
|
||||
.network_secret_digest
|
||||
.as_ref()
|
||||
.is_none_or(|d| d.iter().all(|b| *b == 0));
|
||||
|
||||
let identity_ok = if my_digest_empty || peer_digest_empty {
|
||||
// Credential node: only check network_name
|
||||
my_identity.network_name == peer_identity.network_name
|
||||
} else {
|
||||
my_identity == peer_identity
|
||||
};
|
||||
|
||||
if !identity_ok {
|
||||
return Err(Error::SecretKeyError(
|
||||
"network identity not match".to_string(),
|
||||
));
|
||||
}
|
||||
self.peers.add_new_peer_conn(peer_conn).await;
|
||||
self.peers.add_new_peer_conn(peer_conn).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -414,7 +437,7 @@ impl PeerManager {
|
||||
{
|
||||
self.add_new_peer_conn(peer).await?;
|
||||
} else {
|
||||
self.foreign_network_client.add_new_peer_conn(peer).await;
|
||||
self.foreign_network_client.add_new_peer_conn(peer).await?;
|
||||
}
|
||||
Ok((peer_id, conn_id))
|
||||
}
|
||||
@@ -674,6 +697,12 @@ impl PeerManager {
|
||||
let secure_mode_enabled = self.is_secure_mode_enabled;
|
||||
let stats_mgr = self.global_ctx.stats_manager().clone();
|
||||
let route = self.get_route();
|
||||
let is_credential_node = self
|
||||
.global_ctx
|
||||
.get_network_identity()
|
||||
.network_secret
|
||||
.is_none()
|
||||
&& secure_mode_enabled;
|
||||
|
||||
let label_set =
|
||||
LabelSet::new().with_label_type(LabelType::NetworkName(global_ctx.get_network_name()));
|
||||
@@ -721,6 +750,17 @@ impl PeerManager {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Step 10b: credential nodes don't forward handshake packets
|
||||
if is_credential_node
|
||||
&& (hdr.packet_type == PacketType::HandShake as u8
|
||||
|| hdr.packet_type == PacketType::NoiseHandshakeMsg1 as u8
|
||||
|| hdr.packet_type == PacketType::NoiseHandshakeMsg2 as u8
|
||||
|| hdr.packet_type == PacketType::NoiseHandshakeMsg3 as u8)
|
||||
{
|
||||
tracing::debug!("credential node dropping forwarded handshake packet");
|
||||
continue;
|
||||
}
|
||||
|
||||
if hdr.forward_counter > 2 && hdr.is_latency_first() {
|
||||
tracing::trace!(?hdr, "set_latency_first false because too many hop");
|
||||
hdr.set_latency_first(false);
|
||||
@@ -934,6 +974,11 @@ impl PeerManager {
|
||||
self.my_peer_id
|
||||
}
|
||||
|
||||
async fn get_peer_identity_type(&self, peer_id: PeerId) -> Option<PeerIdentityType> {
|
||||
let peer_map = self.peers.upgrade()?;
|
||||
peer_map.get_peer_identity_type(peer_id)
|
||||
}
|
||||
|
||||
async fn list_foreign_networks(&self) -> ForeignNetworkRouteInfoMap {
|
||||
let ret = DashMap::new();
|
||||
let Some(foreign_mgr) = self.foreign_network_manager.upgrade() else {
|
||||
@@ -1965,7 +2010,7 @@ mod tests {
|
||||
return false;
|
||||
};
|
||||
conns.iter().any(|c| {
|
||||
c.secure_auth_level == SecureAuthLevel::SharedNodePubkeyVerified as i32
|
||||
c.secure_auth_level == SecureAuthLevel::PeerVerified as i32
|
||||
&& c.noise_local_static_pubkey.len() == 32
|
||||
&& c.noise_remote_static_pubkey.len() == 32
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user