summaryrefslogtreecommitdiff
path: root/doc/rfc/rfc9618.txt
diff options
context:
space:
mode:
Diffstat (limited to 'doc/rfc/rfc9618.txt')
-rw-r--r--doc/rfc/rfc9618.txt927
1 files changed, 927 insertions, 0 deletions
diff --git a/doc/rfc/rfc9618.txt b/doc/rfc/rfc9618.txt
new file mode 100644
index 0000000..a4d39a5
--- /dev/null
+++ b/doc/rfc/rfc9618.txt
@@ -0,0 +1,927 @@
+
+
+
+
+Internet Engineering Task Force (IETF) D. Benjamin
+Request for Comments: 9618 Google LLC
+Updates: 5280 August 2024
+Category: Standards Track
+ISSN: 2070-1721
+
+
+ Updates to X.509 Policy Validation
+
+Abstract
+
+ This document updates RFC 5280 to replace the algorithm for X.509
+ policy validation with an equivalent, more efficient algorithm. The
+ original algorithm built a structure that scaled exponentially in the
+ worst case, leaving implementations vulnerable to denial-of-service
+ attacks.
+
+Status of This Memo
+
+ This is an Internet Standards Track document.
+
+ This document is a product of the Internet Engineering Task Force
+ (IETF). It represents the consensus of the IETF community. It has
+ received public review and has been approved for publication by the
+ Internet Engineering Steering Group (IESG). Further information on
+ Internet Standards is available in Section 2 of RFC 7841.
+
+ Information about the current status of this document, any errata,
+ and how to provide feedback on it may be obtained at
+ https://www.rfc-editor.org/info/rfc9618.
+
+Copyright Notice
+
+ Copyright (c) 2024 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (https://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document. Code Components extracted from this document must
+ include Revised BSD License text as described in Section 4.e of the
+ Trust Legal Provisions and are provided without warranty as described
+ in the Revised BSD License.
+
+Table of Contents
+
+ 1. Introduction
+ 1.1. Summary of Changes from RFC 5280
+ 2. Conventions and Definitions
+ 3. Denial-of-Service Vulnerability
+ 3.1. Policy Trees
+ 3.2. Exponential Growth
+ 3.3. Attack Vector
+ 4. Avoiding Exponential Growth
+ 4.1. Policy Graphs
+ 4.2. Verification Outputs
+ 5. Updates to RFC 5280
+ 5.1. Updates to Section 6.1
+ 5.2. Updates to Section 6.1.2
+ 5.3. Updates to Section 6.1.3
+ 5.4. Updates to Section 6.1.4
+ 5.5. Updates to Section 6.1.5
+ 5.6. Updates to Section 6.1.6
+ 6. Other Mitigations
+ 6.1. Verify Signatures First
+ 6.2. Limit Certificate Depth
+ 6.3. Limit Policy Tree Size
+ 6.4. Inhibit Policy Mapping
+ 6.5. Disable Policy Checking
+ 7. Security Considerations
+ 8. IANA Considerations
+ 9. References
+ 9.1. Normative References
+ 9.2. Informative References
+ Acknowledgements
+ Author's Address
+
+1. Introduction
+
+ [RFC5280] defines a suite of extensions for determining the policies
+ that apply to a certification path. A policy is described by an
+ object identifier (OID) and a set of optional qualifiers.
+
+ Policy validation in [RFC5280] is complex. As an overview, the
+ certificate policies extension (Section 4.2.1.4 of [RFC5280])
+ describes the policies, with optional qualifiers, under which an
+ individual certificate was issued. The policy mappings extension
+ (Section 4.2.1.5 of [RFC5280]) allows a CA certificate to map its
+ policy OIDs to other policy OIDs in certificates that it issues.
+ Subject to these mappings and other extensions, the certification
+ path's overall policy set is the intersection of policies asserted by
+ each certificate in the path.
+
+ The procedure in Section 6.1 of [RFC5280] determines this set in the
+ course of certification path validation. It does so by building a
+ policy tree containing policies asserted by each certificate and the
+ mappings between them. This tree can grow exponentially in the depth
+ of the certification path, which means an attacker, with a small
+ input, can cause a path validator to consume excessive memory and
+ computational resources. This cost asymmetry can lead to a denial-
+ of-service vulnerability in X.509-based applications, such as
+ [CVE-2023-0464] and [CVE-2023-23524].
+
+ Section 3 describes this vulnerability. Section 4.1 describes the
+ primary mitigation for this vulnerability, a replacement for the
+ policy tree structure. Section 5 provides updates to [RFC5280] that
+ implement this change. Finally, Section 6 discusses alternative
+ mitigation strategies for X.509 applications.
+
+1.1. Summary of Changes from RFC 5280
+
+ The algorithm for processing certificate policies and policy mappings
+ is replaced with one that builds an equivalent but much more
+ efficient structure. This new algorithm does not change the validity
+ status of any certification path or which certificate policies are
+ valid for it.
+
+2. Conventions and Definitions
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
+ "OPTIONAL" in this document are to be interpreted as described in
+ BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all
+ capitals, as shown here.
+
+3. Denial-of-Service Vulnerability
+
+ This section discusses how the path validation algorithm defined in
+ Section 6.1.2 of [RFC5280] can lead to a denial-of-service
+ vulnerability in X.509-based applications.
+
+3.1. Policy Trees
+
+ Section 6.1.2 of [RFC5280] constructs the valid_policy_tree, a tree
+ of certificate policies, during certification path validation. The
+ nodes at any given depth in the tree correspond to policies asserted
+ by a certificate in the certification path. A node's parent policy
+ is the policy in the issuer certificate that was mapped to this
+ policy, and a node's children are the policies the node was mapped to
+ in the subject certificate.
+
+ For example, suppose a certification path contains:
+
+ * An intermediate certificate that asserts the following policy
+ OIDs: OID1, OID2, and OID5. It contains mappings from OID1 to
+ OID3 and from OID1 to OID4.
+
+ * An end-entity certificate that asserts the following policy OIDs:
+ OID2, OID3, and OID6.
+
+ This would result in the tree shown below. Note that OID5 and OID6
+ are not included or mapped across the whole path, so they do not
+ appear in the final structure.
+
+ +-----------+
+ Root: | anyPolicy |
+ +-----------+
+ |{anyPolicy}|
+ +-----------+
+ / \
+ / \
+ v v
+ +------------+ +------------+
+ Intermediate: | OID1 | | OID2 |
+ (OID5 discarded) +------------+ +------------+
+ |{OID3, OID4}| | {OID2} |
+ +------------+ +------------+
+ | |
+ | |
+ v v
+ +------------+ +------------+
+ End-entity: | OID3 | | OID2 |
+ (OID6 discarded) +------------+ +------------+
+
+ The complete algorithm for building this structure is described in
+ steps (d), (e), and (f) in Section 6.1.3 of [RFC5280]; steps (h),
+ (i), and (j) in Section 6.1.4 of [RFC5280]; and steps (a), (b), and
+ (g) in Section 6.1.5 of [RFC5280].
+
+3.2. Exponential Growth
+
+ The valid_policy_tree grows exponentially in the worst case. In step
+ (d.1) in Section 6.1.3 of [RFC5280], a single policy P can produce
+ multiple child nodes if multiple issuer policies map to P. This can
+ cause the tree size to increase in size multiplicatively at each
+ level.
+
+ In particular, consider a certificate chain where every intermediate
+ certificate asserts policies OID1 and OID2 and then contains the full
+ Cartesian product of mappings:
+
+ * OID1 maps to OID1
+
+ * OID1 maps to OID2
+
+ * OID2 maps to OID1
+
+ * OID2 maps to OID2
+
+ At each depth, the tree would double in size. For example, if there
+ are two intermediate certificates and one end-entity certificate, the
+ resulting tree would be as depicted in Figure 1.
+
+ +-----------------------+
+ | anyPolicy |
+ +-----------------------+
+ | {anyPolicy} |
+ +-----------------------+
+ / \
+ / \
+ v v
+ +------------+ +------------+
+ | OID1 | | OID2 |
+ +------------+ +------------+
+ |{OID1, OID2}| |{OID1, OID2}|
+ +------------+ +------------+
+ / \ / \
+ / \ / \
+ v v v v
+ +------------+ +------------+ +------------+ +------------+
+ | OID1 | | OID2 | | OID1 | | OID2 |
+ +------------+ +------------+ +------------+ +------------+
+ |{OID1, OID2}| |{OID1, OID2}| |{OID1, OID2}| |{OID1, OID2}|
+ +------------+ +------------+ +------------+ +------------+
+ | | | | | | | |
+ v v v v v v v v
+ +------+ +------+ +------+ +------+ +------+ +------+ +------+ +------+
+ | OID1 | | OID2 | | OID1 | | OID2 | | OID1 | | OID2 | | OID1 | | OID2 |
+ +------+ +------+ +------+ +------+ +------+ +------+ +------+ +------+
+
+ Figure 1: An Example X.509 Policy Tree with Exponential Growth
+
+3.3. Attack Vector
+
+ An attacker can use the exponential growth to mount a denial-of-
+ service attack against an X.509-based application. The attacker
+ sends a certificate chain as described in Section 3.2 and triggers
+ the target application's certificate validation process. For
+ example, the target application may be a TLS server [RFC8446] that
+ performs client certificate validation. The target application will
+ consume far more resources processing the input than the attacker
+ consumed to send it, which prevents the target application from
+ servicing other clients.
+
+4. Avoiding Exponential Growth
+
+ This document mitigates the denial-of-service vulnerability described
+ in Section 3 by replacing the policy tree with a policy graph
+ structure, which is described in this section. The policy graph
+ grows linearly instead of exponentially. This removes the asymmetric
+ cost in policy validation.
+
+ X.509 implementations SHOULD perform policy validation by building a
+ policy graph, following the procedure described in Section 5. This
+ replacement procedure computes the same policies as in [RFC5280], but
+ one of the outputs is in a different form. See Section 4.2 for
+ details. Section 6 describes alternative mitigations for
+ implementations that depend on the original, exponential-sized
+ output.
+
+4.1. Policy Graphs
+
+ The tree structure in [RFC5280] is an unnecessarily inefficient
+ representation of a certification path's policy mappings. When
+ multiple issuer policies map to a single subject policy, the subject
+ policy will correspond to multiple duplicate nodes in the policy
+ tree. Children of the subject policy are then duplicated
+ recursively. This duplication is the source of the exponential
+ growth described in Section 3.2.
+
+ A policy graph represents the same information with a directed
+ acyclic graph of policy nodes. It eliminates this duplication by
+ using a single node with multiple parents. See Section 5 for the
+ procedure for building this structure. Figure 2 shows the updated
+ representation of the example in Figure 1.
+
+ +-----------+
+ | anyPolicy |
+ +-----------+
+ |{anyPolicy}|
+ +-----------+
+ / \
+ / \
+ v v
+ +------------+ +------------+
+ | OID1 | | OID2 |
+ +------------+ +------------+
+ |{OID1, OID2}| |{OID1, OID2}|
+ +------------+ +------------+
+ | \ / |
+ | \ / |
+ | \/ |
+ | /\ |
+ | / \ |
+ v v v v
+ +------------+ +------------+
+ | OID1 | | OID2 |
+ +------------+ +------------+
+ |{OID1, OID2}| |{OID1, OID2}|
+ +------------+ +------------+
+ | \ / |
+ | \ / |
+ | \/ |
+ | /\ |
+ | / \ |
+ v v v v
+ +------------+ +------------+
+ | OID1 | | OID2 |
+ +------------+ +------------+
+
+ Figure 2: A More Efficient Representation of an X.509 Policy Tree
+
+ This graph's size is bounded linearly by the total number of
+ certificate policies (Section 4.2.1.4 of [RFC5280]) and policy
+ mappings (Section 4.2.1.5 of [RFC5280]). The policy tree in
+ [RFC5280] is the tree of all paths from the root to a leaf in the
+ policy graph, so no information is lost in the graph representation.
+
+4.2. Verification Outputs
+
+ Section 6.1.6 of [RFC5280] describes the entire valid_policy_tree
+ structure as an output of the verification process. However,
+ Section 12.2 of [X.509] only describes the following as outputs: the
+ authorities-constrained policies, the user-constrained policies, and
+ their associated qualifiers.
+
+ As the valid_policy_tree is the exponential structure, computing it
+ reintroduces the denial-of-service vulnerability. X.509
+ implementations SHOULD NOT output the entire valid_policy_tree
+ structure; instead, they SHOULD limit output to just the set of
+ authorities-constrained and/or user-constrained policies, as
+ described in [X.509]. Sections 5.6 and 6 discuss other mitigations
+ for applications where this option is not available.
+
+ X.509 implementations MAY omit policy qualifiers from the output to
+ simplify processing. Note that Section 4.2.1.4 of [RFC5280] already
+ recommends that certification authorities omit policy qualifiers from
+ policy information terms.
+
+5. Updates to RFC 5280
+
+ This section provides updates to [RFC5280]. These updates implement
+ the changes described in Section 4.
+
+5.1. Updates to Section 6.1
+
+ Section 6.1 of [RFC5280] is updated as follows:
+
+ OLD:
+
+ | A particular certification path may not, however, be appropriate
+ | for all applications. Therefore, an application MAY augment this
+ | algorithm to further limit the set of valid paths. The path
+ | validation process also determines the set of certificate policies
+ | that are valid for this path, based on the certificate policies
+ | extension, policy mappings extension, policy constraints
+ | extension, and inhibit anyPolicy extension. To achieve this, the
+ | path validation algorithm constructs a valid policy tree. If the
+ | set of certificate policies that are valid for this path is not
+ | empty, then the result will be a valid policy tree of depth n,
+ | otherwise the result will be a null valid policy tree.
+
+ NEW:
+
+ | A particular certification path may not, however, be appropriate
+ | for all applications. Therefore, an application MAY augment this
+ | algorithm to further limit the set of valid paths. The path
+ | validation process also determines the set of certificate policies
+ | that are valid for this path, based on the certificate policies
+ | extension, policy mappings extension, policy constraints
+ | extension, and inhibit anyPolicy extension. To achieve this, the
+ | path validation algorithm constructs a valid policy set, which may
+ | be empty if no certificate policies are valid for this path.
+
+5.2. Updates to Section 6.1.2
+
+ The following replaces entry (a) in Section 6.1.2 of [RFC5280]:
+
+ | (a) valid_policy_graph: A directed acyclic graph of certificate
+ | policies with their optional qualifiers; each of the leaves
+ | of the graph represents a valid policy at this stage in the
+ | certification path validation. If valid policies exist at
+ | this stage in the certification path validation, the depth of
+ | the graph is equal to the number of certificates in the chain
+ | that have been processed. If valid policies do not exist at
+ | this stage in the certification path validation, the graph is
+ | set to NULL. Once the graph is set to NULL, policy
+ | processing ceases. Implementations MAY omit qualifiers if
+ | not returned in the output.
+ |
+ | Each node in the valid_policy_graph includes three data
+ | objects: the valid policy, a set of associated policy
+ | qualifiers, and a set of one or more expected policy values.
+ |
+ | Nodes in the graph can be divided into depths, numbered
+ | starting from zero. A node at depth x can have zero or more
+ | children at depth x+1 and, with the exception of depth zero,
+ | one or more parents at depth x-1. No other edges between
+ | nodes may exist.
+ |
+ | If the node is at depth x, the components of the node have
+ | the following semantics:
+ |
+ | (1) The valid_policy is a single policy OID representing a
+ | valid policy for the path of length x.
+ |
+ | (2) The qualifier_set is a set of policy qualifiers
+ | associated with the valid policy in certificate x. It
+ | is only necessary to maintain this field if policy
+ | qualifiers are returned to the application. See
+ | Section 6.1.5, step (g).
+ |
+ | (3) The expected_policy_set contains one or more policy OIDs
+ | that would satisfy this policy in the certificate x+1.
+ |
+ | The initial value of the valid_policy_graph is a single node
+ | with valid_policy anyPolicy, an empty qualifier_set, and an
+ | expected_policy_set with the single value anyPolicy. This
+ | node is considered to be at depth zero.
+ |
+ | The graph additionally satisfies the following invariants:
+ |
+ | * For any depth x and policy OID P-OID, there is at most one
+ | node at depth x whose valid_policy is P-OID.
+ |
+ | * The expected_policy_set of a node whose valid_policy is
+ | anyPolicy is always {anyPolicy}.
+ |
+ | * A node at depth x whose valid_policy is anyPolicy, except
+ | for the one at depth zero, always has exactly one parent:
+ | a node at depth x-1 whose valid_policy is also anyPolicy.
+ |
+ | * Each node at depth greater than 0 has either one or more
+ | parent nodes whose valid_policy is not anyPolicy or a
+ | single parent node whose valid_policy is anyPolicy. That
+ | is, a node cannot simultaneously be a child of both
+ | anyPolicy and some non-anyPolicy OID.
+ |
+ | Figure 3 is a graphic representation of the initial state of
+ | the valid_policy_graph. Additional figures will use this
+ | format to describe changes in the valid_policy_graph during
+ | path processing.
+ |
+ | +----------------+
+ | | anyPolicy | <---- valid_policy
+ | +----------------+
+ | | {} | <---- qualifier_set
+ | +----------------+
+ | | {anyPolicy} | <---- expected_policy_set
+ | +----------------+
+ |
+ | Figure 3: Initial Value of the valid_policy_graph State
+ | Variable
+
+5.3. Updates to Section 6.1.3
+
+ The following replaces steps (d), (e), and (f) in Section 6.1.3 of
+ [RFC5280]:
+
+ | (d) If the certificate policies extension is present in the
+ | certificate and the valid_policy_graph is not NULL, process
+ | the policy information by performing the following steps in
+ | order:
+ |
+ | (1) For each policy P not equal to anyPolicy in the
+ | certificate policies extension, let P-OID denote the OID
+ | for policy P and P-Q denote the qualifier set for policy
+ | P. Perform the following steps in order:
+ |
+ | (i) Let parent_nodes be the nodes at depth i-1 in the
+ | valid_policy_graph where P-OID is in the
+ | expected_policy_set. If parent_nodes is not
+ | empty, create a child node as follows: set the
+ | valid_policy to P-OID, set the qualifier_set to
+ | P-Q, set the expected_policy_set to {P-OID}, and
+ | set the parent nodes to parent_nodes.
+ |
+ | For example, consider a valid_policy_graph with a
+ | node of depth i-1 where the expected_policy_set is
+ | {Gold, White} and a second node where the
+ | expected_policy_set is {Gold, Yellow}. Assume the
+ | certificate policies Gold and Silver appear in the
+ | certificate policies extension of certificate i.
+ | The Gold policy is matched, but the Silver policy
+ | is not. This rule will generate a child node of
+ | depth i for the Gold policy. The result is shown
+ | as Figure 4.
+ |
+ | +-----------------+ +-----------------+
+ | | Red | | Blue |
+ | +-----------------+ +-----------------+
+ | | {} | | {} | depth i-1
+ | +-----------------+ +-----------------+
+ | | {Gold, White} | | {Gold, Yellow} |
+ | +-----------------+ +-----------------+
+ | \ /
+ | \ /
+ | \ /
+ | v v
+ | +-----------------+
+ | | Gold |
+ | +-----------------+
+ | | {} | depth i
+ | +-----------------+
+ | | {Gold} |
+ | +-----------------+
+ |
+ | Figure 4: Processing an Exact Match
+ |
+ | (ii) If there was no match in step (i) and the
+ | valid_policy_graph includes a node of depth i-1
+ | with the valid_policy anyPolicy, generate a child
+ | node with the following values: set the
+ | valid_policy to P-OID, set the qualifier_set to
+ | P-Q, set the expected_policy_set to {P-OID}, and
+ | set the parent node to the anyPolicy node at depth
+ | i-1.
+ |
+ | For example, consider a valid_policy_graph with a
+ | node of depth i-1 where the valid_policy is
+ | anyPolicy. Assume the certificate policies Gold
+ | and Silver appear in the certificate policies
+ | extension of certificate i. The Gold policy does
+ | not have a qualifier, but the Silver policy has
+ | the qualifier Q-Silver. If Gold and Silver were
+ | not matched in (i) above, this rule will generate
+ | two child nodes of depth i, one for each policy.
+ | The result is shown as Figure 5.
+ |
+ | +-----------------+
+ | | anyPolicy |
+ | +-----------------+
+ | | {} |
+ | +-----------------+ depth i-1
+ | | {anyPolicy} |
+ | +-----------------+
+ | / \
+ | / \
+ | / \
+ | v v
+ | +-----------------+ +-----------------+
+ | | Gold | | Silver |
+ | +-----------------+ +-----------------+
+ | | {} | | {Q-Silver} | depth i
+ | +-----------------+ +-----------------+
+ | | {Gold} | | {Silver} |
+ | +-----------------+ +-----------------+
+ |
+ | Figure 5: Processing Unmatched Policies When a
+ | Leaf Node Specifies anyPolicy
+ |
+ | (2) If the certificate policies extension includes the
+ | policy anyPolicy with the qualifier set AP-Q and either
+ | (a) inhibit_anyPolicy is greater than 0 or (b) i<n and
+ | the certificate is self-issued, then:
+ |
+ | For each policy OID P-OID (including anyPolicy) that
+ | appears in the expected_policy_set of some node in the
+ | valid_policy_graph for depth i-1, if P-OID does not
+ | appear as the valid_policy of some node at depth i,
+ | create a single child node with the following values:
+ | set the valid_policy to P-OID, set the qualifier_set to
+ | AP-Q, set the expected_policy_set to {P-OID}, and set
+ | the parents to the nodes at depth i-1 where P-OID
+ | appears in expected_policy_set.
+ |
+ | This is equivalent to running step (1) above as if the
+ | certificate policies extension contained a policy with
+ | OID P-OID and qualifier set AP-Q.
+ |
+ | For example, consider a valid_policy_graph with a node
+ | of depth i-1 where the expected_policy_set is {Gold,
+ | Silver} and a second node of depth i-1 where the
+ | expected_policy_set is {Gold}. Assume anyPolicy appears
+ | in the certificate policies extension of certificate i
+ | with policy qualifiers AP-Q, but Gold and Silver do not
+ | appear. This rule will generate two child nodes of
+ | depth i, one for each policy. The result is shown below
+ | as Figure 6.
+ |
+ | +-----------------+ +-----------------+
+ | | Red | | Blue |
+ | +-----------------+ +-----------------+
+ | | {} | | {} | depth i-1
+ | +-----------------+ +-----------------+
+ | | {Gold, Silver} | | {Gold} |
+ | +-----------------+ +-----------------+
+ | | \ |
+ | | \ |
+ | | \ |
+ | | \ |
+ | | \ |
+ | v v v
+ | +-----------------+ +-----------------+
+ | | Silver | | Gold |
+ | +-----------------+ +-----------------+
+ | | {AP-Q} | | {AP-Q} | depth i
+ | +-----------------+ +-----------------+
+ | | {Silver} | | {Gold} |
+ | +-----------------+ +-----------------+
+ |
+ | Figure 6: Processing Unmatched Policies When the
+ | Certificate Policies Extension Specifies anyPolicy
+ |
+ | (3) If there is a node in the valid_policy_graph of depth
+ | i-1 or less without any child nodes, delete that node.
+ | Repeat this step until there are no nodes of depth i-1
+ | or less without children.
+ |
+ | For example, consider the valid_policy_graph shown in
+ | Figure 7 below. The two nodes at depth i-1 that are
+ | marked with an 'X' have no children, and they are
+ | deleted. Applying this rule to the resulting graph will
+ | cause the nodes at depth i-2 that is marked with a 'Y'
+ | to be deleted. In the resulting graph, there are no
+ | nodes of depth i-1 or less without children, and this
+ | step is complete.
+ |
+ | +-----------+
+ | | | depth i-3
+ | +-----------+
+ | / | \
+ | / | \
+ | v v v
+ | +-----------+ +-----------+ +-----------+
+ | | | | | | Y | depth i-2
+ | +-----------+ +-----------+ +-----------+
+ | | \ | |
+ | | \ | |
+ | v v v v
+ | +-----------+ +-----------+ +-----------+
+ | | X | | | | X | depth i-1
+ | +-----------+ +-----------+ +-----------+
+ | / | \
+ | / | \
+ | v v v
+ | +-----------+ +-----------+ +-----------+
+ | | | | | | | depth i
+ | +-----------+ +-----------+ +-----------+
+ |
+ | Figure 7: Pruning the valid_policy_graph
+ |
+ | (e) If the certificate policies extension is not present, set the
+ | valid_policy_graph to NULL.
+ |
+ | (f) Verify that either explicit_policy is greater than 0 or the
+ | valid_policy_graph is not equal to NULL.
+
+ The text following step (f) in Section 6.1.3 of [RFC5280], beginning
+ with "If any of steps (a), (b), (c), or (f) fails", is left
+ unmodified.
+
+5.4. Updates to Section 6.1.4
+
+ The following replaces step (b) in Section 6.1.4 of [RFC5280]:
+
+ | (b) If a policy mappings extension is present, then for each
+ | issuerDomainPolicy ID-P in the policy mappings extension:
+ |
+ | (1) If the policy_mapping variable is greater than 0 and
+ | there is a node in the valid_policy_graph of depth i
+ | where ID-P is the valid_policy, set expected_policy_set
+ | to the set of subjectDomainPolicy values that are
+ | specified as equivalent to ID-P by the policy mappings
+ | extension.
+ |
+ | (2) If the policy_mapping variable is greater than 0 and no
+ | node of depth i in the valid_policy_graph has a
+ | valid_policy of ID-P but there is a node of depth i with
+ | a valid_policy of anyPolicy, then generate a child node
+ | of the node of depth i-1 that has a valid_policy of
+ | anyPolicy as follows:
+ |
+ | (i) set the valid_policy to ID-P;
+ |
+ | (ii) set the qualifier_set to the qualifier set of the
+ | policy anyPolicy in the certificate policies
+ | extension of certificate i; and
+ |
+ | (iii) set the expected_policy_set to the set of
+ | subjectDomainPolicy values that are specified as
+ | equivalent to ID-P by the policy mappings
+ | extension.
+ |
+ | (3) If the policy_mapping variable is equal to 0:
+ |
+ | (i) delete the node, if any, of depth i in the
+ | valid_policy_graph where ID-P is the valid_policy.
+ |
+ | (ii) If there is a node in the valid_policy_graph of
+ | depth i-1 or less without any child nodes, delete
+ | that node. Repeat this step until there are no
+ | nodes of depth i-1 or less without children.
+
+5.5. Updates to Section 6.1.5
+
+ The following replaces step (g) in Section 6.1.5 of [RFC5280]:
+
+ | (g) Calculate the user_constrained_policy_set as follows. The
+ | user_constrained_policy_set is a set of policy OIDs, along
+ | with associated policy qualifiers.
+ |
+ | (1) If the valid_policy_graph is NULL, set
+ | valid_policy_node_set to the empty set.
+ |
+ | (2) If the valid_policy_graph is not NULL, set
+ | valid_policy_node_set to the set of policy nodes whose
+ | valid_policy is not anyPolicy and whose parent list is a
+ | single node with valid_policy of anyPolicy.
+ |
+ | (3) If the valid_policy_graph is not NULL and contains a
+ | node of depth n with the valid_policy anyPolicy, add it
+ | to valid_policy_node_set.
+ |
+ | (4) Compute authority_constrained_policy_set, a set of
+ | policy OIDs and associated qualifiers as follows. For
+ | each node in valid_policy_node_set:
+ |
+ | (i) Add the node's valid_policy to
+ | authority_constrained_policy_set.
+ |
+ | (ii) Collect all qualifiers in the node, its ancestors,
+ | and descendants and associate them with
+ | valid_policy. Applications that do not use policy
+ | qualifiers MAY skip this step to simplify
+ | processing.
+ |
+ | (5) Set user_constrained_policy_set to
+ | authority_constrained_policy_set.
+ |
+ | (6) If the user-initial-policy-set is not anyPolicy:
+ |
+ | (i) Remove any elements of user_constrained_policy_set
+ | that do not appear in user-initial-policy-set.
+ |
+ | (ii) If anyPolicy appears in
+ | authority_constrained_policy_set with qualifiers
+ | AP-Q, for each OID P-OID in user-initial-policy-
+ | set that does not appear in
+ | user_constrained_policy_set, add P-OID with
+ | qualifiers AP-Q to user_constrained_policy_set.
+
+ In addition, the final paragraph in Section 6.1.5 of [RFC5280] is
+ updated as follows:
+
+ OLD:
+
+ | If either (1) the value of explicit_policy variable is greater
+ | than zero or (2) the valid_policy_tree is not NULL, then path
+ | processing has succeeded.
+
+ NEW:
+
+ | If either (1) the value of explicit_policy is greater than zero,
+ | or (2) the user_constrained_policy_set is not empty, then path
+ | processing has succeeded.
+
+5.6. Updates to Section 6.1.6
+
+ The following replaces Section 6.1.6 of [RFC5280]:
+
+ | If path processing succeeds, the procedure terminates, returning a
+ | success indication together with the final value of the
+ | user_constrained_policy_set, the working_public_key, the
+ | working_public_key_algorithm, and the
+ | working_public_key_parameters.
+ |
+ | Note that the original procedure described in [RFC5280] included a
+ | valid_policy_tree structure as part of the output. This structure
+ | grows exponentially in the size of the input, so computing it
+ | risks denial-of-service vulnerabilities in X.509-based
+ | applications, such as [CVE-2023-0464] and [CVE-2023-23524].
+ | Accordingly, this output is deprecated. Computing this structure
+ | is NOT RECOMMENDED.
+ |
+ | An implementation that requires valid_policy_tree for
+ | compatibility with legacy systems may compute it from
+ | valid_policy_graph by recursively duplicating every multi-parent
+ | node. This may be done on-demand when the calling application
+ | first requests this output. However, this computation may consume
+ | exponential time and memory, so such implementations SHOULD
+ | mitigate denial-of-service attacks in other ways, such as by
+ | limiting the depth or size of the tree.
+
+6. Other Mitigations
+
+ X.509 implementations that are unable to switch to the policy graph
+ structure SHOULD mitigate the denial-of-service attack in other ways.
+ This section describes alternate mitigation and partial mitigation
+ strategies.
+
+6.1. Verify Signatures First
+
+ X.509 validators SHOULD verify signatures in certification paths
+ before or in conjunction with policy verification. This limits the
+ attack to entities in control of CA certificates. For some
+ applications, this may be sufficient to mitigate the attack.
+ However, other applications may still be impacted, for example:
+
+ * Any application that evaluates an untrusted PKI, such as a hosting
+ provider that evaluates a customer-supplied PKI
+
+ * Any application that evaluates an otherwise trusted PKI that
+ includes untrusted entities with technically constrained
+ intermediate certificates. If the intermediates do not constrain
+ policy mapping or path length, those entities may be able to
+ perform this attack.
+
+6.2. Limit Certificate Depth
+
+ The policy tree grows exponentially in the depth of a certification
+ path, so limiting the depth and certificate size can mitigate the
+ attack.
+
+ However, this option may not be viable for all applications. Too low
+ of a limit may reject existing paths that the application wishes to
+ accept. Too high of a limit may still admit a denial-of-service
+ attack for the application. By modifying the example in Section 3.2
+ to increase the number of policies asserted in each certificate, an
+ attacker could still achieve O(N^(depth/2)) scaling.
+
+6.3. Limit Policy Tree Size
+
+ The attack can be mitigated by limiting the number of nodes in the
+ policy tree and rejecting the certification path if this limit is
+ reached. This limit should be set high enough to still admit
+ existing valid certification paths for the application but low enough
+ to no longer admit a denial-of-service attack.
+
+6.4. Inhibit Policy Mapping
+
+ If policy mapping is disabled via the initial-policy-mapping-inhibit
+ setting (see Section 6.1.1 of [RFC5280]), the attack is mitigated.
+ This also significantly simplifies the X.509 implementation, which
+ reduces the risk of other security bugs. However, this will break
+ compatibility with any existing certification paths that rely on
+ policy mapping.
+
+ To facilitate this mitigation, certificate authorities SHOULD NOT
+ issue certificates with the policy mappings extension
+ (Section 4.2.1.5 of [RFC5280]). Applications maintaining policies
+ for accepted trust anchors are RECOMMENDED to forbid this extension
+ in participating certificate authorities.
+
+6.5. Disable Policy Checking
+
+ An X.509 validator can mitigate this attack by disabling policy
+ validation entirely. This may be viable for applications that do not
+ require policy validation. In this case, critical policy-related
+ extensions, notably the policy constraints extension
+ (Section 4.2.1.11 of [RFC5280]), MUST be treated as unrecognized
+ extensions as described in Section 4.2 of [RFC5280] and be rejected.
+
+7. Security Considerations
+
+ Section 3 discusses how the policy tree algorithm in [RFC5280] can
+ lead to denial-of-service vulnerabilities in X.509-based
+ applications, such as [CVE-2023-0464] and [CVE-2023-23524].
+
+ Section 5 replaces this algorithm to avoid this issue. As discussed
+ in Section 4.1, the new structure scales linearly with the input.
+ This means input limits in X.509 validators will more naturally bound
+ processing time, thus avoiding these vulnerabilities.
+
+8. IANA Considerations
+
+ This document has no IANA actions.
+
+9. References
+
+9.1. Normative References
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119,
+ DOI 10.17487/RFC2119, March 1997,
+ <https://www.rfc-editor.org/info/rfc2119>.
+
+ [RFC5280] Cooper, D., Santesson, S., Farrell, S., Boeyen, S.,
+ Housley, R., and W. Polk, "Internet X.509 Public Key
+ Infrastructure Certificate and Certificate Revocation List
+ (CRL) Profile", RFC 5280, DOI 10.17487/RFC5280, May 2008,
+ <https://www.rfc-editor.org/info/rfc5280>.
+
+ [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
+ 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
+ May 2017, <https://www.rfc-editor.org/info/rfc8174>.
+
+9.2. Informative References
+
+ [CVE-2023-0464]
+ CVE, "Excessive Resource Usage Verifying X.509 Policy
+ Constraints", CVE-2023-0464, March 2023,
+ <https://www.cve.org/CVERecord?id=CVE-2023-0464>.
+
+ [CVE-2023-23524]
+ CVE, "Processing a maliciously crafted certificate may
+ lead to a denial-of-service", CVE-2023-23524, February
+ 2023, <https://www.cve.org/CVERecord?id=CVE-2023-23524>.
+
+ [RFC8446] Rescorla, E., "The Transport Layer Security (TLS) Protocol
+ Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,
+ <https://www.rfc-editor.org/info/rfc8446>.
+
+ [X.509] ITU-T, "Information technology - Open Systems
+ Interconnection - The Directory: Public-key and attribute
+ certificate frameworks", ITU-T Recommendation X.509,
+ October 2019, <https://www.itu.int/rec/T-REC-X.509>.
+
+Acknowledgements
+
+ The author thanks Bob Beck, Adam Langley, Matt Mueller, and Ryan
+ Sleevi for many valuable discussions that led to discovering this
+ issue, understanding it, and developing the mitigation. The author
+ also thanks Martin Thomson, Job Snijders, and John Scudder for their
+ review and feedback on this document.
+
+Author's Address
+
+ David Benjamin
+ Google LLC
+ Email: davidben@google.com