RFC 3280

Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile

📅 published May 2002, from ietf

RFC 3280: Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile ✨🎀

okay bestie, let's start with the basics 💅 This is RFC 3280, published in April 2002 by the Network Working Group. It's a Standards Track document, which means it's an official Internet protocol spec, not just a vibe. 🔥

The authors are R. Housley (RSA Laboratories), W. Polk (NIST), W. Ford (VeriSign), and D. Solo (Citigroup). The big news is that this RFC obsoletes RFC 2459 💀, so 2459 is out and 3280 is the new source of truth. It doesn't update any other RFCs.


Status of this Memo

ok so this doc is an Internet standards track protocol for the Internet community, and it's basically asking everyone to talk about it and send ideas for making it better 🫶. If you want to know where this protocol actually stands, check the current edition of "Internet Official Protocol Standards" (STD 1), which tracks the official standardization state and status 📚. And distribution of this memo is unlimited, so share it with everyone 💖


this one's the legal bit but still cute 🌸 Copyright (C) The Internet Society (2002). All Rights Reserved. 🦋


Abstract

so here's the tea ☕ This memo sets the rules for how the X.509 v3 certificate and X.509 v2 Certificate Revocation List (CRL) get used on the Internet 🌐. It starts with a quick overview and the model behind it, so you're not lost ✨

The v3 certificate format gets a deep dive, including extra info on how Internet name forms are formatted and what they mean 🧚. Then it covers the standard certificate extensions, and defines two Internet-specific extensions of its own 🎀. There's also a set of certificate extensions that are required 🔥

The v2 CRL format gets the same deep-dive treatment, and the required CRL extensions get defined too 👑. Last but not least, it describes an algorithm for X.509 certification path validation, which is how you check a chain of certificates all the way up 🫶. The ASN.1 module and examples live in the appendices, so go check those out too 🍓


Table of Contents 📚

   1  Introduction  . . . . . . . . . . . . . . . . . . . . . .   4
   2  Requirements and Assumptions  . . . . . . . . . . . . . .   5
   2.1  Communication and Topology  . . . . . . . . . . . . . .   6
   2.2  Acceptability Criteria  . . . . . . . . . . . . . . . .   6
   2.3  User Expectations . . . . . . . . . . . . . . . . . . .   7
   2.4  Administrator Expectations  . . . . . . . . . . . . . .   7
   3  Overview of Approach  . . . . . . . . . . . . . . . . . .   7
   3.1  X.509 Version 3 Certificate . . . . . . . . . . . . . .   8
   3.2  Certification Paths and Trust . . . . . . . . . . . . .   9
   3.3  Revocation  . . . . . . . . . . . . . . . . . . . . . .  11
   3.4  Operational Protocols . . . . . . . . . . . . . . . . .  13
   3.5  Management Protocols  . . . . . . . . . . . . . . . . .  13
   4  Certificate and Certificate Extensions Profile  . . . . .  14
   4.1  Basic Certificate Fields  . . . . . . . . . . . . . . .  15
   4.1.1  Certificate Fields  . . . . . . . . . . . . . . . . .  16
   4.1.1.1  tbsCertificate  . . . . . . . . . . . . . . . . . .  16
   4.1.1.2  signatureAlgorithm  . . . . . . . . . . . . . . . .  16
   4.1.1.3  signatureValue  . . . . . . . . . . . . . . . . . .  16
   4.1.2  TBSCertificate  . . . . . . . . . . . . . . . . . . .  17
   4.1.2.1  Version . . . . . . . . . . . . . . . . . . . . . .  17
   4.1.2.2  Serial number . . . . . . . . . . . . . . . . . . .  17
   4.1.2.3  Signature . . . . . . . . . . . . . . . . . . . . .  18
   4.1.2.4  Issuer  . . . . . . . . . . . . . . . . . . . . . .  18
   4.1.2.5  Validity  . . . . . . . . . . . . . . . . . . . . .  22
   4.1.2.5.1  UTCTime . . . . . . . . . . . . . . . . . . . . .  22
   4.1.2.5.2  GeneralizedTime . . . . . . . . . . . . . . . . .  22
   4.1.2.6  Subject . . . . . . . . . . . . . . . . . . . . . .  23
   4.1.2.7  Subject Public Key Info . . . . . . . . . . . . . .  24
   4.1.2.8  Unique Identifiers  . . . . . . . . . . . . . . . .  24
   4.1.2.9 Extensions . . . . . . . . . . . . . . . . . . . . .  24
   4.2  Certificate Extensions  . . . . . . . . . . . . . . . .  24
   4.2.1  Standard Extensions . . . . . . . . . . . . . . . . .  25
   4.2.1.1  Authority Key Identifier  . . . . . . . . . . . . .  26
   4.2.1.2  Subject Key Identifier  . . . . . . . . . . . . . .  27
   4.2.1.3  Key Usage . . . . . . . . . . . . . . . . . . . . .  28
   4.2.1.4  Private Key Usage Period  . . . . . . . . . . . . .  29
   4.2.1.5  Certificate Policies  . . . . . . . . . . . . . . .  30
   4.2.1.6  Policy Mappings . . . . . . . . . . . . . . . . . .  33
   4.2.1.7  Subject Alternative Name  . . . . . . . . . . . . .  33
   4.2.1.8  Issuer Alternative Name . . . . . . . . . . . . . .  36
   4.2.1.9  Subject Directory Attributes  . . . . . . . . . . .  36
   4.2.1.10  Basic Constraints  . . . . . . . . . . . . . . . .  36
   4.2.1.11  Name Constraints . . . . . . . . . . . . . . . . .  37
   4.2.1.12  Policy Constraints . . . . . . . . . . . . . . . .  40
   4.2.1.13  Extended Key Usage . . . . . . . . . . . . . . . .  40
   4.2.1.14  CRL Distribution Points  . . . . . . . . . . . . .  42
   4.2.1.15  Inhibit Any-Policy . . . . . . . . . . . . . . . .  44
   4.2.1.16  Freshest CRL . . . . . . . . . . . . . . . . . . .  44
   4.2.2  Internet Certificate Extensions . . . . . . . . . . .  45
   4.2.2.1  Authority Information Access  . . . . . . . . . . .  45
   4.2.2.2  Subject Information Access  . . . . . . . . . . . .  46
   5  CRL and CRL Extensions Profile  . . . . . . . . . . . . .  48
   5.1  CRL Fields  . . . . . . . . . . . . . . . . . . . . . .  49
   5.1.1  CertificateList Fields  . . . . . . . . . . . . . . .  50
   5.1.1.1  tbsCertList . . . . . . . . . . . . . . . . . . . .  50
   5.1.1.2  signatureAlgorithm  . . . . . . . . . . . . . . . .  50
   5.1.1.3  signatureValue  . . . . . . . . . . . . . . . . . .  51
   5.1.2  Certificate List "To Be Signed" . . . . . . . . . . .  51
   5.1.2.1  Version . . . . . . . . . . . . . . . . . . . . . .  52
   5.1.2.2  Signature . . . . . . . . . . . . . . . . . . . . .  52
   5.1.2.3  Issuer Name . . . . . . . . . . . . . . . . . . . .  52
   5.1.2.4  This Update . . . . . . . . . . . . . . . . . . . .  52
   5.1.2.5  Next Update . . . . . . . . . . . . . . . . . . . .  53
   5.1.2.6  Revoked Certificates  . . . . . . . . . . . . . . .  53
   5.1.2.7  Extensions  . . . . . . . . . . . . . . . . . . . .  53
   5.2  CRL Extensions  . . . . . . . . . . . . . . . . . . . .  53
   5.2.1  Authority Key Identifier  . . . . . . . . . . . . . .  54
   5.2.2  Issuer Alternative Name . . . . . . . . . . . . . . .  54
   5.2.3  CRL Number  . . . . . . . . . . . . . . . . . . . . .  55
   5.2.4  Delta CRL Indicator . . . . . . . . . . . . . . . . .  55
   5.2.5  Issuing Distribution Point  . . . . . . . . . . . . .  58
   5.2.6  Freshest CRL  . . . . . . . . . . . . . . . . . . . .  59
   5.3  CRL Entry Extensions  . . . . . . . . . . . . . . . . .  60
   5.3.1  Reason Code . . . . . . . . . . . . . . . . . . . . .  60
   5.3.2  Hold Instruction Code . . . . . . . . . . . . . . . .  61
   5.3.3  Invalidity Date . . . . . . . . . . . . . . . . . . .  62
   5.3.4  Certificate Issuer  . . . . . . . . . . . . . . . . .  62
   6  Certificate Path Validation . . . . . . . . . . . . . . .  62
   6.1  Basic Path Validation . . . . . . . . . . . . . . . . .  63
   6.1.1  Inputs  . . . . . . . . . . . . . . . . . . . . . . .  66
   6.1.2  Initialization  . . . . . . . . . . . . . . . . . . .  67
   6.1.3  Basic Certificate Processing  . . . . . . . . . . . .  70
   6.1.4  Preparation for Certificate i+1 . . . . . . . . . . .  75
   6.1.5  Wrap-up procedure . . . . . . . . . . . . . . . . . .  78
   6.1.6  Outputs . . . . . . . . . . . . . . . . . . . . . . .  80
   6.2  Extending Path Validation . . . . . . . . . . . . . . .  80
   6.3  CRL Validation  . . . . . . . . . . . . . . . . . . . .  81
   6.3.1  Revocation Inputs . . . . . . . . . . . . . . . . . .  82
   6.3.2  Initialization and Revocation State Variables . . . .  82
   6.3.3  CRL Processing  . . . . . . . . . . . . . . . . . . .  83
   7  References  . . . . . . . . . . . . . . . . . . . . . . .  86
   8  Intellectual Property Rights  . . . . . . . . . . . . . .  88
   9  Security Considerations . . . . . . . . . . . . . . . . .  89
   Appendix A.  ASN.1 Structures and OIDs . . . . . . . . . . .  92
   A.1 Explicitly Tagged Module, 1988 Syntax  . . . . . . . . .  92
   A.2 Implicitly Tagged Module, 1988 Syntax  . . . . . . . . . 105
   Appendix B.  ASN.1 Notes . . . . . . . . . . . . . . . . . . 112
   Appendix C.  Examples  . . . . . . . . . . . . . . . . . . . 115
   C.1  DSA Self-Signed Certificate . . . . . . . . . . . . . . 115
   C.2  End Entity Certificate Using DSA  . . . . . . . . . . . 119
   C.3  End Entity Certificate Using RSA  . . . . . . . . . . . 122
   C.4  Certificate Revocation List . . . . . . . . . . . . . . 126
   Author Addresses . . . . . . . . . . . . . . . . . . . . . . 128
   Full Copyright Statement . . . . . . . . . . . . . . . . . . 129

1. Introduction ✨

okay so bestie, this spec is one piece of a whole family of standards for the X.509 Public Key Infrastructure (PKI) for the Internet 🔐💖

it profiles the format and semantics of certificates and certificate revocation lists (CRLs) for the Internet PKI. it also describes procedures for processing certification paths in the Internet environment, and the appendices give ASN.1 modules for all the data structures it defines or references 🎀

section 2 covers the Internet PKI requirements and the assumptions that shape the scope of this doc 🧚 section 3 presents an architectural model and explains how it relates to earlier IETF and ISO/IEC/ITU-T standards. it spells out how this document connects to the IETF PEM specs and the ISO/IEC/ITU-T X.509 docs 🦋

section 4 profiles the X.509 version 3 certificate, and section 5 profiles the X.509 version 2 CRL. both include the ISO/IEC/ITU-T and ANSI extensions that might be useful in the Internet PKI 💅 the profiles are written in the 1988 Abstract Syntax Notation One (ASN.1) instead of the 1997 ASN.1 syntax that the newest ISO/IEC/ITU-T standards use 🌸

section 6 has the certification path validation procedures, which are based on the ISO/IEC/ITU-T definition. implementations are REQUIRED to derive the same results, but they are not required to use the specified procedures 👑 that's a very important distinction, so don't mix it up 🙈

procedures for identifying and encoding public key material and digital signatures live in [PKIXALGS] 🔑 implementations of this spec are not required to use any particular cryptographic algorithms. BUT if a conforming implementation uses the algorithms identified in [PKIXALGS], it MUST identify and encode the public key material and digital signatures the way that companion spec describes ✨

lastly, three appendices are here to help implementers 🧚 Appendix A has all the ASN.1 structures defined or referenced in this spec, again in the 1988 ASN.1. Appendix B has notes on the less familiar features of the ASN.1 notation used here. Appendix C has examples of a conforming certificate and a conforming CRL 💜

this spec obsoletes RFC 2459 🫶 and it differs from RFC 2459 in five big ways, so let's go:

  • 🔥 to promote interoperable implementations, there's now a detailed certification path validation algorithm in section 6.1. RFC 2459 only had a high-level description of path validation, so this is a major glow-up
  • 🔥 there's an algorithm in section 6.3 for working out a certificate's status using CRLs. that material wasn't in RFC 2459 at all
  • 🔥 to support new usage models, Section 5 now has detailed info on using delta CRLs
  • 🔥 identification and encoding of public key material and digital signatures aren't in this spec anymore. they're now covered in the companion spec [PKIXALGS]
  • 🔥 four extra extensions are specified: three certificate extensions and one CRL extension 🌈 the certificate ones are subject info access, inhibit any-policy, and freshest CRL, and freshest CRL is also defined as a CRL extension
  • 🔥 throughout the spec, clarifications were added so it lines up better with the ITU-T X.509 spec. X.509 defines the certificate and CRL format and a lot of the extensions in here, so these changes make it more likely that implementations of this spec interoperate with implementations based on the ITU-T spec 💖

the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 🎀 these are the words that carry real weight, so keep an eye out for them 👀

2. Requirements and Assumptions 🌸

the goal of this spec is to develop a profile that makes it easier to use X.509 certificates in Internet applications, for communities that want to use X.509 tech 💅 those applications can include WWW, electronic mail, user authentication, and IPsec. to remove some of the obstacles to using X.509 certificates, this document defines a profile that helps with building certificate management systems, developing application tools, and getting interoperability determined by policy 🧚

some communities will need to supplement this profile, or maybe replace it entirely, to meet the needs of specialized application domains or environments with extra authorization, assurance, or operational requirements 🦋 but for basic applications, there are common representations of frequently used attributes. that way, app developers can grab the info they need without caring which issuer made a particular certificate or certificate revocation list (CRL) 💜

a certificate user should review the certificate policy the certification authority (CA) generated before relying on the authentication or non-repudiation services tied to the public key in a particular certificate 👀 with that in mind, this standard doesn't prescribe legally binding rules or duties ⚖️

as supplemental authorization and attribute management tools show up, like attribute certificates, it may be appropriate to limit the authenticated attributes included in a certificate 🌈 those other management tools might be better ways to convey lots of authenticated attributes ✨

2.1. Communication and Topology 🌐

the users of certificates will work in a wide range of environments when it comes to communication topology, especially users of secure electronic mail 💌 this profile supports users without high bandwidth, real-time IP connectivity, or high connection availability. on top of that, the profile allows for firewalls or other filtered communication 🛡️

this profile doesn't assume that an X.500 Directory system or an LDAP directory system is deployed. it also doesn't prohibit using an X.500 Directory or an LDAP directory. any means of distributing certificates and certificate revocation lists (CRLs) can be used, so no drama there 🫶

2.2. Acceptability Criteria 🎯

the goal of the Internet Public Key Infrastructure (PKI) is to meet the needs of deterministic, automated identification, authentication, access control, and authorization functions 🤖 the services it supports decide which attributes go in the certificate, plus the ancillary control info in there, like policy data and certification path constraints 💖

2.3. User Expectations 🧑‍💻

users of the Internet PKI are people and processes that use client software and are the subjects named in certificates 🙋‍♀️ these uses include readers and writers of electronic mail, the clients for WWW browsers, WWW servers, and the key manager for IPsec within a router. this profile knows the platforms these users rely on have limits, and so do the users themselves in terms of sophistication and attentiveness 🥹

because of that, the profile asks for minimal user configuration (for example, trusted CA keys and rules), explicit platform usage constraints inside the certificate, and certification path constraints that shield the user from lots of malicious actions. applications should sensibly automate validation functions too 🛡️✨

2.4. Administrator Expectations 🛠️

same energy as the user expectations: the Internet PKI profile is built to support the people who generally operate CAs 🧑‍🔧 giving administrators unbounded choices raises the chances that one subtle CA administrator mistake turns into broad compromise 😭 unbounded choices also make the software that processes and validates the certificates the CA creates way more complicated 💀

3. Overview of Approach 🗺️

here's a simplified view of the architectural model the PKIX specifications assume 🦋

the components in this model are:

  • end entity: a user of PKI certificates and/or an end user system that is the subject of a certificate 🙋‍♀️
  • CA: certification authority 👑
  • RA: registration authority, i.e., an optional system that a CA delegates certain management functions to 🧚
  • CRL issuer: an optional system that a CA delegates the publication of certificate revocation lists to 📜
  • repository: a system or collection of distributed systems that stores certificates and CRLs and serves as a means of distributing them to end entities 📦

note that an Attribute Authority (AA) might also choose to delegate the publication of CRLs to a CRL issuer 💜

+---+
| C |                       +------------+
| e | <-------------------->| End entity |
| r |       Operational     +------------+
| t |       transactions          ^
| i |      and management         |  Management
| f |       transactions          |  transactions        PKI
| i |                             |                     users
| c |                             v
| a | =======================  +--+------------+  ==============
| t |                          ^               ^
| e |                          |               |         PKI
|   |                          v               |      management
| & |                       +------+           |       entities
|   | <---------------------|  RA  |<----+     |
| C |  Publish certificate  +------+     |     |
| R |                                    |     |
| L |                                    |     |
|   |                                    v     v
| R |                                +------------+
| e | <------------------------------|     CA     |
| p |   Publish certificate          +------------+
| o |   Publish CRL                     ^      ^
| s |                                   |      |  Management
| i |                +------------+     |      |  transactions
| t | <--------------| CRL Issuer |<----+      |
| o |   Publish CRL  +------------+            v
| r |                                      +------+
| y |                                      |  CA  |
+---+                                      +------+

                   Figure 1 - PKI Entities

ooh the diagram 🌈✨ that's the whole PKI cast in one picture

3.1. X.509 Version 3 Certificate

Okay bestie, so users of a public key need to be sure the private key tied to it is owned by the right remote subject (person or system) that an encryption or digital signature mechanism is talking to 🔐. That confidence comes from public key certificates, which are data structures that bind public key values to subjects ✨. The binding is asserted when a trusted CA digitally signs each certificate. The CA can base that assertion on technical means (a.k.a., proof of possession through a challenge-response protocol), on presentation of the private key, or on an assertion by the subject 🦋. A certificate has a limited valid lifetime, and it's shown in its signed contents ⏳. A certificate-using client can independently check the signature and timeliness, so certificates can be distributed through untrusted communications and server systems, and they can get cached in unsecured storage in certificate-using systems. Iconic, honestly 👑.

ITU-T X.509 (formerly CCITT X.509) or ISO/IEC 9594-8, first published in 1988 as part of the X.500 Directory recommendations, defines a standard certificate format [X.509] 🌸. The certificate format in the 1988 standard is called the version 1 (v1) format. When X.500 got revised in 1993, two more fields were added, and that became the version 2 (v2) format.

The Internet Privacy Enhanced Mail (PEM) RFCs, published in 1993, include specifications for a public key infrastructure based on X.509 v1 certificates [RFC 1422]. The experience gained trying to deploy RFC 1422 made it super clear that the v1 and v2 certificate formats are deficient in several respects 💀. Most importantly, more fields were needed to carry information that PEM design and implementation experience had proven necessary. So ISO/IEC, ITU-T and ANSI X9 developed the X.509 version 3 (v3) certificate format 🎀. The v3 format extends the v2 format by adding provision for additional extension fields. Particular extension field types may be specified in standards or may be defined and registered by any organization or community. In June 1996, standardization of the basic v3 format was completed [X.509].

ISO/IEC, ITU-T, and ANSI X9 have also developed standard extensions for use in the v3 extensions field [X.509][X9.55]. These extensions can convey things like additional subject identification information, key attribute information, policy information, and certification path constraints 🧚.

The thing is, those standard extensions are very broad in their applicability 🙈. To develop interoperable implementations of X.509 v3 systems for Internet use, it's necessary to specify a profile for use of the X.509 v3 extensions that's tailored for the Internet. It's one goal of this document to specify a profile for Internet WWW, electronic mail, and IPsec applications. Environments with additional requirements may build on this profile or may replace it 💜.


3.2. Certification Paths and Trust

A user of a security service that needs to know a public key generally has to obtain and validate a certificate containing that key 🔑. If the public key user doesn't already hold an assured copy of the public key of the CA that signed the certificate, the CA's name, and related information (such as the validity period or name constraints), then it might need an additional certificate to get that public key. In general, a chain of multiple certificates may be needed: a certificate of the public key owner (the end entity) signed by one CA, plus zero or more additional certificates of CAs signed by other CAs. Such chains, called certification paths, are required because a public key user is only initialized with a limited number of assured CA public keys 🔗.

There are different ways CAs might be configured so that public key users can find certification paths. For PEM, RFC 1422 defined a rigid hierarchical structure of CAs. There are three types of PEM certification authority:

  • (a) Internet Policy Registration Authority (IPRA): This authority, operated under the auspices of the Internet Society, acts as the root of the PEM certification hierarchy at level 1. It issues certificates only for the next level of authorities, PCAs. All certification paths start with the IPRA.
  • (b) Policy Certification Authorities (PCAs): PCAs are at level 2 of the hierarchy, with each PCA being certified by the IPRA. A PCA shall establish and publish a statement of its policy with respect to certifying users or subordinate certification authorities. Distinct PCAs aim to satisfy different user needs. For example, one PCA (an organizational PCA) might support the general electronic mail needs of commercial organizations, and another PCA (a high-assurance PCA) might have a more stringent policy designed for satisfying legally binding digital signature requirements.
  • (c) Certification Authorities (CAs): CAs are at level 3 of the hierarchy and can also be at lower levels. Those at level 3 are certified by PCAs. CAs represent, for example, particular organizations, particular organizational units (e.g., departments, groups, sections), or particular geographical areas.

RFC 1422 furthermore has a name subordination rule, which requires that a CA can only issue certificates for entities whose names are subordinate (in the X.500 naming tree) to the name of the CA itself 📜. The trust associated with a PEM certification path is implied by the PCA name. The name subordination rule makes sure that CAs below the PCA are sensibly constrained as to the set of subordinate entities they can certify (e.g., a CA for an organization can only certify entities in that organization's name tree). Certificate user systems are able to mechanically check that the name subordination rule has been followed 🤖.

The RFC 1422 uses the X.509 v1 certificate formats. The limitations of X.509 v1 required imposing several structural restrictions to clearly associate policy information or restrict the utility of certificates. These restrictions included:

  • (a) a pure top-down hierarchy, with all certification paths starting from IPRA;
  • (b) a naming subordination rule restricting the names of a CA's subjects; and
  • (c) use of the PCA concept, which requires knowledge of individual PCAs to be built into certificate chain verification logic. Knowledge of individual PCAs was required to determine if a chain could be accepted.

With X.509 v3, most of the requirements addressed by RFC 1422 can be addressed using certificate extensions, without a need to restrict the CA structures used 🌈. In particular, the certificate extensions relating to certificate policies obviate the need for PCAs, and the constraint extensions obviate the need for the name subordination rule. So this document supports a more flexible architecture, including:

  • (a) Certification paths start with a public key of a CA in a user's own domain, or with the public key of the top of a hierarchy. Starting with the public key of a CA in a user's own domain has certain advantages. In some environments, the local domain is the most trusted.
  • (b) Name constraints may be imposed through explicit inclusion of a name constraints extension in a certificate, but are not required.
  • (c) Policy extensions and policy mappings replace the PCA concept, which permits a greater degree of automation. The application can determine if the certification path is acceptable based on the contents of the certificates instead of a priori knowledge of PCAs. This permits automation of certification path processing 🤩.

3.3. Revocation

When a certificate is issued, it's expected to be in use for its entire validity period. However, various circumstances may cause a certificate to become invalid prior to the expiration of the validity period 😬. Such circumstances include change of name, change of association between subject and CA (e.g., an employee terminates employment with an organization), and compromise or suspected compromise of the corresponding private key. Under such circumstances, the CA needs to revoke the certificate 🚫.

X.509 defines one method of certificate revocation. This method involves each CA periodically issuing a signed data structure called a certificate revocation list (CRL). A CRL is a time stamped list identifying revoked certificates, which is signed by a CA or CRL issuer and made freely available in a public repository 📋. Each revoked certificate is identified in a CRL by its certificate serial number. When a certificate-using system uses a certificate (e.g., for verifying a remote user's digital signature), that system not only checks the certificate signature and validity but also acquires a suitably-recent CRL and checks that the certificate serial number is not on that CRL. The meaning of "suitably-recent" may vary with local policy, but it usually means the most recently-issued CRL. A new CRL is issued on a regular periodic basis (e.g., hourly, daily, or weekly). An entry is added to the CRL as part of the next update following notification of revocation. An entry MUST NOT be removed from the CRL until it appears on one regularly scheduled CRL issued beyond the revoked certificate's validity period 🚨.

An advantage of this revocation method is that CRLs may be distributed by exactly the same means as certificates themselves, namely, via untrusted servers and untrusted communications 🦋.

One limitation of the CRL revocation method, using untrusted communications and servers, is that the time granularity of revocation is limited to the CRL issue period. For example, if a revocation is reported now, that revocation will not be reliably notified to certificate-using systems until all currently issued CRLs are updated -- this may be up to one hour, one day, or one week, depending on the frequency that CRLs are issued ⏰.

As with the X.509 v3 certificate format, in order to facilitate interoperable implementations from multiple vendors, the X.509 v2 CRL format needs to be profiled for Internet use. It's one goal of this document to specify that profile. However, this profile does not require the issuance of CRLs. Message formats and protocols supporting on-line revocation notification are defined in other PKIX specifications. On-line methods of revocation notification may be applicable in some environments as an alternative to the X.509 CRL. On-line revocation checking may significantly reduce the latency between a revocation report and the distribution of the information to relying parties. Once the CA accepts a revocation report as authentic and valid, any query to the on-line service will correctly reflect the certificate validation impacts of the revocation ✨. However, these methods impose new security requirements: the certificate validator needs to trust the on-line validation service, while the repository does not need to be trusted 🔐.

3.4. Operational Protocols ✨

okay so bestie, operational protocols are the delivery squad 🚚💖 They get certificates and CRLs (or status info) to the client systems that rely on them. There are lots of ways to deliver them, including distribution based on LDAP, HTTP, FTP, and X.500 🌸 The protocols that handle these are defined in other PKIX specs. Those specs can also define message formats and procedures for all of these environments, plus definitions of or references to the right MIME content types 🎀

3.5. Management Protocols 🧚

management protocols are the behind-the-scenes support team 💅 They handle on-line interactions between PKI users and management entities. For example, one might run between a CA and the client system holding a key pair, or between two CAs that cross-certify each other 🫶 The functions these protocols might need to support are:

  • (a) registration: the process where a user first makes itself known to a CA (directly, or through an RA) before that CA issues any certificate for that user 🪪
  • (b) initialization: before a client system can operate securely, it needs key materials that have the right relationship with keys stored elsewhere in the infrastructure 🔐 For example, the client needs to be securely initialized with the public key and other assured information of the trusted CA(s), so it can validate certificate paths.

Furthermore, a client typically needs to be initialized with its own key pair(s) 💜

  • (c) certification: the process where a CA issues a certificate for a user's public key, then returns that certificate to the user's client system and/or posts it in a repository 📬
  • (d) key pair recovery: as an option, user client key materials (e.g., a user's private key used for encryption purposes) may be backed up by a CA or a key backup system 🗝️ If a user needs to recover that backed up key material (e.g., after a forgotten password or a lost key chain file), an on-line protocol exchange may be needed to make it happen 🙈
  • (e) key pair update: all key pairs need to be updated regularly, meaning replaced with a new key pair and new certificates issued 🔄
  • (f) revocation request: an authorized person tells a CA about an abnormal situation that requires certificate revocation 🚨
  • (g) cross-certification: two CAs exchange the information used to establish a cross-certificate. A cross-certificate is a certificate issued by one CA to another CA, containing a CA signature key that is used for issuing certificates 🦋

Note that on-line protocols are not the only way to do any of this 🌈 For every function there are off-line methods that achieve the same result, and this specification does not mandate on-line protocols. For example, when hardware tokens are used, many of these functions can happen as part of the physical token delivery 📦 Some of the functions can also be combined into one protocol exchange. Specifically, two or more of the registration, initialization, and certification functions can be combined into one exchange ✨

The PKIX series of specifications defines a set of standard message formats that support the functions above 💌 The protocols for carrying these messages in different environments (e.g., e-mail, file transfer, and WWW) are described in those specifications 🍓

4. Certificate and Certificate Extensions Profile 👑

okay this section is the main event 🎀 It presents a profile for public key certificates that fosters interoperability and a reusable PKI 💅 It's based on the X.509 v3 certificate format and the standard certificate extensions defined in [X.509]. The ISO/IEC and ITU-T documents use the 1997 version of ASN.1. This document uses the 1988 ASN.1 syntax, but the encoded certificate and standard extensions are equivalent, so no drama 🙌 This section also defines private extensions needed to support a PKI for the Internet community 🌸

Certificates can show up in a wide range of applications and environments, covering lots of interoperability goals and an even broader spectrum of operational and assurance requirements 🦋 The goal here is to set a common baseline for generic applications that need broad interoperability plus limited special-purpose requirements ✨ The emphasis is on supporting X.509 v3 certificates for informal Internet electronic mail, IPsec, and WWW applications 💖

4.1. Basic Certificate Fields 🧩

the X.509 v3 certificate basic syntax looks like this. For signature calculation, the data to be signed is encoded using the ASN.1 distinguished encoding rules (DER) [X.690]. ASN.1 DER encoding is a tag, length, value encoding system for each element 🧚

Certificate  ::=  SEQUENCE  {
     tbsCertificate       TBSCertificate,
     signatureAlgorithm   AlgorithmIdentifier,
     signatureValue       BIT STRING  }

TBSCertificate  ::=  SEQUENCE  {
     version         [0]  EXPLICIT Version DEFAULT v1,
     serialNumber         CertificateSerialNumber,
     signature            AlgorithmIdentifier,
     issuer               Name,
     validity             Validity,
     subject              Name,
     subjectPublicKeyInfo SubjectPublicKeyInfo,
     issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
                          -- If present, version MUST be v2 or v3
     subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
                          -- If present, version MUST be v2 or v3
     extensions      [3]  EXPLICIT Extensions OPTIONAL
                          -- If present, version MUST be v3
     }

Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }

CertificateSerialNumber  ::=  INTEGER

Validity ::= SEQUENCE {
     notBefore      Time,
     notAfter       Time }

Time ::= CHOICE {
     utcTime        UTCTime,
     generalTime    GeneralizedTime }

UniqueIdentifier  ::=  BIT STRING

SubjectPublicKeyInfo  ::=  SEQUENCE  {
     algorithm            AlgorithmIdentifier,
     subjectPublicKey     BIT STRING  }

Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
Extension  ::=  SEQUENCE  {
     extnID      OBJECT IDENTIFIER,
     critical    BOOLEAN DEFAULT FALSE,
     extnValue   OCTET STRING  }

the following items describe the X.509 v3 certificate for use on the Internet 🌈

4.1.1. Certificate Fields 💜

the Certificate is a SEQUENCE of three required fields 📋 Each one is described in detail in the subsections below.

4.1.1.1. tbsCertificate 📝

this field contains the names of the subject and issuer, a public key associated with the subject, a validity period, and other associated information 🪪 The fields are described in detail in section 4.1.2. The tbsCertificate usually includes extensions, which are described in section 4.2 🎀

4.1.1.2. signatureAlgorithm ✍️

the signatureAlgorithm field holds the identifier for the cryptographic algorithm the CA used to sign this certificate 🔑 [PKIXALGS] lists supported signature algorithms, but other signature algorithms MAY also be supported 💅

An algorithm identifier is defined by this ASN.1 structure:

AlgorithmIdentifier  ::=  SEQUENCE  {
     algorithm               OBJECT IDENTIFIER,
     parameters              ANY DEFINED BY algorithm OPTIONAL  }

The algorithm identifier is used to identify a cryptographic algorithm 🧠 The OBJECT IDENTIFIER component identifies the algorithm (such as DSA with SHA-1). The contents of the optional parameters field vary depending on the algorithm identified 🫶

This field MUST contain the same algorithm identifier as the signature field in the sequence tbsCertificate (section 4.1.2.3). 🚨

4.1.1.3. signatureValue 🖋️

the signatureValue field holds a digital signature computed over the ASN.1 DER encoded tbsCertificate 💫 That DER encoded tbsCertificate is used as the input to the signature function. The signature value is encoded as a BIT STRING and included in the signature field. The details of this process are specified for each of the algorithms listed in [PKIXALGS] 🌸

By generating this signature, a CA certifies the validity of the information in the tbsCertificate field 🦋 In particular, the CA certifies the binding between the public key material and the subject of the certificate 💖

4.1.2. TBSCertificate 🎀

the sequence TBSCertificate holds information about the subject of the certificate and the CA that issued it 🪄 Every TBSCertificate contains the names of the subject and issuer, a public key associated with the subject, a validity period, a version number, and a serial number. Some MAY contain optional unique identifier fields 🧩 The rest of this section covers the syntax and semantics of these fields. A TBSCertificate usually includes extensions. Extensions for the Internet PKI are described in Section 4.2 ✨

4.1.2.1. Version 🔢

this field describes the version of the encoded certificate 📜 When extensions are used, as expected in this profile, version MUST be 3 (value is 2). If no extensions are present but a UniqueIdentifier is present, the version SHOULD be 2 (value is 1); however, version MAY be 3. If only basic fields are present, the version SHOULD be 1 (the value is omitted from the certificate as the default value); however, the version MAY be 2 or 3 🌷

Implementations SHOULD be prepared to accept any version certificate. At a minimum, conforming implementations MUST recognize version 3 certificates 🙌

Generation of version 2 certificates is not expected by implementations based on this profile 🙈

4.1.2.2. Serial number 🔢

the serial number MUST be a positive integer assigned by the CA to each certificate 🪪 It MUST be unique for each certificate issued by a given CA (i.e., the issuer name and serial number identify a unique certificate). CAs MUST force the serialNumber to be a non-negative integer 🚫➖

Given the uniqueness requirements above, serial numbers can be expected to contain long integers 🌈 Certificate users MUST be able to handle serialNumber values up to 20 octets. Conformant CAs MUST NOT use serialNumber values longer than 20 octets 🙅‍♀️

Note: Non-conforming CAs may issue certificates with serial numbers that are negative, or zero. Certificate users SHOULD be prepared to gracefully handle such certificates 💀

4.1.2.3. Signature ✍️

this field contains the algorithm identifier for the algorithm the CA used to sign the certificate 🔐

This field MUST contain the same algorithm identifier as the signatureAlgorithm field in the sequence Certificate (section 4.1.1.2). The contents of the optional parameters field vary according to the algorithm identified. [PKIXALGS] lists the supported signature algorithms, but other signature algorithms MAY also be supported 💜

4.1.2.4 Issuer ✨

okay so the issuer field is basically the "who signed this and put it out there" tag 💅 it MUST contain a non-empty distinguished name (DN). it's defined as the X.501 type Name [X.501], and the ASN.1 for it looks like this 🎀

Name ::= CHOICE {
  RDNSequence }

RDNSequence ::= SEQUENCE OF RelativeDistinguishedName

RelativeDistinguishedName ::=
  SET OF AttributeTypeAndValue

AttributeTypeAndValue ::= SEQUENCE {
  type     AttributeType,
  value    AttributeValue }

AttributeType ::= OBJECT IDENTIFIER

AttributeValue ::= ANY DEFINED BY AttributeType
DirectoryString ::= CHOICE {
      teletexString           TeletexString (SIZE (1..MAX)),
      printableString         PrintableString (SIZE (1..MAX)),
      universalString         UniversalString (SIZE (1..MAX)),
      utf8String              UTF8String (SIZE (1..MAX)),
      bmpString               BMPString (SIZE (1..MAX)) }

so a Name is a hierarchical name made of attributes, like country name with a value like US 🌍 the type of each AttributeValue is decided by its AttributeType, and usually it's a DirectoryString 💖

DirectoryString is a choice between PrintableString, TeletexString, BMPString, UTF8String, and UniversalString. UTF8String [RFC 2279] is the preferred encoding, and all certificates issued after December 31, 2003 MUST use the UTF8String encoding of DirectoryString (except as noted below). until that date, conforming CAs MUST pick from these options when making a distinguished name, including their own 😭

  • (a) if the character set is sufficient, the string MAY be represented as a PrintableString;
  • (b) failing (a), if the BMPString character set is sufficient the string MAY be represented as a BMPString; and
  • (c) failing (a) and (b), the string MUST be represented as a UTF8String. If (a) or (b) is satisfied, the CA MAY still choose to represent the string as a UTF8String.

there are exceptions to the December 31, 2003 UTF8 rule, and they're kind of iconic ngl 🦋

  • (a) CAs MAY issue "name rollover" certificates to support an orderly migration to UTF8String encoding. Such certificates would include the CA's UTF8String encoded name as issuer and the old name encoding as subject, or vice-versa.
  • (b) As stated in section 4.1.2.6, the subject field MUST be populated with a non-empty distinguished name matching the contents of the issuer field in all certificates issued by the subject CA regardless of encoding.

TeletexString and UniversalString are only around for backward compatibility. they SHOULD NOT be used for certificates for new subjects 🙈 but these types MAY be used in certificates where the name was previously established. Certificate users SHOULD be prepared to receive certificates with these types.

also, lots of legacy implementations support names encoded in the ISO 8859-1 character set (Latin1String) [ISO 8859-1] but tag them as TeletexString. TeletexString encodes a bigger character set than ISO 8859-1, but it encodes some characters differently, so Implementations SHOULD be prepared to handle both encodings 🧚

as we said, distinguished names are made of attributes. this spec doesn't restrict which attribute types can show up in names. but conforming implementations MUST be prepared to receive certificates with issuer names containing the set of attribute types listed below. this spec RECOMMENDS support for additional attribute types too ✨

the X.500 series [X.520] has standard sets of attributes. Implementations of this specification MUST be prepared to receive the following standard attribute types in issuer and subject (section 4.1.2.6) names:

  • country,
  • organization,
  • organizational-unit,
  • distinguished name qualifier,
  • state or province name,
  • common name (e.g., "Susan Housley"), and
  • serial number.

and implementations of this specification SHOULD be prepared to receive these standard attribute types in issuer and subject names too 💜

  • locality,
  • title,
  • surname,
  • given name,
  • initials,
  • pseudonym, and
  • generation qualifier (e.g., "Jr.", "3rd", or "IV").

the syntax and OIDs for these attribute types are in the ASN.1 modules in Appendix A 🎀

also, implementations of this specification MUST be prepared to receive the domainComponent attribute, as defined in [RFC 2247]. the Domain Name System (DNS) is a hierarchical labeling system, and this attribute is a handy way for orgs that want their DNs to mirror their DNS names 🌸 it is NOT a replacement for the dNSName component of the alternative name field. implementations aren't required to turn these names into DNS names. the syntax and OID for this attribute type are in the ASN.1 modules in Appendix A.

Certificate users MUST be prepared to process the issuer distinguished name and subject distinguished name (section 4.1.2.6) fields so they can do name chaining for certification path validation (section 6). name chaining happens by matching the issuer distinguished name in one certificate with the subject name in a CA certificate. it's giving puzzle pieces 🧩

this spec only needs a subset of the name comparison stuff from the X.500 series. Conforming implementations are REQUIRED to implement these name comparison rules:

  • (a) attribute values encoded in different types (e.g., PrintableString and BMPString) MAY be assumed to represent different strings;
  • (b) attribute values in types other than PrintableString are case sensitive (this permits matching of attribute values as binary objects);
  • (c) attribute values in PrintableString are not case sensitive (e.g., "Marianne Swanson" is the same as "MARIANNE SWANSON"); and
  • (d) attribute values in PrintableString are compared after removing leading and trailing white space and converting internal substrings of one or more consecutive white space characters to a single space.

these comparison rules let a certificate user validate certificates issued in languages or encodings they don't know 🌈

implementations of this specification MAY use these comparison rules to process unfamiliar attribute types for name chaining. that way they can handle certificates with unfamiliar attributes in the issuer name 🦋

one more thing 👑 the X.500 comparison rules say the character sets used to encode data in names don't matter, since the characters get compared without caring about encoding. Implementations of this profile are permitted to use the X.500 comparison algorithm. such an implementation will recognize a superset of the name matches the algorithm above recognizes.


4.1.2.5 Validity ✨

the validity period is the time window where the CA promises it'll keep info about the certificate's status 🫶 it's a SEQUENCE of two dates: when the validity period begins (notBefore) and when it ends (notAfter). both can be encoded as UTCTime or GeneralizedTime.

CAs conforming to this profile MUST always encode certificate validity dates through the year 2049 as UTCTime; certificate validity dates in 2050 or later MUST be encoded as GeneralizedTime. periodt 💅

the validity period runs from notBefore through notAfter, inclusive. so both ends count 🍓

4.1.2.5.1 UTCTime ✨

UTCTime is the standard ASN.1 type for dates and times. it gives the year through the two low order digits, and the time is down to one minute or one second. UTCTime includes either Z (Zulu, or Greenwich Mean Time) or a time differential ⭐

for this profile, UTCTime values MUST be expressed in Greenwich Mean Time (Zulu) and MUST include seconds (times look like YYMMDDHHMMSSZ), even when the seconds are zero. conforming systems MUST read the year field (YY) like this 😭

  • Where YY is greater than or equal to 50, the year SHALL be interpreted as 19YY; and
  • Where YY is less than 50, the year SHALL be interpreted as 20YY.

4.1.2.5.2 GeneralizedTime ✨

GeneralizedTime is the standard ASN.1 type for time with variable precision. it can optionally include the time differential between local time and Greenwich Mean Time 🧚

for this profile, GeneralizedTime values MUST be expressed in Greenwich Mean Time (Zulu) and MUST include seconds (times look like YYYYMMDDHHMMSSZ), even when the seconds are zero. GeneralizedTime values MUST NOT include fractional seconds. no decimals, bestie 🙅‍♀️💀

4.1.2.6 Subject ✨

okay so the subject field is all about who this certificate is actually about 🎀 it's the entity linked to the key sitting in the subject public key field. the subject name MAY be carried in the subject field and/or the subjectAltName extension. if the subject is a CA (like when the basic constraints from section 4.2.1.10 are there and cA is TRUE), then the subject field MUST be populated with a non-empty distinguished name that matches the issuer field (section 4.1.2.4) on every certificate that CA issues 💅 same deal for CRL issuers! if the subject is a CRL issuer (like when the key usage extension from 4.2.1.3 is there and cRLSign is TRUE), the subject field MUST be populated with a non-empty distinguished name matching the issuer field (section 4.1.2.4) in all CRLs that subject CRL issuer puts out 🌸 and if the naming info lives ONLY in the subjectAltName extension (think a key tied to just an email or URI), then the subject name MUST be an empty sequence and the subjectAltName extension MUST be critical. no cap, that one's a whole vibe 🫶

when it's not empty, the subject field MUST contain an X.500 distinguished name (DN) ✨ the DN MUST be unique for each subject entity that the one CA certifies (as defined by the issuer name field). a CA MAY issue more than one certificate with the same DN to the same subject entity, and that's totally allowed 🦋

the subject name field is the X.501 type Name 🧚 the implementation rules for it are the same ones defined for the issuer field (section 4.1.2.4). when you're encoding attribute values of type DirectoryString, the encoding rules for the issuer field MUST be implemented 💖 implementations of this specification MUST be prepared to receive subject names with the attribute types that the issuer field requires, and they SHOULD be prepared to receive subject names with the recommended attribute types for the issuer field too 🌈 the syntax and OIDs for those attribute types are in the ASN.1 modules in Appendix A 📜 implementations of this specification MAY use these comparison rules to process unfamiliar attribute types (i.e., for name chaining). this is what lets implementations handle certificates with unfamiliar attributes in the subject name, and honestly that's so iconic 👑

okay now the legacy stuff 🙈 some older implementations embed an RFC 822 name in the subject distinguished name as an EmailAddress attribute. its value is type IA5String, because the '@' character isn't part of the PrintableString character set 💀 EmailAddress attribute values are not case sensitive (e.g., "fanfeedback@redsox.com" is the same as "FANFEEDBACK@REDSOX.COM") 😭

conforming implementations that generate new certificates with electronic mail addresses MUST use the rfc822Name in the subject alternative name field (section 4.2.1.7) to describe those identities ✨ putting the EmailAddress attribute in the subject distinguished name too, just to support legacy implementations, is deprecated but permitted 🍓

4.1.2.7 Subject Public Key Info 🔑

this field carries the public key and tells you which algorithm the key is used with (e.g., RSA, DSA, or Diffie-Hellman) 💜 the algorithm gets identified with the AlgorithmIdentifier structure from section 4.1.1.2. the object identifiers for the supported algorithms, plus the ways to encode the public key material (the public key and its parameters), are specified in [PKIXALGS] 🎀

4.1.2.8 Unique Identifiers 🪪

okay this one's a bit of a rule-y moment 🙈 these fields MUST only appear if the version is 2 or 3 (section 4.1.2.1), and they MUST NOT appear if the version is 1 🌸 the subject and issuer unique identifiers are there to handle the possibility that subject and/or issuer names get reused over time. this profile RECOMMENDS that names not be reused for different entities, and that Internet certificates not use unique identifiers at all 💅 CAs conforming to this profile SHOULD NOT generate certificates with unique identifiers, and applications conforming to this profile SHOULD be capable of parsing unique identifiers 🫶

4.1.2.9 Extensions 🧩

this field MUST only appear if the version is 3 (section 4.1.2.1) ✨ when it's present, it's a SEQUENCE of one or more certificate extensions. the format and content of those extensions in the Internet PKI are defined in section 4.2 🦋

4.2 Certificate Extensions 🌈

the extensions defined for X.509 v3 certificates give you ways to attach extra attributes to users or public keys, and to manage a certification hierarchy 🧚 the X.509 v3 format also lets communities define private extensions for info that's unique to them 💖 every extension in a certificate is either critical or non-critical, and a certificate using system MUST reject the certificate if it runs into a critical extension it doesn't recognize 😭 a non-critical extension MAY be ignored if it isn't recognized, though 🙈 the next sections list the recommended extensions used in Internet certificates and where the info should go 📜 communities can use additional extensions too, but caution ought to be exercised before adopting any critical extensions in certificates that might stop them from working in a general context ⚠️

each extension includes an OID and an ASN.1 structure ✨ when an extension shows up in a certificate, the OID appears as the field extnID, and the matching ASN.1 encoded structure is the value of the octet string extnValue 💜 a certificate MUST NOT include more than one instance of a particular extension. for example, a certificate may contain only one authority key identifier extension (section 4.2.1.1) 🍓 an extension includes the boolean critical, which defaults to FALSE, and the text for each extension says which values are acceptable for the critical field 🎀

conforming CAs MUST support the key identifiers (sections 4.2.1.1 and 4.2.1.2), basic constraints (section 4.2.1.10), key usage (section 4.2.1.3), and certificate policies (section 4.2.1.5) extensions 🫶 if the CA issues certificates with an empty sequence for the subject field, the CA MUST support the subject alternative name extension (section 4.2.1.7) 🙌 support for everything else is OPTIONAL. conforming CAs MAY support extensions that aren't identified in this specification, but certificate issuers are cautioned that marking those as critical may get in the way of interoperability 🧐

at a minimum, applications conforming to this profile MUST recognize these extensions: key usage (section 4.2.1.3), certificate policies (section 4.2.1.5), the subject alternative name (section 4.2.1.7), basic constraints (section 4.2.1.10), name constraints (section 4.2.1.11), policy constraints (section 4.2.1.12), extended key usage (section 4.2.1.13), and inhibit any-policy (section 4.2.1.15) 👑 on top of that, applications conforming to this profile SHOULD recognize the authority and subject key identifier (sections 4.2.1.1 and 4.2.1.2) and the policy mapping (section 4.2.1.6) extensions 💅

4.2.1 Standard Extensions 📚

this section names the standard certificate extensions defined in [X.509] for use in the Internet PKI 💖 each extension is tied to an OID defined in [X.509]. these OIDs are members of the id-ce arc, which is defined by the following 🧚

   id-ce   OBJECT IDENTIFIER ::=  { joint-iso-ccitt(2) ds(5) 29 }

4.2.1.1 Authority Key Identifier 🔐

the authority key identifier extension is how you identify the public key that matches the private key used to sign a certificate 🎀 it's used when an issuer has multiple signing keys, whether that's because of multiple concurrent key pairs or a changeover 🦋 the identification MAY be based on either the key identifier (the subject key identifier in the issuer's certificate) or on the issuer name and serial number ✨

the keyIdentifier field of the authorityKeyIdentifier extension MUST be included in all certificates generated by conforming CAs, so certification path construction is easier 🛤️ there's one exception: where a CA distributes its public key in a "self-signed" certificate, the authority key identifier MAY be omitted 🙈 the signature on a self-signed certificate is generated with the private key tied to the certificate's subject public key (this proves the issuer has both the public and private keys 🔑). in that case the subject and authority key identifiers would be identical, but only the subject key identifier is needed for certification path building 💜

the value of the keyIdentifier field SHOULD be derived from the public key used to verify the certificate's signature, or come from a method that generates unique values 🌸 two common methods for generating key identifiers from the public key, and one common method for generating unique values, are described in section 4.2.1.2 📜 where a key identifier hasn't been established before, this specification RECOMMENDS one of those methods for generating keyIdentifier values 💅 where a key identifier has already been established, the CA SHOULD use that previously established identifier 🫶

this profile RECOMMENDS that all certificate users support the key identifier method 🙌

this extension MUST NOT be marked critical 🚫

the ASN.1 for it looks like this 👀

   id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }

   AuthorityKeyIdentifier ::= SEQUENCE {
      keyIdentifier             [0] KeyIdentifier           OPTIONAL,
      authorityCertIssuer       [1] GeneralNames            OPTIONAL,
      authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL  }

   KeyIdentifier ::= OCTET STRING

4.2.1.2 Subject Key Identifier 💖

Okay bestie, the subject key identifier extension is how you spot every certificate that holds a particular public key 🔑✨

To make certification path building easier 🛤️, this extension MUST appear in all conforming CA certificates. That means any certificate with the basic constraints extension (section 4.2.1.10) where cA is TRUE. The value of the subject key identifier MUST be the value placed in the key identifier field of the Authority Key Identifier extension (section 4.2.1.1) of certificates issued by the subject of this certificate.

For CA certificates, subject key identifiers SHOULD be derived from the public key, or from a method that generates unique values. There are two popular ways to make key identifiers from the public key:

(1) The keyIdentifier is the 160-bit SHA-1 hash of the value of the BIT STRING subjectPublicKey, excluding the tag, length, and number of unused bits.

(2) The keyIdentifier is a four bit type field with the value 0100, followed by the least significant 60 bits of the SHA-1 hash of the value of the BIT STRING subjectPublicKey, excluding the tag, length, and number of unused bit string bits.

Another common method for generating unique values is a monotonically increasing sequence of integers 🔢.

For end entity certificates, the subject key identifier extension helps applications find the certificates that contain the public key they're using 📱. If an end entity has obtained multiple certificates, especially from multiple CAs, the subject key identifier lets you quickly grab the whole set of certificates holding that public key. To help applications pick the right end entity certificate, this extension SHOULD be included in all end entity certificates. Iykyk 😌.

For end entity certificates, subject key identifiers SHOULD be derived from the public key. The two common methods for doing that are the ones listed above.

If no key identifier has been set up yet, this specification recommends using one of those methods to generate the keyIdentifier. If a key identifier has already been established, the CA SHOULD use that previously established identifier 🙌.

This extension MUST NOT be marked critical. 🚫
id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 14 }

SubjectKeyIdentifier ::= KeyIdentifier

4.2.1.3 Key Usage 🔐

The key usage extension is the one that says what the key inside the certificate is actually for 💅, like encipherment, signatures, or signing other certificates. This restriction is handy when a key could do more than one thing, but you only want it doing one. For example, if an RSA key should only verify signatures on objects that aren't public key certificates or CRLs, you'd assert the digitalSignature and/or nonRepudiation bits. And if an RSA key should only be used for key management, you'd assert the keyEncipherment bit.

This extension MUST appear in certificates that contain public keys used to validate digital signatures on other public key certificates or CRLs. When this extension shows up, it SHOULD be marked critical.

      id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }

      KeyUsage ::= BIT STRING {
           digitalSignature        (0),
           nonRepudiation          (1),
           keyEncipherment         (2),
           dataEncipherment        (3),
           keyAgreement            (4),
           keyCertSign             (5),
           cRLSign                 (6),
           encipherOnly            (7),
           decipherOnly            (8) }

Here's how the bits in the KeyUsage type work 🧩:

  • The digitalSignature bit is asserted when the subject public key is used with a digital signature mechanism for security services other than certificate signing (bit 5) or CRL signing (bit 6). These mechanisms are often used for entity authentication and data origin authentication with integrity.
  • The nonRepudiation bit is asserted when the subject public key is used to verify digital signatures that provide a non-repudiation service. That service protects against the signing entity falsely denying some action, and it excludes certificate or CRL signing. If there's a later conflict, a reliable third party may determine the authenticity of the signed data.
  • Further distinctions between the digitalSignature and nonRepudiation bits may be provided in specific certificate policies.
  • The keyEncipherment bit is asserted when the subject public key is used for key transport. For example, when an RSA key is used for key management, this bit gets set.
  • The dataEncipherment bit is asserted when the subject public key is used for enciphering user data, other than cryptographic keys.
  • The keyAgreement bit is asserted when the subject public key is used for key agreement. For example, when a Diffie-Hellman key is used for key management, this bit gets set.
  • The keyCertSign bit is asserted when the subject public key is used for verifying a signature on public key certificates. If keyCertSign is asserted, then the cA bit in the basic constraints extension (section 4.2.1.10) MUST also be asserted.
  • The cRLSign bit is asserted when the subject public key is used for verifying a signature on a certificate revocation list (for example a CRL, delta CRL, or an ARL). This bit MUST be asserted in certificates that are used to verify signatures on CRLs.
  • The meaning of the encipherOnly bit is undefined without the keyAgreement bit. When encipherOnly is asserted and keyAgreement is also set, the subject public key may be used only for enciphering data while performing key agreement.
  • The meaning of the decipherOnly bit is undefined without the keyAgreement bit. When decipherOnly is asserted and keyAgreement is also set, the subject public key may be used only for deciphering data while performing key agreement.

This profile doesn't restrict which combinations of bits can be set in a keyUsage extension. The appropriate keyUsage values for particular algorithms are specified in [PKIXALGS] ✨.

4.2.1.4 Private Key Usage Period ⏳

This extension SHOULD NOT be used within the Internet PKI 🙅‍♀️. CAs conforming to this profile MUST NOT generate certificates that include a critical private key usage period extension.

The private key usage period extension lets the certificate issuer give the private key a different validity period than the certificate itself. It's meant for digital signature keys 🖋️. The extension has two optional components, notBefore and notAfter. The private key associated with the certificate SHOULD NOT be used to sign objects before or after the times given by those two components, respectively. CAs conforming to this profile MUST NOT generate certificates with private key usage period extensions unless at least one of the two components is present and the extension is non-critical.

When it's used, notBefore and notAfter are represented as GeneralizedTime and MUST be specified and interpreted as defined in section 4.1.2.5.2 🕰️.

id-ce-privateKeyUsagePeriod OBJECT IDENTIFIER ::=  { id-ce 16 }

PrivateKeyUsagePeriod ::= SEQUENCE {
     notBefore       [0]     GeneralizedTime OPTIONAL,
     notAfter        [1]     GeneralizedTime OPTIONAL }

4.2.1.5 Certificate Policies ✨

Okay bestie, so the certificate policies extension is a list of one or more policy information terms 📜. Each term has an object identifier (OID) and optional qualifiers 💅. The qualifiers MAY be present, but they aren't expected to change what the policy means 🫶.

In an end entity certificate, these terms show which policy the cert was issued under and what it can be used for 🎀. In a CA certificate, they limit which policies are allowed for certification paths that include that cert 🦋. If a CA does not want to limit those paths, it MAY assert the special policy anyPolicy, with a value of { 2 5 29 32 0 } 👑.

Apps with specific policy requirements are expected to keep a list of the policies they'll accept, then compare the policy OIDs in the cert against that list 💜. If this extension is critical, the path validation software MUST be able to interpret it (qualifiers included), or it MUST reject the cert 💀.

For interoperability, this profile recommends that policy information terms contain only an OID 🌸. If an OID alone isn't enough, the profile strongly recommends that qualifiers be limited to the ones defined in this section 🧚. When qualifiers are used with anyPolicy, they MUST be limited to the qualifiers identified in this section 🔥.

There are two policy qualifier types for cert policy writers and issuers, the CPS Pointer and User Notice qualifiers 🍓.

The CPS Pointer qualifier points to a Certification Practice Statement (CPS) published by the CA. The pointer is a URI. How you process it is a local matter, and no action is mandated by this spec, no matter what criticality value the extension has 🌈.

User notice is meant to be displayed to a relying party when a cert is used ✨. Application software SHOULD display all user notices in all certs of the certification path used, except that if a notice is duplicated, only one copy needs to be displayed. To prevent that duplication, this qualifier SHOULD only be present in end entity certs and CA certs issued to other organizations 🙈.

The user notice has two optional fields, noticeRef and explicitText 💖.

  • The noticeRef field, if used, names an organization and identifies, by number, a specific textual statement that organization wrote. For example, it might identify the organization "CertsRUs" and notice number 1. In a typical setup, the app keeps a notice file with the current notices for CertsRUs, pulls the notice text out of that file, and displays it 📂. Messages MAY be multilingual, so the software can pick the message in its own language 🌍.
  • The explicitText field includes the text directly in the cert 🎀. It's a string with a maximum size of 200 characters 📏.

If both noticeRef and explicitText are in the same qualifier, and the app can find the notice text that noticeRef points to, then that text SHOULD be displayed. Otherwise, the explicitText string SHOULD be displayed 💅.

Note: While explicitText has a maximum size of 200 characters, some non-conforming CAs go over that limit. So cert users SHOULD gracefully handle explicitText with more than 200 characters 💀🫶.
   id-ce-certificatePolicies OBJECT IDENTIFIER ::=  { id-ce 32 }

   anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificate-policies 0 }

   certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation

   PolicyInformation ::= SEQUENCE {
        policyIdentifier   CertPolicyId,
        policyQualifiers   SEQUENCE SIZE (1..MAX) OF
                                PolicyQualifierInfo OPTIONAL }

   CertPolicyId ::= OBJECT IDENTIFIER

   PolicyQualifierInfo ::= SEQUENCE {
        policyQualifierId  PolicyQualifierId,
        qualifier          ANY DEFINED BY policyQualifierId }

   -- policyQualifierIds for Internet policy qualifiers

   id-qt          OBJECT IDENTIFIER ::=  { id-pkix 2 }
   id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }
   id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }

   PolicyQualifierId ::=
        OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )

   Qualifier ::= CHOICE {
        cPSuri           CPSuri,
        userNotice       UserNotice }

   CPSuri ::= IA5String

   UserNotice ::= SEQUENCE {
        noticeRef        NoticeReference OPTIONAL,
        explicitText     DisplayText OPTIONAL}

   NoticeReference ::= SEQUENCE {
        organization     DisplayText,
        noticeNumbers    SEQUENCE OF INTEGER }

   DisplayText ::= CHOICE {
        ia5String        IA5String      (SIZE (1..200)),
        visibleString    VisibleString  (SIZE (1..200)),
        bmpString        BMPString      (SIZE (1..200)),
        utf8String       UTF8String     (SIZE (1..200)) }

4.2.1.6 Policy Mappings ✨

This extension is used in CA certificates 🏛️. It lists one or more pairs of OIDs, and each pair has an issuerDomainPolicy and a subjectDomainPolicy 💫. The pairing says the issuing CA considers its issuerDomainPolicy equivalent to the subject CA's subjectDomainPolicy 🦋.

The issuing CA's users might accept an issuerDomainPolicy for certain apps. The policy mapping defines the list of policies tied to the subject CA that may be accepted as comparable to that issuerDomainPolicy 🎀.

Each issuerDomainPolicy named in the policy mapping extension SHOULD also be asserted in a certificate policies extension in the same cert 🫶. Policies SHOULD NOT be mapped either to or from the special value anyPolicy (section 4.2.1.5) 🙅‍♀️.

This extension MAY be supported by CAs and/or applications, and it MUST be non-critical 💜.

   id-ce-policyMappings OBJECT IDENTIFIER ::=  { id-ce 33 }

   PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
        issuerDomainPolicy      CertPolicyId,
        subjectDomainPolicy     CertPolicyId }

4.2.1.7. Subject Alternative Name 🦋

Okay bestie, so the subject alternative names extension is how you bind extra identities to the subject of a cert 🎀 Defined options include an Internet electronic mail address, a DNS name, an IP address, and a uniform resource identifier (URI). There are other options too, including completely local definitions 🧚 Multiple name forms, and multiple instances of each name form, MAY be included. Whenever such identities are to be bound into a certificate, the subject alternative name (or issuer alternative name) extension MUST be used 💖 However, a DNS name MAY be represented in the subject field using the domainComponent attribute, as described in section 4.1.2.4.

Because the subject alternative name is considered to be definitively bound to the public key, all parts of the subject alternative name MUST be verified by the CA 🔥

Further, if the only subject identity in the cert is an alternative name form (like an email address), then the subject distinguished name MUST be empty (an empty sequence), and the subjectAltName extension MUST be present. If the subject field contains an empty sequence, the subjectAltName extension MUST be marked critical 💀

When the subjectAltName extension contains an Internet mail address, the address MUST be included as an rfc822Name. The format of an rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822]. An addr-spec has the form local-part@domain. Note that an addr-spec has no phrase (such as a common name) before it, has no comment (text surrounded in parentheses) after it, and is not surrounded by < and >. Note that while upper and lower case letters are allowed in an RFC 822 addr-spec, no significance is attached to the case 🙈

When the subjectAltName extension contains an iPAddress, the address MUST be stored in the octet string in "network byte order," as specified in RFC 791 [RFC 791]. The least significant bit (LSB) of each octet is the LSB of the corresponding byte in the network address. For IP Version 4, as specified in RFC 791, the octet string MUST contain exactly four octets. For IP Version 6, as specified in RFC 1883, the octet string MUST contain exactly sixteen octets [RFC 1883] 🌈

When the subjectAltName extension contains a domain name system label, the domain name MUST be stored in the dNSName (an IA5String). The name MUST be in the "preferred name syntax," as specified by RFC 1034 [RFC 1034]. Note that while upper and lower case letters are allowed in domain names, no significance is attached to the case. In addition, while the string " " is a legal domain name, subjectAltName extensions with a dNSName of " " MUST NOT be used. Finally, the use of the DNS representation for Internet mail addresses (wpolk.nist.gov instead of wpolk@nist.gov) MUST NOT be used; such identities are to be encoded as rfc822Name 🍓

Note: work is currently underway to specify domain names in international character sets. Such names will likely not be accommodated by IA5String. Once this work is complete, this profile will be revisited and the appropriate functionality will be added.

When the subjectAltName extension contains a URI, the name MUST be stored in the uniformResourceIdentifier (an IA5String). The name MUST NOT be a relative URL, and it MUST follow the URL syntax and encoding rules specified in [RFC 1738]. The name MUST include both a scheme (e.g., "http" or "ftp") and a scheme-specific-part. The scheme-specific-part MUST include a fully qualified domain name or IP address as the host 🦋

As specified in [RFC 1738], the scheme name is not case-sensitive (e.g., "http" is equivalent to "HTTP"). The host part is also not case-sensitive, but other components of the scheme-specific-part may be case-sensitive. When comparing URIs, conforming implementations MUST compare the scheme and host without regard to case, but assume the remainder of the scheme-specific-part is case sensitive ✨

When the subjectAltName extension contains a DN in the directoryName, the DN MUST be unique for each subject entity certified by the one CA as defined by the issuer name field. A CA MAY issue more than one certificate with the same DN to the same subject entity 🌸

The subjectAltName MAY carry additional name types through the use of the otherName field. The format and semantics of the name are indicated through the OBJECT IDENTIFIER in the type-id field. The name itself is conveyed as value field in otherName. For example, Kerberos [RFC 1510] format names can be encoded into the otherName, using a Kerberos 5 principal name OID and a SEQUENCE of the Realm and the PrincipalName 🔥

Subject alternative names MAY be constrained in the same manner as subject distinguished names using the name constraints extension, as described in section 4.2.1.11 💅

If the subjectAltName extension is present, the sequence MUST contain at least one entry. Unlike the subject field, conforming CAs MUST NOT issue certificates with subjectAltNames containing empty GeneralName fields. For example, an rfc822Name is represented as an IA5String. While an empty string is a valid IA5String, such an rfc822Name is not permitted by this profile. The behavior of clients that encounter such a certificate when processing a certification path is not defined by this profile 😭

Finally, the semantics of subject alternative names that include wildcard characters (e.g., as a placeholder for a set of names) are not addressed by this specification. Applications with specific requirements MAY use such names, but they must define the semantics 👑

id-ce-subjectAltName OBJECT IDENTIFIER ::=  { id-ce 17 }

SubjectAltName ::= GeneralNames

GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
GeneralName ::= CHOICE {
     otherName                       [0]     OtherName,
     rfc822Name                      [1]     IA5String,
     dNSName                         [2]     IA5String,
     x400Address                     [3]     ORAddress,
     directoryName                   [4]     Name,
     ediPartyName                    [5]     EDIPartyName,
     uniformResourceIdentifier       [6]     IA5String,
     iPAddress                       [7]     OCTET STRING,
     registeredID                    [8]     OBJECT IDENTIFIER }

OtherName ::= SEQUENCE {
     type-id    OBJECT IDENTIFIER,
     value      [0] EXPLICIT ANY DEFINED BY type-id }

EDIPartyName ::= SEQUENCE {
     nameAssigner            [0]     DirectoryString OPTIONAL,
     partyName               [1]     DirectoryString }

4.2.1.8. Issuer Alternative Names 🧚

As with 4.2.1.7, this extension is used to associate Internet style identities with the certificate issuer. Issuer alternative names MUST be encoded as in 4.2.1.7 💖

Where present, this extension SHOULD NOT be marked critical 🌈

id-ce-issuerAltName OBJECT IDENTIFIER ::=  { id-ce 18 }

IssuerAltName ::= GeneralNames

4.2.1.9. Subject Directory Attributes 🍓

The subject directory attributes extension is used to convey identification attributes (e.g., nationality) of the subject. The extension is defined as a sequence of one or more attributes. This extension MUST be non-critical 🫶

id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::=  { id-ce 9 }

SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF Attribute

4.2.1.10. Basic Constraints 👑

The basic constraints extension identifies whether the subject of the certificate is a CA and the maximum depth of valid certification paths that include this certificate ✨

The cA boolean indicates whether the certified public key belongs to a CA. If the cA boolean is not asserted, then the keyCertSign bit in the key usage extension MUST NOT be asserted 🙈

The pathLenConstraint field is meaningful only if the cA boolean is asserted and the key usage extension asserts the keyCertSign bit (section 4.2.1.3). In this case, it gives the maximum number of non-self-issued intermediate certificates that may follow this certificate in a valid certification path. A certificate is self-issued if the DNs that appear in the subject and issuer fields are identical and are not empty. (Note: The last certificate in the certification path is not an intermediate certificate, and is not included in this limit. Usually, the last certificate is an end entity certificate, but it can be a CA certificate.) A pathLenConstraint of zero indicates that only one more certificate may follow in a valid certification path. Where it appears, the pathLenConstraint field MUST be greater than or equal to zero. Where pathLenConstraint does not appear, no limit is imposed 🦋

This extension MUST appear as a critical extension in all CA certificates that contain public keys used to validate digital signatures on certificates. This extension MAY appear as a critical or non-critical extension in CA certificates that contain public keys used exclusively for purposes other than validating digital signatures on certificates. Such CA certificates include ones that contain public keys used exclusively for validating digital signatures on CRLs and ones that contain key management public keys used with certificate enrollment protocols. This extension MAY appear as a critical or non-critical extension in end entity certificates 🌸

CAs MUST NOT include the pathLenConstraint field unless the cA boolean is asserted and the key usage extension asserts the keyCertSign bit 😭

id-ce-basicConstraints OBJECT IDENTIFIER ::=  { id-ce 19 }

BasicConstraints ::= SEQUENCE {
     cA                      BOOLEAN DEFAULT FALSE,
     pathLenConstraint       INTEGER (0..MAX) OPTIONAL }

4.2.1.11 Name Constraints ✨

okay so the name constraints extension is basically a fence 🚧 for names. It MUST be used only in a CA certificate, and it defines the name space that all subject names in later certificates in a certification path MUST be located in. 💅 The restrictions hit the subject distinguished name AND the subject alternative names, but only when that name form is actually present. If the cert has no name of that type, it's still acceptable, no cap.

Name constraints don't get applied to certificates where the issuer and subject are identical, unless it's the final certificate in the path. ngl this exists so CAs doing key rollover with self-issued certificates don't get blocked 🙈

Restrictions are written as permitted or excluded name subtrees. Any name that matches the excludedSubtrees field is invalid, even if permittedSubtrees says it's fine 💀 This extension MUST be critical. 🔥

In this profile, the minimum and maximum fields aren't used with any name forms, so minimum MUST be zero and maximum MUST be absent. 🎀

For URIs, the constraint applies to the host part of the name. It MAY be a host or a domain, like "foo.bar.com" or ".xyz.com". When the constraint starts with a period, it MAY be expanded with one or more subdomains. So ".xyz.com" is satisfied by both abc.xyz.com and abc.def.xyz.com, but "xyz.com" on its own does NOT satisfy it. When the constraint doesn't start with a period, it's a specific host. 🦋

A name constraint for Internet mail addresses MAY specify a particular mailbox, all addresses at a particular host, or all mailboxes in a domain. For one mailbox, the constraint is the complete address, like "root@xyz.com" (the root mailbox on the host xyz.com). For every address on a host, you just write the host name, so "xyz.com" covers any mail address at xyz.com. For a whole domain, you add a leading period (same as URIs), so ".xyz.com" covers all the mail addresses in the xyz.com domain, but NOT the addresses on the host xyz.com itself. 💌

DNS name restrictions look like foo.bar.com. Any DNS name you can make by adding stuff to the left-hand side satisfies the constraint. So www.foo.bar.com works, but foo1.bar.com doesn't. 🌸

There are legacy implementations where an RFC 822 name is tucked inside the subject distinguished name, in an attribute of type EmailAddress (section 4.1.2.6). When rfc822 names are constrained but the certificate has no subject alternative name, the rfc822 name constraint MUST be applied to that EmailAddress attribute in the subject distinguished name. The ASN.1 syntax for EmailAddress and its OID are in Appendix A. 🧚

Restrictions of the form directoryName MUST be applied to the subject field in the certificate and to subjectAltName extensions of type directoryName. Restrictions of the form x400Address MUST be applied to subjectAltName extensions of type x400Address. ✨

When applying directoryName restrictions, an implementation MUST compare DN attributes. At a minimum, implementations MUST perform the DN comparison rules in Section 4.1.2.4. CAs issuing certificates with a directoryName restriction SHOULD NOT rely on an implementation of the full ISO DN name comparison algorithm. This implies name restrictions MUST be stated identically to the encoding used in the subject field or subjectAltName extension. 🫶

The syntax of iPAddress MUST be as described in section 4.2.1.7, with the following extras just for Name Constraints. For IPv4 addresses, the ipAddress field of generalName MUST contain eight (8) octets, encoded in the style of RFC 1519 (CIDR) to represent an address range [RFC 1519]. For IPv6 addresses, the ipAddress field MUST contain 32 octets, similarly encoded. For example, a name constraint for "class C" subnet 10.9.8.0 is represented as the octets 0A 09 08 00 FF FF FF 00, which means the CIDR notation 10.9.8.0/255.255.255.0. 🔥

The syntax and semantics for name constraints on otherName, ediPartyName, and registeredID are NOT defined by this specification. 🙈

id-ce-nameConstraints OBJECT IDENTIFIER ::=  { id-ce 30 }

NameConstraints ::= SEQUENCE {
     permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
     excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }

GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree

GeneralSubtree ::= SEQUENCE {
     base                    GeneralName,
     minimum         [0]     BaseDistance DEFAULT 0,
     maximum         [1]     BaseDistance OPTIONAL }

BaseDistance ::= INTEGER (0..MAX)

4.2.1.12 Policy Constraints ✨

The policy constraints extension can be used in certificates issued to CAs. It constrains path validation in two ways: it can prohibit policy mapping, or it can require that every certificate in a path contain an acceptable policy identifier. 🎀

If the inhibitPolicyMapping field is present, its value is the number of additional certificates that may appear in the path before policy mapping is no longer permitted. For example, a value of one means policy mapping may be processed in certificates issued by the subject of this certificate, but not in any additional certificates in the path. 🌈

If the requireExplicitPolicy field is present, its value is the number of additional certificates that may appear in the path before an explicit policy is required for the entire path. When an explicit policy is required, every certificate in the path needs to contain an acceptable policy identifier in the certificate policies extension. An acceptable policy identifier is either the identifier of a policy required by the user of the certification path, or the identifier of a policy that has been declared equivalent through policy mapping. 💜

Conforming CAs MUST NOT issue certificates where policy constraints is an empty sequence. That is, at least one of the inhibitPolicyMapping field or the requireExplicitPolicy field MUST be present. How clients handle an empty policy constraints field is not addressed in this profile. 🙈

This extension MAY be critical or non-critical. 🦋

id-ce-policyConstraints OBJECT IDENTIFIER ::=  { id-ce 36 }

PolicyConstraints ::= SEQUENCE {
     requireExplicitPolicy           [0] SkipCerts OPTIONAL,
     inhibitPolicyMapping            [1] SkipCerts OPTIONAL }

SkipCerts ::= INTEGER (0..MAX)

4.2.1.13 Extended Key Usage ✨

This extension says what purposes the certified public key may be used for, either on top of or instead of the basic purposes in the key usage extension. Generally, it only shows up in end entity certificates. It's defined like this: 🧚

id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }

ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId

KeyPurposeId ::= OBJECT IDENTIFIER

Key purposes can be defined by any organization that needs them. Object identifiers used to identify key purposes MUST be assigned in accordance with IANA or ITU-T Recommendation X.660 [X.660]. 💅

This extension MAY, at the option of the certificate issuer, be either critical or non-critical. 🔥

If the extension is present, the certificate MUST only be used for one of the purposes indicated. If multiple purposes are indicated, the application doesn't need to recognize all of them, as long as the intended purpose is one of them. Certificate-using applications MAY require that a particular purpose be indicated in order for the certificate to be acceptable to that application. 🫶

If a CA includes extended key usages to satisfy such applications but doesn't want to restrict how the key is used, the CA can include the special keyPurposeID anyExtendedKeyUsage. If anyExtendedKeyUsage is present, the extension SHOULD NOT be critical. 🌸

If a certificate contains both a key usage extension and an extended key usage extension, both extensions MUST be processed independently, and the certificate MUST only be used for a purpose consistent with both extensions. If there's no purpose consistent with both extensions, then the certificate MUST NOT be used for any purpose. 💀

The following key usage purposes are defined: 🌈

anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 }

id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }

id-kp-serverAuth             OBJECT IDENTIFIER ::= { id-kp 1 }
-- TLS WWW server authentication
-- Key usage bits that may be consistent: digitalSignature,
-- keyEncipherment or keyAgreement

id-kp-clientAuth             OBJECT IDENTIFIER ::= { id-kp 2 }
-- TLS WWW client authentication
-- Key usage bits that may be consistent: digitalSignature
-- and/or keyAgreement
id-kp-codeSigning             OBJECT IDENTIFIER ::= { id-kp 3 }
-- Signing of downloadable executable code
-- Key usage bits that may be consistent: digitalSignature

id-kp-emailProtection         OBJECT IDENTIFIER ::= { id-kp 4 }
-- E-mail protection
-- Key usage bits that may be consistent: digitalSignature,
-- nonRepudiation, and/or (keyEncipherment or keyAgreement)

id-kp-timeStamping            OBJECT IDENTIFIER ::= { id-kp 8 }
-- Binding the hash of an object to a time
-- Key usage bits that may be consistent: digitalSignature
-- and/or nonRepudiation

id-kp-OCSPSigning            OBJECT IDENTIFIER ::= { id-kp 9 }
-- Signing OCSP responses
-- Key usage bits that may be consistent: digitalSignature
-- and/or nonRepudiation

4.2.1.14 CRL Distribution Points 🎀

okay so the CRL distribution points extension is how everyone finds the CRL 🗺️ it tells you where to grab the revocation info, and it's giving main character energy ✨ The extension SHOULD be non-critical 🙈 but this profile RECOMMENDS that CAs and apps support it, bestie 🫶 more CRL drama lives in section 5 💅

The cRLDistributionPoints extension is a SEQUENCE of DistributionPoint 💖 each DistributionPoint has three fields: distributionPoint, reasons, and cRLIssuer. All three are optional, but there are rules 👀 A DistributionPoint MUST NOT consist of only the reasons field, so either distributionPoint or cRLIssuer MUST be present 🙅‍♀️ If the certificate issuer is not the CRL issuer, the cRLIssuer field MUST be present and contain the Name of the CRL issuer 🌸 If the certificate issuer is also the CRL issuer, then the cRLIssuer field MUST be omitted and the distributionPoint field MUST be present 🦋 And if distributionPoint is omitted, cRLIssuer MUST be present and include a Name that matches an X.500 or LDAP directory entry where the CRL is located 🧚

When distributionPoint is there, it holds either a SEQUENCE of general names or one single value, nameRelativeToCRLIssuer 🍓 If the cRLDistributionPoints extension has a general name of type URI, the following semantics MUST be assumed: the URI points to the current CRL for the associated reasons, and it'll be issued by the associated cRLIssuer 🔥 The URI values you're expecting are the ones defined in 4.2.1.7. Processing rules for any other values aren't defined in this spec, so don't go guessing 🙈

If the DistributionPointName has multiple values, each name is a different way to get the same CRL 🌈 For example, that one CRL could be retrieved through both LDAP and HTTP, iykyk 💜

If the DistributionPointName has the single value nameRelativeToCRLIssuer, that value is a distinguished name fragment 🎀 The fragment gets appended to the X.500 distinguished name of the CRL issuer to make the distribution point name. If the cRLIssuer field is in the DistributionPoint, the fragment gets appended to the distinguished name that field contains. Otherwise, it gets appended to the certificate issuer distinguished name ✨ The DistributionPointName MUST NOT use the nameRealtiveToCRLIssuer alternative when cRLIssuer contains more than one distinguished name 🙅‍♀️

If the DistributionPoint leaves out the reasons field, the CRL MUST include revocation information for all reasons 💅

The cRLIssuer is the entity who signs and issues the CRL 👑 If it's there, it MUST contain at least one an X.500 distinguished name (DN), and it MAY also contain other name forms 🫶 Since cRLIssuer gets compared to the CRL issuer name, the X.501 type Name MUST follow the encoding rules for the issuer name field in the certificate (section 4.1.2.4) 🤓

id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::=  { id-ce 31 }

CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint

DistributionPoint ::= SEQUENCE {
     distributionPoint       [0]     DistributionPointName OPTIONAL,
     reasons                 [1]     ReasonFlags OPTIONAL,
     cRLIssuer               [2]     GeneralNames OPTIONAL }

DistributionPointName ::= CHOICE {
     fullName                [0]     GeneralNames,
     nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }

ReasonFlags ::= BIT STRING {
     unused                  (0),
     keyCompromise           (1),
     cACompromise            (2),
     affiliationChanged      (3),
     superseded              (4),
     cessationOfOperation    (5),
     certificateHold         (6),
     privilegeWithdrawn      (7),
     aACompromise            (8) }

4.2.1.15 Inhibit Any-Policy 🧚

the inhibit any-policy extension can show up in certificates issued to CAs 💖 it says the special anyPolicy OID, { 2 5 29 32 0 }, doesn't count as an explicit match for other certificate policies. The value is how many more certificates can appear in the path before anyPolicy stops being allowed 🌸 For example, a value of one means anyPolicy can be processed in certificates issued by the subject of this certificate, but not in any extra certificates after that 🦋

This extension MUST be critical. 🔥

id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::=  { id-ce 54 }

InhibitAnyPolicy ::= SkipCerts

SkipCerts ::= INTEGER (0..MAX)

4.2.1.16 Freshest CRL (a.k.a. Delta CRL Distribution Point) 🌈

the freshest CRL extension tells you how to get delta CRL info 🧁 The extension MUST be non-critical. More CRL management tea is in section 5 ✨

It uses the same syntax as the cRLDistributionPoints extension, described in section 4.2.1.14, and the same conventions apply to both 💜

id-ce-freshestCRL OBJECT IDENTIFIER ::=  { id-ce 46 }

FreshestCRL ::= CRLDistributionPoints

4.2.2 Private Internet Extensions 💜

this section defines two extensions for the Internet Public Key Infrastructure 🎀 They can point applications to online info about the issuing CA or the subject 🫶 Since that info might come in several forms, each extension is a sequence of IA5String values, and each value is a URI ✨ The URI itself tells you the location and format of the info, plus how to get it 🔗

There's an object identifier for the private extension, and it lives under the arc id-pe inside the arc id-pkix 🧚 Any future extensions for the Internet PKI are also expected to live under id-pe 🌸

   id-pkix  OBJECT IDENTIFIER  ::=
            { iso(1) identified-organization(3) dod(6) internet(1)
                    security(5) mechanisms(5) pkix(7) }

   id-pe  OBJECT IDENTIFIER  ::=  { id-pkix 1 }

4.2.2.1 Authority Information Access 🦋

the authority information access extension shows how to reach CA info and services for the issuer of the certificate it's in 💖 That can include online validation services and CA policy data 📜 (CRL locations aren't in this one, though. They come from the cRLDistributionPoints extension 🙈) This extension MAY be in end entity or CA certificates, and it MUST be non-critical 🔥

id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }

AuthorityInfoAccessSyntax  ::=
        SEQUENCE SIZE (1..MAX) OF AccessDescription

AccessDescription  ::=  SEQUENCE {
        accessMethod          OBJECT IDENTIFIER,
        accessLocation        GeneralName  }

id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }

id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }

id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }

Each entry in the AuthorityInfoAccessSyntax sequence describes the format and location of extra info the CA that issued the certificate provides 🌈 The accessMethod field tells you the type and format of the info, and the accessLocation field tells you where it lives 🗺️ The retrieval mechanism might be implied by accessMethod or specified by accessLocation 💅

This profile defines two accessMethod OIDs: id-ad-caIssuers and id-ad-ocsp 🎀

The id-ad-caIssuers OID is used when the extra info lists CAs that have issued certificates above the CA that issued this one 🧚 The CA issuers description is meant to help certificate users pick a certification path that ends at a point they trust 💖

When id-ad-caIssuers is the accessMethod, accessLocation describes the description server and the access protocol needed to get the description ✨ accessLocation is a GeneralName, which can take a few forms 🫶 If the info is available over http, ftp, or ldap, accessLocation MUST be a uniformResourceIdentifier 🔗 If it's available through the Directory Access Protocol (DAP), accessLocation MUST be a directoryName. That directoryName's entry holds CA certificates in the crossCertificatePair attribute 📚 If the info comes by electronic mail, accessLocation MUST be an rfc822Name 📧 The semantics of any other id-ad-caIssuers accessLocation name forms aren't defined 🙈

The id-ad-ocsp OID is used when revocation info for this certificate is available through the Online Certificate Status Protocol (OCSP) [RFC 2560] 🔥

When id-ad-ocsp is the accessMethod, accessLocation is the location of the OCSP responder, using the conventions defined in [RFC 2560] 🫶

Other PKIX specifications may define additional access descriptors 🌈

4.2.2.2. Subject Information Access 💖

Okay so the subject information access extension is basically the "how do I reach you?" card for whoever the certificate is about 🎀 It tells you how to get info and services for the subject of the certificate it lives in. If the subject is a CA, that can mean certificate validation services and CA policy data 🧚 If the subject is an end entity, the extension describes what kinds of services are offered and how to get to them. In that case, the actual contents are defined in the protocol specs for those services, bestie 💅 This extension may be included in subject or CA certificates, and it MUST be non-critical 🔥

id-pe-subjectInfoAccess OBJECT IDENTIFIER ::= { id-pe 11 }

SubjectInfoAccessSyntax  ::=
        SEQUENCE SIZE (1..MAX) OF AccessDescription

AccessDescription  ::=  SEQUENCE {
        accessMethod          OBJECT IDENTIFIER,
        accessLocation        GeneralName  }

Each entry in the SubjectInfoAccessSyntax sequence is like a little info packet 📦 It describes the format and location of extra information provided by the subject of the certificate it's in. The accessMethod field tells you the type and format of the info, and the accessLocation field tells you where to find it 🗺️ The retrieval mechanism may be implied by the accessMethod or specified by accessLocation 🌸

This profile defines one access method for when the subject is a CA, and one for when the subject is an end entity. Additional access methods may be defined in the future in the protocol specifications for other services ✨

The id-ad-caRepository OID is used when the subject is a CA and it publishes its certificates and CRLs (if issued) in a repository 📚 The accessLocation field is a GeneralName, so it can take several forms. Where the info is available via http, ftp, or ldap, accessLocation MUST be a uniformResourceIdentifier. Where the info is available via the directory access protocol (dap), accessLocation MUST be a directoryName. When the info is available via electronic mail, accessLocation MUST be an rfc822Name. The semantics of other name forms of accessLocation (when accessMethod is id-ad-caRepository) are not defined by this specification 🙈

The id-ad-timeStamping OID is used when the subject offers timestamping services using the Time Stamp Protocol defined in [PKIXTSA] ⏰ Where the timestamping services are available via http or ftp, accessLocation MUST be a uniformResourceIdentifier. Where they're available via electronic mail, accessLocation MUST be an rfc822Name. Where timestamping services are available using TCP/IP, the dNSName or ipAddress name forms may be used. The semantics of other name forms of accessLocation (when accessMethod is id-ad-timeStamping) are not defined by this specification 💜

Additional access descriptors may be defined in other PKIX specifications 🦋

id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }

id-ad-caRepository OBJECT IDENTIFIER ::= { id-ad 5 }

id-ad-timeStamping OBJECT IDENTIFIER ::= { id-ad 3 }

5. CRL and CRL Extensions Profile 🌈

Okay so as we talked about above, the big goal of this X.509 v2 CRL profile is to foster an interoperable and reusable Internet PKI 🫶 To get there, it gives guidelines for using extensions and makes some assumptions about what info goes in the CRL.

CRLs can be used in a wide range of applications and environments, covering a huge spectrum of interoperability goals and an even bigger spectrum of operational and assurance requirements 🌍 This profile sets a common baseline for generic applications that need broad interoperability. It defines a set of info you can expect in every CRL, and it defines common locations within the CRL for frequently used attributes, plus common ways to represent those attributes 💅

CRL issuers issue CRLs. In general, the CRL issuer is the CA. CAs publish CRLs to give status info about the certificates they issued 🎀 However, a CA may delegate this job to another trusted authority. Whenever the CRL issuer is not the CA that issued the certificates, the CRL is called an indirect CRL 🧚

Each CRL has a particular scope. The CRL scope is the set of certificates that could appear on a given CRL. For example, the scope could be "all certificates issued by CA X", "all CA certificates issued by CA X", "all certificates issued by CA X that have been revoked for reasons of key compromise and CA compromise", or it could be a set of certificates based on arbitrary local information, such as "all certificates issued to the NIST employees located in Boulder" 🌸

A complete CRL lists all unexpired certificates, within its scope, that have been revoked for one of the revocation reasons covered by the CRL scope. The CRL issuer MAY also generate delta CRLs 🔥 A delta CRL only lists those certificates, within its scope, whose revocation status has changed since a referenced complete CRL was issued. That referenced complete CRL is called a base CRL. The scope of a delta CRL MUST be the same as the base CRL that it references ✨

This profile does not define any private Internet CRL extensions or CRL entry extensions 🙈

Environments with additional or special purpose requirements may build on this profile or may replace it 🦋

Conforming CAs are not required to issue CRLs if other revocation or certificate status mechanisms are provided 💖 When CRLs are issued, the CRLs MUST be version 2 CRLs, include the date by which the next CRL will be issued in the nextUpdate field (section 5.1.2.5), include the CRL number extension (section 5.2.3), and include the authority key identifier extension (section 5.2.1). Conforming applications that support CRLs are REQUIRED to process both version 1 and version 2 complete CRLs that provide revocation information for all certificates issued by one CA 👑 Conforming applications are NOT REQUIRED to support processing of delta CRLs, indirect CRLs, or CRLs with a scope other than all certificates issued by one CA.

5.1. CRL Fields 🍓

The X.509 v2 CRL syntax is as follows. For signature calculation, the data that is to be signed is ASN.1 DER encoded. ASN.1 DER encoding is a tag, length, value encoding system for each element 🧁

CertificateList  ::=  SEQUENCE  {
     tbsCertList          TBSCertList,
     signatureAlgorithm   AlgorithmIdentifier,
     signatureValue       BIT STRING  }

TBSCertList  ::=  SEQUENCE  {
     version                 Version OPTIONAL,
                                  -- if present, MUST be v2
     signature               AlgorithmIdentifier,
     issuer                  Name,
     thisUpdate              Time,
     nextUpdate              Time OPTIONAL,
     revokedCertificates     SEQUENCE OF SEQUENCE  {
          userCertificate         CertificateSerialNumber,
          revocationDate          Time,
          crlEntryExtensions      Extensions OPTIONAL
                                        -- if present, MUST be v2
                               }  OPTIONAL,
     crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
                                        -- if present, MUST be v2
                               }

-- Version, Time, CertificateSerialNumber, and Extensions
-- are all defined in the ASN.1 in section 4.1

-- AlgorithmIdentifier is defined in section 4.1.1.2

The following items describe how the X.509 v2 CRL is used in the Internet PKI 🌈

5.1.1. CertificateList Fields 🦋

The CertificateList is a SEQUENCE of three required fields 💜 The fields are described in detail in the following subsections.

5.1.1.1. tbsCertList 🎀

The first field in the sequence is the tbsCertList. This field is itself a sequence containing the name of the issuer, the issue date, the issue date of the next list, the optional list of revoked certificates, and optional CRL extensions 📜 When there are no revoked certificates, the revoked certificate list is absent. When one or more certificates are revoked, each entry on the revoked certificate list is a sequence of user certificate serial number, revocation date, and optional CRL entry extensions 💅

5.1.1.2. signatureAlgorithm 🔐

The signatureAlgorithm field contains the algorithm identifier for the algorithm the CRL issuer used to sign the CertificateList. The field is of type AlgorithmIdentifier, which is defined in section 4.1.1.2. [PKIXALGS] lists the supported algorithms for this specification, but other signature algorithms MAY also be supported ✨

This field MUST contain the same algorithm identifier as the signature field in the sequence tbsCertList (section 5.1.2.2) 🫶

5.1.1.3. signatureValue ✍️

The signatureValue field contains a digital signature computed upon the ASN.1 DER encoded tbsCertList. The ASN.1 DER encoded tbsCertList is used as the input to the signature function. This signature value is encoded as a BIT STRING and included in the CRL signatureValue field. The details of this process are specified for each of the supported algorithms in [PKIXALGS] 🔥

CAs that are also CRL issuers MAY use one private key to digitally sign certificates and CRLs, or they MAY use separate private keys to digitally sign certificates and CRLs 👑 When separate private keys are employed, each of the public keys associated with those private keys is placed in a separate certificate. One certificate has the keyCertSign bit set in the key usage extension, and the other has the cRLSign bit set in the key usage extension (section 4.2.1.3). When separate private keys are employed, certificates issued by the CA contain one authority key identifier, and the corresponding CRLs contain a different authority key identifier 🌸

Using separate CA certificates for validating certificate signatures and CRL signatures can offer improved security characteristics. However, it adds a burden on applications, and it might limit interoperability 😭 Many applications construct a certification path and then validate the certification path (section 6). CRL checking in turn requires a separate certification path to be constructed and validated for the CA's CRL signature validation certificate 🧚

Applications that perform CRL checking MUST support certification path validation when certificates and CRLs are digitally signed with the same CA private key. These applications SHOULD support certification path validation when certificates and CRLs are digitally signed with different CA private keys 💖

5.1.2. Certificate List "To Be Signed" 🍓

The certificate list to be signed, or TBSCertList, is a sequence of required and optional fields 🎀 The required fields identify the CRL issuer, the algorithm used to sign the CRL, the date and time the CRL was issued, and the date and time by which the CRL issuer will issue the next CRL 🌈

Optional fields include lists of revoked certificates and CRL extensions. The revoked certificate list is optional to support the case where a CA has not revoked any unexpired certificates that it has issued. The profile requires conforming CRL issuers to use the CRL number and authority key identifier CRL extensions in all CRLs issued 🦋

5.1.2.1. Version 🧁

This optional field describes the version of the encoded CRL. When extensions are used, as required by this profile, this field MUST be present and MUST specify version 2 (the integer value is 1) 💅✨

5.1.2.2. Signature ✨

Okay so this field is where the CRL tells everyone which algorithm was used to sign it 🖊️ The [PKIXALGS] spec has OIDs for the most popular signature algorithms running around the Internet PKI, so go check there if you need the exact one 🔍

This field MUST contain the same algorithm identifier as the signatureAlgorithm field in the sequence CertificateList (section 5.1.1.2). No mismatches, bestie 🙅‍♀️💖

5.1.2.3. Issuer Name 🏛️

The issuer name tells you who signed and issued the CRL, so this is the identity bit 👑 It lives in the issuer name field. Alternative name forms can also show up in the issuerAltName extension (section 5.2.2), so keep an eye out for that 👀

The issuer name field MUST contain an X.500 distinguished name (DN). It's defined as the X.501 type Name, and it MUST follow the encoding rules for the issuer name field in the certificate (section 4.1.2.4). Consistency is everything, periodt 💅

5.1.2.4. This Update 📅

This field shows the issue date of this CRL, so it's basically the "posted on" timestamp ⏰ ThisUpdate can be encoded as UTCTime or GeneralizedTime, your pick 🦋

Now here's the lowkey important part. CRL issuers that follow this profile MUST encode thisUpdate as UTCTime for dates through the year 2049. CRL issuers that follow this profile MUST encode thisUpdate as GeneralizedTime for dates in the year 2050 or later. The year 2050 is coming for us all 💀

Where it's encoded as UTCTime, thisUpdate MUST be specified and interpreted as defined in section 4.1.2.5.1. Where it's encoded as GeneralizedTime, thisUpdate MUST be specified and interpreted as defined in section 4.1.2.5.2 🌸

5.1.2.5. Next Update ⏭️

This field says the date by which the next CRL will be issued. The next CRL could show up before that date, but it will not be issued any later than that date 🕰️ CRL issuers SHOULD issue CRLs with a nextUpdate time equal to or later than all previous CRLs, so time only moves forward, no cap 🧚 NextUpdate can be encoded as UTCTime or GeneralizedTime 🎀

This profile requires nextUpdate in all CRLs issued by conforming CRL issuers. Now, the ASN.1 syntax of TBSCertList calls this field OPTIONAL, and that matches the ASN.1 structure defined in [X.509], so it's not a contradiction, it's just a little plot twist 🙈 What clients do when they process a CRL that leaves out nextUpdate is not specified by this profile, so this profile doesn't say anything about it 🤷‍♀️

CRL issuers that follow this profile MUST encode nextUpdate as UTCTime for dates through the year 2049. CRL issuers that follow this profile MUST encode nextUpdate as GeneralizedTime for dates in the year 2050 or later 🍓

Where it's encoded as UTCTime, nextUpdate MUST be specified and interpreted as defined in section 4.1.2.5.1. Where it's encoded as GeneralizedTime, nextUpdate MUST be specified and interpreted as defined in section 4.1.2.5.2 💜

5.1.2.6. Revoked Certificates 🚫

When there are no revoked certificates, the revoked certificates list MUST be absent. Otherwise, revoked certificates get listed by their serial numbers 🔢 Certificates the CA revokes are uniquely identified by the certificate serial number, so that's their ID card 🪪 The date when the revocation happened is specified too ⏳

The time for revocationDate MUST be expressed as described in section 5.1.2.4. Extra info can be supplied in CRL entry extensions, and those are discussed in section 5.3 ✨

5.1.2.7. Extensions 🧩

This field may only appear if the version is 2 (section 5.1.2.1). If it's there, it's a sequence of one or more CRL extensions. CRL extensions get discussed in section 5.2 🎀

5.2. CRL Extensions 🌈

Okay this is where it gets spicy 🌶️ The extensions defined by ANSI X9, ISO/IEC, and ITU-T for X.509 v2 CRLs [X.509] [X9.55] give you ways to attach extra attributes to CRLs. The X.509 v2 CRL format also lets communities define private extensions for info that's unique to them 🦋

Each extension in a CRL can be marked as critical or non-critical. A CRL validation MUST fail if it runs into a critical extension it doesn't know how to process 🚨 But an unrecognized non-critical extension may be ignored, so it's chill 😌 The following subsections cover the extensions used within Internet CRLs 💅

Communities may choose to include extensions in CRLs that aren't defined in this specification. However, caution should be exercised before adopting any critical extensions in CRLs that might get used in a general context 👀 Be careful with that one, bestie ⚠️

Conforming CRL issuers are REQUIRED to include the authority key identifier (section 5.2.1) and the CRL number (section 5.2.3) extensions in all CRLs they issue 👑

5.2.1. Authority Key Identifier 🔑

The authority key identifier extension is how you point to the public key that matches the private key used to sign a CRL 🗝️ You can identify it by the key identifier (that's the subject key identifier in the CRL signer's certificate) or by the issuer name and serial number. This extension is especially useful when an issuer has more than one signing key, whether that's because of multiple concurrent key pairs or a changeover 🔄

Conforming CRL issuers MUST use the key identifier method, and MUST include this extension in all CRLs issued 🫶

The syntax for this CRL extension is defined in section 4.2.1.1 🎀

5.2.2. Issuer Alternative Name 🌍

The issuer alternative names extension lets you attach extra identities to the issuer of the CRL 🪄 The defined options include an rfc822 name (electronic mail address), a DNS name, an IP address, and a URI 📬 You can include multiple instances of a name and multiple name forms too.

Whenever those identities are used, the issuer alternative name extension MUST be used. However, a DNS name MAY be represented in the issuer field using the domainComponent attribute, as described in section 4.1.2.4 🌸

The issuerAltName extension SHOULD NOT be marked critical 🙅‍♀️

The OID and syntax for this CRL extension are defined in section 4.2.1.8 💖

5.2.3. CRL Number 🔢

The CRL number is a non-critical CRL extension, and it conveys a monotonically increasing sequence number for a given CRL scope and CRL issuer 📈 This is how users easily figure out when one CRL supersedes another one, which is so iconic 👑 CRL numbers also help identify complementary complete CRLs and delta CRLs 🧩 CRL issuers that follow this profile MUST include this extension in all CRLs 🫶

If a CRL issuer generates delta CRLs alongside complete CRLs for a given scope, the complete CRLs and delta CRLs MUST share one numbering sequence. If a delta CRL and a complete CRL that cover the same scope are issued at the same time, they MUST have the same CRL number and provide the same revocation information 👯‍♀️ In other words, the combo of the delta CRL and an acceptable complete CRL MUST provide the same revocation information as the complete CRL that was issued at the same time ✨

If a CRL issuer generates two CRLs for the same scope at different times (two complete CRLs, two delta CRLs, or a complete CRL and a delta CRL), the two CRLs MUST NOT have the same CRL number. Put simply, if the this update field (section 5.1.2.4) in the two CRLs isn't identical, the CRL numbers MUST be different 🙅‍♀️💅

Given all of that, CRL numbers can be expected to contain long integers 🧮 CRL verifiers MUST be able to handle CRLNumber values up to 20 octets. Conformant CRL issuers MUST NOT use CRLNumber values longer than 20 octets 🛑

id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 }

CRLNumber ::= INTEGER (0..MAX)

5.2.4. Delta CRL Indicator ✨

okay so the delta CRL indicator is a critical CRL extension that marks a CRL as a delta CRL 🦋. A delta CRL only carries updates to revocation info that was already shipped out, instead of the whole list. That's a huge glow-up for network load and processing time in some setups 💅. Delta CRLs are usually smaller than the CRLs they update, so apps grabbing them burn less bandwidth than apps grabbing full CRLs. Apps that keep revocation info in some format other than the CRL structure can also slide new revocation info into their local database without reprocessing everything 🫶.

The delta CRL indicator extension holds one value, a BaseCRLNumber. That number points at the complete CRL (for a given scope) that the delta was built from as its starting point 🎀. A conforming CRL issuer MUST publish that referenced base CRL as a complete CRL, no skipping 😭. The delta CRL has every update to revocation status for that same scope. Put a delta CRL together with its base CRL and you get the same thing as a complete CRL for that scope, at the moment the delta was published ✨.

When a conforming CRL issuer makes a delta CRL, the delta CRL MUST include a critical delta CRL indicator extension. No exceptions, bestie 💖.

When a delta CRL gets issued, it MUST cover the same set of reasons and the same set of certificates that the base CRL it references covered 🌸. Basically the scope of the delta CRL MUST match the scope of the complete CRL used as the base. The referenced base CRL and the delta CRL MUST omit the issuing distribution point extension, or both have identical issuing distribution point extensions 🍓. Also, the CRL issuer MUST use the same private key to sign the delta CRL and any complete CRL it can be used to update 🔑.

An app that supports delta CRLs can build a CRL that's complete for a given scope by combining a delta CRL for that scope with either an issued complete CRL for that scope or a locally constructed complete CRL for that scope 🧚.

When a delta CRL gets combined with a complete CRL or a locally constructed CRL, the result has the CRL number from the CRL number extension in the delta CRL used to build it 💜. It also gets the thisUpdate and nextUpdate times from the matching fields of that delta CRL. On top of that, the locally constructed CRL inherits the issuing distribution point from the delta CRL 👑.

A complete CRL and a delta CRL MAY be combined if all four of these conditions are satisfied 🌈:

  • (a) The complete CRL and delta CRL have the same issuer.
  • (b) The complete CRL and delta CRL have the same scope. The two CRLs have the same scope if either of the following conditions are met:
    • (1) The issuingDistributionPoint extension is omitted from both the complete CRL and the delta CRL.
    • (2) The issuingDistributionPoint extension is present in both the complete CRL and the delta CRL, and the values for each of the fields in the extensions are the same in both CRLs.
  • (c) The CRL number of the complete CRL is equal to or greater than the BaseCRLNumber specified in the delta CRL. That is, the complete CRL contains (at a minimum) all the revocation information held by the referenced base CRL.
  • (d) The CRL number of the complete CRL is less than the CRL number of the delta CRL. That is, the delta CRL follows the complete CRL in the numbering sequence.

CRL issuers MUST make sure that a delta CRL plus any appropriate complete CRL accurately reflects the current revocation status 🫶. The CRL issuer MUST include an entry in the delta CRL for each certificate within the scope of the delta CRL whose status has changed since the referenced base CRL was generated:

  • (a) If the certificate is revoked for a reason included in the scope of the CRL, list the certificate as revoked.
  • (b) If the certificate is valid and was listed on the referenced base CRL or any subsequent CRL with reason code certificateHold, and the reason code certificateHold is included in the scope of the CRL, list the certificate with the reason code removeFromCRL.
  • (c) If the certificate is revoked for a reason outside the scope of the CRL, but the certificate was listed on the referenced base CRL or any subsequent CRL with a reason code included in the scope of this CRL, list the certificate as revoked but omit the reason code.
  • (d) If the certificate is revoked for a reason outside the scope of the CRL and the certificate was neither listed on the referenced base CRL nor any subsequent CRL with a reason code included in the scope of this CRL, do not list the certificate on this CRL.

A certificate's status counts as changed if it gets revoked, placed on hold, released from hold, or if its revocation reason changes 🎀.

It's totally fine to list a certificate with reason code removeFromCRL on a delta CRL, even if it wasn't on hold in the referenced base CRL 🙈. If the certificate got placed on hold in any CRL issued after the base but before this delta CRL, and then released from hold, it MUST be listed on the delta CRL with revocation reason removeFromCRL. That's the rule, periodt 💅.

A CRL issuer MAY optionally list a certificate on a delta CRL with reason code removeFromCRL if the notAfter time in the certificate comes before the thisUpdate time in the delta CRL, and the certificate was listed on the referenced base CRL or in any CRL issued after the base but before this delta CRL ✨.

If a certificate revocation notice shows up on a delta CRL first, the certificate's validity period might expire before the next complete CRL for the same scope gets issued 😭. In that case, the revocation notice MUST be included in all subsequent delta CRLs until it's included on at least one explicitly issued complete CRL for this scope 💀.

An app that supports delta CRLs MUST be able to build a current complete CRL by combining a previously issued complete CRL and the most current delta CRL 👑. An app that supports delta CRLs MAY also be able to build a current complete CRL by combining a previously locally constructed complete CRL and the current delta CRL 🌸. A delta CRL counts as the current one if the current time falls between the times in its thisUpdate and nextUpdate fields 🍓. Under some circumstances, the CRL issuer may publish one or more delta CRLs before the nextUpdate field says so 🧚. If an app runs into more than one current delta CRL for a given scope, it SHOULD consider the one with the latest value in thisUpdate to be the most current one 💜.

id-ce-deltaCRLIndicator OBJECT IDENTIFIER ::= { id-ce 27 }

BaseCRLNumber ::= CRLNumber

5.2.5. Issuing Distribution Point 💅

The issuing distribution point is a critical CRL extension that names the CRL distribution point and scope for a particular CRL 🎀. It also says whether the CRL covers revocations for end entity certificates only, CA certificates only, attribute certificates only, or a limited set of reason codes 🦋. Even though the extension is critical, conforming implementations are not required to support it 🙈.

The CRL is signed with the CRL issuer's private key 🔑. CRL Distribution Points don't have their own key pairs, fr fr. If the CRL is stored in the X.500 Directory, it lives in the Directory entry for the CRL distribution point, which can be different from the Directory entry of the CRL issuer 🌈.

The reason codes tied to a distribution point MUST be specified in onlySomeReasons 💖. If onlySomeReasons doesn't appear, the distribution point MUST contain revocations for all reason codes 👑. CAs can use CRL distribution points to split up the CRL based on compromise versus routine revocation 🧚. In that setup, the revocations with reason code keyCompromise (1), cACompromise (2), and aACompromise (8) show up in one distribution point, and the revocations with other reason codes show up in another one 🌸.

If the distributionPoint field is present and has a URI, the following semantics MUST be assumed: the object is a pointer to the most current CRL issued by this CRL issuer 🍓. The URI schemes ftp, http, mailto [RFC1738] and ldap [RFC1778] are defined for this purpose ✨. The URI MUST be an absolute pathname, not a relative pathname, and MUST specify the host 😭.

If the distributionPoint field is absent, the CRL MUST contain entries for all revoked unexpired certificates issued by the CRL issuer, if any, within the scope of the CRL 💀.

The CRL issuer MUST assert the indirectCRL boolean if the scope of the CRL includes certificates issued by authorities other than the CRL issuer 🫶. The authority responsible for each entry is indicated by the certificate issuer CRL entry extension (section 5.3.4) 🎀.

id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 }

issuingDistributionPoint ::= SEQUENCE {
     distributionPoint          [0] DistributionPointName OPTIONAL,
     onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE,
     onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE,
     onlySomeReasons            [3] ReasonFlags OPTIONAL,
     indirectCRL                [4] BOOLEAN DEFAULT FALSE,
     onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }

5.2.6. Freshest CRL (a.k.a. Delta CRL Distribution Point) 🦋

The freshest CRL extension tells you where to find the delta CRL information for this complete CRL 🧚. The extension MUST be non-critical 💜. This extension MUST NOT appear in delta CRLs 🙅.

It uses the same syntax as the cRLDistributionPoints certificate extension, described in section 4.2.1.14 🌈. The only thing that matters here is the distribution point field. The reasons and CRLIssuer fields MUST be omitted from this CRL extension 💅.

Each distribution point name gives the location where you can find a delta CRL for this complete CRL 🫶. The scope of these delta CRLs MUST be the same as the scope of this complete CRL 👑. The contents of this CRL extension are only used to locate delta CRLs. They aren't used to validate the CRL or the referenced delta CRLs 🎀. The encoding conventions defined for distribution points in section 4.2.1.14 apply to this extension 🍓.

id-ce-freshestCRL OBJECT IDENTIFIER ::=  { id-ce 46 }

FreshestCRL ::= CRLDistributionPoints

5.3. CRL Entry Extensions 💌

okay so CRL entry extensions are the add-ons that ISO/IEC, ITU-T, and ANSI X9 cooked up for X.509 v2 CRLs, and they let you attach extra info to each entry [X.509] [X9.55] 💅. Communities can also make their own private ones for their own needs 🎀. Each extension in an entry is either critical or non-critical, and here's the tea: a CRL validation MUST fail if it hits a critical CRL entry extension it doesn't know how to process 😭. An unrecognized non-critical one? It can just get ignored, no drama 🫶. The subsections below are the recommended extensions for Internet CRL entries and where the info should live 🧚. Communities can add more if they want, but be careful about adopting critical ones in entries that might get used in a general context, bestie ⚠️. caution is giving.

Every CRL entry extension used in this spec is non-critical 🌸. Supporting them is optional for conforming CRL issuers and apps 🙈. Still, CRL issuers SHOULD include reason codes (section 5.3.1) and invalidity dates (section 5.3.3) whenever that info is available ✨.

5.3.1. Reason Code

okay the reasonCode is a non-critical CRL entry extension that tells you why a cert got revoked 🥀. CRL issuers are strongly encouraged to include meaningful reason codes in entries, but the reason code extension SHOULD be absent instead of using the unspecified (0) reasonCode value. no vague vibes allowed 💅.

id-ce-cRLReason OBJECT IDENTIFIER ::= { id-ce 21 }

-- reasonCode ::= { CRLReason }

CRLReason ::= ENUMERATED {
     unspecified             (0),
     keyCompromise           (1),
     cACompromise            (2),
     affiliationChanged      (3),
     superseded              (4),
     cessationOfOperation    (5),
     certificateHold         (6),
     removeFromCRL           (8),
     privilegeWithdrawn      (9),
     aACompromise           (10) }

5.3.2. Hold Instruction Code

the hold instruction code is a non-critical CRL entry extension that gives you a registered instruction ID telling you what to do after you hit a cert that's been placed on hold ⏸️. it's giving "read the manual" 📖.

id-ce-holdInstructionCode OBJECT IDENTIFIER ::= { id-ce 23 }

holdInstructionCode ::= OBJECT IDENTIFIER

Here are the instruction codes that have been defined. Conforming applications that process this extension MUST recognize the following instruction codes 🔥.

holdInstruction    OBJECT IDENTIFIER ::=
                 { iso(1) member-body(2) us(840) x9-57(10040) 2 }

id-holdinstruction-none   OBJECT IDENTIFIER ::= {holdInstruction 1}
id-holdinstruction-callissuer
                          OBJECT IDENTIFIER ::= {holdInstruction 2}
id-holdinstruction-reject OBJECT IDENTIFIER ::= {holdInstruction 3}

okay the rules here are super clear 👑. Conforming applications which encounter an id-holdinstruction-callissuer MUST call the certificate issuer or reject the certificate. Conforming applications which encounter an id-holdinstruction-reject MUST reject the certificate 💀. And the id-holdinstruction-none code is semantically the same as having no holdInstructionCode at all, and its use is strongly deprecated for the Internet PKI 🙅‍♀️.

5.3.3. Invalidity Date

the invalidity date is a non-critical CRL entry extension that tells you the date the private key was (or is suspected to have been) compromised, or the date the cert otherwise became invalid 🕰️. This can be earlier than the revocation date in the entry, which is just the day the CA processed the revocation. When a revocation first gets posted by a CRL issuer, the invalidity date may come before the issue date of earlier CRLs, but the revocation date SHOULD NOT precede the issue date of earlier CRLs 📅. Whenever the info is available, CRL issuers are strongly encouraged to share it with CRL users 🫶.

The GeneralizedTime values in this field MUST be expressed in Greenwich Mean Time (Zulu), and MUST be specified and interpreted as defined in section 4.1.2.5.2 🌍. no timezone chaos, periodt 💅.

id-ce-invalidityDate OBJECT IDENTIFIER ::= { id-ce 24 }

invalidityDate ::=  GeneralizedTime

5.3.4. Certificate Issuer

this CRL entry extension identifies the certificate issuer tied to an entry in an indirect CRL, which is a CRL with the indirectCRL indicator set in its issuing distribution point extension 🕵️‍♀️. If this extension is missing on the first entry in an indirect CRL, the certificate issuer defaults to the CRL issuer. On later entries, if the extension is missing, the certificate issuer is the same as the one for the entry before it. Here's how the field is defined:

id-ce-certificateIssuer   OBJECT IDENTIFIER ::= { id-ce 29 }

certificateIssuer ::=     GeneralNames

If used by conforming CRL issuers, this extension MUST always be critical 🔒. If an implementation ignored it, it couldn't correctly attribute CRL entries to certificates, and that's a whole mess 😭. This specification RECOMMENDS that implementations recognize this extension 🎀.

6. Certification Path Validation ✨

certification path validation procedures for the Internet PKI are based on the algorithm supplied in [X.509] 🧩. Path processing verifies the binding between the subject distinguished name and/or subject alternative name and the subject public key. That binding is limited by constraints in the certs that make up the path, plus inputs from the relying party. The basic constraints and policy constraints extensions let the path processing logic automate the decision making, which is honestly iconic 🤖.

This section describes an algorithm for validating certification paths. Conforming implementations are not required to implement this algorithm, but they MUST provide functionality equivalent to the external behavior this procedure produces 💖. Any algorithm works for a particular implementation as long as it derives the correct result 🦋.

In section 6.1, the text describes basic path validation. Valid paths begin with certificates issued by a trust anchor 🌈. The algorithm needs the public key of the CA, the CA's name, and any constraints on the set of paths that may be validated using that key 🔑.

Choosing a trust anchor is a matter of policy 🍓. It could be the top CA in a hierarchical PKI, the CA that issued the verifier's own certificate(s), or any other CA in a network PKI. The path validation procedure is the same no matter which trust anchor you pick ✨. Different applications may rely on different trust anchors, or may accept paths that begin with any of a set of trust anchors 👑.

Section 6.2 describes methods for using the path validation algorithm in specific implementations. It covers two cases: when paths may begin with one of several trusted CAs, and when compatibility with the PEM architecture is required 🌸. Section 6.3 describes the steps needed to determine whether a certificate is revoked or on hold when CRLs are the revocation mechanism the certificate issuer uses 🧚.

6.1. Basic Path Validation 🧚

Okay bestie, this is the big one 💅 This part describes an algorithm for X.509 path processing. A conformant implementation MUST include an X.509 path processing procedure that is functionally equivalent to the external behavior of this algorithm. BUT support for some of the certificate extensions processed here are OPTIONAL for compliant implementations 🫶 Clients that don't support these extensions MAY omit the matching steps in the path validation algorithm.

For example, clients are NOT REQUIRED to support the policy mapping extension 🗺️ Clients that skip this extension MAY omit the path validation steps where policy mappings get processed. Just know that clients MUST reject the certificate if it contains an unsupported critical extension. No skipping that one, periodt 💀

The algorithm in this section checks the certificate against the current date and time ⏰ A conformant implementation MAY also support validation against some point in the past. Heads up though: there are no mechanisms for validating a certificate at a time outside its validity period 🙈

The trust anchor is an input to the algorithm. There's no requirement that the same trust anchor be used for every certification path, so different trust anchors MAY be used to validate different paths. We'll get into that more in Section 6.2 🦋

The main goal of path validation is to verify the binding between a subject distinguished name or a subject alternative name and a subject public key, as shown in the end entity certificate, based on the public key of the trust anchor 💖 To do that, you first need to get a sequence of certificates that support that binding. How you get that sequence is outside the scope of this specification, so that's not on us 🤷‍♀️

So to hit that goal, path validation checks (among other things) that a prospective certification path, which is a sequence of n certificates, satisfies these conditions:

  • (a) for all x in {1, ..., n-1}, the subject of certificate x is the issuer of certificate x+1;
  • (b) certificate 1 is issued by the trust anchor;
  • (c) certificate n is the certificate to be validated; and
  • (d) for all x in {1, ..., n}, the certificate was valid at the time in question.

If the trust anchor shows up as a self-signed certificate, that self-signed certificate is NOT included as part of the prospective certification path 🌸 Instead, info about trust anchors is handed in as inputs to the certification path validation algorithm (section 6.1.1) ✨

Now, a particular certification path might not be right for every application 👑 So an application MAY augment this algorithm to further limit the set of valid paths. The path validation process also figures out which certificate policies are valid for this path, based on the certificate policies extension, the policy mapping extension, the policy constraints extension, and the inhibit any-policy extension. To pull that off, the algorithm builds a valid policy tree 🌳 If the set of valid certificate policies for this path isn't empty, the result is a valid policy tree of depth n. If it IS empty, the result is a null valid policy tree.

A certificate counts as self-issued if the DNs in the subject and issuer fields are identical and not empty 🪞 Usually the issuer and subject are different for each certificate in a path. BUT a CA may issue a certificate to itself to support key rollover or changes in certificate policies, and those self-issued certificates are not counted when evaluating path length or name constraints. Iconic CA behavior 💅

This section walks through the algorithm in four basic steps: (1) initialization, (2) basic certificate processing, (3) preparation for the next certificate, and (4) wrap-up. Steps (1) and (4) happen exactly once. Step (2) happens for every certificate in the path. Step (3) happens for every certificate in the path EXCEPT the final one. Here's a flowchart to make it click 🧩

                           +-------+
                           | START |
                           +-------+
                               |
                               V
                       +----------------+
                       | Initialization |
                       +----------------+
                               |
                               +<--------------------+
                               |                     |
                               V                     |
                       +----------------+            |
                       |  Process Cert  |            |
                       +----------------+            |
                               |                     |
                               V                     |
                       +================+            |
                       |  IF Last Cert  |            |
                       |    in Path     |            |
                       +================+            |
                         |            |              |
                    THEN |            | ELSE         |
                         V            V              |
              +----------------+ +----------------+  |
              |    Wrap up     | |  Prepare for   |  |
              +----------------+ |   Next Cert    |  |
                      |          +----------------+  |
                      V               |              |
                  +-------+           +--------------+
                  | STOP  |
                  +-------+


         Figure 2.  Certification Path Processing Flowchart

6.1.1. Inputs 📥

This algorithm assumes the following seven inputs are handed to the path processing logic:

  • (a) a prospective certification path of length n.
  • (b) the current date/time.
  • (c) user-initial-policy-set: a set of certificate policy identifiers naming the policies that are acceptable to the certificate user. The user-initial-policy-set contains the special value any-policy if the user doesn't care about certificate policy 🫧
  • (d) trust anchor information, describing a CA that serves as a trust anchor for the certification path. The trust anchor information includes:
    • (1) the trusted issuer name,
    • (2) the trusted public key algorithm,
    • (3) the trusted public key, and
    • (4) optionally, the trusted public key parameters associated with the public key.

The trust anchor information may be provided to the path processing procedure in the form of a self-signed certificate. It's trusted because it was delivered to the path processing procedure by some trustworthy out-of-band procedure 🔐 If the trusted public key algorithm needs parameters, those parameters come along with the trusted public key.

  • (e) initial-policy-mapping-inhibit, which indicates whether policy mapping is allowed in the certification path.
  • (f) initial-explicit-policy, which indicates whether the path must be valid for at least one of the certificate policies in the user-initial-policy-set.
  • (g) initial-any-policy-inhibit, which indicates whether the anyPolicy OID should be processed if it's included in a certificate 🧠

6.1.2. Initialization 🌸

okay so this is the setup era 💖 the initialization phase sets up eleven state variables 🎀 using the seven inputs from before. let's gooo ✨

  • (a) valid_policy_tree: a tree of certificate policies, plus their optional qualifiers 🌳. each leaf is a valid policy at this stage of path validation. if valid policies exist at this stage, the depth of the tree equals the number of certificates in the chain that have been processed. if valid policies don't exist at this stage, the tree is set to NULL. once it's NULL, policy processing ceases 💀

each node has four data objects: the valid policy, a set of associated policy qualifiers, a set of one or more expected policy values, and a criticality indicator. if the node is at depth x, its parts mean this:

  • (1) valid_policy is a single policy OID for a valid policy on the path of length x.
  • (2) qualifier_set is the set of policy qualifiers attached to that valid policy in certificate x.
  • (3) criticality_indicator tells you whether the certificate policy extension in certificate x was marked as critical.
  • (4) expected_policy_set holds one or more policy OIDs that would satisfy this policy in certificate x+1.

the starting value of valid_policy_tree is one node with valid_policy set to anyPolicy, an empty qualifier_set, an expected_policy_set with the single value anyPolicy, and a criticality_indicator of FALSE. this node counts as depth zero 🧚

Figure 3 is a little picture of that starting state 🦋 later figures will use the same format to show how valid_policy_tree changes during path processing.

          +----------------+
          |   anyPolicy    |   <---- valid_policy
          +----------------+
          |       {}       |   <---- qualifier_set
          +----------------+
          |     FALSE      |   <---- criticality_indicator
          +----------------+
          |  {anyPolicy}   |   <---- expected_policy_set
          +----------------+

Figure 3. Initial value of the valid_policy_tree state variable

  • (b) permitted_subtrees: a set of root names for each name type (e.g., X.500 distinguished names, email addresses, or ip addresses) that defines the subtrees where every subject name in later certificates in the certification path MUST fall 🚧 this variable has a set for each name type. the starting value for the Distinguished Names set is the set of all Distinguished names, and the starting value for the set of RFC822 names is the set of all RFC822 names, and so on.
  • (c) excluded_subtrees: the same idea, a set of root names for each name type (e.g., X.500 distinguished names, email addresses, or ip addresses), but this time it defines subtrees where no subject name in later certificates in the certification path may fall 🙅 there's a set for each name type, and every set starts out empty.
  • (d) explicit_policy: an integer that says whether a non-NULL valid_policy_tree is required 👑 the integer is the number of non-self-issued certificates to process before that requirement kicks in. once it's set, it can be decreased but not increased. so if a certificate in the path needs a non-NULL valid_policy_tree, a later certificate can not remove that requirement 🔒 if initial-explicit-policy is set, the starting value is 0. otherwise it's n+1.
  • (e) inhibit_any-policy: an integer that says whether the anyPolicy policy identifier counts as a match 🙈 the integer is the number of non-self-issued certificates to process before any anyPolicy OID asserted in a certificate gets ignored. once it's set, it can be decreased but not increased. so if a certificate in the path inhibits anyPolicy processing, a later certificate can not allow it again. if initial-any-policy-inhibit is set, the starting value is 0. otherwise it's n+1.
  • (f) policy_mapping: an integer that says whether policy mapping is allowed 🍓 the integer is the number of non-self-issued certificates to process before policy mapping gets inhibited. once it's set, it can be decreased but not increased. so if a certificate in the path says policy mapping is not permitted, a later certificate can't override that. if initial-policy-mapping-inhibit is set, the starting value is 0. otherwise it's n+1.
  • (g) working_public_key_algorithm: the digital signature algorithm used to verify the signature on a certificate 🔐 it starts out from the trusted public key algorithm in the trust anchor information.
  • (h) working_public_key: the public key used to verify the signature on a certificate 🗝️ it starts out from the trusted public key in the trust anchor information.
  • (i) working_public_key_parameters: the parameters tied to the current public key that might be needed to verify a signature (it depends on the algorithm) 🧩 it starts out from the trusted public key parameters in the trust anchor information.
  • (j) working_issuer_name: the issuer distinguished name expected in the next certificate in the chain 📛 it starts out as the trusted issuer from the trust anchor information.
  • (k) max_path_length: an integer that starts at n, goes down by one for each non-self-issued certificate in the path, and may be reduced to the value in the path length constraint field of the basic constraints extension of a CA certificate 📏

once all the setup steps are done, run the basic certificate processing steps in 6.1.3 ✨💜

6.1.3. Basic Certificate Processing ✨

okay bestie, this is the basic path processing we run on certificate i (for all i in [1..n]) 💅. Here's the full checklist:

(a) Verify the basic certificate information. The certificate MUST satisfy each of the following:

(1) The certificate was signed with the working_public_key_algorithm using the working_public_key and the working_public_key_parameters 🔥.

(2) The certificate validity period includes the current time ⏰.

(3) At the current time, the certificate is not revoked and is not on hold status 🙈. This may be determined by obtaining the appropriate CRL (section 6.3), status information, or by out-of-band mechanisms.

(4) The certificate issuer name is the working_issuer_name 🎀.

(b) If certificate i is self-issued and it is not the final certificate in the path, skip this step for certificate i. Otherwise, verify that the subject name is within one of the permitted_subtrees for X.500 distinguished names, and verify that each of the alternative names in the subjectAltName extension (critical or non-critical) is within one of the permitted_subtrees for that name type 🌸.

(c) If certificate i is self-issued and it is not the final certificate in the path, skip this step for certificate i. Otherwise, verify that the subject name is not within one of the excluded_subtrees for X.500 distinguished names, and verify that each of the alternative names in the subjectAltName extension (critical or non-critical) is not within one of the excluded_subtrees for that name type 🚫.

(d) If the certificate policies extension is present in the certificate and the valid_policy_tree 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 in policy P and P-Q denote the qualifier set for policy P. Perform the following steps in order:

(i) If the valid_policy_tree includes a node of depth i-1 where P-OID is in the expected_policy_set, create a child node as follows: set the valid_policy to OID-P; set the qualifier_set to P-Q, and set the expected_policy_set to {P-OID}.

For example, consider a valid_policy_tree with a node of depth i-1 where the expected_policy_set is {Gold, White}. 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       |
                             +-----------------+
                             |       {}        |
                             +-----------------+   node of depth i-1
                             |      FALSE      |
                             +-----------------+
                             |  {Gold, White}  |
                             +-----------------+
                                      |
                                      |
                                      |
                                      V
                             +-----------------+
                             |      Gold       |
                             +-----------------+
                             |       {}        |
                             +-----------------+ node of depth i
                             |  uninitialized  |
                             +-----------------+
                             |     {Gold}      |
                             +-----------------+

                    Figure 4.  Processing an exact match

(ii) If there was no match in step (i) and the valid_policy_tree 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, and set the expected_policy_set to {P-OID}.

For example, consider a valid_policy_tree 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    |
                             +-----------------+
                             |       {}        |
                             +-----------------+ node of depth i-1
                             |      FALSE      |
                             +-----------------+
                             |   {anyPolicy}   |
                             +-----------------+
                                /           \
                               /             \
                              /               \
                             /                 \
               +-----------------+          +-----------------+
               |      Gold       |          |     Silver      |
               +-----------------+          +-----------------+
               |       {}        |          |   {Q-Silver}    |
               +-----------------+ nodes of +-----------------+
               | uninitialized   | depth i  | uninitialized   |
               +-----------------+          +-----------------+
               |     {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_any-policy is greater than 0 or (b) i<n and the certificate is self-issued, then:

For each node in the valid_policy_tree of depth i-1, for each value in the expected_policy_set (including anyPolicy) that does not appear in a child node, create a child node with the following values: set the valid_policy to the value from the expected_policy_set in the parent node; set the qualifier_set to AP-Q, and set the expected_policy_set to the value in the valid_policy from this node.

For example, consider a valid_policy_tree with a node of depth i-1 where the expected_policy_set is {Gold, Silver}. Assume anyPolicy appears in the certificate policies extension of certificate i, but Gold and Silver do not. This rule will generate two child nodes of depth i, one for each policy. The result is shown below as Figure 6.

                          +-----------------+
                          |      Red        |
                          +-----------------+
                          |       {}        |
                          +-----------------+ node of depth i-1
                          |      FALSE      |
                          +-----------------+
                          |  {Gold, Silver} |
                          +-----------------+
                             /           \
                            /             \
                           /               \
                          /                 \
            +-----------------+          +-----------------+
            |      Gold       |          |     Silver      |
            +-----------------+          +-----------------+
            |       {}        |          |       {}        |
            +-----------------+ nodes of +-----------------+
            |  uninitialized  | depth i  |  uninitialized  |
            +-----------------+          +-----------------+
            |     {Gold}      |          |    {Silver}     |
            +-----------------+          +-----------------+

         Figure 6.  Processing unmatched policies when the certificate
         policies extension specifies anyPolicy

(3) If there is a node in the valid_policy_tree 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_tree shown in Figure 7 below. The two nodes at depth i-1 that are marked with an 'X' have no children, and are deleted. Applying this rule to the resulting tree will cause the node at depth i-2 that is marked with an 'Y' to be deleted. The following application of the rule does not cause any nodes to be deleted, and this step is complete.

                              +-----------+
                              |           | node of depth i-3
                              +-----------+
                              /     |     \
                             /      |      \
                            /       |       \
                +-----------+ +-----------+ +-----------+
                |           | |           | |     Y     | nodes of
                +-----------+ +-----------+ +-----------+ depth i-2
                /   \               |             |
               /     \              |             |
              /       \             |             |
   +-----------+ +-----------+ +-----------+ +-----------+ nodes of
   |           | |     X     | |           | |    X      |  depth
   +-----------+ +-----------+ +-----------+ +-----------+   i-1
         |                      /    |    \
         |                     /     |     \
         |                    /      |      \
   +-----------+ +-----------+ +-----------+ +-----------+ nodes of
   |           | |           | |           | |           |  depth
   +-----------+ +-----------+ +-----------+ +-----------+   i

          Figure 7.  Pruning the valid_policy_tree

(4) If the certificate policies extension was marked as critical, set the criticality_indicator in all nodes of depth i to TRUE. If the certificate policies extension was not marked critical, set the criticality_indicator in all nodes of depth i to FALSE.

(e) If the certificate policies extension is not present, set the valid_policy_tree to NULL 🧺.

(f) Verify that either explicit_policy is greater than 0 or the valid_policy_tree is not equal to NULL;

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 6.1.4. If i is equal to n, perform the wrap-up steps listed in 6.1.5 🎀.

6.1.4. Preparation for Certificate i+1 🎀

okay so, this is the step where we get everything ready for certificate i+1 🦋 to prepare, we run through these steps for certificate i, bestie:

  • (a) If a policy mapping extension is present, verify that the special value anyPolicy does not appear as an issuerDomainPolicy or a subjectDomainPolicy. 🙈
  • (b) If a policy mapping extension is present, then for each issuerDomainPolicy ID-P in the policy mapping extension: 🌸
    • (1) If the policy_mapping variable is greater than 0, for each node in the valid_policy_tree 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 mapping extension.

If no node of depth i in the valid_policy_tree 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;
  • (iii) set the criticality_indicator to the criticality of the certificate policies extension of certificate i;
  • (iv) and set the 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 equal to 0:
    • (i) delete each node of depth i in the valid_policy_tree where ID-P is the valid_policy.
    • (ii) If there is a node in the valid_policy_tree 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.
  • (c) Assign the certificate subject name to working_issuer_name. 💖
  • (d) Assign the certificate subjectPublicKey to working_public_key. ✨
  • (e) If the subjectPublicKeyInfo field of the certificate contains an algorithm field with non-null parameters, assign the parameters to the working_public_key_parameters variable.

If the subjectPublicKeyInfo field of the certificate contains an algorithm field with null parameters or parameters are omitted, compare the certificate subjectPublicKey algorithm to the working_public_key_algorithm. If the certificate subjectPublicKey algorithm and the working_public_key_algorithm are different, set the working_public_key_parameters to null. 🧚

  • (f) Assign the certificate subjectPublicKey algorithm to the working_public_key_algorithm variable. 🍓
  • (g) If a name constraints extension is included in the certificate, modify the permitted_subtrees and excluded_subtrees state variables as follows:
    • (1) If permittedSubtrees is present in the certificate, set the permitted_subtrees state variable to the intersection of its previous value and the value indicated in the extension field. If permittedSubtrees does not include a particular name type, the permitted_subtrees state variable is unchanged for that name type. For example, the intersection of nist.gov and csrc.nist.gov is csrc.nist.gov. And, the intersection of nist.gov and rsasecurity.com is the empty set. 👑
    • (2) If excludedSubtrees is present in the certificate, set the excluded_subtrees state variable to the union of its previous value and the value indicated in the extension field. If excludedSubtrees does not include a particular name type, the excluded_subtrees state variable is unchanged for that name type. For example, the union of the name spaces nist.gov and csrc.nist.gov is nist.gov. And, the union of nist.gov and rsasecurity.com is both name spaces. 🌈
  • (h) If the issuer and subject names are not identical:
    • (1) If explicit_policy is not 0, decrement explicit_policy by 1.
    • (2) If policy_mapping is not 0, decrement policy_mapping by 1.
    • (3) If inhibit_any-policy is not 0, decrement inhibit_any-policy by 1.
  • (i) If a policy constraints extension is included in the certificate, modify the explicit_policy and policy_mapping state variables as follows:
    • (1) If requireExplicitPolicy is present and is less than explicit_policy, set explicit_policy to the value of requireExplicitPolicy.
    • (2) If inhibitPolicyMapping is present and is less than policy_mapping, set policy_mapping to the value of inhibitPolicyMapping.
  • (j) If the inhibitAnyPolicy extension is included in the certificate and is less than inhibit_any-policy, set inhibit_any-policy to the value of inhibitAnyPolicy. 🦋
  • (k) Verify that the certificate is a CA certificate (as specified in a basicConstraints extension or as verified out-of-band). 💅
  • (l) If the certificate was not self-issued, verify that max_path_length is greater than zero and decrement max_path_length by 1. 🫶
  • (m) If pathLengthConstraint is present in the certificate and is less than max_path_length, set max_path_length to the value of pathLengthConstraint. 🌸
  • (n) If a key usage extension is present, verify that the keyCertSign bit is set. 🔥
  • (o) Recognize and process any other critical extension present in the certificate. Process any other recognized non-critical extension present in the certificate. 💜
⚠️ If check (a), (k), (l), (n) or (o) fails, the procedure terminates, returning a failure indication and an appropriate reason. No skipping this, bestie, it's a hard stop 💀

If (a), (k), (l), (n) and (o) have completed successfully, increment i and perform the basic certificate processing specified in 6.1.3. ✨


6.1.5. Wrap-up procedure 🌷

okay this is the wrap-up for the end entity certificate, so we run these steps for certificate n, iykyk 🧁

  • (a) If certificate n was not self-issued and explicit_policy is not 0, decrement explicit_policy by 1. 💖
  • (b) If a policy constraints extension is included in the certificate and requireExplicitPolicy is present and has a value of 0, set the explicit_policy state variable to 0. 🎀
  • (c) Assign the certificate subjectPublicKey to working_public_key. 🦋
  • (d) If the subjectPublicKeyInfo field of the certificate contains an algorithm field with non-null parameters, assign the parameters to the working_public_key_parameters variable.

If the subjectPublicKeyInfo field of the certificate contains an algorithm field with null parameters or parameters are omitted, compare the certificate subjectPublicKey algorithm to the working_public_key_algorithm. If the certificate subjectPublicKey algorithm and the working_public_key_algorithm are different, set the working_public_key_parameters to null. 🧚

  • (e) Assign the certificate subjectPublicKey algorithm to the working_public_key_algorithm variable. 🍓
  • (f) Recognize and process any other critical extension present in the certificate n. Process any other recognized non-critical extension present in certificate n. 🫶
  • (g) Calculate the intersection of the valid_policy_tree and the user-initial-policy-set, as follows:
    • (i) If the valid_policy_tree is NULL, the intersection is NULL.
    • (ii) If the valid_policy_tree is not NULL and the user-initial-policy-set is any-policy, the intersection is the entire valid_policy_tree.
    • (iii) If the valid_policy_tree is not NULL and the user-initial-policy-set is not any-policy, calculate the intersection of the valid_policy_tree and the user-initial-policy-set as follows:
      1. Determine the set of policy nodes whose parent nodes have a valid_policy of anyPolicy. This is the valid_policy_node_set.
      2. If the valid_policy of any node in the valid_policy_node_set is not in the user-initial-policy-set and is not anyPolicy, delete this node and all its children.
      3. If the valid_policy_tree includes a node of depth n with the valid_policy anyPolicy and the user-initial-policy-set is not any-policy perform the following steps:
        • a. Set P-Q to the qualifier_set in the node of depth n with valid_policy anyPolicy.
        • b. For each P-OID in the user-initial-policy-set that is not the valid_policy of a node in the valid_policy_node_set, create a child node whose parent is the node of depth n-1 with the valid_policy anyPolicy. Set the values in the child node as follows: set the valid_policy to P-OID; set the qualifier_set to P-Q; copy the criticality_indicator from the node of depth n with the valid_policy anyPolicy; and set the expected_policy_set to {P-OID}.
        • c. Delete the node of depth n with the valid_policy anyPolicy.
      4. If there is a node in the valid_policy_tree of depth n-1 or less without any child nodes, delete that node. Repeat this step until there are no nodes of depth n-1 or less without children. 🌈

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. 👑🎉


6.1.6. Outputs 🧚

if path processing succeeds, the procedure terminates and hands back a success indication, plus the final value of the valid_policy_tree, the working_public_key, the working_public_key_algorithm, and the working_public_key_parameters. literally the whole payoff ✨💅

6.2. Using the Path Validation Algorithm ✨

Okay bestie, so the path validation algorithm 🦋 is all about validating ONE certification path at a time. Every path starts at a specific trust anchor, but there's no rule saying every path your system checks has to share the same trust anchor 💅. An implementation that supports multiple trust anchors MAY augment the algorithm in section 6.1 to further limit the set of valid certification paths that begin with a particular trust anchor. For example, an implementation MAY modify the algorithm to apply name constraints to a specific trust anchor during the initialization phase, or the application MAY require a particular alternative name form to be present in the end entity certificate, or the application MAY impose requirements on application-specific extensions. So the path validation algorithm in section 6.1 is giving you the minimum conditions for a path to count as valid 🎀.

The selection of one or more trusted CAs is a local decision 🌈. A system may provide any one of its trusted CAs as the trust anchor for a particular path. The inputs to the path validation algorithm may be different for each path. Those inputs may reflect application-specific requirements or limits on how much a particular trust anchor is trusted 🔥. For example, a trusted CA may only be trusted for a particular certificate policy, and that restriction can be expressed through the inputs to the path validation procedure. It's giving customization, honestly 😭.

It's also possible to specify an extended version of the above certification path processing procedure that gives default behavior identical to the rules of PEM [RFC 1422] 🧚. In this extended version, the extra inputs are a list of one or more Policy Certification Authority (PCA) names and an indicator of the position in the certification path where the PCA is expected. At the nominated PCA position, the CA name gets compared against that list. If a recognized PCA name is found, then a constraint of SubordinateToCA is implicitly assumed for the rest of the certification path and processing continues 💜. If no valid PCA name is found, and the certification path can't be validated on the basis of identified policies either, then the certification path is considered invalid 💀.


6.3. CRL Validation 🧾

This section walks through the steps needed to figure out whether a certificate is revoked or on hold, for when CRLs are the revocation mechanism the certificate issuer is using 🍓. Conforming implementations that support CRLs are not required to implement this algorithm, but they MUST be functionally equivalent to the external behavior that comes out of this procedure. Any algorithm can be used by a particular implementation as long as it derives the correct result, so you have freedom, main character energy ✨.

This algorithm assumes that all of the needed CRLs are already sitting in a local cache 🗂️. Also, if the next update time of a CRL has passed, the algorithm assumes there's a mechanism to fetch a current CRL and put it in the local CRL cache.

This algorithm defines a set of inputs, a set of state variables, and processing steps that get performed for each certificate in the path. The output of the algorithm is the revocation status of the certificate 🦋.

6.3.1. Revocation Inputs 🔐

To support revocation processing, the algorithm needs two inputs:

  • (a) certificate: The algorithm needs the certificate serial number and issuer name to determine whether a certificate is on a particular CRL. The basicConstraints extension is used to determine whether the supplied certificate is associated with a CA or an end entity. If present, the algorithm uses the cRLDistributionsPoint and freshestCRL extensions to determine revocation status 🌟.
  • (b) use-deltas: This boolean input determines whether delta CRLs are applied to CRLs 🫶.

Note that implementations supporting legacy PKIs, such as RFC 1422 and X.509 version 1, will need an additional input indicating whether the supplied certificate is associated with a CA or an end entity 🙈.

6.3.2. Initialization and Revocation State Variables 🌸

To support CRL processing, the algorithm needs the following state variables, and yes they each have their own job 👑:

  • (a) reasons_mask: This variable holds the set of revocation reasons supported by the CRLs and delta CRLs processed so far. The legal members of the set are the possible revocation reason values: unspecified, keyCompromise, caCompromise, affiliationChanged, superseded, cessationOfOperation, certificateHold, privilegeWithdrawn, and aACompromise. The special value all-reasons is used to denote the set of all legal members. This variable is initialized to the empty set 🍭.
  • (b) cert_status: This variable holds the status of the certificate. It may be assigned one of the following values: unspecified, keyCompromise, caCompromise, affiliationChanged, superseded, cessationOfOperation, certificateHold, removeFromCRL, privilegeWithdrawn, aACompromise, the special value UNREVOKED, or the special value UNDETERMINED. This variable is initialized to the special value UNREVOKED 💖.
  • (c) interim_reasons_mask: This holds the set of revocation reasons supported by the CRL or delta CRL currently being processed 🎀.
Note: In some environments, it isn't necessary to check all reason codes. For example, some environments only care about caCompromise and keyCompromise for CA certificates. This algorithm checks all reason codes, so if you want to limit the checking to a subset, you may need extra processing and state variables to do that 🫠.

6.3.3. CRL Processing ✨

okay bestie, this algorithm is giving "innocent until proven guilty" 💅 It starts by assuming the certificate is not revoked 🦋 Then it checks one or more CRLs until either the certificate status is confirmed as revoked, or enough CRLs have been checked to cover all the reason codes 💖

So for each distribution point (DP) in the certificate CRL distribution points extension, and for each matching CRL in the local CRL cache, the loop keeps going while ((reasons_mask is not all-reasons) and (cert_status is UNREVOKED)) and does the following 🌸

  • (a) Update the local CRL cache by getting a complete CRL, a delta CRL, or both, depending on what's needed:
    • (1) If the current time is after the value of the CRL next update field, then do one of these:
      • (i) If use-deltas is set and either the certificate or the CRL has the freshest CRL extension, get a delta CRL with the a next update value that is after the current time, and use it to update the locally cached CRL as specified in section 5.2.4 🧚
      • (ii) Update the local CRL cache with a current complete CRL, check that the current time is before the next update value in the new CRL, and keep processing with the new CRL. If use-deltas is set, also get the current delta CRL that can be used to update the new locally cached complete CRL as specified in section 5.2.4 ✨
    • (2) If the current time is before the value of the next update field and use-deltas is set, get the current delta CRL that can be used to update the locally cached complete CRL as specified in section 5.2.4 🍓
  • (b) Verify the issuer and scope of the complete CRL like this:
    • (1) If the DP includes cRLIssuer, check that the issuer field in the complete CRL matches cRLIssuer in the DP, and that the complete CRL has an issuing distribution point extension with the indrectCRL boolean asserted. Otherwise, check that the CRL issuer matches the certificate issuer 🎀
    • (2) If the complete CRL includes an issuing distribution point (IDP) CRL extension, check the following:
      • (i) If the distribution point name is present in the IDP CRL extension and the distribution field is present in the DP, check that one of the names in the IDP matches one of the names in the DP. If the distribution point name is present in the IDP CRL extension and the distribution field is omitted from the DP, check that one of the names in the IDP matches one of the names in the cRLIssuer field of the DP 🦋
      • (ii) If the onlyContainsUserCerts boolean is asserted in the IDP CRL extension, check that the certificate does not include the basic constraints extension with the cA boolean asserted 💜
      • (iii) If the onlyContainsCACerts boolean is asserted in the IDP CRL extension, check that the certificate includes the basic constraints extension with the cA boolean asserted 🌈
      • (iv) Check that the onlyContainsAttributeCerts boolean is not asserted 🙈
  • (c) If use-deltas is set, verify the issuer and scope of the delta CRL like this:
    • (1) Check that the delta CRL issuer matches the complete CRL issuer 🫶
    • (2) If the complete CRL includes an issuing distribution point (IDP) CRL extension, check that the delta CRL contains a matching IDP CRL extension. If the complete CRL omits an IDP CRL extension, check that the delta CRL also omits an IDP CRL extension 🔥
    • (3) Check that the delta CRL authority key identifier extension matches the complete CRL authority key identifier extension 👑
  • (d) Compute the interim_reasons_mask for this CRL like this:
    • (1) If the issuing distribution point (IDP) CRL extension is present and includes onlySomeReasons, and the DP includes reasons, set interim_reasons_mask to the intersection of reasons in the DP and onlySomeReasons in the IDP CRL extension 🌸
    • (2) If the IDP CRL extension includes onlySomeReasons but the DP omits reasons, set interim_reasons_mask to the value of onlySomeReasons in the IDP CRL extension 🍓
    • (3) If the IDP CRL extension is not present or omits onlySomeReasons, but the DP includes reasons, set interim_reasons_mask to the value of DP reasons 🧚
    • (4) If the IDP CRL extension is not present or omits onlySomeReasons, and the DP omits reasons, set interim_reasons_mask to the special value all-reasons 🌈
  • (e) Check that interim_reasons_mask includes one or more reasons that are not included in the reasons_mask ✨
  • (f) Get and validate the certification path for the complete CRL issuer. If a key usage extension is present in the CRL issuer's certificate, check that the cRLSign bit is set 💅
  • (g) Validate the signature on the complete CRL using the public key validated in step (f) 🔐
  • (h) If use-deltas is set, validate the signature on the delta CRL using the public key validated in step (f) 🦋
  • (i) If use-deltas is set, search for the certificate on the delta CRL. If an entry is found that matches the certificate issuer and serial number as described in section 5.3.4, set the cert_status variable to the indicated reason like this:
    • (1) If the reason code CRL entry extension is present, set the cert_status variable to the value of the reason code CRL entry extension 💖
    • (2) If the reason code CRL entry extension is not present, set the cert_status variable to the value unspecified 🙈
  • (j) If (cert_status is UNREVOKED), search for the certificate on the complete CRL. If an entry is found that matches the certificate issuer and serial number as described in section 5.3.4, set the cert_status variable to the indicated reason as described in step (i) 💀
  • (k) If (cert_status is removeFromCRL), set cert_status to UNREVOKED 🎀

If ((reasons_mask is all-reasons) OR (cert_status is not UNREVOKED)), then the revocation status has been determined, so return cert_status 👑

If the revocation status has not been determined, repeat the process above with any available CRLs that are not specified in a distribution point but are issued by the certificate issuer 🌸 For processing a CRL like this, assume a DP with both the reasons and the cRLIssuer fields omitted, and a distribution point name of the certificate issuer. That means the sequence of names in fullName is generated from the certificate issuer field as well as the certificate issuerAltName extension. If the revocation status remains undetermined, return the cert_status UNDETERMINED 🦋


7. References ✨

okay, the reference list is next! 📚 Every single one is kept exactly as written, typos and all 🫶

[ISO 10646] ISO/IEC 10646-1:1993.  International Standard --
            Information technology -- Universal Multiple-Octet Coded
            Character Set (UCS) -- Part 1: Architecture and Basic
            Multilingual Plane.

[RFC 791]   Postel, J.,  "Internet Protocol", STD 5, RFC 791,
            September 1981.

[RFC 822]   Crocker, D., "Standard for the format of ARPA Internet
            text messages", STD 11, RFC 822, August 1982.

[RFC 1034]  Mockapetris, P., "Domain Names - Concepts and
            Facilities", STD 13, RFC 1034, November 1987.

[RFC 1422]  Kent, S., "Privacy Enhancement for Internet Electronic
            Mail: Part II: Certificate-Based Key Management," RFC
            1422, February 1993.

[RFC 1423]  Balenson, D., "Privacy Enhancement for Internet
            Electronic Mail: Part III: Algorithms, Modes, and
            Identifiers," RFC 1423, February 1993.

[RFC 1510]  Kohl, J. and C. Neuman, "The Kerberos Network
            Authentication Service (V5)," RFC 1510, September 1993.

[RFC 1519]  Fuller, V., T. Li, J. Yu and K. Varadhan, "Classless
            Inter-Domain Routing (CIDR): An Address Assignment and
            Aggregation Strategy", RFC 1519, September 1993.

[RFC 1738]  Berners-Lee, T., L. Masinter and M. McCahill, "Uniform
            Resource Locators (URL)", RFC 1738, December 1994.

[RFC 1778]  Howes, T., S. Kille, W. Yeong and C. Robbins, "The String
            Representation of Standard Attribute Syntaxes," RFC 1778,
            March 1995.

[RFC 1883]  Deering, S. and R. Hinden.  "Internet Protocol, Version 6
            (IPv6) Specification", RFC 1883, December 1995.

[RFC 2044]  F. Yergeau, F., "UTF-8, a transformation format of
            Unicode and ISO 10646", RFC 2044, October 1996.

[RFC 2119]  Bradner, S., "Key words for use in RFCs to Indicate
            Requirement Levels", BCP 14, RFC 2119, March 1997.

[RFC 2247]  Kille, S., M. Wahl, A. Grimstad, R. Huber and S.
            Sataluri, "Using Domains in LDAP/X.500 Distinguished
            Names", RFC 2247, January 1998.

[RFC 2252]  Wahl, M., A. Coulbeck, T. Howes and S. Kille,
            "Lightweight Directory Access Protocol (v3):  Attribute
            Syntax Definitions", RFC 2252, December 1997.

[RFC 2277]  Alvestrand, H., "IETF Policy on Character Sets and
            Languages", BCP 18, RFC 2277, January 1998.

[RFC 2279]  Yergeau, F., "UTF-8, a transformation format of ISO
            10646", RFC 2279, January 1998.

[RFC 2459]  Housley, R., W. Ford, W. Polk and D. Solo, "Internet
            X.509 Public Key Infrastructure: Certificate and CRL
            Profile", RFC 2459, January 1999.

[RFC 2560]  Myers, M., R. Ankney, A. Malpani, S. Galperin and C.
            Adams, "Online Certificate Status Protocal - OCSP", June
            1999.

[SDN.701]   SDN.701, "Message Security Protocol 4.0", Revision A,
            1997-02-06.

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

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

[X.520]     ITU-T Recommendation X.520: Information Technology - Open
            Systems Interconnection - The Directory: Selected
            Attribute Types, 1993.

[X.660]     ITU-T Recommendation X.660 Information Technology - ASN.1
            encoding rules: Specification of Basic Encoding Rules
            (BER), Canonical Encoding Rules (CER) and Distinguished
            Encoding Rules (DER), 1997.

[X.690]     ITU-T Recommendation X.690 Information Technology - Open
            Systems Interconnection - Procedures for the operation of
            OSI Registration Authorities: General procedures, 1992.

[X9.55]     ANSI X9.55-1995, Public Key Cryptography For The
            Financial Services Industry: Extensions To Public Key
            Certificates And Certificate Revocation Lists, 8
            December, 1995.

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

[PKIXTSA]   Adams, C., Cain, P., Pinkas, D. and R. Zuccherato,
            "Internet X.509 Public Key Infrastructure Time-Stamp
            Protocol (TSP)", RFC 3161, August 2001.

8. Intellectual Property Rights ✨

Okay so, the IETF has been told that some intellectual property rights might be claimed for parts of this spec 👀. If you want the full list of claimed rights, check the online list at http://www.ietf.org/ipr.html 🔗.

The IETF doesn't take a side on whether any of those rights are valid, how far they reach, or whether a license for them is even available 🙃. It also doesn't say it went looking for any of them 🫠. The IETF's rules for rights in standards-track and standards-related docs are in BCP 11 📚. You can also ask the IETF Secretariat for copies of rights claims submitted for publication, any license assurances that were promised, or the results of anyone trying to get a general license or permission for proprietary rights, for implementers or users of this spec 📬.


9. Security Considerations 🔐

Main vibe: most of this spec is about the format and content of certificates and CRLs 📜. Since they're digitally signed, you don't need any extra integrity service on top 🙌. Certs and CRLs don't need to be kept secret, and letting anyone access them, unrestricted and anonymously, has no security implications 🫶.

BUT security factors outside this spec still affect how much assurance users get 😬. This section is the highlight reel of critical issues for implementers, administrators and users 🎬.

The way CAs and RAs check that a subject's identity really matches their public key makes a huge difference to how much trust a certificate deserves 🕵️‍♀️. Relying parties might want to read the CA's certificate practice statement 📖. This is especially important when a CA is issuing certificates to other CAs 🏛️.

Using one key pair for both signing and other purposes is strongly discouraged 🙅‍♀️. Separate key pairs for signing and key management give users several perks 💅. Losing or leaking a signing key is a different situation from losing or leaking a key management key, so separate pairs let you respond in a balanced, flexible way 🤸. Different validity periods or key lengths for each pair might also make sense in some environments ⏳. Sadly, some legacy apps (e.g., SSL) use one key pair for both signing and key management 😭.

Protecting private keys is a huge deal 🔑. On a small scale, if users don't protect their private keys, an attacker can pretend to be them or decrypt their personal info 🥷. On a bigger scale, if someone steals a CA's private signing key, things get catastrophic 💀. If an attacker gets that key without anyone noticing, they can issue fake certificates and CRLs 🎭. Once fake certs and CRLs exist, nobody trusts the system anymore 💔. If a compromise is detected, every certificate issued by the compromised CA MUST be revoked, so its users can't keep talking to users of other CAs 🚫. Rebuilding after a compromise is a real headache, so CAs are advised to combine strong technical measures (e.g., tamper-resistant cryptographic modules) with solid management procedures (e.g., separation of duties) to prevent this in the first place 🛡️.

Losing a CA's private signing key is also a problem 😩. The CA wouldn't be able to produce CRLs or do a normal key rollover 🙃. CAs SHOULD keep secure backups of their signing keys 💾. How secure the key backup procedures are matters a lot for avoiding key compromise 🔐.

How fresh and available revocation info is also affects how much a certificate should be trusted ⏰. Certificates expire naturally, but stuff can happen during their lifetime that breaks the link between the subject and their public key 💔. If revocation info is late or missing, the assurance for that binding drops hard 📉. Relying parties might not be able to process every critical extension that can show up in a CRL 🤷‍♀️. CAs SHOULD take extra care when they only make revocation info available through CRLs with critical extensions, especially if this profile doesn't require support for those extensions 🧐. Here's an example: say revocation info comes from a mix of delta CRLs and full CRLs, and delta CRLs go out more often than full CRLs. Then relying parties that can't handle the critical extensions for delta CRL processing won't be able to get the newest revocation info 😵. On the flip side, if a full CRL gets issued every time a delta CRL does, everyone gets timely revocation info, even relying parties who can't handle those extensions 🎉. Similarly, implementations of the certification path validation mechanism in section 6 that skip revocation checking give less assurance than the ones that do check 🙅.

The certification path validation algorithm depends on knowing, for certain, the public keys (and other info) of one or more trusted CAs 👑. Deciding to trust a CA is a big deal, because it ultimately decides how much trust any certificate gets 🎀. Getting the trusted CA public keys to users in an authenticated way (usually as a "self-signed" certificate) is a security-critical out-of-band process 🔒. That process is outside the scope of this spec 🙏.

Also, if a trusted CA has a key compromise or fails, users will need to update the info they give the path validation routine 🔄. Trusting too many CAs makes that trusted CA info a pain to maintain 😫. Trusting only one CA, though, could box users into a closed community 📦.

The quality of the implementations that process certificates matters too 🧑‍💻. The path validation algorithm in section 6 relies on the integrity of the trusted CA info, especially the integrity of the public keys tied to those trusted CAs 🔑. If an attacker swaps in public keys they hold the private keys for, they can trick the user into accepting fake certificates 🤡.

A key-to-subject binding can't be any stronger than the cryptographic module and algorithms used to generate the signature 💪. Short key lengths or weak hash algorithms make a certificate less useful 📉. CAs are encouraged to keep up with advances in cryptology so they can use strong cryptographic techniques 📚. CAs SHOULD decline to issue certificates to CAs or end entities that generate weak signatures 🚫.

Name comparison is a sneaky one 👀. Inconsistent name comparison rules can lead to accepting invalid X.509 certification paths, or rejecting valid ones 😵‍💫. The X.500 series defines distinguished name comparison rules that compare strings without caring about case, character set, multi-character white space substrings, or leading and trailing white space 🧐. This spec relaxes those requirements and requires support for binary comparison at a minimum 🫶.

CAs MUST encode the distinguished name in the subject field of a CA certificate exactly the same way as the distinguished name in the issuer field of certificates that CA issues 🔤. If CAs use different encodings, implementations might fail to recognize name chains for paths that include that certificate 😭. The result? Valid paths could get rejected 💔.

Name constraints for distinguished names also MUST be stated with exactly the same encoding used in the subject field or subjectAltName extension 📝. If they aren't, excludedSubTrees constraints won't match and invalid paths get accepted 🚨. Same story for permittedSubtrees constraints: they won't match, so valid paths get rejected 😩. To avoid accepting invalid paths, CAs SHOULD state name constraints for distinguished names as permittedSubtrees wherever they can 💖.


Appendix A. Psuedo-ASN.1 Structures and OIDs 🧚

Okay, this appendix describes the data objects that conforming PKI components use, written in an "ASN.1-like" syntax 📝. It's a hybrid of the 1988 and 1993 ASN.1 syntaxes, with the 1988 syntax extended by the 1993 UNIVERSAL types UniversalString, BMPString and UTF8String 🌈.

Here's the drama: ASN.1 doesn't allow type statements in an ASN.1 module, and the 1993 standard doesn't allow the new UNIVERSAL types in modules that use the 1988 syntax 🙈. So this module doesn't conform to either version of the ASN.1 standard 😅.

This appendix can be converted into 1988 ASN.1 by swapping the UNIVERSAL type definitions for the 1988 catch-all "ANY" 🔁.

A.1 Explicitly Tagged Module, 1988 Syntax 💜

PKIX1Explicit88 { iso(1) identified-organization(3) dod(6) internet(1)
  security(5) mechanisms(5) pkix(7) id-mod(0) id-pkix1-explicit(18) }

DEFINITIONS EXPLICIT TAGS ::=

BEGIN

-- EXPORTS ALL --

-- IMPORTS NONE --

-- UNIVERSAL Types defined in 1993 and 1998 ASN.1
-- and required by this specification

UniversalString ::= [UNIVERSAL 28] IMPLICIT OCTET STRING
        -- UniversalString is defined in ASN.1:1993

BMPString ::= [UNIVERSAL 30] IMPLICIT OCTET STRING
      -- BMPString is the subtype of UniversalString and models
      -- the Basic Multilingual Plane of ISO/IEC/ITU 10646-1

UTF8String ::= [UNIVERSAL 12] IMPLICIT OCTET STRING
      -- The content of this type conforms to RFC 2279.

-- PKIX specific OIDs

id-pkix  OBJECT IDENTIFIER  ::=
         { iso(1) identified-organization(3) dod(6) internet(1)
                    security(5) mechanisms(5) pkix(7) }

-- PKIX arcs

id-pe OBJECT IDENTIFIER  ::=  { id-pkix 1 }
        -- arc for private certificate extensions
id-qt OBJECT IDENTIFIER ::= { id-pkix 2 }
        -- arc for policy qualifier types
id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
        -- arc for extended key purpose OIDS
id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
        -- arc for access descriptors

-- policyQualifierIds for Internet policy qualifiers

id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }
      -- OID for CPS qualifier
id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }
      -- OID for user notice qualifier

-- access descriptor definitions

id-ad-ocsp         OBJECT IDENTIFIER ::= { id-ad 1 }
id-ad-caIssuers    OBJECT IDENTIFIER ::= { id-ad 2 }
id-ad-timeStamping OBJECT IDENTIFIER ::= { id-ad 3 }
id-ad-caRepository OBJECT IDENTIFIER ::= { id-ad 5 }

-- attribute data types

Attribute       ::=     SEQUENCE {
      type              AttributeType,
      values    SET OF AttributeValue }
            -- at least one value is required

AttributeType           ::=  OBJECT IDENTIFIER

AttributeValue          ::=  ANY

AttributeTypeAndValue           ::=     SEQUENCE {
        type    AttributeType,
        value   AttributeValue }

-- suggested naming attributes: Definition of the following
--   information object set may be augmented to meet local
--   requirements.  Note that deleting members of the set may
--   prevent interoperability with conforming implementations.
-- presented in pairs: the AttributeType followed by the
--   type definition for the corresponding AttributeValue
--Arc for standard naming attributes

okay bestie, this is the naming attribute zone and it's giving main character energy 💖🎀

id-at OBJECT IDENTIFIER ::= { joint-iso-ccitt(2) ds(5) 4 }
-- Naming attributes of type X520name

id-at-name              AttributeType ::= { id-at 41 }
id-at-surname           AttributeType ::= { id-at 4 }
id-at-givenName         AttributeType ::= { id-at 42 }
id-at-initials          AttributeType ::= { id-at 43 }
id-at-generationQualifier AttributeType ::= { id-at 44 }

X520name ::= CHOICE {
      teletexString     TeletexString   (SIZE (1..ub-name)),
      printableString   PrintableString (SIZE (1..ub-name)),
      universalString   UniversalString (SIZE (1..ub-name)),
      utf8String        UTF8String      (SIZE (1..ub-name)),
      bmpString         BMPString       (SIZE (1..ub-name)) }

-- Naming attributes of type X520CommonName

id-at-commonName        AttributeType ::= { id-at 3 }

X520CommonName ::= CHOICE {
      teletexString     TeletexString   (SIZE (1..ub-common-name)),
      printableString   PrintableString (SIZE (1..ub-common-name)),
      universalString   UniversalString (SIZE (1..ub-common-name)),
      utf8String        UTF8String      (SIZE (1..ub-common-name)),
      bmpString         BMPString       (SIZE (1..ub-common-name)) }

-- Naming attributes of type X520LocalityName

id-at-localityName      AttributeType ::= { id-at 7 }

X520LocalityName ::= CHOICE {
      teletexString     TeletexString   (SIZE (1..ub-locality-name)),
      printableString   PrintableString (SIZE (1..ub-locality-name)),
      universalString   UniversalString (SIZE (1..ub-locality-name)),
      utf8String        UTF8String      (SIZE (1..ub-locality-name)),
      bmpString         BMPString       (SIZE (1..ub-locality-name)) }

-- Naming attributes of type X520StateOrProvinceName

id-at-stateOrProvinceName AttributeType ::= { id-at 8 }

X520StateOrProvinceName ::= CHOICE {
      teletexString     TeletexString   (SIZE (1..ub-state-name)),
      printableString   PrintableString (SIZE (1..ub-state-name)),
      universalString   UniversalString (SIZE (1..ub-state-name)),
      utf8String        UTF8String      (SIZE (1..ub-state-name)),
      bmpString         BMPString       (SIZE(1..ub-state-name)) }

-- Naming attributes of type X520OrganizationName

id-at-organizationName  AttributeType ::= { id-at 10 }

X520OrganizationName ::= CHOICE {
      teletexString     TeletexString
                          (SIZE (1..ub-organization-name)),
      printableString   PrintableString
                          (SIZE (1..ub-organization-name)),
      universalString   UniversalString
                          (SIZE (1..ub-organization-name)),
      utf8String        UTF8String
                          (SIZE (1..ub-organization-name)),
      bmpString         BMPString
                          (SIZE (1..ub-organization-name))  }

-- Naming attributes of type X520OrganizationalUnitName

id-at-organizationalUnitName AttributeType ::= { id-at 11 }

X520OrganizationalUnitName ::= CHOICE {
      teletexString     TeletexString
                          (SIZE (1..ub-organizational-unit-name)),
      printableString   PrintableString
                          (SIZE (1..ub-organizational-unit-name)),
      universalString   UniversalString
                          (SIZE (1..ub-organizational-unit-name)),
      utf8String        UTF8String
                          (SIZE (1..ub-organizational-unit-name)),
      bmpString         BMPString
                          (SIZE (1..ub-organizational-unit-name)) }

-- Naming attributes of type X520Title

id-at-title             AttributeType ::= { id-at 12 }

X520Title ::= CHOICE {
      teletexString     TeletexString   (SIZE (1..ub-title)),
      printableString   PrintableString (SIZE (1..ub-title)),
      universalString   UniversalString (SIZE (1..ub-title)),
      utf8String        UTF8String      (SIZE (1..ub-title)),
      bmpString         BMPString       (SIZE (1..ub-title)) }

-- Naming attributes of type X520dnQualifier

id-at-dnQualifier       AttributeType ::= { id-at 46 }

X520dnQualifier ::=     PrintableString
-- Naming attributes of type X520countryName (digraph from IS 3166)

id-at-countryName       AttributeType ::= { id-at 6 }

X520countryName ::=     PrintableString (SIZE (2))

-- Naming attributes of type X520SerialNumber

id-at-serialNumber      AttributeType ::= { id-at 5 }

X520SerialNumber ::=    PrintableString (SIZE (1..ub-serial-number))

-- Naming attributes of type X520Pseudonym

id-at-pseudonym         AttributeType ::= { id-at 65 }

X520Pseudonym ::= CHOICE {
   teletexString     TeletexString   (SIZE (1..ub-pseudonym)),
   printableString   PrintableString (SIZE (1..ub-pseudonym)),
   universalString   UniversalString (SIZE (1..ub-pseudonym)),
   utf8String        UTF8String      (SIZE (1..ub-pseudonym)),
   bmpString         BMPString       (SIZE (1..ub-pseudonym)) }

-- Naming attributes of type DomainComponent (from RFC 2247)

id-domainComponent      AttributeType ::=
                          { 0 9 2342 19200300 100 1 25 }

DomainComponent ::=     IA5String

-- Legacy attributes

pkcs-9 OBJECT IDENTIFIER ::=
       { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }

id-emailAddress          AttributeType ::= { pkcs-9 1 }

EmailAddress ::=         IA5String (SIZE (1..ub-emailaddress-length))

-- naming data types --

Name ::= CHOICE { -- only one possibility for now --
      rdnSequence  RDNSequence }

RDNSequence ::= SEQUENCE OF RelativeDistinguishedName

DistinguishedName ::=   RDNSequence
RelativeDistinguishedName  ::=
                    SET SIZE (1 .. MAX) OF AttributeTypeAndValue

-- Directory string type --

DirectoryString ::= CHOICE {
      teletexString             TeletexString   (SIZE (1..MAX)),
      printableString           PrintableString (SIZE (1..MAX)),
      universalString           UniversalString (SIZE (1..MAX)),
      utf8String              UTF8String      (SIZE (1..MAX)),
      bmpString               BMPString       (SIZE (1..MAX)) }

-- certificate and CRL specific structures begin here

Certificate  ::=  SEQUENCE  {
     tbsCertificate       TBSCertificate,
     signatureAlgorithm   AlgorithmIdentifier,
     signature            BIT STRING  }

TBSCertificate  ::=  SEQUENCE  {
     version         [0]  Version DEFAULT v1,
     serialNumber         CertificateSerialNumber,
     signature            AlgorithmIdentifier,
     issuer               Name,
     validity             Validity,
     subject              Name,
     subjectPublicKeyInfo SubjectPublicKeyInfo,
     issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
                          -- If present, version MUST be v2 or v3
     subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
                          -- If present, version MUST be v2 or v3
     extensions      [3]  Extensions OPTIONAL
                          -- If present, version MUST be v3 --  }

Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }

CertificateSerialNumber  ::=  INTEGER

Validity ::= SEQUENCE {
     notBefore      Time,
     notAfter       Time  }

Time ::= CHOICE {
     utcTime        UTCTime,
     generalTime    GeneralizedTime }

UniqueIdentifier  ::=  BIT STRING
SubjectPublicKeyInfo  ::=  SEQUENCE  {
     algorithm            AlgorithmIdentifier,
     subjectPublicKey     BIT STRING  }

Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension

Extension  ::=  SEQUENCE  {
     extnID      OBJECT IDENTIFIER,
     critical    BOOLEAN DEFAULT FALSE,
     extnValue   OCTET STRING  }

-- CRL structures

CertificateList  ::=  SEQUENCE  {
     tbsCertList          TBSCertList,
     signatureAlgorithm   AlgorithmIdentifier,
     signature            BIT STRING  }

TBSCertList  ::=  SEQUENCE  {
     version                 Version OPTIONAL,
                                  -- if present, MUST be v2
     signature               AlgorithmIdentifier,
     issuer                  Name,
     thisUpdate              Time,
     nextUpdate              Time OPTIONAL,
     revokedCertificates     SEQUENCE OF SEQUENCE  {
          userCertificate         CertificateSerialNumber,
          revocationDate          Time,
          crlEntryExtensions      Extensions OPTIONAL
                                         -- if present, MUST be v2
                               }  OPTIONAL,
     crlExtensions           [0] Extensions OPTIONAL }
                                         -- if present, MUST be v2

-- Version, Time, CertificateSerialNumber, and Extensions were
-- defined earlier for use in the certificate structure

AlgorithmIdentifier  ::=  SEQUENCE  {
     algorithm               OBJECT IDENTIFIER,
     parameters              ANY DEFINED BY algorithm OPTIONAL  }
                                -- contains a value of the type
                                -- registered for use with the
                                -- algorithm object identifier value

-- X.400 address syntax starts here
ORAddress ::= SEQUENCE {
   built-in-standard-attributes BuiltInStandardAttributes,
   built-in-domain-defined-attributes
                   BuiltInDomainDefinedAttributes OPTIONAL,
   -- see also teletex-domain-defined-attributes
   extension-attributes ExtensionAttributes OPTIONAL }

-- Built-in Standard Attributes

BuiltInStandardAttributes ::= SEQUENCE {
   country-name                  CountryName OPTIONAL,
   administration-domain-name    AdministrationDomainName OPTIONAL,
   network-address           [0] IMPLICIT NetworkAddress OPTIONAL,
     -- see also extended-network-address
   terminal-identifier       [1] IMPLICIT TerminalIdentifier OPTIONAL,
   private-domain-name       [2] PrivateDomainName OPTIONAL,
   organization-name         [3] IMPLICIT OrganizationName OPTIONAL,
     -- see also teletex-organization-name
   numeric-user-identifier   [4] IMPLICIT NumericUserIdentifier
                                 OPTIONAL,
   personal-name             [5] IMPLICIT PersonalName OPTIONAL,
     -- see also teletex-personal-name
   organizational-unit-names [6] IMPLICIT OrganizationalUnitNames
                                 OPTIONAL }
     -- see also teletex-organizational-unit-names

CountryName ::= [APPLICATION 1] CHOICE {
   x121-dcc-code         NumericString
                           (SIZE (ub-country-name-numeric-length)),
   iso-3166-alpha2-code  PrintableString
                           (SIZE (ub-country-name-alpha-length)) }

AdministrationDomainName ::= [APPLICATION 2] CHOICE {
   numeric   NumericString   (SIZE (0..ub-domain-name-length)),
   printable PrintableString (SIZE (0..ub-domain-name-length)) }

NetworkAddress ::= X121Address  -- see also extended-network-address

X121Address ::= NumericString (SIZE (1..ub-x121-address-length))

TerminalIdentifier ::= PrintableString (SIZE
(1..ub-terminal-id-length))

PrivateDomainName ::= CHOICE {
   numeric   NumericString   (SIZE (1..ub-domain-name-length)),
   printable PrintableString (SIZE (1..ub-domain-name-length)) }

OrganizationName ::= PrintableString
                            (SIZE (1..ub-organization-name-length))
  -- see also teletex-organization-name

NumericUserIdentifier ::= NumericString
                            (SIZE (1..ub-numeric-user-id-length))

PersonalName ::= SET {
   surname     [0] IMPLICIT PrintableString
                    (SIZE (1..ub-surname-length)),
   given-name  [1] IMPLICIT PrintableString
                    (SIZE (1..ub-given-name-length)) OPTIONAL,
   initials    [2] IMPLICIT PrintableString
                    (SIZE (1..ub-initials-length)) OPTIONAL,
   generation-qualifier [3] IMPLICIT PrintableString
                    (SIZE (1..ub-generation-qualifier-length))
                    OPTIONAL }
  -- see also teletex-personal-name

OrganizationalUnitNames ::= SEQUENCE SIZE (1..ub-organizational-units)
                             OF OrganizationalUnitName
  -- see also teletex-organizational-unit-names

OrganizationalUnitName ::= PrintableString (SIZE
                    (1..ub-organizational-unit-name-length))

-- Built-in Domain-defined Attributes
BuiltInDomainDefinedAttributes ::= SEQUENCE SIZE
                    (1..ub-domain-defined-attributes) OF
                    BuiltInDomainDefinedAttribute

BuiltInDomainDefinedAttribute ::= SEQUENCE {
   type PrintableString (SIZE
                   (1..ub-domain-defined-attribute-type-length)),
   value PrintableString (SIZE
                   (1..ub-domain-defined-attribute-value-length)) }

-- Extension Attributes

ExtensionAttributes ::= SET SIZE (1..ub-extension-attributes) OF
               ExtensionAttribute

ExtensionAttribute ::=  SEQUENCE {
   extension-attribute-type [0] IMPLICIT INTEGER
                   (0..ub-extension-attributes),
   extension-attribute-value [1]
                   ANY DEFINED BY extension-attribute-type }

-- Extension types and attribute values

common-name INTEGER ::= 1

CommonName ::= PrintableString (SIZE (1..ub-common-name-length))

teletex-common-name INTEGER ::= 2

TeletexCommonName ::= TeletexString (SIZE (1..ub-common-name-length))

teletex-organization-name INTEGER ::= 3

TeletexOrganizationName ::=
                TeletexString (SIZE (1..ub-organization-name-length))

teletex-personal-name INTEGER ::= 4

TeletexPersonalName ::= SET {
   surname     [0] IMPLICIT TeletexString
                    (SIZE (1..ub-surname-length)),
   given-name  [1] IMPLICIT TeletexString
                    (SIZE (1..ub-given-name-length)) OPTIONAL,
   initials    [2] IMPLICIT TeletexString
                    (SIZE (1..ub-initials-length)) OPTIONAL,
   generation-qualifier [3] IMPLICIT TeletexString
                    (SIZE (1..ub-generation-qualifier-length))
                    OPTIONAL }

teletex-organizational-unit-names INTEGER ::= 5

TeletexOrganizationalUnitNames ::= SEQUENCE SIZE
      (1..ub-organizational-units) OF TeletexOrganizationalUnitName

TeletexOrganizationalUnitName ::= TeletexString
                  (SIZE (1..ub-organizational-unit-name-length))

pds-name INTEGER ::= 7

PDSName ::= PrintableString (SIZE (1..ub-pds-name-length))

physical-delivery-country-name INTEGER ::= 8

PhysicalDeliveryCountryName ::= CHOICE {
   x121-dcc-code NumericString (SIZE
(ub-country-name-numeric-length)),
   iso-3166-alpha2-code PrintableString
                  (SIZE (ub-country-name-alpha-length)) }

postal-code INTEGER ::= 9

PostalCode ::= CHOICE {
   numeric-code NumericString (SIZE (1..ub-postal-code-length)),
   printable-code PrintableString (SIZE (1..ub-postal-code-length)) }

physical-delivery-office-name INTEGER ::= 10

PhysicalDeliveryOfficeName ::= PDSParameter

physical-delivery-office-number INTEGER ::= 11

PhysicalDeliveryOfficeNumber ::= PDSParameter

extension-OR-address-components INTEGER ::= 12

ExtensionORAddressComponents ::= PDSParameter

physical-delivery-personal-name INTEGER ::= 13

PhysicalDeliveryPersonalName ::= PDSParameter

physical-delivery-organization-name INTEGER ::= 14

PhysicalDeliveryOrganizationName ::= PDSParameter

extension-physical-delivery-address-components INTEGER ::= 15

ExtensionPhysicalDeliveryAddressComponents ::= PDSParameter

unformatted-postal-address INTEGER ::= 16

UnformattedPostalAddress ::= SET {
   printable-address SEQUENCE SIZE (1..ub-pds-physical-address-lines)
         OF PrintableString (SIZE (1..ub-pds-parameter-length))
         OPTIONAL,
   teletex-string TeletexString
         (SIZE (1..ub-unformatted-address-length)) OPTIONAL }

street-address INTEGER ::= 17

StreetAddress ::= PDSParameter

post-office-box-address INTEGER ::= 18

PostOfficeBoxAddress ::= PDSParameter

poste-restante-address INTEGER ::= 19
PosteRestanteAddress ::= PDSParameter

unique-postal-name INTEGER ::= 20

UniquePostalName ::= PDSParameter

local-postal-attributes INTEGER ::= 21

LocalPostalAttributes ::= PDSParameter

PDSParameter ::= SET {
   printable-string PrintableString
                (SIZE(1..ub-pds-parameter-length)) OPTIONAL,
   teletex-string TeletexString
                (SIZE(1..ub-pds-parameter-length)) OPTIONAL }

extended-network-address INTEGER ::= 22

ExtendedNetworkAddress ::= CHOICE {
   e163-4-address SEQUENCE {
      number      [0] IMPLICIT NumericString
                       (SIZE (1..ub-e163-4-number-length)),
      sub-address [1] IMPLICIT NumericString
                       (SIZE (1..ub-e163-4-sub-address-length))
                       OPTIONAL },
   psap-address [0] IMPLICIT PresentationAddress }

PresentationAddress ::= SEQUENCE {
    pSelector     [0] EXPLICIT OCTET STRING OPTIONAL,
    sSelector     [1] EXPLICIT OCTET STRING OPTIONAL,
    tSelector     [2] EXPLICIT OCTET STRING OPTIONAL,
    nAddresses    [3] EXPLICIT SET SIZE (1..MAX) OF OCTET STRING }

terminal-type  INTEGER ::= 23

TerminalType ::= INTEGER {
   telex (3),
   teletex (4),
   g3-facsimile (5),
   g4-facsimile (6),
   ia5-terminal (7),
   videotex (8) } (0..ub-integer-options)

-- Extension Domain-defined Attributes

teletex-domain-defined-attributes INTEGER ::= 6
TeletexDomainDefinedAttributes ::= SEQUENCE SIZE
   (1..ub-domain-defined-attributes) OF TeletexDomainDefinedAttribute

TeletexDomainDefinedAttribute ::= SEQUENCE {
        type TeletexString
               (SIZE (1..ub-domain-defined-attribute-type-length)),
        value TeletexString
               (SIZE (1..ub-domain-defined-attribute-value-length)) }

--  specifications of Upper Bounds MUST be regarded as mandatory
--  from Annex B of ITU-T X.411 Reference Definition of MTS Parameter
--  Upper Bounds

-- Upper Bounds
ub-name INTEGER ::= 32768
ub-common-name INTEGER ::= 64
ub-locality-name INTEGER ::= 128
ub-state-name INTEGER ::= 128
ub-organization-name INTEGER ::= 64
ub-organizational-unit-name INTEGER ::= 64
ub-title INTEGER ::= 64
ub-serial-number INTEGER ::= 64
ub-match INTEGER ::= 128
ub-emailaddress-length INTEGER ::= 128
ub-common-name-length INTEGER ::= 64
ub-country-name-alpha-length INTEGER ::= 2
ub-country-name-numeric-length INTEGER ::= 3
ub-domain-defined-attributes INTEGER ::= 4
ub-domain-defined-attribute-type-length INTEGER ::= 8
ub-domain-defined-attribute-value-length INTEGER ::= 128
ub-domain-name-length INTEGER ::= 16
ub-extension-attributes INTEGER ::= 256
ub-e163-4-number-length INTEGER ::= 15
ub-e163-4-sub-address-length INTEGER ::= 40
ub-generation-qualifier-length INTEGER ::= 3
ub-given-name-length INTEGER ::= 16
ub-initials-length INTEGER ::= 5
ub-integer-options INTEGER ::= 256
ub-numeric-user-id-length INTEGER ::= 32
ub-organization-name-length INTEGER ::= 64
ub-organizational-unit-name-length INTEGER ::= 32
ub-organizational-units INTEGER ::= 4
ub-pds-name-length INTEGER ::= 16
ub-pds-parameter-length INTEGER ::= 30
ub-pds-physical-address-lines INTEGER ::= 6
ub-postal-code-length INTEGER ::= 16
ub-pseudonym INTEGER ::= 128
ub-surname-length INTEGER ::= 40
ub-terminal-id-length INTEGER ::= 24
ub-unformatted-address-length INTEGER ::= 180
ub-x121-address-length INTEGER ::= 16

-- Note - upper bounds on string types, such as TeletexString, are
-- measured in characters.  Excepting PrintableString or IA5String, a
-- significantly greater number of octets will be required to hold
-- such a value.  As a minimum, 16 octets, or twice the specified
-- upper bound, whichever is the larger, should be allowed for
-- TeletexString.  For UTF8String or UniversalString at least four
-- times the upper bound should be allowed.

END

A.2 Implicitly Tagged Module, 1988 Syntax ✨

Okay bestie, this is where the module flips to IMPLICIT TAGS 🎀 so the tagging vibe changes but the definitions stay exactly the same. 💅

PKIX1Implicit88 { iso(1) identified-organization(3) dod(6) internet(1)
  security(5) mechanisms(5) pkix(7) id-mod(0) id-pkix1-implicit(19) }

DEFINITIONS IMPLICIT TAGS ::=

BEGIN

-- EXPORTS ALL --

IMPORTS
      id-pe, id-kp, id-qt-unotice, id-qt-cps,
      -- delete following line if "new" types are supported --
      BMPString, UTF8String,  -- end "new" types --
      ORAddress, Name, RelativeDistinguishedName,
      CertificateSerialNumber, Attribute, DirectoryString
      FROM PKIX1Explicit88 { iso(1) identified-organization(3)
            dod(6) internet(1) security(5) mechanisms(5) pkix(7)
            id-mod(0) id-pkix1-explicit(18) };


-- ISO arc for standard certificate and CRL extensions

id-ce OBJECT IDENTIFIER  ::=  {joint-iso-ccitt(2) ds(5) 29}

-- authority key identifier OID and syntax

id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }
AuthorityKeyIdentifier ::= SEQUENCE {
    keyIdentifier             [0] KeyIdentifier            OPTIONAL,
    authorityCertIssuer       [1] GeneralNames             OPTIONAL,
    authorityCertSerialNumber [2] CertificateSerialNumber  OPTIONAL }
    -- authorityCertIssuer and authorityCertSerialNumber MUST both
    -- be present or both be absent

KeyIdentifier ::= OCTET STRING

-- subject key identifier OID and syntax

id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 14 }

SubjectKeyIdentifier ::= KeyIdentifier

-- key usage extension OID and syntax

id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }

KeyUsage ::= BIT STRING {
     digitalSignature        (0),
     nonRepudiation          (1),
     keyEncipherment         (2),
     dataEncipherment        (3),
     keyAgreement            (4),
     keyCertSign             (5),
     cRLSign                 (6),
     encipherOnly            (7),
     decipherOnly            (8) }

-- private key usage period extension OID and syntax

id-ce-privateKeyUsagePeriod OBJECT IDENTIFIER ::=  { id-ce 16 }

PrivateKeyUsagePeriod ::= SEQUENCE {
     notBefore       [0]     GeneralizedTime OPTIONAL,
     notAfter        [1]     GeneralizedTime OPTIONAL }
     -- either notBefore or notAfter MUST be present

-- certificate policies extension OID and syntax

id-ce-certificatePolicies OBJECT IDENTIFIER ::=  { id-ce 32 }

anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 }

CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation

PolicyInformation ::= SEQUENCE {

     policyIdentifier   CertPolicyId,
     policyQualifiers   SEQUENCE SIZE (1..MAX) OF
             PolicyQualifierInfo OPTIONAL }

CertPolicyId ::= OBJECT IDENTIFIER

PolicyQualifierInfo ::= SEQUENCE {
       policyQualifierId  PolicyQualifierId,
       qualifier        ANY DEFINED BY policyQualifierId }

-- Implementations that recognize additional policy qualifiers MUST
-- augment the following definition for PolicyQualifierId

PolicyQualifierId ::=
    OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )

-- CPS pointer qualifier

CPSuri ::= IA5String

-- user notice qualifier

UserNotice ::= SEQUENCE {
     noticeRef        NoticeReference OPTIONAL,
     explicitText     DisplayText OPTIONAL}

NoticeReference ::= SEQUENCE {
     organization     DisplayText,
     noticeNumbers    SEQUENCE OF INTEGER }

DisplayText ::= CHOICE {
     ia5String        IA5String      (SIZE (1..200)),
     visibleString    VisibleString  (SIZE (1..200)),
     bmpString        BMPString      (SIZE (1..200)),
     utf8String       UTF8String     (SIZE (1..200)) }

-- policy mapping extension OID and syntax

id-ce-policyMappings OBJECT IDENTIFIER ::=  { id-ce 33 }

PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
     issuerDomainPolicy      CertPolicyId,
     subjectDomainPolicy     CertPolicyId }

-- subject alternative name extension OID and syntax

id-ce-subjectAltName OBJECT IDENTIFIER ::=  { id-ce 17 }
SubjectAltName ::= GeneralNames

GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName

GeneralName ::= CHOICE {
     otherName                       [0]     AnotherName,
     rfc822Name                      [1]     IA5String,
     dNSName                         [2]     IA5String,
     x400Address                     [3]     ORAddress,
     directoryName                   [4]     Name,
     ediPartyName                    [5]     EDIPartyName,
     uniformResourceIdentifier       [6]     IA5String,
     iPAddress                       [7]     OCTET STRING,
     registeredID                    [8]     OBJECT IDENTIFIER }

-- AnotherName replaces OTHER-NAME ::= TYPE-IDENTIFIER, as
-- TYPE-IDENTIFIER is not supported in the '88 ASN.1 syntax

okay bestie, the ASN.1 module is giving main character energy now 💅✨

AnotherName ::= SEQUENCE {
     type-id    OBJECT IDENTIFIER,
     value      [0] EXPLICIT ANY DEFINED BY type-id }

EDIPartyName ::= SEQUENCE {
     nameAssigner            [0]     DirectoryString OPTIONAL,
     partyName               [1]     DirectoryString }

-- issuer alternative name extension OID and syntax

id-ce-issuerAltName OBJECT IDENTIFIER ::=  { id-ce 18 }

IssuerAltName ::= GeneralNames

id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::=  { id-ce 9 }

SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF Attribute

-- basic constraints extension OID and syntax

id-ce-basicConstraints OBJECT IDENTIFIER ::=  { id-ce 19 }

BasicConstraints ::= SEQUENCE {
     cA                      BOOLEAN DEFAULT FALSE,
     pathLenConstraint       INTEGER (0..MAX) OPTIONAL }

-- name constraints extension OID and syntax

id-ce-nameConstraints OBJECT IDENTIFIER ::=  { id-ce 30 }
NameConstraints ::= SEQUENCE {
     permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
     excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }

GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree

GeneralSubtree ::= SEQUENCE {
     base                    GeneralName,
     minimum         [0]     BaseDistance DEFAULT 0,
     maximum         [1]     BaseDistance OPTIONAL }

BaseDistance ::= INTEGER (0..MAX)

-- policy constraints extension OID and syntax

id-ce-policyConstraints OBJECT IDENTIFIER ::=  { id-ce 36 }

PolicyConstraints ::= SEQUENCE {
     requireExplicitPolicy           [0] SkipCerts OPTIONAL,
     inhibitPolicyMapping            [1] SkipCerts OPTIONAL }

SkipCerts ::= INTEGER (0..MAX)

-- CRL distribution points extension OID and syntax

id-ce-cRLDistributionPoints     OBJECT IDENTIFIER  ::=  {id-ce 31}

CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint

DistributionPoint ::= SEQUENCE {
     distributionPoint       [0]     DistributionPointName OPTIONAL,
     reasons                 [1]     ReasonFlags OPTIONAL,
     cRLIssuer               [2]     GeneralNames OPTIONAL }

DistributionPointName ::= CHOICE {
     fullName                [0]     GeneralNames,
     nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }

ReasonFlags ::= BIT STRING {
     unused                  (0),
     keyCompromise           (1),
     cACompromise            (2),
     affiliationChanged      (3),
     superseded              (4),
     cessationOfOperation    (5),
     certificateHold         (6),
     privilegeWithdrawn      (7),
     aACompromise            (8) }

-- extended key usage extension OID and syntax

id-ce-extKeyUsage OBJECT IDENTIFIER ::= {id-ce 37}

ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId


KeyPurposeId ::= OBJECT IDENTIFIER

-- permit unspecified key uses

anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 }

-- extended key purpose OIDs

id-kp-serverAuth             OBJECT IDENTIFIER ::= { id-kp 1 }
id-kp-clientAuth             OBJECT IDENTIFIER ::= { id-kp 2 }
id-kp-codeSigning            OBJECT IDENTIFIER ::= { id-kp 3 }
id-kp-emailProtection        OBJECT IDENTIFIER ::= { id-kp 4 }
id-kp-timeStamping           OBJECT IDENTIFIER ::= { id-kp 8 }
id-kp-OCSPSigning            OBJECT IDENTIFIER ::= { id-kp 9 }

-- inhibit any policy OID and syntax

id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::=  { id-ce 54 }

InhibitAnyPolicy ::= SkipCerts

-- freshest (delta)CRL extension OID and syntax

id-ce-freshestCRL OBJECT IDENTIFIER ::=  { id-ce 46 }

FreshestCRL ::= CRLDistributionPoints

-- authority info access

id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }

AuthorityInfoAccessSyntax  ::=
        SEQUENCE SIZE (1..MAX) OF AccessDescription

AccessDescription  ::=  SEQUENCE {
        accessMethod          OBJECT IDENTIFIER,
        accessLocation        GeneralName  }

-- subject info access

id-pe-subjectInfoAccess OBJECT IDENTIFIER ::= { id-pe 11 }
SubjectInfoAccessSyntax  ::=
        SEQUENCE SIZE (1..MAX) OF AccessDescription

-- CRL number extension OID and syntax

id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 }

CRLNumber ::= INTEGER (0..MAX)

-- issuing distribution point extension OID and syntax

id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 }

IssuingDistributionPoint ::= SEQUENCE {
     distributionPoint          [0] DistributionPointName OPTIONAL,
     onlyContainsUserCerts      [1] BOOLEAN DEFAULT FALSE,
     onlyContainsCACerts        [2] BOOLEAN DEFAULT FALSE,
     onlySomeReasons            [3] ReasonFlags OPTIONAL,
     indirectCRL                [4] BOOLEAN DEFAULT FALSE,
     onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }

id-ce-deltaCRLIndicator OBJECT IDENTIFIER ::= { id-ce 27 }

BaseCRLNumber ::= CRLNumber

-- CRL reasons extension OID and syntax

id-ce-cRLReasons OBJECT IDENTIFIER ::= { id-ce 21 }

CRLReason ::= ENUMERATED {
     unspecified             (0),
     keyCompromise           (1),
     cACompromise            (2),
     affiliationChanged      (3),
     superseded              (4),
     cessationOfOperation    (5),
     certificateHold         (6),
     removeFromCRL           (8),
     privilegeWithdrawn      (9),
     aACompromise           (10) }

-- certificate issuer CRL entry extension OID and syntax

id-ce-certificateIssuer OBJECT IDENTIFIER ::= { id-ce 29 }

CertificateIssuer ::= GeneralNames

-- hold instruction extension OID and syntax
id-ce-holdInstructionCode OBJECT IDENTIFIER ::= { id-ce 23 }

HoldInstructionCode ::= OBJECT IDENTIFIER

-- ANSI x9 holdinstructions

-- ANSI x9 arc holdinstruction arc

holdInstruction OBJECT IDENTIFIER ::=
          {joint-iso-itu-t(2) member-body(2) us(840) x9cm(10040) 2}

-- ANSI X9 holdinstructions referenced by this standard

id-holdinstruction-none OBJECT IDENTIFIER  ::=
                {holdInstruction 1} -- deprecated

id-holdinstruction-callissuer OBJECT IDENTIFIER ::=
                {holdInstruction 2}

id-holdinstruction-reject OBJECT IDENTIFIER ::=
                {holdInstruction 3}

-- invalidity date CRL entry extension OID and syntax

id-ce-invalidityDate OBJECT IDENTIFIER ::= { id-ce 24 }

InvalidityDate ::=  GeneralizedTime

END

Appendix B. ASN.1 Notes ✨

okay bestie, this is the appendix where the ASN.1 gremlins live 🧚 so get comfy because there are a LOT of little rules here 💅

CAs MUST force the serialNumber to be a non-negative integer 🎀 which means the sign bit in the DER encoding of the INTEGER value MUST be zero. If you need to make that happen, just add a leading (leftmost) 00'H octet. This kills a potential ambiguity when mapping a string of octets to an integer value, so nobody gets confused 🙈

As we mentioned in section 4.1.2.2, serial numbers can be expected to contain long integers 🔢 so certificate users MUST be able to handle serialNumber values up to 20 octets in length. Conformant CAs MUST NOT use serialNumber values longer than 20 octets. no exceptions, periodt 💅

As noted in section 5.2.3, CRL numbers are also going to be long integers 🌸 so CRL validators MUST be able to handle cRLNumber values up to 20 octets in length. Conformant CRL issuers MUST NOT use cRLNumber values longer than 20 octets. same energy, different list 💜

The construct SEQUENCE SIZE (1..MAX) OF shows up in a bunch of ASN.1 constructs ✨ A valid ASN.1 sequence can have zero or more entries, but the SIZE (1..MAX) bit forces it to have at least one entry. The MAX just means the upper bound is unspecified, and implementations are free to pick an upper bound that fits their environment 🦋

The construct positiveInt ::= INTEGER (0..MAX) defines positiveInt as a subtype of INTEGER that only holds integers greater than or equal to zero 🍓 The upper bound is unspecified, so implementations are free to choose one that suits their environment 🌈

The character string type PrintableString is pretty basic 🥺 It supports the lower case letters 'a' through 'z', the upper case letters 'A' through 'Z', the digits '0' through '9', and eleven special characters: ' = ( ) + , - . / : ? and space.

Implementers, pls note 📣 the at sign ('@') and the underscore ('_') are NOT supported by PrintableString, and honestly that's a problem because these characters show up in internet addresses constantly 😭 Such addresses MUST be encoded using an ASN.1 type that supports them. They're usually encoded as IA5String, either in the emailAddress attribute inside a distinguished name or in the rfc822Name field of GeneralName. Conforming implementations MUST NOT encode strings that include either the at sign or underscore as PrintableString. big no no 🙅‍♀️

The character string type TeletexString is a superset of PrintableString 💖 It supports a fairly standard (ASCII-like) Latin character set, Latin characters with non-spacing accents, and Japanese characters. the range is giving world tour 🌍

Named bit lists are BIT STRINGs where the values have been given names 🎀 This spec uses named bit lists in the definitions for the key usage, CRL distribution points and freshest CRL certificate extensions, plus the freshest CRL and issuing distribution point CRL extensions. When you DER encode a named bit list, trailing zeroes MUST be omitted. So the encoded value ends with the last named bit that is set to one. clean and minimal ✨

The character string type UniversalString supports any of the characters allowed by ISO 10646-1 [ISO 10646] 🌏 ISO 10646-1 is the Universal multiple-octet coded Character Set (UCS). It specifies the architecture and the "basic multilingual plane", which is a huge standard character set that includes all the major world character standards. it's literally everything 😭

The character string type UTF8String was introduced in the 1997 version of ASN.1 💜 It was added to the list of choices for DirectoryString in the 2001 version of X.520 [X.520]. UTF8String is a universal type with tag number 12. Its content was defined by RFC 2044 [RFC 2044] and then updated in RFC 2279 [RFC 2279]. iconic glow-up arc 🦋

In anticipation of those changes, and in line with IETF Best Practices codified in RFC 2277 [RFC 2277], IETF Policy on Character Sets and Languages, this document includes UTF8String as a choice in DirectoryString and in the CPS qualifier extensions 🫶 so it's already ready for the party 🎉

Implementers should note that the DER encoding of SET OF values requires ordering of the encodings of the values 🧠 this one shows up especially with distinguished names, so keep an eye on it 👀

Implementers should also note that in the DER encoding of SET or SEQUENCE components, a component whose value is the DEFAULT gets omitted from the encoded certificate or CRL 🙈 For example, a BasicConstraints extension whose cA value is FALSE would leave the cA boolean out of the encoded certificate. the default is literally invisible, it's giving minimalism ✨

Object Identifiers (OIDs) are used all over this spec to identify certificate policies, public key and signature algorithms, certificate extensions, and more 🦋 There's no maximum size for OIDs, but this spec mandates support for OIDs whose arc elements are less than 2^28, meaning they MUST be between 0 and 268,435,455, inclusive. That lets each arc element fit into a single 32 bit word 🧚 Implementations MUST also support OIDs where the dotted decimal string representation (see [RFC 2252], section 4.1) can be up to 100 bytes (inclusive). Implementations MUST be able to handle OIDs with up to 20 elements (inclusive). CAs SHOULD NOT issue certificates that contain OIDs exceeding these requirements. Likewise, CRL issuers SHOULD NOT issue CRLs that contain OIDs exceeding these requirements. keep the OIDs chill, bestie 🌸

Implementors are warned that the X.500 standards community has developed a series of extensibility rules 🚨 These rules decide when an ASN.1 definition can be changed without assigning a new object identifier (OID). For example, at least two extension definitions in RFC 2459 [RFC 2459], the predecessor to this profile document, have different ASN.1 definitions in this specification but still use the same OID 💀 So if unknown elements show up inside an extension, and that extension is not marked critical, those unknown elements ought to be ignored, like so:

  • (a) ignore all unknown bit name assignments within a bit string;
  • (b) ignore all unknown named numbers in an ENUMERATED type or INTEGER type that is being used in the enumerated style, provided the number occurs as an optional element of a SET or SEQUENCE; and
  • (c) ignore all unknown elements in SETs, at the end of SEQUENCEs, or in CHOICEs where the CHOICE is itself an optional element of a SET or SEQUENCE.

BUT, if an extension containing unexpected values IS marked critical, the implementation MUST reject the certificate or CRL containing the unrecognized extension. no mercy for critical stuff 🔥 the implementation MUST reject it, full stop 🚫


Appendix C. Examples 🎀

okay so this section has four examples: three certificates and a CRL 🦋 The first two certificates and the CRL make up a minimal certification path, so they go together like peanut butter and jelly 🥪

Section C.1 has an annotated hex dump of a "self-signed" certificate issued by a CA whose distinguished name is cn=us,o=gov,ou=nist ✨ That certificate has a DSA public key with parameters, and it's signed by the matching DSA private key.

Section C.2 has an annotated hex dump of an end entity certificate 💜 It contains a DSA public key and is signed by the private key that goes with the "self-signed" certificate from section C.1.

Section C.3 has a dump of an end entity certificate with an RSA public key, signed with RSA and MD5 🙈 This one is NOT part of the minimal certification path, so it's kind of the side character 🎭

Section C.4 has an annotated hex dump of a CRL 🌈 The CRL is issued by the CA whose distinguished name is cn=us,o=gov,ou=nist, and its list of revoked certificates includes the end entity certificate from C.2. plot twist, it's revoked 😭

The certificates were processed using Peter Gutman's dumpasn1 utility to generate the output 🧚 You can find the source for dumpasn1 at http://www.cs.auckland.ac.nz/~pgut001/dumpasn1.c, and the binaries for the certificates and CRLs are at http://csrc.nist.gov/pki/pkixtools 🍓

C.1. Certificate ✨

okay so this section is literally a certificate you can read like a little receipt 🧾💅 it's a hex dump of a 699 byte version 3 certificate, and every line is annotated so you can follow along. the cert holds:

  • (a) a serial number of 23 (17 in hex) 🔢
  • (b) a signature made with DSA and the SHA-1 hash algorithm 🔐
  • (c) an issuer's distinguished name of OU=NIST; O=gov; C=US 🏛️
  • (d) a subject's distinguished name that's the same, OU=NIST; O=gov; C=US 🪞
  • (e) an issue date of June 30, 1997 and an expiry of December 31, 1997 📅
  • (f) a 1024 bit DSA public key, with its parameters 🗝️
  • (g) a subject key identifier extension made with method (1) of section 4.2.1.2 🆔
  • (h) a CA certificate, which you can tell from the basic constraints extension 👑

the issuer and the subject are the same name, so this is self-issued energy 🫶 the dump below is the whole thing, byte by byte, with the tag, length and value for each piece 🦋

  0 30  699: SEQUENCE {
  4 30  635:   SEQUENCE {
  8 A0    3:     [0] {
 10 02    1:       INTEGER 2
          :       }
 13 02    1:     INTEGER 17
 16 30    9:     SEQUENCE {
 18 06    7:       OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
          :       }
 27 30   42:     SEQUENCE {
 29 31   11:       SET {
 31 30    9:         SEQUENCE {
 33 06    3:           OBJECT IDENTIFIER countryName (2 5 4 6)
 38 13    2:           PrintableString 'US'
          :           }
          :         }
 42 31   12:       SET {
 44 30   10:         SEQUENCE {
 46 06    3:           OBJECT IDENTIFIER organizationName (2 5 4 10)
 51 13    3:           PrintableString 'gov'
          :           }
          :         }
 56 31   13:       SET {
 58 30   11:         SEQUENCE {
 60 06    3:           OBJECT IDENTIFIER
          :             organizationalUnitName (2 5 4 11)
 65 13    4:           PrintableString 'NIST'
           :           }
           :         }
           :       }
 71 30   30:     SEQUENCE {
 73 17   13:       UTCTime '970630000000Z'
 88 17   13:       UTCTime '971231000000Z'
           :       }
103 30   42:     SEQUENCE {
105 31   11:       SET {
107 30    9:         SEQUENCE {
109 06    3:           OBJECT IDENTIFIER countryName (2 5 4 6)
114 13    2:           PrintableString 'US'
           :           }
           :         }
118 31   12:       SET {
120 30   10:         SEQUENCE {
122 06    3:           OBJECT IDENTIFIER organizationName (2 5 4 10)
127 13    3:           PrintableString 'gov'
           :           }
           :         }
132 31   13:       SET {
134 30   11:         SEQUENCE {
136 06    3:           OBJECT IDENTIFIER
           :             organizationalUnitName (2 5 4 11)
141 13    4:           PrintableString 'NIST'
           :           }
           :         }
           :       }
147 30  440:     SEQUENCE {
151 30  300:       SEQUENCE {
155 06    7:         OBJECT IDENTIFIER dsa (1 2 840 10040 4 1)
164 30  287:         SEQUENCE {
168 02  129:           INTEGER
           :             00 B6 8B 0F 94 2B 9A CE A5 25 C6 F2 ED FC
           :             FB 95 32 AC 01 12 33 B9 E0 1C AD 90 9B BC
           :             48 54 9E F3 94 77 3C 2C 71 35 55 E6 FE 4F
           :             22 CB D5 D8 3E 89 93 33 4D FC BD 4F 41 64
           :             3E A2 98 70 EC 31 B4 50 DE EB F1 98 28 0A
           :             C9 3E 44 B3 FD 22 97 96 83 D0 18 A3 E3 BD
           :             35 5B FF EE A3 21 72 6A 7B 96 DA B9 3F 1E
           :             5A 90 AF 24 D6 20 F0 0D 21 A7 D4 02 B9 1A
           :             FC AC 21 FB 9E 94 9E 4B 42 45 9E 6A B2 48
           :             63 FE 43
300 02   21:           INTEGER
           :             00 B2 0D B0 B1 01 DF 0C 66 24 FC 13 92 BA
           :             55 F7 7D 57 74 81 E5
323 02  129:           INTEGER
           :             00 9A BF 46 B1 F5 3F 44 3D C9 A5 65 FB 91
           :             C0 8E 47 F1 0A C3 01 47 C2 44 42 36 A9 92
           :             81 DE 57 C5 E0 68 86 58 00 7B 1F F9 9B 77
           :             A1 C5 10 A5 80 91 78 51 51 3C F6 FC FC CC
           :             46 C6 81 78 92 84 3D F4 93 3D 0C 38 7E 1A
           :             5B 99 4E AB 14 64 F6 0C 21 22 4E 28 08 9C
           :             92 B9 66 9F 40 E8 95 F6 D5 31 2A EF 39 A2
           :             62 C7 B2 6D 9E 58 C4 3A A8 11 81 84 6D AF
           :             F8 B4 19 B4 C2 11 AE D0 22 3B AA 20 7F EE
           :             1E 57 18
           :           }
           :         }
455 03  133:       BIT STRING 0 unused bits, encapsulates {
459 02  129:           INTEGER
           :             00 B5 9E 1F 49 04 47 D1 DB F5 3A DD CA 04
           :             75 E8 DD 75 F6 9B 8A B1 97 D6 59 69 82 D3
           :             03 4D FD 3B 36 5F 4A F2 D1 4E C1 07 F5 D1
           :             2A D3 78 77 63 56 EA 96 61 4D 42 0B 7A 1D
           :             FB AB 91 A4 CE DE EF 77 C8 E5 EF 20 AE A6
           :             28 48 AF BE 69 C3 6A A5 30 F2 C2 B9 D9 82
           :             2B 7D D9 C4 84 1F DE 0D E8 54 D7 1B 99 2E
           :             B3 D0 88 F6 D6 63 9B A7 E2 0E 82 D4 3B 8A
           :             68 1B 06 56 31 59 0B 49 EB 99 A5 D5 81 41
           :             7B C9 55
           :           }
           :       }
591 A3   50:     [3] {
593 30   48:       SEQUENCE {
595 30   29:         SEQUENCE {
597 06    3:           OBJECT IDENTIFIER
           :             subjectKeyIdentifier (2 5 29 14)
602 04   22:           OCTET STRING, encapsulates {
604 04   20:               OCTET STRING
           :                 86 CA A5 22 81 62 EF AD 0A 89 BC AD 72 41
           :                 2C 29 49 F4 86 56
           :               }
           :           }
626 30   15:         SEQUENCE {
628 06    3:           OBJECT IDENTIFIER basicConstraints (2 5 29 19)
633 01    1:           BOOLEAN TRUE
636 04    5:           OCTET STRING, encapsulates {
638 30    3:               SEQUENCE {
640 01    1:                 BOOLEAN TRUE
           :                 }
           :               }
           :           }
           :         }
           :       }
           :     }
643 30    9:   SEQUENCE {
645 06    7:     OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
           :     }
654 03   47:   BIT STRING 0 unused bits, encapsulates {
657 30   44:       SEQUENCE {
659 02   20:         INTEGER
           :           43 1B CF 29 25 45 C0 4E 52 E7 7D D6 FC B1
           :           66 4C 83 CF 2D 77
681 02   20:         INTEGER

           :           0B 5B 9A 24 11 98 E8 F3 86 90 04 F6 08 A9
           :           E1 8D A5 CC 3A D4
           :         }
           :       }
           :   }

C.2. Certificate ✨

okay bestie, this one is a whole annotated hex dump of a 730 byte version 3 certificate 🤓🫶 we're going to read it like a detective 🕵️‍♀️💅 here's the tea on what's inside:

  • the serial number is 18 (12 hex) 🔢
  • it's signed with DSA and the SHA-1 hash algorithm 🔏
  • the issuer's distinguished name is OU=nist; O=gov; C=US 🏛️
  • the subject's distinguished name is CN=Tim Polk; OU=nist; O=gov; C=US 🙋‍♀️
  • it was valid from July 30, 1997 through December 1, 1997 📅
  • it has a 1024 bit DSA public key 🗝️
  • it's an end entity certificate, since the basic constraints extension is not there at all 🧚
  • it has an authority key identifier extension that matches the subject key identifier of the certificate in Appendix C.1, so they're giving matching energy 💜
  • and it has one alternative name, an RFC 822 address of "wpolk@nist.gov" 📬

okay now the actual dump 👀✨

   0 30  730: SEQUENCE {
   4 30  665:   SEQUENCE {
   8 A0    3:     [0] {
  10 02    1:       INTEGER 2
            :       }
  13 02    1:     INTEGER 18
  16 30    9:     SEQUENCE {
  18 06    7:       OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
            :       }
  27 30   42:     SEQUENCE {
  29 31   11:       SET {
  31 30    9:         SEQUENCE {
  33 06    3:           OBJECT IDENTIFIER countryName (2 5 4 6)
  38 13    2:           PrintableString 'US'
            :           }
            :         }
  42 31   12:       SET {
  44 30   10:         SEQUENCE {
  46 06    3:           OBJECT IDENTIFIER organizationName (2 5 4 10)
  51 13    3:           PrintableString 'gov'
            :           }
            :         }

  56 31   13:       SET {
  58 30   11:         SEQUENCE {
  60 06    3:           OBJECT IDENTIFIER
            :             organizationalUnitName (2 5 4 11)
  65 13    4:           PrintableString 'NIST'
            :           }
            :         }
            :       }
  71 30   30:     SEQUENCE {
  73 17   13:       UTCTime '970730000000Z'
  88 17   13:       UTCTime '971201000000Z'
            :       }
 103 30   61:     SEQUENCE {
 105 31   11:       SET {
 107 30    9:         SEQUENCE {
 109 06    3:           OBJECT IDENTIFIER countryName (2 5 4 6)
 114 13    2:           PrintableString 'US'
            :           }
            :         }
 118 31   12:       SET {
 120 30   10:         SEQUENCE {
 122 06    3:           OBJECT IDENTIFIER organizationName (2 5 4 10)
 127 13    3:           PrintableString 'gov'
            :           }
            :         }
 132 31   13:       SET {
 134 30   11:         SEQUENCE {
 136 06    3:           OBJECT IDENTIFIER
            :             organizationalUnitName (2 5 4 11)
 141 13    4:           PrintableString 'NIST'
            :           }
            :         }
 147 31   17:       SET {
 149 30   15:         SEQUENCE {
 151 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
 156 13    8:           PrintableString 'Tim Polk'
            :           }
            :         }
            :       }
 166 30  439:     SEQUENCE {
 170 30  300:       SEQUENCE {
 174 06    7:         OBJECT IDENTIFIER dsa (1 2 840 10040 4 1)
 183 30  287:         SEQUENCE {
 187 02  129:           INTEGER
            :             00 B6 8B 0F 94 2B 9A CE A5 25 C6 F2 ED FC
            :             FB 95 32 AC 01 12 33 B9 E0 1C AD 90 9B BC
            :             48 54 9E F3 94 77 3C 2C 71 35 55 E6 FE 4F
            :             22 CB D5 D8 3E 89 93 33 4D FC BD 4F 41 64
            :             3E A2 98 70 EC 31 B4 50 DE EB F1 98 28 0A
            :             C9 3E 44 B3 FD 22 97 96 83 D0 18 A3 E3 BD
            :             35 5B FF EE A3 21 72 6A 7B 96 DA B9 3F 1E
            :             5A 90 AF 24 D6 20 F0 0D 21 A7 D4 02 B9 1A
            :             FC AC 21 FB 9E 94 9E 4B 42 45 9E 6A B2 48
            :             63 FE 43
 319 02   21:           INTEGER
            :             00 B2 0D B0 B1 01 DF 0C 66 24 FC 13 92 BA
            :             55 F7 7D 57 74 81 E5
 342 02  129:           INTEGER
            :             00 9A BF 46 B1 F5 3F 44 3D C9 A5 65 FB 91
            :             C0 8E 47 F1 0A C3 01 47 C2 44 42 36 A9 92
            :             81 DE 57 C5 E0 68 86 58 00 7B 1F F9 9B 77
            :             A1 C5 10 A5 80 91 78 51 51 3C F6 FC FC CC
            :             46 C6 81 78 92 84 3D F4 93 3D 0C 38 7E 1A
            :             5B 99 4E AB 14 64 F6 0C 21 22 4E 28 08 9C
            :             92 B9 66 9F 40 E8 95 F6 D5 31 2A EF 39 A2
            :             62 C7 B2 6D 9E 58 C4 3A A8 11 81 84 6D AF
            :             F8 B4 19 B4 C2 11 AE D0 22 3B AA 20 7F EE
            :             1E 57 18
            :           }
            :         }
 474 03  132:       BIT STRING 0 unused bits, encapsulates {
 478 02  128:           INTEGER
            :             30 B6 75 F7 7C 20 31 AE 38 BB 7E 0D 2B AB
            :             A0 9C 4B DF 20 D5 24 13 3C CD 98 E5 5F 6C
            :             B7 C1 BA 4A BA A9 95 80 53 F0 0D 72 DC 33
            :             37 F4 01 0B F5 04 1F 9D 2E 1F 62 D8 84 3A
            :             9B 25 09 5A 2D C8 46 8E 2B D4 F5 0D 3B C7
            :             2D C6 6C B9 98 C1 25 3A 44 4E 8E CA 95 61
            :             35 7C CE 15 31 5C 23 13 1E A2 05 D1 7A 24
            :             1C CB D3 72 09 90 FF 9B 9D 28 C0 A1 0A EC
            :             46 9F 0D B8 D0 DC D0 18 A6 2B 5E F9 8F B5
            :             95 BE
            :           }
            :       }
 609 A3   62:     [3] {
 611 30   60:       SEQUENCE {
 613 30   25:         SEQUENCE {
 615 06    3:           OBJECT IDENTIFIER subjectAltName (2 5 29 17)
 620 04   18:           OCTET STRING, encapsulates {
 622 30   16:               SEQUENCE {
 624 81   14:                 [1] 'wpolk@nist.gov'
            :                 }
            :               }
            :           }
 640 30   31:         SEQUENCE {
 642 06    3:           OBJECT IDENTIFIER

            :             authorityKeyIdentifier (2 5 29 35)
 647 04   24:           OCTET STRING, encapsulates {
 649 30   22:               SEQUENCE {
 651 80   20:                 [0]
            :                   86 CA A5 22 81 62 EF AD 0A 89 BC AD 72
            :                   41 2C 29 49 F4 86 56
            :                 }
            :               }
            :           }
            :         }
            :       }
            :     }
 673 30    9:   SEQUENCE {
 675 06    7:     OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
            :     }
 684 03   48:   BIT STRING 0 unused bits, encapsulates {
 687 30   45:       SEQUENCE {
 689 02   20:         INTEGER
            :           36 97 CB E3 B4 2C E1 BB 61 A9 D3 CC 24 CC
            :           22 92 9F F4 F5 87
 711 02   21:         INTEGER
            :           00 AB C9 79 AF D2 16 1C A9 E3 68 A9 14 10
            :           B4 A0 2E FF 22 5A 73
            :         }
            :       }
            :   }

C.3. End Entity Certificate Using RSA 🎀

okay bestie, this one is an annotated hex dump of a 654 byte version 3 certificate, and it's giving full detective energy 🕵️‍♀️✨ here's what's inside:

  • (a) the serial number is 256;
  • (b) the certificate is signed with RSA and the SHA-1 hash algorithm 🔥
  • (c) the issuer's distinguished name is OU=NIST; O=gov; C=US
  • (d) and the subject's distinguished name is CN=Tim Polk; OU=NIST; O=gov; C=US 💅
  • (e) the certificate was issued on May 21, 1996 at 09:58:26 and expired on May 21, 1997 at 09:58:26 🦋
  • (f) the certificate contains a 1024 bit RSA public key 🔑
  • (g) the certificate is an end entity certificate (not a CA certificate) 🌸
  • (h) the certificate includes an alternative subject name of "<http://www.itl.nist.gov/div893/staff/polk/index.html>" and an alternative issuer name of "<http://www.nist.gov/>". both are URLs, obsessed 😭
  • (i) the certificate includes an authority key identifier extension and a certificate policies extension specifying the policy OID 2.16.840.1.101.3.2.1.48.9; and 🧚
  • (j) the certificate includes a critical key usage extension specifying that the public key is intended for verification of digital signatures ✨

here's the full annotated dump, every byte in its place 🌈

  0 30  654: SEQUENCE {
  4 30  503:   SEQUENCE {
  8 A0    3:     [0] {
 10 02    1:       INTEGER 2
           :       }
 13 02    2:     INTEGER 256
 17 30   13:     SEQUENCE {
 19 06    9:       OBJECT IDENTIFIER
           :         sha1withRSAEncryption (1 2 840 113549 1 1 5)
 30 05    0:       NULL
           :       }
 32 30   42:     SEQUENCE {
 34 31   11:       SET {
 36 30    9:         SEQUENCE {
 38 06    3:           OBJECT IDENTIFIER countryName (2 5 4 6)
 43 13    2:           PrintableString 'US'
           :           }
           :         }
 47 31   12:       SET {
 49 30   10:         SEQUENCE {
 51 06    3:           OBJECT IDENTIFIER organizationName (2 5 4 10)
 56 13    3:           PrintableString 'gov'
           :           }
           :         }
 61 31   13:       SET {
 63 30   11:         SEQUENCE {
 65 06    3:           OBJECT IDENTIFIER
           :             organizationalUnitName (2 5 4 11)
 70 13    4:           PrintableString 'NIST'
           :           }
           :         }
           :       }
 76 30   30:     SEQUENCE {
 78 17   13:       UTCTime '960521095826Z'
 93 17   13:       UTCTime '970521095826Z'
           :       }
108 30   61:     SEQUENCE {
110 31   11:       SET {
112 30    9:         SEQUENCE {
114 06    3:           OBJECT IDENTIFIER countryName (2 5 4 6)
119 13    2:           PrintableString 'US'
           :           }
           :         }
123 31   12:       SET {
125 30   10:         SEQUENCE {
127 06    3:           OBJECT IDENTIFIER organizationName (2 5 4 10)
132 13    3:           PrintableString 'gov'
           :           }
           :         }
137 31   13:       SET {
139 30   11:         SEQUENCE {
141 06    3:           OBJECT IDENTIFIER
           :             organizationalUnitName (2 5 4 11)
146 13    4:           PrintableString 'NIST'
           :           }
           :         }
152 31   17:       SET {
154 30   15:         SEQUENCE {
156 06    3:           OBJECT IDENTIFIER commonName (2 5 4 3)
161 13    8:           PrintableString 'Tim Polk'
           :           }
           :         }
           :       }
171 30  159:     SEQUENCE {
174 30   13:       SEQUENCE {
176 06    9:         OBJECT IDENTIFIER
           :           rsaEncryption (1 2 840 113549 1 1 1)
187 05    0:         NULL
           :         }
189 03  141:       BIT STRING 0 unused bits, encapsulates {
193 30  137:           SEQUENCE {
196 02  129:             INTEGER
           :               00 E1 6A E4 03 30 97 02 3C F4 10 F3 B5 1E
           :               4D 7F 14 7B F6 F5 D0 78 E9 A4 8A F0 A3 75
           :               EC ED B6 56 96 7F 88 99 85 9A F2 3E 68 77
           :               87 EB 9E D1 9F C0 B4 17 DC AB 89 23 A4 1D
           :               7E 16 23 4C 4F A8 4D F5 31 B8 7C AA E3 1A
           :               49 09 F4 4B 26 DB 27 67 30 82 12 01 4A E9
           :               1A B6 C1 0C 53 8B 6C FC 2F 7A 43 EC 33 36
           :               7E 32 B2 7B D5 AA CF 01 14 C6 12 EC 13 F2
           :               2D 14 7A 8B 21 58 14 13 4C 46 A3 9A F2 16
           :               95 FF 23
328 02    3:             INTEGER 65537
           :             }
           :           }
           :       }
333 A3  175:     [3] {
336 30  172:       SEQUENCE {
339 30   63:         SEQUENCE {
341 06    3:           OBJECT IDENTIFIER subjectAltName (2 5 29 17)
346 04   56:           OCTET STRING, encapsulates {
348 30   54:               SEQUENCE {
350 86   52:                 [6]
           :                   'http://www.itl.nist.gov/div893/staff/'
           :                   'polk/index.html'
           :                 }
           :               }
           :           }
404 30   31:         SEQUENCE {
406 06    3:           OBJECT IDENTIFIER issuerAltName (2 5 29 18)
411 04   24:           OCTET STRING, encapsulates {
413 30   22:               SEQUENCE {
415 86   20:                 [6] 'http://www.nist.gov/'
           :                 }
           :               }
           :           }
437 30   31:         SEQUENCE {
439 06    3:           OBJECT IDENTIFIER
           :             authorityKeyIdentifier (2 5 29 35)
444 04   24:           OCTET STRING, encapsulates {
446 30   22:               SEQUENCE {
448 80   20:                 [0]
           :                   08 68 AF 85 33 C8 39 4A 7A F8 82 93 8E
           :                   70 6A 4A 20 84 2C 32
           :                 }
           :               }
           :           }
470 30   23:         SEQUENCE {
472 06    3:           OBJECT IDENTIFIER
           :             certificatePolicies (2 5 29 32)
477 04   16:           OCTET STRING, encapsulates {
479 30   14:               SEQUENCE {
481 30   12:                 SEQUENCE {
483 06   10:                   OBJECT IDENTIFIER
           :                            '2 16 840 1 101 3 2 1 48 9'
           :                   }
           :                 }
           :               }
           :           }
495 30   14:         SEQUENCE {
497 06    3:           OBJECT IDENTIFIER keyUsage (2 5 29 15)
502 01    1:           BOOLEAN TRUE
505 04    4:           OCTET STRING, encapsulates {
507 03    2:               BIT STRING 7 unused bits
           :                 '1'B (bit 0)
           :               }
           :           }
           :         }
           :       }
           :     }

511 30   13:   SEQUENCE {
513 06    9:     OBJECT IDENTIFIER
           :       sha1withRSAEncryption (1 2 840 113549 1 1 5)
524 05    0:     NULL
           :     }
526 03  129:   BIT STRING 0 unused bits
           :     1E 07 77 6E 66 B5 B6 B8 57 F0 03 DC 6F 77
           :     6D AF 55 1D 74 E5 CE 36 81 FC 4B C5 F4 47
           :     82 C4 0A 25 AA 8D D6 7D 3A 89 AB 44 34 39
           :     F6 BD 61 1A 78 85 7A B8 1E 92 A2 22 2F CE
           :     07 1A 08 8E F1 46 03 59 36 4A CB 60 E6 03
           :     40 01 5B 2A 44 D6 E4 7F EB 43 5E 74 0A E6
           :     E4 F9 3E E1 44 BE 1F E7 5F 5B 2C 41 8D 08
           :     BD 26 FE 6A A6 C3 2F B2 3B 41 12 6B C1 06
           :     8A B8 4C 91 59 EB 2F 38 20 2A 67 74 20 0B
           :     77 F3
           :   }

C.4. Certificate Revocation List 🌸

this section is an annotated hex dump of a version 2 CRL with one extension, cRLNumber. the CRL was issued by OU=NIST; O=gov; C=US on August 7, 1997, and the next scheduled issuance was September 7, 1997 📅 it includes one revoked certificate: serial number 18 (12 hex), which was revoked on July 31, 1997 due to keyCompromise 💀 the CRL itself is number 18, and it was signed with DSA and SHA-1 🔐

  0 30  203: SEQUENCE {
  3 30  140:   SEQUENCE {
  6 02    1:     INTEGER 1
  9 30    9:     SEQUENCE {
 11 06    7:       OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
           :       }
 20 30   42:     SEQUENCE {
 22 31   11:       SET {
 24 30    9:         SEQUENCE {
 26 06    3:           OBJECT IDENTIFIER countryName (2 5 4 6)
 31 13    2:           PrintableString 'US'
           :           }
           :         }
 35 31   12:       SET {
 37 30   10:         SEQUENCE {
 39 06    3:           OBJECT IDENTIFIER organizationName (2 5 4 10)
 44 13    3:           PrintableString 'gov'
           :           }
           :         }
 49 31   13:       SET {
 51 30   11:         SEQUENCE {
 53 06    3:           OBJECT IDENTIFIER
           :             organizationalUnitName (2 5 4 11)
 58 13    4:           PrintableString 'NIST'
           :           }
           :         }
           :       }
 64 17   13:     UTCTime '970807000000Z'
 79 17   13:     UTCTime '970907000000Z'
 94 30   34:     SEQUENCE {
 96 30   32:       SEQUENCE {
 98 02    1:         INTEGER 18
101 17   13:         UTCTime '970731000000Z'
116 30   12:         SEQUENCE {
118 30   10:           SEQUENCE {
120 06    3:             OBJECT IDENTIFIER cRLReason (2 5 29 21)
125 04    3:             OCTET STRING, encapsulates {
127 0A    1:                 ENUMERATED 1
           :                 }
           :             }
           :           }
           :         }
           :       }
130 A0   14:     [0] {
132 30   12:       SEQUENCE {
134 30   10:         SEQUENCE {
136 06    3:           OBJECT IDENTIFIER cRLNumber (2 5 29 20)
141 04    3:           OCTET STRING, encapsulates {
143 02    1:               INTEGER 12
           :               }
           :           }
           :         }
           :       }
           :     }
146 30    9:   SEQUENCE {
148 06    7:     OBJECT IDENTIFIER dsaWithSha1 (1 2 840 10040 4 3)
           :     }
157 03   47:   BIT STRING 0 unused bits, encapsulates {
160 30   44:       SEQUENCE {
162 02   20:         INTEGER
           :           22 4E 9F 43 BA 95 06 34 F2 BB 5E 65 DB A6
           :           80 05 C0 3A 29 47
184 02   20:         INTEGER
           :           59 1A 57 C9 82 D7 02 21 14 C3 D4 0B 32 1B
           :           96 16 B1 1F 46 5A
           :         }
           :       }
           :   }

Author Addresses 💌

meet the crew who wrote this 🫶

   Russell Housley
   RSA Laboratories
   918 Spring Knoll Drive
   Herndon, VA 20170
   USA

   EMail:  rhousley@rsasecurity.com

   Warwick Ford
   VeriSign, Inc.
   401 Edgewater Place
   Wakefield, MA 01880
   USA

   EMail:  wford@verisign.com

   Tim Polk
   NIST
   Building 820, Room 426
   Gaithersburg, MD 20899
   USA

   EMail:  wpolk@nist.gov

   David Solo
   Citigroup
   909 Third Ave, 16th Floor
   New York, NY 10043
   USA

   EMail:  dsolo@alum.mit.edu

Copyright (C) The Internet Society (2002). All Rights Reserved. ✨

okay so this part is the legal bit, but it's still kind of iconic 💅 Anyone can copy this document and share it, and translations of it too. You can also make derivative works that comment on it, explain it, or help people implement it, and you can prepare, copy, publish, and distribute those, in whole or in part, with no restrictions of any kind. The one catch: the copyright notice and this paragraph have to be included on every copy and every derivative work 🎀

The original document itself can't be modified in any way. That means you can't remove the copyright notice or the references to the Internet Society or other Internet organizations. There are two exceptions. The first is when it's needed for developing Internet standards, and then the copyright procedures defined in the Internet Standards process have to be followed. The second is when it's required to translate it into languages other than English 🌸

These permissions are perpetual, and the Internet Society or its successors or assigns will never revoke them. Iykyk 🦋

Last but not least, the document and the information in it are provided on an "AS IS" basis, and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. No cap, that's a lot of legal fine print 💀


Acknowledgement 🫶

Funding for the RFC Editor function is currently provided by the Internet Society. Thank you, Internet Society 🍓

📦 where this page comes from