Skip to main content

build_path

Function build_path 

Source
pub fn build_path(
    target: &Certificate,
    pool: &CertPool,
    anchors: &[TrustAnchor],
) -> Result<Vec<Certificate>>
Expand description

Build a certification path from target through certificates in pool to one of the provided trust anchors.

Returns the ordered chain [target, intermediate..., anchor-issued] ready for pkix_path::validate_path. Signatures are not verified here; that is the responsibility of the caller via pkix_path::validate_path.

§Algorithm

Single-pass depth-first search at the configured max_depth. Candidates at each frame are ordered by AKI/SKI tier (RFC 5280 §4.2.1.1) so disambiguating bridge-CA / cross-cert topologies succeeds on the first candidate when AKI/SKI bindings are well-formed. Cycles are detected by SubjectPublicKeyInfo algorithm OID + raw public-key bits; algorithm parameters are excluded so RFC 8017 absent-vs-NULL ambiguity in rsaEncryption SPKIs does not break detection.

This is a thin wrapper over the PathCandidates iterator: it returns the iterator’s first yield, or invokes a depth+1 probe (with fresh budget) on None to distinguish Error::NoPathFound from Error::DepthExceeded.

§Errors

§Choosing between build_path, the iterator, and build_first_valid_path

Use this single-shot API when:

  • the pool is from a trusted source (in-house cert store, configured intermediate bundle), and
  • finding any topologically valid chain is sufficient (the caller does not need to retry with alternate chains if signature verification fails downstream).

Use build_path_candidates (or its _with_config sibling) when you want full control over candidate iteration — for adversarial pools (CMS SignedData.certificates bags, federal-bridge cross-cert topologies, anywhere the wire-order of certs is not under your control) so failed signature verification can be retried against the next candidate path. See PathCandidates for the build-then-validate retry-loop pattern.

Use build_first_valid_path (or its _with_config sibling) for the common case of “iterate candidates until one validates”: it wraps the iterator + pkix_path::validate_path retry loop and returns the first chain that survives both topological build and signature verification. Prefer this over build_path when the pool contains alternatives whose signatures may be rejected by the verifier (e.g., cross-signed intermediates using algorithms outside the verifier’s dispatch table).

§Limitations

Candidate selection uses AKI/SKI as an ordering heuristic, not a security gate. When the cert seeking an issuer carries an AuthorityKeyIdentifier extension with a keyIdentifier field (RFC 5280 §4.2.1.1), pool candidates whose SubjectKeyIdentifier (§4.2.1.2) matches are tried before DN-only matches. This is best-effort disambiguation for bridge-CA and key-rollover topologies where multiple CA certs share an issuer DN. The signature itself is not verified by this crate — that happens downstream in pkix_path::validate_path. Consequences:

  • When the AKI heuristic picks the wrong candidate (e.g., AKI is absent or malformed, multiple candidates share the same SKI, or the AKI/SKI binding is wrong), the returned chain may fail validate_path with SignatureInvalid rather than Error::NoPathFound here. Callers handling adversarial pools should use build_path_candidates to retry alternate chains.
  • Malformed AKI or SKI extensions are treated as if absent (fail-soft). They do not cause path building to abort; they simply degrade selection to DN-only ranking for that cert.
  • The AKI authorityCertIssuer + authorityCertSerialNumber fields (the rare alternative to keyIdentifier) are not currently used for ranking. Only the keyIdentifier field participates.

Anchor matching is by DN only. When a candidate’s issuer DN matches any anchor in anchors, path building terminates immediately with that chain — the anchor’s SubjectPublicKeyInfo is not verified against what the chain expects.

Shortest-first is no longer guaranteed. Earlier versions of this crate used iterative-deepening DFS to return the shortest topology first. The single-pass DFS used now (which shares state with the PathCandidates iterator) yields paths in depth-first order. For typical pools the first yielded chain is still the shortest; for adversarial pools, a deeper chain may be returned first if its branch is explored before a shallower alternative. If shortest-first matters, inspect the returned chain length and (rarely) re-run with a tightened max_depth.

§Security

Pool contents should be from a trusted source. The DFS frame-entry budget enforces a hard cap on search work to prevent denial-of-service via oversized or crafted pools.