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