1use structured_pkix::temporal::{Instant, LeapTable, Reading, Uncertainty};
4
5mod accuracy;
6pub use accuracy::{AccuracyReading, Component, ComponentReading, DeviationError, DeviationReason};
7mod policy_accuracy;
8pub use policy_accuracy::{EffectiveAccuracy, InvalidPolicyAccuracy, PolicyAccuracy};
9mod imprint;
10pub use imprint::{HashAlgorithmReading, MessageImprint};
11mod imprint_check;
12pub use imprint_check::{ImprintAgreement, ImprintError};
13mod computed;
14pub use computed::{
15 ComputedInput, ImprintContext, ImprintDigest, ImprintProof, ImprintState, InputFailure,
16 RawInput,
17};
18mod requested;
19pub use requested::{ImprintOperand, RequestAgreement, RequestImprintError, RequestedContentError};
20mod extension;
21pub use extension::{RecognitionError, TokenExtension, TokenExtensions};
22mod info;
23pub use info::{IntegerField, TokenInfo};
24mod tsa;
25pub use tsa::TsaReading;
26mod token;
27pub use computed::{AsyncComputedInput, AsyncRawInput};
28pub use token::{AsyncInfoVisitor, InfoError, Token};
29mod timeliness;
30pub use timeliness::{RequestWindow, Timeliness, timeliness};
31mod request;
32pub use request::Request;
33mod request_encoding;
34pub use request_encoding::{NewRequest, RequestEncodingError, RequestExtension};
35pub mod response;
36pub use response::Response;
37mod request_extensions;
38mod request_fields;
39pub use request_fields::{RequestFieldError, RequestFields};
40mod authority;
41mod carried;
42mod signature;
43pub use authority::{AuthorityError, AuthorityFacts, AuthoritySource, TsaIdentity, TsaUsage};
44pub use signature::{SignatureError, TokenSignature};
45mod check;
46mod profile;
47pub use check::{
48 CheckContext, CheckError, CheckedTimestamp, Evidence, EvidenceCopyError, InfoCheckError,
49 MappedCheckError, Requested,
50};
51pub use profile::{
52 MappedProfileCheckError, ProfileCheckError, ProfileFailure, ProfileInput, ProfileSource,
53};
54mod retained;
55pub use retained::{RetainedFacts, RetainedImprint};
56
57pub(crate) fn record<W: structured_asn1::memory::Work>(
58 faults: &mut structured_asn1::memory::OwnedVec<crate::Error, W>,
59 error: crate::Error,
60) -> crate::Result<()> {
61 if error.is_terminal() {
62 return Err(error);
63 }
64 let at = error.offset();
65 let field = error.field();
66 faults
67 .try_push(error)
68 .map_err(|reason| crate::Error::resource(reason, field, at))
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub struct Accuracy {
80 seconds: u64,
81 millis: u64,
82 micros: u64,
83}
84
85impl Accuracy {
86 #[must_use]
88 pub const fn new(seconds: u64, millis: u64, micros: u64) -> Self {
89 Self {
90 seconds,
91 millis,
92 micros,
93 }
94 }
95 #[must_use]
97 pub const fn seconds(self) -> u64 {
98 self.seconds
99 }
100 #[must_use]
102 pub const fn millis(self) -> u64 {
103 self.millis
104 }
105 #[must_use]
107 pub const fn micros(self) -> u64 {
108 self.micros
109 }
110 #[must_use]
112 pub fn nanos(self) -> u128 {
113 u128::from(self.seconds) * 1_000_000_000
115 + u128::from(self.millis) * 1_000_000
116 + u128::from(self.micros) * 1_000
117 }
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122pub enum BoundUncertainty {
123 AccuracyUnstated,
125 Utc(Uncertainty),
127}
128
129pub use structured_pkix::temporal::CompareError as GenerationOrderError;
131
132#[derive(Debug, Clone, Copy, PartialEq, Eq)]
134pub struct GenerationInterval {
135 pub earliest: Instant,
137 pub latest: Instant,
139}
140#[derive(Debug, Clone, Copy, PartialEq, Eq)]
142pub enum IntervalError {
143 Resource(structured_asn1::memory::MemoryError),
145 Uncertain(BoundUncertainty),
147}
148pub fn interval_in<W: structured_asn1::memory::Work>(
151 reading: Reading,
152 accuracy: Option<Accuracy>,
153 utc: &LeapTable<'_>,
154 work: &W,
155) -> core::result::Result<GenerationInterval, IntervalError> {
156 let bits = usize::BITS - utc.transitions().len().leading_zeros();
157 work.charge_work(48 + 9 * (u64::from(bits) + 1))
158 .map_err(IntervalError::Resource)?;
159 Ok(GenerationInterval {
160 earliest: earliest(reading, accuracy, utc).map_err(IntervalError::Uncertain)?,
161 latest: latest(reading, accuracy, utc).map_err(IntervalError::Uncertain)?,
162 })
163}
164
165pub fn earliest(
168 reading: Reading,
169 accuracy: Option<Accuracy>,
170 utc: &LeapTable<'_>,
171) -> Result<Instant, BoundUncertainty> {
172 let accuracy = accuracy.ok_or(BoundUncertainty::AccuracyUnstated)?;
173 shift(reading.start(), accuracy, true, utc)
174}
175
176pub fn latest(
179 reading: Reading,
180 accuracy: Option<Accuracy>,
181 utc: &LeapTable<'_>,
182) -> Result<Instant, BoundUncertainty> {
183 let accuracy = accuracy.ok_or(BoundUncertainty::AccuracyUnstated)?;
188 let upper = reading.upper_bound(utc).map_err(BoundUncertainty::Utc)?;
189 shift(upper, accuracy, false, utc)
190}
191
192fn shift(
193 at: Instant,
194 accuracy: Accuracy,
195 earlier: bool,
196 utc: &LeapTable<'_>,
197) -> Result<Instant, BoundUncertainty> {
198 let nanos = i128::try_from(accuracy.nanos())
199 .map_err(|_| BoundUncertainty::Utc(Uncertainty::OutOfRange))?;
200 utc.shift(at, if earlier { -nanos } else { nanos })
201 .map_err(BoundUncertainty::Utc)
202}