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