Skip to main content

nodedb_cluster/transport/
auth_context.rs

1// SPDX-License-Identifier: BUSL-1.1
2
3//! Per-transport authentication state shared across inbound and outbound
4//! paths.
5//!
6//! The [`AuthContext`] bundles the MAC key and the per-peer sequence
7//! trackers so that `send.rs`, `serve.rs`, and the spawned per-connection
8//! tasks all operate on the same state. Wrapped in an `Arc` and cloned
9//! into every per-connection / per-stream task.
10
11use crate::rpc_codec::{MacKey, PeerSeqSender, PeerSeqWindow};
12
13use super::credentials::TransportCredentials;
14
15/// Shared auth state — node identity, MAC key, per-peer counters.
16#[derive(Debug)]
17pub struct AuthContext {
18    /// Local node id. Used as `from_node_id` on every outbound envelope.
19    pub local_node_id: u64,
20    /// Cluster-wide MAC key. `MacKey::zero()` when the transport was
21    /// constructed with [`TransportCredentials::Insecure`] — replay
22    /// protection is cosmetic in that mode.
23    pub mac_key: MacKey,
24    /// Outbound sequence counters, keyed by remote peer id. `peer_id = 0`
25    /// is the fallback key for bootstrap RPCs sent to an address whose
26    /// node id is not yet known.
27    pub peer_seq_out: PeerSeqSender,
28    /// Inbound replay-detection windows, keyed by the `from_node_id`
29    /// advertised in the envelope (and MAC-verified before consultation).
30    pub peer_seq_in: PeerSeqWindow,
31}
32
33impl AuthContext {
34    /// Build an auth context from the same credentials that drive the
35    /// TLS configuration.
36    pub fn from_credentials(local_node_id: u64, creds: &TransportCredentials) -> Self {
37        let mac_key = match creds {
38            TransportCredentials::Mtls(tls) => MacKey::from_bytes(tls.cluster_secret),
39            TransportCredentials::Insecure => MacKey::zero(),
40        };
41        Self {
42            local_node_id,
43            mac_key,
44            peer_seq_out: PeerSeqSender::new(),
45            peer_seq_in: PeerSeqWindow::new(),
46        }
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53    use crate::transport::config::TlsCredentials;
54    use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer};
55
56    fn dummy_tls(secret: [u8; 32]) -> TlsCredentials {
57        TlsCredentials {
58            cert: CertificateDer::from(vec![1, 2, 3]),
59            key: PrivateKeyDer::from(PrivatePkcs8KeyDer::from(vec![4, 5, 6])),
60            ca_cert: CertificateDer::from(vec![7, 8, 9]),
61            additional_ca_certs: Vec::new(),
62            crls: Vec::new(),
63            cluster_secret: secret,
64            spki_pin: [0u8; 32],
65        }
66    }
67
68    #[test]
69    fn insecure_yields_zero_mac_key() {
70        let ctx = AuthContext::from_credentials(1, &TransportCredentials::Insecure);
71        assert!(ctx.mac_key.is_zero());
72        assert_eq!(ctx.local_node_id, 1);
73    }
74
75    #[test]
76    fn mtls_yields_cluster_secret() {
77        let secret = [0xABu8; 32];
78        let ctx = AuthContext::from_credentials(42, &TransportCredentials::Mtls(dummy_tls(secret)));
79        assert!(!ctx.mac_key.is_zero());
80        assert_eq!(ctx.mac_key.as_bytes(), &secret);
81    }
82}