1use std::{
8 collections::HashMap,
9 sync::Arc,
10 time::{Duration, Instant, SystemTime},
11};
12
13use ed25519_dalek::{
14 Signature, Signer, SigningKey as Ed25519SecretKey, Verifier, VerifyingKey as Ed25519PublicKey,
15};
16
17use serde::{Deserialize, Serialize};
18use tokio::sync::RwLock;
19use tracing::{debug, info, warn, error};
20
21use crate::{
22 nat_traversal_api::PeerId,
23 crypto::raw_public_keys::key_utils::{
24 public_key_to_bytes, public_key_from_bytes,
25 derive_peer_id_from_public_key, verify_peer_id,
26 },
27};
28
29fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
31 let len_equal = a.len() == b.len();
33
34 let min_len = a.len().min(b.len());
36 let mut result = 0u8;
37
38 for i in 0..min_len {
40 result |= a[i] ^ b[i];
41 }
42
43 if !len_equal {
45 result |= 1;
46 }
47
48 result == 0
50}
51
52#[derive(Debug, thiserror::Error)]
54pub enum AuthError {
55 #[error("Invalid signature")]
56 InvalidSignature,
57 #[error("Challenge expired")]
58 ChallengeExpired,
59 #[error("Peer not found")]
60 PeerNotFound,
61 #[error("Authentication timeout")]
62 Timeout,
63 #[error("Invalid peer ID")]
64 InvalidPeerId,
65 #[error("Signature error: {0}")]
66 SignatureError(String),
67 #[error("Serialization error: {0}")]
68 SerializationError(String),
69 #[error("Key error: {0}")]
70 KeyError(String),
71}
72
73#[derive(Debug, Clone)]
75pub struct AuthConfig {
76 pub auth_timeout: Duration,
78 pub challenge_validity: Duration,
80 pub require_authentication: bool,
82 pub max_auth_attempts: u32,
84}
85
86impl Default for AuthConfig {
87 fn default() -> Self {
88 Self {
89 auth_timeout: Duration::from_secs(10),
90 challenge_validity: Duration::from_secs(60),
91 require_authentication: true,
92 max_auth_attempts: 3,
93 }
94 }
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
99pub enum AuthMessage {
100 AuthRequest {
102 peer_id: PeerId,
103 public_key: [u8; 32],
104 timestamp: SystemTime,
105 },
106 Challenge {
108 nonce: [u8; 32],
109 timestamp: SystemTime,
110 },
111 ChallengeResponse {
113 nonce: [u8; 32],
114 signature: Vec<u8>,
115 timestamp: SystemTime,
116 },
117 AuthSuccess {
119 session_id: [u8; 32],
120 timestamp: SystemTime,
121 },
122 AuthFailure {
124 reason: String,
125 },
126}
127
128#[derive(Debug, Clone)]
130pub struct AuthenticatedPeer {
131 pub peer_id: PeerId,
133 pub public_key: Ed25519PublicKey,
135 pub authenticated_at: Instant,
137 pub session_id: [u8; 32],
139}
140
141pub struct AuthManager {
143 secret_key: Ed25519SecretKey,
145 public_key: Ed25519PublicKey,
147 peer_id: PeerId,
149 config: AuthConfig,
151 authenticated_peers: Arc<RwLock<HashMap<PeerId, AuthenticatedPeer>>>,
153 pending_challenges: Arc<RwLock<HashMap<PeerId, PendingChallenge>>>,
155}
156
157#[derive(Debug)]
159struct PendingChallenge {
160 nonce: [u8; 32],
161 created_at: Instant,
162 attempts: u32,
163}
164
165impl AuthManager {
166 pub fn new(secret_key: Ed25519SecretKey, config: AuthConfig) -> Self {
168 let public_key = secret_key.verifying_key();
169 let peer_id = derive_peer_id_from_public_key(&public_key);
170
171 info!("Initialized AuthManager with peer ID: {:?}", peer_id);
172
173 Self {
174 secret_key,
175 public_key,
176 peer_id,
177 config,
178 authenticated_peers: Arc::new(RwLock::new(HashMap::new())),
179 pending_challenges: Arc::new(RwLock::new(HashMap::new())),
180 }
181 }
182
183 pub fn peer_id(&self) -> PeerId {
185 self.peer_id
186 }
187
188 pub fn public_key_bytes(&self) -> [u8; 32] {
190 public_key_to_bytes(&self.public_key)
191 }
192
193 pub fn config(&self) -> &AuthConfig {
195 &self.config
196 }
197
198 pub fn create_auth_request(&self) -> AuthMessage {
200 AuthMessage::AuthRequest {
201 peer_id: self.peer_id,
202 public_key: self.public_key_bytes(),
203 timestamp: SystemTime::now(),
204 }
205 }
206
207 pub async fn handle_auth_request(
209 &self,
210 peer_id: PeerId,
211 public_key_bytes: [u8; 32],
212 ) -> Result<AuthMessage, AuthError> {
213 let public_key = public_key_from_bytes(&public_key_bytes)
215 .map_err(|e| AuthError::KeyError(e.to_string()))?;
216
217 if !verify_peer_id(&peer_id, &public_key) {
218 return Err(AuthError::InvalidPeerId);
219 }
220
221 let nonce = {
223 use rand::Rng;
224 let mut nonce = [0u8; 32];
225 rand::thread_rng().fill(&mut nonce);
226 nonce
227 };
228
229 let mut challenges = self.pending_challenges.write().await;
231 challenges.insert(peer_id, PendingChallenge {
232 nonce,
233 created_at: Instant::now(),
234 attempts: 0,
235 });
236
237 debug!("Created challenge for peer {:?}", peer_id);
238
239 Ok(AuthMessage::Challenge {
240 nonce,
241 timestamp: SystemTime::now(),
242 })
243 }
244
245 pub fn create_challenge_response(&self, nonce: [u8; 32]) -> Result<AuthMessage, AuthError> {
247 let signature = self.secret_key.sign(&nonce);
249
250 Ok(AuthMessage::ChallengeResponse {
251 nonce,
252 signature: signature.to_vec(),
253 timestamp: SystemTime::now(),
254 })
255 }
256
257 pub async fn verify_challenge_response(
259 &self,
260 peer_id: PeerId,
261 public_key_bytes: [u8; 32],
262 nonce: [u8; 32],
263 signature_bytes: &[u8],
264 ) -> Result<AuthMessage, AuthError> {
265 let mut challenges = self.pending_challenges.write().await;
269 let challenge_exists = challenges.contains_key(&peer_id);
270 let stored_nonce = challenges.get(&peer_id).map(|c| c.nonce).unwrap_or([0u8; 32]);
271 let created_at = challenges.get(&peer_id).map(|c| c.created_at).unwrap_or(Instant::now());
272 let attempts = challenges.get_mut(&peer_id).map(|c| {
273 c.attempts += 1;
274 c.attempts
275 }).unwrap_or(0);
276
277 let nonce_matches = constant_time_eq(&stored_nonce, &nonce);
279 let not_expired = created_at.elapsed() <= self.config.challenge_validity;
280 let attempts_ok = attempts < self.config.max_auth_attempts;
281
282 let public_key_result = public_key_from_bytes(&public_key_bytes);
284 let signature_result = Signature::from_slice(signature_bytes);
285
286 let verification_result = match (public_key_result, signature_result) {
288 (Ok(pk), Ok(sig)) => pk.verify(&nonce, &sig).is_ok(),
289 _ => false,
290 };
291
292 let session_id = {
294 use rand::Rng;
295 let mut id = [0u8; 32];
296 rand::thread_rng().fill(&mut id);
297 id
298 };
299
300 let all_valid = challenge_exists && nonce_matches && not_expired &&
302 attempts_ok && verification_result;
303
304 debug!("Verification results - exists: {}, nonce_matches: {}, not_expired: {}, attempts_ok: {}, verification: {}",
305 challenge_exists, nonce_matches, not_expired, attempts_ok, verification_result);
306
307 if all_valid {
309 challenges.remove(&peer_id);
311 drop(challenges); if let Ok(public_key) = public_key_from_bytes(&public_key_bytes) {
315 let mut peers = self.authenticated_peers.write().await;
316 peers.insert(peer_id, AuthenticatedPeer {
317 peer_id,
318 public_key,
319 authenticated_at: Instant::now(),
320 session_id,
321 });
322
323 info!("Successfully authenticated peer {:?}", peer_id);
324 }
325
326 Ok(AuthMessage::AuthSuccess {
327 session_id,
328 timestamp: SystemTime::now(),
329 })
330 } else {
331 let error = if !challenge_exists {
333 AuthError::PeerNotFound
334 } else if !not_expired {
335 challenges.remove(&peer_id);
336 AuthError::ChallengeExpired
337 } else if !attempts_ok {
338 challenges.remove(&peer_id);
339 AuthError::InvalidSignature
340 } else if !nonce_matches {
341 AuthError::InvalidSignature
342 } else {
343 AuthError::InvalidSignature
344 };
345
346 Err(error)
347 }
348 }
349
350 pub async fn is_authenticated(&self, peer_id: &PeerId) -> bool {
352 let peers = self.authenticated_peers.read().await;
353 peers.contains_key(peer_id)
354 }
355
356 pub async fn get_authenticated_peer(&self, peer_id: &PeerId) -> Option<AuthenticatedPeer> {
358 let peers = self.authenticated_peers.read().await;
359 peers.get(peer_id).cloned()
360 }
361
362 pub async fn handle_auth_success(
364 &self,
365 peer_id: PeerId,
366 public_key_bytes: [u8; 32],
367 session_id: [u8; 32],
368 ) -> Result<(), AuthError> {
369 let public_key = public_key_from_bytes(&public_key_bytes)
371 .map_err(|e| AuthError::KeyError(e.to_string()))?;
372
373 let mut peers = self.authenticated_peers.write().await;
375 peers.insert(peer_id, AuthenticatedPeer {
376 peer_id,
377 public_key,
378 authenticated_at: Instant::now(),
379 session_id,
380 });
381
382 info!("Marked peer {:?} as authenticated after receiving AuthSuccess", peer_id);
383 Ok(())
384 }
385
386 pub async fn remove_peer(&self, peer_id: &PeerId) {
388 let mut peers = self.authenticated_peers.write().await;
389 if peers.remove(peer_id).is_some() {
390 info!("Removed authenticated peer {:?}", peer_id);
391 }
392 }
393
394 pub async fn cleanup_expired_challenges(&self) {
396 let mut challenges = self.pending_challenges.write().await;
397 let now = Instant::now();
398
399 challenges.retain(|peer_id, challenge| {
400 let expired = now.duration_since(challenge.created_at) <= self.config.challenge_validity;
401 if !expired {
402 debug!("Removing expired challenge for peer {:?}", peer_id);
403 }
404 expired
405 });
406 }
407
408 pub async fn list_authenticated_peers(&self) -> Vec<PeerId> {
410 let peers = self.authenticated_peers.read().await;
411 peers.keys().cloned().collect()
412 }
413
414 pub fn serialize_message(msg: &AuthMessage) -> Result<Vec<u8>, AuthError> {
416 serde_json::to_vec(msg)
417 .map_err(|e| AuthError::SerializationError(e.to_string()))
418 }
419
420 pub fn deserialize_message(data: &[u8]) -> Result<AuthMessage, AuthError> {
422 serde_json::from_slice(data)
423 .map_err(|e| AuthError::SerializationError(e.to_string()))
424 }
425}
426
427pub struct AuthProtocol {
429 auth_manager: Arc<AuthManager>,
430 pending_auth: Arc<tokio::sync::RwLock<HashMap<PeerId, [u8; 32]>>>,
432}
433
434impl AuthProtocol {
435 pub fn new(auth_manager: Arc<AuthManager>) -> Self {
437 Self {
438 auth_manager,
439 pending_auth: Arc::new(tokio::sync::RwLock::new(HashMap::new())),
440 }
441 }
442
443 pub async fn handle_message(
445 &self,
446 peer_id: PeerId,
447 message: AuthMessage,
448 ) -> Result<Option<AuthMessage>, AuthError> {
449 match message {
450 AuthMessage::AuthRequest { peer_id: req_peer_id, public_key, .. } => {
451 if req_peer_id != peer_id {
452 return Err(AuthError::InvalidPeerId);
453 }
454 self.pending_auth.write().await.insert(peer_id, public_key);
456 let response = self.auth_manager.handle_auth_request(peer_id, public_key).await?;
457 Ok(Some(response))
458 }
459 AuthMessage::Challenge { nonce, .. } => {
460 let response = self.auth_manager.create_challenge_response(nonce)?;
461 Ok(Some(response))
462 }
463 AuthMessage::ChallengeResponse { nonce, signature, .. } => {
464 let public_key_bytes = match self.pending_auth.read().await.get(&peer_id) {
466 Some(key) => *key,
467 None => return Err(AuthError::PeerNotFound),
468 };
469
470 let response = self.auth_manager.verify_challenge_response(
471 peer_id,
472 public_key_bytes,
473 nonce,
474 &signature,
475 ).await?;
476
477 if matches!(response, AuthMessage::AuthSuccess { .. }) {
479 self.pending_auth.write().await.remove(&peer_id);
480 }
481
482 Ok(Some(response))
483 }
484 AuthMessage::AuthSuccess { session_id, .. } => {
485 info!("Authentication successful with peer {:?}, session: {:?}",
486 peer_id, hex::encode(&session_id));
487 Ok(None)
488 }
489 AuthMessage::AuthFailure { reason } => {
490 warn!("Authentication failed with peer {:?}: {}", peer_id, reason);
491 Err(AuthError::InvalidSignature)
492 }
493 }
494 }
495
496 pub async fn initiate_auth(&self) -> AuthMessage {
498 self.auth_manager.create_auth_request()
499 }
500}
501
502#[cfg(test)]
503mod tests {
504 use super::*;
505 use crate::crypto::raw_public_keys::key_utils::generate_ed25519_keypair;
506
507 #[tokio::test]
508 async fn test_auth_manager_creation() {
509 let (secret_key, _) = generate_ed25519_keypair();
510 let config = AuthConfig::default();
511 let auth_manager = AuthManager::new(secret_key, config);
512
513 let peer_id = auth_manager.peer_id();
515 assert_eq!(peer_id.0.len(), 32);
516 }
517
518 #[tokio::test]
519 async fn test_authentication_flow() {
520 let (secret_key1, public_key1) = generate_ed25519_keypair();
522 let (secret_key2, _) = generate_ed25519_keypair();
523
524 let auth1 = AuthManager::new(secret_key1, AuthConfig::default());
525 let auth2 = AuthManager::new(secret_key2, AuthConfig::default());
526
527 let auth_request = auth1.create_auth_request();
529
530 let challenge = match &auth_request {
532 AuthMessage::AuthRequest { peer_id, public_key, .. } => {
533 auth2.handle_auth_request(*peer_id, *public_key).await.unwrap()
534 }
535 _ => panic!("Expected AuthRequest"),
536 };
537
538 let response = match &challenge {
540 AuthMessage::Challenge { nonce, .. } => {
541 auth1.create_challenge_response(*nonce).unwrap()
542 }
543 _ => panic!("Expected Challenge"),
544 };
545
546 let result = match &response {
548 AuthMessage::ChallengeResponse { nonce, signature, .. } => {
549 auth2.verify_challenge_response(
550 auth1.peer_id(),
551 public_key_to_bytes(&public_key1),
552 *nonce,
553 signature,
554 ).await
555 }
556 _ => panic!("Expected ChallengeResponse"),
557 };
558
559 assert!(matches!(result, Ok(AuthMessage::AuthSuccess { .. })));
561
562 assert!(auth2.is_authenticated(&auth1.peer_id()).await);
564 }
565
566 #[tokio::test]
567 async fn test_invalid_signature() {
568 let (secret_key1, _) = generate_ed25519_keypair();
569 let (secret_key2, public_key2) = generate_ed25519_keypair();
570
571 let auth1 = AuthManager::new(secret_key1, AuthConfig::default());
572 let _auth2 = AuthManager::new(secret_key2, AuthConfig::default());
573
574 let peer_id2 = derive_peer_id_from_public_key(&public_key2);
576 let challenge = auth1.handle_auth_request(peer_id2, public_key_to_bytes(&public_key2))
577 .await.unwrap();
578
579 let invalid_signature = vec![0u8; 64];
581 let nonce = match &challenge {
582 AuthMessage::Challenge { nonce, .. } => *nonce,
583 _ => panic!("Expected Challenge"),
584 };
585
586 let result = auth1.verify_challenge_response(
588 peer_id2,
589 public_key_to_bytes(&public_key2),
590 nonce,
591 &invalid_signature,
592 ).await;
593
594 assert!(matches!(result, Err(AuthError::InvalidSignature)));
595 }
596
597 #[tokio::test]
598 async fn test_challenge_expiry() {
599 let (secret_key, public_key) = generate_ed25519_keypair();
600 let mut config = AuthConfig::default();
601 config.challenge_validity = Duration::from_millis(100); let auth = AuthManager::new(secret_key, config);
604 let peer_id = derive_peer_id_from_public_key(&public_key);
605
606 let _challenge = auth.handle_auth_request(peer_id, public_key_to_bytes(&public_key))
608 .await.unwrap();
609
610 tokio::time::sleep(Duration::from_millis(200)).await;
612
613 let result = auth.verify_challenge_response(
615 peer_id,
616 public_key_to_bytes(&public_key),
617 [0u8; 32], &[0u8; 64], ).await;
620
621 assert!(matches!(result, Err(AuthError::ChallengeExpired)));
622 }
623
624 #[tokio::test]
625 async fn test_message_serialization() {
626 let (_, public_key) = generate_ed25519_keypair();
627 let peer_id = derive_peer_id_from_public_key(&public_key);
628
629 let msg = AuthMessage::AuthRequest {
630 peer_id,
631 public_key: public_key_to_bytes(&public_key),
632 timestamp: SystemTime::now(),
633 };
634
635 let serialized = AuthManager::serialize_message(&msg).unwrap();
637 let deserialized = AuthManager::deserialize_message(&serialized).unwrap();
638
639 match (msg, deserialized) {
640 (
641 AuthMessage::AuthRequest { peer_id: p1, public_key: k1, .. },
642 AuthMessage::AuthRequest { peer_id: p2, public_key: k2, .. }
643 ) => {
644 assert_eq!(p1, p2);
645 assert_eq!(k1, k2);
646 }
647 _ => panic!("Message mismatch"),
648 }
649 }
650}