Skip to main content

structured_cms/evidence/
renewal.rs

1//! Exact previous-chain input for RFC4998 §5.2 hash-tree renewal.
2
3use super::{
4    EvidenceRecord, FIELD, encoding,
5    input::{Hasher, InputError},
6    syntax,
7};
8use crate::encoding::{FeedError, Form, Projection, Rules};
9use crate::{Error, ErrorCode, Result};
10use structured_asn1::{
11    Class, Reader,
12    length::DerLength,
13    memory::{OwnedVec, Work},
14};
15use structured_pkix::algorithm::digest::AsnDigest;
16
17/// Immutable DER input covering EVERY chain preceding an actual new chain.
18///
19/// The surrounding sequence receives its required minimal DER length. Chain
20/// values are projected through the shared encoding kernel; BER wrappers and
21/// segmentation are not confused with DER bytes. No later chain or
22/// unprotected CryptoInfos/EncryptionInfo is included (§5.2 steps3–4).
23pub struct PriorSequence<'record, 'document> {
24    record: &'record EvidenceRecord<'document>,
25    before: usize,
26    length: u64,
27    projected: Prefix<'record, 'document>,
28}
29enum Prefix<'r, 'd> {
30    Owned(OwnedVec<Projection<'d>>),
31    Borrowed(&'r [Projection<'d>]),
32}
33impl<'d> Prefix<'_, 'd> {
34    fn values(&self) -> &[Projection<'d>] {
35        match self {
36            Self::Owned(values) => values,
37            Self::Borrowed(values) => values,
38        }
39    }
40}
41impl<'r, 'd> PriorSequence<'r, 'd> {
42    /// Binds the prefix to the actual new chain and admits it before hashing.
43    pub fn new(
44        record: &'r EvidenceRecord<'d>,
45        before_chain: usize,
46        operation: &Reader<'d>,
47    ) -> Result<Self> {
48        operation.charge(1).map_err(encoding)?;
49        if before_chain == 0 || before_chain >= record.chains.len() {
50            return Err(syntax(
51                ErrorCode::InvalidLocation,
52                record.original.element.span(),
53            ));
54        }
55        let projected = Self::project(record, before_chain, operation)?;
56        let length = prefix_length(
57            &projected,
58            &operation.execution(),
59            record.original.element.span().start,
60        )?;
61        Ok(Self {
62            record,
63            before: before_chain,
64            length,
65            projected: Prefix::Owned(projected),
66        })
67    }
68    pub(super) fn all(
69        record: &EvidenceRecord<'d>,
70        operation: &Reader<'d>,
71    ) -> Result<OwnedVec<Projection<'d>>> {
72        Self::project(record, record.chains.len() - 1, operation)
73    }
74    pub(super) fn borrowed(
75        record: &'r EvidenceRecord<'d>,
76        before: usize,
77        projected: &'r [Projection<'d>],
78        operation: &Reader<'_>,
79    ) -> Result<Self> {
80        let values = &projected[..before];
81        let length = prefix_length(
82            values,
83            &operation.execution(),
84            record.original.element.span().start,
85        )?;
86        Ok(Self {
87            record,
88            before,
89            length,
90            projected: Prefix::Borrowed(values),
91        })
92    }
93    fn project(
94        record: &EvidenceRecord<'d>,
95        count: usize,
96        operation: &Reader<'d>,
97    ) -> Result<OwnedVec<Projection<'d>>> {
98        let origin = record.original.reader_in(operation)?;
99        let work = origin.execution_query(operation);
100        let mut rules = Rules::new(&work);
101        // These IMPLICIT SET OF and OCTET STRING roles come from the SAME
102        // parsed schemas. Context tag number alone never selects their form.
103        for stamp in &record.timestamps[..record
104            .chains
105            .get(count)
106            .map_or(record.timestamps.len(), |chain| chain.first)]
107        {
108            work.charge_work(1).map_err(|cause| {
109                Error::resource(cause, FIELD, stamp.original.element.span().start)
110            })?;
111            if let Some(span) = stamp.attributes_span {
112                rules.insert(span, Form::Set, &work)?;
113            }
114            if let super::TimeStamp::Rfc3161(token) = &stamp.token {
115                let message = token.message();
116                for span in [message.certificate_field(), message.revocation_field()]
117                    .into_iter()
118                    .flatten()
119                {
120                    rules.insert(span, Form::Set, &work)?;
121                }
122                for certificate in message.certificates() {
123                    for identifier in [
124                        certificate.signature_algorithm(),
125                        certificate.tbs().signature(),
126                        certificate.tbs().public_key().algorithm(),
127                    ] {
128                        rules.algorithm(identifier, &work)?;
129                    }
130                }
131                for signer in message.signers() {
132                    work.charge_work(1)
133                        .map_err(|cause| Error::resource(cause, FIELD, signer.span().start))?;
134                    for attrs in [signer.signed_attributes(), signer.unsigned_attributes()]
135                        .into_iter()
136                        .flatten()
137                    {
138                        rules.insert(attrs.element().span(), Form::Set, &work)?;
139                    }
140                    for identifier in [
141                        signer.digest_algorithm().identifier(),
142                        signer.signature_algorithm().identifier(),
143                    ]
144                    .into_iter()
145                    .flatten()
146                    {
147                        rules.algorithm(identifier, &work)?;
148                    }
149                    let sid = signer.fields().identity[1];
150                    if sid.tag().class() == Class::ContextSpecific {
151                        rules.insert(sid.span(), Form::Octets, &work)?;
152                    }
153                }
154            }
155        }
156        let mut values = work.vector();
157        values
158            .try_reserve_exact(count)
159            .map_err(|cause| Error::resource(cause, FIELD, record.original.element.span().start))?;
160        for chain in &record.chains[..count] {
161            let parent = chain.original.reader_in(operation)?;
162            values
163                .try_push(Projection::new(&parent, chain.original.element, &rules)?)
164                .map_err(|cause| {
165                    Error::resource(cause, FIELD, chain.original.element.span().start)
166                })?;
167        }
168        Ok(values.into_owned())
169    }
170    /// The selected new chain ordinal; no order is inferred from timestamps.
171    #[must_use]
172    pub fn before_chain(&self) -> usize {
173        self.before
174    }
175    pub(super) fn contains(&self, stamp: &super::ArchiveTimeStamp<'_>) -> bool {
176        core::ptr::eq(
177            stamp,
178            &raw const self.record.timestamps[self.record.chains[self.before].first],
179        )
180    }
181    pub(super) fn hash<'p, P: AsnDigest<'p>, W: Work, SE>(
182        &self,
183        hasher: &Hasher<'p, '_, P, W>,
184    ) -> core::result::Result<P::Output, InputError<SE, P::Error>> {
185        let mut state = hasher.start()?;
186        hasher.update(&mut state, &[0x30])?;
187        hasher.update(&mut state, DerLength::new(self.length).as_bytes())?;
188        for chain in self.projected.values() {
189            chain
190                .feed(&hasher.work, |bytes| hasher.update(&mut state, bytes))
191                .map_err(|cause| match cause {
192                    FeedError::Resource(cause) => hasher.resource(cause),
193                    FeedError::Callback(cause) => cause,
194                })?;
195        }
196        hasher.finish(state)
197    }
198}
199fn prefix_length<W: Work>(values: &[Projection<'_>], work: &W, at: u64) -> Result<u64> {
200    let mut length = 0u64;
201    for value in values {
202        work.charge_work(1)
203            .map_err(|cause| Error::resource(cause, FIELD, at))?;
204        length = length
205            .checked_add(value.len())
206            .ok_or_else(|| Error::schema(ErrorCode::LengthOverflow, FIELD, at))?;
207    }
208    Ok(length)
209}