structured_cms/
timestamp.rs1use structured_pkix::temporal::{Instant, LeapTable, Reading, Uncertainty};
4
5mod accuracy;
6pub use accuracy::{AccuracyReading, Component, ComponentReading, DeviationError, DeviationReason};
7mod imprint;
8pub use imprint::{HashAlgorithmReading, MessageImprint};
9mod imprint_check;
10pub use imprint_check::{ImprintAgreement, ImprintError};
11mod requested;
12pub use requested::{ImprintOperand, RequestAgreement, RequestImprintError, RequestedContentError};
13mod extension;
14pub use extension::{RecognitionError, TokenExtension, TokenExtensions};
15mod info;
16pub use info::{IntegerField, TokenInfo};
17mod tsa;
18pub use tsa::TsaReading;
19mod token;
20pub use token::{InfoError, Token};
21mod timeliness;
22pub use timeliness::{RequestWindow, Timeliness, timeliness};
23mod request;
24pub use request::Request;
25mod request_extensions;
26mod request_fields;
27pub use request_fields::{RequestFieldError, RequestFields};
28mod authority;
29mod carried;
30mod signature;
31pub use authority::{AuthorityError, AuthorityFacts, AuthoritySource, TsaIdentity, TsaUsage};
32pub use signature::{SignatureError, TokenSignature};
33mod check;
34mod profile;
35pub use check::{
36 CheckContext, CheckError, CheckedTimestamp, Evidence, EvidenceCopyError, InfoCheckError,
37 MappedCheckError, Requested,
38};
39pub use profile::{
40 MappedProfileCheckError, ProfileCheckError, ProfileFailure, ProfileInput, ProfileSource,
41};
42mod retained;
43pub use retained::{RetainedFacts, RetainedImprint};
44
45pub(crate) fn record<W: structured_asn1::memory::Work>(
46 faults: &mut structured_asn1::memory::OwnedVec<crate::Error, W>,
47 error: crate::Error,
48) -> crate::Result<()> {
49 if error.is_terminal() {
50 return Err(error);
51 }
52 let at = error.offset();
53 let field = error.field();
54 faults
55 .try_push(error)
56 .map_err(|reason| crate::Error::resource(reason, field, at))
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67pub struct Accuracy {
68 seconds: u64,
69 millis: u64,
70 micros: u64,
71}
72
73impl Accuracy {
74 #[must_use]
76 pub const fn new(seconds: u64, millis: u64, micros: u64) -> Self {
77 Self {
78 seconds,
79 millis,
80 micros,
81 }
82 }
83 #[must_use]
85 pub const fn seconds(self) -> u64 {
86 self.seconds
87 }
88 #[must_use]
90 pub const fn millis(self) -> u64 {
91 self.millis
92 }
93 #[must_use]
95 pub const fn micros(self) -> u64 {
96 self.micros
97 }
98 #[must_use]
100 pub fn nanos(self) -> u128 {
101 u128::from(self.seconds) * 1_000_000_000
103 + u128::from(self.millis) * 1_000_000
104 + u128::from(self.micros) * 1_000
105 }
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
110pub enum BoundUncertainty {
111 AccuracyUnstated,
113 Utc(Uncertainty),
115}
116
117pub fn earliest(
120 reading: Reading,
121 accuracy: Option<Accuracy>,
122 utc: &LeapTable<'_>,
123) -> Result<Instant, BoundUncertainty> {
124 let accuracy = accuracy.ok_or(BoundUncertainty::AccuracyUnstated)?;
125 shift(reading.start(), accuracy, true, utc)
126}
127
128pub fn latest(
131 reading: Reading,
132 accuracy: Option<Accuracy>,
133 utc: &LeapTable<'_>,
134) -> Result<Instant, BoundUncertainty> {
135 let accuracy = accuracy.ok_or(BoundUncertainty::AccuracyUnstated)?;
140 let upper = reading.upper_bound(utc).map_err(BoundUncertainty::Utc)?;
141 shift(upper, accuracy, false, utc)
142}
143
144fn shift(
145 at: Instant,
146 accuracy: Accuracy,
147 earlier: bool,
148 utc: &LeapTable<'_>,
149) -> Result<Instant, BoundUncertainty> {
150 let nanos = i128::try_from(accuracy.nanos())
151 .map_err(|_| BoundUncertainty::Utc(Uncertainty::OutOfRange))?;
152 utc.shift(at, if earlier { -nanos } else { nanos })
153 .map_err(BoundUncertainty::Utc)
154}