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