1use std::{
15 collections::HashMap,
16 sync::Arc,
17 time::{Duration, Instant, SystemTime},
18};
19
20use ed25519_dalek::{
21 Signature, Signer, SigningKey as Ed25519SecretKey, Verifier, VerifyingKey as Ed25519PublicKey,
22};
23
24use serde::{Deserialize, Serialize};
25use tokio::sync::RwLock;
26use tracing::{debug, error, info, warn};
27
28use crate::{
29 crypto::raw_public_keys::key_utils::{
30 derive_peer_id_from_public_key, public_key_from_bytes, public_key_to_bytes, verify_peer_id,
31 },
32 nat_traversal_api::PeerId,
33};
34
35fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
37 let len_equal = a.len() == b.len();
39
40 let min_len = a.len().min(b.len());
42 let mut result = 0u8;
43
44 for i in 0..min_len {
46 result |= a[i] ^ b[i];
47 }
48
49 if !len_equal {
51 result |= 1;
52 }
53
54 result == 0
56}
57
58#[derive(Debug, thiserror::Error)]
60#[allow(missing_docs)]
61pub enum AuthError {
62 #[error("Invalid signature")]
63 InvalidSignature,
64 #[error("Challenge expired")]
65 ChallengeExpired,
66 #[error("Peer not found")]
67 PeerNotFound,
68 #[error("Authentication timeout")]
69 Timeout,
70 #[error("Invalid peer ID")]
71 InvalidPeerId,
72 #[error("Signature error: {0}")]
73 SignatureError(String),
74 #[error("Serialization error: {0}")]
75 SerializationError(String),
76 #[error("Key error: {0}")]
77 KeyError(String),
78}
79
80#[derive(Debug, Clone)]
82pub struct AuthConfig {
83 pub auth_timeout: Duration,
85 pub challenge_validity: Duration,
87 pub require_authentication: bool,
89 pub max_auth_attempts: u32,
91}
92
93impl Default for AuthConfig {
94 fn default() -> Self {
95 Self {
96 auth_timeout: Duration::from_secs(10),
97 challenge_validity: Duration::from_secs(60),
98 require_authentication: true,
99 max_auth_attempts: 3,
100 }
101 }
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106#[allow(missing_docs)]
107pub enum AuthMessage {
108 AuthRequest {
110 peer_id: PeerId,
111 public_key: [u8; 32],
112 timestamp: SystemTime,
113 },
114 Challenge {
116 nonce: [u8; 32],
117 timestamp: SystemTime,
118 },
119 ChallengeResponse {
121 nonce: [u8; 32],
122 signature: Vec<u8>,
123 timestamp: SystemTime,
124 },
125 AuthSuccess {
127 session_id: [u8; 32],
128 timestamp: SystemTime,
129 },
130 AuthFailure { reason: String },
132}
133
134#[derive(Debug, Clone)]
136pub struct AuthenticatedPeer {
137 pub peer_id: PeerId,
139 pub public_key: Ed25519PublicKey,
141 pub authenticated_at: Instant,
143 pub session_id: [u8; 32],
145}
146
147#[derive(Debug)]
149pub struct AuthManager {
150 secret_key: Ed25519SecretKey,
152 public_key: Ed25519PublicKey,
154 peer_id: PeerId,
156 config: AuthConfig,
158 authenticated_peers: Arc<RwLock<HashMap<PeerId, AuthenticatedPeer>>>,
160 pending_challenges: Arc<RwLock<HashMap<PeerId, PendingChallenge>>>,
162}
163
164#[derive(Debug)]
166struct PendingChallenge {
167 nonce: [u8; 32],
168 created_at: Instant,
169 attempts: u32,
170}
171
172impl AuthManager {
173 pub fn new(secret_key: Ed25519SecretKey, config: AuthConfig) -> Self {
175 let public_key = secret_key.verifying_key();
176 let peer_id = derive_peer_id_from_public_key(&public_key);
177
178 info!("Initialized AuthManager with peer ID: {:?}", peer_id);
179
180 Self {
181 secret_key,
182 public_key,
183 peer_id,
184 config,
185 authenticated_peers: Arc::new(RwLock::new(HashMap::new())),
186 pending_challenges: Arc::new(RwLock::new(HashMap::new())),
187 }
188 }
189
190 pub fn peer_id(&self) -> PeerId {
192 self.peer_id
193 }
194
195 pub fn public_key_bytes(&self) -> [u8; 32] {
197 public_key_to_bytes(&self.public_key)
198 }
199
200 pub fn config(&self) -> &AuthConfig {
202 &self.config
203 }
204
205 pub fn create_auth_request(&self) -> AuthMessage {
207 AuthMessage::AuthRequest {
208 peer_id: self.peer_id,
209 public_key: self.public_key_bytes(),
210 timestamp: SystemTime::now(),
211 }
212 }
213
214 pub async fn handle_auth_request(
216 &self,
217 peer_id: PeerId,
218 public_key_bytes: [u8; 32],
219 ) -> Result<AuthMessage, AuthError> {
220 let public_key = public_key_from_bytes(&public_key_bytes)
222 .map_err(|e| AuthError::KeyError(e.to_string()))?;
223
224 if !verify_peer_id(&peer_id, &public_key) {
225 return Err(AuthError::InvalidPeerId);
226 }
227
228 let nonce = {
230 use rand::Rng;
231 let mut nonce = [0u8; 32];
232 rand::thread_rng().fill(&mut nonce);
233 nonce
234 };
235
236 let mut challenges = self.pending_challenges.write().await;
238 challenges.insert(
239 peer_id,
240 PendingChallenge {
241 nonce,
242 created_at: Instant::now(),
243 attempts: 0,
244 },
245 );
246
247 debug!("Created challenge for peer {:?}", peer_id);
248
249 Ok(AuthMessage::Challenge {
250 nonce,
251 timestamp: SystemTime::now(),
252 })
253 }
254
255 pub fn create_challenge_response(&self, nonce: [u8; 32]) -> Result<AuthMessage, AuthError> {
257 let signature = self.secret_key.sign(&nonce);
259
260 Ok(AuthMessage::ChallengeResponse {
261 nonce,
262 signature: signature.to_vec(),
263 timestamp: SystemTime::now(),
264 })
265 }
266
267 pub async fn verify_challenge_response(
269 &self,
270 peer_id: PeerId,
271 public_key_bytes: [u8; 32],
272 nonce: [u8; 32],
273 signature_bytes: &[u8],
274 ) -> Result<AuthMessage, AuthError> {
275 let mut challenges = self.pending_challenges.write().await;
279 let challenge_exists = challenges.contains_key(&peer_id);
280 let stored_nonce = challenges
281 .get(&peer_id)
282 .map(|c| c.nonce)
283 .unwrap_or([0u8; 32]);
284 let created_at = challenges
285 .get(&peer_id)
286 .map(|c| c.created_at)
287 .unwrap_or(Instant::now());
288 let attempts = challenges
289 .get_mut(&peer_id)
290 .map(|c| {
291 c.attempts += 1;
292 c.attempts
293 })
294 .unwrap_or(0);
295
296 let nonce_matches = constant_time_eq(&stored_nonce, &nonce);
298 let not_expired = created_at.elapsed() <= self.config.challenge_validity;
299 let attempts_ok = attempts < self.config.max_auth_attempts;
300
301 let public_key_result = public_key_from_bytes(&public_key_bytes);
303 let signature_result = Signature::from_slice(signature_bytes);
304
305 let verification_result = match (public_key_result, signature_result) {
307 (Ok(pk), Ok(sig)) => pk.verify(&nonce, &sig).is_ok(),
308 _ => false,
309 };
310
311 let session_id = {
313 use rand::Rng;
314 let mut id = [0u8; 32];
315 rand::thread_rng().fill(&mut id);
316 id
317 };
318
319 let all_valid =
321 challenge_exists && nonce_matches && not_expired && attempts_ok && verification_result;
322
323 debug!(
324 "Verification results - exists: {}, nonce_matches: {}, not_expired: {}, attempts_ok: {}, verification: {}",
325 challenge_exists, nonce_matches, not_expired, attempts_ok, verification_result
326 );
327
328 if all_valid {
330 challenges.remove(&peer_id);
332 drop(challenges); if let Ok(public_key) = public_key_from_bytes(&public_key_bytes) {
336 let mut peers = self.authenticated_peers.write().await;
337 peers.insert(
338 peer_id,
339 AuthenticatedPeer {
340 peer_id,
341 public_key,
342 authenticated_at: Instant::now(),
343 session_id,
344 },
345 );
346
347 info!("Successfully authenticated peer {:?}", peer_id);
348 }
349
350 Ok(AuthMessage::AuthSuccess {
351 session_id,
352 timestamp: SystemTime::now(),
353 })
354 } else {
355 let error = if !challenge_exists {
357 AuthError::PeerNotFound
358 } else if !not_expired {
359 challenges.remove(&peer_id);
360 AuthError::ChallengeExpired
361 } else if !attempts_ok {
362 challenges.remove(&peer_id);
363 AuthError::InvalidSignature
364 } else if !nonce_matches {
365 AuthError::InvalidSignature
366 } else {
367 AuthError::InvalidSignature
368 };
369
370 Err(error)
371 }
372 }
373
374 pub async fn is_authenticated(&self, peer_id: &PeerId) -> bool {
376 let peers = self.authenticated_peers.read().await;
377 peers.contains_key(peer_id)
378 }
379
380 pub async fn get_authenticated_peer(&self, peer_id: &PeerId) -> Option<AuthenticatedPeer> {
382 let peers = self.authenticated_peers.read().await;
383 peers.get(peer_id).cloned()
384 }
385
386 pub async fn handle_auth_success(
388 &self,
389 peer_id: PeerId,
390 public_key_bytes: [u8; 32],
391 session_id: [u8; 32],
392 ) -> Result<(), AuthError> {
393 let public_key = public_key_from_bytes(&public_key_bytes)
395 .map_err(|e| AuthError::KeyError(e.to_string()))?;
396
397 let mut peers = self.authenticated_peers.write().await;
399 peers.insert(
400 peer_id,
401 AuthenticatedPeer {
402 peer_id,
403 public_key,
404 authenticated_at: Instant::now(),
405 session_id,
406 },
407 );
408
409 info!(
410 "Marked peer {:?} as authenticated after receiving AuthSuccess",
411 peer_id
412 );
413 Ok(())
414 }
415
416 pub async fn remove_peer(&self, peer_id: &PeerId) {
418 let mut peers = self.authenticated_peers.write().await;
419 if peers.remove(peer_id).is_some() {
420 info!("Removed authenticated peer {:?}", peer_id);
421 }
422 }
423
424 pub async fn cleanup_expired_challenges(&self) {
426 let mut challenges = self.pending_challenges.write().await;
427 let now = Instant::now();
428
429 challenges.retain(|peer_id, challenge| {
430 let expired =
431 now.duration_since(challenge.created_at) <= self.config.challenge_validity;
432 if !expired {
433 debug!("Removing expired challenge for peer {:?}", peer_id);
434 }
435 expired
436 });
437 }
438
439 pub async fn list_authenticated_peers(&self) -> Vec<PeerId> {
441 let peers = self.authenticated_peers.read().await;
442 peers.keys().cloned().collect()
443 }
444
445 pub fn serialize_message(msg: &AuthMessage) -> Result<Vec<u8>, AuthError> {
447 serde_json::to_vec(msg).map_err(|e| AuthError::SerializationError(e.to_string()))
448 }
449
450 pub fn deserialize_message(data: &[u8]) -> Result<AuthMessage, AuthError> {
452 serde_json::from_slice(data).map_err(|e| AuthError::SerializationError(e.to_string()))
453 }
454}
455
456pub struct AuthProtocol {
458 auth_manager: Arc<AuthManager>,
459 pending_auth: Arc<tokio::sync::RwLock<HashMap<PeerId, [u8; 32]>>>,
461}
462
463impl AuthProtocol {
464 pub fn new(auth_manager: Arc<AuthManager>) -> Self {
466 Self {
467 auth_manager,
468 pending_auth: Arc::new(tokio::sync::RwLock::new(HashMap::new())),
469 }
470 }
471
472 pub async fn handle_message(
474 &self,
475 peer_id: PeerId,
476 message: AuthMessage,
477 ) -> Result<Option<AuthMessage>, AuthError> {
478 match message {
479 AuthMessage::AuthRequest {
480 peer_id: req_peer_id,
481 public_key,
482 ..
483 } => {
484 if req_peer_id != peer_id {
485 return Err(AuthError::InvalidPeerId);
486 }
487 self.pending_auth.write().await.insert(peer_id, public_key);
489 let response = self
490 .auth_manager
491 .handle_auth_request(peer_id, public_key)
492 .await?;
493 Ok(Some(response))
494 }
495 AuthMessage::Challenge { nonce, .. } => {
496 let response = self.auth_manager.create_challenge_response(nonce)?;
497 Ok(Some(response))
498 }
499 AuthMessage::ChallengeResponse {
500 nonce, signature, ..
501 } => {
502 let public_key_bytes = match self.pending_auth.read().await.get(&peer_id) {
504 Some(key) => *key,
505 None => return Err(AuthError::PeerNotFound),
506 };
507
508 let response = self
509 .auth_manager
510 .verify_challenge_response(peer_id, public_key_bytes, nonce, &signature)
511 .await?;
512
513 if matches!(response, AuthMessage::AuthSuccess { .. }) {
515 self.pending_auth.write().await.remove(&peer_id);
516 }
517
518 Ok(Some(response))
519 }
520 AuthMessage::AuthSuccess { session_id, .. } => {
521 info!(
522 "Authentication successful with peer {:?}, session: {:?}",
523 peer_id,
524 hex::encode(session_id)
525 );
526 Ok(None)
527 }
528 AuthMessage::AuthFailure { reason } => {
529 warn!("Authentication failed with peer {:?}: {}", peer_id, reason);
530 Err(AuthError::InvalidSignature)
531 }
532 }
533 }
534
535 pub async fn initiate_auth(&self) -> AuthMessage {
537 self.auth_manager.create_auth_request()
538 }
539}
540
541#[cfg(test)]
542mod tests {
543 use super::*;
544 use crate::crypto::raw_public_keys::key_utils::generate_ed25519_keypair;
545
546 #[tokio::test]
547 async fn test_auth_manager_creation() {
548 let (secret_key, _) = generate_ed25519_keypair();
549 let config = AuthConfig::default();
550 let auth_manager = AuthManager::new(secret_key, config);
551
552 let peer_id = auth_manager.peer_id();
554 assert_eq!(peer_id.0.len(), 32);
555 }
556
557 #[tokio::test]
558 async fn test_authentication_flow() {
559 let (secret_key1, public_key1) = generate_ed25519_keypair();
561 let (secret_key2, _) = generate_ed25519_keypair();
562
563 let auth1 = AuthManager::new(secret_key1, AuthConfig::default());
564 let auth2 = AuthManager::new(secret_key2, AuthConfig::default());
565
566 let auth_request = auth1.create_auth_request();
568
569 let challenge = match &auth_request {
571 AuthMessage::AuthRequest {
572 peer_id,
573 public_key,
574 ..
575 } => auth2
576 .handle_auth_request(*peer_id, *public_key)
577 .await
578 .unwrap(),
579 _ => panic!("Expected AuthRequest"),
580 };
581
582 let response = match &challenge {
584 AuthMessage::Challenge { nonce, .. } => {
585 auth1.create_challenge_response(*nonce).unwrap()
586 }
587 _ => panic!("Expected Challenge"),
588 };
589
590 let result = match &response {
592 AuthMessage::ChallengeResponse {
593 nonce, signature, ..
594 } => {
595 auth2
596 .verify_challenge_response(
597 auth1.peer_id(),
598 public_key_to_bytes(&public_key1),
599 *nonce,
600 signature,
601 )
602 .await
603 }
604 _ => panic!("Expected ChallengeResponse"),
605 };
606
607 assert!(matches!(result, Ok(AuthMessage::AuthSuccess { .. })));
609
610 assert!(auth2.is_authenticated(&auth1.peer_id()).await);
612 }
613
614 #[tokio::test]
615 async fn test_invalid_signature() {
616 let (secret_key1, _) = generate_ed25519_keypair();
617 let (secret_key2, public_key2) = generate_ed25519_keypair();
618
619 let auth1 = AuthManager::new(secret_key1, AuthConfig::default());
620 let _auth2 = AuthManager::new(secret_key2, AuthConfig::default());
621
622 let peer_id2 = derive_peer_id_from_public_key(&public_key2);
624 let challenge = auth1
625 .handle_auth_request(peer_id2, public_key_to_bytes(&public_key2))
626 .await
627 .unwrap();
628
629 let invalid_signature = vec![0u8; 64];
631 let nonce = match &challenge {
632 AuthMessage::Challenge { nonce, .. } => *nonce,
633 _ => panic!("Expected Challenge"),
634 };
635
636 let result = auth1
638 .verify_challenge_response(
639 peer_id2,
640 public_key_to_bytes(&public_key2),
641 nonce,
642 &invalid_signature,
643 )
644 .await;
645
646 assert!(matches!(result, Err(AuthError::InvalidSignature)));
647 }
648
649 #[tokio::test]
650 async fn test_challenge_expiry() {
651 let (secret_key, public_key) = generate_ed25519_keypair();
652 let config = AuthConfig {
653 challenge_validity: Duration::from_millis(100), ..Default::default()
655 };
656
657 let auth = AuthManager::new(secret_key, config);
658 let peer_id = derive_peer_id_from_public_key(&public_key);
659
660 let _challenge = auth
662 .handle_auth_request(peer_id, public_key_to_bytes(&public_key))
663 .await
664 .unwrap();
665
666 tokio::time::sleep(Duration::from_millis(200)).await;
668
669 let result = auth
671 .verify_challenge_response(
672 peer_id,
673 public_key_to_bytes(&public_key),
674 [0u8; 32], &[0u8; 64], )
677 .await;
678
679 assert!(matches!(result, Err(AuthError::ChallengeExpired)));
680 }
681
682 #[tokio::test]
683 async fn test_message_serialization() {
684 let (_, public_key) = generate_ed25519_keypair();
685 let peer_id = derive_peer_id_from_public_key(&public_key);
686
687 let msg = AuthMessage::AuthRequest {
688 peer_id,
689 public_key: public_key_to_bytes(&public_key),
690 timestamp: SystemTime::now(),
691 };
692
693 let serialized = AuthManager::serialize_message(&msg).unwrap();
695 let deserialized = AuthManager::deserialize_message(&serialized).unwrap();
696
697 match (msg, deserialized) {
698 (
699 AuthMessage::AuthRequest {
700 peer_id: p1,
701 public_key: k1,
702 ..
703 },
704 AuthMessage::AuthRequest {
705 peer_id: p2,
706 public_key: k2,
707 ..
708 },
709 ) => {
710 assert_eq!(p1, p2);
711 assert_eq!(k1, k2);
712 }
713 _ => panic!("Message mismatch"),
714 }
715 }
716}