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;
34pub use check::{
35 CheckContext, CheckError, CheckedTimestamp, Evidence, EvidenceCopyError, InfoCheckError,
36 MappedCheckError, Requested,
37};
38mod retained;
39pub use retained::{RetainedFacts, RetainedImprint};
40
41pub(crate) fn record<W: structured_asn1::memory::Work>(
42 faults: &mut structured_asn1::memory::OwnedVec<crate::Error, W>,
43 error: crate::Error,
44) -> crate::Result<()> {
45 if error.is_terminal() {
46 return Err(error);
47 }
48 let at = error.offset();
49 let field = error.field();
50 faults
51 .try_push(error)
52 .map_err(|reason| crate::Error::resource(reason, field, at))
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub struct Accuracy {
64 seconds: u64,
65 millis: u64,
66 micros: u64,
67}
68
69impl Accuracy {
70 #[must_use]
72 pub const fn new(seconds: u64, millis: u64, micros: u64) -> Self {
73 Self {
74 seconds,
75 millis,
76 micros,
77 }
78 }
79 #[must_use]
81 pub const fn seconds(self) -> u64 {
82 self.seconds
83 }
84 #[must_use]
86 pub const fn millis(self) -> u64 {
87 self.millis
88 }
89 #[must_use]
91 pub const fn micros(self) -> u64 {
92 self.micros
93 }
94 #[must_use]
96 pub fn nanos(self) -> u128 {
97 u128::from(self.seconds) * 1_000_000_000
99 + u128::from(self.millis) * 1_000_000
100 + u128::from(self.micros) * 1_000
101 }
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
106pub enum BoundUncertainty {
107 AccuracyUnstated,
109 Utc(Uncertainty),
111}
112
113pub fn earliest(
116 reading: Reading,
117 accuracy: Option<Accuracy>,
118 utc: &LeapTable<'_>,
119) -> Result<Instant, BoundUncertainty> {
120 let accuracy = accuracy.ok_or(BoundUncertainty::AccuracyUnstated)?;
121 shift(reading.start(), accuracy, true, utc)
122}
123
124pub fn latest(
127 reading: Reading,
128 accuracy: Option<Accuracy>,
129 utc: &LeapTable<'_>,
130) -> Result<Instant, BoundUncertainty> {
131 let accuracy = accuracy.ok_or(BoundUncertainty::AccuracyUnstated)?;
136 let upper = reading.upper_bound(utc).map_err(BoundUncertainty::Utc)?;
137 shift(upper, accuracy, false, utc)
138}
139
140fn shift(
141 at: Instant,
142 accuracy: Accuracy,
143 earlier: bool,
144 utc: &LeapTable<'_>,
145) -> Result<Instant, BoundUncertainty> {
146 let nanos = i128::try_from(accuracy.nanos())
147 .map_err(|_| BoundUncertainty::Utc(Uncertainty::OutOfRange))?;
148 utc.shift(at, if earlier { -nanos } else { nanos })
149 .map_err(BoundUncertainty::Utc)
150}