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, error, info, warn};
20
21use crate::{
22 crypto::raw_public_keys::key_utils::{
23 derive_peer_id_from_public_key, public_key_from_bytes, public_key_to_bytes, verify_peer_id,
24 },
25 nat_traversal_api::PeerId,
26};
27
28fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
30 let len_equal = a.len() == b.len();
32
33 let min_len = a.len().min(b.len());
35 let mut result = 0u8;
36
37 for i in 0..min_len {
39 result |= a[i] ^ b[i];
40 }
41
42 if !len_equal {
44 result |= 1;
45 }
46
47 result == 0
49}
50
51#[derive(Debug, thiserror::Error)]
53pub enum AuthError {
54 #[error("Invalid signature")]
55 InvalidSignature,
56 #[error("Challenge expired")]
57 ChallengeExpired,
58 #[error("Peer not found")]
59 PeerNotFound,
60 #[error("Authentication timeout")]
61 Timeout,
62 #[error("Invalid peer ID")]
63 InvalidPeerId,
64 #[error("Signature error: {0}")]
65 SignatureError(String),
66 #[error("Serialization error: {0}")]
67 SerializationError(String),
68 #[error("Key error: {0}")]
69 KeyError(String),
70}
71
72#[derive(Debug, Clone)]
74pub struct AuthConfig {
75 pub auth_timeout: Duration,
77 pub challenge_validity: Duration,
79 pub require_authentication: bool,
81 pub max_auth_attempts: u32,
83}
84
85impl Default for AuthConfig {
86 fn default() -> Self {
87 Self {
88 auth_timeout: Duration::from_secs(10),
89 challenge_validity: Duration::from_secs(60),
90 require_authentication: true,
91 max_auth_attempts: 3,
92 }
93 }
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98pub enum AuthMessage {
99 AuthRequest {
101 peer_id: PeerId,
102 public_key: [u8; 32],
103 timestamp: SystemTime,
104 },
105 Challenge {
107 nonce: [u8; 32],
108 timestamp: SystemTime,
109 },
110 ChallengeResponse {
112 nonce: [u8; 32],
113 signature: Vec<u8>,
114 timestamp: SystemTime,
115 },
116 AuthSuccess {
118 session_id: [u8; 32],
119 timestamp: SystemTime,
120 },
121 AuthFailure { reason: String },
123}
124
125#[derive(Debug, Clone)]
127pub struct AuthenticatedPeer {
128 pub peer_id: PeerId,
130 pub public_key: Ed25519PublicKey,
132 pub authenticated_at: Instant,
134 pub session_id: [u8; 32],
136}
137
138pub struct AuthManager {
140 secret_key: Ed25519SecretKey,
142 public_key: Ed25519PublicKey,
144 peer_id: PeerId,
146 config: AuthConfig,
148 authenticated_peers: Arc<RwLock<HashMap<PeerId, AuthenticatedPeer>>>,
150 pending_challenges: Arc<RwLock<HashMap<PeerId, PendingChallenge>>>,
152}
153
154#[derive(Debug)]
156struct PendingChallenge {
157 nonce: [u8; 32],
158 created_at: Instant,
159 attempts: u32,
160}
161
162impl AuthManager {
163 pub fn new(secret_key: Ed25519SecretKey, config: AuthConfig) -> Self {
165 let public_key = secret_key.verifying_key();
166 let peer_id = derive_peer_id_from_public_key(&public_key);
167
168 info!("Initialized AuthManager with peer ID: {:?}", peer_id);
169
170 Self {
171 secret_key,
172 public_key,
173 peer_id,
174 config,
175 authenticated_peers: Arc::new(RwLock::new(HashMap::new())),
176 pending_challenges: Arc::new(RwLock::new(HashMap::new())),
177 }
178 }
179
180 pub fn peer_id(&self) -> PeerId {
182 self.peer_id
183 }
184
185 pub fn public_key_bytes(&self) -> [u8; 32] {
187 public_key_to_bytes(&self.public_key)
188 }
189
190 pub fn config(&self) -> &AuthConfig {
192 &self.config
193 }
194
195 pub fn create_auth_request(&self) -> AuthMessage {
197 AuthMessage::AuthRequest {
198 peer_id: self.peer_id,
199 public_key: self.public_key_bytes(),
200 timestamp: SystemTime::now(),
201 }
202 }
203
204 pub async fn handle_auth_request(
206 &self,
207 peer_id: PeerId,
208 public_key_bytes: [u8; 32],
209 ) -> Result<AuthMessage, AuthError> {
210 let public_key = public_key_from_bytes(&public_key_bytes)
212 .map_err(|e| AuthError::KeyError(e.to_string()))?;
213
214 if !verify_peer_id(&peer_id, &public_key) {
215 return Err(AuthError::InvalidPeerId);
216 }
217
218 let nonce = {
220 use rand::Rng;
221 let mut nonce = [0u8; 32];
222 rand::thread_rng().fill(&mut nonce);
223 nonce
224 };
225
226 let mut challenges = self.pending_challenges.write().await;
228 challenges.insert(
229 peer_id,
230 PendingChallenge {
231 nonce,
232 created_at: Instant::now(),
233 attempts: 0,
234 },
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
271 .get(&peer_id)
272 .map(|c| c.nonce)
273 .unwrap_or([0u8; 32]);
274 let created_at = challenges
275 .get(&peer_id)
276 .map(|c| c.created_at)
277 .unwrap_or(Instant::now());
278 let attempts = challenges
279 .get_mut(&peer_id)
280 .map(|c| {
281 c.attempts += 1;
282 c.attempts
283 })
284 .unwrap_or(0);
285
286 let nonce_matches = constant_time_eq(&stored_nonce, &nonce);
288 let not_expired = created_at.elapsed() <= self.config.challenge_validity;
289 let attempts_ok = attempts < self.config.max_auth_attempts;
290
291 let public_key_result = public_key_from_bytes(&public_key_bytes);
293 let signature_result = Signature::from_slice(signature_bytes);
294
295 let verification_result = match (public_key_result, signature_result) {
297 (Ok(pk), Ok(sig)) => pk.verify(&nonce, &sig).is_ok(),
298 _ => false,
299 };
300
301 let session_id = {
303 use rand::Rng;
304 let mut id = [0u8; 32];
305 rand::thread_rng().fill(&mut id);
306 id
307 };
308
309 let all_valid =
311 challenge_exists && nonce_matches && not_expired && attempts_ok && verification_result;
312
313 debug!(
314 "Verification results - exists: {}, nonce_matches: {}, not_expired: {}, attempts_ok: {}, verification: {}",
315 challenge_exists, nonce_matches, not_expired, attempts_ok, verification_result
316 );
317
318 if all_valid {
320 challenges.remove(&peer_id);
322 drop(challenges); if let Ok(public_key) = public_key_from_bytes(&public_key_bytes) {
326 let mut peers = self.authenticated_peers.write().await;
327 peers.insert(
328 peer_id,
329 AuthenticatedPeer {
330 peer_id,
331 public_key,
332 authenticated_at: Instant::now(),
333 session_id,
334 },
335 );
336
337 info!("Successfully authenticated peer {:?}", peer_id);
338 }
339
340 Ok(AuthMessage::AuthSuccess {
341 session_id,
342 timestamp: SystemTime::now(),
343 })
344 } else {
345 let error = if !challenge_exists {
347 AuthError::PeerNotFound
348 } else if !not_expired {
349 challenges.remove(&peer_id);
350 AuthError::ChallengeExpired
351 } else if !attempts_ok {
352 challenges.remove(&peer_id);
353 AuthError::InvalidSignature
354 } else if !nonce_matches {
355 AuthError::InvalidSignature
356 } else {
357 AuthError::InvalidSignature
358 };
359
360 Err(error)
361 }
362 }
363
364 pub async fn is_authenticated(&self, peer_id: &PeerId) -> bool {
366 let peers = self.authenticated_peers.read().await;
367 peers.contains_key(peer_id)
368 }
369
370 pub async fn get_authenticated_peer(&self, peer_id: &PeerId) -> Option<AuthenticatedPeer> {
372 let peers = self.authenticated_peers.read().await;
373 peers.get(peer_id).cloned()
374 }
375
376 pub async fn handle_auth_success(
378 &self,
379 peer_id: PeerId,
380 public_key_bytes: [u8; 32],
381 session_id: [u8; 32],
382 ) -> Result<(), AuthError> {
383 let public_key = public_key_from_bytes(&public_key_bytes)
385 .map_err(|e| AuthError::KeyError(e.to_string()))?;
386
387 let mut peers = self.authenticated_peers.write().await;
389 peers.insert(
390 peer_id,
391 AuthenticatedPeer {
392 peer_id,
393 public_key,
394 authenticated_at: Instant::now(),
395 session_id,
396 },
397 );
398
399 info!(
400 "Marked peer {:?} as authenticated after receiving AuthSuccess",
401 peer_id
402 );
403 Ok(())
404 }
405
406 pub async fn remove_peer(&self, peer_id: &PeerId) {
408 let mut peers = self.authenticated_peers.write().await;
409 if peers.remove(peer_id).is_some() {
410 info!("Removed authenticated peer {:?}", peer_id);
411 }
412 }
413
414 pub async fn cleanup_expired_challenges(&self) {
416 let mut challenges = self.pending_challenges.write().await;
417 let now = Instant::now();
418
419 challenges.retain(|peer_id, challenge| {
420 let expired =
421 now.duration_since(challenge.created_at) <= self.config.challenge_validity;
422 if !expired {
423 debug!("Removing expired challenge for peer {:?}", peer_id);
424 }
425 expired
426 });
427 }
428
429 pub async fn list_authenticated_peers(&self) -> Vec<PeerId> {
431 let peers = self.authenticated_peers.read().await;
432 peers.keys().cloned().collect()
433 }
434
435 pub fn serialize_message(msg: &AuthMessage) -> Result<Vec<u8>, AuthError> {
437 serde_json::to_vec(msg).map_err(|e| AuthError::SerializationError(e.to_string()))
438 }
439
440 pub fn deserialize_message(data: &[u8]) -> Result<AuthMessage, AuthError> {
442 serde_json::from_slice(data).map_err(|e| AuthError::SerializationError(e.to_string()))
443 }
444}
445
446pub struct AuthProtocol {
448 auth_manager: Arc<AuthManager>,
449 pending_auth: Arc<tokio::sync::RwLock<HashMap<PeerId, [u8; 32]>>>,
451}
452
453impl AuthProtocol {
454 pub fn new(auth_manager: Arc<AuthManager>) -> Self {
456 Self {
457 auth_manager,
458 pending_auth: Arc::new(tokio::sync::RwLock::new(HashMap::new())),
459 }
460 }
461
462 pub async fn handle_message(
464 &self,
465 peer_id: PeerId,
466 message: AuthMessage,
467 ) -> Result<Option<AuthMessage>, AuthError> {
468 match message {
469 AuthMessage::AuthRequest {
470 peer_id: req_peer_id,
471 public_key,
472 ..
473 } => {
474 if req_peer_id != peer_id {
475 return Err(AuthError::InvalidPeerId);
476 }
477 self.pending_auth.write().await.insert(peer_id, public_key);
479 let response = self
480 .auth_manager
481 .handle_auth_request(peer_id, public_key)
482 .await?;
483 Ok(Some(response))
484 }
485 AuthMessage::Challenge { nonce, .. } => {
486 let response = self.auth_manager.create_challenge_response(nonce)?;
487 Ok(Some(response))
488 }
489 AuthMessage::ChallengeResponse {
490 nonce, signature, ..
491 } => {
492 let public_key_bytes = match self.pending_auth.read().await.get(&peer_id) {
494 Some(key) => *key,
495 None => return Err(AuthError::PeerNotFound),
496 };
497
498 let response = self
499 .auth_manager
500 .verify_challenge_response(peer_id, public_key_bytes, nonce, &signature)
501 .await?;
502
503 if matches!(response, AuthMessage::AuthSuccess { .. }) {
505 self.pending_auth.write().await.remove(&peer_id);
506 }
507
508 Ok(Some(response))
509 }
510 AuthMessage::AuthSuccess { session_id, .. } => {
511 info!(
512 "Authentication successful with peer {:?}, session: {:?}",
513 peer_id,
514 hex::encode(&session_id)
515 );
516 Ok(None)
517 }
518 AuthMessage::AuthFailure { reason } => {
519 warn!("Authentication failed with peer {:?}: {}", peer_id, reason);
520 Err(AuthError::InvalidSignature)
521 }
522 }
523 }
524
525 pub async fn initiate_auth(&self) -> AuthMessage {
527 self.auth_manager.create_auth_request()
528 }
529}
530
531#[cfg(test)]
532mod tests {
533 use super::*;
534 use crate::crypto::raw_public_keys::key_utils::generate_ed25519_keypair;
535
536 #[tokio::test]
537 async fn test_auth_manager_creation() {
538 let (secret_key, _) = generate_ed25519_keypair();
539 let config = AuthConfig::default();
540 let auth_manager = AuthManager::new(secret_key, config);
541
542 let peer_id = auth_manager.peer_id();
544 assert_eq!(peer_id.0.len(), 32);
545 }
546
547 #[tokio::test]
548 async fn test_authentication_flow() {
549 let (secret_key1, public_key1) = generate_ed25519_keypair();
551 let (secret_key2, _) = generate_ed25519_keypair();
552
553 let auth1 = AuthManager::new(secret_key1, AuthConfig::default());
554 let auth2 = AuthManager::new(secret_key2, AuthConfig::default());
555
556 let auth_request = auth1.create_auth_request();
558
559 let challenge = match &auth_request {
561 AuthMessage::AuthRequest {
562 peer_id,
563 public_key,
564 ..
565 } => auth2
566 .handle_auth_request(*peer_id, *public_key)
567 .await
568 .unwrap(),
569 _ => panic!("Expected AuthRequest"),
570 };
571
572 let response = match &challenge {
574 AuthMessage::Challenge { nonce, .. } => {
575 auth1.create_challenge_response(*nonce).unwrap()
576 }
577 _ => panic!("Expected Challenge"),
578 };
579
580 let result = match &response {
582 AuthMessage::ChallengeResponse {
583 nonce, signature, ..
584 } => {
585 auth2
586 .verify_challenge_response(
587 auth1.peer_id(),
588 public_key_to_bytes(&public_key1),
589 *nonce,
590 signature,
591 )
592 .await
593 }
594 _ => panic!("Expected ChallengeResponse"),
595 };
596
597 assert!(matches!(result, Ok(AuthMessage::AuthSuccess { .. })));
599
600 assert!(auth2.is_authenticated(&auth1.peer_id()).await);
602 }
603
604 #[tokio::test]
605 async fn test_invalid_signature() {
606 let (secret_key1, _) = generate_ed25519_keypair();
607 let (secret_key2, public_key2) = generate_ed25519_keypair();
608
609 let auth1 = AuthManager::new(secret_key1, AuthConfig::default());
610 let _auth2 = AuthManager::new(secret_key2, AuthConfig::default());
611
612 let peer_id2 = derive_peer_id_from_public_key(&public_key2);
614 let challenge = auth1
615 .handle_auth_request(peer_id2, public_key_to_bytes(&public_key2))
616 .await
617 .unwrap();
618
619 let invalid_signature = vec![0u8; 64];
621 let nonce = match &challenge {
622 AuthMessage::Challenge { nonce, .. } => *nonce,
623 _ => panic!("Expected Challenge"),
624 };
625
626 let result = auth1
628 .verify_challenge_response(
629 peer_id2,
630 public_key_to_bytes(&public_key2),
631 nonce,
632 &invalid_signature,
633 )
634 .await;
635
636 assert!(matches!(result, Err(AuthError::InvalidSignature)));
637 }
638
639 #[tokio::test]
640 async fn test_challenge_expiry() {
641 let (secret_key, public_key) = generate_ed25519_keypair();
642 let mut config = AuthConfig::default();
643 config.challenge_validity = Duration::from_millis(100); let auth = AuthManager::new(secret_key, config);
646 let peer_id = derive_peer_id_from_public_key(&public_key);
647
648 let _challenge = auth
650 .handle_auth_request(peer_id, public_key_to_bytes(&public_key))
651 .await
652 .unwrap();
653
654 tokio::time::sleep(Duration::from_millis(200)).await;
656
657 let result = auth
659 .verify_challenge_response(
660 peer_id,
661 public_key_to_bytes(&public_key),
662 [0u8; 32], &[0u8; 64], )
665 .await;
666
667 assert!(matches!(result, Err(AuthError::ChallengeExpired)));
668 }
669
670 #[tokio::test]
671 async fn test_message_serialization() {
672 let (_, public_key) = generate_ed25519_keypair();
673 let peer_id = derive_peer_id_from_public_key(&public_key);
674
675 let msg = AuthMessage::AuthRequest {
676 peer_id,
677 public_key: public_key_to_bytes(&public_key),
678 timestamp: SystemTime::now(),
679 };
680
681 let serialized = AuthManager::serialize_message(&msg).unwrap();
683 let deserialized = AuthManager::deserialize_message(&serialized).unwrap();
684
685 match (msg, deserialized) {
686 (
687 AuthMessage::AuthRequest {
688 peer_id: p1,
689 public_key: k1,
690 ..
691 },
692 AuthMessage::AuthRequest {
693 peer_id: p2,
694 public_key: k2,
695 ..
696 },
697 ) => {
698 assert_eq!(p1, p2);
699 assert_eq!(k1, k2);
700 }
701 _ => panic!("Message mismatch"),
702 }
703 }
704}