skip to content

In certificate path processing, what is the difference between building a certification path and validating one?

level: middleimportance: must knowfreq 65%

answer

  1. a search, then a check
  2. building can retry; validating answers
  3. one prospective path in, a verdict out
  4. inputs: the path, the time, the anchor
  5. state flows from the anchor downward

basics

~20 s

Building is a search: it hunts through the certificates a verifier can reach for an ordered run from an end-entity certificate to an anchor it holds. Validating is a check that accepts or rejects one such run.

solid answer

~50 s

**Path building** is a search problem. Given an end-entity certificate, a pool of candidate CA certificates from wherever the verifier can get them, and the anchors it holds, it looks for an ordered run of certificates reaching one of those anchors. The search can find nothing, find one path, or find several different ones. **Path validation** is a decision procedure over exactly one prospective path. Its inputs are a prospective certification path of length n, the current date and time, and trust anchor information - the anchor's name, public key and algorithm. As specified, it then processes the path from the anchor downward, carrying a working public key and a working issuer name, checking each certificate's signature, its validity window, name chaining, revocation status and the constraints it inherits. Building can retry; validating just answers.

code

pseudocode · 17 lines
pseudocode
function check(leaf, candidates, anchors, now):
    for each path in search(leaf, candidates, anchors):   -- may yield several
        if validate(path, now, path.anchor) == accepted:
            return accepted
    return no_path_found

function validate(path, now, anchor):
    working_public_key  = anchor.public_key
    working_issuer_name = anchor.name
    for each cert in path ordered anchor -> end_entity:
        if verify_signature(cert, working_public_key) fails: reject
        if now < cert.notBefore or now > cert.notAfter:     reject
        if cert.issuer != working_issuer_name:               reject
        -- revocation status for this certificate is checked here too
        working_public_key  = cert.SubjectPublicKeyInfo
        working_issuer_name = cert.subject
    return accepted

go deeper

for a junior

Know that a verifier does two different jobs: it first has to find a run of certificates reaching something it trusts, and only then check that run. Merging the two makes every chain failure sound identical.

for a middle

Explain the three inputs validation is given - a prospective path, the current date and time, and trust anchor information - and how a working key and working issuer name are carried down the path.

for a senior

Talk about search behaviour: whether your verifier retries after a rejection, how many candidates it will consider, and why two runtimes handed identical certificates can disagree about the same leaf.

for a principal

Decide how much path-building freedom you want across an estate. A verifier that searches widely accepts more and is harder to reason about; one that accepts only the ordering it was handed is predictable and brittle.

## Two jobs that get spoken of as one "The client validates the chain" hides two different pieces of work, with different failure modes and different people to blame. **Path building is a search.** The verifier starts from an end-entity certificate and a pool of candidate CA certificates - whatever it was handed, whatever it has cached, whatever it can fetch - plus the set of trust anchors it holds. It looks for an ordered run of certificates in which each is issued by the next and the top one is issued by an anchor. Like any search, it can come back empty, come back with one answer, or come back with several. **Path validation is a check.** It takes one candidate run and returns a verdict. It does not go looking for alternatives, and it has no opinion about certificates that are not in the run it was given. | | Path building | Path validation | |---|---|---| | Shape | a search over candidates | a decision procedure | | Input | a leaf, a candidate pool, an anchor set | one prospective path, the time, anchor information | | Outcomes | no path, one path, several paths | accepted or rejected | | On failure | may try another ordering | returns a verdict and stops | | Varies between verifiers | considerably | far less | ## The three inputs that matter The validation algorithm is given a **prospective certification path of length n**, the **current date and time**, and **trust anchor information** - the anchor's name, its public key and that key's algorithm. Several initial policy-processing settings exist alongside these, but the three above are the ones every answer needs: - the *path* is a candidate, not a fact - it is whatever the search assembled; - the *time* is what makes `notBefore` and `notAfter` checkable, which is why a machine with a wrong clock rejects perfectly good certificates and accepts expired ones; - the *anchor* is an input, not an outcome. A verifier never discovers its anchor during the walk; it is told which one to start from. ## Why the check runs downward The search usually starts at the leaf, because that is the certificate the verifier was handed. The specified validation algorithm runs the other way: it begins at the anchor and consumes the path toward the end-entity certificate. It has to, because it must start from something it already trusts. It initialises a `working_public_key` and a `working_issuer_name` from the trust anchor information, then for each certificate in turn: 1. verifies the certificate's signature using the current `working_public_key`; 2. checks the current time falls inside that certificate's `notBefore` and `notAfter`; 3. checks the certificate's `issuer` equals the current `working_issuer_name`; 4. checks revocation status, by whichever mechanism the deployment uses - a separate subject with its own machinery; 5. replaces `working_public_key` and `working_issuer_name` from this certificate's `SubjectPublicKeyInfo` and `subject`, and folds in any constraints it imposes on what follows. Constraints such as `pathLenConstraint` and `nameConstraints` bind everything *beneath* the certificate that states them, so they can only be accumulated in that direction. Implementations may verify individual signatures in either order; what matters is that the state the algorithm carries flows from the anchor down. ## Why the distinction earns its keep Three practical consequences follow, and all three show up in real incidents: - **A rejection is a verdict on one path, not on a certificate.** Another run through the candidate pool may reach a different anchor, or reach the same anchor through a different intermediate, and validate cleanly. A verifier that assembles one path and stops has answered a narrower question than the one the operator was asking. - **Two verifiers given identical bytes can disagree.** They hold different anchors, they cache different intermediates, and they differ in how hard they search after a first failure. None of that is a difference in the validation algorithm. - **Error messages conflate the two.** "Unable to get local issuer" is a build failure - nothing to check. "Certificate has expired" is a validation verdict - there was something to check and it failed. Knowing which one you are looking at tells you whether the missing piece is a certificate or a fact about one. ## The honest summary Building asks *is there a run of certificates from here to something I trust?* Validation asks *is this particular run acceptable right now?* A candidate who keeps those apart can diagnose a chain problem; a candidate who merges them can only report that "the certificate did not work".

  • Why does validation process the path from the anchor downward when the search usually starts at the end-entity certificate?
    Because the check has to start from something already trusted. It initialises a working public key and a working issuer name from the trust anchor information, then replaces both from each certificate it consumes. Constraints such as `pathLenConstraint` and `nameConstraints` also bind everything beneath the certificate that states them, so they can only be accumulated downward. The search starts at the leaf only because that is the certificate it was handed.
  • A verifier rejects a path. Does that mean no valid path exists for that end-entity certificate?
    No. Rejection is a verdict on one prospective path, not on the certificate. Another run through the candidate pool can reach a different anchor, or the same anchor through a different intermediate, and validate. A verifier that constructs one path and stops has answered a narrower question, which is why implementations that keep searching accept certificates that single-path verifiers reject.
  • What does a wrong system clock do to this process?
    It corrupts the one input that is not a certificate. The current date and time is supplied to validation, so a clock set far ahead rejects certificates inside their real window, and one set far back accepts certificates that have expired. Path building is unaffected - the search still finds the run - which is why the symptom is a validation verdict rather than a missing issuer.

saying these in an interview costs you the question

  • Uses building and validating as if they were one indivisible step.
  • Describes the specified validation algorithm as starting at the end-entity certificate.
  • Thinks one rejected path proves no valid path exists.
  • Forgets that the current date and time is an input to validation.
  • Assumes a verifier validates whatever ordered list it happened to be handed.