Skip to main content

auths_verifier/
verifier.rs

1//! Dependency-injected [`Verifier`] for attestation and chain verification.
2
3use std::sync::Arc;
4
5use auths_crypto::CryptoProvider;
6
7use crate::clock::ClockProvider;
8use crate::core::{Attestation, DevicePublicKey, VerifiedAttestation};
9use crate::error::AttestationError;
10use crate::types::{CanonicalDid, VerificationReport};
11use crate::verify;
12use crate::witness::WitnessVerifyConfig;
13
14/// Dependency-injected verifier for attestation and chain verification.
15///
16/// Uses `Arc<dyn CryptoProvider>` and `Arc<dyn ClockProvider>` for
17/// lifetime-free sharing across async tasks and web server handler state.
18///
19/// Usage:
20/// ```ignore
21/// use std::sync::Arc;
22/// use auths_verifier::{Verifier, SystemClock};
23/// use auths_crypto::RingCryptoProvider;
24///
25/// let verifier = Verifier::native();
26/// let result = verifier.verify_with_keys(&att, &pk).await;
27/// ```
28#[derive(Clone)]
29pub struct Verifier {
30    provider: Arc<dyn CryptoProvider>,
31    clock: Arc<dyn ClockProvider>,
32}
33
34impl Verifier {
35    /// Create a `Verifier` with the given crypto provider and clock.
36    ///
37    /// Args:
38    /// * `provider`: Ed25519 crypto backend.
39    /// * `clock`: Clock provider for expiry checks.
40    pub fn new(provider: Arc<dyn CryptoProvider>, clock: Arc<dyn ClockProvider>) -> Self {
41        Self { provider, clock }
42    }
43
44    /// Create a `Verifier` using the native Ring crypto provider and system clock.
45    #[cfg(feature = "native")]
46    pub fn native() -> Self {
47        Self {
48            provider: Arc::new(auths_crypto::RingCryptoProvider),
49            clock: Arc::new(crate::clock::SystemClock),
50        }
51    }
52
53    /// Verify an attestation's signatures against the issuer's public key.
54    ///
55    /// Args:
56    /// * `att`: The attestation to verify.
57    /// * `issuer_pk`: Typed issuer public key (Ed25519 or P-256).
58    pub async fn verify_with_keys(
59        &self,
60        att: &Attestation,
61        issuer_pk: &DevicePublicKey,
62    ) -> Result<VerifiedAttestation, AttestationError> {
63        verify::verify_with_keys_at(
64            att,
65            issuer_pk,
66            self.clock.now(),
67            true,
68            self.provider.as_ref(),
69        )
70        .await?;
71        Ok(VerifiedAttestation::from_verified(att.clone()))
72    }
73
74    /// Verify an attestation against a specific point in time (skips clock-skew check).
75    ///
76    /// Args:
77    /// * `att`: The attestation to verify.
78    /// * `issuer_pk`: Typed issuer public key (Ed25519 or P-256).
79    /// * `at`: The reference timestamp for expiry evaluation.
80    pub async fn verify_at_time(
81        &self,
82        att: &Attestation,
83        issuer_pk: &DevicePublicKey,
84        at: chrono::DateTime<chrono::Utc>,
85    ) -> Result<VerifiedAttestation, AttestationError> {
86        verify::verify_with_keys_at(att, issuer_pk, at, false, self.provider.as_ref()).await?;
87        Ok(VerifiedAttestation::from_verified(att.clone()))
88    }
89
90    /// Verify an ordered attestation chain starting from a known root public key.
91    ///
92    /// Args:
93    /// * `attestations`: Ordered attestation chain (root first).
94    /// * `root_pk`: Typed root identity public key (Ed25519 or P-256).
95    pub async fn verify_chain(
96        &self,
97        attestations: &[Attestation],
98        root_pk: &DevicePublicKey,
99    ) -> Result<VerificationReport, AttestationError> {
100        verify::verify_chain_inner(
101            attestations,
102            root_pk,
103            self.provider.as_ref(),
104            self.clock.now(),
105        )
106        .await
107    }
108
109    /// Verify a chain and additionally validate witness receipts against a quorum threshold.
110    ///
111    /// Args:
112    /// * `attestations`: Ordered attestation chain (root first).
113    /// * `root_pk`: Typed root identity public key (Ed25519 or P-256).
114    /// * `witness_config`: Witness receipts and quorum threshold to validate.
115    pub async fn verify_chain_with_witnesses(
116        &self,
117        attestations: &[Attestation],
118        root_pk: &DevicePublicKey,
119        witness_config: &WitnessVerifyConfig<'_>,
120    ) -> Result<VerificationReport, AttestationError> {
121        let mut report = self.verify_chain(attestations, root_pk).await?;
122        if !report.is_valid() {
123            return Ok(report);
124        }
125
126        let quorum =
127            crate::witness::verify_witness_receipts(witness_config, self.provider.as_ref()).await;
128        if quorum.verified < quorum.required {
129            report.status = crate::types::VerificationStatus::InsufficientWitnesses {
130                required: quorum.required,
131                verified: quorum.verified,
132            };
133            report.warnings.push(format!(
134                "Witness quorum not met: {}/{} verified",
135                quorum.verified, quorum.required
136            ));
137        }
138        report.witness_quorum = Some(quorum);
139        Ok(report)
140    }
141
142    /// Verify that a specific device is authorized under a given identity.
143    ///
144    /// Args:
145    /// * `identity_did`: The DID of the authorizing identity.
146    /// * `device_did`: The device DID to check authorization for.
147    /// * `attestations`: Pool of attestations to search.
148    /// * `identity_pk`: Typed identity public key (Ed25519 or P-256).
149    pub async fn verify_device_authorization(
150        &self,
151        identity_did: &str,
152        device_did: &CanonicalDid,
153        attestations: &[Attestation],
154        identity_pk: &DevicePublicKey,
155    ) -> Result<VerificationReport, AttestationError> {
156        verify::verify_device_authorization_inner(
157            identity_did,
158            device_did,
159            attestations,
160            identity_pk,
161            self.provider.as_ref(),
162            self.clock.now(),
163        )
164        .await
165    }
166}