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