RFC 4158

Internet X.509 Public Key Infrastructure: Certification Path Building

πŸ“… published September 2005, from ietf

RFC 4158: Internet X.509 Public Key Infrastructure: Certification Path Building πŸ¦‹

okay bestie, this is RFC 4158 πŸŽ€ Its title is "Internet X.509 Public Key Infrastructure: Certification Path Building," and it came out in September 2005 ✨. It's Informational, so it's guidance and advice, not a standard. It comes from the Network Working Group, and the authors are M. Cooper (Orion Security Solutions), Y. Dzambasow (A&N Associates), P. Hesse (Gemini Security Solutions), S. Joseph (Van Dyke Technologies), and R. Nicholas (BAE Systems) πŸ’…. The title block doesn't list anything it obsoletes or updates, so there's no drama there 🫢.

Status of This Memo 🌸

This memo gives info to the Internet community. It doesn't specify an Internet standard of any kind. Distribution of this memo is unlimited πŸ’œ.

Copyright (C) The Internet Society (2005).

Abstract ✨

This document gives developers guidance and recommendations for building X.509 public-key certification paths inside their applications. If you follow what's in here, you're way more likely to end up with a robust X.509 certificate-enabled app that can build valid certification paths across a wide range of PKI environments πŸ”₯. Main character energy, honestly πŸ‘‘.

Table of Contents πŸ“

   1. Introduction ....................................................3
      1.1. Motivation .................................................4
      1.2. Purpose ....................................................4
      1.3. Terminology ................................................5
      1.4. Notation ...................................................8
      1.5. Overview of PKI Structures .................................8
           1.5.1. Hierarchical Structures .............................8
           1.5.2. Mesh Structures ....................................10
           1.5.3. Bi-Lateral Cross-Certified Structures ..............11
           1.5.4. Bridge Structures ..................................13
      1.6. Bridge Structures and Certification Path Processing .......14

   2. Certification Path Building ....................................15
      2.1. Introduction to Certification Path Building ...............15
      2.2. Criteria for Path Building ................................16
      2.3. Path-Building Algorithms ..................................17
      2.4. How to Build a Certification Path .........................21
           2.4.1. Certificate Repetition .............................23
           2.4.2. Introduction to Path-Building Optimization .........24
      2.5. Building Certification Paths for Revocation Signer
           Certificates ..............................................30
      2.6. Suggested Path-Building Software Components ...............31
      2.7. Inputs to the Path-Building Module ........................33
           2.7.1. Required Inputs ....................................33
           2.7.2. Optional Inputs ....................................34
   3. Optimizing Path Building .......................................35
      3.1. Optimized Path Building ...................................35
      3.2. Sorting vs. Elimination ...................................38
      3.3. Representing the Decision Tree ............................41
           3.3.1. Node Representation for CA Entities ................41
           3.3.2. Using Nodes to Iterate Over All Paths ..............42
      3.4. Implementing Path-Building Optimization ...................45
      3.5. Selected Methods for Sorting Certificates .................46
           3.5.1. basicConstraints Is Present and cA Equals True .....47
           3.5.2. Recognized Signature Algorithms ....................48
           3.5.3. keyUsage Is Correct ................................48
           3.5.4. Time (T) Falls within the Certificate Validity .....48
           3.5.5. Certificate Was Previously Validated ...............49
           3.5.6. Previously Verified Signatures .....................49
           3.5.7. Path Length Constraints ............................50
           3.5.8. Name Constraints ...................................50
           3.5.9. Certificate Is Not Revoked .........................51
           3.5.10. Issuer Found in the Path Cache ....................52
           3.5.11. Issuer Found in the Application Protocol ..........52
           3.5.12. Matching Key Identifiers (KIDs) ...................52
           3.5.13. Policy Processing .................................53
           3.5.14. Policies Intersect the Sought Policy Set ..........54
           3.5.15. Endpoint Distinguished Name (DN) Matching .........55
           3.5.16. Relative Distinguished Name (RDN) Matching ........55
           3.5.17. Certificates are Retrieved from
                   cACertificate Directory Attribute .................56
           3.5.18. Consistent Public Key and Signature Algorithms ....56
           3.5.19. Similar Issuer and Subject Names ..................57
           3.5.20. Certificates in the Certification Cache ...........57
           3.5.21. Current CRL Found in Local Cache ..................58
      3.6. Certificate Sorting Methods for Revocation Signer
           Certification Paths .......................................58
           3.6.1. Identical Trust Anchors ............................58
           3.6.2. Endpoint Distinguished Name (DN) Matching ..........59
           3.6.3. Relative Distinguished Name (RDN) Matching .........59
           3.6.4. Identical Intermediate Names .......................60
   4. Forward Policy Chaining ........................................60
      4.1. Simple Intersection .......................................61
      4.2. Policy Mapping ............................................62
      4.3. Assigning Scores for Forward Policy Chaining ..............63
   5. Avoiding Path-Building Errors ..................................64
      5.1. Dead Ends .................................................64
      5.2. Loop Detection ............................................65
      5.3. Use of Key Identifiers ....................................66
      5.4. Distinguished Name Encoding ...............................66
   6. Retrieval Methods ..............................................67
      6.1. Directories Using LDAP ....................................67
      6.2. Certificate Store Access via HTTP .........................69
      6.3. Authority Information Access ..............................69
      6.4. Subject Information Access ................................70
      6.5. CRL Distribution Points ...................................70
      6.6. Data Obtained via Application Protocol ....................71
      6.7. Proprietary Mechanisms ....................................71
   7. Improving Retrieval Performance ................................71
      7.1. Caching ...................................................72
      7.2. Retrieval Order ...........................................73
      7.3. Parallel Fetching and Prefetching .........................73
   8. Security Considerations ........................................74
      8.1. General Considerations for Building a Certification Path ..74
      8.2. Specific Considerations for Building Revocation
           Signer Paths ..............................................75
   9. Acknowledgements ...............................................78
   10. Normative References ..........................................78
   11. Informative References ........................................78

1. Introduction 🌷

[X.509] public key certificates have become an accepted way to securely bind the identity of a person or device to a public key πŸ”. That's what lets you do public key stuff like digital signature verification and public key-based encryption. BUT (and this is a big but) before an application can use the public key in a certificate, it first has to figure out whether the certificate is authentic. That means checking that every certificate leading up to a trusted public key, called a trust anchor, is valid. Once you've validated that certification path, you can trace the identity-to-key binding in each certificate all the way back to a single trust anchor πŸ¦‹.

Figuring out whether a certificate is authentic is called certification path processing πŸ’…. It sets up a chain of trust between a trust anchor and a certificate, and that chain is a series of certificates called a certification path. A certification path starts with a certificate whose signature can be checked using a trust anchor, and it ends with the target certificate. Path processing means building and validating that path so you can tell whether the target certificate is okay to use in a particular application context πŸ’–. For more on certification paths and trust, check out Section 3.2 of [RFC3280] ✨.

1.1. Motivation πŸ’œ

Lots of other docs (like [RFC3280]) cover certification path validation requirements and procedures in detail, but they don't really talk about certification path building. Why? Because how you find the path doesn't change how it gets validated πŸ™ˆ. So this doc is here to give useful guidance to people building certification path-building implementations 🧚.

The need for complex certification paths is also growing. A lot of PKIs now use complicated structures (see Section 1.5) instead of simple hierarchies 🌈. Some enterprises are also slowly moving away from trust lists packed with tons of trust anchors, and heading toward an infrastructure with one trust anchor and many cross-certified relationships ⭐. This doc has helpful info for building certification paths in these more complicated situations πŸ’….

1.2. Purpose πŸŽ€

This document gives info and guidance for certification path building. There are no requirements or protocol specifications in here 🫢. It offers many options for doing certification path building, not just one particular way. The authors pulled from their own experience with existing complex certification paths to share insights and recommendations with developers who are adding support for [X.509] certificates to their apps πŸ”₯.

This doc also suggests an effective general approach to path building that uses a depth first tree traversal 🌸. The authors think this approach has the right balance of simple design and really effective, infrastructure-neutral path-building capabilities πŸ‘‘. But the algorithm is only a suggested approach. Other approaches (e.g., breadth first tree traversals) exist and may turn out to be more effective under certain conditions πŸ¦‹. Certification path validation is described in detail in both [X.509] and [RFC3280], so it isn't repeated here πŸ’–.

This document does not provide guidance for building the certification path from an end entity certificate to a proxy certificate as described in [RFC3820] πŸ™ˆ.


1.3. Terminology πŸ“šβœ¨

Okay bestie, this is the glossary πŸ’… These terms get used in these exact ways throughout the doc, so no freelancing, fr fr πŸ™ˆ

  • Building in the Forward direction: the process of building a certification path from the target certificate to a trust anchor. "Forward" is the former name of the crossCertificatePair element issuedToThisCA. πŸ¦‹
  • Building in the Reverse direction: the process of building a certification path from a trust anchor to the target certificate. "Reverse" is the former name of the crossCertificatePair element issuedByThisCA. πŸ”„
  • Certificate: a digital binding that cannot be counterfeited between a named entity and a public key. πŸ”
  • Certificate Graph: a graph that represents the entire PKI (or all cross-certified PKIs) in which all named entities are viewed as nodes and all certificates are viewed as arcs between nodes. πŸ•ΈοΈ
  • Certificate Processing System: an application or device that performs the functions of certification path building and certification path validation. βš™οΈ
  • Certification Authority (CA): an entity that issues and manages certificates. πŸ‘‘
  • Certification Path: an ordered list of certificates starting with a certificate signed by a trust anchor and ending with the target certificate. πŸ›€οΈ
  • Certification Path Building: the process used to assemble the certification path between the trust anchor and the target certificate. 🧩
  • Certification Path Validation: the process that verifies the binding between the subject and the subject-public-key defined in the target certificate, using a trust anchor and set of known constraints. βœ…
  • Certificate Revocation List (CRL): a signed, time stamped list identifying a set of certificates that are no longer considered valid by the certificate issuer. 🚫
  • CRL Signer Certificate: the specific certificate that may be used for verifying the signature on a CRL issued by, or on behalf of, a specific CA. ✍️
  • Cross-Certificate: a certificate issued by one CA to another CA for the purpose of establishing a trust relationship between the two CAs. 🀝
  • Cross-Certification: the act of issuing cross-certificates. πŸ’ž
  • Decision Tree: when the path-building software has multiple certificates to choose from, and must make a decision, the collection of possible choices is called a decision tree. 🌳
  • Directory: generally used to refer an LDAP accessible repository for certificates and PKI information. The term may also be used generically to refer to any certificate storing repository. πŸ“
  • End Entity: the holder of a private key and corresponding certificate, whose identity is defined as the Subject of the certificate. Human end entities are often called "subscribers". πŸ§β€β™€οΈ
  • Is-revocation-signer indicator: a boolean flag furnished to the path-building software. If set, this indicates that the target certificate is a Revocation Signer certificate for a specific CA. For example, if building a certification path for an indirect CRL Signer certificate, this flag would be set. 🚩
  • Local PKI: the set of PKI components and data (certificates, directories, CRLs, etc.) that are created and used by the certificate using organization. In general, this concept refers to the components that are in close proximity to the certificate using application. The assumption is that the local data is more easily accessible and/or inexpensive to retrieve than non-local PKI data. 🏠
  • Local Realm: See Local PKI. 🏑
  • Node (in a certificate graph): the collection of certificates having identical subject distinguished names. πŸ“
  • Online Certificate Status Protocol (OCSP): an Internet protocol used by a client to obtain the revocation status of a certificate from a server. πŸ“‘
  • OCSP Response Signer Certificate: the specific certificate that may be used for verifying the signature on an OCSP response. This response may be provided by the CA, on behalf of the CA, or by a different signer as determined by the Relying Party's local policy. πŸ–‹οΈ
  • Public Key Infrastructure (PKI): the set of hardware, software, personnel, policy, and procedures used by a CA to issue and manage certificates. πŸ—οΈ
  • Relying Party (RP): an application or entity that processes certificates for the purpose of 1) verifying a digital signature, 2) authenticating another entity, or 3) establishing confidential communications. πŸ’β€β™€οΈ
  • Revocation Signer Certificate: refers collectively to either a CRL Signer Certificate or OCSP Response Signer Certificate. 🫢
  • Target Certificate: the certificate that is to be validated by a Relying Party. It is the "Certificate targeted for validation". Although frequently this is the End Entity or a leaf node in the PKI structure, this could also be a CA certificate if a CA certificate is being validated. (e.g., This could be for the purpose of building and validating a certification path for the signer of a CRL.) 🎯
  • Trust (of public keys): in the scope of this document, a public key is considered trustworthy if the certificate containing the public key can be validated according to the procedures in [RFC3280]. πŸ’œ
  • Trust List: a list of trust anchors. πŸ“
  • Trust Anchor: the combination of a trusted public key and the name of the entity to which the corresponding private key belongs. βš“
  • Trust Anchor Certificate: a self-signed certificate for a trust anchor that is used in certification path processing. πŸͺͺ
  • User: an individual that is using a certificate processing system. This document refers to some cases in which users may or may not be prompted with information or requests, depending upon the implementation of the certificate processing system. πŸ™‹β€β™€οΈ

1.4. Notation πŸŽ€

This document makes use of a few common notations that are used in the diagrams and examples. Lowkey important, so pay attention πŸ‘€

The first is the arrow symbol (->), which represents the issuance of a certificate from one entity to another. For example, if entity H were to issue a certificate to entity K, this is denoted as H->K. ➑️

Sometimes it is necessary to specify the subject and issuer of a given certificate. If entity H were to issue a certificate to entity K this can be denoted as K(H). 🏷️

These notations can be combined to denote complicated certification paths such as C(D)->B(C)->A(B). 🧢✨


1.5. Overview of PKI Structures 🌈

When verifying [X.509] public key certificates, often the application performing the verification has no knowledge of the underlying Public Key Infrastructure (PKI) that issued the certificate. PKI structures can range from very simple, hierarchical structures to complex structures such as mesh architectures involving multiple bridges (see Section 1.5.4). These structures define the types of certification paths that might be built and validated by an application [MINHPKIS]. This section describes four common PKI structures. πŸ›οΈπŸ’–

1.5.1. Hierarchical Structures 🏰

okay so bestie, a hierarchical PKI (see Figure 1 πŸŽ€) is one where every end entity and relying party uses a single "Root CA" as their trust anchor. πŸ’… If the hierarchy has more than one level, the Root CA certifies the public keys of intermediate CAs, which are also called subordinate CAs. Those CAs then certify the public keys of end entities (subscribers), or, in a big PKI, they can certify other CAs too 🧚. In this setup, certificates only go in one direction. A CA never certifies a CA that is "superior" to itself, and typically only one superior CA certifies each CA 🌸.

                           +---------+
                       +---| Root CA |---+
                       |   +---------+   |
                       |                 |
                       |                 |
                       v                 v
                    +----+            +----+
              +-----| CA |      +-----| CA |------+
              |     +----+      |     +----+      |
              |                 |                 |
              v                 v                 v
           +----+            +----+            +----+
        +--| CA |-----+      | CA |-+      +---| CA |---+
        |  +----+     |      +----+ |      |   +----+   |
        |     |       |       |     |      |    |       |
        |     |       |       |     |      |    |       |
        v     v       v       v     v      v    v       v
     +----+ +----+ +----+ +----+ +----+ +----+ +----+ +----+
     | EE | | EE | | EE | | EE | | EE | | EE | | EE | | EE |
     +----+ +----+ +----+ +----+ +----+ +----+ +----+ +----+

                Figure 1 - Sample Hierarchical PKI

so, building a certification path in a hierarchical PKI is super straightforward ✨. The relying party just keeps retrieving issuer certificates, one after another, until it finds a certificate that was issued by the trust anchor (the "Root CA" in Figure 1) πŸ¦‹.

a really popular twist on the single-rooted hierarchy is having multiple CAs as trust anchors (see Figure 2 🌈). end entity certificates get validated the same way as in any hierarchical PKI. the only difference is that a certificate gets accepted if it can be verified back to any one of the trust anchors in the set. πŸ‘‘ web browsers do this all the time, and they ship with trust lists containing dozens to more than one hundred CAs 😭.

⚠️ bestie, this approach makes certificate verification simpler in a limited way, but it can also bring some security vulnerabilities πŸ’€. the user may have little or no idea what policies or operating practices each trust anchor follows, and they may not even know which root was used to verify a given certificate πŸ™ˆ. on top of that, if any trusted CA's private key gets compromised, or a rogue CA certificate sneaks into the trust list, the whole system could be compromised. ngl, that's a lot of risk 😬. the flip side is that if the trust list is properly managed and kept to a reasonable size, it can be an efficient way to build and validate certification paths πŸ’–.
        +-------------------------------------------------------+
        |                      Trust List                       |
        |                                                       |
        |     +---------+     +---------+      +---------+      |
        |  +--| Root CA |     | Root CA |      | Root CA |      |
        |  |  +---------+     +---------+      +---------+      |
        |  |      |                |                 |          |
        +--|------|----------------|---------------- |----------+
           |      |                |                 |
           |      |                |                 |
           |      |                v                 |
           |      |             +----+               |
           |      |        +----| CA |---+           |
           |      |        |    +----+   |           |
           |      |        |             |           |
           |      |        v             v           v
           |      |     +----+        +----+      +----+
           |      |     | CA |---+    | CA |-+    | CA |---+
           |      |     +----+   |    +----+ |    +----+   |
           |      |       |      |    |      |       |     |
           |      |       |      |    |      |       |     |
           v      v       v      v    v      v       v     v
        +----+ +----+ +----+ +----+ +----+ +----+ +----+ +----+
        | EE | | EE | | EE | | EE | | EE | | EE | | EE | | EE |
        +----+ +----+ +----+ +----+ +----+ +----+ +----+ +----+

             Figure 2 - Multi-Rooted Hierarchical PKI

1.5.2. Mesh Structures πŸ•ΈοΈ

in a typical mesh style PKI (see Figure 3 πŸ¦‹), each end entity trusts the CA that issued its own certificate(s). 🫢 so there's no 'Root CA' for the entire PKI, bestie. the CAs in this environment are peers πŸ‘―β€β™€οΈ: they're neither superior nor subordinate to one another. in a mesh, CAs cross-certify, which means each CA issues a certificate to, and is issued a certificate by, its peer CAs in the PKI πŸ’œ. the figure shows a mesh PKI that is fully cross-certified (sometimes called a full mesh) πŸ”₯. however, it's possible to build and deploy a mesh PKI with a mix of uni-directional and bi-directional cross-certifications, which is called a partial mesh 🌸. partial meshes may also include CAs that aren't cross-certified with other CAs in the mesh πŸ™ƒ.

                      +---------------------------------+
                      |                                 |
          +-----------+----------------------+          |
          |           v                      v          |
          |       +-------+               +------+      |
          |  +--->| CA B  |<------------->| CA C |<--+  |
          |  |    +-------+               +------+   |  |
          |  |      |    ^                  ^  |     |  |
          |  |      v    |                  |  |     |  |
          |  |   +----+  |                  |  |     |  |
          |  |   | EE |  +----+    +--------+  v     |  |
          |  |   +----+       |    |         +----+  |  |
          |  |                |    |         | EE |  |  |
          v  v                v    v         +----+  v  v
        +------+             +------+             +------+
        | CA E |<----------->| CA A |<----------->| CA D |
        +------+             +------+             +------+
         |  ^  ^                                    ^ ^  |
         |  |  |                                    | |  |
         v  |  +------------------------------------+ |  v
     +----+ |                                         | +----+
     | EE | |                +------+                 | | EE |
     +----+ +----------------| CA F |-----------------+ +----+
                             +------+

                       Figure 3 - Mesh PKI

so, certification path building in a mesh PKI is way more complex than in a hierarchical one πŸ˜΅β€πŸ’«. that's because there's likely to be multiple paths between a relying party's trust anchor and the certificate being verified. those extra paths make it easier to end up with "loops", "dead ends", or invalid paths while the software is building the certification path between a trust anchor and a target certificate πŸŒ€. even worse, when no valid path exists at all, the total number of paths the path-building software has to traverse before it can conclude "no path exists" can grow exceedingly large πŸ’€. for example, if you ignore everything except the structure of the graph, the Mesh PKI figure above has 22 non-self issued CA certificates and a total of 5,092,429 certification paths between CA F and the EE issued by CA D without repeating any certificates 🀯. that's literally a whole maze, bestie 🧩.

1.5.3. Bi-Lateral Cross-Certified Structures πŸŒ‰

PKIs can be connected through cross-certification, so the relying parties of each one can verify and accept certificates issued by the other PKI ✨. if the PKIs are hierarchical, cross-certification usually happens when each Root CA issues a certificate for the other PKI's Root CA. πŸŽ€ that makes things a bit more complex, but it's still essentially a hierarchical environment πŸ“. if the PKIs are mesh style, then a CA within each PKI is picked, more or less arbitrarily, to set up the cross-certification, which effectively creates a bigger mesh PKI πŸ¦‹. Figure 4 shows a hybrid situation where a hierarchical PKI is cross-certifying with a mesh PKI 🌈.

                   PKI 1 and 2 cross-certificates
                  +-------------------------------+
                  |                               |
                  |                               v
                  |                           +---------+
                  |                      +----| Root CA |---+
                  |                      |    +---------+   |
                  |                      |       PKI 1      |
                  |                      v                  v
                  |                     +------+         +------+
                  v PKI 2             +-|  CA  |-+       |  CA  |
                 +------+             | +------+ |       +------+
        +------->|  CA  |<-----+      |     |    |         |   |
        |        +------+      |      |     |    |         |   |
        |         |    |       |      v     v    v         v   v
        |         |    |       |  +----+ +----+ +----+ +----+ +----+
        |         v    v       |  | EE | | EE | | EE | | EE | | EE |
        |      +----+ +----+   |  +----+ +----+ +----+ +----+ +----+
        |      | EE | | EE |   |
        |      +----+ +----+   |
        v                      v
     +------+                +------+
     |  CA  |<-------------->|  CA  |------+
     +------+                +------+      |
      |    |                  |    |       |
      |    |                  |    |       |
      v    v                  v    v       v
  +----+ +----+            +----+ +----+ +----+
  | EE | | EE |            | EE | | EE | | EE |
  +----+ +----+            +----+ +----+ +----+

                      Figure 4 - Hybrid PKI

okay, real talk πŸ₯Ί. in current implementations, this situation raises a concern: the applications used under the hierarchical PKIs might not have path building capabilities robust enough to handle this more complex certificate graph 😰. as the number of cross-certified PKIs grows, the number of relationships between them grows exponentially πŸ“ˆ. there are two principal concerns about cross-certification. the first is the creation of unintended certification paths through transitive trust πŸ™€. the second is the dilution of assurance, which happens when a high-assurance PKI with restrictive operating policies gets cross-certified with a PKI that has less restrictive policies 😀. (proper name constraints and certificate policies processing can help mitigate the problem of assurance dilution πŸ›‘οΈβœ¨.)

1.5.4. Bridge Structures ✨

okay so the next way to link PKIs together is a "bridge" certification authority (BCA) πŸŒ‰. The BCA is basically the nexus, the central hub where trust paths between multiple PKIs get set up πŸ’…. The BCA cross-certifies with one CA in each participating PKI. Each PKI only cross-certifies with one other CA (the BCA), and the BCA cross-certifies only once with each participating PKI. 😭

Here's the iconic part: the number of cross-certified relationships in a bridged setup grows linearly with the number of PKIs, but in mesh architectures it grows exponentially. Linear vs. exponential is literally a whole glow-up πŸ“ˆπŸ”₯. Still, when you connect PKIs this way, the number and variety of them ends up giving you a non-hierarchical environment, like the one in Figure 5 πŸ¦‹. (Note: as discussed in Section 2.3, non-hierarchical PKIs can be considered hierarchical, depending upon perspective. πŸ™ˆ)

                  PKI 1 cross-certified with Bridge
                  +-------------------------------+
                  |                               |
                  v                               v
            +-----------+                    +---------+
            | Bridge CA |                +---| Root CA |-----+
            +-----------+                |   +---------+     |
                  ^                      |      PKI 1        |
       PKI 2 cross|cert with Bridge      v                   v
                  |                     +------+         +------+
                  v PKI 2             +-|  CA  |-+       |  CA  |
                 +------+             | +------+ |       +------+
        +------->|  CA  |<-----+      |     |    |         |   |
        |        +------+      |      |     |    |         |   |
        |         |    |       |      v     v    v         v   v
        |         |    |       |  +----+ +----+ +----+ +----+ +----+
        |         v    v       |  | EE | | EE | | EE | | EE | | EE |
        |      +----+ +----+   |  +----+ +----+ +----+ +----+ +----+
        |      | EE | | EE |   |
        |      +----+ +----+   |
        v                      v
     +------+                +------+
     |  CA  |<-------------->|  CA  |------+
     +------+                +------+      |
      |    |                  |    |       |
      |    |                  |    |       |
      v    v                  v    v       v
  +----+ +----+            +----+ +----+ +----+
  | EE | | EE |            | EE | | EE | | EE |
  +----+ +----+            +----+ +----+ +----+

         Figure 5 - Cross-Certification with a Bridge CA

1.6. Bridge Structures and Certification Path Processing 🌈

developers building certificate-enabled apps meant for widespread use across different sectors are encouraged to think about supporting a Bridge PKI structure πŸ’–. Why? Because handling certification path processing for a Bridge PKI means supporting all the PKI structures the Bridge might connect (hierarchical, mesh, hybrid, and so on) 🧩. So an app that can successfully build valid certification paths in all Bridge PKIs has already implemented all the processing logic needed for the simpler structures. It's giving complete coverage ✨.

So, if an application fully supports the Bridge PKI structure, it can be deployed in any standards-compliant PKI environment and will perform the required certification path processing properly πŸ‘‘πŸ«Ά.


2. Certification Path Building πŸŽ€

certification path building is the process where the certificate processing system gets the certification path between a trust anchor and the target certificate πŸ¦‹. Different implementations can build paths in different ways, so this document is not trying to name one "best" way. Instead, it gives guidance on the technical issues around path building, plus the capabilities path-building implementations need to build paths successfully, no matter what PKI structure they're dealing with πŸ’….

2.1. Introduction to Certification Path Building 🌸

okay so a certification path is an ordered list of certificates. It starts with a certificate that can be validated by one of the relying party's trust anchors, and ends with the certificate being validated. (That certificate is called the "target certificate" throughout this document 🎯.) Trust anchors are typically stored in trust anchor certificates, though that's not required πŸ€·β€β™€οΈ. The intermediate certificates in the path can be retrieved by any means the validating application has available. That could be LDAP, HTTP, SQL, a local cache or certificate store, or as part of the security protocol itself, which is common with signed S/MIME messages and SSL/TLS sessions πŸ”.

Figure 6 shows an example of a certification path 🧚. In this figure, the horizontal arrows represent certificates, and the notation B(A) means a certificate issued to B, signed by A.

   +---------+      +-----+     +-----+     +-----+     +--------+
   |  Trust  |----->| CA  |---->| CA  |---->| CA  |---->| Target |
   | Anchor  |  :   |  A  |  :  |  B  |  :  |  C  |  :  |   EE   |
   +---------+  :   +-----+  :  +-----+  :  +-----+  :  +--------+
                :            :           :           :
                :            :           :           :
              Cert 1       Cert 2      Cert 3      Cert 4
         A(Trust Anchor)    B(A)        C(B)      Target(C)

               Figure 6 - Example Certification Path

Unlike certification path validation, certification path building isn't covered by the standards that define a PKI's semantics and structure πŸ™ƒ. That's because validating a path isn't affected by how the path was built. BUT (lowercase, we're keeping the vibe 😌) being able to build a valid certification path is of paramount importance for apps that rely on a PKI 😀. Without valid certification paths, certificates can't be validated according to [RFC3280], so they can't be trusted πŸ’€. Basically, building a path is every bit as important as validating it properly πŸ’―.

There are a lot of issues that can complicate path building πŸ˜΅β€πŸ’«. For example, building a path through a cross-certified environment could mean the path-building module has to traverse multiple PKI domains spanning multiple directories, use multiple algorithms, and deal with varying key lengths. A path-building client may also have to manage a bunch of trust anchors, partially populated directory entries (like missing issuedToThisCA entries in the crossCertificatePair attribute), parsing of certain certificate extensions (like authorityInformationAccess) and directory attributes (like crossCertificatePair), plus error handling such as loop detection πŸŒ€.

On top of that, a developer has to decide whether to build paths from a trust anchor (the reverse direction) to the target certificate, or from the target certificate (the forward direction) to a trust anchor πŸ€”. Some implementations may even do both. The choice a developer makes should depend on the environment and the underlying PKI for that environment. More info on making this choice is in Section 2.3 πŸ“š.

2.2. Criteria for Path Building 🎯

from here on out, this document will be talking about specific algorithms and mechanisms to help developers of certification path-building implementations πŸ› οΈ. To justify these mechanisms, it's important to spell out what the authors considered the criteria for a path-building implementation πŸ“.

Criterion 1: The implementation is able to find all possible paths, excepting paths containing repeated subject name/public key pairs. This means that all potentially valid certification paths between the trust anchor and the target certificate which may be valid paths can be built by the algorithm πŸ”. As discussed in Section 2.4.2, we recommend that subject names and public key pairs are not repeated in paths πŸ™Œ.

Criterion 2: The implementation is as efficient as possible. An efficient certification path-building implementation is defined to be one that builds paths that are more likely to validate following [RFC3280], before building paths that are not likely to validate. The understanding here is that there's no way to account for all possible configurations and infrastructures 🌍. This criterion is meant to make sure implementations can produce useful error information πŸ“£. If a particular path is entirely valid except for a single expired certificate, that's most likely the 'right' path πŸ‘€. If other paths are invalid for multiple obscure reasons, that gives you very little useful info πŸ₯±.

The algorithms and mechanisms discussed from here on are chosen because the authors consider them good methods for meeting the criteria above πŸ’œβœ¨.

2.3. Path-Building Algorithms ✨

okay bestie, so people who know the Bridge CA stuff or mesh-type PKIs usually picture path building as walking a super tangled graph πŸ•ΈοΈ ngl that's giving chaos. But honestly? Writing a path-builder can be literally just traversing a spanning tree 🌳, even in a wildly cross-certified mess. Complex setups AND plain hierarchies can both be drawn as trees because a certificate is never allowed to repeat in a path πŸ™…β€β™€οΈ. If repeats were allowed, you'd get loops (A issues to B, B issues to C, C issues to A), and the number of paths and the number of certs in a path would both grow forever πŸ’€. Figure 7 shows this from the trust anchor's point of view πŸ¦‹.

        +---------+                        +---------+
        |  Trust  |                        |  Trust  |
        | Anchor  |                        |  Anchor |
        +---------+                        +---------+
         |       |                         |         |
         v       v                         v         v
      +---+    +---+                     +---+      +---+
      | A |<-->| C |                  +--| A |      | C |--+
      +---+    +---+                  |  +---+      +---+  |
       |         |                    |     |       |      |
       |  +---+  |                    v     v       v      v
       +->| B |<-+                  +---+  +---+  +---+  +---+
          +---+                     | B |  | C |  | A |  | B |
            |                       +---+  +---+  +---+  +---+
            v                         |      |      |       |
          +----+                      v      v      v       v
          | EE |                  +----+   +---+  +---+  +----+
          +----+                  | EE |   | B |  | B |  | EE |
                                  +----+   +---+  +---+  +----+
     A certificate graph with               |        |
     bi-directional cross-cert.             v        v
     between CAs A and C.                 +----+  +----+
                                          | EE |  | EE |
                                          +----+  +----+

                                     The same certificate graph
                                     rendered as a tree - the
                                     way path-building software
                                     could see it.

Figure 7 - Simple Certificate Graph - From Anchor Tree Depiction

once you look at it this way, ALL PKIs look like hierarchies growing out of the trust anchor πŸ‘‘, no matter how complicated the infrastructure is. Figure 8 shows the same graph from the end entity (EE) (the target certificate in this example) 🧚. This is how it would look if you were building in the forward (from EE or from target) direction. In this example, without knowing any particulars of the certificates, building from EE seems to have a smaller decision tree than building from the trust anchor πŸ‘€. There are fewer nodes in the tree, that's true, but it's not necessarily more efficient in this example πŸ€·β€β™€οΈ.

                  +---------+         +---------+
                  |  Trust  |         |  Trust  |
                  | Anchor  |         |  Anchor |
                  +---------+         +---------+
                       ^                   ^
                       |                   |
                       |                   |
                     +---+               +---+
                     | A |               | C |
                     +---+               +---+
        +---------+    ^                   ^      +---------+
        |  Trust  |    |                   |      |  Trust  |
        | Anchor  |    |                   |      |  Anchor |
        +---------+    |                   |      +---------+
             ^         |                   |           ^
             |       +---+               +---+         |
             +-------| C |               | A |---------+
                     +---+               +---+
                      ^                    ^
                      |                    |
                      |         +---+      |
                      +---------| B |------+
                                +---+
                                  ^
                                  |
                                  |
                               +----+
                               | EE |
                               +----+

               The same certificate graph rendered
                as a tree but from the end entity
                  rather than the trust anchor.

Figure 8 - Certificate Graph - From Target Certificate Depiction

okay so, suppose a path-building algorithm did ZERO optimizations πŸ™ˆ. It can only tell that the current certificate in the tree was issued by the trust anchor, or that it issued the target certificate (EE). From the tree above, building from the target certificate means going through two intermediate certificates before you hit a certificate issued by the trust anchor 100% of the time (e.g., EE chains to B, which then chains to C, which is issued by the Trust Anchor) 😭. The path-building module would NOT chain C to A, because it can recognize that C has a certificate issued by the Trust Anchor (TA) πŸ™…β€β™€οΈ.

On the other hand, in the first tree (Figure 7: from anchor depiction), there's a 50% probability of building a path that's longer than needed (e.g., TA to A to C to B to EE rather than the shorter TA to A to B to EE) 🫠. Even with our simplistic example, though, the path-building software, when it's at A, could be designed to recognize that B's subject distinguished name (DN) matches the issuer DN of the EE πŸ’…. With just this one optimization, the builder could prefer B to C. (B's subject DN matches that of the EE's issuer, whereas C's subject DN does not.) So, for this example, assuming the issuedByThisCA (reverse) and issuedToThisCA (forward) elements were fully populated in the directory, and our path-building module implemented the DN-matching optimization I just mentioned, path building from either the trust anchor or the target certificate could be made roughly equivalent πŸŽ€. A list of possible optimization methods is provided later in this document.

A more complicated example happens when the path-building software runs into a situation where there are multiple certificates to choose from while building a path. We call this a large decision tree, or a situation with high fan-out 🌈. This might happen if an implementation has multiple trust anchors to choose from and is building in the reverse (from trust anchor) direction. Or it may happen in either direction if a Bridge CA is encountered πŸŒ‰. Large decision trees are the enemy of efficient path-building software πŸ’€. To combat this problem, implementations should make careful decisions about the path-building direction, and should utilize optimizations such as those discussed in Section 3.1 when confronted with a large decision tree πŸ”₯.

No matter which path-building approach an algorithm uses, cases can be constructed that make the algorithm perform poorly 😭. The following questions should help a developer decide which direction to build certification paths for their application πŸ’–:

  1. What is required to accommodate the local PKI environment and the PKI environments with which interoperability will be required?

a. If using a directory, is the directory [RFC2587] compliant (specifically, are the issuedToThisCA [forward] cross-certificates and/or the cACertificate attributes fully populated in the directory)? If yes, you are able to build in the forward direction.

b. If using a directory, does the directory contain all the issuedByThisCA (reverse) cross-certificates in the crossCertificatePair attribute, or, alternately, are all certificates issued from each CA available via some other means? If yes, it is possible to build in the reverse direction. Note: [RFC2587] does not require the issuedByThisCA (reverse) cross-certificates to be populated; if they are absent, it will not be possible to build solely in the reverse direction.

c. Are all issuer certificates available via some means other than a directory (e.g., the authorityInformationAccess extension is present and populated in all certificates)? If yes, you are able to build in the forward direction.

  1. How many trust anchors will the path-building and validation software be using?

a. Are there (or will there be) multiple trust anchors in the local PKI? If yes, forward path building may offer better performance πŸš€.

b. Will the path-building and validation software need to place trust in trust anchors from PKIs that do not populate reverse cross-certificates for all intermediate CAs? If no, and the local PKI populates reverse cross-certificates, reverse path building is an option πŸ’œ.

2.4. How to Build a Certification Path ✨

okay so, we already said path building is basically a tree traversal 🌳 that part was easy to see in a simple example, but what about a messier one? πŸ’… Before we get into a more complicated scenario, we need to talk about loops and what actually counts as a loop in a certification path πŸ” [X.509] says the same certificate may not repeat in a path. ngl that works pretty well, because you literally can't make an endless loop without repeating at least one certificate in the path. πŸ™ˆ BUT this rule doesn't fully handle Bridged PKI environments, so we have to level up πŸ”₯

            +---+    +---+
            | F |--->| H |
            +---+    +---+
             ^ ^       ^
             |  \       \
             |   \       \
             |    v       v
             |  +---+    +---+
             |  | G |--->| I |
             |  +---+    +---+
             |   ^
             |  /
             | /
         +------+       +-----------+        +------+   +---+   +---+
         | TA W |<----->| Bridge CA |<------>| TA X |-->| L |-->| M |
         +------+       +-----------+        +------+   +---+   +---+
                           ^      ^               \        \
                          /        \               \        \
                         /          \               \        \
                        v            v               v        v
                  +------+         +------+        +---+    +---+
                  | TA Y |         | TA Z |        | J |    | N |
                  +------+         +------+        +---+    +---+
                   /   \              / \            |        |
                  /     \            /   \           |        |
                 /       \          /     \          v        v
                v         v        v       v       +---+    +----+
              +---+     +---+    +---+   +---+     | K |    | EE |
              | A |<--->| C |    | O |   | P |     +---+    +----+
              +---+     +---+    +---+   +---+
                 \         /      /  \       \
                  \       /      /    \       \
                   \     /      v      v       v
                    v   v    +---+    +---+   +---+
                    +---+    | Q |    | R |   | S |
                    | B |    +---+    +---+   +---+
                    +---+               |
                      /\                |
                     /  \               |
                    v    v              v
                 +---+  +---+         +---+
                 | E |  | D |         | T |
                 +---+  +---+         +---+

                       Figure 9 - Four Bridged PKIs

Figure 9 shows four root certification authorities cross-certified with a Bridge CA (BCA) πŸŒ‰ There are multiple trust anchors drawn in the Figure, but all of our examples treat TA Z as the trust anchor πŸ’œ The other trust anchors are there for different relying parties. By building certification paths through the BCA, trust gets extended across all four infrastructures ✨ In Figure 9, the BCA has four certificates issued to it, one from each of the trust anchors in the graph. If they're stored in the BCA directory system, those four certificates would live in the issuedToThisCA (forward) entry of four different crossCertificatePair structures πŸŽ€ The BCA has also issued four certificates, one to each trust anchor. If stored in the BCA directory system, those would be in the issuedByThisCA (reverse) entry of the same four crossCertificatePair structures πŸ¦‹ (Quick note: the cross-certificates are stored as matched pairs in the crossCertificatePair attribute. For example, one crossCertificatePair structure might hold both A(B) and B(A), but it would not hold A(C) and B(A) together.) Then all four crossCertificatePair structures get stored in the BCA's directory entry in the crossCertificatePair attribute πŸ—‚οΈ

2.4.1. Certificate Repetition

[X.509] requires that certificates are not repeated when building paths 🚫 For example, using the figure above, do NOT build the path TA Z->BCA->Y->A->C->A->C->B->D. The repetition isn't needed to get from Z to D, and it also reuses a certificate (the one issued from C to A), which makes the path non-compliant with [X.509] πŸ’€

What about this path from TA Z to EE?

            TA Z->BCA->Y->BCA->W->BCA->X->L->N->EE

Unlike the first example, this path doesn't make the developer repeat any certificates, so it IS compliant with [X.509] πŸ™Œ Each BCA certificate comes from a different source, which means each one is a different certificate. Now imagine the bottom left PKI (in Figure 9) had double arrows between Y and C, and also between Y and A. Then this path could be built:

            TA Z->BCA->Y->A->C->Y->BCA->W->BCA->X->L->N->EE

A path like this could get arbitrarily complex and touch every cross-certified CA in every PKI in a cross-certified environment, and it would still be compliant with [X.509] πŸ˜΅β€πŸ’« Realistically though, an application wouldn't usually want or need a path like that, and here's why:

  • First, paths like the example above are generally not intended by the PKI designers, and they should not be necessary to validate any given certificate. If you need a convoluted path like this (when there's no simpler path) to validate a certificate, that's most likely a sign of a flaw in the PKI design 🚩
  • Second, the longer a path gets, the greater the potential dilution of trust in it. Every link in the infrastructure (certification by CAs and cross-certification between CAs) can cost some amount of assurance πŸ“‰
  • Third, the longer and more complicated a path is, the less likely it is to validate, because of basic constraints, policies or policy constraints, name constraints, CRL availability, or even revocation 😩
  • Lastly, and definitely not least important from a developer's or user's perspective, is performance 🏎️ Allowing paths like the one above massively increases the number of possible paths for every certificate in a mesh or cross-certified environment. Every path built may need one or more of these: validation of certificate properties, CPU intensive signature validations, CRL retrievals, increased network load, and local memory caching. Getting rid of the superfluous paths can greatly improve performance, especially when no path exists at all 🫢

There's a special case involving certificates that have the same distinguished names but different encodings, which is required by [RFC3280]. That case should not be counted as a repeated certificate. See Section 5.4 for more info 🌸

2.4.2. Introduction to Path-Building Optimization

So how do we get rid of these superfluous paths? πŸ€” Instead of only blocking identical certificates from repeating, it is recommended that a developer block the same public key and subject name pair from repeating. For maximum flexibility, the subject name should collectively include any subject alternative names. With this approach, all of the intended and needed paths should still be available, and the excess and diluted paths get eliminated πŸ‘‘ For example, only one path exists from TA Z to EE in the diagram above with this approach: TA Z->BCA->X->L->N->EE. Main character energy 🎬

Using the simplifying rule of not repeating pairs of subject names (including subject alternative names) and public keys, and only using certificates found in the cACertificate and forward (issuedToThisCA) element of the crossCertificatePair attributes, Figure 10 shows the forward path-building decision tree from EE to all reachable nodes in the graph. This is the ideal graph for a path builder trying to build a path from TA Z to EE 🧚

     +------+       +-----------+        +------+   +---+
     | TA W |<------| Bridge CA |<-------| TA X |<--| L |
     +------+       +-----------+        +------+   +---+
                       /     \                        ^
                      /       \                        \
                     /         \                        \
                    v           v                        \
              +------+         +------+                 +---+
              | TA Y |         | TA Z |                 | N |
              +------+         +------+                 +---+
                                                          ^
                                                           \
                                                            \
                                                          +----+
                                                          | EE |
                                                          +----+

          Figure 10 - Forward (From Entity) Decision Tree

It is not possible to build forward direction paths into the infrastructures behind CAs W, Y, and Z, because W, Y, and Z haven't been issued certificates by their subordinate CAs πŸ™ƒ (The subordinate CAs are F and G, A and C, and O and P, respectively.) If simplicity and speed matter most, the graph in Figure 10 is a super appealing way to structure the path-building algorithm πŸ’– Finding a path from EE to one of the four trust anchors is reasonably simple. Alternatively, a developer could build in the opposite direction, using the reverse cross-certificates from any one of the four trust anchors around the BCA πŸ”„ The graph in Figure 11 shows all possible paths as a tree coming out of TA Z. (Note: it is not recommended that implementations try to figure out all possible paths, because that would require retrieving and storing all PKI data, including certificates and CRLs! That example is only here to show how complex things can get 😭)

Okay so Figure 11 is giving a lot πŸ’€πŸŒ³ Look at the tree and try not to get lost.

     +---+    +---+
     | I |--->| H |
     +---+    +---+
       ^
       |      +---+    +---+
       |      | H |--->| I |
       |      +---+    +---+
     +---+     ^
     | G |    /      +---+    +---+    +---+
     +---+   /       | F |--->| H |--->| I |
       ^    /        +---+    +---+    +---+
        \  /          ^
         \/          /
        +---+    +---+    +---+    +---+                +---+
        | F |    | G |--->| I |--->| H |                | M |
        +---+    +---+    +---+    +---+                +---+
          ^      ^                                        ^
          |     /                                         |
        +------+       +-----------+         +------+   +---+
        | TA W |<------| Bridge CA |-------->| TA X |-->| L |
        +------+       +-----------+         +------+   +---+
                        /          ^              \         \
                       v            \              v         v
                 +------+            +------+     +---+     +---+
                 | TA Y |            | TA Z |     | J |     | N |
                 +------+            +------+     +---+     +---+
                /       \              /     \        \       \
               v         v            v       v        v       v
            +---+      +---+        +---+   +---+    +---+  +----+
            | A |      | C |        | O |   | P |    | K |  | EE |
            +---+      +---+        +---+   +---+    +---+  +----+
            /   \       /   \       /   \        \
           v     v     v     v     v     v        v
        +---+ +---+ +---+ +---+ +---+ +---+     +---+
        | B | | C | | A | | B | | Q | | R |     | S |
        +---+ +---+ +---+ +---+ +---+ +---+     +---+
        /    \     \    \    \      \     \
       v      v     v    v    v      v     v
     +---+ +---+ +---+ +---+ +---+  +---+  +---+
     | E | | D | | B | | B | | E |  | D |  | T |
     +---+ +---+ +---+ +---+ +---+  +---+  +---+
                 /  |    |  \
               v    v    v   v
           +---+ +---+ +---+ +---+
           | E | | D | | E | | D |
           +---+ +---+ +---+ +---+

             Figure 11 - Reverse (From Anchor) Decision Tree

Bestie, this is giving complicated but also giving "choices matter" ✨ Picking the right branch can make a HUGE difference in how fast you get a valid path πŸƒβ€β™€οΈπŸ’¨

The path builder could literally walk the entire graph before finding the shortest path, which here is TA Z->BCA->X->L->N->EE 😭 With a tree like this, plain depth-first traversal is super inefficient πŸ™ˆ So the module needs to decide two things: which direction to traverse the tree, and which branches are more likely to lead to a valid path πŸ§ πŸ’…

So the ideal path-building algorithm is a tree traversal with weights or priorities on each branch point to guide it 🌿 If it's designed well, it'll find the "best path first" more often than not πŸŽ€

(Quick aside πŸ’–: "best path first" is in quotes because what counts as "best" can differ from PKI to PKI. That's for the developer to decide, not this document 🫢)

Finding the "best path first" is all about making the implementation efficient, which is one of our criteria from Section 2.2 ✨

So how does a developer actually get there? Path building can be modeled as a depth-first search, which is the simple way to think about tree traversal 🌸 Figure 12 shows a basic depth-first version with no preference given to sort order πŸ¦‹

Note: The arrows in the lower portion of the figure do not indicate the direction of certificate issuance; they indicate the direction of the tree traversal from the target certificate (EE).
               +----+                        +----+  +----+
               | TA |                        | TA |  | TA |
               +----+                        +----+  +----+
                /  \                           ^     ^
               /    \                           |     |
              v      v                        +---+ +---+
            +---+   +---+                     | A | | C |
            | A |<->| C |                     +---+ +---+
            +---+   +---+                        ^   ^
              ^      ^                   +----+  |   |  +----+
               \    /                    | TA |  |   |  | TA |
                v  v                     +----+  |   |  +----+
               +---+                         ^   |   |   ^
               | B |                          \  |   |  /
               +---+                           \ |   | /
                / \                           +---+ +---+
               /   \                          | C | | A |
              v     v                         +---+ +---+
            +---+ +---+                          ^    ^
            | E | | D |                          |   /
            +---+ +---+                          |  /
                                                +---+
          Infrastructure                        | B |
                                                +---+
                                                  ^
                                                  |
                                               +----+
                                               | EE |
                                               +----+

                                      The Same Infrastructure
                                       Represented as a Tree

                    +----+               +----+
                    | TA |               | TA |
                    +----+               +----+
                       ^                    ^
                       |                    |
                      +---+               +---+
                      | A |               | C |
                      +---+               +---+
   +----+                ^                 ^                 +----+
   | TA |                |                 |                 | TA |
   +----+                |                 |                 +----+
      ^                  |                 |                   ^
       \                 |                 |                  /
      +---+           +---+                +---+           +---+
      | C |           | C |                | A |           | A |
      +---+           +---+                +---+           +---+
         ^               ^                    ^               ^
         |               |                   /               /
         |               |                  /               /
        +---+           +---+          +---+           +---+
        | B |           | B |          | B |           | B |
        +---+           +---+          +---+           +---+
          ^               ^              ^               ^
          |               |              |               |
          |               |              |               |
        +----+          +----+         +----+          +----+
        | EE |          | EE |         | EE |          | EE |
        +----+          +----+         +----+          +----+

                     All possible paths from EE to TA
                using a depth first decision tree traversal

       Figure 12 - Path Building Using a Depth First Tree Traversal

Figure 12 shows there are four possible paths here πŸ‘ Now imagine only the last one (TA->A->B->EE) validates. That could happen for lots of reasons, like name constraints, policy processing, validity periods, or path length constraints πŸ₯Ί

The goal of an efficient path builder is to find that fourth path first by testing certificate properties as it walks the tree πŸ”βœ¨ For example, when the software is at entity B, it should look at both A and C to figure out which is the more likely choice πŸ‘€ An efficient module would conclude that A is more likely to be correct 🎯 Then at A, it compares ending the path at TA versus continuing to C, and a good module picks TA and finds the "best path first" πŸ‘‘

What if the choice between CA certificates isn't just a binary one like before? πŸ€” What if there's an arbitrary number of CA certificates at a branch point, which means an arbitrary number of branches? That's typical in a mesh-style PKI CA or at a Bridge CA directory entry, since each one has multiple certificates issued to itself from other CAs 🌈 Here's the good news: the algorithm doesn't really change, as long as it's structured properly πŸ’… Instead of treating each decision as binary (A or C), the builder should sort all the options at a branch point and then pick the best one from the list 🧚 If the path can't be built through the first choice, try the second choice next when you backtrack to that point πŸ”„ Keep going like this until a path is found or every CA node in the tree has been traversed 🫢

Also, the certificates at a given point should only be sorted at the moment a decision is first made πŸ•°οΈ In our example, A and C get sorted when the algorithm reaches B ✨ There's no memory-resident representation of the entire tree, which is honestly so iconic πŸ™Œ Like any recursive depth-first search, the only things the algorithm needs to track are which nodes (entities) lie behind it on the current path, and, for each of those nodes, which arcs (certificates) have already been tried πŸ“πŸ’–

2.5. Building Certification Paths for Revocation Signer Certificates πŸ”

okay so this part is extra special bc the Revocation Signer certificate may or may not be the same thing as the Certification Authority certificate πŸ€” like, after a CA does a key rollover, the new CA certificate ends up being the CRL Signer certificate, but the old CA certificate is still the Certification Authority certificate for anything that was issued before πŸ”„. With indirect CRLs, the CRL Signer certificate has a different name AND a different key than the Certification Authority certificate πŸ™ˆ. And with OCSP, the Revocation Signer certificate might belong to an OCSP Responder that's a totally different entity from the CA πŸ’€ (plot twist, iykyk).

when the Revocation Signer certificate and the Certification Authority certificate are identical, you're literally already set ✨ no extra path-building drama needed. The path you built (and validated) for the CA certificate can just be reused as the path for the Revocation Signer certificate πŸ’–. The signature on the revocation data (e.g., CRL or OCSP response) gets verified with that same certificate, and that's the whole thing πŸ’…. The efficient validation algorithm should first try all the possible CRLs issued by the Certification Authority and check if any of them (a) cover the certificate in question, (b) are current, and (c) are signed using the same key used to sign the certificate πŸ‘‘.

when the Revocation Signer certificate is not identical to the Certification Authority certificate, a certification path needs to be built (and validated) for the Revocation Signer certificate πŸ₯Ί. Generally, the path-building software can build the path the same way it would for any other certificate 🧚. BUT this document also covers some later sections with methods for seriously speeding up path building for the Revocation Signer certificate case πŸš€.


2.6. Suggested Path-Building Software Components πŸ› οΈ

okay, there's no single way to define an interface to a path-building module πŸ™ƒ. This document isn't trying to force a particular method or semantic on anyone, it's totally up to the implementer to decide πŸ’œ. There are lots of ways to do it. For example, a path-building module could build every conceivable path and hand the entire list back to the caller πŸ“œ. Or it could build until it finds just one that validates and then stop right there ⭐. Or it could build paths iteratively, relying on validation happening outside of the builder and making successive calls to the builder to get more paths until one valid path is found or all possible paths have been found πŸ”. All of these are valid approaches, and each one might bring different benefits to a particular environment or application 🌈.

Regardless of semantics, a path-building module needs to have the following components:

  1. The logic for building and traversing the certificate graph.
  2. Logic for retrieving the necessary certificates (and CRLs and/or other revocation status information if the path is to be validated) from the available source(s).

Now, if you want a more efficient and agile path-building module (and I know you do 😀), the following is a good starting point, and it ties into the rest of this document. For a path-building module to take full advantage of all the suggested optimizations listed in this document, it's going to need every one of the components below πŸŽ€.

  1. A local certificate and CRL cache.
    • a. This can be used by all certificate-using components, and it doesn't need to be specific to the path-building software 🫢. A local cache could be memory resident, stored in an operating system or application certificate store, stored in a database, or even stored in individual files on the hard disk πŸ’Ύ. The implementation of this cache is beyond the scope of this document, but some design considerations are listed below πŸ“.
  2. The logic for building and traversing the certificate graph/tree.
    • a. This does the sorting work that prioritizes certificates (which helps optimize path building) while traversing the tree πŸ¦‹.
    • b. There's no need to build a complete graph before path building starts πŸ™Œ. Since path building can be implemented as a depth-first tree traversal, the path builder only has to store its current location in the tree along with the points traversed to get there πŸ—ΊοΈ. All completed branches can be tossed from memory, and future branches get discovered as the tree is traversed ✨.
  3. Logic for retrieving the necessary certificates from the available certificate source(s):
    • a. Local cache.
      • i. Be able to retrieve all certificates for an entity by subject name, as well as individual certificates by issuer and serial number tuple πŸ”‘.
      • ii. Tracking which directory attribute (including issuedToThisCA <forward> and issuedByThisCA <reverse> for split crossCertificatePair attributes) each certificate was found in may be useful 🧭. This allows for things like retrieving only forward cross-certificates, and so on πŸ’….
      • iii. A "freshness" timestamp (cache expiry time) can be used to figure out when the directory should be searched again ⏰.
    • b. LDAPv3 directory for certificates and CRLs.
      • i. Consider supporting multiple directories for general queries πŸ“š.
      • ii. Consider supporting dynamic LDAP connections for retrieving CRLs using an LDAP URI [RFC3986] in the CRL distribution point certificate extension 🌐.
      • iii. Support LDAP referrals. This is usually just a matter of turning on the right flag in the LDAP API 🏳️.
    • c. HTTP support for CRL distribution points and authority information access (AIA) support.
      • i. Consider HTTPS support, but be warned that it might create unbounded recursion when the implementation tries to build a certification path for the server's certificate, if that in turn needs an additional HTTPS lookup πŸŒ€ (scary, I know 😭).
  4. A certification path cache that stores previously validated relationships between certificates. This cache should include:
    • a. A configurable expiration date for each entry. This date can be set based on things like the expiry of the information used to determine the validity of an entry, bandwidth, assurance level, storage space, and so on πŸ“….
    • b. Support to store previously verified issuer certificate to subject certificate relationships.
      • i. Since the issuer DN and serial number tuple uniquely identifies a certificate, a pair of these tuples (one for the issuer and one for the subject) is an effective way to store this relationship πŸ’œ.
    • c. Support for storing "known bad" paths and certificates. Once a certificate is determined to be invalid, implementations can decide not to retry path development and validation 🚫.

2.7. Inputs to the Path-Building Module πŸ“₯

okay so [X.509] specifically covers the list of inputs needed for path validation πŸ“‹, but it doesn't make any specific suggestions about useful inputs for path building πŸ€·β€β™€οΈ. BUT the whole goal of path building is to find certification paths that will validate, so it makes sense that the same inputs used for validation could be used to optimize path building πŸ’–.

2.7.1. Required Inputs 🎯

Setting aside configuration information like repository or cache locations, these are the required inputs to the certification path-building process:

  1. The Target Certificate: The certificate that is to be validated. This is one endpoint for the path. (It's also possible to provide information used to retrieve a certificate for a target, instead of the certificate itself 🧩.)
  2. Trust List: This is the other endpoint of the path, and it can consist of either:
    • a. Trusted CA certificates
    • b. Trusted keys and DNs; a certificate isn't necessarily required πŸ”

2.7.2. Optional Inputs ✨

On top of the inputs listed in Section 2.7.1, the following optional inputs can also be super useful for optimizing path building πŸ’…. However, if the path-building software takes advantage of all of the optimization methods described later in this document, then all of the following optional inputs will be required 😩.

  1. Time (T): The time for which the certificate is to be validated (e.g., if you're validating a historical signature from one year ago, T is needed to build a valid path) ⏳.
    • a. If it's not included as an input, the path-building software should always build for T equal to the current system time πŸ•°οΈ.
  2. Initial-inhibit-policy-mapping indicator
  3. Initial-require-explicit-policy indicator
  4. Initial-any-policy-inhibit indicator
  5. Initial user acceptable policy set
  6. Error handlers (call backs or virtual classes)
  7. Handlers for custom certificate extensions
  8. Is-revocation-provider indicator
    • a. > IMPORTANT: When building a certification path for an OCSP Responder certificate specified as part of the local configuration, this flag should not be set. It's set when building a certification path for a CRL Signer certificate, or for an OCSP Responder Signer certificate discovered using the information asserted in an authorityInformationAccess certificate extension 🚨.
  9. The complete certification path for the Certification Authority (if Is-revocation-provider is set) πŸ”—
  10. Collection of certificates that may be useful in building the path πŸ“¦
  11. Collection of certificate revocation lists and/or other revocation data πŸ—‚οΈ

The last two items are mostly a matter of convenience πŸ’. Alternatively, certificates and revocation information could be placed in a local cache that the path-building module can access before it tries to build a path 🧁.


3. Optimizing Path Building πŸš€

this section is all about recommending methods for optimizing path-building processes, so buckle up bestie πŸŽ’πŸ’–

3.1. Optimized Path Building ✨

okay so path building gets a major glow-up when you sort the certificates at every decision point (every node in the tree) and then pick the most promising one you haven't selected yet, as described in Section 2.4.2 🫢. This keeps going until the path terminates. It's basically like a weighted edge tree, where the edges are certificates and the nodes are subject DNs 🌸. BUT (unlike the weighted edge graph idea) a path builder doesn't need the whole graph on hand to work efficiently πŸ’…. Plus, the path builder can be stateless about nodes that aren't in the current path, so the working data set can stay pretty small 🧚.

Being stateless about nodes outside the current path is what makes the sorting tricks in this doc work. At first it seems smart to sort a CA's certificates once and keep that order for later, right? Nope, ngl. Keeping that state around can wipe out all the efficiency sorting gives you 😭. Check out this diagram:

            +---+
            | R |
            +---+
             ^
            /
           v
         +---+       +---+      +---+    +---+    +----+
         | A |<----->| E |<---->| D |--->| Z |--->| EE |
         +---+       +---+      +---+    +---+    +----+
            ^         ^ ^        ^
             \       /   \      /
              \     /     \    /
               v   v       v  v
               +---+       +---+
               | B |<----->| C |
               +---+       +---+

            Figure 13 - Example of Path-Building Optimization

In this example, the builder is going forward (from the target) to build a path between R and EE. It has also opted to let subject name and key repeat πŸ¦‹. This allows multiple traversals through any of the cross-certified CAs, which creates enough complexity in this small example to show off proper state maintenance. (A similarly complex example could be designed by using multiple keys for each entity and prohibiting repetition.)

Step one is easy peasy: the builder builds Z(D)->EE(Z). Next, the builder adds D and faces a decision between two certificates (choose between D(C) or D(E)). Now it sorts the two choices in order of priority. The sorting is partly based on what's already in the path πŸ’–.

Suppose the builder selects the order [D(E), D(C)]. The current path is now D(E)->Z(D)->EE(Z). Right now the builder has three nodes in the graph (EE, Z, and D), and it should maintain the state, including the sort order of the certificates at D, when it adds the next node, E. When E is added, the builder has four certificates to sort: E(A), E(B), E(C), and E(D). In this case, the example builder opts for the order [E(C), E(B), E(A), E(D)]. The current path is now E(C)->D(E)->Z(D)->EE(Z), and the path has four nodes: EE, Z, D, and E πŸ“.

Upon adding the fifth node, C, the builder sorts the certificates (C(B), C(D), and C(E)) at C and selects C(E). The path is now C(E)->E(C)->D(E)->Z(D)->EE(Z), and the path has five nodes: EE, Z, D, E, and C πŸŽ€.

Now the builder finds itself back at node E with four certificates. If it used the sort order from the first encounter with E, it would have [E(C), E(B), E(A), E(D)]. In the current path's context, that ordering may be inappropriate. For starters, E(C) is already in the path, so it definitely does not deserve first place πŸ™ˆ.

The best way to handle this is for the path builder to treat this instance of E as a new (sixth) node in the tree. In other words, there's no state information for this new instance of E. It gets treated like any other new node. The certificates at the new node are sorted based on the current path content, and then the first certificate is selected. For example, the builder may examine E(B) and notice that it contains a name constraint prohibiting "C". At this point in the decision tree, E(B) couldn't be added to the path and still produce a valid result, since "C" is already in the path. So E(B) should be placed at the bottom of the prioritized list.

Alternatively, E(B) could be eliminated from this new node in the tree. It's super important to get that this certificate is eliminated only at this node and only for the current path. If path building fails through C and traverses back up the tree to the first instance of E, E(B) could still produce a valid path that doesn't include C. Specifically, R->A->B->E->D->Z->EE πŸ‘‘. So the state at any node should not alter the state of previous or subsequent nodes. (The exception is prioritizing certificates in the subsequent nodes.)

The state at any node stays in its own lane. Previous and subsequent nodes don't get changed by it (other than getting their certificates reprioritized). Keep that straight and the whole thing stays clean πŸ’….

In this example, the builder should also note that E(C) is already in the path, and it should either make it last or eliminate it from this node, since certificates cannot be repeated in a path 🌈.

If the builder eliminates both E(B) and E(C) at this node, it's only left to choose between E(A) and E(D). Now the path has six nodes: EE, Z, D, E(1), C, and E(2). E(1) has four certificates, and E(2) has two, which the builder sorts to yield [E(A), E(D)]. The current path is now E(A)->C(E)->E(C)->D(E)->Z(D)->EE(Z). A(R) gets found when the seventh node is added, and the path terminates because one of the trust anchors has been found ⭐.

If the first path fails to validate, the builder still has the seven nodes and their state information to work with. On the next iteration, it can traverse back up the tree to a working decision point, like A, and select the next certificate in the sorted list at A. In this example, that would be A(B). (A(R) has already been tested.) This would dead end, so the builder traverses back up to the next decision point, E(2), where it would try D(E). This keeps repeating until the traversal backs all the way up to EE or a valid path is found. If the tree traversal returns to EE, every possible path has been exhausted, and the builder can conclude that no valid path exists πŸ’€.

Sorting certificates to optimize path building beats not optimizing the tree traversal, no contest πŸ”₯. But the process can get even more streamlined by eliminating certificates, and whole branches of the tree along with them, as paths are being built πŸ¦‹.

3.2. Sorting vs. Elimination πŸ’…

Okay so picture this: you're building a path and you've found three CA certificates for one target certificate, and you have to decide which one to try first 🧐. When you check them (like in the last example), one of them has a name constraint that would break the path you've built so far. Sorting would put that one at the very back of the line, no cap. But the path builder could also decide that this constraint eliminates the certificate right here, at this point in the graph, which cuts the choices by 33% πŸ”₯.

NOTE: Elimination only applies to a single decision point during the tree traversal. The same certificate can show up again somewhere else in the tree, and there it may or may not get eliminated. The previous section has an example of exactly this πŸ™ˆ.

Eliminating certificates can be a total glow-up for performance, because it can skip a big, time-consuming chunk of infrastructure that was never going to lead to a valid path ✨. So the big question is whether to sort or to eliminate, and it's basically a fight between flexibility of the software interface and efficiency πŸ₯Š.

Here's the tea: if you throw out invalid paths as you build them and only return likely valid ones, you end up with a super efficient path-building module πŸ’–. The catch is that, unless the software makes some allowances for it, the calling application can't see what went wrong. The user might just get the unhelpful error message: "No certification path found." πŸ’€

On the flip side, the path-building module could decide not to rule out any certification paths at all. It could return every path it can build from the certificate graph, and then the validation engine figures out which ones are valid and which aren't 🧠. This gives the user or calling application complete details on why each and every path fails to validate. The downside is performance, obviously: an application or end user might wait a really long time while cross-certified PKIs get navigated to build paths that will never validate 😭.

Neither option is super desirable on its own. One gives users good performance, which is great. The other lets administrators diagnose problems with the PKI, the directory, or the software, which is also great 🫢. So here are some suggestions for finding a middle ground.

First, developers are strongly encouraged to output detailed log information from the path-building software. The log should explicitly show every choice the builder makes and why πŸ“. It should clearly identify which certificates are found and used at each step of building the path. If someone takes care to make a useful log, PKI administrators and help desk folks will have plenty of info to diagnose a problem πŸ•΅οΈβ€β™€οΈ. Ideally, there'd be a way to turn logging on and off, so it isn't running all the time. It's also recommended that the log contain enough information for a developer or tester to recreate the paths the path-building software tried, which helps with diagnostics and testing πŸ§ͺ.

Second, it's desirable to return something useful to the user, and the easiest way is probably a "dual mode" path-building module πŸ‘‘. In the first mode [mode 1], the software eliminates any and all paths that won't validate, which makes it super efficient 🏎️. In the second mode [mode 2], all the sorting methods still get applied, but no paths get eliminated based on those sorting methods. Having this dual mode means the module can first fail to find a valid path, and then switch over to mode 2 just long enough to generate a single path (assuming one exists) πŸ¦‹. It's a middle ground: the software is very fast, but it still gives the user something more specific than "no path found" 🌈.

Third, it may be useful to not rule out any paths, and instead limit how many paths can be built for a particular input 🧚. If the path-building module is designed to return the "best path first," then the paths most likely to validate come back before the limit is hit. Once the limit is reached, the module can stop building paths, which gives the caller a much quicker response than one that builds every possible path ⚑.

Ultimately, the developer decides how to handle the trade-off between efficiency and information πŸ’œ. A developer could land on the middle ground by making some optimizations elimination rules and leaving others as non-eliminating. A developer could even verify certificate signatures, or check revocation status, while building the path, and then decide whether to eliminate the certificate in question based on the result 🌸.

This document suggests the following approach:

  1. While building paths, eliminate any and all certificates that do not satisfy all path validation requirements, with the following exceptions:
    • a. Do not check revocation status if it requires a directory lookup or network access.
    • b. Do not check digital signatures (see Section 8.1, General Considerations for Building A Certification Path, for additional considerations).
    • c. Do not check anything that cannot be checked as part of the iterative process of traversing the tree.
    • d. Create a detailed log, if this feature is enabled.
    • e. If a path cannot be found, the path builder shifts to "mode 2" and allows the building of a single bad path.
      • i. Return the path with a failure indicator, as well as error information detailing why the path is bad.
  2. If path building succeeds, validate the path in accordance with [X.509] and [RFC3280], with the following recommendations:
    • a. For a performance boost, do not re-check items already checked by the path builder. (Note: if pre-populated paths are supplied to the path-building system, the entire path has to be fully re-validated.)
    • b. If the path validation failed, call the path builder again to build another path.
      • i. Always store the error information and path from the first iteration, and return this to the user in the event that no valid path is found. Since the path-building software was designed to return the "best path first," this path should be shown to the user ✨.

As we said above, this document recommends that developers do not validate digital signatures or check revocation status as part of the path-building process πŸ™…β€β™€οΈ. That recommendation rests on two assumptions about PKI and how it's used. First, signatures in a working PKI are usually good πŸ’―. Since signature validation is costly in terms of processor time, it's better to hold off on signature checking until a complete path is found, and then check the signatures on each certificate in the certification path, starting with the trust anchor (see Section 8.1). Second, it's fairly uncommon in typical application environments to run into a revoked certificate, so most certificates validated won't be revoked πŸ₯Ή. That makes it better to delay retrieving CRLs or other revocation status information until a complete path has been found. This lowers the chance of fetching revocation status information you never needed while building paths πŸŽ€.


3.3. Representing the Decision Tree 🌳

There are a multitude of ways to implement certification path building, and just as many ways to represent the decision tree in memory 🀯.

The method described below works really well with the optimization methods listed later in this document πŸ’–. It's the best approach the authors of this document have implemented, but it is absolutely not the only way to do it. Developers should tailor this approach to their own requirements, or they may find that a different approach suits their environment, programming language, or programming style πŸ’….

3.3.1. Node Representation for CA Entities 🧩

A "node" in the certification graph is a collection of CA certificates that all have identical subject DNs 🫧. To fully implement the optimizations coming up, the path-building module will need to be able to keep track of the following information for each node, at minimum:

  1. Certificates contained in the node
  2. Sorted order of the certificates
  3. "Current" certificate indicator
  4. The current policy set (It may be split into authority and user constrained sets, if desired.)
    • It is suggested that encapsulating the policy set in an object with logic for manipulating the set, such as performing intersections, mappings, etc., will simplify implementation πŸ“.
  5. Indicators (requireExplicitPolicy, inhibitPolicyMapping, anyPolicyInhibit) and corresponding skipCert values
  6. A method for indicating which certificates are eliminated, or for removing them from the node.
    • If nodes are recreated from the cache on demand, it may be simpler to remove eliminated certificates from the node πŸ—‘οΈ.
  7. A "next" indicator that points to the next node in the current path ➑️
  8. A "previous" indicator that points to the previous node in the current path ⬅️

3.3.2. Using Nodes to Iterate Over All Paths πŸ¦‹

okay so the simplest version goes like this πŸ’…: you make a node, sort the certificates, figure out the next subject DN you need from the first certificate, and then attach a brand new node to the certification path through the next indicator (that's Number 7 up above 🧚). You keep doing this until the path terminates. (ngl this is important: end entity certificates are allowed to not have subject DNs per [RFC3280]. But end entity certs never issue certificates, so it doesn't mess anything up here πŸ™ˆ)

Okay, the algorithm is built to use recursion, so keep that in your head 🧠. Check out Figure 12 and pretend the only valid path for E is TA->A->B->E πŸ’–.

If our path-building module is building forward for E, we make a node for E first. There's nothing to sort because there's only one certificate, so all the initial values get loaded into the node straight from E. For example, the policy set gets pulled out of the certificate and stored in the node ✨.

Next, we read the issuer DN (B) from E and create a new node for B, which holds both certificates issued to B, which are B(A) and B(C). The sorting rules get applied to those two, and the sorting algorithm gives back B(C);B(A). We store this sorted order and set the current indicator to B(C). The indicators get set and the policy sets get calculated as far as they can go with respect to B(C) 🌸. Here's the vibe right now, with the current certificate marked with a "*" πŸ‘‘:

+-------------+    +---------------+
| Node 1      |    | Node 2        |
| Subject: E  |--->| Subject: B    |
| Issuers: B* |    | Issuers: C*,A |
+-------------+    +---------------+

Next up, we make a node for C and add all three certificates to it. The sorting algorithm happens to put them in this order: C(TA);C(A);C(B) πŸ“

+-------------+    +---------------+    +------------------+
| Node 1      |    | Node 2        |    | Node 3           |
| Subject: E  |--->| Subject: B    |--->| Subject: C       |
| Issuers: B  |    | Issuers: C*,A |    | Issuers: TA*,A,B |
+-------------+    +---------------+    +------------------+

We've reached the trust anchor, so the path (TA->C->B->E) gets validated, but it fails 😭. (Remember, the only valid path is TA->A->B->E.) So the path-building module moves the current certificate indicator in node 3 over to C(A) and adds the node for A πŸŽ€.

      +-------------+    +---------------+    +------------------+
      | Node 1      |    | Node 2        |    | Node 3           |
      | Subject: E  |--->| Subject: B    |--->| Subject: C       |
      | Issuers: B  |    | Issuers: C*,A |    | Issuers: TA,A*,B |
      +-------------+    +---------------+    +------------------+
                                                        |
                                                        v
                                              +------------------+
                                              | Node 4           |
                                              | Subject: A       |
                                              | Issuers: TA*,C,B |
                                              +------------------+

The path TA->A->C->B->E gets validated and... it also fails πŸ’€. So the module moves the current indicator in node 4 to A(C) and adds a node for C 🫢.

+-------------+    +---------------+    +------------------+
| Node 1      |    | Node 2        |    | Node 3           |
| Subject: E  |--->| Subject: B    |--->| Subject: C       |
| Issuers: B  |    | Issuers: C*,A |    | Issuers: TA,A*,B |
+-------------+    +---------------+    +------------------+
                                                 |
                                                 v
               +------------------+    +------------------+
               | Node 5           |    | Node 4           |
               | Subject: C       |<---| Subject: A       |
               | Issuers: TA*,A,B |    | Issuers: TA,C*,B |
               +------------------+    +------------------+

Now comes the big decision: do we allow repeating name and key? πŸ€” If the certification path-building module will NOT allow repetition of name and key, then none of the certificates in node 5 are usable. (C and its public key are already in the path at node 3.) So node 5 gets removed from the current path, and the current certificate indicator on node 4 moves to A(B).

If the module is only disallowing repeated certificates instead, C(A) gets eliminated from node 5 because it's already in use in node 3. Path building keeps going by first validating TA->C->A->C->B->E, and then it keeps trying to build paths through C(B). After that also fails to produce a valid path, node 5 gets removed from the current path and the current certificate indicator on node 4 moves to A(B) πŸ’….

      +-------------+    +---------------+    +------------------+
      | Node 1      |    | Node 2        |    | Node 3           |
      | Subject: E  |--->| Subject: B    |--->| Subject: C       |
      | Issuers: B  |    | Issuers: C*,A |    | Issuers: TA,A*,B |
      +-------------+    +---------------+    +------------------+
                                                        |
                                                        v
                                              +------------------+
                                              | Node 4           |
                                              | Subject: A       |
                                              | Issuers: TA,C,B* |
                                              +------------------+

Now we make a fresh node 5 for B. Same story as the last one: if we're not repeating name and key, B has no usable certificates either, because B and B's public key are already in node 2. So this new node 5 gets removed from the path too. At this point every certificate in node 4 has been tried, so node 4 is removed from the path, and the current indicator on node 3 moves to C(B) 🌈.

Also like before, if we're allowing repeated name and key, B(C) gets removed from the new node 5 (it's already in use in node 3), and the path gets tried through the one leftover certificate, B(A). When that fails, it leads right back to removing node 5 from the path. Once again, every certificate in node 4 has been tried, so node 4 is removed from the path, and the current indicator on node 3 moves to C(B) πŸ”₯.

This keeps going until every certificate in node 1 has been tried (if there's more than one), or until a valid path turns up ✨. Once the process ends and no valid path was found, it's safe to conclude that no path can be found from E to TA 😀.


3.4. Implementing Path-Building Optimization πŸ’…

This section covers methods you can use to optimize certification path building by sorting certificates 🧚. Optimization, like we talked about earlier, is all about prioritizing a list of certificates, which basically means weighting the branches of the graph or tree 🌳. These methods can give each certificate a cumulative score. Scoring works by testing each certificate against whichever optimization methods a developer chooses to build in, then adding the score from each test to that certificate's running total πŸŽ€. Once every certificate at a given branch point in the builder's decision tree has a score, you sort them so the highest-scoring one gets picked first, the second-highest gets picked second, and so on πŸ‘‘.

Here's a quick example. Say the path builder only has these two simple sorting methods:

  1. If the certificate has a subject key ID, +5 to score.
  2. If the certificate has an authority key ID, +10 to score.

And then it looks at three certificates:

  1. Issued by CA 1; has authority key ID; score is 10.
  2. Issued by CA 2; has subject key ID; score is 5.
  3. Issued by CA 1; has subject key ID and authority key ID; score is 15.

Sorted in descending order by score, that's 3, 1, and 2 πŸ“. The path-building software should try building a path through certificate 3 first. If that doesn't work, it should try certificate 1. And last of all, it should try certificate 2 πŸ¦‹.

The optimization methods below describe tests that developers may choose to run, but they don't suggest scores for any of them. Instead, developers should evaluate each method against the environment the application will run in, and assign weights to each one in the path-building software πŸ’–. Plus, a lot of these methods aren't just yes-or-no. Some are tri-valued, and some work nicely on sliding or exponential scales πŸ“ˆ. In the end, the implementer decides how much each optimization matters for their own software or infrastructure 🫢.

On top of the scores for each method, many methods can also be used to eliminate branches during tree traversal, instead of just scoring and weighting them. Every case where an optimization method can eliminate certificates is noted along with that method's description ✨.

A lot of the sorting methods below are based on what the authors have seen as common in PKIs 🌸. Many of them are aimed at making path building fast for the common PKI, but there are cases where almost any sorting method could lead to inefficient path building 😬. The goal is that even if one method points the algorithm in the wrong direction for a given situation or configuration, the remaining methods will override the bad method and send the traversal down the correct branch of the tree more often than not πŸ‘‘. This definitely won't be true for every environment and configuration, and these methods may need tweaking to optimize further for the application's target operating environment πŸ™ˆ.

Last but not least: the list in this document is not meant to be exhaustive πŸ’…. If the operating environment calls for it, a developer may want to define additional sorting methods 🧚.

3.5. Selected Methods for Sorting Certificates ✨

okay so before we dive in, bestie, don't read anything into the order these methods show up in πŸ‘€ the ranking is not the vibe. whether a sorting criterion is actually useful depends completely on the operating environment. for pretty much any method, i can build an example where it works great, and i can also build a counter-example where it flops πŸ’€

each sorting method is its own thing. it may (or may not) be used to give extra scores to each certificate being tested. the implementer picks which methods to use and what weights to give them. and like i said earlier, this list is not exhaustive, so there's more out there 🌸

also, name chaining (the subject name of the issuer certificate matching the issuer name of the issued certificate) is not treated as a sorting method. why? because you need it just to build the decision tree these methods get applied to, so it's already a given πŸ™ˆ and preventing repeated certificates isn't covered by the sorting methods either. path builders handle name chaining and certificate repetition no matter which optimization approach they use πŸ”₯

each sorting method description tells you a few things: whether the method can be used to eliminate certificates, how many possible numeric values (sorting weights) the method has, which components from Section 2.6 it needs, the forward and reverse method descriptions, and finally why it's included at all πŸ’…

now, elimination is kinda tricky, so listen up πŸ‘‚ for a lot of these methods, certificates only get eliminated at one particular decision point. for example, the path built up to certificate X might get invalidated by name constraints when certificate Y is added. at that decision point only, Y can be eliminated from further consideration. but at some future decision point, while building that same path, adding Y might not invalidate anything at all πŸ¦‹

for some other sorting methods, certificates could be eliminated from the whole process entirely. for example, certificates with unsupported signature algorithms could never be part of any path that gets validated. the path builder can totally be designed to work that way, but it's perfectly fine to always discard certificates only for a given decision point, no matter what caused it 🧚


3.5.1. basicConstraints Is Present and cA Equals True πŸŽ€

May be used to eliminate certificates: Yes Number of possible values: Binary Components required: None

Forward Method: Certificates with basicConstraints present and cA=TRUE, or those designated as CA certificates out-of-band, get priority. Certificates without basicConstraints, with basicConstraints and cA=FALSE, or those that aren't designated as CA certificates out-of-band may be eliminated or get zero priority.

Reverse Method: Same as forward, except for end entity certificates at the terminus of the path.

Justification: according to [RFC3280], basicConstraints is required to be present with cA=TRUE in all CA certificates, or it has to be verified through an out-of-band mechanism. a valid path just can't be built if this condition isn't met 😭

3.5.2. Recognized Signature Algorithms πŸ¦‹

May be used to eliminate certificates: Yes Number of possible values: Binary Components required: None

Forward Method: Certificates containing recognized signature and public key algorithms [PKIXALGS] get priority.

Reverse Method: Same as forward.

Justification: if the path-building software can't process the signatures on a certificate, the certification path can't be validated. no cap, that's a dead end πŸ’€

3.5.3. keyUsage Is Correct πŸ”‘

May be used to eliminate certificates: Yes Number of possible values: Binary Components required: None

Forward Method: if keyUsage is present, certificates with keyCertSign set get 100% priority. if keyUsage is present and keyCertSign isn't set, the certificate may be eliminated or get zero priority. everything else gets zero priority.

Reverse Method: Same as forward, except for end entity certificates at the terminus of the path.

Justification: a valid certification path can't go through a CA certificate with inappropriate keyUsage. also, digitalSignature isn't required to be set in a CA certificate, so don't panic if it's missing 🫢

3.5.4. Time (T) Falls within the Certificate Validity ⏰

May be used to eliminate certificates: Yes Number of possible values: Binary Components required: None

Forward Method: certificates whose validity period contains the required time (T) get 100% priority. otherwise, the certificate is eliminated or gets priority zero.

Reverse Method: Same as forward.

Justification: a valid certification path can't be built if T falls outside the certificate's validity period 🌈

NOTE: be extra careful to return a meaningful error to the caller, especially when the target certificate doesn't meet this criterion and this sorting method is being used for elimination. (for example, the certificate is expired or isn't valid yet.) nobody wants a mysterious "nope" πŸ™ˆ

3.5.5. Certificate Was Previously Validated 🌸

May be used to eliminate certificates: No Number of possible values: Binary Components required: Certification Path Cache

Forward Method: a certificate that's present in the certification path cache gets priority.

Reverse Method: Does not apply. (knowing whether a certificate's validity is known or unknown doesn't tell you anything about the right direction in the decision tree. in other words, knowing a CA certificate's validity doesn't mean the target is more likely to be found down that path than another one. πŸ€·β€β™€οΈ)

Justification: certificates in the path cache have been validated before. assuming the initial constraints haven't changed, it's very likely the path from that certificate to a trust anchor is still valid. (changes to the initial constraints might make a certificate that was previously considered valid stop being considered valid, so keep that in mind πŸ‘€)

Note: the items in the path cache need appropriate lifetimes πŸ•°οΈ for example, it could be inappropriate to cache a relationship beyond the period the related CRL will be trusted by the application. you also have to think about certificates and CRLs farther up the path when setting cache lifetimes. like, if the issuer certificate expires in ten days but the issued certificate is valid for 20 days, caching the relationship beyond 10 days would be inappropriate. not it πŸ™…β€β™€οΈ

3.5.6. Previously Verified Signatures πŸ”

May be used to eliminate certificates: Yes Number of possible values: Binary Components required: Path Cache

Forward Method: if a previously verified relationship exists in the path cache between the subject certificate and a public key present in one or more issuer certificates, all the certificates containing that public key get higher priority. other certificates may be eliminated or set to zero priority.

Reverse Method: if known bad signature relationships exist between certificates, those relationships can be used to eliminate potential certificates from the decision tree. nothing can be concluded about the likelihood of finding a given target certificate down one branch versus another based on known good signature relationships.

Justification: if the public key in certificate (A) was previously used to verify a signature on a second certificate (B), then any and all certificates containing the same key as (A) may be used to verify the signature on (B). likewise, any certificates that don't contain the same key as (A) can't be used to verify the signature on (B). this forward direction method is especially strong for multiply cross-certified CAs after a key rollover has happened πŸ”„βœ¨

3.5.7. Path Length Constraints πŸ“

May be used to eliminate certificates: Yes Number of possible values: Binary Components required: None

Forward Method: certificates with basic constraints present and containing a path length constraint that would invalidate the current path may be eliminated or set to zero priority. (the current length is known since the software is building from the target certificate.) otherwise, the priority is 100%.

Reverse Method: this method may be applied in reverse. to do that, the builder keeps a current path length constraint variable, then sets zero priority for (or eliminates) certificates that would violate the constraint.

Justification: a valid path can't be built if the path length constraint has been violated πŸ’–

3.5.8. Name Constraints 🏷️

May be used to eliminate certificates: Yes Number of possible values: Binary Components required: None

Forward Method: certificates containing nameConstraints that would be violated by the certificates already in the path up to this point get zero priority or are eliminated.

Reverse Method: certificates that will allow successful processing of any name constraints present in the path up to this point get higher priority.

Justification: a valid path can't be built if name constraints are violated. rules are rules, periodt πŸ’…

3.5.9. Certificate Is Not Revoked 🚫

May be used to eliminate certificates: No Number of possible values: Three Components required: CRL Cache

Forward Method: if a current CRL for a certificate is in the CRL cache and the certificate serial number isn't on that CRL, the certificate gets priority. if the certificate serial number is on the CRL, it gets zero priority. if an (acceptably fresh) OCSP response is available for a certificate and it identifies the certificate as valid, the certificate gets priority. if an OCSP response is available for a certificate and it identifies the certificate as invalid, the certificate gets zero priority.

Reverse Method: Same as forward.

Alternately, the certificate may be eliminated if the CRL or OCSP response is verified. that means fully verifying the CRL or OCSP response signature and its relationship to the certificate in question, in accordance with [RFC3280]. it's viable, but the signature verification it needs makes it less attractive as an elimination method. it's suggested that this method only be used for sorting, and that CRLs and OCSP responses get validated after path building 🧁

Justification: certificates known to be not revoked can be considered more likely to be valid than certificates whose revocation status is unknown. that's even more true when CRL or OCSP response validation happens after path validation, since CRLs or OCSP responses are only retrieved when complete paths are found 🌟

NOTE: be extra careful to let meaningful errors propagate to the caller, especially when the target certificate is revoked. if a path builder eliminates certificates using CRLs or OCSP responses, some status information should be kept so a meaningful error can be returned if no path is found. πŸ’€ don't ghost your user!

3.5.10. Issuer Found in the Path Cache 🧚

May be used to eliminate certificates: No πŸ™…β€β™€οΈ Number of possible values: Binary Components required: Certification Path Cache

Forward Method: okay so, a certificate whose issuer has an entry (or entries) in the path cache gets priority πŸ’–

Reverse Method: does not apply πŸ€·β€β™€οΈ

Justification: the path cache only holds certificates that were already validated back to a trust anchor, so it's more likely than not that the same path, or a new one, can be built from that point to the (or one of the) trust anchor(s) ✨ but for certificates whose issuers aren't in the path cache, nothing can be concluded 🫠

NOTE: this method is NOT the same as "Certificate Was Previously Validated" πŸ™…β€β™€οΈ it's possible for this sorting method to evaluate to true while the other method evaluates to zero. Different vibes, bestie!

3.5.11. Issuer Found in the Application Protocol πŸ“‘

May be used to eliminate certificates: No Number of possible values: Binary Components required: Certification Path Cache

Forward Method: if the issuer of a certificate the target sent through the application protocol (SSL/TLS, S/MIME, etc.) matches the signer of the certificate you're looking at, then that certificate has priority πŸŽ€

Reverse Method: if the subject of a certificate matches the issuer of a certificate the target sent through the application protocol (SSL/TLS, S/MIME, etc.), then that certificate has priority πŸ¦‹

Justification: the application protocol might carry certificates the sender thinks are valuable for path building, and those are more likely to lead to a path to the target certificate. The sender really knows what's up 🫢


3.5.12. Matching Key Identifiers (KIDs) πŸ”‘

May be used to eliminate certificates: No Number of possible values: Three Components required: None

Forward Method: certificates whose subject key identifier (SKID) matches the current certificate's authority key identifier (AKID) have the highest priority πŸ‘‘ certificates without a SKID have medium priority. Certificates whose SKID doesn't match the current certificate's AKID (if both are present) have zero priority πŸ’€ If the current certificate expresses the issuer name and serial number in the AKID, certificates that match both of those identifiers have the highest priority. Certificates that match only the issuer name in the AKID have medium priority.

Reverse Method: certificates whose AKID matches the current certificate's SKID have the highest priority πŸ‘‘ certificates without an AKID have medium priority. Certificates whose AKID doesn't match the current certificate's SKID (if both are present) have zero priority πŸ’€ If the certificate expresses the issuer name and serial number in the AKID, certificates that match both of those identifiers in the current certificate have the highest priority. Certificates that match only the issuer name in the AKID have medium priority.

Justification: KID matching is a super useful way to guide path building (that's literally their purpose in the certificate), so it gets a heavy weight πŸ’ͺ

NOTE: even though [RFC3280] says KIDs are required to be present, it is extremely important that KIDs are used ONLY as sorting criteria or as hints during certification path building 🚨 KIDs are not required to match during certification path validation and can't be used to eliminate certificates. This matters a LOT for interoperating across domains and multi-vendor implementations, where the KIDs may not be calculated the same way 😭

3.5.13. Policy Processing πŸ“œ

May be used to eliminate certificates: Yes Number of possible values: Three Components required: None

Forward Method: certificates that satisfy Forward Policy Chaining have priority. (See Section 4 entitled "Forward Policy Chaining" for details.) If the caller provided an initial-policy-set and did NOT set the initial-require-explicit flag, the weight of this sorting method should be increased. If the initial-require-explicit-policy flag was set by the caller or by a certificate, certificates may be eliminated πŸ™ˆ

Reverse Method: certificates that contain policies/policy mappings that will allow successful policy processing of the path up to this point have priority. If the caller provided an initial-policy-set and did NOT set the initial-require-explicit flag, the weight of this sorting method should be increased. Certificates may be eliminated only if initial-require-explicit was set by the caller, or if require-explicit-policy was set by a certificate in the path up to this point.

Justification: in a policy-using environment, certificates that successfully propagate policies are more likely to be part of an intended certification path than the ones that don't 🌈

When building in the forward direction, it's always possible that a certificate closer to the trust anchor will set the require-explicit-policy indicator. So giving preference to certification paths that propagate policies may increase the odds of finding a valid path first πŸƒβ€β™€οΈ If the caller (or a certificate in the current path) has specified or set the initial-require-explicit-policy indicator as true, this sorting method can ALSO be used to eliminate certificates when building in the forward direction.

If building in reverse, it's always possible that a certificate farther along the path will set the require-explicit-policy indicator, so favoring certificates that propagate policies will serve well in that case. When require-explicit-policy is set by certificates or the caller, certificates can be eliminated with this method 🫧


3.5.14. Policies Intersect the Sought Policy Set 🎯

May be used to eliminate certificates: No Number of possible values: Additive Components required: None

Forward Method: certificates that assert policies found in the initial-acceptable-policy-set have priority. Each additional matching policy could have an additive affect on the total score.

Alternately, this could be binary: it matches 1 or more, or it matches none.

Reverse Method: certificates that assert policies found in the target certificate, or map policies to those found in the target certificate, have priority. Each additional matching policy could have an additive affect on the total score. Alternately, this could be binary: it matches 1 or more, or it matches none.

Justification: in the forward direction, as the path gets close to the trust anchor in a cross-certified environment, the policies asserted in the CA certificates will match those in the caller's domain. Since the initial acceptable policy set is specified in the caller's domain, matches may mean the path building is getting closer to a desired trust anchor πŸ₯Ή In the reverse direction, finding policies that match the target certificate's may mean the path is getting close to the target's domain 🏑


3.5.15. Endpoint Distinguished Name (DN) Matching πŸͺͺ

May be used to eliminate certificates: No Number of possible values: Binary Components required: None

Forward Method: certificates whose issuer exactly matches a trust anchor subject DN have priority.

Reverse Method: certificates whose subject exactly matches the target entity issuer DN have priority.

Justification: in the forward direction, if a certificate's issuer DN matches a trust anchor's DN [X.501], then it may complete the path βœ… In the reverse direction, if the certificate's subject DN matches the issuer DN of the target certificate, it may be the last certificate required to complete the path 🏁


3.5.16. Relative Distinguished Name (RDN) Matching 🌳

May be used to eliminate certificates: No Number of possible values: Sliding Scale Components required: None

Forward Method: certificates that match more ordered RDNs between the issuer DN and a trust anchor DN have priority. When all the RDNs match, this yields the highest priority.

Reverse Method: certificates with subject DNs that match more RDNs with the target's issuer DN have higher priority. When all the RDNs match, this yields the highest priority.

Justification: in PKIs, DNs are frequently built in a tree-like fashion 🌲 Higher numbers of matches may mean the trust anchor is to be found in that direction within the tree. Note that when all the RDNs match [X.501], this sorting method appears to mirror the preceding one. However, this sorting method should be capable of producing a 100% weight even if the issuer DN has MORE RDNs than the trust anchor. The Issuer DN only needs to contain all the RDNs (in order) of the trust anchor πŸ’…

NOTE: when all RDNs match, this sorting method mirrors the functionality of the preceding one. This allows partial matches to be weighted differently from exact matches. Also, this method can require a lot of processing if many trust anchors are present πŸ₯΅

3.5.17. Certificates are Retrieved from cACertificate Directory Attribute πŸ“‚

May be used to eliminate certificates: No Number of possible values: Binary Components required: Certificate Cache with flags for the attribute from where the certificate was retrieved, and Remote Certificate Storage/Retrieval using a directory

Forward Method: certificates retrieved from the cACertificate directory attribute have priority over certificates retrieved from the crossCertificatePair attribute. (See [RFC2587].)

Reverse Method: does not apply πŸ€·β€β™€οΈ

Justification: the cACertificate directory attribute holds certificates issued from local sources, plus self-issued certificates. By using cACertificate before crossCertificatePair, the path-building algorithm will (depending on the local PKI configuration) tend to prefer the local PKI before venturing out to external cross-certified PKIs 🏠 Most of today's PKI applications spend most of their time processing information from the local (user's own) PKI, and the local PKI is usually very efficient to traverse because it's close by and the network is fast πŸš€


3.5.18. Consistent Public Key and Signature Algorithms πŸ”

May be used to eliminate certificates: Yes Number of possible values: Binary Components required: None

Forward Method: if the public key in the issuer certificate matches the algorithm used to sign the subject certificate, then it has priority. (Certificates with unmatched public key and signature algorithms may be eliminated.)

Reverse Method: if the public key in the current certificate matches the algorithm used to sign the subject certificate, then it has priority. (Certificates with unmatched public key and signature algorithms may be eliminated.)

Justification: when the public key and signature algorithms aren't consistent, the signature on the subject certificate won't verify successfully 😡 For example, if the issuer certificate contains an RSA public key, then it could NOT have issued a subject certificate signed with the DSA-with-SHA-1 algorithm. Total mismatch, no thanks πŸ™…β€β™€οΈπŸ’œ

3.5.19. Similar Issuer and Subject Names ✨

May be used to eliminate certificates:  No
Number of possible values:  Sliding Scale
Components required:  None

Forward Method: certs whose subject DN matches more RDNs with the target cert's issuer DN get priority πŸ’…

Reverse Method: same as forward 🫢

Justification: okay so searching the local domain before branching out to cross-certified domains is just more efficient 🧠 Trying certs with similar names first makes the path builder way more efficient. Cross-certs from external domains usually match fewer RDNs (if any at all), while local-domain certs match multiple RDNs all the time 🌸

3.5.20. Certificates in the Certification Cache πŸŽ€

May be used to eliminate certificates:  No
Number of possible values:  Three
Components required:  Local Certificate Cache and Remote Certificate
Storage/Retrieval (e.g., LDAP directory as the repository)

Forward Method: a cert whose issuer cert is already in the cert cache and populated with certs gets higher priority πŸ“¦ A cert whose issuer's entry is fully populated with current data (every cert attribute got searched within the timeout period) also gets higher priority ✨

Reverse Method: if the subject of a cert is in the cert cache and populated with certs, it gets higher priority πŸ’œ If that entry is fully populated with current data (every cert attribute got searched within the timeout period), it gets higher priority too πŸ¦‹

Justification: when the required directory values are already populated in the cache, there's a better chance that all the certs and CRLs needed to finish the path (to the trust anchor, or to the target if you're building in reverse) are already there from a path built earlier. So you skip directory access entirely πŸ™Œ And if no path turns up, the performance cost is low, because those certs probably weren't pulled from the network anyway 🫠

3.5.21. Current CRL Found in Local Cache πŸ”₯

May be used to eliminate certificates: No
Number of possible values:  Binary
Components Required:  CRL Cache

Forward Method: certs get priority if the issuer's CRL entry exists and is populated with current data in the CRL cache πŸ’–

Reverse Method: certs get priority if the subject's CRL entry exists and is populated with current data in the CRL cache 🌈

Justification: if revocation only gets checked after a full path is found, then this basically means a full path went through this entity at some point in the past, so a path probably still exists πŸ‘‘ It also cuts down on remote retrievals until they're actually needed πŸ“


3.6. Certificate Sorting Methods for Revocation Signer Certification Paths 🧚

Unless you're using a locally-configured OCSP responder or some other locally-configured trusted revocation status service, revocation info is expected to come from the PKI that issued the cert 🏰 So when you're building a certification path for a Revocation Signer cert, it's a good idea to keep the building algorithm inside the PKI that issued the cert. The sorting methods below try to order possible paths so the intended Revocation Signer certification path shows up first πŸ’…

These sorting methods aren't meant to replace the ones from the previous section. They work best when you use them together with the ones in Section 3.5. Some criteria below have the same names as the ones in the previous section. That just means the earlier criteria get tweaked a bit when you're building the Revocation Signer certification path 🫢

3.6.1. Identical Trust Anchors πŸ¦‹

May be used to eliminate certificates: No
Number of possible values: Binary
Components required: Is-revocation-signer indicator and the
Certification Authority's trust anchor

Forward Method: not applicable πŸ™ˆ

Reverse Method: path building should start from the same trust anchor that was used to validate the Certification Authority before trying any other trust anchors. Trust anchors that have a different public key but the same subject DN as the Certification Authority's trust anchor should be tried before the ones with mismatched names πŸ’œ

Justification: revocation info for a cert should come from the PKI that issued that cert. So building a path from a different trust anchor than the Certification Authority's is a big no-no πŸ™…β€β™€οΈ

3.6.2. Endpoint Distinguished Name (DN) Matching 🌸

May be used to eliminate certificates: No
Number of possible values: Binary
Components required: Is-revocation-signer indicator and the
Certification Authority's trust anchor

Forward Method: this works the same as the sorting method in 3.5.15, except instead of matching against all trust anchors, the DN matching only happens against the trust anchor DN that was used to validate the CA certificate 🎯

Reverse Method: no change for the Revocation Signer's certification path 🫢

Justification: revocation info for a cert should come from the PKI that issued it, so building a path to a different trust anchor than the CA's isn't ideal πŸ™ƒ This sorting method helps steer forward path building toward the trust anchor that was used to validate the CA certificate 🧭

3.6.3. Relative Distinguished Name (RDN) Matching πŸ“

May be used to eliminate certificates: No
Number of possible values: Sliding Scale
Components required: Is-revocation-signer indicator and the
Certification Authority's trust anchor

Forward Method: this works the same as the sorting method in 3.5.16, except the RDN matching only happens against the trust anchor DN used to validate the CA certificate, not against all trust anchors πŸ’–

Reverse Method: no change for the Revocation Signer's certification path 🌈

Justification: same vibe as before. Revocation info should come from the PKI that issued the cert, so building toward a different trust anchor than the CA's isn't it. This sorting method nudges forward path building toward the trust anchor used to validate the CA certificate 🧚

3.6.4. Identical Intermediate Names πŸ”₯

May be used to eliminate certificates: No
Number of possible values: Binary
Components required: Is-revocation-signer indicator and the
Certification Authority's complete certification path

Forward Method: if the issuer DN in the cert matches the issuer DN of a cert in the Certification Authority's path, it gets higher priority πŸ‘‘

Reverse Method: if the subject DN in the cert matches the subject DN of a cert in the Certification Authority's path, it gets higher priority πŸ¦‹

Justification: following the same path as the Certificate keeps the path-building algorithm from wandering off in a weird direction 🧭 This sorting method doesn't care whether the cert is self-issued, and that's a good thing, because you wouldn't want to downgrade a re-key cert 🫢


4. Forward Policy Chaining πŸ’…

It's super tempting to assume that certificate policies don't help much with path building when you start from the target certificate πŸ™„ It's easy to get the "validate as you go" idea from the trust anchor side, and way less obvious that you can get any value going the other direction. But policy validation is basically the intersection of the issuer policy set with the subject policy set, plus mapping policies from the issuer set to the subject set. So you can do policy validation while building a path forward as well as in reverse ✨ You just reverse the procedure. Not as ideal as validating from the trust anchor, ngl, but it's a method that can mostly get rid of what's long been seen as a weakness of building in the forward direction (from the target certificate) πŸ’–

4.1. Simple Intersection πŸŽ€

The most basic form of policy processing is intersecting the policy sets from the first CA certificate all the way through the target certificate. The good news is that intersecting policy sets always gives the same final set no matter what order you do it in. So you can process the intersections in either direction πŸ™Œ For example, say the trust anchor issues a CA certificate (A) with policies {X,Y,Z}, and that CA issues another CA certificate (B) with policies {X,Y}, and then CA B issues a third CA certificate (C) with policy set {Y,G}. You'd normally calculate the policy set from the trust anchor like this:

1) Intersect A{X,Y,Z} with B{X,Y} to yield the set {X,Y}

2) Intersect that result, {X,Y} with C{Y,G} to yield the final set
   {Y}

So now we've shown that certificate C is good for policy Y πŸ‘‘

The other direction is the exact same procedure, just reversed:

1) Intersect C{Y,G} with B{X,Y} to yield the set {Y}

2) Intersect that result, {Y} with A{X,Y,Z} to yield the final set
   {Y}

Just like in the reverse direction, we've shown that certificate C is good for policy Y, except this time it's the forward direction πŸ¦‹

When you build in the forward direction, policy processing works a lot like it does in reverse. The software gives preference to certs that propagate policies 🧚 Neither approach guarantees that a path with valid policies will be found. Both approaches just help guide the path in the direction it needs to go for the policies to propagate 🫢

If the caller supplied an initial-acceptable-policy set, there's less value in using it when building forward, unless the caller also set inhibit-policy-mapping. In that case, the path builder can further limit path building to propagating policies that exist in the initial-acceptable-policy-set 🌸 Even if inhibit-policy-mapping isn't set, the initial-policy-set can still help guide path building toward the desired trust anchor πŸ’œ

4.2. Policy Mapping πŸ—ΊοΈ

okay so this is where it gets spicy 🌢️ when a CA issues a certificate into another domain that uses totally different policy identifiers, the CA can use policy mappings to say "hey, my X is basically your G" 🀝 the example from before: if A put a policy mapping in the cert it issued to B that mapped X to G, then C would be good for X and Y:

  1. Intersect A{X,Y,Z} with B{X,Y} to yield the set {X,Y} ✨
  2. Process Policy Mappings in B's certificate (X maps to G) to yield {G,Y} (same as {Y,G}) πŸ”„
  3. Intersect that result, {G,Y} with C{Y,G} to yield the final set {G,Y} πŸ’–

bestie, the thing to remember is that policies are always written from the relying party's point of view πŸ‘‘ so C is actually good for {X, Y}, not {Y, G}. "G" doesn't mean anything to the trust anchor that issued A without the mapping, so it doesn't get to be the answer πŸ™ˆ

when you're building in the forward direction, you can "unmap" policies by running the mapping procedure backwards πŸ”™ but there's one big catch 🚨 if policy mapping has already happened going forward, there's no way to know ahead of time whether a future addition to the path will break the policy chain by setting inhibit-policy-mapping. πŸ’€ the good news is it's pretty uncommon for anyone to set that flag, so we're usually fine 🫢 here's the forward procedure:

  1. Begin with C's policy set {Y,G} πŸŽ€
  2. Apply the policy mapping in B's certificate (X maps to G) in reverse to yield {Y,X} (same as {X,Y}) πŸ”
  3. Intersect the result {X,Y} with B{X,Y} to yield the set {X,Y} ✨
  4. Intersect that result, {X,Y}, with A{X,Y,Z} to yield the final set {X,Y} πŸ’…

just like in the reverse direction, we figure out that certificate C is good for {X,Y} βœ… but what if an inhibit-policy-mapping flag shows up partway through? what do we do?? 😱 honestly it's not that hard to track 🧠 the software just keeps a flag on any policy that got added because of a mapping, a simple Boolean that travels with the policies in the set. okay now imagine A's certificate has the inhibit-policy-mapping constraint with a skip certificates value of zero πŸ‘€

  1. Begin with C's policy set {Y,G} πŸŽ€
  2. Apply the policy mapping in B's certificate and mark X as resulting from a mapping. (X maps to G) in reverse to yield {Y,Xm} (same as {Xm,Y}) 🏷️
  3. Intersect the result {Xm,Y} with B{X,Y} to yield the set {Xm,Y} πŸ”—
  4. A's certificate expresses the inhibit policy mapping constraint, so eliminate any policies in the current set that were propagated due to mapping (which is Xm) to yield {Y} 🚫
  5. Intersect that result, {Y} with A{X,Y,Z} to yield the final set {Y} 🫧

and if, in our example, the policy set ever goes totally empty (with require-explicit-policy set), the path builder has to back up and try a different branch of the tree 🌳 this is basically the same path-building move we use in the reverse direction when the policy set goes empty. iconic, honestly πŸ‘‘


4.3. Assigning Scores for Forward Policy Chaining πŸ“Š

assuming the path-building module is keeping track of the current forward policy set, you can give each candidate a weight using this procedure πŸ’―

  1. For each CA certificate being scored: πŸ”
    • a. Copy the current forward policy set.
    • b. Process policy mappings in the CA certificate in order to "un-map" policies, if any.
    • c. Intersect the resulting set with CA certificate's policies.

the bigger the policy set you end up with, the bigger the score for that CA certificate πŸ“ˆ

  1. If an initial acceptable set was supplied, intersect this set with the resulting set for each CA certificate from (1). 🎯

the bigger the resulting set, the higher the score is for that certificate πŸ† and honestly? if your operating environment needs something different, other scoring schemes might work better too 🌈


5. Avoiding Path-Building Errors 🚧

this section is all about the sneaky errors that can pop up during path building, plus how to dodge them when you're writing your path-building functions πŸ₯· let's gooo πŸ”₯

5.1. Dead Ends πŸ•³οΈ

in a non-hierarchical PKI, a simple path-building algorithm can fail too early without ever finding a path, all because it hit a "dead end" 😭 check out Figure 14:

        +----+      +---+
        | TA |      | Z |
        +----+      +---+
           |          |
           |          |
           V          V
         +---+      +---+
         | C |<-----| Y |
         +---+      +---+
           |
           |
           V
         +--------+
         | Target |
         +--------+

  Figure 14 - Dead End Example

so C has two certificates, one issued by Y and one issued by the Trust Anchor 🧩 now suppose we use a simple "find issuer" algorithm, and the path builder finds the certificates in this order: Target(C), C(Y), Y(Z), Z(Z). 😬 Z has no certificates issued by anybody else, so the simple process just stops πŸ›‘ and since Z isn't the relying party's trust anchor, the certification path isn't complete and it won't validate. ❌ the lesson here is that unless the PKI is super simple, your path builder needs extra logic for entities that have certificates from different issuers 🧠 it also needs to be able to climb back up the decision tree and try another path if it wants to be robust πŸ’ͺ

5.2. Loop Detection πŸ”

in a non-hierarchical PKI, a path-building algorithm can get stuck going around in circles and never find a path πŸŒ€ check out this example:

          +----+
          | TA |
          +----+
            |
            |
          +---+      +---+
          | A |    ->| Z |
          +---+   /  +---+
            |    /     |
            |   /      |
            V  /       V
          +---+      +---+
          | B |<-----| Y |
          +---+      +---+
            |
            |
            V
          +--------+
          | Target |
          +--------+

  Figure 15 - Loop Example

let's say we're using the simplest "find issuer" algorithm, and certificates come back in this order: Target(B), B(Y), Y(Z), Z(B), B(Y), Y(Z), Z(B), B(Y), ... 🫠 now there's a loop, and the correct path (Target, B, A) never gets found 😭 the system has to spot loops made by duplicate certificates (which X.509 doesn't allow in a path) before they form, so the path-building process can keep going and find valid paths ✨ the authors of this document recommend that loop detection doesn't just catch a certificate repeating in the path, but also catches the same subject name / subject alternative name / subject public key combination showing up twice πŸ” a name/key pair only needs to appear once in the path πŸ’œ (see Section 2.4.2 for the reasoning behind this, bestie πŸ“š)

5.3. Use of Key Identifiers πŸ”‘

okay this one is important 🚨 if people compute the subject key identifier and authority key identifier in public key certificates in inconsistent or incompatible ways, path-building algorithms that rely on those fields to find certificates can fail, even when a valid path actually exists 😭 path-building implementations should use the key identifiers that are already there and should not try to recompute subject key identifiers πŸ™…β€β™€οΈ it is extremely important that Key Identifiers only get used as sorting criteria or hints 🧭 KIDs are not required to match during certification path validation, and they can't be used to rule certificates out ❌ this matters a LOT when you're interoperating across domains and multi-vendor setups, because the KIDs might not be calculated the same way everywhere 🌍

path-building and processing implementations also shouldn't treat the authority key identifier form that uses the authority DN and serial number as a strict matching rule 🚫 that's because cross-certification can cause this value not to match in the cross-certificates πŸ™ˆ

5.4. Distinguished Name Encoding πŸ”€

certification path-building software shouldn't depend on DNs being encoded as PrintableString πŸ™… even though they're often PrintableString, DNs can also show up as other types, including BMPString or UTF8String 🌏 so software that can't process BMPString and UTF8String encoded DNs might not be able to build and validate some certification paths πŸ’€

also, [RFC3280] compliant certificates are required to encode DNs as UTF8String as of January 1, 2004 πŸ“… certification path-building software should be ready to handle "name rollover" certificates as described in [RFC3280] πŸŽ€ and note that including a "name rollover" certificate in a certification path does not count as repeating a DN and key πŸ’… implementations that do include a "name rollover" certificate in the path should make sure DNs with different encodings are treated as dissimilar 🧩 (implementations may instead handle matching DNs of different encodings, and then they won't need to include "name rollover" certificates in the path 🫢)

6. Retrieval Methods πŸ“₯

building a certification path needs the certificates and CRLs that make up the path to actually be available πŸ“¦ there are lots of different ways to get these certificates and CRLs 🌸 this section lists a few of the common ones, plus some suggested approaches for speeding things up ⚑ this section isn't meant to be a complete reference for certificate and CRL retrieval methods or for every optimization that could help with path building, so don't expect it to cover everything 🧚

6.1. Directories Using LDAP πŸ’–

okay so most applications use LDAP (the Lightweight Directory Access Protocol) πŸ’… when they want to pull data from directories that follow the X.500 model. And apps might run into directories that support either LDAP v2 [RFC1777] or LDAP v3 [RFC3377] 🧚

LDAP v3 defines exactly one attribute retrieval option, the "binary" option πŸŽ€. When you put it in a retrieval request, it was meant to make the directory ignore the string-based representations of BER-encoded directory information and send the requested attribute(s) back in BER format πŸ€“. Since every PKI object we care about is BER-encoded, the "binary" option should be used. BUT not every directory supports it 😭, so apps need to be able to request attributes both with and without it. For example, if an app wants the userCertificate attribute, it should request userCertificate;binary. If the info it needs doesn't come back, robust implementations may opt to request userCertificate as well πŸ’œ.

The following attributes should be considered by PKI application developers when they're doing certificate retrieval from LDAP sources πŸ‘€:

userCertificate: this one holds certificates issued by one or more certification authorities whose subject DN matches that of the directory entry 🌈. It's multi-valued, so all the values should be received and considered during path building. Typically only end entity certificates get stored here (this is the attribute an app would ask for to find a person's encryption certificate), but implementers may opt to search this attribute when looking in CA entries to make their path builder more robust πŸ’ͺ. If it's empty, the overhead of including this attribute when you're already requesting one or both of the two below is marginal ✨.

cACertificate: this holds self-issued certificates (if any) and any certificates issued to this certification authority by other certification authorities in the same realm. (Realm is dependent upon local policy πŸ—ΊοΈ.) It's multi-valued too, so all values should be received and considered during path building 🫢.

crossCertificatePair: in conformant implementations, the crossCertificatePair is used to contain all of the following, except self-issued certificates issued to this certification authority: the certificates issued to this certification authority, plus the certificates issued by this certification authority to other certification authorities 🌸. Each attribute value is a structure with two elements. The issuedToThisCA element contains certificates issued to this certification authority by other certification authorities. The issuedByThisCA element contains certificates issued by this certification authority to other certification authorities. Both elements are labeled optional in the ASN.1 definition 🧩. If both elements are present in a single value, the issuer name in one certificate is required to match the subject name in the other and vice versa, and the subject public key in one certificate shall be capable of verifying the digital signature on the other certificate and vice versa πŸ”. Honestly, different standards have had different requirements about where this info could be found, which is so messy πŸ™ƒ. For example, the LDAP v2 schema [RFC2587] says the issuedToThisCA element (once called 'forward') of the crossCertificatePair attribute is mandatory, and the issuedByThisCA element (once called 'reverse') is optional. Meanwhile, Section 11.2.3 of [X.509] requires the issuedByThisCA element to be present if the CA issues a certificate to another CA and the subject is not a subordinate CA in a hierarchy πŸ“œ. Conformant directories behave as [X.509] requires, but robust path-building implementations may want to retrieve all certificates from the cACertificate and crossCertificatePair attributes so they get every possible certification authority certificate πŸ†.

certificateRevocationList: this attribute contains a certificate revocation list (CRL) 🚫. A CRL is defined in [RFC3280] as a time stamped list identifying revoked certificates, which is signed by a CA or CRL issuer and made freely available in a public repository. Each revoked certificate is identified in a CRL by its certificate serial number πŸ”’. There may be one or more CRLs in this attribute, and the values should be processed in accordance with [RFC3280].

authorityRevocationList: this attribute also contains CRLs 🫧. These CRLs hold revocation information about certificates issued to other CAs. There may be one or more CRLs in this attribute, and the values should be processed in accordance with [RFC3280].

Certification path processing systems that plan to interoperate with varying PKI structures and directory designs should, at a minimum, be able to retrieve and process the userCertificate, cACertificate, crossCertificatePair, certificateRevocationList, and authorityRevocationList attributes from directory entries 🎯.


6.2. Certificate Store Access via HTTP 🌸

another way to retrieve certificates is using HTTP as the interface for grabbing certificates and CRLs from PKI repositories 🌐. A current PKIX document [CERTSTORE] gives a protocol for a general-purpose interface capability for retrieving certificates and CRLs from PKI repositories. But since the [CERTSTORE] document is still a work in progress as of when this was written, no details are given here on how to use this mechanism for certificate and CRL retrieval 🚧. Instead, go check the [CERTSTORE] document or its current version πŸ‘€. Certification path processing systems may wish to implement support for this interface capability, especially if they'll be used in environments that provide HTTP-based access to certificates and CRLs ✨.


6.3. Authority Information Access πŸ¦‹

the authority information access (AIA) extension, defined within [RFC3280], tells you how to access CA information and services for the issuer of the certificate the extension appears in πŸ¦‹. If a certificate with an AIA extension contains an accessMethod defined with the id-ad-caIssuers OID, the AIA may be used to retrieve one or more certificates for the CA that issued the certificate containing the AIA extension πŸ“₯. The AIA will provide a uniform resource identifier (URI) [RFC3986] when certificates can be retrieved via LDAP, HTTP, or FTP. It will provide a directoryName when certificates can be retrieved via directory access protocol (DAP). It will provide an rfc822Name when certificates can be retrieved via electronic mail πŸ“§. Additionally, the AIA may specify the location of an OCSP [RFC2560] responder that can provide revocation information for the certificate πŸ”.

If it's present, AIA may give forward path-building implementations a direct link to a certificate for the issuer of a given certificate πŸ”—. So implementations may wish to support decoding the AIA extension and processing the LDAP, HTTP, FTP, DAP, or e-mail locators πŸ’Œ. Support for AIA is optional; [RFC3280] compliant implementations are not required to populate the AIA extension πŸ™…β€β™€οΈ. However, implementers of path-building and validation modules are strongly encouraged to support AIA, especially the HTTP transport. This gives you usability and interoperability with lots of existing PKIs 🌈.


6.4. Subject Information Access 🫢

the subject information access (SIA) extension, defined within [RFC3280], tells you how to access information and services for the subject of the certificate it appears in 🫢. If a certificate with an SIA extension contains an accessMethod defined with the id-ad-caRepository OID, the SIA may be used to locate one or more certificates (and possibly CRLs) for entities that were issued certificates by the subject πŸ—‚οΈ. The SIA will provide a uniform resource identifier (URI) [RFC3986] when data can be retrieved via LDAP, HTTP, or FTP. It will provide a directoryName when data can be retrieved via directory access protocol (DAP). It will provide an rfc822Name when data can be retrieved via electronic mail πŸ“¬.

If it's present, the SIA extension may give reverse path-building implementations the certificates they need to keep building the path 🧭. So implementations may wish to support decoding the SIA extension and processing the LDAP, HTTP, FTP, DAP, or e-mail locators πŸͺ„. Support for SIA is optional; [RFC3280] compliant implementations are not required to populate the SIA extension 🫠. However, implementers of path-building and validation modules are strongly encouraged to support SIA, especially the HTTP transport. This gives you usability and interoperability with many existing PKIs πŸ’–.


6.5. CRL Distribution Points πŸ‘‘

the CRL distribution points (CRLDP) extension, defined within [RFC3280], tells you how to access CRL info πŸ‘‘. If a CRLDP extension appears within a certificate, the CRL(s) it points to are generally the CRLs that would contain revocation information for the certificate πŸ“‹. The CRLDP extension may point to multiple distribution points where the CRL info can be obtained, and the certificate processing system should process the CRLDP extension in accordance with [RFC3280] 🧾. The most common distribution points contain URIs where the right CRL can be downloaded, and directory names that you can query in a directory to retrieve the CRL attributes from the matching entry πŸ“₯.

If it's present, CRLDP can give certificate processing implementations a link to CRL info for a given certificate πŸ”—. So implementations may wish to support decoding the CRLDP extension and using that info to retrieve CRLs. Support for CRLDP is optional, and [RFC3280] compliant implementations need not populate the CRLDP extension πŸ™†β€β™€οΈ. However, implementers of path-building and validation modules are strongly encouraged to support CRLDPs. At a minimum, developers are encouraged to consider supporting the LDAP and HTTP transports, since that gives you interoperability across a wide range of existing PKIs 🌍.


6.6. Data Obtained via Application Protocol ✨

lots of application protocols, like SSL/TLS and S/MIME, let one party hand certificates and CRLs over to another 🀝. Data delivered this way is generally super valuable to path-building software (it points toward valid paths!), so it should be stored and used accordingly πŸ’Ž.

Note: self-signed certificates obtained via application protocol are not trustworthy 🚨. Implementations should only consider the relying party's trust anchors when building paths πŸ›‘οΈ.

6.7. Proprietary Mechanisms πŸ’…

some certificate issuing systems and certificate processing systems may use proprietary retrieval mechanisms, like network mapped drives, databases, or other methods that aren't directly referenced in the IETF standards πŸ—„οΈ. Certificate processing systems may wish to support other proprietary mechanisms, but should only do so in addition to supporting standard retrieval mechanisms such as LDAP, AIA, and CRLDP (unless they're functioning in a closed environment) πŸ”’πŸ«Ά

7. Improving Retrieval Performance ✨

okay so speed is literally everything πŸ’… retrieval performance can get a glow-up through a few different mechanisms, like caches and setting a specific retrieval order. this section walks through some ways a certificate processing system can get faster while pulling PKI objects. ngl, slow systems are giving "nobody wants to use this" energy πŸ’€, so the systems are encouraged to do whatever they can to cut down the delays that come with asking external sources for data and waiting on it 🫢

7.1. Caching πŸŽ€

bestie, certificate processing systems in a non-hierarchical PKI will often need to grab certificates and certificate revocation lists (CRLs) from somewhere outside the application protocol. usually that's an X.500 or LDAP repository, an Internet URI [RFC3986], or some other non-local source 🌸 because connections take time to set up and transfers take time to finish, these systems ought to be as efficient as possible when pulling from outside sources. the best move for speed is honestly caching ⚑

here's the vibe: a system can cache data it got from external sources for some period of time, but never longer than the useful period of the data (aka an expired certificate need not be cached, it's over πŸ’€). yes, caching means more memory and disk use, but the savings from skipping network transmissions are huge, so it's worth it. also, CRLs are often issued and available before the nextUpdate date in the CRL, so implementations may want to grab those "fresher" CRLs before nextUpdate has passed 🌈

there are tons of ways to build a cache, and the specifics can be what makes one system different from another πŸ‘‘ still, here are some things implementers may want to think about:

  • If PKI objects are cached, the certification path-building mechanism should be able to examine and retrieve from the cache during path building. this lets the system find or kill one or more paths quickly without contacting a directory or other retrieval mechanism 🧚
  • Sharing caches between multiple users (via a local area network or LAN) may be useful if many users in one organization consistently perform PKI operations with another organization πŸ“
  • Caching not only PKI objects (such as certificates and CRLs) but also relationships between PKI objects (storing a link between a certificate and the issuer's certificate) may be useful. this linking might not always be the most correct or best relationship, but it could be one that worked in another scenario πŸ¦‹
  • Previously built paths and partial paths are super useful to cache, because they hold info on past successes or failures πŸ’œ also, if the cache is safe from unauthorized modifications, caching validation and signature checking status for certificates, CRLs, and paths can be stored too ✨

7.2. Retrieval Order 🌷

to be efficient, certificate processing systems are also encouraged to think about the order they retrieve PKI objects in, plus which mechanism they retrieve them from 🫢 if caching is in play, the caches can be checked for PKI objects before trying any other retrieval mechanism. if there are multiple caches (like local disk and network), check them from fastest to slowest based on how fast they're expected to return a result 🏎️ for example, if a system wants a certificate with a particular subject DN, it might check the local cache first, then the network cache, and then try directory retrieval. the details of each retrieval mechanism and how much it costs are up to the implementer 🌈

on top of ordering mechanisms, the system ought to rank the different external sources a PKI object can come from. if the AIA is in a certificate, with a URI [RFC3986] for the issuer's certificate, the system (if it's able to) may want to check local cache first, then use that URI (because it's expected to point straight at the exact certificate) before going digging through certificates that might be in a directory 🎯

if a directory is being consulted, it may be smart to pull attributes in a specific order too πŸ’… a highly cross-certified PKI structure leads to lots of possible certification paths, which can mean multiple validation attempts before a successful path shows up πŸ˜΅β€πŸ’« so cACertificate and userCertificate (which usually hold certificates from within the same 'realm') could be checked before trying to retrieve the crossCertificatePair values for an entry. another option is to grab all three attributes in one query, but tag the cross-certificates as such and only use them after the possibilities from the cACertificate attribute run out. the best approach depends on the app and the PKI environment, periodt πŸ’–

7.3. Parallel Fetching and Prefetching πŸš€

a big chunk of this document has been about a path-building algorithm that keeps the performance hit from network retrievals low, by avoiding those retrievals and using caches πŸ™ˆ another way to speed things up is to do network retrievals ahead of time (prefetching) or at the same time as other operations (parallel fetching). for example, if an email app gets a signed email message, it could download the certificates and CRLs it needs before the recipient opens (or tries to verify) the message. implementations that offer parallel and/or prefetching, along with a robust cache, can seriously improve performance and user experience ✨πŸ”₯


8. Security Considerations πŸ”’

okay this part is SERIOUS bestie, so read it all 😭 it's the one section you can't skip

8.1. General Considerations for Building a Certification Path πŸ›‘οΈ

so certification path building deals directly with security-relevant PKI data, but the PKI data itself doesn't need any special handling, because its integrity is locked in by the digital signature applied to it πŸ” the only exception is protecting the trust anchor public keys properly. these have to be kept safe and obtained out of band (e.g., not from an electronic mail message or a directory) with respect to the path-building module πŸ™…β€β™€οΈ

The biggest security risks in this document are about doing certification path validation while certification paths are being built. so, it's noted here that fully implemented certification path validation in accordance with [RFC3280] and [X.509] is required for certification path building, certification path validation, and the certificate-using application to all be properly secured. all of the Security Considerations listed in Section 9 of [RFC3280] apply equally here 🚨

also, just like any app that eats data from potentially untrusted network locations, certification path-building components should be carefully built to reduce or eliminate the chance of network-based exploits πŸ’€ for example, a badly implemented path-building module might not check the length of the CRLDP URI [RFC3986] before using the C function strcpy() to put the address in a 1024 byte buffer. a hacker could use that flaw to make a buffer overflow exploit by encoding malicious assembly code into the CRLDP of a certificate, then use that certificate to try an authentication. that kind of attack could hand the attacker system-level control and expose the sensitive data the PKI was meant to protect 😱🧨

path building can also be used to launch a denial of service (DOS) attack. this could happen if someone can make lots of simple requests that cause a server to do a bunch of path developments, each one eating up time and resources 🫠 servers can help by limiting how many resources they'll put toward path building, and by being able to cut those resources further when the load is heavy. standard DOS protections, like systems that identify and block attackers, can be useful too πŸ›‘

a DOS attack can also be made by presenting spurious CA certificates containing very large public keys. when the system tries to use that huge public key to verify the digital signature on more certificates, it can cause a long processing delay 🐒 there are two strategies to fix this. the first is to only do signature verifications after a complete path has been built, starting from the trust anchor. that way the spurious CA certificate gets kicked out before the large public key is ever used. the second strategy is to recognize keys longer than a certain size and simply reject them πŸ™…β€β™€οΈ

a similar DOS attack can happen with very large public keys in end entity certificates. if a system uses the public key in a certificate before building and validating that certificate's certification path, it can cause long processing delays too 😩 so to prevent this, the public key in an end entity certificate should not be used for any purpose until a complete certification path for that certificate has been built and validated πŸ’œ

8.2. Specific Considerations for Building Revocation Signer Certification Paths ✨

Okay bestie, this part is about the CRL Signer. If the CRL Signer's certificate (and its certification path) is not the same as the Certification Authority's certificate (and certification path), you should take extra care when building the CRL Signer certification path. 🧐

If nobody thinks about building that CRL Signer path, it could end up terminating at a different root, or going through a different path to the same root. 😬 If that's allowed to happen, the relying party might check the wrong revocation data, or even maliciously swapped data, and that's a denial of service or security breach waiting to happen. πŸ’€

Here's an example. Say this certification path gets built for E and it's valid for an example "high assurance" policy:

A->B->C->E

When the building and validation routine checks that E isn't revoked, C is the Certification Authority certificate. The path builder finds that the CRL for E is issued by C2, which has the subject name "C" but a different key from the one that signed E. C2 is the CRL Signer. πŸ•΅οΈβ€β™€οΈ A careless, unrestrictive path builder might then build a path like this for the CRL Signer C2 certificate:

X->Y->Z->C2

If a path like that gets through, you can't conclude anything about E's revocation status, because C2 is a different CA from C. πŸ™…β€β™€οΈ

Good news though: stopping this is actually easy, and the fix makes CRL Signer path building super efficient. πŸ’… If the CRL Signer certificate is identical to the Certification Authority certificate, just use the Certification Authority certification path to verify the CRL. No extra path building needed. ✨ If the CRL Signer certificate is not identical to the Certification Authority certificate, you should build a second path for the CRL Signer certificate, exactly the same way you would for any certificate, but with these extra guidelines:

  1. Trust Anchor: The CRL Signer's certification path should start with the same trust anchor as the Certification Authority's certification path. Any trust anchor certificate whose subject DN matches the Certification Authority's trust anchor should be considered acceptable, though it ranks lower than one with a matching public key and subject DN. πŸ”‘ Different trust anchor public keys are fine at the start of the CRL signer's path and the Certification Authority's path, but both keys must be trusted by the relying party, following the recommendations in Section 8.1.
  2. CA Name Matching: The subject DNs for all CA certificates in the two certification paths should match one-to-one (ignoring self-issued certificates) for the entire length of the shorter of the two paths. πŸͺž
  3. CRL Signer Certification Path Length: The length of the CRL Signer certification path (ignoring self-issued certificates) should be equal to or less than the length of the Certification Authority certification path plus (+) one. This lets a given Certification Authority issue a certificate to a delegated or subordinate CRL Signer. This setup is the maximum certification path length for a CRL Signer certificate. πŸ“

Why the first guideline matters: without it, any trusted CA could issue CRLs for any other CA, even if the PKIs have nothing to do with each other. 😱 For instance, one company could revoke certificates issued by another company if the relying party trusted the trust anchors from both. The first two guidelines also stop erroneous CRL checks, because global uniqueness of names is not guaranteed. πŸ™ˆ

The second guideline blocks roaming certification paths like the CRL Signer path from the earlier A->B->C->E example. It's super important that "ignoring self-issued certificates" gets implemented properly. Self-issued certificates get left out of the one-to-one name comparison so that key rollover can work. πŸ”„ A path-building algorithm may be optimized to only consider certificates with the acceptable subject DN for the given point in the CRL Signer certification path while it's building the path. πŸš€

The third and final guideline makes sure the CRL used is the intended one. Without a limit on the length of the CRL Signer certification path, the path could wander off into another domain and still pass the first two guidelines. πŸŒ€ Using the same A->B->C->E path, the Certification Authority C, and a CRL Signer C2, a CRL Signer path like this could pass the first two guidelines:

A->B->C->D->X->Y->RogueCA->C2

In that example, the trust anchor is identical for both paths, and the one-to-one name matching test passes for A->B->C. 😀 But accepting a path like that has obvious security consequences, so the third guideline exists to prevent it. Applying the second and third guidelines to that path, the path builder could have spotted it was unacceptable before building it, just by looking at the issuer DN in C2. Given the length and name guidelines, the path builder could tell that "RogueCA" isn't one of the possible names, by comparing it against the set of possible CRL Signer issuer DNs, which are A, B, or C. 🚫

Similar consideration should be given when building the path for the OCSP Responder certificate, when the CA is the OCSP Response Signer or the CA has delegated OCSP Response signing to another entity. πŸ¦‹


9. Acknowledgements 🫢

The authors send big thank-yous to David Lemire for co-authoring "Managing Interoperability in Non-Hierarchical Public Key Infrastructures," which the introductory sections borrowed from heavily. πŸ’œ

This document has also gotten a lot of love from the review and extra technical insight of Dr. Santosh Chokhani, Carl Wallace, Denis Pinkas, Steve Hanna, Alice Sturgeon, Russ Housley, and Tim Polk. πŸ‘‘


10. Normative References πŸ“š

[RFC3280]   Housley, R., Polk, W., Ford, W., and D. Solo, "Internet
            X.509 Public Key Infrastructure Certificate and
            Certificate Revocation List (CRL) Profile", RFC 3280,
            April 2002.

11. Informative References 🌸

[MINHPKIS]  Hesse, P., and D. Lemire, "Managing Interoperability in
            Non-Hierarchical Public Key Infrastructures", 2002
            Conference Proceedings of the Internet Society Network
            and Distributed System Security Symposium, February 2002.

[RFC1777]   Yeong, W., Howes, T., and S. Kille, "Lightweight
            Directory Access Protocol", RFC 1777, March 1995.

[RFC2560]   Myers, M., Ankney, R., Malpani, A., Galperin, S., and C.
            Adams, "X.509 Internet Public Key Infrastructure Online
            Certificate Status Protocol - OCSP", RFC 2560, June 1999.

[RFC2587]   Boeyen, S., Howes, T., and P. Richard, "Internet X.509
            Public Key Infrastructure LDAPv2 Schema", RFC 2587, June
            1999.

[RFC3377]   Hodges, J. and R. Morgan, "Lightweight Directory Access
            Protocol (v3): Technical Specification", RFC 3377,
            September 2002.

[RFC3820]   Tuecke, S., Welch, V., Engert, D., Pearlman, L., and M.
            Thompson, "Internet X.509 Public Key Infrastructure (PKI)
            Proxy Certificate Profile", RFC 3820, June 2004.

[RFC3986]   Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
            Resource Identifier (URI): Generic Syntax", STD 66, RFC
            3986, January 2005.

[X.501]     ITU-T Recommendation X.501: Information Technology - Open
            Systems Interconnection - The Directory: Models, 1993.

[X.509]     ITU-T Recommendation X.509 (2000 E): Information
            Technology - Open Systems Interconnection - The
            Directory: Authentication Framework, March 2000.

[PKIXALGS]  Bassham, L., Polk, W. and R. Housley, "Algorithms and
            Identifiers for the Internet X.509 Public Key
            Infrastructure Certificate and Certificate Revocation
            Lists (CRL) Profile", RFC 3279, April 2002.

[CERTSTORE] P. Gutmann, "Internet X.509 Public Key Infrastructure
            Operational Protocols: Certificate Store Access via
            HTTP", Work in Progress, August 2004.

Authors' Addresses πŸŽ€

Matt Cooper
Orion Security Solutions, Inc.
1489 Chain Bridge Rd, Ste. 300
McLean, VA  22101,  USA

Phone:  +1-703-917-0060
EMail:  mcooper@orionsec.com


Yuriy Dzambasow
A&N Associates, Inc.
999 Corporate Blvd Ste. 100
Linthicum, MD  21090,  USA

Phone:  +1-410-859-5449 x107
EMail:  yuriy@anassoc.com


Peter Hesse
Gemini Security Solutions, Inc.
4451 Brookfield Corporate Dr. Ste. 200
Chantilly, VA  20151,  USA

Phone:  +1-703-378-5808 x105
EMail:  pmhesse@geminisecurity.com


Susan Joseph
Van Dyke Technologies
6716 Alexander Bell Drive
Columbia, MD 21046

EMail:  susan.joseph@vdtg.com


Richard Nicholas
BAE Systems Information Technology
141 National Business Parkway, Ste. 210
Annapolis Junction, MD  20701,  USA

Phone:  +1-301-939-2722
EMail:  richard.nicholas@it.baesystems.com

Copyright (C) The Internet Society (2005). πŸ’–

This document is subject to the rights, licenses and restrictions in BCP 78. Except as set forth there, the authors keep all their rights. πŸ”

This document and the information in it are provided "AS IS." THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. πŸ™


Intellectual Property πŸ¦‹

The IETF takes no position on whether any Intellectual Property Rights or other rights that someone might claim over the technology in this document are valid or in scope. It also doesn't say whether a license for those rights is available, and it hasn't independently gone looking for any such rights. πŸ” You can find the procedures for rights in RFC documents in BCP 78 and BCP 79.

Copies of IPR disclosures sent to the IETF Secretariat, along with any assurances of licenses that will be made available, or the outcome of an attempt to get a general license or permission for implementers or users of this specification to use those proprietary rights, can be found in the IETF online IPR repository at http://www.ietf.org/ipr. πŸ“‚

The IETF invites anyone who knows about copyrights, patents, patent applications, or other proprietary rights that might cover technology needed to implement this standard to let them know. Send that information to the IETF at ietf-ipr@ietf.org. πŸ’Œ


Acknowledgement 🌈

Funding for the RFC Editor function is currently provided by the Internet Society. πŸ’œβœ¨

πŸ“¦ where this page comes from