1use async_trait::async_trait;
18use chrono::{DateTime, Duration, Utc};
19use serde::{Deserialize, Serialize};
20use std::collections::HashMap;
21use thiserror::Error;
22use tracing::info;
23use uuid::Uuid;
24
25use uvb_core::{TenantId, UserId};
26
27#[derive(Debug, Error)]
29pub enum BiometricError {
30 #[error("User verification not performed")]
31 UserVerificationNotPerformed,
32
33 #[error("Liveness detection not supported")]
34 LivenessNotSupported,
35
36 #[error("Step-up authentication required")]
37 StepUpRequired,
38
39 #[error("Biometric re-verification required")]
40 ReverificationRequired,
41
42 #[error("Biometric quality too low: {quality} (minimum: {minimum})")]
43 QualityTooLow { quality: u8, minimum: u8 },
44
45 #[error("Authenticator not verified")]
46 AuthenticatorNotVerified,
47
48 #[error("Biometric verification expired at {0}")]
49 VerificationExpired(DateTime<Utc>),
50
51 #[error("Risk score too high: {0}")]
52 RiskScoreTooHigh(u8),
53
54 #[error("Storage error: {0}")]
55 Storage(String),
56}
57
58#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
60pub enum BiometricModality {
61 Fingerprint,
62 FaceRecognition,
63 IrisScanning,
64 VoiceRecognition,
65 BehavioralBiometrics,
66}
67
68impl BiometricModality {
69 pub fn name(&self) -> &'static str {
71 match self {
72 Self::Fingerprint => "Fingerprint",
73 Self::FaceRecognition => "Face Recognition",
74 Self::IrisScanning => "Iris Scanning",
75 Self::VoiceRecognition => "Voice Recognition",
76 Self::BehavioralBiometrics => "Behavioral Biometrics",
77 }
78 }
79
80 pub fn spoofing_risk(&self) -> RiskLevel {
82 match self {
83 Self::IrisScanning => RiskLevel::Low,
84 Self::FaceRecognition => RiskLevel::Medium, Self::Fingerprint => RiskLevel::Medium, Self::VoiceRecognition => RiskLevel::High, Self::BehavioralBiometrics => RiskLevel::Low,
88 }
89 }
90
91 pub fn requires_liveness(&self) -> bool {
93 matches!(
94 self,
95 Self::FaceRecognition | Self::Fingerprint | Self::VoiceRecognition
96 )
97 }
98}
99
100#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
102pub enum RiskLevel {
103 Low,
104 Medium,
105 High,
106 Critical,
107}
108
109#[derive(Clone, Debug, Serialize, Deserialize)]
111pub struct AuthenticatorCapabilities {
112 pub aaguid: String,
114
115 pub manufacturer: Option<String>,
117
118 pub model: Option<String>,
120
121 pub supports_uv: bool,
123
124 pub supports_liveness: bool,
126
127 pub biometric_modality: Option<BiometricModality>,
129
130 pub certification_level: CertificationLevel,
132
133 pub firmware_version: Option<String>,
135}
136
137impl AuthenticatorCapabilities {
138 pub fn new(aaguid: String) -> Self {
140 Self {
141 aaguid,
142 manufacturer: None,
143 model: None,
144 supports_uv: false,
145 supports_liveness: false,
146 biometric_modality: None,
147 certification_level: CertificationLevel::None,
148 firmware_version: None,
149 }
150 }
151
152 pub fn is_secure(&self) -> bool {
154 self.supports_uv
155 && self.supports_liveness
156 && self.certification_level >= CertificationLevel::Level1
157 }
158
159 pub fn security_score(&self) -> u8 {
161 let mut score = 0u8;
162
163 if self.supports_uv {
164 score += 30;
165 }
166 if self.supports_liveness {
167 score += 30;
168 }
169 score += match self.certification_level {
170 CertificationLevel::Level3Plus => 40,
171 CertificationLevel::Level3 => 30,
172 CertificationLevel::Level2 => 20,
173 CertificationLevel::Level1 => 10,
174 CertificationLevel::None => 0,
175 };
176
177 score
178 }
179}
180
181#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
183pub enum CertificationLevel {
184 None,
185 Level1,
186 Level2,
187 Level3,
188 Level3Plus,
189}
190
191#[derive(Clone, Debug, Serialize, Deserialize)]
193pub struct BiometricVerification {
194 pub verification_id: String,
196
197 pub user_id: UserId,
199
200 pub tenant_id: TenantId,
202
203 pub aaguid: String,
205
206 pub modality: Option<BiometricModality>,
208
209 pub user_verification: bool,
211
212 pub liveness_detection: bool,
214
215 pub quality_score: Option<u8>,
217
218 pub verified_at: DateTime<Utc>,
220
221 pub expires_at: DateTime<Utc>,
223
224 pub ip_address: Option<String>,
226
227 pub risk_score: u8,
229
230 pub step_up_completed: bool,
232}
233
234impl BiometricVerification {
235 pub fn new(
237 user_id: UserId,
238 tenant_id: TenantId,
239 aaguid: String,
240 modality: Option<BiometricModality>,
241 user_verification: bool,
242 liveness_detection: bool,
243 validity_seconds: i64,
244 ) -> Self {
245 let now = Utc::now();
246 Self {
247 verification_id: Uuid::new_v4().to_string(),
248 user_id,
249 tenant_id,
250 aaguid,
251 modality,
252 user_verification,
253 liveness_detection,
254 quality_score: None,
255 verified_at: now,
256 expires_at: now + Duration::seconds(validity_seconds),
257 ip_address: None,
258 risk_score: 0,
259 step_up_completed: false,
260 }
261 }
262
263 pub fn is_expired(&self) -> bool {
265 Utc::now() > self.expires_at
266 }
267
268 pub fn with_quality(mut self, score: u8) -> Self {
270 self.quality_score = Some(score);
271 self
272 }
273
274 pub fn with_risk_score(mut self, score: u8) -> Self {
276 self.risk_score = score;
277 self
278 }
279
280 pub fn with_ip(mut self, ip: String) -> Self {
282 self.ip_address = Some(ip);
283 self
284 }
285
286 pub fn mark_step_up_completed(mut self) -> Self {
288 self.step_up_completed = true;
289 self
290 }
291}
292
293#[derive(Clone, Debug, Serialize, Deserialize)]
295pub struct BiometricPolicy {
296 pub tenant_id: TenantId,
298
299 pub require_uv: bool,
301
302 pub require_liveness: bool,
304
305 pub min_quality_score: u8,
307
308 pub min_certification_level: CertificationLevel,
310
311 pub verification_validity_seconds: i64,
313
314 pub require_step_up_sensitive: bool,
316
317 pub risk_threshold_reverify: u8,
319
320 pub allowed_modalities: Option<Vec<BiometricModality>>,
322}
323
324impl Default for BiometricPolicy {
325 fn default() -> Self {
326 Self {
327 tenant_id: TenantId::new("default"),
328 require_uv: true, require_liveness: false, min_quality_score: 50,
331 min_certification_level: CertificationLevel::Level1,
332 verification_validity_seconds: 300, require_step_up_sensitive: true,
334 risk_threshold_reverify: 70,
335 allowed_modalities: None, }
337 }
338}
339
340impl BiometricPolicy {
341 pub fn strict() -> Self {
343 Self {
344 tenant_id: TenantId::new("strict"),
345 require_uv: true,
346 require_liveness: true, min_quality_score: 70,
348 min_certification_level: CertificationLevel::Level2,
349 verification_validity_seconds: 60, require_step_up_sensitive: true,
351 risk_threshold_reverify: 50, allowed_modalities: Some(vec![
353 BiometricModality::Fingerprint,
354 BiometricModality::FaceRecognition,
355 BiometricModality::IrisScanning,
356 ]),
357 }
358 }
359
360 pub fn lenient() -> Self {
362 Self {
363 tenant_id: TenantId::new("lenient"),
364 require_uv: true, require_liveness: false,
366 min_quality_score: 30,
367 min_certification_level: CertificationLevel::None,
368 verification_validity_seconds: 900, require_step_up_sensitive: false,
370 risk_threshold_reverify: 90, allowed_modalities: None,
372 }
373 }
374
375 pub fn check_compliance(
377 &self,
378 verification: &BiometricVerification,
379 capabilities: &AuthenticatorCapabilities,
380 ) -> Result<(), BiometricError> {
381 if self.require_uv && !verification.user_verification {
383 return Err(BiometricError::UserVerificationNotPerformed);
384 }
385
386 if self.require_liveness && !verification.liveness_detection {
388 return Err(BiometricError::LivenessNotSupported);
389 }
390
391 if let Some(quality) = verification.quality_score {
393 if quality < self.min_quality_score {
394 return Err(BiometricError::QualityTooLow {
395 quality,
396 minimum: self.min_quality_score,
397 });
398 }
399 }
400
401 if capabilities.certification_level < self.min_certification_level {
403 return Err(BiometricError::AuthenticatorNotVerified);
404 }
405
406 if verification.is_expired() {
408 return Err(BiometricError::VerificationExpired(verification.expires_at));
409 }
410
411 if verification.risk_score > self.risk_threshold_reverify {
413 return Err(BiometricError::ReverificationRequired);
414 }
415
416 if let Some(ref allowed) = self.allowed_modalities {
418 if let Some(modality) = verification.modality {
419 if !allowed.contains(&modality) {
420 return Err(BiometricError::AuthenticatorNotVerified);
421 }
422 }
423 }
424
425 Ok(())
426 }
427}
428
429#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
431pub enum OperationSensitivity {
432 Low,
433 Medium,
434 High,
435 Critical,
436}
437
438impl OperationSensitivity {
439 pub fn requires_step_up(&self) -> bool {
441 matches!(self, Self::High | Self::Critical)
442 }
443
444 pub fn required_freshness(&self) -> i64 {
446 match self {
447 Self::Low => 900, Self::Medium => 300, Self::High => 60, Self::Critical => 30, }
452 }
453}
454
455#[async_trait]
457pub trait BiometricStorage: Send + Sync {
458 async fn store_capabilities(
460 &self,
461 capabilities: &AuthenticatorCapabilities,
462 ) -> Result<(), BiometricError>;
463
464 async fn get_capabilities(
466 &self,
467 aaguid: &str,
468 ) -> Result<Option<AuthenticatorCapabilities>, BiometricError>;
469
470 async fn store_verification(
472 &self,
473 verification: &BiometricVerification,
474 ) -> Result<(), BiometricError>;
475
476 async fn get_latest_verification(
478 &self,
479 user_id: &UserId,
480 ) -> Result<Option<BiometricVerification>, BiometricError>;
481
482 async fn store_policy(&self, policy: &BiometricPolicy) -> Result<(), BiometricError>;
484
485 async fn get_policy(&self, tenant_id: &TenantId) -> Result<BiometricPolicy, BiometricError>;
487}
488
489pub struct InMemoryBiometricStorage {
491 capabilities: tokio::sync::RwLock<HashMap<String, AuthenticatorCapabilities>>,
492 verifications: tokio::sync::RwLock<HashMap<UserId, BiometricVerification>>,
493 policies: tokio::sync::RwLock<HashMap<TenantId, BiometricPolicy>>,
494}
495
496impl InMemoryBiometricStorage {
497 pub fn new() -> Self {
498 Self {
499 capabilities: tokio::sync::RwLock::new(HashMap::new()),
500 verifications: tokio::sync::RwLock::new(HashMap::new()),
501 policies: tokio::sync::RwLock::new(HashMap::new()),
502 }
503 }
504}
505
506impl Default for InMemoryBiometricStorage {
507 fn default() -> Self {
508 Self::new()
509 }
510}
511
512#[async_trait]
513impl BiometricStorage for InMemoryBiometricStorage {
514 async fn store_capabilities(
515 &self,
516 capabilities: &AuthenticatorCapabilities,
517 ) -> Result<(), BiometricError> {
518 let mut caps = self.capabilities.write().await;
519 caps.insert(capabilities.aaguid.clone(), capabilities.clone());
520 Ok(())
521 }
522
523 async fn get_capabilities(
524 &self,
525 aaguid: &str,
526 ) -> Result<Option<AuthenticatorCapabilities>, BiometricError> {
527 let caps = self.capabilities.read().await;
528 Ok(caps.get(aaguid).cloned())
529 }
530
531 async fn store_verification(
532 &self,
533 verification: &BiometricVerification,
534 ) -> Result<(), BiometricError> {
535 let mut verifications = self.verifications.write().await;
536 verifications.insert(verification.user_id.clone(), verification.clone());
537 Ok(())
538 }
539
540 async fn get_latest_verification(
541 &self,
542 user_id: &UserId,
543 ) -> Result<Option<BiometricVerification>, BiometricError> {
544 let verifications = self.verifications.read().await;
545 Ok(verifications.get(user_id).cloned())
546 }
547
548 async fn store_policy(&self, policy: &BiometricPolicy) -> Result<(), BiometricError> {
549 let mut policies = self.policies.write().await;
550 policies.insert(policy.tenant_id.clone(), policy.clone());
551 Ok(())
552 }
553
554 async fn get_policy(&self, tenant_id: &TenantId) -> Result<BiometricPolicy, BiometricError> {
555 let policies = self.policies.read().await;
556 Ok(policies
557 .get(tenant_id)
558 .cloned()
559 .unwrap_or_else(BiometricPolicy::default))
560 }
561}
562
563pub struct BiometricSecurityManager<S: BiometricStorage> {
565 storage: S,
566}
567
568impl<S: BiometricStorage> BiometricSecurityManager<S> {
569 pub fn new(storage: S) -> Self {
571 Self { storage }
572 }
573
574 pub async fn register_authenticator(
576 &self,
577 capabilities: AuthenticatorCapabilities,
578 ) -> Result<AuthenticatorCapabilities, BiometricError> {
579 self.storage.store_capabilities(&capabilities).await?;
580 info!(
581 "Authenticator registered: {} (secure: {})",
582 capabilities.aaguid,
583 capabilities.is_secure()
584 );
585 Ok(capabilities)
586 }
587
588 pub async fn record_verification(
590 &self,
591 verification: BiometricVerification,
592 ) -> Result<BiometricVerification, BiometricError> {
593 let policy = self.storage.get_policy(&verification.tenant_id).await?;
595
596 let capabilities = self
598 .storage
599 .get_capabilities(&verification.aaguid)
600 .await?
601 .unwrap_or_else(|| AuthenticatorCapabilities::new(verification.aaguid.clone()));
602
603 policy.check_compliance(&verification, &capabilities)?;
605
606 self.storage.store_verification(&verification).await?;
607
608 info!(
609 "Biometric verification recorded for user {} (UV: {}, liveness: {})",
610 verification.user_id, verification.user_verification, verification.liveness_detection
611 );
612 Ok(verification)
613 }
614
615 pub async fn verify_for_operation(
617 &self,
618 user_id: &UserId,
619 tenant_id: &TenantId,
620 sensitivity: OperationSensitivity,
621 ) -> Result<(), BiometricError> {
622 let policy = self.storage.get_policy(tenant_id).await?;
624
625 let verification = self
627 .storage
628 .get_latest_verification(user_id)
629 .await?
630 .ok_or(BiometricError::UserVerificationNotPerformed)?;
631
632 let capabilities = self
634 .storage
635 .get_capabilities(&verification.aaguid)
636 .await?
637 .unwrap_or_else(|| AuthenticatorCapabilities::new(verification.aaguid.clone()));
638
639 policy.check_compliance(&verification, &capabilities)?;
641
642 let age_seconds = (Utc::now() - verification.verified_at).num_seconds();
644 if age_seconds > sensitivity.required_freshness() {
645 return Err(BiometricError::ReverificationRequired);
646 }
647
648 if sensitivity.requires_step_up()
650 && policy.require_step_up_sensitive
651 && !verification.step_up_completed
652 {
653 return Err(BiometricError::StepUpRequired);
654 }
655
656 info!(
657 "Biometric verification passed for user {} (sensitivity: {:?})",
658 user_id, sensitivity
659 );
660 Ok(())
661 }
662
663 pub fn calculate_risk_score(
665 &self,
666 verification: &BiometricVerification,
667 capabilities: &AuthenticatorCapabilities,
668 ) -> u8 {
669 let mut risk = 0u8;
670
671 if !verification.user_verification {
673 risk = risk.saturating_add(40);
674 }
675
676 if !verification.liveness_detection {
678 if let Some(modality) = verification.modality {
679 if modality.requires_liveness() {
680 risk = risk.saturating_add(30);
681 }
682 }
683 }
684
685 if let Some(quality) = verification.quality_score {
687 if quality < 50 {
688 risk = risk.saturating_add(20);
689 }
690 }
691
692 if capabilities.certification_level < CertificationLevel::Level1 {
694 risk = risk.saturating_add(10);
695 }
696
697 risk
698 }
699}
700
701#[cfg(test)]
702mod tests {
703 use super::*;
704
705 #[test]
706 fn test_authenticator_security_score() {
707 let mut caps = AuthenticatorCapabilities::new("test-aaguid".to_string());
708 caps.supports_uv = true;
709 caps.supports_liveness = true;
710 caps.certification_level = CertificationLevel::Level3;
711
712 assert_eq!(caps.security_score(), 90); assert!(caps.is_secure());
714 }
715
716 #[tokio::test]
717 async fn test_verification_recording() {
718 let storage = InMemoryBiometricStorage::new();
719 let manager = BiometricSecurityManager::new(storage);
720
721 let mut caps = AuthenticatorCapabilities::new("secure-auth".to_string());
723 caps.supports_uv = true;
724 caps.supports_liveness = true;
725 caps.certification_level = CertificationLevel::Level2;
726 manager.register_authenticator(caps).await.unwrap();
727
728 let verification = BiometricVerification::new(
730 UserId::new("test_user"),
731 TenantId::new("test_tenant"),
732 "secure-auth".to_string(),
733 Some(BiometricModality::Fingerprint),
734 true,
735 true,
736 300,
737 );
738
739 let recorded = manager.record_verification(verification).await.unwrap();
740 assert!(recorded.user_verification);
741 assert!(recorded.liveness_detection);
742 }
743
744 #[tokio::test]
745 async fn test_policy_compliance() {
746 let policy = BiometricPolicy::strict();
747 let mut caps = AuthenticatorCapabilities::new("test".to_string());
748 caps.supports_uv = true;
749 caps.supports_liveness = true;
750 caps.certification_level = CertificationLevel::Level2;
751
752 let verification = BiometricVerification::new(
753 UserId::new("test_user"),
754 TenantId::new("test_tenant"),
755 "test".to_string(),
756 Some(BiometricModality::Fingerprint),
757 true,
758 true,
759 300,
760 );
761
762 assert!(policy.check_compliance(&verification, &caps).is_ok());
764
765 let mut bad_verification = verification.clone();
767 bad_verification.user_verification = false;
768 assert!(policy.check_compliance(&bad_verification, &caps).is_err());
769 }
770
771 #[test]
772 fn test_risk_scoring() {
773 let storage = InMemoryBiometricStorage::new();
774 let manager = BiometricSecurityManager::new(storage);
775
776 let verification = BiometricVerification::new(
777 UserId::new("test_user"),
778 TenantId::new("test_tenant"),
779 "test".to_string(),
780 Some(BiometricModality::FaceRecognition),
781 false, false, 300,
784 )
785 .with_quality(30); let caps = AuthenticatorCapabilities::new("test".to_string());
788 let risk = manager.calculate_risk_score(&verification, &caps);
791 assert_eq!(risk, 100); }
793}