<?xml version='1.0'encoding='utf-8'?>encoding='UTF-8'?> <!DOCTYPE rfc [ <!ENTITY nbsp " "> <!ENTITY zwsp "​"> <!ENTITY nbhy "‑"> <!ENTITY wj "⁠"> ]><?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?> <!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.5 (Ruby 3.2.2) --><rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-ietf-lamps-x509-policy-graph-05" number="9618" category="std" consensus="true" submissionType="IETF" obsoletes="" updates="5280" tocInclude="true" sortRefs="true" symRefs="true" xml:lang="en" version="3"><!-- xml2rfc v2v3 conversion 3.19.1 --><front> <title abbrev="Updates to X.509 Policy Validation">Updates to X.509 Policy Validation</title> <seriesInfoname="Internet-Draft" value="draft-ietf-lamps-x509-policy-graph-05"/>name="RFC" value="9618"/> <author initials="D." surname="Benjamin" fullname="David Benjamin"> <organization>Google LLC</organization> <address> <email>davidben@google.com</email> </address> </author> <date year="2024"month="February" day="01"/> <area>Security</area> <workgroup>Limited Additional Mechanismsmonth="August"/> <area>sec</area> <workgroup>lamps</workgroup> <!-- [rfced] Please insert any keywords (beyond those that appear in the title) forPKIX and SMIME</workgroup> <keyword>Internet-Draft</keyword> <abstract> <?line 57?> <t>Thisuse on https://www.rfc-editor.org/search. --> <keyword>Certificate</keyword> <abstract><t>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 structurewhichthat scaled exponentially in the worst case, leaving implementations vulnerable to denial-of-service attacks.</t> </abstract><note removeInRFC="true"> <name>Discussion Venues</name> <t>Discussion of this document takes place on the Limited Additional Mechanisms for PKIX and SMIME Working Group mailing list (spasm@ietf.org), which is archived at <eref target="https://mailarchive.ietf.org/arch/browse/spasm/"/>.</t> <t>Source for this draft and an issue tracker can be found at <eref target="https://github.com/davidben/x509-policy-graph"/>.</t> </note></front> <middle><?line 64?><section anchor="introduction"> <name>Introduction</name> <t><xref target="RFC5280"/> defines a suite of extensions for determining the"policies" whichpolicies that apply to a certification path. A policy is described by an object identifier(OID),(OID) and a set of optional qualifiers.</t> <!-- [rfced] How does "collecting the corresponding qualifiers" connect with the rest of the sentence? Original: 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, collecting the corresponding qualifiers. Perhaps: 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 and their corresponding qualifiers. Or: 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 and the collection of corresponding qualifiers. --> <t>Policy validation in <xref target="RFC5280"/> is complex. As an overview, the certificate policies extension (<xref section="4.2.1.4" sectionFormat="of" target="RFC5280"/>) describes the policies, with optional qualifiers, under which an individual certificate was issued. The policy mappings extension (<xref section="4.2.1.5" sectionFormat="of" target="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 thepath, collecting the corresponding qualifiers.</t>path.</t> <t>The procedure in <xref section="6.1" sectionFormat="of" target="RFC5280"/> determines this set in the course of certification path validation. It does so by building a policytree,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 <xref target="CVE-2023-0464"/> and <xref target="CVE-2023-23524"/>.</t> <t><xref target="dos"/> describes this vulnerability. <xref target="policy-graph"/> describes the primary mitigation for this vulnerability, a replacement for the policy tree structure. <xref target="updates"/> provides updates to <xref target="RFC5280"/>whichthat implement this change. Finally, <xref target="other-mitigations"/> discusses alternative mitigation strategies for X.509 applications.</t> <section anchor="summary-of-changes-from-rfc-5280"> <name>Summary of Changes from RFC 5280</name> <t>The algorithm for processing certificate policies and policy mappings is replaced with onewhichthat builds anequivalent,equivalent but much more efficient structure. This new algorithm does not change the validity status of any certificationpath, norpath or which certificate policies are valid for it.</t> </section> </section> <section anchor="conventions-and-definitions"> <name>Conventions and Definitions</name><t>The<t> The key words"MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY","<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>", "<bcp14>MAY</bcp14>", and"OPTIONAL""<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as described inBCP 14BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they appear in all capitals, as shownhere.</t>here. </t> </section> <section anchor="dos"><name>Denial of Service<name>Denial-of-Service Vulnerability</name> <t>This section discusses how the path validation algorithm defined in <xref section="6.1.2" sectionFormat="of" target="RFC5280"/> can lead to a denial-of-service vulnerability in X.509-based applications.</t> <section anchor="policy-trees"> <name>Policy Trees</name> <t><xref section="6.1.2" sectionFormat="of" target="RFC5280"/> constructs the <tt>valid_policy_tree</tt>, 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. <!-- [rfced] Will readers understand what "it" refers to here? Original: A node's parent policy is the policy in the issuer certificate which was mapped to this policy, and a node's children are the policies it was mapped to in the subject certificate. Perhaps: 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. --> 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.</t> <!-- [rfced] Would it be helpful to add "from" in this sentence? Or is the current clear? Original: It contains mappings OID1 to OID3, and OID1 to OID4. Perhaps: It contains mappings from OID1 to OID3 and from OID1 to OID4. --> <t>For example, suppose a certification path contains:</t> <ul spacing="normal"><li> <t>An<li>An intermediate certificatewhichthat asserts the following policyOIDsOIDs: OID1, OID2, and OID5. It contains mappings from OID1 toOID3,OID3 and from OID1 toOID4.</t> </li> <li> <t>AnOID4.</li> <li>An end-entity certificatewhichthat asserts the following policyOIDsOIDs: OID2, OID3, andOID6.</t> </li>OID6.</li> </ul> <t>This would result in the tree shownin <xref target="basic-tree"/>.below. Note that OID5 and OID6 are not included or mapped across the whole path, so they do not appear in the final structure.</t><figure anchor="basic-tree"> <name>An Example X.509 Policy Tree</name><artset> <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="336" width="424" viewBox="0 0 424 336" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round"> <path d="M 152,160 L 152,224" fill="none" stroke="black"/> <path d="M 152,288 L 152,320" fill="none" stroke="black"/> <path d="M 200,232 L 200,280" fill="none" stroke="black"/> <path d="M 232,32 L 232,96" fill="none" stroke="black"/> <path d="M 256,160 L 256,224" fill="none" stroke="black"/> <path d="M 256,288 L 256,320" fill="none" stroke="black"/> <path d="M 312,160 L 312,224" fill="none" stroke="black"/> <path d="M 312,288 L 312,320" fill="none" stroke="black"/> <path d="M 328,32 L 328,96" fill="none" stroke="black"/> <path d="M 360,232 L 360,280" fill="none" stroke="black"/> <path d="M 416,160 L 416,224" fill="none" stroke="black"/> <path d="M 416,288 L 416,320" fill="none" stroke="black"/> <path d="M 232,32 L 328,32" fill="none" stroke="black"/> <path d="M 232,64 L 328,64" fill="none" stroke="black"/> <path d="M 232,96 L 328,96" fill="none" stroke="black"/> <path d="M 152,160 L 256,160" fill="none" stroke="black"/> <path d="M 312,160 L 416,160" fill="none" stroke="black"/> <path d="M 152,192 L 256,192" fill="none" stroke="black"/> <path d="M 312,192 L 416,192" fill="none" stroke="black"/> <path d="M 152,224 L 256,224" fill="none" stroke="black"/> <path d="M 312,224 L 416,224" fill="none" stroke="black"/> <path d="M 152,288 L 256,288" fill="none" stroke="black"/> <path d="M 312,288 L 416,288" fill="none" stroke="black"/> <path d="M 152,320 L 256,320" fill="none" stroke="black"/> <path d="M 312,320 L 416,320" fill="none" stroke="black"/> <path d="M 324,104 L 348,152" fill="none" stroke="black"/> <path d="M 220,152 L 244,104" fill="none" stroke="black"/> <polygon class="arrowhead" points="368,280 356,274.4 356,285.6" fill="black" transform="rotate(90,360,280)"/> <polygon class="arrowhead" points="356,152 344,146.4 344,157.6" fill="black" transform="rotate(63.43494882292201,348,152)"/> <polygon class="arrowhead" points="228,152 216,146.4 216,157.6" fill="black" transform="rotate(116.56505117707799,220,152)"/> <polygon class="arrowhead" points="208,280 196,274.4 196,285.6" fill="black" transform="rotate(90,200,280)"/> <g class="text"> <text x="112" y="52">Root:</text> <text x="280" y="52">anyPolicy</text> <text x="280" y="84">{anyPolicy}</text> <text x="80" y="180">Intermediate:</text> <text x="204" y="180">OID1</text> <text x="364" y="180">OID2</text> <text x="24" y="196">(OID5</text> <text x="92" y="196">discarded)</text> <text x="180" y="212">{OID3,</text> <text x="232" y="212">OID4}</text> <text x="364" y="212">{OID2}</text> <text x="88" y="308">End-entity:</text> <text x="204" y="308">OID3</text> <text x="364" y="308">OID2</text> <text x="24" y="324">(OID6</text> <text x="92" y="324">discarded)</text> </g> </svg> </artwork> <artwork type="ascii-art"><![CDATA[ +-----------+ Root: | anyPolicy | +-----------+ |{anyPolicy}| +-----------+ / \ / \ v v +------------+ +------------+ Intermediate: | OID1 | | OID2 | (OID5 discarded) +------------+ +------------+ |{OID3, OID4}| | {OID2} | +------------+ +------------+ | | | | v v +------------+ +------------+ End-entity: | OID3 | | OID2 | (OID6 discarded) +------------+ +------------+ ]]></artwork> </artset></figure><t>The complete algorithm for building this structure is described in steps (d), (e), and (f)ofin <xref section="6.1.3" sectionFormat="of"target="RFC5280"/>,target="RFC5280"/>; steps (h), (i), and (j)ofin <xref section="6.1.4" sectionFormat="of"target="RFC5280"/>,target="RFC5280"/>; and steps (a), (b), and (g)ofin <xref section="6.1.5" sectionFormat="of" target="RFC5280"/>.</t> </section> <section anchor="exponential-growth"> <name>Exponential Growth</name> <t>The <tt>valid_policy_tree</tt> grows exponentially in the worst case. In step (d.1)ofin <xref section="6.1.3" sectionFormat="of" target="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.</t> <t>In particular, consider a certificate chain where every intermediate certificate asserts policies OID1 andOID2,OID2 and then contains the full Cartesian product of mappings:</t> <ul spacing="normal"> <li> <t>OID1 maps to OID1</t> </li> <li> <t>OID1 maps to OID2</t> </li> <li> <t>OID2 maps to OID1</t> </li> <li> <t>OID2 maps to OID2</t> </li> </ul> <t>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 <xref target="exponential-tree"/>.</t> <figure anchor="exponential-tree"> <name>An Example X.509 Policy Tree with Exponential Growth</name> <artset> <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="448" width="576" viewBox="0 0 576 448" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round"> <path d="M 8,400 L 8,432" fill="none" stroke="black"/> <path d="M 24,288 L 24,352" fill="none" stroke="black"/> <path d="M 40,360 L 40,392" fill="none" stroke="black"/> <path d="M 64,400 L 64,432" fill="none" stroke="black"/> <path d="M 80,400 L 80,432" fill="none" stroke="black"/> <path d="M 104,160 L 104,224" fill="none" stroke="black"/> <path d="M 104,360 L 104,392" fill="none" stroke="black"/> <path d="M 128,288 L 128,352" fill="none" stroke="black"/> <path d="M 136,400 L 136,432" fill="none" stroke="black"/> <path d="M 152,400 L 152,432" fill="none" stroke="black"/> <path d="M 168,288 L 168,352" fill="none" stroke="black"/> <path d="M 184,360 L 184,392" fill="none" stroke="black"/> <path d="M 200,32 L 200,96" fill="none" stroke="black"/> <path d="M 208,160 L 208,224" fill="none" stroke="black"/> <path d="M 208,400 L 208,432" fill="none" stroke="black"/> <path d="M 224,400 L 224,432" fill="none" stroke="black"/> <path d="M 248,360 L 248,392" fill="none" stroke="black"/> <path d="M 272,288 L 272,352" fill="none" stroke="black"/> <path d="M 280,400 L 280,432" fill="none" stroke="black"/> <path d="M 296,400 L 296,432" fill="none" stroke="black"/> <path d="M 312,288 L 312,352" fill="none" stroke="black"/> <path d="M 328,360 L 328,392" fill="none" stroke="black"/> <path d="M 352,400 L 352,432" fill="none" stroke="black"/> <path d="M 368,400 L 368,432" fill="none" stroke="black"/> <path d="M 392,32 L 392,96" fill="none" stroke="black"/> <path d="M 392,160 L 392,224" fill="none" stroke="black"/> <path d="M 392,360 L 392,392" fill="none" stroke="black"/> <path d="M 416,288 L 416,352" fill="none" stroke="black"/> <path d="M 424,400 L 424,432" fill="none" stroke="black"/> <path d="M 440,400 L 440,432" fill="none" stroke="black"/> <path d="M 456,288 L 456,352" fill="none" stroke="black"/> <path d="M 472,360 L 472,392" fill="none" stroke="black"/> <path d="M 496,160 L 496,224" fill="none" stroke="black"/> <path d="M 496,400 L 496,432" fill="none" stroke="black"/> <path d="M 512,400 L 512,432" fill="none" stroke="black"/> <path d="M 536,360 L 536,392" fill="none" stroke="black"/> <path d="M 560,288 L 560,352" fill="none" stroke="black"/> <path d="M 568,400 L 568,432" fill="none" stroke="black"/> <path d="M 200,32 L 392,32" fill="none" stroke="black"/> <path d="M 200,64 L 392,64" fill="none" stroke="black"/> <path d="M 200,96 L 392,96" fill="none" stroke="black"/> <path d="M 104,160 L 208,160" fill="none" stroke="black"/> <path d="M 392,160 L 496,160" fill="none" stroke="black"/> <path d="M 104,192 L 208,192" fill="none" stroke="black"/> <path d="M 392,192 L 496,192" fill="none" stroke="black"/> <path d="M 104,224 L 208,224" fill="none" stroke="black"/> <path d="M 392,224 L 496,224" fill="none" stroke="black"/> <path d="M 24,288 L 128,288" fill="none" stroke="black"/> <path d="M 168,288 L 272,288" fill="none" stroke="black"/> <path d="M 312,288 L 416,288" fill="none" stroke="black"/> <path d="M 456,288 L 560,288" fill="none" stroke="black"/> <path d="M 24,320 L 128,320" fill="none" stroke="black"/> <path d="M 168,320 L 272,320" fill="none" stroke="black"/> <path d="M 312,320 L 416,320" fill="none" stroke="black"/> <path d="M 456,320 L 560,320" fill="none" stroke="black"/> <path d="M 24,352 L 128,352" fill="none" stroke="black"/> <path d="M 168,352 L 272,352" fill="none" stroke="black"/> <path d="M 312,352 L 416,352" fill="none" stroke="black"/> <path d="M 456,352 L 560,352" fill="none" stroke="black"/> <path d="M 8,400 L 64,400" fill="none" stroke="black"/> <path d="M 80,400 L 136,400" fill="none" stroke="black"/> <path d="M 152,400 L 208,400" fill="none" stroke="black"/> <path d="M 224,400 L 280,400" fill="none" stroke="black"/> <path d="M 296,400 L 352,400" fill="none" stroke="black"/> <path d="M 368,400 L 424,400" fill="none" stroke="black"/> <path d="M 440,400 L 496,400" fill="none" stroke="black"/> <path d="M 512,400 L 568,400" fill="none" stroke="black"/> <path d="M 8,432 L 64,432" fill="none" stroke="black"/> <path d="M 80,432 L 136,432" fill="none" stroke="black"/> <path d="M 152,432 L 208,432" fill="none" stroke="black"/> <path d="M 224,432 L 280,432" fill="none" stroke="black"/> <path d="M 296,432 L 352,432" fill="none" stroke="black"/> <path d="M 368,432 L 424,432" fill="none" stroke="black"/> <path d="M 440,432 L 496,432" fill="none" stroke="black"/> <path d="M 512,432 L 568,432" fill="none" stroke="black"/> <path d="M 188,232 L 212,280" fill="none" stroke="black"/> <path d="M 380,104 L 404,152" fill="none" stroke="black"/> <path d="M 484,232 L 508,280" fill="none" stroke="black"/> <path d="M 92,280 L 116,232" fill="none" stroke="black"/> <path d="M 188,152 L 212,104" fill="none" stroke="black"/> <path d="M 388,280 L 412,232" fill="none" stroke="black"/> <polygon class="arrowhead" points="544,392 532,386.4 532,397.6" fill="black" transform="rotate(90,536,392)"/> <polygon class="arrowhead" points="516,280 504,274.4 504,285.6" fill="black" transform="rotate(63.43494882292201,508,280)"/> <polygon class="arrowhead" points="480,392 468,386.4 468,397.6" fill="black" transform="rotate(90,472,392)"/> <polygon class="arrowhead" points="412,152 400,146.4 400,157.6" fill="black" transform="rotate(63.43494882292201,404,152)"/> <polygon class="arrowhead" points="400,392 388,386.4 388,397.6" fill="black" transform="rotate(90,392,392)"/> <polygon class="arrowhead" points="396,280 384,274.4 384,285.6" fill="black" transform="rotate(116.56505117707799,388,280)"/> <polygon class="arrowhead" points="336,392 324,386.4 324,397.6" fill="black" transform="rotate(90,328,392)"/> <polygon class="arrowhead" points="256,392 244,386.4 244,397.6" fill="black" transform="rotate(90,248,392)"/> <polygon class="arrowhead" points="220,280 208,274.4 208,285.6" fill="black" transform="rotate(63.43494882292201,212,280)"/> <polygon class="arrowhead" points="196,152 184,146.4 184,157.6" fill="black" transform="rotate(116.56505117707799,188,152)"/> <polygon class="arrowhead" points="192,392 180,386.4 180,397.6" fill="black" transform="rotate(90,184,392)"/> <polygon class="arrowhead" points="112,392 100,386.4 100,397.6" fill="black" transform="rotate(90,104,392)"/> <polygon class="arrowhead" points="100,280 88,274.4 88,285.6" fill="black" transform="rotate(116.56505117707799,92,280)"/> <polygon class="arrowhead" points="48,392 36,386.4 36,397.6" fill="black" transform="rotate(90,40,392)"/> <g class="text"> <text x="304" y="52">anyPolicy</text> <text x="304" y="84">{anyPolicy}</text> <text x="156" y="180">OID1</text> <text x="444" y="180">OID2</text> <text x="132" y="212">{OID1,</text> <text x="184" y="212">OID2}</text> <text x="420" y="212">{OID1,</text> <text x="472" y="212">OID2}</text> <text x="76" y="308">OID1</text> <text x="220" y="308">OID2</text> <text x="364" y="308">OID1</text> <text x="508" y="308">OID2</text> <text x="52" y="340">{OID1,</text> <text x="104" y="340">OID2}</text> <text x="196" y="340">{OID1,</text> <text x="248" y="340">OID2}</text> <text x="340" y="340">{OID1,</text> <text x="392" y="340">OID2}</text> <text x="484" y="340">{OID1,</text> <text x="536" y="340">OID2}</text> <text x="36" y="420">OID1</text> <text x="108" y="420">OID2</text> <text x="180" y="420">OID1</text> <text x="252" y="420">OID2</text> <text x="324" y="420">OID1</text> <text x="396" y="420">OID2</text> <text x="468" y="420">OID1</text> <text x="540" y="420">OID2</text> </g> </svg> </artwork> <artwork type="ascii-art"><![CDATA[ +-----------------------+ | 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 | +------+ +------+ +------+ +------+ +------+ +------+ +------+ +------+ ]]></artwork> </artset> </figure> </section> <section anchor="attack-vector"> <name>Attack Vector</name> <!-- [rfced] May we update "preventing it" as follows for clarity? The pronoun "it" is used once before in the sentence to refer to something else. Original: The target application will consume far more resources processing the input than the attacker consumed to send it, preventing it from servicing other clients. Perhaps: 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. --> <t>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 <xref target="exponential-growth"/> and triggers the target application's certificate validation process. For example, the target application may be a TLS server <xref target="RFC8446"/>serverthat performs client certificate validation. The target application will consume far more resources processing the input than the attacker consumed to send it,preventing itwhich prevents the target application from servicing other clients.</t> </section> </section> <section anchor="avoiding-exponential-growth"> <name>Avoiding Exponential Growth</name> <t>This document mitigates the denial-of-service vulnerability described in <xref target="dos"/> 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.</t> <t>X.509 implementationsSHOULD<bcp14>SHOULD</bcp14> perform policy validation by building a policy graph, following the procedure described in <xref target="updates"/>. This replacement procedure computes the same policies as in <xref target="RFC5280"/>,howeverbut one of the outputs is in a different form. See <xref target="outputs"/> for details. <xref target="other-mitigations"/> describes alternative mitigations for implementations that depend on the original, exponential-sized output.</t> <section anchor="policy-graph"> <name>Policy Graphs</name> <!-- [rfced] FYI - We updated "Where [RFC5280] adds multiple duplicate nodes" in this sentence as follows. Please let us know any concerns. Original: Where [RFC5280] adds multiple duplicate nodes, a policy graph adds a single node with multiple parents. Updated: The policy tree in [RFC5280] adds multiple duplicate nodes, but a policy graph adds a single node with multiple parents. --> <t>The tree structurefromin <xref target="RFC5280"/> is an unnecessarily inefficient representation of a certification path's policy mappings.AWhen multiple issuer policies map to a singlecertificatesubject policy, the subject policymaywill correspond to multiplenodes, but each node is identical, with identical children.duplicate nodes in the policy tree. Children of the subject policy are then duplicated recursively. Thisredundancyduplication is the source of the exponential growth described in <xref target="exponential-growth"/>.</t> <t>A policy graphisrepresents the same information with a directed acyclic graph of policy nodes.Where <xref target="RFC5280"/> adds multiple duplicate nodes, a policy graph addsIt eliminates this duplication by using a single node with multiple parents. See <xref target="updates"/> for the procedure for building this structure. <xref target="exponential-tree-as-graph"/> shows the updated representation of the example in <xref target="exponential-tree"/>.</t> <figure anchor="exponential-tree-as-graph"> <name>A More Efficient Representation of an X.509 Policy Tree</name> <artset> <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="576" width="248" viewBox="0 0 248 576" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round"> <path d="M 8,160 L 8,224" fill="none" stroke="black"/> <path d="M 8,336 L 8,400" fill="none" stroke="black"/> <path d="M 8,512 L 8,544" fill="none" stroke="black"/> <path d="M 48,232 L 48,328" fill="none" stroke="black"/> <path d="M 48,408 L 48,504" fill="none" stroke="black"/> <path d="M 80,32 L 80,96" fill="none" stroke="black"/> <path d="M 112,160 L 112,224" fill="none" stroke="black"/> <path d="M 112,336 L 112,400" fill="none" stroke="black"/> <path d="M 112,512 L 112,544" fill="none" stroke="black"/> <path d="M 136,160 L 136,224" fill="none" stroke="black"/> <path d="M 136,336 L 136,400" fill="none" stroke="black"/> <path d="M 136,512 L 136,544" fill="none" stroke="black"/> <path d="M 176,32 L 176,96" fill="none" stroke="black"/> <path d="M 192,232 L 192,328" fill="none" stroke="black"/> <path d="M 192,408 L 192,504" fill="none" stroke="black"/> <path d="M 240,160 L 240,224" fill="none" stroke="black"/> <path d="M 240,336 L 240,400" fill="none" stroke="black"/> <path d="M 240,512 L 240,544" fill="none" stroke="black"/> <path d="M 80,32 L 176,32" fill="none" stroke="black"/> <path d="M 80,64 L 176,64" fill="none" stroke="black"/> <path d="M 80,96 L 176,96" fill="none" stroke="black"/> <path d="M 8,160 L 112,160" fill="none" stroke="black"/> <path d="M 136,160 L 240,160" fill="none" stroke="black"/> <path d="M 8,192 L 112,192" fill="none" stroke="black"/> <path d="M 136,192 L 240,192" fill="none" stroke="black"/> <path d="M 8,224 L 112,224" fill="none" stroke="black"/> <path d="M 136,224 L 240,224" fill="none" stroke="black"/> <path d="M 8,336 L 112,336" fill="none" stroke="black"/> <path d="M 136,336 L 240,336" fill="none" stroke="black"/> <path d="M 8,368 L 112,368" fill="none" stroke="black"/> <path d="M 136,368 L 240,368" fill="none" stroke="black"/> <path d="M 8,400 L 112,400" fill="none" stroke="black"/> <path d="M 136,400 L 240,400" fill="none" stroke="black"/> <path d="M 8,512 L 112,512" fill="none" stroke="black"/> <path d="M 136,512 L 240,512" fill="none" stroke="black"/> <path d="M 8,544 L 112,544" fill="none" stroke="black"/> <path d="M 136,544 L 240,544" fill="none" stroke="black"/> <path d="M 100,408 L 148,504" fill="none" stroke="black"/> <path d="M 100,232 L 148,328" fill="none" stroke="black"/> <path d="M 172,104 L 196,152" fill="none" stroke="black"/> <path d="M 60,152 L 84,104" fill="none" stroke="black"/> <path d="M 100,328 L 148,232" fill="none" stroke="black"/> <path d="M 100,504 L 148,408" fill="none" stroke="black"/> <polygon class="arrowhead" points="200,504 188,498.4 188,509.6" fill="black" transform="rotate(90,192,504)"/> <polygon class="arrowhead" points="200,328 188,322.4 188,333.6" fill="black" transform="rotate(90,192,328)"/> <polygon class="arrowhead" points="204,152 192,146.4 192,157.6" fill="black" transform="rotate(63.43494882292201,196,152)"/> <polygon class="arrowhead" points="156,504 144,498.4 144,509.6" fill="black" transform="rotate(63.43494882292201,148,504)"/> <polygon class="arrowhead" points="156,328 144,322.4 144,333.6" fill="black" transform="rotate(63.43494882292201,148,328)"/> <polygon class="arrowhead" points="108,504 96,498.4 96,509.6" fill="black" transform="rotate(116.56505117707799,100,504)"/> <polygon class="arrowhead" points="108,328 96,322.4 96,333.6" fill="black" transform="rotate(116.56505117707799,100,328)"/> <polygon class="arrowhead" points="68,152 56,146.4 56,157.6" fill="black" transform="rotate(116.56505117707799,60,152)"/> <polygon class="arrowhead" points="56,504 44,498.4 44,509.6" fill="black" transform="rotate(90,48,504)"/> <polygon class="arrowhead" points="56,328 44,322.4 44,333.6" fill="black" transform="rotate(90,48,328)"/> <g class="text"> <text x="128" y="52">anyPolicy</text> <text x="128" y="84">{anyPolicy}</text> <text x="60" y="180">OID1</text> <text x="188" y="180">OID2</text> <text x="36" y="212">{OID1,</text> <text x="88" y="212">OID2}</text> <text x="164" y="212">{OID1,</text> <text x="216" y="212">OID2}</text> <text x="60" y="356">OID1</text> <text x="188" y="356">OID2</text> <text x="36" y="388">{OID1,</text> <text x="88" y="388">OID2}</text> <text x="164" y="388">{OID1,</text> <text x="216" y="388">OID2}</text> <text x="60" y="532">OID1</text> <text x="188" y="532">OID2</text> </g> </svg> </artwork> <artwork type="ascii-art"><![CDATA[ +-----------+ | 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 | +------------+ +------------+ ]]></artwork> </artset> </figure> <t>This graph's size is bounded linearly by the total number of certificate policies (<xref section="4.2.1.4" sectionFormat="of" target="RFC5280"/>) and policy mappings (<xref section="4.2.1.5" sectionFormat="of" target="RFC5280"/>). The policy treefromin <xref target="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.</t> </section> <section anchor="outputs"> <name>Verification Outputs</name> <!-- [rfced] How may we update "Section 12.2 of [X.509] instead only outputs" to avoid personification of the section? That is, instead of "Section 12.2 ... outputs", perhaps the sentence can be updated to note that Section 12.2 describes the outputs (or something similar)? Original: Section 12.2 of [X.509] instead only outputs the authorities-constrained policies, the user-constrained policies, and their associated qualifiers. Perhaps: 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. --> <t><xref section="6.1.6" sectionFormat="of" target="RFC5280"/> describes the entire <tt>valid_policy_tree</tt> structure as an output of the verification process. However, Section 12.2 of <xref target="X.509"/>insteadonlyoutputsdescribes the following as outputs: the authorities-constrained policies, the user-constrained policies, and their associated qualifiers.</t> <t>As the <tt>valid_policy_tree</tt> is the exponential structure, computing it reintroduces the denial-of-service vulnerability. X.509 implementationsSHOULD NOT<bcp14>SHOULD NOT</bcp14> output the entire <tt>valid_policy_tree</tt>structure and instead SHOULDstructure; instead, they <bcp14>SHOULD</bcp14> limit output to just the set of authorities-constrained and/or user-constrained policies, as described in <xref target="X.509"/>. Sections <xreftarget="update-outputs"/>target="update-outputs" format="counter"/> and <xreftarget="other-mitigations"/>target="other-mitigations" format="counter"/> discuss other mitigations for applications where this option is not available.</t> <t>X.509 implementationsMAY<bcp14>MAY</bcp14> omit policy qualifiers from the output to simplify processing. Note that <xref section="4.2.1.4" sectionFormat="of" target="RFC5280"/> already recommends that certification authorities omit policy qualifiers from policy information terms.</t> </section> </section> <section anchor="updates"> <name>Updates to RFC 5280</name> <t>This section provides updates to <xref target="RFC5280"/>.This implementsThese updates implement the changes described in <xref target="avoiding-exponential-growth"/>.</t> <section anchor="updates-to-section-61"> <name>Updates to Section 6.1</name><t>This update replaces a paragraph of <xref<t><xref section="6.1" sectionFormat="of" target="RFC5280"/> is updated as follows:</t> <t>OLD:</t><ul empty="true"> <li> <t>A<blockquote><t>A particular certification path may not, however, be appropriate for all applications. Therefore, an applicationMAY<bcp14>MAY</bcp14> 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 policytree.</t> </li> </ul>tree.</t></blockquote> <t>NEW:</t><ul empty="true"> <li> <t>A<blockquote><t>A particular certification path may not, however, be appropriate for all applications. Therefore, an applicationMAY<bcp14>MAY</bcp14> 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 thispath.</t> </li> </ul>path.</t></blockquote> </section> <!-- [rfced] In the RFC Series, we use the <blockquote> element for OLD and NEW text in documents that update another. We noticed a bug in the txt output when we added <blockquote> to Sections 5.2-5.5, and we opened the following issue: https://github.com/ietf-tools/xml2rfc/issues/1148 We will publish this document once this issue has been resolved. --> <!-- [rfced] FYI - The replacement text in Sections 5.2 and 5.3 in this document contains figures. The numbering of the figures in the replacement text doesn’t match up with the numbering of the corresponding figures in RFC 5280. Unfortunately, xml2rfc does not allow us to adjust figure numbers. To align the figure numbers, we removed the figure number from the original Figure 1. We feel this is the best option, but please let us know any concerns. --> <section anchor="updates-to-section-612"> <name>Updates to Section 6.1.2</name><t>This update<t>The following replaces entry (a)ofin <xref section="6.1.2" sectionFormat="of"target="RFC5280"/> with the following text:</t>target="RFC5280"/>: </t> <blockquote> <ol spacing="normal" type="(%c)"><li> <t><tt>valid_policy_graph</tt>: 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. ImplementationsMAY<bcp14>MAY</bcp14> omit qualifiers if not returned in the output. </t><t> Each<t>Each node in the <tt>valid_policy_graph</tt> includes three data objects: the valid policy, a set of associated policy qualifiers, and a set of one or more expected policy values. </t><t> Nodes<t>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. </t><t> If<t>If the node is at depth x, the components of the node have the following semantics: </t> <ol spacing="normal" type="(%d)"><li> <t>The <tt>valid_policy</tt> is a single policy OID representing a valid policy for the path of length x.</t> </li> <li> <t>The <tt>qualifier_set</tt> 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).</t> </li> <li> <t>The <tt>expected_policy_set</tt> contains one or more policy OIDs that would satisfy this policy in the certificate x+1.</t> </li> </ol><t> The<t>The initial value of the <tt>valid_policy_graph</tt> is a single node with <tt>valid_policy</tt> anyPolicy, an empty <tt>qualifier_set</tt>, and an <tt>expected_policy_set</tt> with the single value anyPolicy. This node is considered to be at depth zero. </t><t> The<t>The graph additionally satisfies the following invariants: </t> <!-- [rfced] Please review "policy OID P-OID" and "OID P-OID" in the sentences below. Are these redundant? Let us know if any updates are needed or if the current is correct. Original: * For any depth x and policy OID P-OID, there is at most one node at depth x whose valid_policy is P-OID. .... For each policy OID P-OID (including anyPolicy) which appears in the expected_policy_set of some node in the valid_policy_graph for depth i-1, .... 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. .... (ii) If anyPolicy appears in authority_constrained_policy_set with qualifiers AP- Q, for each OID P-OID in user-initial-policy-set which does not appear in user_constrained_policy_set, add P-OID with qualifiers AP-Q to user_constrained_policy_set. Perhaps: * For any depth x and P-OID (OID for policy P), there is at most one node at depth x whose valid_policy is P-OID. ... For each P-OID (including anyPolicy) that appears in the expected_policy_set of some node in the valid_policy_graph for depth i-1, .... This is equivalent to running step (1) above, as if the certificate policies extension contained a policy with P-OID and qualifier set AP-Q. .... (ii) If anyPolicy appears in authority_constrained_policy_set with qualifiers AP- Q, for each 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. --> <ul spacing="normal"> <li> <t>For any depth x and policy OID P-OID, there is at most one node at depth x whose <tt>valid_policy</tt> is P-OID.</t> </li> <li> <t>The <tt>expected_policy_set</tt> of a node whose <tt>valid_policy</tt> is anyPolicy is always {anyPolicy}.</t> </li> <li> <t>A node at depth x whose <tt>valid_policy</tt> is anyPolicy, except for the one at depth zero, always has exactly one parent: a node at depth x-1 whose <tt>valid_policy</tt> is also anyPolicy.</t> </li> <li> <t>Each node at depth greater than 0 has either one or more parent nodes whose <tt>valid_policy</tt> is notanyPolicy,anyPolicy or a single parent node whose <tt>valid_policy</tt> is anyPolicy. That is, a node cannot simultaneously be a child of both anyPolicy and some non-anyPolicy OID.</t> </li> </ul><t> <xref<t><xref target="graph-initial"/> is a graphic representation of the initial state of the <tt>valid_policy_graph</tt>. Additional figures will use this format to describe changes in the <tt>valid_policy_graph</tt> during path processing. </t> <figure anchor="graph-initial"> <name>InitialvalueValue of thevalid_policy_graph<tt>valid_policy_graph</tt> State Variable</name> <artset> <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="160" width="376" viewBox="0 0 376 160" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round"> <path d="M 8,32 L 8,128" fill="none" stroke="black"/> <path d="M 144,32 L 144,128" fill="none" stroke="black"/> <path d="M 8,32 L 144,32" fill="none" stroke="black"/> <path d="M 176,48 L 208,48" fill="none" stroke="black"/> <path d="M 8,64 L 144,64" fill="none" stroke="black"/> <path d="M 176,80 L 208,80" fill="none" stroke="black"/> <path d="M 8,96 L 144,96" fill="none" stroke="black"/> <path d="M 176,112 L 208,112" fill="none" stroke="black"/> <path d="M 8,128 L 144,128" fill="none" stroke="black"/> <polygon class="arrowhead" points="184,112 172,106.4 172,117.6" fill="black" transform="rotate(180,176,112)"/> <polygon class="arrowhead" points="184,80 172,74.4 172,85.6" fill="black" transform="rotate(180,176,80)"/> <polygon class="arrowhead" points="184,48 172,42.4 172,53.6" fill="black" transform="rotate(180,176,48)"/> <g class="text"> <text x="72" y="52">anyPolicy</text> <text x="268" y="52">valid_policy</text> <text x="76" y="84">{}</text> <text x="272" y="84">qualifier_set</text> <text x="72" y="116">{anyPolicy}</text> <text x="296" y="116">expected_policy_set</text> </g> </svg> </artwork> <artwork type="ascii-art"><![CDATA[ +----------------+ | anyPolicy | <---- valid_policy +----------------+ | {} | <---- qualifier_set +----------------+ | {anyPolicy} | <---- expected_policy_set +----------------+ ]]></artwork> </artset> </figure> </li> </ol> </blockquote> </section> <section anchor="updates-to-section-613"> <name>Updates to Section 6.1.3</name><t>This update<t>The following replaces steps (d), (e), and (f)ofin <xref section="6.1.3" sectionFormat="of"target="RFC5280"/> with the following text:</t>target="RFC5280"/>: </t> <blockquote> <ol spacing="normal" type="(%c)" start="4"><li> <t>If the certificate policies extension is present in the certificate and the <tt>valid_policy_graph</tt> is not NULL, process the policy information by performing the following steps in order: </t> <ol spacing="normal" type="(%d)"><li> <t>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: </t> <ol spacing="normal" type="(%i)"><li> <t>Let <tt>parent_nodes</tt> be the nodes at depth i-1 in the <tt>valid_policy_graph</tt> where P-OID is in the <tt>expected_policy_set</tt>. If <tt>parent_nodes</tt> is not empty, create a child node as follows: set the <tt>valid_policy</tt> to P-OID, set the <tt>qualifier_set</tt> to P-Q, set the <tt>expected_policy_set</tt> to {P-OID}, and set the parent nodes to <tt>parent_nodes</tt>. </t><t> For<t>For example, consider a <tt>valid_policy_graph</tt> with a node of depth i-1 where the <tt>expected_policy_set</tt> is {Gold,White},White} and a second node where the <tt>expected_policy_set</tt> 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 <xref target="exact-match"/>. </t> <figure anchor="exact-match"> <name>Processing an Exact Match</name> <artset> <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="336" width="456" viewBox="0 0 456 336" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round"> <path d="M 8,32 L 8,128" fill="none" stroke="black"/> <path d="M 112,208 L 112,304" fill="none" stroke="black"/> <path d="M 152,32 L 152,128" fill="none" stroke="black"/> <path d="M 208,32 L 208,128" fill="none" stroke="black"/> <path d="M 256,208 L 256,304" fill="none" stroke="black"/> <path d="M 352,32 L 352,128" fill="none" stroke="black"/> <path d="M 8,32 L 152,32" fill="none" stroke="black"/> <path d="M 208,32 L 352,32" fill="none" stroke="black"/> <path d="M 8,64 L 152,64" fill="none" stroke="black"/> <path d="M 208,64 L 352,64" fill="none" stroke="black"/> <path d="M 8,96 L 152,96" fill="none" stroke="black"/> <path d="M 208,96 L 352,96" fill="none" stroke="black"/> <path d="M 8,128 L 152,128" fill="none" stroke="black"/> <path d="M 208,128 L 352,128" fill="none" stroke="black"/> <path d="M 112,208 L 256,208" fill="none" stroke="black"/> <path d="M 112,240 L 256,240" fill="none" stroke="black"/> <path d="M 112,272 L 256,272" fill="none" stroke="black"/> <path d="M 112,304 L 256,304" fill="none" stroke="black"/> <path d="M 100,136 L 132,200" fill="none" stroke="black"/> <path d="M 236,200 L 268,136" fill="none" stroke="black"/> <polygon class="arrowhead" points="244,200 232,194.4 232,205.6" fill="black" transform="rotate(116.56505117707799,236,200)"/> <polygon class="arrowhead" points="140,200 128,194.4 128,205.6" fill="black" transform="rotate(63.43494882292201,132,200)"/> <g class="text"> <text x="80" y="52">Red</text> <text x="284" y="52">Blue</text> <text x="76" y="84">{}</text> <text x="276" y="84">{}</text> <text x="400" y="84">depth</text> <text x="440" y="84">i-1</text> <text x="52" y="116">{Gold,</text> <text x="108" y="116">White}</text> <text x="252" y="116">{Gold,</text> <text x="312" y="116">Yellow}</text> <text x="180" y="228">Gold</text> <text x="180" y="260">{}</text> <text x="304" y="260">depth</text> <text x="336" y="260">i</text> <text x="180" y="292">{Gold}</text> </g> </svg> </artwork> <artwork type="ascii-art"><![CDATA[ +-----------------+ +-----------------+ | Red | | Blue | +-----------------+ +-----------------+ | {} | | {} | depth i-1 +-----------------+ +-----------------+ | {Gold, White} | | {Gold, Yellow} | +-----------------+ +-----------------+ \ / \ / \ / v v +-----------------+ | Gold | +-----------------+ | {} | depth i +-----------------+ | {Gold} | +-----------------+ ]]></artwork> </artset> </figure> </li> <li> <t>If there was no match in step (i) and the <tt>valid_policy_graph</tt> includes a node of depth i-1 with the <tt>valid_policy</tt> anyPolicy, generate a child node with the following values: set the <tt>valid_policy</tt> to P-OID, set the <tt>qualifier_set</tt> to P-Q, set the <tt>expected_policy_set</tt> to {P-OID}, and set the parent node to the anyPolicy node at depth i-1. </t><t> For<t>For example, consider a <tt>valid_policy_graph</tt> with a node of depth i-1 where the <tt>valid_policy</tt> 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 <xref target="unmatched-anypolicy"/>. </t> <figure anchor="unmatched-anypolicy"> <name>Processing Unmatched PolicieswhenWhen a Leaf Node Specifies anyPolicy</name> <artset> <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="336" width="472" viewBox="0 0 472 336" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round"> <path d="M 8,208 L 8,304" fill="none" stroke="black"/> <path d="M 120,32 L 120,128" fill="none" stroke="black"/> <path d="M 152,208 L 152,304" fill="none" stroke="black"/> <path d="M 240,208 L 240,304" fill="none" stroke="black"/> <path d="M 264,32 L 264,128" fill="none" stroke="black"/> <path d="M 384,208 L 384,304" fill="none" stroke="black"/> <path d="M 120,32 L 264,32" fill="none" stroke="black"/> <path d="M 120,64 L 264,64" fill="none" stroke="black"/> <path d="M 120,96 L 264,96" fill="none" stroke="black"/> <path d="M 120,128 L 264,128" fill="none" stroke="black"/> <path d="M 8,208 L 152,208" fill="none" stroke="black"/> <path d="M 240,208 L 384,208" fill="none" stroke="black"/> <path d="M 8,240 L 152,240" fill="none" stroke="black"/> <path d="M 240,240 L 384,240" fill="none" stroke="black"/> <path d="M 8,272 L 152,272" fill="none" stroke="black"/> <path d="M 240,272 L 384,272" fill="none" stroke="black"/> <path d="M 8,304 L 152,304" fill="none" stroke="black"/> <path d="M 240,304 L 384,304" fill="none" stroke="black"/> <path d="M 236,136 L 268,200" fill="none" stroke="black"/> <path d="M 116,200 L 148,136" fill="none" stroke="black"/> <polygon class="arrowhead" points="276,200 264,194.4 264,205.6" fill="black" transform="rotate(63.43494882292201,268,200)"/> <polygon class="arrowhead" points="124,200 112,194.4 112,205.6" fill="black" transform="rotate(116.56505117707799,116,200)"/> <g class="text"> <text x="192" y="52">anyPolicy</text> <text x="188" y="84">{}</text> <text x="312" y="100">depth</text> <text x="352" y="100">i-1</text> <text x="192" y="116">{anyPolicy}</text> <text x="76" y="228">Gold</text> <text x="308" y="228">Silver</text> <text x="76" y="260">{}</text> <text x="308" y="260">{Q-Silver}</text> <text x="432" y="260">depth</text> <text x="464" y="260">i</text> <text x="76" y="292">{Gold}</text> <text x="308" y="292">{Silver}</text> </g> </svg> </artwork> <artwork type="ascii-art"><![CDATA[ +-----------------+ | anyPolicy | +-----------------+ | {} | +-----------------+ depth i-1 | {anyPolicy} | +-----------------+ / \ / \ / \ v v +-----------------+ +-----------------+ | Gold | | Silver | +-----------------+ +-----------------+ | {} | | {Q-Silver} | depth i +-----------------+ +-----------------+ | {Gold} | | {Silver} | +-----------------+ +-----------------+ ]]></artwork> </artset> </figure> </li> </ol> </li> <li> <t>If the certificate policies extension includes the policy anyPolicy with the qualifier set AP-Q and either (a) <tt>inhibit_anyPolicy</tt> is greater than 0 or (b) i<n and the certificate is self-issued, then: </t><t> For<t>For each policy OID P-OID (including anyPolicy)whichthat appears in the <tt>expected_policy_set</tt> of some node in the <tt>valid_policy_graph</tt> for depth i-1, if P-OID does not appear as the <tt>valid_policy</tt> of some node at depth i, create a single child node with the following values: set the <tt>valid_policy</tt> to P-OID, set the <tt>qualifier_set</tt> to AP-Q, set the <tt>expected_policy_set</tt> to {P-OID}, and set the parents to the nodes at depth i-1 where P-OID appears in <tt>expected_policy_set</tt>. </t><t> This<t>This is equivalent to running step (1)above,above as if the certificate policies extension contained a policy with OID P-OID and qualifier set AP-Q. </t><t> For<t>For example, consider a <tt>valid_policy_graph</tt> with a node of depth i-1 where the <tt>expected_policy_set</tt> is {Gold,Silver},Silver} and a second node of depth i-1 where the <tt>expected_policy_set</tt> 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 <xref target="anypolicy-in-extension"/>. </t> <figure anchor="anypolicy-in-extension"> <name>Processing Unmatched Policies When the Certificate Policies Extension Specifies anyPolicy</name> <artset> <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="368" width="432" viewBox="0 0 432 368" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round"> <path d="M 8,32 L 8,128" fill="none" stroke="black"/> <path d="M 8,240 L 8,336" fill="none" stroke="black"/> <path d="M 72,136 L 72,232" fill="none" stroke="black"/> <path d="M 152,32 L 152,128" fill="none" stroke="black"/> <path d="M 152,240 L 152,336" fill="none" stroke="black"/> <path d="M 184,32 L 184,128" fill="none" stroke="black"/> <path d="M 184,240 L 184,336" fill="none" stroke="black"/> <path d="M 256,136 L 256,232" fill="none" stroke="black"/> <path d="M 328,32 L 328,128" fill="none" stroke="black"/> <path d="M 328,240 L 328,336" fill="none" stroke="black"/> <path d="M 8,32 L 152,32" fill="none" stroke="black"/> <path d="M 184,32 L 328,32" fill="none" stroke="black"/> <path d="M 8,64 L 152,64" fill="none" stroke="black"/> <path d="M 184,64 L 328,64" fill="none" stroke="black"/> <path d="M 8,96 L 152,96" fill="none" stroke="black"/> <path d="M 184,96 L 328,96" fill="none" stroke="black"/> <path d="M 8,128 L 152,128" fill="none" stroke="black"/> <path d="M 184,128 L 328,128" fill="none" stroke="black"/> <path d="M 8,240 L 152,240" fill="none" stroke="black"/> <path d="M 184,240 L 328,240" fill="none" stroke="black"/> <path d="M 8,272 L 152,272" fill="none" stroke="black"/> <path d="M 184,272 L 328,272" fill="none" stroke="black"/> <path d="M 8,304 L 152,304" fill="none" stroke="black"/> <path d="M 184,304 L 328,304" fill="none" stroke="black"/> <path d="M 8,336 L 152,336" fill="none" stroke="black"/> <path d="M 184,336 L 328,336" fill="none" stroke="black"/> <path d="M 148,136 L 196,232" fill="none" stroke="black"/> <polygon class="arrowhead" points="264,232 252,226.4 252,237.6" fill="black" transform="rotate(90,256,232)"/> <polygon class="arrowhead" points="204,232 192,226.4 192,237.6" fill="black" transform="rotate(63.43494882292201,196,232)"/> <polygon class="arrowhead" points="80,232 68,226.4 68,237.6" fill="black" transform="rotate(90,72,232)"/> <g class="text"> <text x="80" y="52">Red</text> <text x="260" y="52">Blue</text> <text x="76" y="84">{}</text> <text x="252" y="84">{}</text> <text x="376" y="84">depth</text> <text x="416" y="84">i-1</text> <text x="52" y="116">{Gold,</text> <text x="112" y="116">Silver}</text> <text x="260" y="116">{Gold}</text> <text x="76" y="260">Silver</text> <text x="260" y="260">Gold</text> <text x="76" y="292">{AP-Q}</text> <text x="260" y="292">{AP-Q}</text> <text x="376" y="292">depth</text> <text x="408" y="292">i</text> <text x="76" y="324">{Silver}</text> <text x="260" y="324">{Gold}</text> </g> </svg> </artwork> <artwork type="ascii-art"><![CDATA[ +-----------------+ +-----------------+ | Red | | Blue | +-----------------+ +-----------------+ | {} | | {} | depth i-1 +-----------------+ +-----------------+ | {Gold, Silver} | | {Gold} | +-----------------+ +-----------------+ | \ | | \ | | \ | | \ | | \ | v v v +-----------------+ +-----------------+ | Silver | | Gold | +-----------------+ +-----------------+ | {AP-Q} | | {AP-Q} | depth i +-----------------+ +-----------------+ | {Silver} | | {Gold} | +-----------------+ +-----------------+ ]]></artwork> </artset> </figure> </li> <li> <t>If there is a node in the <tt>valid_policy_graph</tt> 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. </t> <t> For example, consider thevalid_policy_graph<tt>valid_policy_graph</tt> shown in <xref target="pruning"/> 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. </t> <figure anchor="pruning"> <name>Pruning the valid_policy_graph</name> <artset> <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="384" width="416" viewBox="0 0 416 384" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round"> <path d="M 8,128 L 8,160" fill="none" stroke="black"/> <path d="M 8,224 L 8,256" fill="none" stroke="black"/> <path d="M 8,320 L 8,352" fill="none" stroke="black"/> <path d="M 56,168 L 56,216" fill="none" stroke="black"/> <path d="M 104,128 L 104,160" fill="none" stroke="black"/> <path d="M 104,224 L 104,256" fill="none" stroke="black"/> <path d="M 104,320 L 104,352" fill="none" stroke="black"/> <path d="M 120,32 L 120,64" fill="none" stroke="black"/> <path d="M 120,128 L 120,160" fill="none" stroke="black"/> <path d="M 120,224 L 120,256" fill="none" stroke="black"/> <path d="M 120,320 L 120,352" fill="none" stroke="black"/> <path d="M 168,72 L 168,120" fill="none" stroke="black"/> <path d="M 168,168 L 168,216" fill="none" stroke="black"/> <path d="M 168,264 L 168,312" fill="none" stroke="black"/> <path d="M 216,32 L 216,64" fill="none" stroke="black"/> <path d="M 216,128 L 216,160" fill="none" stroke="black"/> <path d="M 216,224 L 216,256" fill="none" stroke="black"/> <path d="M 216,320 L 216,352" fill="none" stroke="black"/> <path d="M 232,128 L 232,160" fill="none" stroke="black"/> <path d="M 232,224 L 232,256" fill="none" stroke="black"/> <path d="M 232,320 L 232,352" fill="none" stroke="black"/> <path d="M 280,168 L 280,216" fill="none" stroke="black"/> <path d="M 328,128 L 328,160" fill="none" stroke="black"/> <path d="M 328,224 L 328,256" fill="none" stroke="black"/> <path d="M 328,320 L 328,352" fill="none" stroke="black"/> <path d="M 120,32 L 216,32" fill="none" stroke="black"/> <path d="M 120,64 L 216,64" fill="none" stroke="black"/> <path d="M 8,128 L 104,128" fill="none" stroke="black"/> <path d="M 120,128 L 216,128" fill="none" stroke="black"/> <path d="M 232,128 L 328,128" fill="none" stroke="black"/> <path d="M 8,160 L 104,160" fill="none" stroke="black"/> <path d="M 120,160 L 216,160" fill="none" stroke="black"/> <path d="M 232,160 L 328,160" fill="none" stroke="black"/> <path d="M 8,224 L 104,224" fill="none" stroke="black"/> <path d="M 120,224 L 216,224" fill="none" stroke="black"/> <path d="M 232,224 L 328,224" fill="none" stroke="black"/> <path d="M 8,256 L 104,256" fill="none" stroke="black"/> <path d="M 120,256 L 216,256" fill="none" stroke="black"/> <path d="M 232,256 L 328,256" fill="none" stroke="black"/> <path d="M 8,320 L 104,320" fill="none" stroke="black"/> <path d="M 120,320 L 216,320" fill="none" stroke="black"/> <path d="M 232,320 L 328,320" fill="none" stroke="black"/> <path d="M 8,352 L 104,352" fill="none" stroke="black"/> <path d="M 120,352 L 216,352" fill="none" stroke="black"/> <path d="M 232,352 L 328,352" fill="none" stroke="black"/> <path d="M 100,168 L 124,216" fill="none" stroke="black"/> <path d="M 212,264 L 236,312" fill="none" stroke="black"/> <path d="M 212,72 L 236,120" fill="none" stroke="black"/> <path d="M 100,120 L 124,72" fill="none" stroke="black"/> <path d="M 100,312 L 124,264" fill="none" stroke="black"/> <polygon class="arrowhead" points="288,216 276,210.4 276,221.6" fill="black" transform="rotate(90,280,216)"/> <polygon class="arrowhead" points="244,312 232,306.4 232,317.6" fill="black" transform="rotate(63.43494882292201,236,312)"/> <polygon class="arrowhead" points="244,120 232,114.4 232,125.6" fill="black" transform="rotate(63.43494882292201,236,120)"/> <polygon class="arrowhead" points="176,312 164,306.4 164,317.6" fill="black" transform="rotate(90,168,312)"/> <polygon class="arrowhead" points="176,216 164,210.4 164,221.6" fill="black" transform="rotate(90,168,216)"/> <polygon class="arrowhead" points="176,120 164,114.4 164,125.6" fill="black" transform="rotate(90,168,120)"/> <polygon class="arrowhead" points="132,216 120,210.4 120,221.6" fill="black" transform="rotate(63.43494882292201,124,216)"/> <polygon class="arrowhead" points="108,312 96,306.4 96,317.6" fill="black" transform="rotate(116.56505117707799,100,312)"/> <polygon class="arrowhead" points="108,120 96,114.4 96,125.6" fill="black" transform="rotate(116.56505117707799,100,120)"/> <polygon class="arrowhead" points="64,216 52,210.4 52,221.6" fill="black" transform="rotate(90,56,216)"/> <g class="text"> <text x="248" y="52">depth</text> <text x="288" y="52">i-3</text> <text x="280" y="148">Y</text> <text x="360" y="148">depth</text> <text x="400" y="148">i-2</text> <text x="56" y="244">X</text> <text x="280" y="244">X</text> <text x="360" y="244">depth</text> <text x="400" y="244">i-1</text> <text x="360" y="340">depth</text> <text x="392" y="340">i</text> </g> </svg> </artwork> <artwork type="ascii-art"><![CDATA[ +-----------+ | | depth i-3 +-----------+ / | \ / | \ v v v +-----------+ +-----------+ +-----------+ | | | | | Y | depth i-2 +-----------+ +-----------+ +-----------+ | \ | | | \ | | v v v v +-----------+ +-----------+ +-----------+ | X | | | | X | depth i-1 +-----------+ +-----------+ +-----------+ / | \ / | \ v v v +-----------+ +-----------+ +-----------+ | | | | | | depth i +-----------+ +-----------+ +-----------+ ]]></artwork> </artset> </figure> </li> </ol> </li> <!-- [rfced] The introductory text in Section 5.3 of this document notes that the text in the section replaces "steps (d), (e), and (f) of Section 6.1.3 of [RFC5280]". In Section 6.1.3 of RFC 5280, the following sentences appear after step (f) and before Figure 7: If any of steps (a), (b), (c), or (f) fails, the procedure terminates, returning a failure indication and an appropriate reason. If i is not equal to n, continue by performing the preparatory steps listed in Section 6.1.4. If i is equal to n, perform the wrap-up steps listed in Section 6.1.5. These sentences (and Figure 7) do not appear to be part of step (f) in RFC 5280. Will it be clear to readers whether or not these sentences are replaced in this document? For example, should the introductory text in this document be updated to something like the following? Or should these sentences appear in this document? Please review and let us know your thoughts. Current: The following replaces steps (d), (e), and (f) in Section 6.1.3 of [RFC5280]: Perhaps: The following replaces the text in Section 6.1.3 of [RFC5280] from step (d) to the end of the section: --> <li> <t>If the certificate policies extension is not present, set the <tt>valid_policy_graph</tt> to NULL.</t> </li> <li> <t>Verify that either <tt>explicit_policy</tt> is greater than 0 or the <tt>valid_policy_graph</tt> is not equal toNULL;</t>NULL.</t> </li> </ol> </blockquote> <t>The text following step (f) in <xref section="6.1.3" sectionFormat="of" target="RFC5280"/>, beginning with "If any of steps (a), (b), (c), or (f) fails", is left unmodified.</t> </section> <section anchor="updates-to-section-614"> <name>Updates to Section 6.1.4</name><t>This update<t>The following replaces step (b)ofin <xref section="6.1.4" sectionFormat="of"target="RFC5280"/>target="RFC5280"/>:</t> <blockquote> <!-- [rfced] Should "issuerDomainPolicy ID-P" be updated to "issuerDomainPolicy (ID-P)" (with parentheses), or is the current okay? Note that RFC 5280 includes this sentence with no parentheses. Original: (b) If a policy mappings extension is present, then for each issuerDomainPolicy ID-P in thefollowing text:</t>policy mappings extension: Perhaps: (b) If a policy mappings extension is present, then for each issuerDomainPolicy (ID-P) in the policy mappings extension: --> <ol spacing="normal" type="(%c)" start="2"><li> <t>If a policy mappings extension is present, then for each issuerDomainPolicy ID-P in the policy mappings extension: </t> <ol spacing="normal" type="(%d)"><li> <t>If thepolicy_mapping<tt>policy_mapping</tt> variable is greater than 0 and there is a node in the <tt>valid_policy_graph</tt> of depth i where ID-P is thevalid_policy,<tt>valid_policy</tt>, set <tt>expected_policy_set</tt> to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension.</t> </li> <li> <t>If thepolicy_mapping<tt>policy_mapping</tt> variable is greater than0,0 and no node of depth i in the <tt>valid_policy_graph</tt> has a <tt>valid_policy</tt> ofID-P,ID-P but there is a node of depth i with a <tt>valid_policy</tt> of anyPolicy, then generate a child node of the node of depth i-1 that has a <tt>valid_policy</tt> of anyPolicy as follows: </t> <ol spacing="normal" type="(%i)"><li> <t>set the <tt>valid_policy</tt> to ID-P;</t> </li> <li> <t>set the <tt>qualifier_set</tt> to the qualifier set of the policy anyPolicy in the certificate policies extension of certificate i; and</t> </li> <li> <t>set the <tt>expected_policy_set</tt> to the set of subjectDomainPolicy values that are specified as equivalent to ID-P by the policy mappings extension.</t> </li> </ol> </li> <li> <t>If the <tt>policy_mapping</tt> variable is equal to 0: </t> <ol spacing="normal" type="(%i)"><li> <t>delete the node, if any, of depth i in the <tt>valid_policy_graph</tt> where ID-P is the <tt>valid_policy</tt>.</t> </li> <li> <t>If there is a node in the <tt>valid_policy_graph</tt> 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.</t> </li> </ol> </li> </ol> </li> </ol> </blockquote> </section> <section anchor="updates-to-section-615"> <name>Updates to Section 6.1.5</name><t>This update<t>The following replaces step (g)ofin <xref section="6.1.5" sectionFormat="of"target="RFC5280"/> with the following text:</t>target="RFC5280"/>:</t> <blockquote> <ol spacing="normal" type="(%c)" start="7"><li> <t>Calculate the <tt>user_constrained_policy_set</tt> as follows. The <tt>user_constrained_policy_set</tt> is a set of policy OIDs, along with associated policy qualifiers. </t> <ol spacing="normal" type="(%d)"><li> <t>If the <tt>valid_policy_graph</tt> is NULL, set <tt>valid_policy_node_set</tt> to the empty set.</t> </li> <li> <t>If the <tt>valid_policy_graph</tt> is not NULL, set <tt>valid_policy_node_set</tt> to the set of policy nodes whose <tt>valid_policy</tt> is not anyPolicy and whose parent list is a single node with <tt>valid_policy</tt> of anyPolicy.</t> </li> <li> <t>If the <tt>valid_policy_graph</tt> is not NULL and contains a node of depth n with the <tt>valid_policy</tt> anyPolicy, add it to <tt>valid_policy_node_set</tt>.</t> </li> <li> <t>Compute <tt>authority_constrained_policy_set</tt>, a set of policy OIDs and associated qualifiers as follows. For each node in <tt>valid_policy_node_set</tt>: </t> <ol spacing="normal" type="(%i)"><li> <t>Add the node's <tt>valid_policy</tt> to <tt>authority_constrained_policy_set</tt>.</t> </li> <li> <t>Collect all qualifiers in the node, its ancestors, and descendants and associate them with <tt>valid_policy</tt>. Applications that do not use policy qualifiersMAY<bcp14>MAY</bcp14> skip this step to simplify processing.</t> </li> </ol> </li> <li> <t>Set <tt>user_constrained_policy_set</tt> to <tt>authority_constrained_policy_set</tt>.</t> </li> <li> <t>If the user-initial-policy-set is not anyPolicy: </t> <ol spacing="normal" type="(%i)"><li> <t>Remove any elements of <tt>user_constrained_policy_set</tt>whichthat do not appear in user-initial-policy-set.</t> </li> <li> <t>If anyPolicy appears in <tt>authority_constrained_policy_set</tt> with qualifiers AP-Q, for each OID P-OID in user-initial-policy-setwhichthat does not appear in <tt>user_constrained_policy_set</tt>, add P-OID with qualifiers AP-Q to <tt>user_constrained_policy_set</tt>.</t> </li> </ol> </li> </ol> </li> </ol><t>Additionally, this update replaces</blockquote> <t>In addition, the final paragraph in <xref section="6.1.5" sectionFormat="of" target="RFC5280"/> is updated as follows:</t> <t>OLD:</t><ul empty="true"> <li> <t>If<blockquote><t>If either (1) the value of <tt>explicit_policy</tt> variable is greater than zero or (2) the <tt>valid_policy_tree</tt> is not NULL, then path processing hassucceeded.</t> </li> </ul>succeeded.</t></blockquote> <t>NEW:</t><ul empty="true"> <li> <t>If<blockquote><t>If either (1) the value of <tt>explicit_policy</tt> is greater thanzerozero, or (2) the <tt>user_constrained_policy_set</tt> is not empty, then path processing hassucceeded.</t> </li> </ul>succeeded.</t></blockquote> </section> <section anchor="update-outputs"> <name>Updates to Section 6.1.6</name><t>This update<t>The following replaces <xref section="6.1.6" sectionFormat="of"target="RFC5280"/> with the following text:</t> <ul empty="true"> <li>target="RFC5280"/>:</t> <blockquote> <t>If path processing succeeds, the procedure terminates, returning a success indication together with the final value of the <tt>user_constrained_policy_set</tt>, the <tt>working_public_key</tt>, the <tt>working_public_key_algorithm</tt>, and the <tt>working_public_key_parameters</tt>.</t> <t>Note that the original procedure described in <xref target="RFC5280"/> included a <tt>valid_policy_tree</tt> 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 <xref target="CVE-2023-0464"/> and <xref target="CVE-2023-23524"/>. Accordingly, this output is deprecated. Computing this structure isNOT RECOMMENDED.</t><bcp14>NOT RECOMMENDED</bcp14>.</t> <!-- [rfced] Should "denial-of-service" here be updated to "denial-of-service attacks", or is the current okay? Original: However, this computation may consume exponential time and memory, so such implementations SHOULD mitigate denial-of-service in other ways, such as limiting the depth or size of the tree. Perhaps: 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. --> <t>An implementationwhichthat requires <tt>valid_policy_tree</tt> for compatibility with legacy systems may compute it from <tt>valid_policy_graph</tt> 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 implementationsSHOULD<bcp14>SHOULD</bcp14> mitigate denial-of-service attacks in other ways, such as by limiting the depth or size of the tree.</t></li> </ul></blockquote> </section> </section> <section anchor="other-mitigations"> <name>Other Mitigations</name> <t>X.509 implementations that are unable to switch to the policy graph structureSHOULD<bcp14>SHOULD</bcp14> mitigate the denial-of-service attack in other ways. This section describes alternate mitigation and partial mitigation strategies.</t> <section anchor="verify-signatures-first"> <name>Verify Signatures First</name> <t>X.509 validatorsSHOULD<bcp14>SHOULD</bcp14> 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 beimpacted. Forimpacted, for example:</t> <!-- [rfced] Will the text starting with "but where..." be clear to readers? Original: * Any application that evaluates an otherwise trusted PKI, but where untrusted entities have technically-constrained intermediate certificates where policy mapping and path length are unconstrained. Perhaps: * Any application that evaluates an otherwise trusted PKI that includes untrusted entities with technically constrained intermediate certificates where policy mapping and path length are unconstrained. --> <ul spacing="normal"> <li> <t>Any application that evaluates an untrusted PKI, such as a hosting provider that evaluates a customer-supplied PKI</t> </li> <li> <t>Any application that evaluates an otherwise trustedPKI, but wherePKI that includes untrusted entitieshave technically-constrainedwith technically constrained intermediatecertificates wherecertificates. If the intermediates do not constrain policy mappingandor pathlength are unconstrained.</t>length, those entities may be able to perform this attack.</t> </li> </ul> </section> <section anchor="limit-certificate-depth"> <name>Limit Certificate Depth</name> <t>The policy tree grows exponentially in the depth of a certification path, so limiting the depth and certificate size can mitigate the attack.</t> <!-- [rfced] Does the "^" here denote superscript? If so, would you you like to make use of <sup> for superscript in this document? In the html and pdf outputs, it appears as superscript; in the text output, it will appear the same. Original: 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. --> <t>However, this option may not be viable for all applications. Too low of a limit may reject existing pathswhichthat the application wishes to accept. Too high of a limit may still admit aDoSdenial-of-service attack for the application. By modifying the example in <xref target="exponential-growth"/> to increase the number of policies asserted in each certificate, an attacker could still achieveO(N^(depth/2))O(N<sup>(depth/2)</sup>) scaling.</t> </section> <section anchor="limit-policy-tree-size"> <name>Limit Policy Tree Size</name> <t>The attack can be mitigated by limiting the number of nodes in the policytree,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 theapplication,application but low enough to no longer admit aDoSdenial-of-service attack.</t> </section> <section anchor="inhibit-policy-mapping"> <name>Inhibit Policy Mapping</name> <t>If policy mapping is disabled via the initial-policy-mapping-inhibit setting (see <xref section="6.1.1" sectionFormat="of" target="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 pathswhichthat rely on policy mapping.</t> <t>To facilitate this mitigation, certificate authoritiesSHOULD NOT<bcp14>SHOULD NOT</bcp14> issue certificates with the policy mappings extension (<xref section="4.2.1.5" sectionFormat="of" target="RFC5280"/>). Applications maintaining policies for accepted trust anchors areRECOMMENDED<bcp14>RECOMMENDED</bcp14> to forbid this extension in participating certificate authorities.</t> </section> <section anchor="disable-policy-checking"> <name>Disable Policy Checking</name> <t>An X.509 validator can mitigate this attack by disabling policy validation entirely. This may be viable for applicationswhichthat do not require policy validation. In this case, critical policy-related extensions, notably the policy constraints extension (<xref section="4.2.1.11" sectionFormat="of" target="RFC5280"/>),MUST<bcp14>MUST</bcp14> be treated as unrecognized extensions as described in <xref section="4.2" sectionFormat="of" target="RFC5280"/> and be rejected.</t> </section> </section> <sectionremoveInRFC="true" anchor="implementation-status"> <name>Implementation Status</name> <t>This section records the status of known implementations of the protocol defined by this specification at the time of posting of this Internet-Draft, and is based on a proposal described in RFC 7942. The description of implementations in this section is intended to assist the IETF in its decision processes in progressing drafts to RFCs. Please note that the listing of any individual implementation here does not imply endorsement by the IETF. Furthermore, no effort has been spent to verify the information presented here that was supplied by IETF contributors. This is not intended as, and must not be construed to be, a catalog of available implementations or their features. Readers are advised to note that other implementations may exist.</t> <t>According to RFC 7942, "this will allow reviewers and working groups to assign due consideration to documents that have the benefit of running code, which may serve as evidence of valuable experimentation and feedback that have made the implemented protocols more mature. It is up to the individual working groups to use this information as they see fit".</t> <t>The following projects adopted the concept outlined in this document:</t> <ul spacing="normal"> <li> <t><xref target="BoringSSL"/></t> </li> <li> <t><xref target="LibreSSL"/></t> </li> </ul> </section> <sectionanchor="security-considerations"> <name>Security Considerations</name> <t><xref target="dos"/> discusses how<xref target="RFC5280"/>'sthe policy tree algorithm in <xref target="RFC5280"/> can lead to denial-of-service vulnerabilities in X.509-based applications, such as <xref target="CVE-2023-0464"/> and <xref target="CVE-2023-23524"/>.</t> <t><xref target="updates"/> replaces this algorithm to avoid this issue. As discussed in <xref target="policy-graph"/>, 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.</t> </section> <section anchor="iana-considerations"> <name>IANA Considerations</name> <t>This document has no IANA actions.</t> </section> </middle> <back> <references> <name>References</name> <references anchor="sec-normative-references"> <name>Normative References</name><reference anchor="RFC5280"> <front> <title>Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile</title> <author fullname="D. Cooper" initials="D." surname="Cooper"/> <author fullname="S. Santesson" initials="S." surname="Santesson"/> <author fullname="S. Farrell" initials="S." surname="Farrell"/> <author fullname="S. Boeyen" initials="S." surname="Boeyen"/> <author fullname="R. Housley" initials="R." surname="Housley"/> <author fullname="W. Polk" initials="W." surname="Polk"/> <date month="May" year="2008"/> <abstract> <t>This memo profiles the X.509 v3 certificate and X.509 v2 certificate revocation list (CRL) for use in the Internet. An overview of this approach and model is provided as an introduction. The X.509 v3 certificate format is described in detail, with additional information regarding<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5280.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/> <xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/> </references> <references anchor="sec-informative-references"> <name>Informative References</name> <!-- [rfced] FYI - For reference [X.509], we added theformat and semantics of Internet name forms. Standard certificate extensionsfollowing URL. Please let us know if there aredescribedany objections. Original: [X.509] International Telecommunications Union, "Information technology - Open Systems Interconnection - The Directory: Public-key andtwo Internet-specific extensions are defined. A set of requiredattribute certificateextensions is specified.frameworks", ITU-T Recommendation X.509, October 2019. Current: [X.509] ITU-T, "Information technology - Open Systems Interconnection - TheX.509 v2 CRL format is described in detail along with standard and Internet-specific extensions. An algorithm for X.509 certification path validation is described. An ASN.1 module and examples are provided in the appendices. [STANDARDS-TRACK]</t> </abstract> </front> <seriesInfo name="RFC" value="5280"/> <seriesInfo name="DOI" value="10.17487/RFC5280"/> </reference> <reference anchor="RFC2119"> <front> <title>Key words for use in RFCs to Indicate Requirement Levels</title> <author fullname="S. Bradner" initials="S." surname="Bradner"/> <date month="March" year="1997"/> <abstract> <t>In many standards track documents several words are used to signify the requirements in the specification. These words are often capitalized. This document defines these words as they should be interpreted in IETF documents. This document specifies an Internet Best Current Practices for the Internet Community, and requests discussionDirectory: Public-key andsuggestions for improvements.</t> </abstract> </front> <seriesInfo name="BCP" value="14"/> <seriesInfo name="RFC" value="2119"/> <seriesInfo name="DOI" value="10.17487/RFC2119"/> </reference> <reference anchor="RFC8174"> <front> <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title> <author fullname="B. Leiba" initials="B." surname="Leiba"/> <date month="May" year="2017"/> <abstract> <t>RFC 2119 specifies common key words that may be used in protocol specifications. This document aims to reduce the ambiguity by clarifying that only UPPERCASE usage of the key words have the defined special meanings.</t> </abstract> </front> <seriesInfo name="BCP" value="14"/> <seriesInfo name="RFC" value="8174"/> <seriesInfo name="DOI" value="10.17487/RFC8174"/> </reference> </references> <references anchor="sec-informative-references"> <name>Informative References</name>attribute certificate frameworks", ITU-T Recommendation X.509, October 2019, <https://www.itu.int/rec/T-REC-X.509>. --> <referenceanchor="X.509">anchor="X.509" target="https://www.itu.int/rec/T-REC-X.509"> <front> <title>Information technology - Open Systems Interconnection - The Directory: Public-key and attribute certificate frameworks</title> <author><organization>International Telecommunications Union</organization><organization>ITU-T</organization> </author> <date year="2019" month="October"/> </front> <seriesInfoname="ITU-T" value="Recommendation X.509"/>name="ITU-T Recommendation" value="X.509"/> </reference> <reference anchor="CVE-2023-0464" target="https://www.cve.org/CVERecord?id=CVE-2023-0464"> <front> <title>Excessive Resource Usage Verifying X.509 Policy Constraints</title> <author><organization/><organization>CVE</organization> </author> <date year="2023" month="March"/> </front> <refcontent>CVE-2023-0464</refcontent> </reference> <reference anchor="CVE-2023-23524" target="https://www.cve.org/CVERecord?id=CVE-2023-23524"> <front> <title>Processing a maliciously crafted certificate may lead to a denial-of-service</title> <author><organization/><organization>CVE</organization> </author> <date year="2023" month="February"/> </front> <refcontent>CVE-2023-23524</refcontent> </reference><reference anchor="BoringSSL" target="https://boringssl.googlesource.com/boringssl"> <front> <title>BoringSSL</title> <author> <organization/> </author> <date year="2024" month="January"/> </front> </reference> <reference anchor="LibreSSL" target="https://www.libressl.org/"> <front> <title>LibreSSL</title> <author> <organization/> </author> <date year="2024" month="January"/> </front> </reference> <reference anchor="RFC8446"> <front> <title>The Transport Layer Security (TLS) Protocol Version 1.3</title> <author fullname="E. Rescorla" initials="E." surname="Rescorla"/> <date month="August" year="2018"/> <abstract> <t>This document specifies version 1.3 of the Transport Layer Security (TLS) protocol. TLS allows client/server applications to communicate over the Internet in a way that is designed to prevent eavesdropping, tampering, and message forgery.</t> <t>This document updates RFCs 5705 and 6066, and obsoletes RFCs 5077, 5246, and 6961. This document also specifies new requirements for TLS 1.2 implementations.</t> </abstract> </front> <seriesInfo name="RFC" value="8446"/> <seriesInfo name="DOI" value="10.17487/RFC8446"/> </reference><xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8446.xml"/> </references> </references><?line 802?><section numbered="false" anchor="acknowledgements"> <name>Acknowledgements</name> <t>The author thanksBob Beck, Adam Langley, Matt Mueller, and Ryan Sleevi<contact fullname="Bob Beck"/>, <contact fullname="Adam Langley"/>, <contact fullname="Matt Mueller"/>, and <contact fullname="Ryan Sleevi"/> for many valuable discussions that led to discovering this issue, understanding it, and developing the mitigation. The author also thanksMartin Thomson and Job Snijders<contact fullname="Martin Thomson"/>, <contact fullname="Job Snijders"/>, and <contact fullname="John Scudder"/> for their review and feedback on this document.</t> </section> </back> <!--##markdown-source: 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 +SGqfLLEaiYeWhFoxdVq5+W7k9OdEf+vXr2mv9+++MO7o7cvDvHvk98fHB/b P0yJk9+/fncMvyfyl3vz+euXL1+8OuSX4anqPHp58NMOa/ud129Oj16/Ojje YdkD82GhHQ4LeHMqemBdaRR5qY8n4J3vn79Ru0+Fg/d2d78BLuQv/7j7G1ia IKt0wY2VBYg4/goTsEG202mFlaC0mqXrvEmXsPqhifqsvCgU8LcmYh6SMMEp OhFh8mMgTC7v4eIXbGoUllsLUJlVST508RiEABkOKAnUzmSvo3huK+SSISHH 60zg1CnIizq5rmmyuYDLWVZ9oIG85xX1HiXOB5RKJHrKeRLj1JEC3Rquz5hm JPYsSpRRADlwUSxAihSilkRHsRqz6hxVSVQ/piqCDeKIFZu8X8Oaq5D9HH71 BKu8TxioCuEbrU8EcShcdMa4CPiZ3zTgltsAOQDCBZphJvdwJCKssBJpsma4 5dMVpvCHEkFWirIatdZ6XZKajdBXcES9nyT/oA4KXlMrneVpx3MgOJVIGMJE +Gd3hP/u8Wjgr2cTsNoAyJjanWTFwth9+P+JLW6ePJ1IL3SRjVFKNZub92Fv FFb69UQW3kXZLjNECe2yCdiEVzNBOlgI+WyMT0Frq1clgmIEtjgWWyF6vEhc 58Vs2WYwD0BmmZF0VpU188TFWbk0OLMuWaZkJb3oRAs8TeZkKXoqIvnrX/+q 0rQ+X4jjJP75auw+X/kl35YlWNLe5xMuE1nMnz6vzt7n06Wt8+qu6lSP3J8/ by35yP+yteh552ukrN/B8VexZ/jSkbck9pGm8CGmVfLFPdujL2S3PiNBn1bA Jg9v2lLn8+mSGRpXxpXXEj7eu6KWPndM0c+n2LM7Kn0ee/YF3X9hJYQ3JU+8 fkWm5OvbTgksx+RyX91z0oFdWN/ugIx6wfI1dECixty5YiTF/oami0etRccW ovUK5R0EUzd6XasH2cNR8kCLF+TB/CFq31AhPwkV8si8eQYvPcjxn1/Ct5Kv +w4Mrl/eTPGlqWlzEWkTXQuJe5tRwwtnNKrfgRUJ6uXynmdJjhf0UMgTAQpk e9bXucTARC4S7CkQZ7J7E4KA5QkEX1p1/Ybw0prcYDpZgV7IcSZJ+wrCyOfK Phe1bnUx+kpAYb0x9qY1ZFGos2bJ/6JZSc8qDV2m+cRnUiep4HMNowMdQ6b6 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 hvhBwgve2zpIV3V8tyBAH0wfqvyfCgtFAoMM90+X8zGnjeS4Futq6DpSrI8e ZDyNhdGRtP7Q5NwhRbfdb4CCXtyv12yh8kkfkVwGQ+Rz44oxKk+M0jQSvdlp zMEJzydhzsbcAjt9CXA6+Czk1IdNtd3L73t4fC+ONyUDbhxpgiP/ai9fHWXD bYvCeKTUg12r3tNacilcx/myC4exGoaXiL6OoXBsfcafBJz4P+hyEenkUz50 uHxWvdbrItjR244I18wtnSo84v4OK7MZYr8uGA1yTE38yY94U24K0joelRhA m2pYSwzTrEAe58XYjs1DajGYFlcN2/VR3Key3aHyJe2EqvfmTpTPbDPkWL9N T/9+6di6Y+y4NWIY0dP4ftlrivplryvqlb22qCsbK9rN/2X+vxOOCLCe1y+H D++G8y5xuXtwy3CBexxHe5/dYojh1F3znQNziOTi4uJmYO6PCOZQrj73pKb9 9YWtbADjYS+eeL6e3PprtgGXQEOAhFxiVCsK6rLljJSeSMXz5pT+i6JR8JER om81SGgbWQjqty2afCkd4RyDPakcac8eyt2uUAf2N73kh2vAAkDlqysW5b6s RzURwSE2KHeVVh9NlBFA0/t/us+OiqK03bMppjb0BhMls1oT88XbQ7KkqAT+ uBRM3GHOiGDybPV7tce9oh0Hr1Pq/k/3Jfql0/RREWtn9NnzYAZqZtWmnKeU nJb/b5EZ6map+j7Zvj35wlofeXUPGtvmZKTaWqyboWVI7H617VtEEfPfsW8/ yTfLD1/Yot/uz8E3+9tAaXvE85rSIY2Gdwk+n15/kr9j9DK/XQdbbkcv8/k/ zUrm23a9epP2Qn0ngtYpuNZepNGX0KSlkps7IthmltCOUdyUNXrMhF4nCehA vkuHpac4JNDkwRYa32Hed0JcFyViwzOwsd9ui6B5uiWChnwdvZCZp18WMrNn Q2as9Rq5UsPFyrAXxZlFnBPysMTIWLH3jg7HbzpnfftVbotxkYkWUsq76lxC kCJTIIpV4Isw2i1AjBi53PHa20zwX2NWGvRnNO4MFr8rGakD0rCXxcGGWkAZ 5m2X10LvBHVJDoMP0nLScdXdmHAjS6peNME2wuGOiqFy3xuFXbabMgGi9AlO mGSwDi+clNhtKPhBKrBB7AE+kcMdddeVErZgvCD+iUsrqeLBSMPeMRz7b70t 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[rfced] The SVG figures in this document have width or height specified, which will make the artwork not scale. Please consider whether scaling should be enabled. Scaling will allow the figures to be resized when viewed on a mobile device; however, there may be aesthetic trade-offs (e.g., a given image may appear too large on a desktop screen, or different figures may scale differently based on their relative sizes). Please review Figures 1-8 in the HTML and PDF outputs, and let us know how to proceed. --> <!-- [rfced] The following terms appear both with and without <tt> in the xml file. Should all instances (aside from those in figures) be marked with <tt>? policy_mapping valid_policy_graph valid_policy --> <!-- [rfced] Please review the "Inclusive Language" portion of the online Style Guide <https://www.rfc-editor.org/styleguide/part2/#inclusive_language> and let us know if any changes are needed. Note that our script did not flag any words in particular, but this should still be reviewed as a best practice. --> </rfc>