zoe_wire_protocol/
connection_info.rs

1//! Connection information for authenticated connections
2//!
3//! This module provides the `ConnectionInfo` type that tracks both transport-level
4//! and application-level authentication for active connections in the Zoe protocol.
5
6use crate::VerifyingKey;
7use std::collections::HashSet;
8use std::net::SocketAddr;
9use std::time::SystemTime;
10
11/// Connection information with verified cryptographic keys
12///
13/// This structure tracks both transport-level and application-level authentication
14/// for active connections in the Zoe protocol. It provides the foundation for
15/// connection-scoped message authentication across multiple key algorithms.
16///
17/// ## Authentication Layers
18///
19/// 1. **Transport Layer**: TLS certificate provides connection-level identity
20/// 2. **Application Layer**: Verified keys provide message-level authentication
21///
22/// The separation allows for different keys to be used for different purposes
23/// while maintaining a clear security model across Ed25519 and ML-DSA algorithms.
24#[derive(Debug, Clone)]
25pub struct ConnectionInfo {
26    /// The public key from the client's TLS certificate
27    ///
28    /// This key identifies the client at the transport layer and is used
29    /// for QUIC connection authentication. It remains constant for the
30    /// lifetime of the connection. Supports Ed25519, ML-DSA-44, ML-DSA-65, ML-DSA-87.
31    pub transport_public_key: VerifyingKey,
32
33    /// Set of public keys verified during challenge handshake
34    ///
35    /// These keys were proven during the initial handshake and can be used
36    /// for message-level authentication. The set is populated during the
37    /// challenge phase and remains immutable for the connection lifetime.
38    ///
39    /// Supports all key algorithms: Ed25519, ML-DSA-44, ML-DSA-65, ML-DSA-87.
40    /// Use `has_verified_key()` for membership testing.
41    pub verified_keys: HashSet<VerifyingKey>,
42
43    /// The remote network address of the client
44    pub remote_address: SocketAddr,
45
46    /// Timestamp when the connection was established
47    pub connected_at: SystemTime,
48}
49
50impl ConnectionInfo {
51    /// Create a new ConnectionInfo with the given transport public key and remote address
52    ///
53    /// # Parameters
54    ///
55    /// * `transport_public_key` - The public key from the client's TLS certificate
56    /// * `remote_address` - The remote network address of the client
57    ///
58    /// # Returns
59    ///
60    /// A new `ConnectionInfo` with empty verified keys set and current timestamp
61    pub fn new(transport_public_key: VerifyingKey, remote_address: SocketAddr) -> Self {
62        Self {
63            transport_public_key,
64            verified_keys: HashSet::new(),
65            remote_address,
66            connected_at: SystemTime::now(),
67        }
68    }
69
70    /// Create a new ConnectionInfo with verified keys
71    ///
72    /// # Parameters
73    ///
74    /// * `transport_public_key` - The public key from the client's TLS certificate
75    /// * `verified_keys` - Set of keys verified during handshake
76    /// * `remote_address` - The remote network address of the client
77    ///
78    /// # Returns
79    ///
80    /// A new `ConnectionInfo` with the provided verified keys and current timestamp
81    pub fn with_verified_keys(
82        transport_public_key: VerifyingKey,
83        verified_keys: HashSet<VerifyingKey>,
84        remote_address: SocketAddr,
85    ) -> Self {
86        Self {
87            transport_public_key,
88            verified_keys,
89            remote_address,
90            connected_at: SystemTime::now(),
91        }
92    }
93
94    /// Add a verified key to this connection
95    ///
96    /// # Parameters
97    ///
98    /// * `public_key` - The public key to add
99    pub fn add_verified_key(&mut self, public_key: VerifyingKey) {
100        self.verified_keys.insert(public_key);
101    }
102
103    /// Check if a specific public key has been verified for this connection
104    ///
105    /// This is the primary method for checking message authentication permissions.
106    /// Services should call this before processing messages that require specific
107    /// key possession proofs.
108    ///
109    /// # Parameters
110    ///
111    /// * `public_key` - The public key to check
112    ///
113    /// # Returns
114    ///
115    /// `true` if the key was successfully verified during handshake, `false` otherwise
116    ///
117    /// # Example
118    ///
119    /// ```rust
120    /// use zoe_wire_protocol::ConnectionInfo;
121    /// use std::net::SocketAddr;
122    ///
123    /// # fn example(connection_info: &ConnectionInfo, required_key: &zoe_wire_protocol::VerifyingKey) -> Result<(), String> {
124    /// // In a message service handler
125    /// if !connection_info.has_verified_key(required_key) {
126    ///     return Err(format!(
127    ///         "Verification required for key: {}",
128    ///         hex::encode(required_key.id())
129    ///     ));
130    /// }
131    /// # Ok(())
132    /// # }
133    /// ```
134    pub fn has_verified_key(&self, public_key: &VerifyingKey) -> bool {
135        self.verified_keys.contains(public_key)
136    }
137
138    /// Get the number of verified keys for this connection
139    ///
140    /// Useful for logging and debugging connection capabilities.
141    ///
142    /// # Returns
143    ///
144    /// The count of keys that were successfully verified during handshake
145    pub fn verified_key_count(&self) -> usize {
146        self.verified_keys.len()
147    }
148
149    /// Get all verified public keys as hex strings (for logging/debugging)
150    ///
151    /// Returns a vector of hex-encoded key IDs for human-readable logging.
152    /// Uses the key's ID (which is a hash for ML-DSA keys or the key bytes for Ed25519).
153    ///
154    /// # Returns
155    ///
156    /// Vector of hex strings representing the key IDs of each verified key
157    ///
158    /// # Example
159    ///
160    /// ```rust
161    /// use zoe_wire_protocol::ConnectionInfo;
162    ///
163    /// # fn example(connection_info: &ConnectionInfo) {
164    /// let key_previews = connection_info.verified_keys_hex();
165    /// println!("Connection has verified keys: {:?}", key_previews);
166    /// // Output: ["a1b2c3d4e5f6g7h8...", "9a8b7c6d5e4f3g2h..."]
167    /// # }
168    /// ```
169    pub fn verified_keys_hex(&self) -> Vec<String> {
170        self.verified_keys
171            .iter()
172            .map(|key| hex::encode(key.id()))
173            .collect()
174    }
175
176    /// Get a reference to the verified keys set
177    ///
178    /// # Returns
179    ///
180    /// A reference to the HashSet containing all verified keys
181    pub fn verified_keys(&self) -> &HashSet<VerifyingKey> {
182        &self.verified_keys
183    }
184}
185
186#[cfg(test)]
187mod tests {
188    use super::*;
189    use crate::KeyPair;
190    use std::net::{IpAddr, Ipv4Addr};
191
192    #[test]
193    fn test_connection_info_creation() {
194        let keypair = KeyPair::generate_ml_dsa44(&mut rand::thread_rng());
195        let transport_key = keypair.public_key();
196        let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 8080);
197
198        let conn_info = ConnectionInfo::new(transport_key.clone(), remote_addr);
199
200        assert_eq!(conn_info.transport_public_key, transport_key);
201        assert_eq!(conn_info.remote_address, remote_addr);
202        assert_eq!(conn_info.verified_key_count(), 0);
203        assert!(conn_info.verified_keys().is_empty());
204    }
205
206    #[test]
207    fn test_connection_info_with_verified_keys() {
208        let keypair1 = KeyPair::generate_ml_dsa44(&mut rand::thread_rng());
209        let keypair2 = KeyPair::generate_ed25519(&mut rand::thread_rng());
210        let transport_key = keypair1.public_key();
211        let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 8080);
212
213        let mut verified_keys = HashSet::new();
214        verified_keys.insert(keypair1.public_key());
215        verified_keys.insert(keypair2.public_key());
216
217        let conn_info = ConnectionInfo::with_verified_keys(
218            transport_key.clone(),
219            verified_keys.clone(),
220            remote_addr,
221        );
222
223        assert_eq!(conn_info.transport_public_key, transport_key);
224        assert_eq!(conn_info.remote_address, remote_addr);
225        assert_eq!(conn_info.verified_key_count(), 2);
226        assert_eq!(conn_info.verified_keys(), &verified_keys);
227    }
228
229    #[test]
230    fn test_add_verified_key() {
231        let keypair1 = KeyPair::generate_ml_dsa44(&mut rand::thread_rng());
232        let keypair2 = KeyPair::generate_ed25519(&mut rand::thread_rng());
233        let transport_key = keypair1.public_key();
234        let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 8080);
235
236        let mut conn_info = ConnectionInfo::new(transport_key, remote_addr);
237        assert_eq!(conn_info.verified_key_count(), 0);
238
239        let test_key = keypair2.public_key();
240        conn_info.add_verified_key(test_key.clone());
241        assert_eq!(conn_info.verified_key_count(), 1);
242        assert!(conn_info.has_verified_key(&test_key));
243    }
244
245    #[test]
246    fn test_has_verified_key() {
247        let keypair1 = KeyPair::generate_ml_dsa44(&mut rand::thread_rng());
248        let keypair2 = KeyPair::generate_ed25519(&mut rand::thread_rng());
249        let keypair3 = KeyPair::generate_ml_dsa65(&mut rand::thread_rng());
250        let transport_key = keypair1.public_key();
251        let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 8080);
252
253        let mut verified_keys = HashSet::new();
254        let verified_key = keypair2.public_key();
255        verified_keys.insert(verified_key.clone());
256
257        let conn_info =
258            ConnectionInfo::with_verified_keys(transport_key, verified_keys, remote_addr);
259
260        assert!(conn_info.has_verified_key(&verified_key));
261        assert!(!conn_info.has_verified_key(&keypair3.public_key()));
262    }
263
264    #[test]
265    fn test_verified_keys_hex() {
266        let keypair1 = KeyPair::generate_ml_dsa44(&mut rand::thread_rng());
267        let keypair2 = KeyPair::generate_ed25519(&mut rand::thread_rng());
268        let transport_key = keypair1.public_key();
269        let remote_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 100)), 8080);
270
271        let mut verified_keys = HashSet::new();
272        let key1 = keypair1.public_key();
273        let key2 = keypair2.public_key();
274        verified_keys.insert(key1.clone());
275        verified_keys.insert(key2.clone());
276
277        let conn_info =
278            ConnectionInfo::with_verified_keys(transport_key, verified_keys, remote_addr);
279        let hex_keys = conn_info.verified_keys_hex();
280
281        assert_eq!(hex_keys.len(), 2);
282        assert!(hex_keys.contains(&hex::encode(key1.id())));
283        assert!(hex_keys.contains(&hex::encode(key2.id())));
284    }
285}