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