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
138#[derive(Debug)]
140pub struct AuthManager {
141 secret_key: Ed25519SecretKey,
143 public_key: Ed25519PublicKey,
145 peer_id: PeerId,
147 config: AuthConfig,
149 authenticated_peers: Arc<RwLock<HashMap<PeerId, AuthenticatedPeer>>>,
151 pending_challenges: Arc<RwLock<HashMap<PeerId, PendingChallenge>>>,
153}
154
155#[derive(Debug)]
157struct PendingChallenge {
158 nonce: [u8; 32],
159 created_at: Instant,
160 attempts: u32,
161}
162
163impl AuthManager {
164 pub fn new(secret_key: Ed25519SecretKey, config: AuthConfig) -> Self {
166 let public_key = secret_key.verifying_key();
167 let peer_id = derive_peer_id_from_public_key(&public_key);
168
169 info!("Initialized AuthManager with peer ID: {:?}", peer_id);
170
171 Self {
172 secret_key,
173 public_key,
174 peer_id,
175 config,
176 authenticated_peers: Arc::new(RwLock::new(HashMap::new())),
177 pending_challenges: Arc::new(RwLock::new(HashMap::new())),
178 }
179 }
180
181 pub fn peer_id(&self) -> PeerId {
183 self.peer_id
184 }
185
186 pub fn public_key_bytes(&self) -> [u8; 32] {
188 public_key_to_bytes(&self.public_key)
189 }
190
191 pub fn config(&self) -> &AuthConfig {
193 &self.config
194 }
195
196 pub fn create_auth_request(&self) -> AuthMessage {
198 AuthMessage::AuthRequest {
199 peer_id: self.peer_id,
200 public_key: self.public_key_bytes(),
201 timestamp: SystemTime::now(),
202 }
203 }
204
205 pub async fn handle_auth_request(
207 &self,
208 peer_id: PeerId,
209 public_key_bytes: [u8; 32],
210 ) -> Result<AuthMessage, AuthError> {
211 let public_key = public_key_from_bytes(&public_key_bytes)
213 .map_err(|e| AuthError::KeyError(e.to_string()))?;
214
215 if !verify_peer_id(&peer_id, &public_key) {
216 return Err(AuthError::InvalidPeerId);
217 }
218
219 let nonce = {
221 use rand::Rng;
222 let mut nonce = [0u8; 32];
223 rand::thread_rng().fill(&mut nonce);
224 nonce
225 };
226
227 let mut challenges = self.pending_challenges.write().await;
229 challenges.insert(
230 peer_id,
231 PendingChallenge {
232 nonce,
233 created_at: Instant::now(),
234 attempts: 0,
235 },
236 );
237
238 debug!("Created challenge for peer {:?}", peer_id);
239
240 Ok(AuthMessage::Challenge {
241 nonce,
242 timestamp: SystemTime::now(),
243 })
244 }
245
246 pub fn create_challenge_response(&self, nonce: [u8; 32]) -> Result<AuthMessage, AuthError> {
248 let signature = self.secret_key.sign(&nonce);
250
251 Ok(AuthMessage::ChallengeResponse {
252 nonce,
253 signature: signature.to_vec(),
254 timestamp: SystemTime::now(),
255 })
256 }
257
258 pub async fn verify_challenge_response(
260 &self,
261 peer_id: PeerId,
262 public_key_bytes: [u8; 32],
263 nonce: [u8; 32],
264 signature_bytes: &[u8],
265 ) -> Result<AuthMessage, AuthError> {
266 let mut challenges = self.pending_challenges.write().await;
270 let challenge_exists = challenges.contains_key(&peer_id);
271 let stored_nonce = challenges
272 .get(&peer_id)
273 .map(|c| c.nonce)
274 .unwrap_or([0u8; 32]);
275 let created_at = challenges
276 .get(&peer_id)
277 .map(|c| c.created_at)
278 .unwrap_or(Instant::now());
279 let attempts = challenges
280 .get_mut(&peer_id)
281 .map(|c| {
282 c.attempts += 1;
283 c.attempts
284 })
285 .unwrap_or(0);
286
287 let nonce_matches = constant_time_eq(&stored_nonce, &nonce);
289 let not_expired = created_at.elapsed() <= self.config.challenge_validity;
290 let attempts_ok = attempts < self.config.max_auth_attempts;
291
292 let public_key_result = public_key_from_bytes(&public_key_bytes);
294 let signature_result = Signature::from_slice(signature_bytes);
295
296 let verification_result = match (public_key_result, signature_result) {
298 (Ok(pk), Ok(sig)) => pk.verify(&nonce, &sig).is_ok(),
299 _ => false,
300 };
301
302 let session_id = {
304 use rand::Rng;
305 let mut id = [0u8; 32];
306 rand::thread_rng().fill(&mut id);
307 id
308 };
309
310 let all_valid =
312 challenge_exists && nonce_matches && not_expired && attempts_ok && verification_result;
313
314 debug!(
315 "Verification results - exists: {}, nonce_matches: {}, not_expired: {}, attempts_ok: {}, verification: {}",
316 challenge_exists, nonce_matches, not_expired, attempts_ok, verification_result
317 );
318
319 if all_valid {
321 challenges.remove(&peer_id);
323 drop(challenges); if let Ok(public_key) = public_key_from_bytes(&public_key_bytes) {
327 let mut peers = self.authenticated_peers.write().await;
328 peers.insert(
329 peer_id,
330 AuthenticatedPeer {
331 peer_id,
332 public_key,
333 authenticated_at: Instant::now(),
334 session_id,
335 },
336 );
337
338 info!("Successfully authenticated peer {:?}", peer_id);
339 }
340
341 Ok(AuthMessage::AuthSuccess {
342 session_id,
343 timestamp: SystemTime::now(),
344 })
345 } else {
346 let error = if !challenge_exists {
348 AuthError::PeerNotFound
349 } else if !not_expired {
350 challenges.remove(&peer_id);
351 AuthError::ChallengeExpired
352 } else if !attempts_ok {
353 challenges.remove(&peer_id);
354 AuthError::InvalidSignature
355 } else if !nonce_matches {
356 AuthError::InvalidSignature
357 } else {
358 AuthError::InvalidSignature
359 };
360
361 Err(error)
362 }
363 }
364
365 pub async fn is_authenticated(&self, peer_id: &PeerId) -> bool {
367 let peers = self.authenticated_peers.read().await;
368 peers.contains_key(peer_id)
369 }
370
371 pub async fn get_authenticated_peer(&self, peer_id: &PeerId) -> Option<AuthenticatedPeer> {
373 let peers = self.authenticated_peers.read().await;
374 peers.get(peer_id).cloned()
375 }
376
377 pub async fn handle_auth_success(
379 &self,
380 peer_id: PeerId,
381 public_key_bytes: [u8; 32],
382 session_id: [u8; 32],
383 ) -> Result<(), AuthError> {
384 let public_key = public_key_from_bytes(&public_key_bytes)
386 .map_err(|e| AuthError::KeyError(e.to_string()))?;
387
388 let mut peers = self.authenticated_peers.write().await;
390 peers.insert(
391 peer_id,
392 AuthenticatedPeer {
393 peer_id,
394 public_key,
395 authenticated_at: Instant::now(),
396 session_id,
397 },
398 );
399
400 info!(
401 "Marked peer {:?} as authenticated after receiving AuthSuccess",
402 peer_id
403 );
404 Ok(())
405 }
406
407 pub async fn remove_peer(&self, peer_id: &PeerId) {
409 let mut peers = self.authenticated_peers.write().await;
410 if peers.remove(peer_id).is_some() {
411 info!("Removed authenticated peer {:?}", peer_id);
412 }
413 }
414
415 pub async fn cleanup_expired_challenges(&self) {
417 let mut challenges = self.pending_challenges.write().await;
418 let now = Instant::now();
419
420 challenges.retain(|peer_id, challenge| {
421 let expired =
422 now.duration_since(challenge.created_at) <= self.config.challenge_validity;
423 if !expired {
424 debug!("Removing expired challenge for peer {:?}", peer_id);
425 }
426 expired
427 });
428 }
429
430 pub async fn list_authenticated_peers(&self) -> Vec<PeerId> {
432 let peers = self.authenticated_peers.read().await;
433 peers.keys().cloned().collect()
434 }
435
436 pub fn serialize_message(msg: &AuthMessage) -> Result<Vec<u8>, AuthError> {
438 serde_json::to_vec(msg).map_err(|e| AuthError::SerializationError(e.to_string()))
439 }
440
441 pub fn deserialize_message(data: &[u8]) -> Result<AuthMessage, AuthError> {
443 serde_json::from_slice(data).map_err(|e| AuthError::SerializationError(e.to_string()))
444 }
445}
446
447pub struct AuthProtocol {
449 auth_manager: Arc<AuthManager>,
450 pending_auth: Arc<tokio::sync::RwLock<HashMap<PeerId, [u8; 32]>>>,
452}
453
454impl AuthProtocol {
455 pub fn new(auth_manager: Arc<AuthManager>) -> Self {
457 Self {
458 auth_manager,
459 pending_auth: Arc::new(tokio::sync::RwLock::new(HashMap::new())),
460 }
461 }
462
463 pub async fn handle_message(
465 &self,
466 peer_id: PeerId,
467 message: AuthMessage,
468 ) -> Result<Option<AuthMessage>, AuthError> {
469 match message {
470 AuthMessage::AuthRequest {
471 peer_id: req_peer_id,
472 public_key,
473 ..
474 } => {
475 if req_peer_id != peer_id {
476 return Err(AuthError::InvalidPeerId);
477 }
478 self.pending_auth.write().await.insert(peer_id, public_key);
480 let response = self
481 .auth_manager
482 .handle_auth_request(peer_id, public_key)
483 .await?;
484 Ok(Some(response))
485 }
486 AuthMessage::Challenge { nonce, .. } => {
487 let response = self.auth_manager.create_challenge_response(nonce)?;
488 Ok(Some(response))
489 }
490 AuthMessage::ChallengeResponse {
491 nonce, signature, ..
492 } => {
493 let public_key_bytes = match self.pending_auth.read().await.get(&peer_id) {
495 Some(key) => *key,
496 None => return Err(AuthError::PeerNotFound),
497 };
498
499 let response = self
500 .auth_manager
501 .verify_challenge_response(peer_id, public_key_bytes, nonce, &signature)
502 .await?;
503
504 if matches!(response, AuthMessage::AuthSuccess { .. }) {
506 self.pending_auth.write().await.remove(&peer_id);
507 }
508
509 Ok(Some(response))
510 }
511 AuthMessage::AuthSuccess { session_id, .. } => {
512 info!(
513 "Authentication successful with peer {:?}, session: {:?}",
514 peer_id,
515 hex::encode(session_id)
516 );
517 Ok(None)
518 }
519 AuthMessage::AuthFailure { reason } => {
520 warn!("Authentication failed with peer {:?}: {}", peer_id, reason);
521 Err(AuthError::InvalidSignature)
522 }
523 }
524 }
525
526 pub async fn initiate_auth(&self) -> AuthMessage {
528 self.auth_manager.create_auth_request()
529 }
530}
531
532#[cfg(test)]
533mod tests {
534 use super::*;
535 use crate::crypto::raw_public_keys::key_utils::generate_ed25519_keypair;
536
537 #[tokio::test]
538 async fn test_auth_manager_creation() {
539 let (secret_key, _) = generate_ed25519_keypair();
540 let config = AuthConfig::default();
541 let auth_manager = AuthManager::new(secret_key, config);
542
543 let peer_id = auth_manager.peer_id();
545 assert_eq!(peer_id.0.len(), 32);
546 }
547
548 #[tokio::test]
549 async fn test_authentication_flow() {
550 let (secret_key1, public_key1) = generate_ed25519_keypair();
552 let (secret_key2, _) = generate_ed25519_keypair();
553
554 let auth1 = AuthManager::new(secret_key1, AuthConfig::default());
555 let auth2 = AuthManager::new(secret_key2, AuthConfig::default());
556
557 let auth_request = auth1.create_auth_request();
559
560 let challenge = match &auth_request {
562 AuthMessage::AuthRequest {
563 peer_id,
564 public_key,
565 ..
566 } => auth2
567 .handle_auth_request(*peer_id, *public_key)
568 .await
569 .unwrap(),
570 _ => panic!("Expected AuthRequest"),
571 };
572
573 let response = match &challenge {
575 AuthMessage::Challenge { nonce, .. } => {
576 auth1.create_challenge_response(*nonce).unwrap()
577 }
578 _ => panic!("Expected Challenge"),
579 };
580
581 let result = match &response {
583 AuthMessage::ChallengeResponse {
584 nonce, signature, ..
585 } => {
586 auth2
587 .verify_challenge_response(
588 auth1.peer_id(),
589 public_key_to_bytes(&public_key1),
590 *nonce,
591 signature,
592 )
593 .await
594 }
595 _ => panic!("Expected ChallengeResponse"),
596 };
597
598 assert!(matches!(result, Ok(AuthMessage::AuthSuccess { .. })));
600
601 assert!(auth2.is_authenticated(&auth1.peer_id()).await);
603 }
604
605 #[tokio::test]
606 async fn test_invalid_signature() {
607 let (secret_key1, _) = generate_ed25519_keypair();
608 let (secret_key2, public_key2) = generate_ed25519_keypair();
609
610 let auth1 = AuthManager::new(secret_key1, AuthConfig::default());
611 let _auth2 = AuthManager::new(secret_key2, AuthConfig::default());
612
613 let peer_id2 = derive_peer_id_from_public_key(&public_key2);
615 let challenge = auth1
616 .handle_auth_request(peer_id2, public_key_to_bytes(&public_key2))
617 .await
618 .unwrap();
619
620 let invalid_signature = vec![0u8; 64];
622 let nonce = match &challenge {
623 AuthMessage::Challenge { nonce, .. } => *nonce,
624 _ => panic!("Expected Challenge"),
625 };
626
627 let result = auth1
629 .verify_challenge_response(
630 peer_id2,
631 public_key_to_bytes(&public_key2),
632 nonce,
633 &invalid_signature,
634 )
635 .await;
636
637 assert!(matches!(result, Err(AuthError::InvalidSignature)));
638 }
639
640 #[tokio::test]
641 async fn test_challenge_expiry() {
642 let (secret_key, public_key) = generate_ed25519_keypair();
643 let config = AuthConfig {
644 challenge_validity: Duration::from_millis(100), ..Default::default()
646 };
647
648 let auth = AuthManager::new(secret_key, config);
649 let peer_id = derive_peer_id_from_public_key(&public_key);
650
651 let _challenge = auth
653 .handle_auth_request(peer_id, public_key_to_bytes(&public_key))
654 .await
655 .unwrap();
656
657 tokio::time::sleep(Duration::from_millis(200)).await;
659
660 let result = auth
662 .verify_challenge_response(
663 peer_id,
664 public_key_to_bytes(&public_key),
665 [0u8; 32], &[0u8; 64], )
668 .await;
669
670 assert!(matches!(result, Err(AuthError::ChallengeExpired)));
671 }
672
673 #[tokio::test]
674 async fn test_message_serialization() {
675 let (_, public_key) = generate_ed25519_keypair();
676 let peer_id = derive_peer_id_from_public_key(&public_key);
677
678 let msg = AuthMessage::AuthRequest {
679 peer_id,
680 public_key: public_key_to_bytes(&public_key),
681 timestamp: SystemTime::now(),
682 };
683
684 let serialized = AuthManager::serialize_message(&msg).unwrap();
686 let deserialized = AuthManager::deserialize_message(&serialized).unwrap();
687
688 match (msg, deserialized) {
689 (
690 AuthMessage::AuthRequest {
691 peer_id: p1,
692 public_key: k1,
693 ..
694 },
695 AuthMessage::AuthRequest {
696 peer_id: p2,
697 public_key: k2,
698 ..
699 },
700 ) => {
701 assert_eq!(p1, p2);
702 assert_eq!(k1, k2);
703 }
704 _ => panic!("Message mismatch"),
705 }
706 }
707}