Skip to main content

structured_pkix/
path.rs

1//! Certification paths: which sequences of certificates lead from a
2//! certificate to an anchor the caller trusts, and what that costs.
3//!
4//! One signature can have several valid paths, and a report shows them,
5//! because a cross-certified provider is recognized under one scheme by one
6//! path and under another by another. That is not the same as enumerating
7//! every path: a certificate set somebody else controls can hold a
8//! combinatorial number of them, and a browser asked for all of them stops
9//! answering. So the search is bounded in every direction it can grow, and
10//! when a bound is reached the answer says so. Silence about truncation
11//! would be a worse answer than the truncation.
12//!
13//! Where the bound is on how many paths are returned, which paths are kept
14//! is not the order they were found in. A second path to the same anchor
15//! naming the same policies tells a reader nothing the first did not; a path
16//! to another anchor, or one naming other policies, is the whole reason
17//! several paths are shown at all. So a path that differs in either is kept
18//! ahead of a repeat of one already held.
19//!
20//! An anchor is an input, never a discovery (RFC 5280 6.1): a self-signed
21//! certificate that happens to sit in the same pool is a certificate like
22//! any other, and a path that ends at one the caller did not name ends
23//! nowhere.
24
25mod error;
26mod name_space;
27mod policy;
28mod validation;
29
30pub use error::{BuildError, BuildResult};
31pub use validation::{
32    ConstraintSource, EffectiveAnchor, NameConstraintFailure, Rejection, RejectionReason,
33    Validation, ValidationBounds, ValidationContext, ValidationFacts, validate, validate_effective,
34};
35
36use crate::algorithm::AlgorithmIdentifier;
37use crate::certificate::{Certificate, Validity};
38use crate::error::Result;
39use crate::extension::Recognizer;
40use crate::key::PublicKeyInfo;
41use crate::name::Name;
42use crate::signature::SignatureValue;
43use structured_asn1::Oid;
44use structured_asn1::memory::{Memory, OwnedMap, OwnedVec, Work};
45
46/// What the caller trusts, as the trust context named it.
47///
48/// A name and a key, because that is what an anchor is: the certificate it
49/// was published in, where there is one, is kept for the report and is not
50/// what makes it an anchor. Two anchors with the same name and different
51/// keys are two anchors, and a path is built to each.
52#[derive(Debug, Clone, Copy)]
53pub struct Anchor<'a> {
54    name: &'a Name<'a>,
55    key: PublicKeyInfo<'a>,
56    certificate: Option<&'a Certificate<'a>>,
57}
58
59impl<'a> Anchor<'a> {
60    /// An anchor the trust context supplies as a name and a key.
61    #[must_use]
62    pub fn new(name: &'a Name<'a>, key: PublicKeyInfo<'a>) -> Self {
63        Self {
64            name,
65            key,
66            certificate: None,
67        }
68    }
69
70    /// An anchor the trust context supplies as a certificate, whose subject
71    /// and key it is. The certificate is not part of any path built to it
72    /// (RFC 5280 6.1), and is kept so a report can name where the anchor
73    /// came from and so that what it says about the names below it is
74    /// obeyed.
75    #[must_use]
76    pub fn from_certificate(certificate: &'a Certificate<'a>) -> Self {
77        Self {
78            name: certificate.tbs().subject(),
79            key: certificate.tbs().public_key(),
80            certificate: Some(certificate),
81        }
82    }
83
84    /// The name a certificate issued under this anchor carries as its issuer.
85    #[must_use]
86    pub fn name(&self) -> &'a Name<'a> {
87        self.name
88    }
89
90    /// The public key information, as encoded, which is what verifies the
91    /// signature of the certificate below it.
92    #[must_use]
93    pub fn key(&self) -> PublicKeyInfo<'a> {
94        self.key
95    }
96
97    /// The certificate the anchor was published in, where the trust context
98    /// had one.
99    #[must_use]
100    pub fn certificate(&self) -> Option<&'a Certificate<'a>> {
101        self.certificate
102    }
103
104    /// Whether two anchors are the same one: the same name and the same key,
105    /// which is what an anchor is.
106    fn same(self, other: Self, execution: &Memory) -> Result<bool> {
107        execution
108            .charge_work(self.key.as_bytes().len().max(other.key.as_bytes().len()) as u64)
109            .map_err(|reason| self.name.resource(reason))?;
110        if self.key.as_bytes() != other.key.as_bytes() {
111            return Ok(false);
112        }
113        self.name.matches(other.name, execution)
114    }
115}
116
117/// What a verifier says about one signature.
118///
119/// The third answer is the one that matters: an algorithm this build cannot
120/// verify is not a signature that passed. Collapsing it into a no would say
121/// the certificate is broken, and into a yes would say it is good; both are
122/// claims nobody made.
123#[derive(Debug, Clone, Copy, PartialEq, Eq)]
124#[non_exhaustive]
125pub enum Verified {
126    /// The signature is the issuer's over these bytes.
127    Yes,
128    /// The signature is not.
129    No,
130    /// This build cannot answer: the algorithm, the key or the parameters
131    /// are outside what it verifies.
132    Unsupported,
133}
134
135/// The key a certificate's signature is checked with, and the parameters
136/// that are in force for it.
137///
138/// "If the public key algorithm parameters are absent, the working public key
139/// parameters are inherited" from the certificate above (RFC 5280 6.1.2 (c)
140/// and 6.1.4 (e)). A key written without them is not a key anything can be
141/// checked with on its own: the curve or the group it belongs to is written
142/// once, in an authority above it, and every key below stands in that same
143/// one. A verifier handed the encoding alone would have to answer that it
144/// cannot say, and a valid path would go unreported.
145///
146/// Where the key carries its own parameters, those are the ones in force and
147/// nothing is inherited. This is the ordinary case: a named curve, an RSA
148/// modulus, an Edwards key.
149#[derive(Debug, Clone, Copy)]
150pub struct WorkingKey<'a> {
151    key: PublicKeyInfo<'a>,
152    /// The authority's written parameters this key stands in, readable where
153    /// they were written, after the transition admitted and established
154    /// algorithm compatibility. Getters never defer an untrusted OID comparison.
155    inherited: Option<crate::algorithm::Nested<'a>>,
156}
157
158impl<'a> WorkingKey<'a> {
159    /// A key that stands on its own, which is what a trust anchor's is: there
160    /// is nothing above it to inherit from.
161    #[must_use]
162    pub fn standing(key: PublicKeyInfo<'a>) -> Self {
163        Self {
164            key,
165            inherited: None,
166        }
167    }
168
169    /// The key itself, as the certificate wrote it.
170    #[must_use]
171    pub fn key(self) -> PublicKeyInfo<'a> {
172        self.key
173    }
174
175    /// The parameters in force: the key's own where it has them, and the ones
176    /// carried down from above where it does not and belongs to the same
177    /// algorithm, subject to its specific key profile. An absent PSS parameter
178    /// field means unrestricted PSS usage and does not inherit restrictions
179    /// (RFC4055 §3.3 case2).
180    ///
181    /// "If the certificate subjectPublicKey algorithm and the
182    /// `working_public_key_algorithm` are different, set the
183    /// `working_public_key_parameters` to null" (RFC 5280 6.1.4 (e)). Nothing
184    /// is carried across a change of algorithm: a curve is not a modulus,
185    /// and an authority on one algorithm certifying a key on another says
186    /// nothing about how that key is written. Handing them over anyway gives
187    /// a verifier a key described by parameters that are not its own, which
188    /// it can only refuse.
189    ///
190    /// The generic RFC5280 transition treats explicit NULL and omitted
191    /// parameters alike. A specific key profile may define absence differently,
192    /// as PSS does. This projection does not validate algorithm-specific syntax:
193    /// the provider also receives the original SPKI and must reject a spelling
194    /// forbidden by its algorithm contract.
195    ///
196    /// `None` means no effective parameters were supplied or inherited. It
197    /// does not itself prove that the key's encoding is valid for its algorithm.
198    #[must_use]
199    pub fn parameters(self) -> Option<&'a [u8]> {
200        self.parameter_source()
201            .map(crate::algorithm::Nested::as_bytes)
202    }
203
204    /// [`Self::parameters`] with their original parser session, offsets and
205    /// depth, which may belong to an authority's certificate.
206    pub(crate) fn parameter_source(self) -> Option<crate::algorithm::Nested<'a>> {
207        if !self.key.algorithm().has_no_parameters() {
208            return self.key.algorithm().parameters_nested();
209        }
210        self.inherited
211    }
212
213    /// Project the subject's effective key using the current parameter state.
214    /// This is only the RFC 5280 §6.1.4(d)–(e) state transition: it does not
215    /// authenticate the certificate, bind issuer names, or establish trust.
216    /// <https://www.rfc-editor.org/rfc/rfc5280#section-6.1.4>
217    ///
218    /// A caller projecting a key from an already validated path starts at its
219    /// anchor and visits the original certificates in issuer-to-subject order.
220    /// Returned SPKI and parameters borrow those sources; no key catalogue,
221    /// copy or repeated signature verification is needed. The current execution
222    /// account pays for each transition and data-dependent OID comparison.
223    ///
224    /// # Panics
225    /// Only if the internal unit-meter invariant is violated: that meter
226    /// always admits local work and cannot produce a truncated transition.
227    pub fn subject<E: Work>(self, certificate: &'a Certificate<'a>, execution: &E) -> Result<Self> {
228        execution
229            .charge_work(1)
230            .map_err(|reason| certificate.tbs().subject().resource(reason))?;
231        // The unit meter never returns local truncation; the same transition
232        // core still enforces the shared execution domain before comparisons.
233        self.below(certificate, execution, &mut ())
234            .map(|key| key.expect("unit meter never truncates parameter projection"))
235    }
236
237    /// The working key one certificate further down: this certificate's own
238    /// key, standing in the parameters in force where it wrote none.
239    ///
240    /// The algorithm those parameters belong to travels with them, since a
241    /// key further down inherits only from a key of its own algorithm.
242    fn below<E: Work>(
243        self,
244        certificate: &'a Certificate<'a>,
245        execution: &E,
246        meter: &mut impl Meter,
247    ) -> Result<Option<Self>> {
248        let key = certificate.tbs().public_key();
249        let mut inherited = None;
250        if key.algorithm().has_no_parameters()
251            && let Some(parameters) = self.parameter_source()
252        {
253            let previous = self.key.algorithm().algorithm().as_bytes();
254            let current = key.algorithm().algorithm().as_bytes();
255            // RFC4055 §§3.1,3.3 case2 overrides generic parameter inheritance
256            // for a PSS SPKI with absent parameters: no key restrictions.
257            // https://www.rfc-editor.org/rfc/rfc4055#section-3.3
258            // NULL is invalid PSS syntax (§3.1), not an inherited-parameter
259            // placeholder. Keep it in the original SPKI and supply no parent
260            // parameters that an adapter could use to repair its spelling.
261            let pss = crate::oid::RSASSA_PSS.as_bytes();
262            if current.len() == pss.len() {
263                let reads = (pss.len() as u64) * 2;
264                if !meter.spend(reads / cost::COMPARED)? {
265                    return Ok(None);
266                }
267                execution
268                    .charge_work(reads)
269                    .map_err(|reason| certificate.tbs().subject().resource(reason))?;
270                if current == pss {
271                    return Ok(Some(Self {
272                        key,
273                        inherited: None,
274                    }));
275                }
276            }
277            if previous.len() == current.len() {
278                if core::ptr::eq(previous, current) {
279                    inherited = Some(parameters);
280                } else {
281                    let reads = (current.len() as u64).checked_mul(2).ok_or_else(|| {
282                        certificate
283                            .tbs()
284                            .subject()
285                            .resource(structured_asn1::memory::MemoryError::WorkExceeded)
286                    })?;
287                    if !meter.spend(reads / cost::COMPARED)? {
288                        return Ok(None);
289                    }
290                    execution
291                        .charge_work(reads)
292                        .map_err(|reason| certificate.tbs().subject().resource(reason))?;
293                    if previous == current {
294                        inherited = Some(parameters);
295                    }
296                }
297            }
298        }
299        Ok(Some(Self { key, inherited }))
300    }
301}
302
303/// Who checks a signature.
304///
305/// Which algorithms may verify what belongs to the algorithm registry rather
306/// than to this crate, so the check is asked for rather than performed here.
307/// A caller that supplies no verifier gets no path: nothing else in a path
308/// binds one certificate to the next.
309pub trait Verify<E: Work = Memory> {
310    /// The original policy, provider or resource failure of this implementation.
311    type Error;
312
313    /// Whether the signature over `signed` is the one the key in `key`
314    /// makes under `algorithm`.
315    ///
316    /// The key arrives with the parameters in force rather than as the
317    /// encoding alone, since a certificate may omit them and stand in the
318    /// ones an authority above it wrote.
319    ///
320    /// A key may also be offered before those are known: while a path is
321    /// being looked for, an authority is asked about with the key exactly as
322    /// its certificate wrote it, because what it stands in is above and
323    /// above has not been reached. An implementation that cannot judge a key
324    /// without parameters it was not given answers `Unsupported` rather than
325    /// `No`. The two are not interchangeable here: `No` prunes the branch,
326    /// and a key that merely could not be judged yet is asked about again
327    /// from the anchor down.
328    ///
329    /// `signature` preserves its original source for selected DER decoders:
330    /// use `signature.reader_in(execution)` with `signature::DssValue::read`.
331    /// Raw algorithms use `signature.octets()` without opening a reader.
332    /// Algorithm permission/capability gates must precede decoding or backend
333    /// work; processing/resource failures must not become `No` or `Unsupported`.
334    fn verify(
335        &self,
336        algorithm: &AlgorithmIdentifier<'_>,
337        key: WorkingKey<'_>,
338        signed: &[u8],
339        signature: SignatureValue<'_>,
340        execution: &E,
341    ) -> core::result::Result<Verified, Self::Error>;
342}
343
344/// Nothing is verified, which is what a caller without a registry has.
345impl<E: Work> Verify<E> for () {
346    type Error = core::convert::Infallible;
347    fn verify(
348        &self,
349        _algorithm: &AlgorithmIdentifier<'_>,
350        _key: WorkingKey<'_>,
351        _signed: &[u8],
352        _signature: SignatureValue<'_>,
353        _execution: &E,
354    ) -> core::result::Result<Verified, Self::Error> {
355        Ok(Verified::Unsupported)
356    }
357}
358
359/// Whether the search has run out of time.
360///
361/// There is no clock here: this crate builds without an operating system, so
362/// wall time is something the caller watches and this asks about. The work
363/// bound below is the one that always applies, and this one narrows it where
364/// the caller can measure.
365pub trait Watch {
366    /// Whether the time the caller allowed has passed.
367    fn out_of_time(&self) -> bool;
368}
369
370/// No clock, so no deadline: the work bound is what stops the search.
371impl Watch for () {
372    fn out_of_time(&self) -> bool {
373        false
374    }
375}
376
377/// What charges work and says whether there is any left.
378///
379/// The search holds the meter, and the planes that work out policies and
380/// names are given it rather than a copy of what it counts: a plane with its
381/// own budget is a second bound the caller never set, and one with none
382/// spends whatever a list somebody else wrote asks for. One trait rather
383/// than the search itself, so those planes do not carry the verifier, the
384/// clock and the recognizer through their signatures to reach the counter.
385pub(crate) trait Meter {
386    /// Charges work, and says whether there is any budget left. Both the
387    /// work bound and the caller's clock are answered here, since running
388    /// out of either stops the same search.
389    fn spend(&mut self, work: u64) -> Result<bool>;
390}
391
392/// No meter, so no bound: for asking a plane what it works out rather than
393/// what it spends, which is what the tests of one plane are about.
394impl Meter for () {
395    fn spend(&mut self, _work: u64) -> Result<bool> {
396        Ok(true)
397    }
398}
399
400/// How far the search may go before it stops and says so.
401///
402/// Every direction a search can grow has a number here, because a
403/// certificate set somebody else controls grows in all of them: deeper
404/// chains, wider fan-out at each step, more paths that differ in one
405/// certificate, more policies in each certificate. The defaults are what a
406/// browser can spend on a document somebody sent, not what a server can
407/// spend on its own inventory.
408#[derive(Debug, Clone, Copy)]
409pub struct Bounds {
410    /// How many certificates a path may hold, the anchor aside.
411    pub depth: usize,
412    /// How many times a certificate may be entered at some depth.
413    pub visited: usize,
414    /// How many candidate issuers may be considered in total.
415    pub edges: usize,
416    /// How much work the checks along the way may cost.
417    pub work: u64,
418    /// How many paths may be returned.
419    pub paths: usize,
420    /// How many graph nodes, retained parent edges and expected policy OIDs
421    /// one path's policy processing may hold together. Scratch capacity is
422    /// additionally admitted by the shared execution account.
423    pub policies: usize,
424}
425
426impl Default for Bounds {
427    fn default() -> Self {
428        Self {
429            depth: 12,
430            visited: 4_096,
431            edges: 16_384,
432            work: 1_000_000,
433            paths: 8,
434            policies: 1_024,
435        }
436    }
437}
438
439/// Which bound stopped the search, where one did.
440///
441/// A report says which, because the answers differ: a search that ran out of
442/// paths has more to show, and a search that ran out of depth was looking in
443/// the wrong place.
444#[derive(Debug, Clone, Copy, PartialEq, Eq)]
445#[non_exhaustive]
446pub enum Truncation {
447    /// A path reached the depth bound and was not followed further.
448    Depth,
449    /// The count of entered certificates reached its bound.
450    Visited,
451    /// The count of considered candidates reached its bound.
452    Edges,
453    /// The checks along the way cost what the caller allowed.
454    Work,
455    /// The caller's clock ran out.
456    Time,
457    /// More paths were found than the caller asked for, and one that was
458    /// found is not among the ones returned.
459    Paths,
460    /// Working out what a path was issued under grew past what the caller
461    /// allowed it to hold, so that path was not settled.
462    Policies,
463}
464
465impl Truncation {
466    /// Whether reaching this bound ends the whole search rather than one
467    /// branch of it.
468    ///
469    /// The counts of work, time, entered certificates and considered
470    /// candidates are spent once for the whole search, so reaching one
471    /// leaves nothing further to look at. Depth, room for paths and the size
472    /// of a policy tree are reached by one branch or one path, and the
473    /// search goes on to the next.
474    fn halts(self) -> bool {
475        matches!(self, Self::Work | Self::Time | Self::Visited | Self::Edges)
476    }
477}
478
479/// One certification path: the certificates from the target up, the anchor
480/// they lead to, and what the authorities along it agreed the target was
481/// issued under.
482#[derive(Debug)]
483pub struct Path<'a> {
484    certificates: OwnedVec<&'a Certificate<'a>>,
485    anchor: Anchor<'a>,
486    policies: OwnedVec<Oid<'a>>,
487}
488
489impl<'a> Path<'a> {
490    /// The certificates, the target first and the one the anchor issued
491    /// last. The anchor's own certificate is not among them.
492    #[must_use]
493    pub fn certificates(&self) -> &[&'a Certificate<'a>] {
494        &self.certificates
495    }
496
497    /// The anchor this path ends at.
498    #[must_use]
499    pub fn anchor(&self) -> Anchor<'a> {
500        self.anchor
501    }
502
503    /// The policies every authority along the path agreed the target was
504    /// issued under, narrowed to the ones the caller asked about.
505    ///
506    /// Empty says the path names no policy the caller asked about, which is
507    /// a path only because nobody along it demanded that it name one.
508    ///
509    /// A set rather than a list, and returned in one order whatever order
510    /// the certificates wrote it in, so that two paths naming one set are
511    /// told apart by walking them once.
512    #[must_use]
513    pub fn policies(&self) -> &[Oid<'a>] {
514        &self.policies
515    }
516
517    /// How many certificates the path holds.
518    #[must_use]
519    pub fn len(&self) -> usize {
520        self.certificates.len()
521    }
522
523    /// Whether the path holds no certificates, which no path this builder
524    /// returns does.
525    #[must_use]
526    pub fn is_empty(&self) -> bool {
527        self.certificates.is_empty()
528    }
529
530    /// Whether two paths say the same thing: the same names carrying the
531    /// same keys, up to the same anchor.
532    ///
533    /// Serial numbers and validity are not part of it, so an authority that
534    /// re-issued its own certificate is one route rather than two. What
535    /// makes a second path worth showing is that it goes somewhere else or
536    /// says something else, and neither of those is a new serial number.
537    fn same_route(
538        &self,
539        chain: &[&'a Certificate<'a>],
540        anchor: Anchor<'a>,
541        execution: &Memory,
542    ) -> Result<bool> {
543        if self.certificates.len() != chain.len() || !self.anchor.same(anchor, execution)? {
544            return Ok(false);
545        }
546        for (ours, theirs) in self.certificates.iter().zip(chain) {
547            execution
548                .charge_work(
549                    ours.tbs()
550                        .public_key()
551                        .as_bytes()
552                        .len()
553                        .max(theirs.tbs().public_key().as_bytes().len()) as u64,
554                )
555                .map_err(|reason| ours.tbs().subject().resource(reason))?;
556            if ours.tbs().public_key().as_bytes() != theirs.tbs().public_key().as_bytes()
557                || !ours
558                    .tbs()
559                    .subject()
560                    .matches(theirs.tbs().subject(), execution)?
561            {
562                return Ok(false);
563            }
564        }
565        Ok(true)
566    }
567
568    /// Whether a path would tell a reader what this one already told them:
569    /// the same anchor, and the same policies. What is worth keeping when
570    /// there is room for fewer paths than were found is one of each of
571    /// these, not the first ones found.
572    /// Both sets arrive in one order, which is what makes this a walk down
573    /// the two rather than a search of one for each member of the other:
574    /// the second is the square of a count the caller's policy ceiling
575    /// allows, and it is repeated against every path being held.
576    fn same_meaning(
577        &self,
578        anchor: Anchor<'a>,
579        policies: &[Oid<'a>],
580        execution: &Memory,
581    ) -> Result<bool> {
582        if !self.anchor.same(anchor, execution)? || self.policies.len() != policies.len() {
583            return Ok(false);
584        }
585        for (ours, theirs) in self.policies.iter().zip(policies) {
586            execution
587                .charge_work(ours.as_bytes().len().max(theirs.as_bytes().len()) as u64)
588                .map_err(|reason| self.anchor.name.resource(reason))?;
589            if ours != theirs {
590                return Ok(false);
591            }
592        }
593        Ok(true)
594    }
595}
596
597/// What the search found, and what it did not get to.
598#[derive(Debug)]
599pub struct Outcome<'a> {
600    paths: OwnedVec<Path<'a>>,
601    truncated: Option<Truncation>,
602}
603
604impl<'a> Outcome<'a> {
605    fn empty(execution: &Memory) -> Self {
606        Self {
607            paths: execution.vector(),
608            truncated: None,
609        }
610    }
611
612    /// The paths, shortest first, and among paths of one length in the order
613    /// the caller's inputs put them in.
614    #[must_use]
615    pub fn paths(&self) -> &[Path<'a>] {
616        &self.paths
617    }
618
619    /// Which bound stopped the search, where one did. `None` says the search
620    /// finished: every path there is, is here.
621    #[must_use]
622    pub fn truncated(&self) -> Option<Truncation> {
623        self.truncated
624    }
625
626    /// Whether the search was stopped rather than finished, which a report
627    /// must say rather than claim it enumerated everything.
628    #[must_use]
629    pub fn is_truncated(&self) -> bool {
630        self.truncated.is_some()
631    }
632}
633
634/// The UTC-label interval the path is built for, retaining leap/fractional labels.
635///
636/// A signature is placed in an interval rather than at an instant, because
637/// what a timestamp proves is an upper bound and the lower one is usually
638/// unknown. A certificate takes part in a path only where it was valid
639/// across the whole of it: resolving at one end would let a signature made
640/// before a certificate existed pass on the strength of a later moment.
641///
642/// Ordinary whole-second constructors remain available. Use the `Instant`
643/// constructors for fractional or inserted-second endpoints; caller-supplied
644/// leap facts authenticate their occurrence separately from this comparison.
645#[derive(Debug, Clone, Copy, PartialEq, Eq)]
646pub struct Interval {
647    from: crate::temporal::Instant,
648    to: crate::temporal::Instant,
649}
650
651impl Interval {
652    /// The interval between two moments, whichever way round the caller
653    /// hands them: an interval is a pair of bounds, not an ordering.
654    #[must_use]
655    pub fn between(first: i64, second: i64) -> Self {
656        Self::between_instants(
657            crate::temporal::Instant::whole(first),
658            crate::temporal::Instant::whole(second),
659        )
660    }
661
662    /// The interval that is one moment, which is what a caller has when the
663    /// signing time is known exactly and nothing wider has to be covered.
664    #[must_use]
665    pub fn at(moment: i64) -> Self {
666        Self::at_instant(crate::temporal::Instant::whole(moment))
667    }
668
669    /// The interval between two lossless labels, in either input order.
670    #[must_use]
671    pub fn between_instants(
672        first: crate::temporal::Instant,
673        second: crate::temporal::Instant,
674    ) -> Self {
675        Self {
676            from: first.min(second),
677            to: first.max(second),
678        }
679    }
680
681    /// A point interval retaining the supplied leap flag and nanoseconds.
682    #[must_use]
683    pub fn at_instant(moment: crate::temporal::Instant) -> Self {
684        Self {
685            from: moment,
686            to: moment,
687        }
688    }
689
690    /// The earlier bound's lossy POSIX projection, without fractional precision.
691    #[must_use]
692    pub fn from(self) -> i64 {
693        self.from.seconds()
694    }
695
696    /// The later bound's lossy POSIX projection, without fractional precision.
697    #[must_use]
698    pub fn to(self) -> i64 {
699        self.to.seconds()
700    }
701
702    /// The earlier lossless UTC label.
703    #[must_use]
704    pub fn from_instant(self) -> crate::temporal::Instant {
705        self.from
706    }
707
708    /// The later lossless UTC label.
709    #[must_use]
710    pub fn to_instant(self) -> crate::temporal::Instant {
711        self.to
712    }
713
714    /// Whether a validity interval holds the whole of this one.
715    fn inside(self, validity: Validity) -> bool {
716        validity.not_before().instant() <= self.from && self.to <= validity.not_after().instant()
717    }
718}
719
720/// What the caller was asking about, before any certificate was read.
721///
722/// The defaults are a validator with no policy of its own: it asks what the
723/// authorities agreed on rather than whether they agreed on one thing, and
724/// reads what the certificates say rather than overriding it. A caller with
725/// a policy of its own says so here, and gets paths that satisfy it or none.
726#[derive(Debug, Clone, Copy)]
727pub struct Policy<'a> {
728    /// The policies the caller is asking about. Empty asks about all of
729    /// them, and a path then carries whatever its authorities agreed on.
730    pub wanted: &'a [Oid<'a>],
731    /// Whether every path must name a policy, rather than only those an
732    /// authority along the way demanded it of.
733    pub explicit: bool,
734    /// Whether a policy one authority maps to another's is honoured.
735    pub mapping: bool,
736    /// Whether the identifier standing for any policy is read as the
737    /// certificate meant it.
738    pub any: bool,
739}
740
741impl Default for Policy<'_> {
742    fn default() -> Self {
743        Self {
744            wanted: &[],
745            explicit: false,
746            mapping: true,
747            any: true,
748        }
749    }
750}
751
752/// What the search charges for the checks it runs, so that a pool somebody
753/// else controls cannot buy an unbounded amount of them. The numbers are
754/// relative to each other rather than to any clock: a signature check is
755/// what a path spends most of its budget on, and a name comparison is a
756/// walk over two names.
757mod cost {
758    /// Reading an extension of a certificate the search is considering.
759    pub(super) const EXTENSION: u64 = 8;
760    /// Reaching for two names to compare them, before what they hold.
761    pub(super) const NAME: u64 = 16;
762    /// How many bytes of the two names one unit of work buys where they are
763    /// compared. Comparing them reads both: the parts of a name holding
764    /// several attributes are ordered against each other, and values that
765    /// are not byte-identical are folded through to the end. What that
766    /// costs is the size of what a pool somebody else wrote put there, so
767    /// it is charged by that size rather than at a flat rate.
768    pub(super) const COMPARED: u64 = 16;
769    /// Asking the verifier about one signature.
770    pub(super) const SIGNATURE: u64 = 1_024;
771    /// Holding one certificate to the constraints above it.
772    pub(super) const CHECK: u64 = 32;
773    /// Looking at one entry of a list a document decides the length of: a
774    /// policy a certificate names, a mapping it declares, a region an
775    /// authority wrote, a node of the working out being indexed.
776    ///
777    /// Charged per entry rather than per list, because the length is what
778    /// somebody else chose. What the entry holds is charged where it is
779    /// read, which for most of these is a lookup in an index and nothing
780    /// more.
781    pub(super) const ENTRY: u64 = 4;
782    /// How many bytes of a certificate one unit of work buys where the whole
783    /// of it is read, which is where its identity is taken.
784    pub(super) const HASHED: u64 = 64;
785}
786
787/// Everything the search asks of the caller: what is trusted, when, how far
788/// to look, what is being asked about, and who answers the questions this
789/// crate does not.
790///
791/// One value rather than a row of arguments, because these travel together:
792/// a path built against other anchors, or for another interval, is another
793/// question rather than the same one asked differently.
794pub struct Context<'a, 'p, V: Verify, W: Watch, R: Recognizer> {
795    /// The current operation's shared execution and storage domain.
796    /// Retained certificate accounts never implicitly finance this search.
797    pub execution: &'p Memory,
798    /// The anchors a path may end at, in the order a report should prefer.
799    pub anchors: &'p [Anchor<'a>],
800    /// The interval the path is built for.
801    pub interval: Interval,
802    /// How far the search may go before it stops and says so.
803    pub bounds: Bounds,
804    /// What the caller is asking about the policies a path was issued under.
805    pub policy: Policy<'a>,
806    /// Who checks a signature.
807    pub verifier: &'p V,
808    /// Who says the time the caller allowed has passed.
809    pub watch: &'p W,
810    /// Which extensions a scheme understands beyond the ones this crate
811    /// reads, since a critical extension nobody understood is a certificate
812    /// no path goes through.
813    pub recognizer: &'p R,
814}
815
816/// The state a search carries, so the bounds are counted in one place.
817struct Search<'a, 'p, V: Verify, W: Watch, R: Recognizer> {
818    execution: &'p Memory,
819    /// The candidates as the caller supplied them, unread until a path
820    /// needs one.
821    supplied: &'p [&'a Certificate<'a>],
822    /// The certificate the question is about, which is not a candidate
823    /// issuer of itself.
824    target: &'a Certificate<'a>,
825    /// The candidates folded to one each, worked out the first time the
826    /// search looks for an issuer.
827    ///
828    /// Not before then: a target an anchor issued is settled by the anchors
829    /// alone, and reading a pool of certificates no path goes through would
830    /// spend the budget that answer needs before the answer is reached. A
831    /// document may carry any number of them, so that is a path a caller
832    /// holds the whole of being reported as left out.
833    pool: Option<OwnedVec<&'a Certificate<'a>>>,
834    anchors: &'p [Anchor<'a>],
835    interval: Interval,
836    bounds: Bounds,
837    policy: Policy<'a>,
838    verifier: &'p V,
839    watch: &'p W,
840    recognizer: &'p R,
841    visited: usize,
842    edges: usize,
843    spent: u64,
844    /// The bound that ended the search, where one did.
845    halted: Option<Truncation>,
846    /// What a bound left out without ending the search.
847    noted: Option<Truncation>,
848    found: OwnedVec<Path<'a>>,
849    /// What the verifier has already said, so that a subpath shared by many
850    /// paths costs one check rather than one per path. Two certificates
851    /// stand for one answer here by where their bytes are, since that is
852    /// what was handed to the verifier; a second copy of one certificate is
853    /// a second entry and not a wrong one.
854    signatures: OwnedMap<(usize, usize, usize), Verified>,
855    /// What each certificate says about itself, which does not depend on
856    /// where in a path it sits. A cross-certified pool reaches the same
857    /// certificate at many depths and on many chains, and reading its
858    /// extensions again each time would charge a caller once per visit for
859    /// an answer that cannot have changed.
860    properties: OwnedMap<usize, Properties<'a>>,
861}
862
863/// What one certificate says about itself, worked out once.
864#[derive(Debug, Clone, Copy)]
865struct Properties<'a> {
866    /// Common facts, or no facts when the local operation could not finish.
867    facts: Option<validation::CertificateFacts<'a>>,
868    /// Whether it can stand in a path at all: valid across the interval, and
869    /// carrying no critical extension nobody understood.
870    usable: bool,
871    /// What it says about issuing certificates, or `None` where it says it
872    /// issues none.
873    issues: Option<crate::constraints::BasicConstraints>,
874    /// Whether it is an anchor's own certificate: it carries the name and
875    /// key of one, and signs itself. Both, because a certificate carrying an
876    /// anchor's identity under somebody else's signature is a link to that
877    /// anchor rather than the anchor.
878    publishes_itself: bool,
879}
880
881impl<V: Verify, W: Watch, R: Recognizer> Meter for Search<'_, '_, V, W, R> {
882    fn spend(&mut self, work: u64) -> Result<bool> {
883        Self::spend(self, work)
884    }
885}
886
887impl<'a, V: Verify, W: Watch, R: Recognizer> validation::Driver<'a, R> for Search<'a, '_, V, W, R> {
888    type VerificationError = V::Error;
889
890    fn verified(
891        &mut self,
892        certificate: &'a Certificate<'a>,
893        key: WorkingKey<'a>,
894    ) -> BuildResult<Option<Verified>, V::Error, R::Error> {
895        Self::verified(self, certificate, key)
896    }
897
898    fn facts(
899        &mut self,
900        certificate: &'a Certificate<'a>,
901        _settings: &validation::Settings<'a, '_, R>,
902    ) -> BuildResult<Option<validation::CertificateFacts<'a>>, V::Error, R::Error> {
903        Ok(properties(self, certificate)?.facts)
904    }
905}
906
907impl<V: Verify, W: Watch, R: Recognizer> Search<'_, '_, V, W, R> {
908    /// Charges work, and says whether the search may go on.
909    fn spend(&mut self, work: u64) -> Result<bool> {
910        debug_assert!(self.spent <= self.bounds.work);
911        if work > self.bounds.work - self.spent {
912            self.stop(Truncation::Work);
913            return Ok(false);
914        }
915        self.execution
916            .charge_work(work)
917            .map_err(|reason| self.target.tbs().subject().resource(reason))?;
918        self.spent += work;
919        if self.watch.out_of_time() {
920            self.stop(Truncation::Time);
921            return Ok(false);
922        }
923        Ok(true)
924    }
925
926    /// Charges for comparing two names, by what comparing them reads.
927    ///
928    /// Before the comparison rather than after it: a bound that is charged
929    /// once the work is done is a bound the last comparison was never held
930    /// to, and a pool of long names is a set of last comparisons.
931    fn spend_names(&mut self, left: &Name<'_>, right: &Name<'_>) -> Result<bool> {
932        validation::spend_names(self, left, right)
933    }
934
935    /// Records which bound stopped the search, keeping the first one: it is
936    /// the one that decided the answer.
937    fn stop(&mut self, at: Truncation) {
938        // Two kinds of bound, kept apart because they are two statements. A
939        // bound that ends the whole search decides the answer and is what
940        // the answer reports; one that ended a branch or left a path out is
941        // worth saying only where nothing ended the search. Keeping one
942        // field for both would let the first branch to run out of depth
943        // swallow the count of certificates that later stopped everything,
944        // and the search would carry on past a bound it had reached while
945        // naming the wrong reason for what it did not do.
946        let recorded = if at.halts() {
947            &mut self.halted
948        } else {
949            &mut self.noted
950        };
951        if recorded.is_none() {
952            *recorded = Some(at);
953        }
954    }
955
956    /// Whether a bound has ended the search.
957    ///
958    /// Running out of room for paths is not one of them: what is worth
959    /// keeping is decided when a path is settled rather than by which was
960    /// found first, so a search that has filled its room keeps looking for
961    /// something better to put in it, under the bounds that remain.
962    fn stopped(&self) -> bool {
963        self.halted.is_some()
964    }
965
966    /// What the answer says about being incomplete: the bound that ended the
967    /// search where one did, and otherwise what was left out along the way.
968    fn truncated(&self) -> Option<Truncation> {
969        self.halted.or(self.noted)
970    }
971
972    /// Asks the verifier about one signature, or repeats what it said about
973    /// the same one before. `None` says the budget ran out before it could
974    /// be asked, which is not an answer about the signature.
975    ///
976    /// The charge is here rather than at the call sites, and only where the
977    /// verifier is actually reached. Repeating what is already known costs a
978    /// lookup, and charging a cryptographic check for it would undo what
979    /// remembering the answer was for: a sub-path shared by many chains
980    /// would spend the budget once per chain that walks it, and the search
981    /// would stop before reaching paths it had already done the work for.
982    fn verified(
983        &mut self,
984        certificate: &Certificate<'_>,
985        key: WorkingKey<'_>,
986    ) -> BuildResult<Option<Verified>, V::Error, R::Error> {
987        // The parameters are part of what was asked, not only the key: one
988        // key standing in two different sets of inherited parameters is two
989        // questions, and answering the second from the first would carry an
990        // answer across paths that do not share what the key stands in.
991        let at = (
992            certificate.signed_bytes().as_ptr() as usize,
993            key.key().as_bytes().as_ptr() as usize,
994            key.parameters().map_or(0, |held| held.as_ptr() as usize),
995        );
996        if let Some(answer) = self
997            .signatures
998            .get(&at, self.execution)
999            .map_err(|reason| certificate.tbs().subject().resource(reason))?
1000        {
1001            return Ok(Some(*answer));
1002        }
1003        if !self.spend(cost::SIGNATURE)? {
1004            return Ok(None);
1005        }
1006        // Admit the cache allocation before invoking the external verifier.
1007        self.signatures
1008            .try_insert(at, Verified::Unsupported)
1009            .map_err(|reason| certificate.tbs().subject().resource(reason))?;
1010        let answer = self
1011            .verifier
1012            .verify(
1013                &certificate.signature_algorithm(),
1014                key,
1015                certificate.signed_bytes(),
1016                certificate.signature_value(),
1017                self.execution,
1018            )
1019            .map_err(BuildError::Verification)?;
1020        *self
1021            .signatures
1022            .get_mut(&at, self.execution)
1023            .map_err(|reason| certificate.tbs().subject().resource(reason))?
1024            .expect("the admitted signature cache entry") = answer;
1025        Ok(Some(answer))
1026    }
1027}
1028
1029/// Admits anchor-folding work before mutation in both local and aggregate budgets.
1030fn spend_anchor(
1031    context: &Context<'_, '_, impl Verify, impl Watch, impl Recognizer>,
1032    spent: &mut u64,
1033    halted: &mut Option<Truncation>,
1034    origin: &Name<'_>,
1035    work: u64,
1036) -> Result<bool> {
1037    debug_assert!(*spent <= context.bounds.work);
1038    if work > context.bounds.work - *spent {
1039        *halted = Some(Truncation::Work);
1040        return Ok(false);
1041    }
1042    if context.watch.out_of_time() {
1043        *halted = Some(Truncation::Time);
1044        return Ok(false);
1045    }
1046    context
1047        .execution
1048        .charge_work(work)
1049        .map_err(|reason| origin.resource(reason))?;
1050    *spent += work;
1051    Ok(true)
1052}
1053
1054/// The anchors a search will look at, with the repeats among the caller's
1055/// folded away, and what folding them spent.
1056///
1057/// Two anchors of one name and one key are one anchor, and the paths to them
1058/// are one path. A trust context assembled from several stores hands the same
1059/// root over more than once, and every copy would buy an edge and a name
1060/// comparison to settle a path that was already settled, so a bound would
1061/// report the answer as truncated over nothing that was left out.
1062///
1063/// Folded by what makes two anchors one, which is the same name and the same
1064/// key however the name was written, and the same certificate or none behind
1065/// both. Folding by the bytes of the name instead would leave one key under
1066/// two spellings as two anchors, and placed in front of a key that does
1067/// verify they can spend a tight bound before it is reached: the path that
1068/// exists is then not returned, which is a lost answer rather than a charge.
1069///
1070/// The keys are grouped first, because they are compared as bytes and a trust
1071/// store's are all different: an anchor is looked at once, and the comparison
1072/// that reads two names runs only where a key was supplied twice, which is
1073/// the case being folded. Comparing every pair would be the square of a count
1074/// for the sake of the pairs that cannot match.
1075fn fold_anchors<'a>(
1076    context: &Context<'a, '_, impl Verify, impl Watch, impl Recognizer>,
1077    spent: &mut u64,
1078    halted: &mut Option<Truncation>,
1079) -> Result<OwnedVec<Anchor<'a>>> {
1080    let mut keyed: OwnedMap<&[u8], OwnedVec<usize>> = context.execution.map();
1081    let mut anchors: OwnedVec<Anchor<'a>> = context.execution.vector();
1082    'anchors: for anchor in context.anchors {
1083        let key = anchor.key().as_bytes();
1084        if !spend_anchor(
1085            context,
1086            spent,
1087            halted,
1088            anchor.name(),
1089            cost::CHECK + key.len() as u64 / cost::HASHED,
1090        )? {
1091            break;
1092        }
1093
1094        let fail = |reason| anchor.name().resource(reason);
1095        if keyed.get(&key, context.execution).map_err(fail)?.is_none() {
1096            keyed
1097                .try_insert(key, context.execution.vector())
1098                .map_err(fail)?;
1099        }
1100        let group = keyed
1101            .get_mut(&key, context.execution)
1102            .map_err(fail)?
1103            .expect("the group was inserted before lookup");
1104        for at in group.iter() {
1105            let theirs: &Name<'_> = anchors[*at].name();
1106            let bytes = (theirs.as_bytes().len() as u64)
1107                .checked_add(anchor.name().as_bytes().len() as u64)
1108                .ok_or_else(|| {
1109                    anchor
1110                        .name()
1111                        .resource(structured_asn1::memory::MemoryError::WorkExceeded)
1112                })?;
1113            if !spend_anchor(
1114                context,
1115                spent,
1116                halted,
1117                anchor.name(),
1118                cost::NAME + bytes / cost::COMPARED,
1119            )? {
1120                break 'anchors;
1121            }
1122            if !theirs.matches(anchor.name(), context.execution)? {
1123                continue;
1124            }
1125
1126            // The names and the key agree, and one thing is left that tells
1127            // two such anchors apart: what each was published in. A trust
1128            // context that supplied the anchor as a constrained certificate
1129            // bound the names below it, and the same name and key supplied
1130            // without one bound nothing. They are two statements about one
1131            // key, and folding them would let the order of the caller's list
1132            // decide which constraint holds and so whether a path exists at
1133            // all.
1134            let held = anchors[*at].certificate();
1135            let bytes = published_bytes(held)
1136                .checked_add(published_bytes(anchor.certificate()))
1137                .ok_or_else(|| {
1138                    anchor
1139                        .name()
1140                        .resource(structured_asn1::memory::MemoryError::WorkExceeded)
1141                })?;
1142            if !spend_anchor(
1143                context,
1144                spent,
1145                halted,
1146                anchor.name(),
1147                cost::CHECK + bytes / cost::HASHED,
1148            )? {
1149                break 'anchors;
1150            }
1151            if published_alike(held, anchor.certificate(), context.execution)? {
1152                continue 'anchors;
1153            }
1154        }
1155        group.try_push(anchors.len()).map_err(fail)?;
1156        anchors.try_push(*anchor).map_err(fail)?;
1157    }
1158    Ok(anchors)
1159}
1160
1161/// The candidates of a pool, each of them once and the target not among
1162/// them.
1163///
1164/// A pool that holds one certificate twice holds one certificate, and folding
1165/// the copies before the search rather than at each step is what makes that
1166/// true of what the search spends as well as of what it finds. A pool
1167/// somebody else wrote may repeat a certificate leading nowhere as often as
1168/// it likes, and charging every copy would let the copies spend the search
1169/// before the issuer that does lead somewhere is reached.
1170///
1171/// The folding is itself charged, because it is itself work somebody else
1172/// decides the size of: the identity of a certificate is its bytes, and there
1173/// may be any number of certificates of any length.
1174fn fold_pool<'a, V: Verify, W: Watch, R: Recognizer>(
1175    search: &mut Search<'a, '_, V, W, R>,
1176    pool: &[&'a Certificate<'a>],
1177    target: &'a Certificate<'a>,
1178) -> BuildResult<OwnedVec<&'a Certificate<'a>>, V::Error, R::Error> {
1179    let mut named: OwnedMap<usize, ()> = search.execution.map();
1180    let mut seen: OwnedMap<&[u8], ()> = search.execution.map();
1181    let mut unique = search.execution.vector();
1182    for candidate in pool {
1183        let bytes = candidate.as_bytes();
1184
1185        // Looking at a candidate at all, which every one of them costs.
1186        if !search.spend(cost::CHECK)? {
1187            break;
1188        }
1189
1190        // A pool that names one certificate over and over names it once,
1191        // and recognising that costs a pointer. Reading the whole encoding
1192        // is what telling a separately written copy from it costs, and
1193        // charging that for every repeat lets the repeats spend the search
1194        // before the issuer that does lead somewhere is reached.
1195        if named
1196            .try_insert(bytes.as_ptr() as usize, ())
1197            .map_err(|reason| candidate.tbs().subject().resource(reason))?
1198            .is_some()
1199        {
1200            continue;
1201        }
1202        if !search.spend(bytes.len() as u64 / cost::HASHED)? {
1203            break;
1204        }
1205
1206        // The target is not a candidate issuer of itself, and a caller who
1207        // put it here was told that changes nothing. Leaving it among the
1208        // candidates makes that false of what the search spends: the cycle
1209        // check refuses it, but only after an edge and a name comparison
1210        // have been charged for it, so a bound tight enough to notice
1211        // reports the answer as truncated over a certificate that could
1212        // never have been followed.
1213        search
1214            .execution
1215            .charge_work(bytes.len().max(target.as_bytes().len()) as u64)
1216            .map_err(|reason| candidate.tbs().subject().resource(reason))?;
1217        if bytes != target.as_bytes()
1218            && seen
1219                .try_insert(bytes, ())
1220                .map_err(|reason| candidate.tbs().subject().resource(reason))?
1221                .is_none()
1222        {
1223            unique
1224                .try_push(*candidate)
1225                .map_err(|reason| candidate.tbs().subject().resource(reason))?;
1226        }
1227    }
1228    Ok(unique)
1229}
1230
1231/// Builds the paths from one certificate to the anchors the caller trusts.
1232///
1233/// The pool is where issuers are looked for, and holding the target itself
1234/// changes nothing: a certificate never appears twice in one path
1235/// (RFC 5280 6.1), so it cannot be its own issuer.
1236///
1237/// # Errors
1238///
1239/// A spent budget, which says this run gave up rather than that the
1240/// certificates are wrong.
1241pub fn build<'a, V: Verify, W: Watch, R: Recognizer>(
1242    target: &'a Certificate<'a>,
1243    pool: &[&'a Certificate<'a>],
1244    context: &Context<'a, '_, V, W, R>,
1245) -> BuildResult<Outcome<'a>, V::Error, R::Error> {
1246    // A path ends at an anchor, so a caller who named none has asked a
1247    // question whose complete answer is no paths. Reading the pool to find
1248    // that out spends a budget on work that cannot change the answer, and a
1249    // bound reached while doing it would report the one conclusive answer
1250    // there is as though something had been left out, which reads to a
1251    // caller as worth asking again.
1252    if context.anchors.is_empty() {
1253        return Ok(Outcome::empty(context.execution));
1254    }
1255
1256    // And a path is built for a moment. A target the caller's interval does
1257    // not hold is not one any path can end at, whatever the anchors and the
1258    // pool say, so folding them to find that out is the same spending on an
1259    // answer that cannot change. The question is asked again where every
1260    // certificate of a path is held to it, and asking it here first is what
1261    // keeps a bound from calling this conclusive answer a partial one.
1262    if !context.interval.inside(target.tbs().validity()) {
1263        return Ok(Outcome::empty(context.execution));
1264    }
1265
1266    let mut spent = 0u64;
1267    let mut halted = None;
1268    let anchors = fold_anchors(context, &mut spent, &mut halted)?;
1269    if halted.is_some() {
1270        return Ok(Outcome {
1271            paths: context.execution.vector(),
1272            truncated: halted,
1273        });
1274    }
1275
1276    let mut search = Search {
1277        execution: context.execution,
1278        supplied: pool,
1279        target,
1280        pool: None,
1281        anchors: &anchors,
1282        interval: context.interval,
1283        bounds: context.bounds,
1284        policy: context.policy,
1285        verifier: context.verifier,
1286        watch: context.watch,
1287        recognizer: context.recognizer,
1288        visited: 0,
1289        edges: 0,
1290        spent,
1291        halted,
1292        noted: None,
1293        found: context.execution.vector(),
1294        signatures: context.execution.map(),
1295        properties: context.execution.map(),
1296    };
1297
1298    // The certificate an anchor was published in is not a step on a path to
1299    // that anchor: "when the trust anchor is provided in the form of a
1300    // self-signed certificate, this self-signed certificate is not included
1301    // as part of the prospective certification path" (RFC 5280 6.1). That
1302    // holds of the first position as much as of the rest, and the rest
1303    // already keep it. Settling such a target reports the anchor as issued
1304    // by itself, which is the anchor named twice rather than a chain of
1305    // authority, and it is what a caller asking about a root would read as
1306    // the root having been certified by somebody.
1307    //
1308    // A self-signed certificate can chain nowhere else, since the only name
1309    // that issued it is its own, so there is nothing further to look for
1310    // and the empty answer is the whole of it.
1311    let known = properties(&mut search, target)?;
1312    let mut chain = context.execution.vector();
1313    if known.usable && !known.publishes_itself {
1314        walk(&mut search, target, &mut chain)?;
1315    }
1316
1317    // Shortest first: a longer path to the same place says the same thing
1318    // through more parties, and a reader reads the first one. Among paths
1319    // of one length the order is the one the caller's inputs put them in,
1320    // which is what makes the same inputs give the same answer twice.
1321    // Include the discovery position in the comparison so the allocation-free
1322    // heap sort preserves the documented order among equal-length paths.
1323    let mut ordered = context.execution.vector();
1324    let found = core::mem::replace(&mut search.found, context.execution.vector());
1325    for (position, path) in found.into_iter().enumerate() {
1326        ordered
1327            .try_push((position, path))
1328            .map_err(|reason| target.tbs().subject().resource(reason))?;
1329    }
1330    ordered
1331        .try_sort_unstable_by(|left, right| {
1332            Ok::<_, structured_asn1::memory::MemoryError>(
1333                (left.1.len(), left.0).cmp(&(right.1.len(), right.0)),
1334            )
1335        })
1336        .map_err(|error| target.tbs().subject().resource(error.into()))?;
1337    for (_, path) in ordered {
1338        search
1339            .found
1340            .try_push(path)
1341            .map_err(|reason| target.tbs().subject().resource(reason))?;
1342    }
1343    let truncated = search.truncated();
1344    Ok(Outcome {
1345        paths: search.found,
1346        truncated,
1347    })
1348}
1349
1350/// Follows one certificate up: to every anchor that could have issued it,
1351/// and to every certificate in the pool that could have.
1352fn walk<'a, V: Verify, W: Watch, R: Recognizer>(
1353    search: &mut Search<'a, '_, V, W, R>,
1354    certificate: &'a Certificate<'a>,
1355    chain: &mut OwnedVec<&'a Certificate<'a>>,
1356) -> BuildResult<(), V::Error, R::Error> {
1357    // One candidate cursor per active certificate replaces recursive DFS.
1358    // Both stacks are admitted by the request domain before their growth.
1359    let mut cursors = search.execution.vector();
1360    let mut entering = certificate;
1361    'enter: loop {
1362        if search.stopped() {
1363            break;
1364        }
1365        if search.visited >= search.bounds.visited {
1366            search.stop(Truncation::Visited);
1367            break;
1368        }
1369        search.visited += 1;
1370        if !search.spend(cost::CHECK)? {
1371            break;
1372        }
1373        if chain.len() >= search.bounds.depth {
1374            search.stop(Truncation::Depth);
1375            break;
1376        }
1377        chain
1378            .try_push(entering)
1379            .map_err(|reason| entering.tbs().subject().resource(reason))?;
1380        cursors
1381            .try_push(0usize)
1382            .map_err(|reason| entering.tbs().subject().resource(reason))?;
1383        settle(search, entering, chain)?;
1384
1385        loop {
1386            if search.stopped() {
1387                break 'enter;
1388            }
1389            let current = *chain.last().expect("the active DFS certificate");
1390            let cursor = cursors.last_mut().expect("its candidate cursor");
1391            if let Some(candidate) = next_issuer(
1392                search,
1393                current,
1394                chain,
1395                chain.len() >= search.bounds.depth,
1396                cursor,
1397            )? {
1398                entering = candidate;
1399                continue 'enter;
1400            }
1401            chain.pop();
1402            cursors.pop();
1403            if chain.is_empty() {
1404                break 'enter;
1405            }
1406        }
1407    }
1408    chain.clear();
1409    Ok(())
1410}
1411
1412/// Ends the chain at every anchor that issued the certificate on top of it,
1413/// which is where a path becomes one.
1414fn settle<'a, V: Verify, W: Watch, R: Recognizer>(
1415    search: &mut Search<'a, '_, V, W, R>,
1416    certificate: &'a Certificate<'a>,
1417    chain: &[&'a Certificate<'a>],
1418) -> BuildResult<(), V::Error, R::Error> {
1419    for at in 0..search.anchors.len() {
1420        let anchor = search.anchors[at];
1421        if search.stopped() {
1422            break;
1423        }
1424        if search.edges >= search.bounds.edges {
1425            search.stop(Truncation::Edges);
1426            break;
1427        }
1428        search.edges += 1;
1429        if !search.spend_names(certificate.tbs().issuer(), anchor.name())? {
1430            break;
1431        }
1432        if !certificate
1433            .tbs()
1434            .issuer()
1435            .matches(anchor.name(), search.execution)?
1436        {
1437            continue;
1438        }
1439        // The signature is checked where the path is walked from the anchor
1440        // down, since that is where the parameters a key may stand in are
1441        // known. Nothing is lost by not asking here: this is the last edge
1442        // of the path, so the check is one step away either way.
1443        let Some(policies) = validate_candidate(search, chain, anchor)? else {
1444            continue;
1445        };
1446        keep(search, chain, anchor, policies)?;
1447    }
1448    Ok(())
1449}
1450
1451/// Puts a settled path among the ones that will be returned, where there is
1452/// room for it or where what it says is not already there.
1453///
1454/// A repeat of a route already held is dropped and is not truncation: it is
1455/// the same path spelled through a re-issued certificate, and nothing was
1456/// lost by not showing it twice. Dropping a path that does say something
1457/// else is truncation, and so is making room for one by putting out a
1458/// repeat of something already shown.
1459/// The chain is held rather than copied until there is somewhere to put it:
1460/// a cross-certified pool settles the same route many times over, and a copy
1461/// made before the question is asked is a copy made for every one of them.
1462fn keep<'a, V: Verify, W: Watch, R: Recognizer>(
1463    search: &mut Search<'a, '_, V, W, R>,
1464    chain: &[&'a Certificate<'a>],
1465    anchor: Anchor<'a>,
1466    policies: OwnedVec<Oid<'a>>,
1467) -> BuildResult<(), V::Error, R::Error> {
1468    // Telling this path from the ones already held reads their names, the
1469    // keys under them and their policies again, once per path held, and how
1470    // long a name or a key encoding is is the pool's to decide. Both are
1471    // read from the front, so two of one length that part near the end are
1472    // read almost to the end. The charge is taken for the whole scan before
1473    // it runs.
1474    //
1475    // Obeyed where there is anything to compare against: a charge that the
1476    // budget cannot meet is the answer that this scan is not going to
1477    // happen, and running it anyway is the reading the charge exists to
1478    // stop. What is then not known is whether this route says what a held
1479    // one already says, so it is not shown, and the answer is marked
1480    // truncated by the charge that failed.
1481    //
1482    // Where nothing is held there is nothing to compare and no scan to
1483    // refuse. The first path a search settles is kept whatever the budget
1484    // says, since dropping it would lose an answer for work nobody was
1485    // going to do.
1486    let held = search.found.len() as u64;
1487    if held > 0 {
1488        if !search.spend(chain.len() as u64)? {
1489            return Ok(());
1490        }
1491        let overflow = || {
1492            anchor
1493                .name
1494                .resource(structured_asn1::memory::MemoryError::WorkExceeded)
1495        };
1496        let mut read = 0u64;
1497        for certificate in chain {
1498            let tbs = certificate.tbs();
1499            let bytes =
1500                tbs.subject().as_bytes().len() as u64 + tbs.public_key().as_bytes().len() as u64;
1501            read = read.checked_add(bytes).ok_or_else(overflow)?;
1502        }
1503        let each = (read / cost::COMPARED)
1504            .checked_add(cost::NAME)
1505            .and_then(|work| work.checked_add(policies.len() as u64))
1506            .ok_or_else(overflow)?;
1507        let work = each.checked_mul(held).ok_or_else(overflow)?;
1508        if !search.spend(work)? {
1509            return Ok(());
1510        }
1511    }
1512
1513    // The same route saying the same thing. A re-issued certificate is one
1514    // route spelled twice, but an authority that re-issued under another
1515    // policy said something else through it, and that is precisely the
1516    // distinct outcome several paths exist to preserve: dropping it as a
1517    // repeat would throw away the answer while reporting nothing missing.
1518    for held in &search.found {
1519        if held.same_route(chain, anchor, search.execution)?
1520            && held.same_meaning(anchor, &policies, search.execution)?
1521        {
1522            return Ok(());
1523        }
1524    }
1525    if search.found.len() < search.bounds.paths {
1526        let mut certificates = search.execution.vector();
1527        certificates
1528            .try_extend_from_slice(chain)
1529            .map_err(|reason| anchor.name.resource(reason))?;
1530        search
1531            .found
1532            .try_push(Path {
1533                certificates,
1534                anchor,
1535                policies,
1536            })
1537            .map_err(|reason| anchor.name.resource(reason))?;
1538        return Ok(());
1539    }
1540
1541    // No room. A path saying something none of the held ones say is worth
1542    // more than a second path saying what one of them already said, so it
1543    // takes the place of the last such repeat. Either way a path that was
1544    // found is not being returned, which the answer has to say.
1545    search.stop(Truncation::Paths);
1546    for held in &search.found {
1547        if held.same_meaning(anchor, &policies, search.execution)? {
1548            return Ok(());
1549        }
1550    }
1551    let mut repeat = None;
1552    for at in (0..search.found.len()).rev() {
1553        let candidate = &search.found[at];
1554        let mut count = 0;
1555        for held in &search.found {
1556            if held.same_meaning(candidate.anchor, &candidate.policies, search.execution)? {
1557                count += 1;
1558                if count > 1 {
1559                    break;
1560                }
1561            }
1562        }
1563        if count > 1 {
1564            repeat = Some(at);
1565            break;
1566        }
1567    }
1568    if let Some(at) = repeat {
1569        // The repeat is taken out and the new path put on the end, rather
1570        // than dropped into the slot the repeat held. Paths of one length
1571        // come back in the order the caller's inputs put them in, and the
1572        // sort that arranges them is by length alone: a path written into
1573        // an earlier slot would sit in front of paths found before it, and
1574        // nothing afterwards would move it back.
1575        let moves = core::mem::size_of_val(&search.found[at..]);
1576        search
1577            .execution
1578            .charge_work(moves as u64)
1579            .map_err(|reason| anchor.name.resource(reason))?;
1580        search.found[at..].rotate_left(1);
1581        search.found.pop();
1582        let mut certificates = search.execution.vector();
1583        certificates
1584            .try_extend_from_slice(chain)
1585            .map_err(|reason| anchor.name.resource(reason))?;
1586        search
1587            .found
1588            .try_push(Path {
1589                certificates,
1590                anchor,
1591                policies,
1592            })
1593            .map_err(|reason| anchor.name.resource(reason))?;
1594    }
1595    Ok(())
1596}
1597
1598/// Follows the chain further up: to every certificate in the pool that could
1599/// have issued the one on top of it.
1600///
1601/// `deepest` says the chain has reached the length the caller allowed, so
1602/// that a candidate found here is one the depth bound refuses to step into
1603/// rather than one to walk. It is what turns the bound into a report: the
1604/// answer says it was reached where a candidate was there to be refused,
1605/// and says nothing where the chain had nowhere to go regardless.
1606fn next_issuer<'a, V: Verify, W: Watch, R: Recognizer>(
1607    search: &mut Search<'a, '_, V, W, R>,
1608    certificate: &'a Certificate<'a>,
1609    chain: &[&'a Certificate<'a>],
1610    deepest: bool,
1611    at: &mut usize,
1612) -> BuildResult<Option<&'a Certificate<'a>>, V::Error, R::Error> {
1613    // The candidates, folded the first time one is looked for. Every later
1614    // position reads the same folded list.
1615    if search.pool.is_none() {
1616        let supplied = search.supplied;
1617        let target = search.target;
1618        search.pool = Some(fold_pool(search, supplied, target)?);
1619    }
1620    // By position rather than by iterator: what follows this borrows the
1621    // search to walk further up, and a candidate is one shared reference,
1622    // so reading it out ends the borrow the loop would otherwise hold.
1623    while let Some(candidate) = search.pool.as_ref().and_then(|pool| pool.get(*at)).copied() {
1624        *at += 1;
1625        if search.stopped() {
1626            break;
1627        }
1628        if search.edges >= search.bounds.edges {
1629            search.stop(Truncation::Edges);
1630            break;
1631        }
1632        search.edges += 1;
1633        if !search.spend_names(certificate.tbs().issuer(), candidate.tbs().subject())? {
1634            break;
1635        }
1636        // A certificate appears once in a path (RFC 5280 6.1), which is
1637        // also what keeps a cycle from being followed round.
1638        //
1639        // Asked of where the certificate is rather than of what it holds.
1640        // The pool was folded before the search so that no two candidates
1641        // carry the same bytes, and the target was taken out of it, so two
1642        // certificates of one chain hold the same bytes exactly when they
1643        // are the same one. Comparing the encodings would read both from
1644        // end to end for an answer their addresses already give, and a pool
1645        // of long re-issued certificates that part only near the end makes
1646        // that a full scan per candidate per position of the chain, where
1647        // the charge just taken covers two names. It is the identity the
1648        // rest of the search already works by: what a certificate says
1649        // about itself is remembered under the same address.
1650        let mut repeated = false;
1651        for held in chain {
1652            search
1653                .execution
1654                .charge_work(1)
1655                .map_err(|reason| certificate.tbs().subject().resource(reason))?;
1656            if core::ptr::eq(held.as_bytes(), candidate.as_bytes()) {
1657                repeated = true;
1658                break;
1659            }
1660        }
1661        if repeated {
1662            continue;
1663        }
1664        if !certificate
1665            .tbs()
1666            .issuer()
1667            .matches(candidate.tbs().subject(), search.execution)?
1668        {
1669            continue;
1670        }
1671        // Everything cheap first, and the signature last: a candidate that
1672        // could not have issued anything, or was not valid when it would
1673        // have had to be, is refused for what it says rather than for what
1674        // its key does, and the check that costs the most is the one a
1675        // hostile pool would most like to buy in quantity.
1676        //
1677        // The certificate an anchor was published in is not a link in a path
1678        // to that anchor: "when the trust anchor is provided in the form of
1679        // a self-signed certificate, this self-signed certificate is not
1680        // included as part of the prospective certification path"
1681        // (RFC 5280 6.1). Walking into it would produce the path that was
1682        // already found, spelled one certificate longer.
1683        //
1684        // Self-signed is the whole of that rule, and names are not enough to
1685        // establish it. A provider recognized under two schemes has its
1686        // identity certified by both, and an authority rolling its key over
1687        // certifies the new key with the old one: the first carries the
1688        // anchor's name and key under somebody else's signature, the second
1689        // carries one name on both sides under the old key's. Both are
1690        // ordinary links, and skipping either would lose a whole route while
1691        // saying nothing about having lost it.
1692        let known = properties(search, candidate)?;
1693        if known.publishes_itself || !known.usable || known.issues.is_none() {
1694            continue;
1695        }
1696        if deepest {
1697            // A candidate that names itself the issuer and can issue is a
1698            // branch the depth bound is refusing, and refusing it is what
1699            // the answer has to say. Whether its signature would have held
1700            // is exactly what the search does not get to find out, so the
1701            // check is not spent on a candidate it will not follow. Once
1702            // one is refused the rest say the same thing, and the search
1703            // has other branches to spend its budget on.
1704            search.stop(Truncation::Depth);
1705            break;
1706        }
1707        // The key is asked about here, where the answer prunes the branch: a
1708        // candidate that did not sign this certificate is not walked into,
1709        // and a pool of such candidates costs one check each rather than a
1710        // subtree each.
1711        //
1712        // It is asked as the certificate wrote it, since what a key standing
1713        // in parameters written above stands in is exactly what this search
1714        // has not found yet. So only a definite no prunes. A registry that
1715        // cannot judge a key on those terms says that it cannot rather than
1716        // saying no, and the branch is walked so the question can be put
1717        // again from the anchor down, where the parameters in force are
1718        // known. Refusing on anything short of a no would lose whole routes.
1719        //
1720        // Asking only where the key carries its own parameters would prune
1721        // almost nothing: an algorithm that takes none writes a null, which
1722        // is written the same way as omitting them, so a pool of ordinary
1723        // wrong-key authorities would be walked in full and could spend the
1724        // whole budget before the one that signed this certificate is
1725        // reached. What tells the two apart is the registry's answer, and
1726        // the registry is who this asks.
1727        let key = WorkingKey::standing(candidate.tbs().public_key());
1728        let Some(answer) = search.verified(certificate, key)? else {
1729            break;
1730        };
1731        if answer == Verified::No {
1732            continue;
1733        }
1734        return Ok(Some(candidate));
1735    }
1736    Ok(None)
1737}
1738
1739/// Whether two anchors were published the same way: in the same certificate,
1740/// or in none. It is the last thing that tells apart two anchors of one name
1741/// and one key, because the certificate an anchor was published in is what
1742/// says how the names below it are constrained.
1743fn published_alike(
1744    left: Option<&Certificate<'_>>,
1745    right: Option<&Certificate<'_>>,
1746    execution: &Memory,
1747) -> Result<bool> {
1748    match (left, right) {
1749        (None, None) => Ok(true),
1750        (Some(ours), Some(theirs)) => binds_alike(ours, theirs, execution),
1751        _ => Ok(false),
1752    }
1753}
1754
1755/// Whether two certificates of one name and one key say the same thing about
1756/// the names below them.
1757///
1758/// By what is read rather than by every byte. An anchor's certificate is not
1759/// a link in any path: the one thing the search takes from it is what it
1760/// says about the space below, which is the regions it names, and nothing
1761/// else about it is consulted anywhere. A trust store holding a root
1762/// re-issued with a new serial, a new validity or a new signature holds one
1763/// statement of trust written twice, and keeping both makes the search try
1764/// each of them at every position where an anchor could end a path: a tight
1765/// bound on edges is then spent on copies, and a path through the one that
1766/// matches is lost.
1767///
1768/// The one extension compared is therefore the one enforced. Basic
1769/// constraints were compared here while an anchor's regions were honoured
1770/// only under an asserted authority bit; they are not read of an anchor any
1771/// more, and comparing them would split anchors that behave identically.
1772fn binds_alike(
1773    ours: &Certificate<'_>,
1774    theirs: &Certificate<'_>,
1775    execution: &Memory,
1776) -> Result<bool> {
1777    if same(ours, theirs) {
1778        return Ok(true);
1779    }
1780    let ours = ours
1781        .tbs()
1782        .extensions()
1783        .get(crate::oid::NAME_CONSTRAINTS, execution)?;
1784    let theirs = theirs
1785        .tbs()
1786        .extensions()
1787        .get(crate::oid::NAME_CONSTRAINTS, execution)?;
1788    Ok(match (ours, theirs) {
1789        (None, None) => true,
1790        (Some(ours), Some(theirs)) => {
1791            ours.is_critical() == theirs.is_critical() && ours.value() == theirs.value()
1792        }
1793        _ => false,
1794    })
1795}
1796
1797/// How many times comparing a name may read it.
1798///
1799/// Once, where every part holds one attribute: the parts line up in the
1800/// order they were written and each pair is compared where it stands. A part
1801/// holding several is a set, whose order carries no meaning, so both sides
1802/// are put in order before they are lined up, and a sort of `n` reads its
1803/// input about `log2(n)` times over. The widest part decides it, since one
1804/// wide part is enough to pay for.
1805///
1806/// A document decides how many attributes a part holds, so this factor is
1807/// theirs to choose too: without it a name of one very wide part is charged
1808/// as though it were read straight through, and the sort runs to the end
1809/// with nothing left to stop it.
1810fn sorting_rounds(name: &Name<'_>) -> u64 {
1811    let widest = name
1812        .parts()
1813        .iter()
1814        .map(|part| part.attributes().len())
1815        .max()
1816        .unwrap_or(1)
1817        .max(1);
1818    u64::from(widest.ilog2()) + 1
1819}
1820
1821/// How many bytes comparing an anchor's published certificate reads on its
1822/// side, which is none where it was published as a name and a key.
1823fn published_bytes(certificate: Option<&Certificate<'_>>) -> u64 {
1824    certificate.map_or(0, |certificate| certificate.as_bytes().len() as u64)
1825}
1826
1827/// Whether two certificates are the same one: the bytes they arrived as. A
1828/// pool that holds one certificate twice holds one certificate.
1829fn same(left: &Certificate<'_>, right: &Certificate<'_>) -> bool {
1830    core::ptr::eq(left.as_bytes(), right.as_bytes()) || left.as_bytes() == right.as_bytes()
1831}
1832
1833/// Whether a certificate is one an anchor was published in: the same name
1834/// and the same key, however the trust context supplied the anchor itself.
1835fn publishes_anchor<V: Verify, W: Watch, R: Recognizer>(
1836    search: &mut Search<'_, '_, V, W, R>,
1837    certificate: &Certificate<'_>,
1838) -> BuildResult<bool, V::Error, R::Error> {
1839    let anchors = search.anchors;
1840    for anchor in anchors {
1841        if !search.spend_names(certificate.tbs().subject(), anchor.name())? {
1842            break;
1843        }
1844        if !certificate
1845            .tbs()
1846            .subject()
1847            .matches(anchor.name(), search.execution)?
1848        {
1849            continue;
1850        }
1851
1852        // The keys are compared byte for byte, and how long a key encoding
1853        // is is decided by whoever wrote the certificate. Two encodings of
1854        // one length that differ near the end are read to the end, and a
1855        // pool can hold a candidate for every anchor: charged at a flat
1856        // rate, one certificate and a handful of anchors buy the reading of
1857        // their product while the bound barely moves. The name comparison
1858        // above is charged by what it reads for the same reason, and this
1859        // is the other side of the same question.
1860        let key = certificate.tbs().public_key().as_bytes();
1861        let against = anchor.key().as_bytes();
1862        let read = (key.len() as u64 + against.len() as u64) / cost::COMPARED;
1863        if !search.spend(read)? {
1864            break;
1865        }
1866        if key == against {
1867            return Ok(true);
1868        }
1869    }
1870    Ok(false)
1871}
1872
1873/// What one certificate says about itself, read the first time it is seen
1874/// and repeated afterwards.
1875///
1876/// Every answer here is a property of the certificate and of the question
1877/// the caller asked, neither of which changes while a search runs, so the
1878/// second visit costs a lookup rather than the extensions again.
1879fn properties<'a, V: Verify, W: Watch, R: Recognizer>(
1880    search: &mut Search<'a, '_, V, W, R>,
1881    certificate: &'a Certificate<'a>,
1882) -> BuildResult<Properties<'a>, V::Error, R::Error> {
1883    let at = certificate.as_bytes().as_ptr() as usize;
1884    if let Some(known) = search
1885        .properties
1886        .get(&at, search.execution)
1887        .map_err(|reason| certificate.tbs().subject().resource(reason))?
1888    {
1889        return Ok(*known);
1890    }
1891    let settings = validation::Settings {
1892        execution: search.execution,
1893        interval: search.interval,
1894        policy: search.policy,
1895        policies: search.bounds.policies,
1896        recognizer: search.recognizer,
1897    };
1898    let facts = validation::certificate_facts(certificate, &settings, search)?;
1899    let usable = facts.is_some_and(|facts| facts.rejected.is_none());
1900    let self_issued = facts.is_some_and(|facts| facts.self_issued);
1901    let issuing = facts.and_then(|facts| {
1902        if facts.issuing.is_none() {
1903            facts.basic
1904        } else {
1905            None
1906        }
1907    });
1908    // Anchor publication identity is search metadata, not a certificate-path
1909    // acceptance rule. Ask the expensive self-signature only after cheap facts.
1910    let publishes_itself = usable
1911        && self_issued
1912        && publishes_anchor(search, certificate)?
1913        && search.verified(
1914            certificate,
1915            WorkingKey::standing(certificate.tbs().public_key()),
1916        )? == Some(Verified::Yes);
1917    let known = Properties {
1918        facts,
1919        usable,
1920        issues: issuing,
1921        publishes_itself,
1922    };
1923    search
1924        .properties
1925        .try_insert(at, known)
1926        .map_err(|reason| certificate.tbs().subject().resource(reason))?;
1927    Ok(known)
1928}
1929
1930/// Whether the chain, read down from the anchor, is a path: every
1931/// certificate within the names the ones above it allowed, under a policy
1932/// they agreed on, and inside the depth they permitted (RFC 5280 6.1.3 and
1933/// 6.1.4).
1934///
1935/// The answer carries what the path was issued under, because that is not a
1936/// property of any one certificate: it is what is left after every authority
1937/// along the path has narrowed it.
1938///
1939/// The chain is held with the target first, so it is read backwards: the
1940/// certificate the anchor issued is where the path starts.
1941fn validate_candidate<'a, V: Verify, W: Watch, R: Recognizer>(
1942    search: &mut Search<'a, '_, V, W, R>,
1943    chain: &[&'a Certificate<'a>],
1944    anchor: Anchor<'a>,
1945) -> BuildResult<Option<OwnedVec<Oid<'a>>>, V::Error, R::Error> {
1946    let settings = validation::Settings {
1947        execution: search.execution,
1948        interval: search.interval,
1949        policy: search.policy,
1950        policies: search.bounds.policies,
1951        recognizer: search.recognizer,
1952    };
1953    // Every adjacent issuer and this terminal anchor were matched before
1954    // settle selected the chain. Preserve that construction witness rather
1955    // than normalizing all the same names a second time during processing.
1956    match validation::process(
1957        validation::Chain::Constructed(chain),
1958        anchor,
1959        &settings,
1960        search,
1961    )? {
1962        Validation::Accepted(facts) => Ok(Some(facts.into_policies())),
1963        Validation::Rejected(_) => Ok(None),
1964        Validation::Incomplete(reason) => {
1965            if !search.stopped() {
1966                search.stop(reason);
1967            }
1968            Ok(None)
1969        }
1970    }
1971}
1972
1973#[cfg(test)]
1974mod tests;