RFC 10002
Certificate Management over CMS (CMC)
Certificate Management over CMS (CMC) 🎀
Okay bestie, here's the tea 💖 This is RFC 10002, a Standards Track doc from the Internet Engineering Task Force (IETF), dated July 2026 🗓️. It's by J. Mandel, Ed. from AKAYLA, Inc. and S. Turner, Ed. from sn3rd, and its ISSN is 2070-1721 ✨. It obsoletes RFC 5272 and RFC 6402 💅, so if you're still using those, it's time to upgrade 🫶
Abstract ✨
So this doc defines the base syntax for CMC, a Certificate Management protocol that runs on the Cryptographic Message Syntax (CMS) 🦋. It's here to handle two immediate needs in the Internet Public Key Infrastructure (PKI) community:
- The need for an interface to public key certification products and services based on CMS and PKCS #10 (Public Key Cryptography Standard), and
- The need for a PKI enrollment protocol for encryption-only keys due to algorithm or hardware design.
CMC also requires the use of the transport document (RFC 10003) and the requirements usage document (RFC 10004) along with this document for a full definition. So you really need all three to get the whole picture 🧚
This document obsoletes RFCs 5272 and 6402.
Status of This Memo 📜
This is an Internet Standards Track document. 🌟
This doc is a product of the Internet Engineering Task Force (IETF), and it represents the consensus of the IETF community. It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). If you want more on Internet Standards, check Section 2 of RFC 7841 🎀
For the current status, any errata, and how to send feedback, head to https://www.rfc-editor.org/info/rfc10002 💌
Copyright Notice ©️
Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved.
This doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please read these carefully, because they spell out your rights and restrictions with respect to this document. Code Components extracted from this doc must include Revised BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they're provided without warranty as described in the Revised BSD License 😭
This doc may contain material from IETF Documents or IETF Contributions published or made publicly available before November 10, 2008. The person(s) controlling the copyright in some of this material may not have granted the IETF Trust the right to allow modifications of such material outside the IETF Standards Process. Without obtaining an adequate license from the person(s) controlling the copyright in those materials, this document may not be modified outside the IETF Standards Process, and derivative works of it may not be created outside the IETF Standards Process, except to format it for publication as an RFC or to translate it into languages other than English.
Table of Contents 🗺️
1. Introduction
1.1. Protocol Requirements
1.2. Requirements Terminology
1.3. Changes Since RFC 2797
1.4. Updates Made by RFC 6402
1.5. Changes Since RFC 6402
2. Protocol Overview
2.1. Terminology
2.2. Protocol Requests/Responses
3. PKI Requests
3.1. Simple PKI Request
3.2. Full PKI Request
3.2.1. PKIData Content Type
3.2.2. Body Part Identification
3.2.3. CMC Unsigned Data Attribute
4. PKI Responses
4.1. Simple PKI Response
4.2. Full PKI Response
4.2.1. PKIResponse Content Type
5. Application of Encryption to a PKI Request/Response
6. Controls
6.1. CMC Status Info Controls
6.1.1. Extended CMC Status Info Control
6.1.2. CMC Status Info Control
6.1.3. CMCStatus Values
6.1.4. CMCFailInfo
6.2. Identification and Identity Proof Controls
6.2.1. Identity Proof Version 2 Control
6.2.2. Identity Proof Control
6.2.3. Identification Control
6.2.4. Hardware Shared-Secret Token Generation
6.3. Linking Identity and POP Information
6.3.1. Cryptographic Linkage
6.3.2. Shared-Secret/Subject DN Linking
6.3.3. Existing Certificate Linking
6.4. Data Return Control
6.5. RA Certificate Modification Controls
6.5.1. Modify Certification Request Control
6.5.2. Add Extensions Control
6.6. Transaction Identifier Control and Sender and Recipient
Nonce Controls
6.7. Encrypted and Decrypted POP Controls
6.8. RA POP Witness Control
6.9. Get Certificate Control
6.10. Get CRL Control
6.11. Revocation Request Control
6.12. Registration and Response Information Controls
6.13. Query Pending Control
6.14. Confirm Certificate Acceptance Control
6.15. Publish Trust Anchors Control
6.16. Authenticated Data Control
6.17. Batch Request and Response Controls
6.18. Publication Information Control
6.19. Control Processed Control
6.20. RA Identity Proof Witness Control
6.21. Response Body Control
7. Other Attributes
7.1. Change Subject Name Attribute
8. Registration Authorities
8.1. Encryption Removal
8.2. Signature Layer Removal
9. CMC Infrastructure Certificate Requirements
9.1. Extended Key Usage
9.2. Subject Information Access
10. Security Considerations
11. IANA Considerations
12. References
12.1. Normative References
12.2. Informative References
Appendix A. ASN.1 Modules
A.1. ASN.1 Module for CMC
A.2. ASN.1 Module for PBKDF2 PRFs
Appendix B. Enrollment Message Flows
B.1. Request of a Signing Certificate
B.2. Single Certification Request Modified by RA
B.3. Direct POP for an RSA or KEM Certificate
B.4. Direct POP with No Signature Mechanism
Appendix C. Production of Diffie-Hellman Public Key Certification
Requests
C.1. No-Signature Signature Mechanism
Acknowledgements
Contributors
Authors' Addresses
1. Introduction ✨
This document defines the base syntax for CMC, a Certificate Management protocol using the Cryptographic Message Syntax (CMS). It addresses two immediate needs within the Internet PKI community:
- The need for an interface to public key certification products and services based on CMS and PKCS #10, and
- The need for a PKI enrollment protocol for encryption-only keys due to algorithm or hardware design.
A small number of additional services are defined to supplement the core certification request service. 🌸
CMC also requires the use of the transport document [CMC-TRANS] and the requirements usage document [CMC-COMPL] along with this document for a full definition.
This document obsoletes RFCs 5272 [CMC-PROTv1] and 6402 [CMC-Updates].
1.1. Protocol Requirements 📋
As much as possible, the protocol must be based on the existing CMS [CMS] [CMS-AE], PKCS #10 [PKCS10], and CRMF (Certificate Request Message Format) [CRMF] specifications.
The protocol must support the current industry practice of a PKCS #10 certification request followed by a PKCS #7 "certs-only" response as a subset of the protocol.
The protocol must easily support the multi-key enrollment protocols required by S/MIME and other groups.
The protocol must supply a way of doing all enrollment operations in a single round trip. When this is not possible, the number of round trips is to be minimized.
The protocol must be designed such that all key generation can occur on the client.
Support must exist for the mandatory algorithms used by S/MIME. Support should exist for all other algorithms cited by the S/MIME core documents.
The protocol must contain Proof-of-Possession (POP) methods. Optional provisions for multiple-round-trip POP will be made if necessary.
The protocol must support deferred and pending responses to enrollment requests for cases where external procedures are required to issue a certificate.
1.2. Requirements Terminology 🔑
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.
1.3. Changes Since RFC 2797 🦋
[CMC-PROTv1] was a major overhaul on the layout of [RFC2797]. It included two different steps. Mainly, some sections got removed from the document and moved to two other documents:
- Information on how to transport messages is now found in [CMC-TRANS].
- Information on which controls and sections of this document must be implemented along with which algorithms are required can now be found in [CMC-COMPL].
A number of new controls were added in [CMC-PROTv1]:
- "Extended CMC Status Info Control" (Section 6.1.1)
- "Publish Trust Anchors Control (Section 6.15)
- "Authenticated Data Control (Section 6.16)
- "Batch Request and Response Controls (Section 6.17)
- "Publication Information Control (Section 6.18)
- "Modify Certification Request Control (Section 6.5.1)
- "Control Processed Control (Section 6.19)
- "Identity Proof Control (Section 6.2.2)
- "POP Link Witness Version 2 Controls (Section 6.3.1.1)
1.4. Updates Made by RFC 6402 🌈
[CMC-Updates] includes changes to [CMC-PROTv1], and they're noted in this section.
Two added controls:
- Registration Authority (RA) Identity Witness allows for an RA to perform identity checking using the identity and shared-secret, and tell any following servers that the identity check was successfully performed.
- Response Body allows for an RA to identify a nested response for an End-Entity (EE) to process.
[CMC-Updates] also:
- Creates the Change Subject Name attribute, which allows a client to request a change in the subject field and Subject Alternative Name extension in a certificate.
- Adds Extended Key Usages (EKUs) for CMC to distinguish server types.
- Defines a new Subject Information Access extension to hold locations to contact the CMC server.
- Clarifies that the use of a preexisting certificate is not limited to just renewal and rekey messages and is required for support. This formalizes a requirement for the ability to do renewal and rekey that previously was implicit.
1.5. Changes Since RFC 6402 💅
🙈 The text I was given stops right after Section 1.4, so this section's body is missing. I've left it out instead of guessing what it says.
1.5. Changes Since RFC 6402 🦋
Okay bestie, this is the glow-up log 💅 This document makes some changes to [CMC-PROTv1], and they're all listed right here so you can see exactly what's new ✨
- Merged [CMC-Updates] text. 🫶
- Included updates inspired by the following errata reports: [Err8385], [Err8137], [Err8027], [Err7629], [Err7628], [Err7627], [Err7379], [Err6571], [Err5931], [Err4775], [Err2731], [Err2063], and [Err3943] (for [CMC-Updates]). 🔥
- To support adopting SHA-256 and HMAC-SHA256,
maca-hMAC-SHA256was added to POPAlgs andmda-sha256was added to WitnessAlgs. Both were included in the example in Appendix B. 🌈 - Updated the "Encrypted and Decrypted POP Controls" section (Section 6.7) to use
HMAC-SHA256. 🔐 - Updated the ASN.1 module to import from the 2008 ASN.1 module from [ADD-ASN1]. 🧚
- Modified the ASN.1 module in Appendix A.1 to import Password-Based Key Derivation Function 2 (PBKDF2) Pseudorandom Functions (PRFs) from Appendix A.2. 🎀
- Added a direct POP example to address management of Key Encapsulation Mechanism (KEM) certificates. 🦋
- Added
id-ce-subjectKeyIdentifierto examples. ✨ - Clarified that the
subjectKeyIdentifierchoice must be used withid-alg-noSignature. 💖 - Updated the CMC Control Attribute Table (see Table 1) to include
raIdentityWitnessandresponseBodyfrom [CMC-Updates]. 🌸 - Added support for
AuthEnvelopedData. 👑
2. Protocol Overview 🌟
Alright, so a PKI enrollment transaction in this spec is generally one round trip of messages, and honestly that's the vibe most of the time 💅 In the simplest case, a PKI enrollment request (we're calling it a PKI Request from here on) goes from the client to the server. Then a PKI enrollment response (aka a PKI Response) comes back from the server to the client. It's giving clean and easy ✨ Things only get more complicated in situations like delayed certificate issuance, where more than one round trip is required 🙈
This spec defines two PKI Request types and two PKI Response types. Let's meet them 🦋
PKI Requests are built using either the PKCS #10 or CRMF structure. The two PKI Requests are:
- Simple PKI Request: the bare PKCS #10 (in the event that no other services are needed). 🍓
- Full PKI Request: one or more PKCS #10, CRMF, or Other Request Message structures wrapped in a CMS encapsulation as part of a PKIData. 🧁
PKI Responses are based on SignedData or AuthenticatedData [CMS]. The two PKI Responses are:
- Simple PKI Response: a "certs-only" SignedData (in the event no other services are needed). 🌷
- Full PKI Response: a PKIResponse content type wrapped in a SignedData. 💜
No special services are provided for either renewal (i.e., a new certificate with the same key) or rekey (i.e., a new certificate with a new key) of client certificates. Instead, renewal and rekey requests look the same as any certification request, except that the Proof-of-Identity is supplied by existing certificates from a trusted Certification Authority (CA). It's the same energy, just with a different receipt 🧾
Note: This is usually the same CA, but it could be a different CA in the same organization where naming is shared.
No special services are provided to tell a rekey request apart from a new certification request (generally for a new purpose). CAs or other publishing agents are also expected to have policies for removing certificates from publication, based either on new certificates being added or on the expiration or revocation of a certificate. A control to unpublish a certificate would normally be included in a rekey request if the CA did not wish to have a grace period between the certificates, be omitted if the CA wishes to have a grace period between certificates, and be omitted from a new certification request. Lots of "it depends" here, but that's the whole point 🙃
A provision exists for RAs to take part in the protocol. They take PKI Requests, wrap them in a second layer of PKI Request with additional requirements or statements from the RA, and then pass this new expanded PKI Request on to the CA 🫶
This specification makes no assumptions about the underlying transport mechanism. The use of CMS does not imply an email-based transport. Several different possible transport methods are defined in [CMC-TRANS]. Not a email-only situation, bestie 📬
Optional services available through this specification are transaction management, replay detection (through nonces), deferred certificate issuance, certificate revocation requests, and certificate / Certificate Revocation List (CRL) retrieval. Extras, but make it aesthetic 💅
2.1. Terminology 📖
There are several different terms, abbreviations, and acronyms used in this document. These are defined here, in no particular order, for convenience and consistency of usage:
- End-Entity (EE): Refers to the entity that owns a key pair and for whom a certificate is issued. 🦋
- Registration Authority (RA) or Local RA (LRA): Refers to an entity that acts as an intermediary between the EE and the CA. Multiple RAs can exist between the EE and the CA. RAs may perform additional services such as key generation or key archival. This document uses the term RA for both RA and LRA. 🧚
- Certification Authority (CA): Refers to the entity that issues certificates. 👑
- Client: Refers to an entity that creates a PKI Request. In this document, both RAs and EEs can be clients. 🌸
- Server: Refers to the entities that process PKI Requests and create PKI Responses. In this document, both CAs and RAs can be servers. 💖
- PKCS #10: Refers to the Public Key Cryptography Standard #10 [PKCS10], which defines a certification request syntax. 📜
- CRMF: Refers to the Certificate Request Message Format [CRMF]. CMC uses the certification request syntax defined in this document as part of the protocol. 🎀
- CMS: Refers to the Cryptographic Message Syntax [CMS]. This document provides for basic cryptographic services including encryption and signing with and without key management. 🔐
- PKI Request/Response: Refers to the requests/responses described in this document. PKI Requests include certification requests, revocation requests, etc. PKI Responses include "certs-only" messages, failure messages, etc. 🍓
- Proof-of-Identity: Refers to the client proving they are who they say that they are to the server. 🪪
- Enrollment or certification request: Refers to the process of a client requesting a certificate. A certification request is a subset of the PKI Requests. 🌈
- Proof-of-Possession (POP): Refers to a value that can be used to prove that the private key corresponding to a public key is in the possession and can be used by an EE. The different types of POP are:
- Signature provides the required POP by a signature operation over some data. ✍️
- Direct provides the required POP operation by an encrypted challenge-response mechanism. 🔑
- Indirect provides the required POP operation by returning the issued certificate in an encrypted state. (This method is not used by CMC.) 🙅
- Publish provides the required POP operation by providing the private key to the certificate issuer. (This method is not currently used by CMC. It would be used by Key Generation or Key Escrow extensions.) 🫣
- Attested provides the required POP operation by allowing a trusted entity to assert that the POP has been proven by one of the above methods. 🤝
- Object IDentifier (OID): A primitive type in Abstract Syntax Notation One [ASN.1]. 🔢
- HMAC: Refers to the Hashed Message Authentication Code. CMC uses the ASN.1 module defined in [HMAC-ALGS]. 🧾
2.2. Protocol Requests/Responses 🎁
Figure 1 shows the Simple PKI Requests and Responses. The contents of the Simple PKI Request and Response are detailed in Sections 3.1 and 4.1. Here's the picture:
Simple PKI Request Simple PKI Response
------------------------- --------------------------
+----------+ +------------------+
| PKCS #10 | | CMS ContentInfo |
+----------+--------------+ +------------------+------+
| Certification Request | | CMS Signed Data, |
| | | no SignerInfo |
| Subject Name | | |
| Subject Public Key Info | | SignedData contains one |
| (K_PUB) | | or more certificates in |
| Attributes | | the certificates field |
| | | Relevant CA certs and |
+-----------+-------------+ | CRLs can be included |
| signed with | | as well. |
| matching | | |
| K_PRIV | | encapsulatedContentInfo |
+-------------+ | is absent. |
+--------------+----------+
| unsigned |
+----------+
Figure 1: Simple PKI Requests and Responses ✨
Figure 2 shows the Full PKI Requests and Responses. The contents of the Full PKI Request and Response are detailed in Sections 3.2 and 4.2. The big one, bestie 👑
Full PKI Request Full PKI Response
----------------------- ------------------------
+----------------+ +----------------+
| CMS ContentInfo| | CMS ContentInfo|
| CMS SignedData | | CMS SignedData |
| or Auth Data | | or Auth Data |
| object | | object |
+----------------+--------+ +----------------+--------+
| | | |
| PKIData | | PKIResponse |
| | | |
| Sequence of: | | Sequence of: |
| <enrollment control>* | | <enrollment control>* |
| <certification request>*| | <CMS object>* |
| <CMS object>* | | <other message>* |
| <other message>* | | |
| | | where * == zero or more |
| where * == zero or more | | |
| | | All certificates issued |
| Certification requests | | as part of the response |
| are CRMF, PKCS #10, or | | are included in the |
| Other. | | "certificates" field |
| | | of the SignedData. |
+-------+-----------------+ | Relevant CA certs and |
| signed (keypair | | CRLs can be included as |
| used may be pre-| | well. |
| existing or | | |
| identified in | +---------+---------------+
| the request) | | signed by the |
+-----------------+ | CA or an LRA |
+---------------+
Figure 2: Full PKI Requests and Responses 🌈
3. PKI Requests 💌
Two types of PKI Requests exist. This section gives the details for both types. Let's dive in, bestie 🦋
3.1. Simple PKI Request ✨
okay so the Simple PKI Request is built on the PKCS #10 CertificationRequest syntax [PKCS10] 💖
When a server processes a Simple PKI Request, the PKI Response it sends back is one of these:
- Simple PKI Response on success. ✨
- Full PKI Response on failure. The server MAY choose not to return a PKI Response in this case. 🙈
The Simple PKI Request MUST NOT be used if a Proof-of-Identity needs to be included. 🚫
The Simple PKI Request cannot be used if the private key is not capable of producing some type of signature.
Note: Diffie-Hellman (DH) and Elliptic Curve Diffie-Hellman (ECDH) keys can use the integrity check algorithms in [DH-POP] to prove they have access to the corresponding private key. 🔑
The Simple PKI Request cannot be used for any of the advanced services specified in this document. 💅
The client MAY incorporate one or more X.509v3 extensions in any certification request based on PKCS #10 as an ExtensionReq attribute. The ExtensionReq attribute is defined as:
ExtensionReq ::= SEQUENCE SIZE (1..MAX) OF Extension
where Extension is imported from [PKIXCERT] [ADD-ASN1] and ExtensionReq is identified by:
id-ExtensionReq OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) 14 }
Servers MUST be able to process all extensions defined, but not prohibited, in [PKIXCERT]. Servers are not required to be able to process other X.509v3 extensions transmitted using this protocol, nor are they required to be able to process private extensions. Servers are not required to put all client-requested extensions into a certificate. Servers are permitted to modify client-requested extensions. Servers MUST NOT alter an extension so as to invalidate the original intent of a client-requested extension. (For example, changing key usage from keyAgreement to digitalSignature.) If a certification request is denied due to the inability to handle a requested extension and a PKI Response is returned, the server MUST return a PKI Response with a CMCFailInfo value with the value unsupportedExt. 🫶
3.2. Full PKI Request
The Full PKI Request provides the most functionality and flexibility. 👑
The Full PKI Request is encapsulated in either a SignedData or an AuthenticatedData with an encapsulated content type of id-cct-PKIData (Section 3.2.1).
When a server processes a Full PKI Request, a PKI Response MUST be returned. The PKI Response returned is:
- Simple PKI Response if the enrollment was successful and only certificates are returned. (An Extended CMC Status Info V2 control with success is implied.)
- Full PKI Response if the enrollment was successful and information is returned in addition to certificates, if the enrollment is pending, or if the enrollment failed.
If SignedData is used, the signature can be generated using either the private key material of an embedded signature certification request (i.e., included in the TaggedRequest tcr or crm fields) or a previously certified signature key. If the private key of a signature certification request is used, then:
- The certification request containing the corresponding public key MUST include a Subject Key Identifier extension.
- The subjectKeyIdentifier form of the signerIdentifier in SignerInfo MUST be used.
- The value of the subjectKeyIdentifier form of SignerInfo MUST be the Subject Key Identifier specified in the corresponding certification request. (The subjectKeyIdentifier form of SignerInfo is used here because no certificates have yet been issued for the signing key.) If the request key is used for signing, there MUST be only one SignerInfo in the SignedData. 🔥
If AuthenticatedData is used, then:
- The Password Recipient Info option of RecipientInfo MUST be used.
- A randomly generated key is used to compute the Message Authentication Code (MAC) value on the encapsulated content.
- The input for the key derivation algorithm is a concatenation of the identifier (encoded as UTF-8) and the shared-secret.
When creating a PKI Request to renew or rekey a certificate:
- The Identification and Identity Proof controls are absent. The same information is provided by the use of an existing certificate from a CA when signing the PKI Request. In this case, the CA that issued the original certificate and the CA the request is made to will usually be the same, but they could have a common operator. 🦋
- CAs and RAs can impose additional restrictions on the signing certificate used. They may require that the most recently issued signing certificate for a client be used.
- Some CAs may prevent renewal operations (i.e., reuse of the same keys). In this case, the CA MUST return a PKI Response with
noKeyReuseas the CMCFailInfo failure code. 🌸
3.2.1. PKIData Content Type
The PKIData content type is used for the Full PKI Request. A PKIData content type is identified by:
id-cct-PKIData OBJECT IDENTIFIER ::= { id-pkix id-cct(12) 2 }
The ASN.1 structure corresponding to the PKIData content type is:
PKIData ::= SEQUENCE {
controlSequence SEQUENCE SIZE (0..MAX) OF TaggedAttribute,
reqSequence SEQUENCE SIZE (0..MAX) OF TaggedRequest,
cmsSequence SEQUENCE SIZE (0..MAX) OF TaggedContentInfo,
otherMsgSequence SEQUENCE SIZE (0..MAX) OF OtherMsg
}
The fields in PKIData have the following meanings:
- controlSequence is a sequence of controls. The controls defined in this document are found in Section 6. Controls can be defined by other parties. Details on the TaggedAttribute structure can be found in Section 3.2.1.1.
- reqSequence is a sequence of certification requests. The certification requests can be a CertificationRequest (PKCS #10), a CertReqMsg (CRMF), or an externally defined PKI Request. Full details are found in Section 3.2.1.2. If an externally defined certification request is present, but the server does not understand the certification request (or will not process it), a CMCStatus of
noSupportMUST be returned for the certification request item and no other certification requests are processed. - cmsSequence is a sequence of CMS (see [CMS]) message objects. See Section 3.2.1.3 for more details.
- otherMsgSequence is a sequence of arbitrary data objects. Data objects placed here are referred to by one or more controls. This allows for controls to use large amounts of data without the data being embedded in the control. See Section 3.2.1.4 for more details.
All certification requests encoded into a single PKIData SHOULD be for the same identity. RAs that batch process (see Section 6.17) are expected to place the PKI Requests received into the cmsSequence of a PKIData. 📦
Processing of the PKIData by a recipient is as follows:
- All controls should be examined and processed in an appropriate manner. The appropriate processing is to complete processing at this time, to ignore the control, or to place the control on a to-do list for later processing. Controls can be processed in any order; the order in the sequence is not significant.
- Items in the reqSequence are not referenced by a control. These items, which are certification requests, also need to be processed. As with controls, the appropriate processing can be either immediate processing or addition to a to-do list for later processing.
- Finally, the to-do list is processed. In many cases, the to-do list will be ordered by grouping specific tasks together.
No processing is required for cmsSequence or otherMsgSequence members of PKIData if they are present and are not referenced by a control. In this case, the cmsSequence and otherMsgSequence members are ignored. 🧚
3.2.1.1. Control Syntax
The actions to be performed for a PKI Request/Response are based on the included controls. Each control consists of an OID and a value based on the OID.
The syntax of a control is:
TaggedAttribute ::= SEQUENCE {
bodyPartID BodyPartID,
attrType CMC-CONTROL.&id({Cmc-Control-Set}),
attrValues SET OF CMC-CONTROL.
&Type({Cmc-Control-Set}{@attrType})
}
The fields in TaggedAttribute have the following meanings:
- bodyPartID is a unique integer that identifies this control.
- attrType is the OID that identifies the control.
- attrValues is comprised of the data values used in processing the control. The structure of the data is dependent on the specific control.
The final server MUST fail the processing of an entire PKIData if any included control is not recognized, that control is not already marked as processed by a Control Processed control (see Section 6.19), and no other error is generated. The PKI Response MUST include a CMCFailInfo value with the value badRequest and the bodyList MUST contain the bodyPartID of the invalid or unrecognized control(s). A server is the final server if and only if it is not passing the PKI Request on to another server. A server is not considered to be the final server if the server would have passed the PKI Request on, but instead it returned a processing error. 🚨
The controls defined by this document are found in Section 6.
3.2.1.2. Certification Request Formats
Certification requests are based on PKCS #10, CRMF, or Other Request formats. Section 3.2.1.2.1 specifies the requirements for clients and servers dealing with PKCS #10. Section 3.2.1.2.2 specifies the requirements for clients and servers dealing with CRMF. Section 3.2.1.2.3 specifies the requirements for clients and servers dealing with Other Requests. 🍓
TaggedRequest ::= CHOICE {
tcr [0] TaggedCertificationRequest,
crm [1] CertReqMsg,
orm [2] SEQUENCE {
bodyPartID BodyPartID,
requestMessageType OTHER-REQUEST.&id({OtherRequests}),
requestMessageValue OTHER-REQUEST.&Type({OtherRequests}
{@.requestMessageType})
}
}
The fields in TaggedRequest have the following meanings:
- tcr is a certification request that uses the PKCS #10 syntax. Details on PKCS #10 are found in Section 3.2.1.2.1.
- crm is a certification request that uses the CRMF syntax. Details on CRMF are found in Section 3.2.1.2.2.
- orm is an externally defined certification request. One example is an attribute certification request. The fields of this structure are:
- bodyPartID is the identifier number for this certification request. Details on body part identifiers are found in Section 3.2.2.
- requestMessageType identifies the other request type. These values are defined outside of this document.
- requestMessageValue is the data associated with the other request type.
3.2.1.2.1. PKCS #10 Certification Syntax ✨
okay so a cert request based on PKCS #10 runs on this little ASN.1 structure 🧩
TaggedCertificationRequest ::= SEQUENCE {
bodyPartID BodyPartID,
certificationRequest CertificationRequest
}
bodyPartIDis the ID number for this certification request 🔢. Deets on body part identifiers live in Section 3.2.2.certificationRequestholds the certification request based on PKCS #10 💌. Its fields are described in [PKCS10].
Okay, the big rule: clients MUST produce the certification request with a subject name and public key 🙅♀️. Some PKI products run off a central repository that hands out subject names once a request comes in, so to make that work, the subject field in a CertificationRequest MAY be NULL, but it MUST be present 🫠. It can be empty, but the field has to show up. CAs that get a CertificationRequest with a NULL subject field MAY reject those requests. If they do reject it and a PKI Response gets sent back, the CA MUST return a PKI Response with the CMCFailInfo value with the value badRequest 💅.
3.2.1.2.2. CRMF Certification Syntax 🎀
A CRMF message uses the following ASN.1 structure (defined in [CRMF][ADD-ASN1] and copied here so you don't have to hunt for it) 🫶
CertReqMsg ::= SEQUENCE {
certReq CertRequest,
popo ProofOfPossession OPTIONAL,
-- content depends upon key type
regInfo SEQUENCE SIZE (1..MAX) OF
SingleAttribute{{RegInfoSet}} OPTIONAL }
CertRequest ::= SEQUENCE {
certReqId INTEGER,
-- ID for matching request and reply
certTemplate CertTemplate,
-- Selected fields of cert to be issued
controls Controls OPTIONAL }
-- Attributes affecting issuance
CertTemplate ::= SEQUENCE {
version [0] Version OPTIONAL,
serialNumber [1] INTEGER OPTIONAL,
signingAlg [2] AlgorithmIdentifier{SIGNATURE-ALGORITHM,
{SignatureAlgorithms}} OPTIONAL,
issuer [3] Name OPTIONAL,
validity [4] OptionalValidity OPTIONAL,
subject [5] Name OPTIONAL,
publicKey [6] SubjectPublicKeyInfo OPTIONAL,
issuerUID [7] UniqueIdentifier OPTIONAL,
subjectUID [8] UniqueIdentifier OPTIONAL,
extensions [9] Extensions{{CertExtensions}} OPTIONAL }
All the CertReqMsg fields get the full breakdown in [CRMF] 📖
This doc adds some extra rules for building and processing CRMF, and they're not optional vibes 👑
- When a Full PKI Request includes a CRMF, both the subject and publicKey fields in the CertTemplate MUST be defined 🔒. The subject field can be encoded as
NULL, but it MUST be present 🙃. - When both CRMF and CMC controls do the same job, the CMC control SHOULD be used 🎯. The CMC control MUST override the CRMF control, so it wins the drama 👑.
- The regInfo field MUST NOT be used on a CRMF 🚫. The same functionality is handled by the CMC regInfo control (Section 6.12) 💫.
- The indirect way of proving POP isn't supported in this protocol 😬. One of the other methods (including the direct one described in this doc) MUST be used, and the value of
encrCertinSubsequentMessageMUST NOT be used. - Since the subject and publicKey fields are always present, the
POPOSigningKeyInputMUST NOT be used when computing the value forPOPSigningKey🙅.
A server doesn't have to use every value the client suggests in the CRMF 🤷♀️
Servers MUST be able to process all extensions defined, but not prohibited, in [PKIXCERT] 💪. Servers don't have to handle other X.509v3 extensions sent over this protocol, or private extensions either 🙈. Servers are allowed to tweak client-requested extensions 🔧. But Servers MUST NOT alter an extension in a way that kills the original intent of a client-requested extension 💀 (for example, changing key usage from keyAgreement to digitalSignature). If a certification request gets denied because the server can't handle a requested extension, and a Full PKI Response is returned, the server MUST return a CMCFailInfo value with the value of unsupportedExt 🥀.
3.2.1.2.3. Other Certification Request 🦋
This doc leaves room for other certification request formats to be defined and used too 🌈. One example is a format for Attribute Certificates. These other formats get defined by specifying an OID for identification, plus the structure that holds the data being passed along ✨
3.2.1.3. Content Info Objects 📦
The cmsSequence field in PKIData and PKIResponse messages holds zero or more tagged content info objects 🧺 Here's the syntax:
TaggedContentInfo ::= SEQUENCE {
bodyPartID BodyPartID,
contentInfo ContentInfo
}
The fields in TaggedContentInfo have the following meanings:
bodyPartIDis a unique integer that identifies this content info object.contentInfois a ContentInfo object (defined in [CMS]).
Five content types show up in cmsSequence: AuthenticatedData, Data, EnvelopedData, SignedData, and AuthEnvelopedData 🎉. The first four live in [CMS], and the last one lives in [CMS-AE].
3.2.1.3.1. Authenticated Data 🔐
AuthenticatedData lets you do pre-shared-secret-based validation of data going between two parties 🤝. Unlike SignedData, it doesn't say which party actually generated the info 👀
AuthenticatedData gives origination authentication when there's a shared secret but PKI-based trust isn't set up yet 🫠. That trust might be missing because a trust anchor isn't installed on the client, or because there's no certificate for a signing key.
This doc uses the AuthenticatedData content type for:
- the
id-cmc-authDatacontrol (Section 6.16), and - the top-level wrapper in environments where an encryption-only key is being certified, or where a shared secret exists but PKI-based trust (needed for
SignedData) hasn't been established yet.
This content type can wrap up both PKIData and PKIResponse as the encapsulated content types 🎁. Those embedded ones can carry extra controls that need processing.
3.2.1.3.2. Data 📄
Data is the plain-jane one for moving unstructured data around 📦
This doc uses the Data content type for:
- Holding the encrypted random value
yfor POP in the Encrypted POP control (see Section 6.7).
3.2.1.3.3. Enveloped Data 🔒
EnvelopedData is all about shrouding data 🧥 (aka hiding it).
EnvelopedData is one of the confidentiality options for sensitive stuff in this protocol 🤫. It can encrypt an entire PKI Request (see Section 5), and it can also wrap private key material that's getting archived 🗄️. If decrypting an EnvelopedData fails, a Full PKI Response gets sent back with a CMCFailInfo value of badMessageCheck and a bodyPartID of 0 💥.
3.2.1.3.4. Signed Data ✍️
SignedData brings the authentication and integrity energy ✨
This doc uses the SignedData content type for:
- The outer wrapper for a PKI Request.
- The outer wrapper for a PKI Response.
When processing a PKI Request/Response, the signature(s) MUST be verified 🔍. If the signature doesn't verify and the PKI Request/Response contains anything other than an Extended CMC Status Info or a CMC Status Info control, a Full PKI Response containing an Extended CMC Status Info or a CMC Status Info control MUST be returned, using a CMCFailInfo with a value of badMessageCheck and a bodyPartID of 0 😭.
For the PKI Response, SignedData lets the server sign whatever data is coming back (if there's any) and carry along the certificates and CRLs that match the PKI Request 📜. If nothing is coming back beyond those certificates and CRLs, there's no eContent field in the EncapsulatedContentInfo and no SignerInfo 🫥.
Only if the server can't sign the response (and can't use any RecipientInfo options from the AuthenticatedData content type either) should it send a negative response 😤.
A Full PKI Response SignedData type containing an Extended CMC Status Info or a CMC Status Info control MUST be returned using a CMCFailInfo with a value of internalCAError and a bodyPartID of 0, and the eContent field in the EncapsulatedContentInfo as well as the SignerInfo fields MUST NOT be populated 🚫.
3.2.1.3.5. Authenticated Enveloped Data 🛡️
AuthEnvelopedData is also all about shrouding data 🧥
It's the primary confidentiality method for sensitive info in this protocol 👑. It can encrypt an entire PKI Request (see Section 5), and it can wrap private key material that's getting archived. If decryption on an AuthEnvelopedData fails, a Full PKI Response comes back with a CMCFailInfo value of badMessageCheck and a bodyPartID of 0 💀.
3.2.1.4. Other Message Bodies 🎁
The otherMsgSequence field in a PKI Request/Response lets you tuck arbitrary data objects into the request or response 🎒. It's meant for a data object that isn't already wrapped up in a cmsSequence field (Section 3.2.1.3). Heads up: the data object gets ignored unless a control points at it by bodyPartID 👀
OtherMsg ::= SEQUENCE {
bodyPartID BodyPartID,
otherMsgType OTHER-MSG.&id({OtherMsgSet}),
otherMsgValue OTHER-MSG.&Type({OtherMsgSet}{@otherMsgType}) }
The fields in OtherMsg have the following meanings:
bodyPartIDis the unique id identifying this data object.otherMsgTypeis the OID that defines the type of message body.otherMsgValueis the data.
3.2.2. Body Part Identification ✨
Okay so every element inside a PKIData or PKIResponse gets its own body part identifier 🎀 It's a 4-octet integer, and the ASN.1 for it is:
bodyIdMax INTEGER ::= 4294967295
BodyPartID ::= INTEGER(0..bodyIdMax)
The ID lives in the certReqIds field for CertReqMsg objects (inside a TaggedRequest), or in the bodyPartID field of the other objects 💅 Each body part identifier MUST be unique within a single PKIData or PKIResponse 🔒 Different layers are allowed to reuse the same IDs, like a PKIData nested inside another PKIData 🪆
The bodyPartID value of 0 is reserved for pointing at the current PKIData object 🧚
Some controls, like the Add Extensions control (Section 6.5.2), use the body part identifier in the pkiDataReference field to point at a PKI Request in the current PKIData. Other controls, like the Extended CMC Status Info control (Section 6.1.1), will also use body part identifiers to point at elements in the previous PKI Request/Response. This way an error can be super specific about which control or PKI Request it's talking about 🎯
A BodyPartList is a list of body parts in a PKI Request/Response (like the Batch Request control in Section 6.17). Its ASN.1 type is:
BodyPartList ::= SEQUENCE SIZE (1..MAX) OF BodyPartID
A BodyPartPath is a path of body part identifiers that moves through nesting (like the Modify Certification Request control in Section 6.5.1). Its ASN.1 type is:
BodyPartPath ::= SEQUENCE SIZE (1..MAX) OF BodyPartID
3.2.3. CMC Unsigned Data Attribute 🎁
Sometimes a PKI Request has to carry data that an RA is supposed to take out during processing 🫣 An example is an encrypted private key, which a Key Archive Agent removes before sending the request on to the CA. The side effect is that every RA that wraps this info has to move the data so it isn't covered by that RA's signature. (A client PKI Request that's been encapsulated by an RA can't have a signed control removed by the Key Archive Agent without breaking the RA's signature. Major drama 😭) The CMC Unsigned Data attribute is here to fix exactly that 💖
This attribute holds information that a client did not directly sign ✍️ When an RA runs into it in the unsigned or unauthenticated attribute field of a request it's aggregating, the RA takes the CMC Unsigned Data attribute out of the request before the request goes into a cmsSequence. Then it tucks the attribute into the unsigned or unauthenticated attributes of the RA's own signed or authenticated data wrapper 📦
The CMC Unsigned Data attribute is identified by:
id-aa-cmc-unsignedData OBJECT IDENTIFIER ::= { id-aa 34 }
Its ASN.1 definition is:
CMCUnsignedData ::= SEQUENCE {
bodyPartPath BodyPartPath,
identifier TYPE-IDENTIFIER.&id,
content TYPE-IDENTIFIER.&Type
}
The fields in CMCUnsignedData mean the following:
- bodyPartPath is the path pointing to the control associated with this data. When an RA moves the control in an unsigned or unauthenticated attribute up one level as part of wrapping the data in a new SignedData or AuthenticatedData, the body part identifier of the embedded item in the PKIData is prepended to the
bodyPartPathsequence. - identifier is the OID that defines the associated data.
- content is the data.
Here's the rule 🙅♀️ There MUST be at most one CMC Unsigned Data attribute in the UnsignedAttribute sequence of a SignerInfo, or in the UnauthenticatedAttribute sequence of an AuthenticatedData. UnsignedAttribute is a set of values, and the attribute can have any number of values greater than zero in that set. If the CMC Unsigned Data attribute is in one SignerInfo or AuthenticatedData, it MUST appear with the same values(s) in all SignerInfo and AuthenticatedData items.
4. PKI Responses 🌸
There are two flavors of PKI Response, and this section spills the tea on both 🍵
4.1. Simple PKI Response
Clients MUST be able to process the Simple PKI Response 💌 The Simple PKI Response is a SignedData with no EncapsulatedContentInfo and no SignerInfo. The certificates requested in the PKI Response come back in the certificate field of the SignedData.
Clients MUST NOT assume the certificates are in any order 🙈 Servers SHOULD pack in all the intermediate certificates needed to build complete certification paths to one or more trust anchors, not just the shiny new certificate(s) ✨ The server MAY additionally return CRLs in the crls field. Servers MAY include the self-signed certificates. Clients MUST NOT implicitly trust an included self-signed certificate(s) just because it's sitting in the certificates field 🚫 If clients get a new self-signed certificate from the server, clients SHOULD provide a mechanism that lets the user use the certificate as a trust anchor.
Note: The Publish Trust Anchors control (Section 6.15) should be used in the event that the server intends the client to accept one or more certificates as trust anchors. This requires the use of the Full PKI Response message.
4.2. Full PKI Response
Clients MUST be able to process a Full PKI Response 🫶
The Full PKI Response is a SignedData or AuthenticatedData that encapsulates a PKIResponse content type. The certificates issued in a PKI Response come back in the certificates field of the immediately encapsulating SignedData.
Clients MUST NOT assume the certificates are in any order 🙈 Servers SHOULD pack in all the intermediate certificates needed to form complete chains to one or more trust anchors, not just the newly issued certificate(s) 💅 The server MAY additionally return CRLs in the CRL bag. Servers MAY include self-signed certificates. Clients MUST NOT implicitly trust an included self-signed certificate(s) just because it's in the certificates field 🙅♀️ If clients get a new self-signed certificate from the server, clients MAY provide a mechanism that lets the user explicitly use the certificate as a trust anchor.
Note: The Publish Trust Anchors control (Section 6.15) exists for the purpose of allowing for distribution of trust anchor certificates. If a trusted anchor publishes a new trusted anchor, this is one case where automated trust of the new trust anchor could be allowed.
4.2.1. PKIResponse Content Type 🦋
The PKIResponse content type is used for the Full PKI Response. It's identified by:
id-cct-PKIResponse OBJECT IDENTIFIER ::= { id-pkix id-cct(12) 3 }
The ASN.1 structure for the PKIResponse content type is:
PKIResponse ::= SEQUENCE {
controlSequence SEQUENCE SIZE (0..MAX) OF TaggedAttribute,
cmsSequence SEQUENCE SIZE (0..MAX) OF TaggedContentInfo,
otherMsgSequence SEQUENCE SIZE (0..MAX) OF OtherMsg
}
ResponseBody ::= PKIResponse
Note: In [RFC2797], this ASN.1 type was named ResponseBody. It has been renamed to PKIResponse for clarity and the old name kept as a synonym.
The fields in PKIResponse mean the following:
controlSequenceis a sequence of controls. The controls defined in this document are found in Section 6. Controls can be defined by other parties. Details on the TaggedAttribute structure are found in Section 3.2.1.1.cmsSequenceis a sequence of [CMS] message objects. See Section 3.2.1.3 for more details.otherMsgSequenceis a sequence of arbitrary data objects. Data objects placed here are referred to by one or more controls. This lets controls use large amounts of data without that data being embedded in the control. See Section 3.2.1.4 for more details.
Processing of a PKIResponse by a recipient goes like this 📝
- All controls should be examined and processed in an appropriate manner. The appropriate processing is to complete processing at this time, to ignore the control, or to place the control on a to-do list for later processing.
- Additional processing of non-element items includes saving the certificates and CRLs present in wrapping layers. This type of processing is based on the consumer of the element and should not be relied on by generators.
No processing is required for cmsSequence or otherMsgSequence members of the PKIResponse if the items are present and are not referenced by a control. In this case, the cmsSequence and otherMsgSequence members are to be ignored 🫠
5. Application of Encryption to a PKI Request/Response ✨
okay bestie, sometimes a PKI Request or Response has to be encrypted 🔒 so the info inside can't be read by unauthorized entities 🙈. This section explains how to encrypt Full PKI Requests and Responses (Simple PKI Requests cannot be encrypted 💀). Data portions that go in the cmsSequence field can be encrypted separately 🎀.
Confidentiality comes from wrapping the PKI Request/Response (which is a SignedData) in an EnvelopedData or an AuthEnvelopedData 🦋. When you use EnvelopedData or AuthEnvelopedData, the nested content type is id-SignedData. ngl this is different from S/MIME, where a MIME layer sits between the encrypted and signed data for EnvelopedData, and between the authenticated encryption and signed data for AuthEnvelopedData 🙃. It is recommended that if an EnvelopedData or AuthEnvelopedData layer is applied to a PKI Request/Response, a second signature layer be placed outside of the EnvelopedData or AuthEnvelopedData layer. Here's how that nesting works 👇
Normal Option 1 Option 2
------ -------- --------
SignedData EnvelopedData SignedData
PKIData SignedData EnvelopedData
PKIData SignedData
PKIData
| Note: PKIResponse can be substituted for PKIData in the above
| figure.
| Note: AuthEnvelopedData can be substituted for EnvelopedData in
| the above figure.
Options 1 and 2 keep sensitive data safe by encrypting the whole Full PKI Request/Response 🌸. An RA that receives a PKI Request it cannot decrypt MAY reject the PKI Request unless it can process the PKI Request without knowledge of the contents (i.e., all it does is amalgamate multiple PKI Requests and forward them to a server) 💅.
After the RA removes the envelope and finishes processing, it may then apply a new EnvelopedData or AuthEnvelopedData layer to protect PKI Requests for transmission to the next processing agent 🧚. Section 8 has more info about RA processing ✨.
Full PKI Requests/Responses can be encrypted or sent in the clear 🦋. Servers that support EnvelopedData or AuthEnvelopedData MUST provide support for all three EnvelopedData or AuthEnvelopedData options, respectively 👑.
Alternatively, an authenticated, secure channel could exist between the parties that need confidentiality 🔐. Clients and servers MAY use such channels instead of the technique described above to provide secure, private communication of Simple and Full PKI Requests/Responses 💜.
6. Controls 🎀👑
Controls are carried as part of both Full PKI Requests and Responses 💖. Each control is encoded as a unique OID followed by the data for the control (see syntax in Section 3.2.1.1). The encoding of the data depends on the control. Processing systems would first detect the OID (TaggedAttribute attrType) and process the corresponding control value (TaggedAttribute attrValues) before processing the message body 🫶.
The OIDs are all defined under the following arc:
id-pkix OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
dod(6) internet(1) security(5) mechanisms(5) pkix(7) }
id-cmc OBJECT IDENTIFIER ::= { id-pkix 7 }
The table below lists the names, OIDs, and syntactic structures for each of the controls described in this document 🌈.
+============================+========+=====================+=======+
|Identifier Description | OID |ASN.1 Structure |Section|
+============================+========+=====================+=======+
|id-cmc-statusInfo | id-cmc |CMCStatusInfo |Section|
| | 1 | |6.1.2 |
+----------------------------+--------+---------------------+-------+
|id-cmc-identification | id-cmc |UTF8String |Section|
| | 2 | |6.2.3 |
+----------------------------+--------+---------------------+-------+
|id-cmc-identityProof | id-cmc |OCTET STRING |Section|
| | 3 | |6.2.2 |
+----------------------------+--------+---------------------+-------+
|id-cmc-dataReturn | id-cmc |OCTET STRING |Section|
| | 4 | |6.4 |
+----------------------------+--------+---------------------+-------+
|id-cmc-transactionId | id-cmc |INTEGER |Section|
| | 5 | |6.6 |
+----------------------------+--------+---------------------+-------+
|id-cmc-senderNonce | id-cmc |OCTET STRING |Section|
| | 6 | |6.6 |
+----------------------------+--------+---------------------+-------+
|id-cmc-recipientNonce | id-cmc |OCTET STRING |Section|
| | 7 | |6.6 |
+----------------------------+--------+---------------------+-------+
|id-cmc-addExtensions | id-cmc |AddExtensions |Section|
| | 8 | |6.5.2 |
+----------------------------+--------+---------------------+-------+
|id-cmc-encryptedPOP | id-cmc |EncryptedPOP |Section|
| | 9 | |6.7 |
+----------------------------+--------+---------------------+-------+
|id-cmc-decryptedPOP | id-cmc |DecryptedPOP |Section|
| | 10 | |6.7 |
+----------------------------+--------+---------------------+-------+
|id-cmc-lraPOPWitness | id-cmc |LraPopWitness |Section|
| | 11 | |6.8 |
+----------------------------+--------+---------------------+-------+
|id-cmc-getCert | id-cmc |GetCert |Section|
| | 15 | |6.9 |
+----------------------------+--------+---------------------+-------+
|id-cmc-getCRL | id-cmc |GetCRL |Section|
| | 16 | |6.10 |
+----------------------------+--------+---------------------+-------+
|id-cmc-revokeRequest | id-cmc |RevokeRequest |Section|
| | 17 | |6.11 |
+----------------------------+--------+---------------------+-------+
|id-cmc-regInfo | id-cmc |OCTET STRING |Section|
| | 18 | |6.12 |
+----------------------------+--------+---------------------+-------+
|id-cmc-responseInfo | id-cmc |OCTET STRING |Section|
| | 19 | |6.12 |
+----------------------------+--------+---------------------+-------+
|id-cmc-queryPending | id-cmc |OCTET STRING |Section|
| | 21 | |6.13 |
+----------------------------+--------+---------------------+-------+
|id-cmc-popLinkRandom | id-cmc |OCTET STRING |Section|
| | 22 | |6.3.1.3|
+----------------------------+--------+---------------------+-------+
|id-cmc-popLinkWitness | id-cmc |OCTET STRING |Section|
| | 23 | |6.3.1.2|
+----------------------------+--------+---------------------+-------+
|id-cmc-confirmCertAcceptance| id-cmc |IssuerAndSerialNumber|Section|
| | 24 | |6.14 |
+----------------------------+--------+---------------------+-------+
|id-cmc-statusInfoV2 | id-cmc |CMCStatusInfoV2 |Section|
| | 25 | |6.1.1 |
+----------------------------+--------+---------------------+-------+
|id-cmc-trustedAnchors | id-cmc |PublishTrustAnchors |Section|
| | 26 | |6.15 |
+----------------------------+--------+---------------------+-------+
|id-cmc-authData | id-cmc |BodyPartID |Section|
| | 27 | |6.16 |
+----------------------------+--------+---------------------+-------+
|id-cmc-batchRequests | id-cmc |BodyPartList |Section|
| | 28 | |6.17 |
+----------------------------+--------+---------------------+-------+
|id-cmc-batchResponses | id-cmc |BodyPartList |Section|
| | 29 | |6.17 |
+----------------------------+--------+---------------------+-------+
|id-cmc-publishCert | id-cmc |CMCPublicationInfo |Section|
| | 30 | |6.18 |
+----------------------------+--------+---------------------+-------+
|id-cmc-modCertTemplate | id-cmc |ModCertTemplate |Section|
| | 31 | |6.5.1 |
+----------------------------+--------+---------------------+-------+
|id-cmc-controlProcessed | id-cmc |ControlList |Section|
| | 32 | |6.19 |
+----------------------------+--------+---------------------+-------+
|id-cmc-popLinkWitnessV2 | id-cmc |PopLinkWitnessV2 |Section|
| | 33 | |6.3.1.1|
+----------------------------+--------+---------------------+-------+
|id-cmc-identityProofV2 | id-cmc |IdentityProofV2 |Section|
| | 34 | |6.2.1 |
+----------------------------+--------+---------------------+-------+
|id-cmc-raIdentityWitness | id-cmc |BodyPartPath |Section|
| | 35 | |6.20 |
+----------------------------+--------+---------------------+-------+
|id-cmc-responseBody | id-cmc |BodyPartPath |Section|
| | 37 | |6.21 |
+----------------------------+--------+---------------------+-------+
Table 1: CMC Control Attributes
6.1. CMC Status Info Controls 📊
The CMC Status Info controls tell you the status of a client/server request/response 🍓. Two controls are described in this section 💜. The Extended CMC Status Info control is the preferred one ✨, and the CMC Status Info control is included for backward compatibility with [RFC2797] 🦋.
Servers MAY emit multiple CMC Status Info controls referring to a single body part 🧚. Clients MUST be able to deal with multiple CMC Status Info controls in a PKI Response 💅. Servers MUST use the Extended CMC Status Info control, but they MAY additionally use the CMC Status Info control 🌸. Clients MUST be able to process the Extended CMC Status Info control 🫶.
6.1.1. Extended CMC Status Info Control ✨
Okay so this is the glow-up version of the status info control 💅 bestie, it's giving v2 but make it iconic. Its OID is:
id-cmc-statusInfoV2 OBJECT IDENTIFIER ::= { id-cmc 25 }
And here's the ASN.1 definition, the main character of this whole section 🎀:
CMCStatusInfoV2 ::= SEQUENCE {
cMCStatus CMCStatus,
bodyList SEQUENCE SIZE (1..MAX) OF
BodyPartReference,
statusString UTF8String OPTIONAL,
otherInfo CHOICE {
failInfo CMCFailInfo,
pendInfo PendInfo,
extendedFailInfo [1] SEQUENCE {
failInfoOID TYPE-IDENTIFIER.&id
({ExtendedFailures}),
failInfoValue TYPE-IDENTIFIER.&Type
({ExtendedFailures}
{@.failInfoOID})
}
} OPTIONAL
}
PendInfo ::= SEQUENCE {
pendToken OCTET STRING,
pendTime GeneralizedTime
}
BodyPartReference ::= CHOICE {
bodyPartID BodyPartID,
bodyPartPath BodyPartPath
}
So what does each field actually mean? 🧐
cMCStatuscontains the returned status value. Details are in Section 6.1.3.bodyListidentifies the controls or other elements to which the status value applies. If an error is returned for a Simple PKI Request, this field is thebodyPartIDchoice ofBodyPartReferencewith the single integer of value 1.statusStringcontains additional description information. This string is human readable.otherInfocontains additional information that expands on the CMC status code returned in thecMCStatusfield.
Now the fields in otherStatusInfo 👀:
failInfois described in Section 6.1.4. It provides an error code that details what failure occurred. This choice is present only ifcMCStatuscontains the valuefailed.pendInfocontains information about when and how the client should request the result of this request. It is present when thecMCStatusis eitherpendingorpartial.pendInfouses the structurePendInfo, which has the fields:pendTokenis the token used in the Query Pending control (Section 6.13).pendTimecontains the suggested time the server wants to be queried about the status of the certification request.
extendedFailInfoincludes application-dependent detailed error information. This choice is present only ifcMCStatuscontains the valuefailed. Caution should be used when defining new values as they may not be correctly recognized by all clients and servers. TheCMCFailInfovalue ofinternalCAErrormay be assumed if the extended error is not recognized. This field uses the typeExtendedFailInfo.ExtendedFailInfohas the fields:failInfoOIDcontains an OID that is associated with a set of extended error values.failInfoValuecontains an extended error code from the defined set of extended error codes.
If the cMCStatus field is success, the Extended CMC Status Info control MAY be omitted unless it is the only item in the response. no cap, that's the whole deal 🫶
6.1.2. CMC Status Info Control 🌸
The classic status info control, the OG 🦋 Its OID is:
id-cmc-statusInfo OBJECT IDENTIFIER ::= { id-cmc 1 }
Its ASN.1 definition is:
CMCStatusInfo ::= SEQUENCE {
cMCStatus CMCStatus,
bodyList BodyPartList,
statusString UTF8String OPTIONAL,
otherInfo CHOICE {
failInfo CMCFailInfo,
pendInfo PendInfo } OPTIONAL
}
The fields in CMCStatusInfo mean:
cMCStatuscontains the returned status value. Details are in Section 6.1.3.bodyListcontains the list of controls or other elements to which the status value applies. If an error is being returned for a Simple PKI Request, this field contains a single integer of value 1.statusStringcontains additional description information. This string is human readable.otherInfoprovides additional information that expands on the CMC status code returned in thecMCStatusfield.failInfois described in Section 6.1.4. It provides an error code that details what failure occurred. This choice is present only ifcMCStatusisfailed.pendInfouses thePendInfoASN.1 structure in Section 6.1.1. It contains information about when and how the client should request results of this request. ThependInfofield MUST be populated for acMCStatusvalue ofpendingorpartial. Further details can be found in Sections 6.1.1 and 6.13.
If the cMCStatus field is success, the CMC Status Info control MAY be omitted unless it is the only item in the response. If no status exists for a Simple or Full PKI Request, then the value of success is assumed.
6.1.3. CMCStatus Values 📊
CMCStatus is the field living inside both status info controls, and it's basically the vibe check for whatever operation just happened. It contains a code showing the success or failure of a specific operation. Its ASN.1 structure is:
CMCStatus ::= INTEGER {
success (0),
-- reserved (1),
failed (2),
pending (3),
noSupport (4),
confirmRequired (5),
popRequired (6),
partial (7)
}
Here's what each value means 💖
successindicates the request was granted or the action was completed.failedindicates the request was not granted or the action was not completed. More information is included elsewhere in the response.pendingindicates the PKI Request has yet to be processed. The requester is responsible to poll back on this Full PKI Request.pendingmay only be returned for certification request operations.noSupportindicates the requested operation is not supported.confirmRequiredindicates a Confirm Certificate Acceptance control (Section 6.14) must be returned before the certificate can be used.popRequiredindicates a direct POP operation is required (Section 6.3.1.3).partialindicates a partial PKI Response is returned. The requester is responsible to poll back for the unfulfilled portions of the Full PKI Request.
6.1.4. CMCFailInfo 💀
CMCFailInfo is also a field in both status info controls, and it gives you the deets on why something failed. It conveys more detailed information relevant to interpreting a failure condition. Its ASN.1 structure is:
CMCFailInfo ::= INTEGER {
badAlg (0),
badMessageCheck (1),
badRequest (2),
badTime (3),
badCertId (4),
unsupportedExt (5),
mustArchiveKeys (6),
badIdentity (7),
popRequired (8),
popFailed (9),
noKeyReuse (10),
internalCAError (11),
tryLater (12),
authDataFail (13)
}
The values of CMCFailInfo mean:
badAlgindicates unrecognized or unsupported algorithm.badMessageCheckindicates integrity check failed.badRequestindicates transaction was not permitted or supported.badTimeindicates message time field was not sufficiently close to the system time.badCertIdindicates no certificate could be identified matching the provided criteria.unsupportedExtindicates a requested X.509 extension is not supported by the recipient CA.mustArchiveKeysindicates private key material must be supplied.badIdentityindicates identification control failed to verify.popRequiredindicates server requires a POP before issuing certificate.popFailedindicates POP processing failed.noKeyReuseindicates server policy does not allow key reuse.internalCAErrorindicates that the CA had an unknown internal failure.tryLaterindicates that the server is not accepting requests at this time and the client should try at a later time.authDataFailindicates failure occurred during processing of authenticated data.
Okay, the important part 🧚: if you need extra failure reasons, they SHOULD use the ExtendedFailureInfo item in the Extended CMC Status Info control. For closed environments, they can be defined using this type instead. Such codes MUST be in the range from 1000 to 1999 ✨
6.2. Identification and Identity Proof Controls 🔐
Some CAs and RAs require a Proof-of-Identity in a certification request. There are lots of ways to do this, with different levels of security and reliability. Everyone has met the bank asking for your mom's maiden name 🙄 The reasoning behind requiring a Proof-of-Identity can be found in Appendix C of [CRMF].
CMC gives you a way to prove the client's identity using a client/server shared-secret. If clients support the Full PKI Request, clients MUST implement this method of Proof-of-Identity (Section 6.2.1). Servers MUST provide this method, but they MAY additionally support bilateral methods of similar strength.
This document also gives you an Identification control (Section 6.2.3) 🌈 It's a simple way for a client to say who they are to the server. Generally, a shared-secret AND an identifier of that shared-secret are passed from the server to the client. The identifier goes in the Identification control, and the shared-secret is used to compute the Identity Proof or Identity Proof v2 control.
6.2.1. Identity Proof Version 2 Control ✨
okay so the Identity Proof Version 2 control is identified by this OID 🦋
id-cmc-identityProofV2 OBJECT IDENTIFIER ::= { id-cmc 34 }
and its ASN.1 definition looks like this 💅
IdentityProofV2 ::= SEQUENCE {
proofAlgID AlgorithmIdentifier{DIGEST-ALGORITHM,
{WitnessAlgs}},
macAlgID AlgorithmIdentifier{MAC-ALGORITHM, {POPAlgs}},
witness OCTET STRING
}
ok so the fields have their own little jobs 🧚
proofAlgIDis the identifier and parameters for the hash algorithm used to convert the shared-secret into a key for the MAC algorithm.macAlgIDis the identifier and the parameters for the message authentication code algorithm used to compute the value of the witness field.witnessis the Proof-of-Identity. 🔥
the required method starts with an out-of-band transfer of a token (the shared-secret) 🎀 and the shared-secret should be generated in a random manner. the distribution of this token is beyond the scope of this document 🙈. then the client provides Proof-of-Identity with this token like this:
- The
PKIDatareqSequencefield (encoded exactly as it appears in the Full PKI Request including the sequence type and length) is the value to be validated. - A hash of the shared-secret as a UTF-8 string is computed using
proofAlgID. - A MAC is then computed using the value produced in Step 1 as the message and the value from Step 2 as the key.
- The result from Step 3 is then encoded as the
witnessvalue in the Identity Proof Version 2 control.
when the server verifies the Identity Proof Version 2 control, it computes the MAC value in the same way and compares it to the witness value contained in the PKI Request. 💜
if a server fails the verification of an Identity Proof Version 2 control, the CMCFailInfo value MUST be present in the Full PKI Response and MUST have a value of badIdentity. 😭
reusing the shared-secret on certification request retries lets the client and server keep the same view of acceptable Proof-of-Identity values. BUT reusing the shared-secret can potentially open the door for some types of attacks. 💀
Implementations MUST be able to support tokens that are at least 16 characters long. Guidance on the amount of entropy actually obtained from a given length token based on character sets can be found in Appendix A of [PASSWORD]. 🌈
6.2.2. Identity Proof Control
the Identity Proof control is identified by this OID 🌸
id-cmc-identityProof OBJECT IDENTIFIER ::= { id-cmc 3 }
and it has this ASN.1 definition 🍓
IdentityProof ::= OCTET STRING
this control gets processed the same way as the Identity Proof Version 2 control, just with fixed algorithms. the hash algorithm is fixed to SHA-1 and the MAC algorithm is fixed to HMAC-SHA1. ✨
6.2.3. Identification Control
okay so servers MAY require the inclusion of the unprotected Identification control with an Identification Proof control. 🫶 The Identification control is meant to hold a text string that helps the server find the shared-secret it needs to validate the contents of the Identity Proof control.
if the Identification control is included in the Full PKI Request, the derivation of the key in Step 2 (from Section 6.2.1) changes. instead of hashing just the shared-secret, you hash the concatenation of the shared-secret and the UTF-8 identity value (without the type and length bytes). main character energy 👑
its OID is:
id-cmc-identification OBJECT IDENTIFIER ::= { id-cmc 2 }
and its ASN.1 definition is:
Identification ::= UTF8String
6.2.4. Hardware Shared-Secret Token Generation
sometimes the shared-secret between the EE and the server gets computed by a hardware device that spits out a series of tokens 🔥. so the EE can prove its identity by sending this token in plain text along with a name string. the protocol above works with a hardware shared-secret token generation device if you make these changes:
- The Identification control MUST be included and MUST contain the hardware-generated token.
- The shared-secret value used above is the same hardware-generated token.
- All certification requests MUST have a subject name, and the subject name MUST contain the fields required to identify the holder of the hardware token device.
- The entire certification request MUST be shrouded in some fashion to prevent eavesdropping.
the token is time critical, so an active eavesdropper cannot be allowed to grab it and submit a different certification request with the same token value. not on my watch 😤
6.3. Linking Identity and POP Information
in a CMC Full PKI Request, Proof-of-Identity info about the client is carried in one of three places: the certificate tied to the signature of the SignedData that holds the certification requests, one of the two Identity Proof controls, or the MAC computed for the AuthenticatedData that holds the certification requests. POP info for key pairs, though, is carried separately for each PKCS #10 or CRMF. (for keys that can make a digital signature, the POP comes from the signature on the PKCS #10 or CRMF. for encryption-only keys, the controls in Section 6.7 are used.) 🦋 to stop substitution-style attacks, the protocol must guarantee that the same entity supplied both the POP and Proof-of-Identity information.
we describe three ways to link identity and POP info: witness values cryptographically derived from a shared-secret (Section 6.3.1), shared-secret/subject name matching (Section 6.3.2), and subject name matching to an existing certificate (Section 6.3.3). Clients and servers MUST support the witness value and the certificate-linking techniques. Clients and servers MAY support shared-secret/name matching or MAY support other bilateral techniques of similar strength. 💅 the idea behind the first two is to make the client sign some data into each certification request that can be directly tied to the shared-secret. this blocks anyone from sneaking certification requests from different entities into a single Full PKI Request 🚫
6.3.1. Cryptographic Linkage
the first technique forces the client to put a piece of info, cryptographically derived from the shared-secret, into each certification request (PKCS #10 or CRMF) as a signed extension. 🧚
6.3.1.1. POP Link Witness Version 2 Controls
the POP Link Witness Version 2 control is identified by this OID 🌈
id-cmc-popLinkWitnessV2 OBJECT IDENTIFIER ::= { id-cmc 33 }
and its ASN.1 definition is:
PopLinkWitnessV2 ::= SEQUENCE {
keyGenAlgorithm AlgorithmIdentifier{KEY-DERIVATION,
{KeyDevAlgs}},
macAlgorithm AlgorithmIdentifier{MAC-ALGORITHM, {POPAlgs}},
witness OCTET STRING
}
the fields work like this:
keyGenAlgorithmcontains the algorithm used to generate the key for the MAC algorithm. This will generally be a hash algorithm, but it could be a more complex algorithm.macAlgorithmcontains the algorithm used to create the witness value.witnesscontains the computed witness value. ✨
this technique is useful if NULL subject Distinguished Names (DNs) are used (because, for example, the server can generate the subject DN for the certificate based only on the shared-secret) 🎀. processing starts when the client gets the shared-secret out-of-band from the server. then the client computes these values:
- The client generates a random byte-string, R, which SHOULD be at least 512 bits in length.
- The key is computed from the shared-secret using the algorithm in
keyGenAlgorithm. - A MAC is then computed over the random value produced in Step 1, using the key computed in Step 2.
- The random value produced in Step 1 is encoded as the value of a POP Link Random control. This control MUST be included in the Full PKI Request.
- The MAC value produced in Step 3 is placed in either the POP Link Witness control or the
witnessfield of the POP Link Witness V2 control.- For CRMF, the POP Link Witness / POP Link Witness V2 control is included in the controls field of the CertRequest structure.
- For PKCS #10, the POP Link Witness / POP Link Witness V2 control is included in the attributes field of the CertificationRequestInfo structure.
when the server gets this, it MUST verify that each certification request contains a copy of the POP Link Witness / POP Link Witness V2 control, and that its value was derived using the method above from the shared-secret and the random string in the POP Link Random control. 🔍
the Identification control (Section 6.2.3) or the subject DN of a certification request can help figure out which shared-secret was used. 💖
6.3.1.2. POP Link Witness Control
the POP Link Witness control is identified by this OID 🌸
id-cmc-popLinkWitness OBJECT IDENTIFIER ::= { id-cmc 23 }
and its ASN.1 definition is:
PopLinkWitness ::= OCTET STRING
for this control, SHA-1 is used as the key generation algorithm and HMAC-SHA1 is used as the MAC algorithm. 🍓
6.3.1.3. POP Link Random Control
the POP Link Random control is identified by this OID 🧚
id-cmc-popLinkRandom OBJECT IDENTIFIER ::= { id-cmc 22 }
and its ASN.1 definition is:
PopLinkRandom ::= OCTET STRING
6.3.2. Shared-Secret/Subject DN Linking ✨
okay so the second way to link identity and POP info is to tie a specific subject DN to the shared-secrets that get handed out out-of-band 🫶. Then the client has to put that exact subject DN in every single certification request when it proves who it is. literally every one 💅 no skipping! I think a LOT of client-server connections using shared-secret-based Proof-of-Identity are gonna go this route 🔥
| Note: It is common to include the subject DN information from
| the certification request.
So when the shared-secret gets made and sent out-of-band to kick off registration (Section 6.2), a particular subject DN gets attached to it and passed along to the client too 🎀. (Quick tea: the subject DN generated MUST be unique per entity, following the CA policy, and you cannot use a NULL subject DN 🙅♀️. A common move is putting the identification value inside the subject DN 🌸.) When the client builds the Full PKI Request, it MUST use these two pieces of info like this:
- The client MUST include the specific subject DN that it received along with the shared-secret as the subject name in every certification request (PKCS #10 and/or CRMF) in the Full PKI Request. The subject names in the certification requests MUST NOT be NULL. 🙈
- The client MUST include an Identity Proof control (Section 6.2.2) or Identity Proof Version 2 control (Section 6.2.1), derived from the shared-secret, in the Full PKI Request. 🧚
The server receiving this message MUST (a) validate the Identity Proof control and then (b) check that the subject DN included in each certification request matches the one associated with the shared-secret. If either of these checks fails, the certification request MUST be rejected. no exceptions, bestie 💀
6.3.3. Existing Certificate Linking 🦋
Linking the POP to an identity is honestly so easy when you're working with an existing certificate 😌. The client copies all of the naming info from the existing certificate (the subject field and the Subject Alternative Name extension) into the new certification request. Then the POP on the new public key happens when the new key signs the identity info, which links the POP to one specific identity. After that, the identity info gets tied to the POP info by signing the entire enrollment request with the private key of the existing certificate. ✨
Existing certificate linking can be used in these situations:
- When replacing a certificate by doing a renewal or rekey certification request. 🔄
- Using an existing certificate to get a new certificate. An example would be getting a key establishment certificate after you've already gotten a signature certificate. 🔑
- Using a third-party certificate to get a new certificate from a CA. An example would be using a certificate and key pair that came with a device to prove an identity. This requires that the CA have an out-of-band channel to map the identity in the device certificate to the new EE identity. it's giving trust chain vibes 🌈
6.4. Data Return Control 🎁
The Data Return control lets clients send arbitrary data (usually some kind of internal state info) to the server and have that data sent back as part of the Full PKI Response 💜. The data inside a Data Return control is treated as opaque by the server, so the server isn't reading into it 👀. The same control is used for both Full PKI Requests and Responses. If the Data Return control shows up in a Full PKI Request, the server MUST return it as part of the PKI Response. 💅
If the info in the Data Return control needs to stay confidential, the client is expected to apply some kind of encryption to the contained data 🔐. The details of that are outside the scope of this specification, so it's a whole other story 📖.
The Data Return control is identified by the OID:
id-cmc-dataReturn OBJECT IDENTIFIER ::= { id-cmc 4 }
The Data Return control has the ASN.1 definition:
DataReturn ::= OCTET STRING
A client could use this control to put an identifier on the exact source of the private key material. This might be the identifier of a hardware device that holds the private key 🧩.
6.5. RA Certificate Modification Controls 🛠️
These controls exist so RAs can modify the contents of a certification request 🪄. Modifications might be needed for different reasons, like adding certificate extensions or changing the subject and/or subject alternative names 🌸.
There are two controls for this. The first one, Modify Certification Request (Section 6.5.1), lets the RA replace or remove any field in the certificate 🔁. The second one, Add Extensions (Section 6.5.2), only lets the RA add extensions ➕.
6.5.1. Modify Certification Request Control 💖
The Modify Certification Request control is how RAs change fields in a requested certificate ✏️.
The Modify Certification Request control is identified by the OID:
id-cmc-modCertTemplate OBJECT IDENTIFIER ::= { id-cmc 31 }
The Modify Certification Request has the ASN.1 definition:
ModCertTemplate ::= SEQUENCE {
pkiDataReference BodyPartPath,
certReferences BodyPartList,
replace BOOLEAN DEFAULT TRUE,
certTemplate CertTemplate
}
Here's what the fields in ModCertTemplate mean 🍓:
- pkiDataReference is the path to the PKI Request containing the certification request(s) to be modified.
- certReferences refers to one or more certification requests in the PKI Request referenced by pkiDataReference that are to be modified. Each BodyPartID of the certReferences sequence MUST be equal to either the bodyPartID of a TaggedCertificationRequest (PKCS #10) or the certReqId of the CertRequest within a CertReqMsg (CRMF). By definition, the certificate extensions included in the certTemplate field are applied to every certification request referenced in the certReferences sequence. If a request corresponding to bodyPartID cannot be found, the CMCFailInfo with a value of
badRequestis returned that references this control. 🙃 - replace specifies whether the target certification request is modified by replacing or deleting fields. If the value is TRUE, the data in this control replaces the data in the target certification request. If the value is FALSE, the data in the target certification request is deleted. The action is slightly different for the extensions field of certTemplate, because each extension is treated individually rather than as a single unit 🧐.
- certTemplate is a certificate template object [CRMF][ADD-ASN1]. If a field is present and replace is TRUE, it replaces that field in the certification request. If the field is present and replace is FALSE, the field in the certification request is removed. If the field is absent, no action is performed. Each extension is treated as a single field.
Servers MUST be able to process all extensions defined, but not prohibited, in [PKIXCERT]. Servers are not required to be able to process every X.509v3 extension transmitted using this protocol, nor are they required to be able to process other, private extensions. Servers are not required to put all RA-requested extensions into a certificate. Servers are permitted to modify RA-requested extensions. Servers MUST NOT alter an extension so as to reverse the meaning of a client-requested extension. If a certification request is denied because the server can't handle a requested extension and a Full PKI Response is returned, the server MUST return a CMCFailInfo value with the value of unsupportedExt. this part is lowkey important, so read it twice 👀
If a certification request is the target of multiple Modify Certification Request controls, the behavior is:
- If control A exists in a layer that contains the layer of control B, control A MUST override control B. In other words, controls should be applied from the innermost layer to the outermost layer. 🪆
- If control A and control B are in the same PKIData (i.e., the same wrapping layer), the order of application is non-determinate. 🎲
The same order of application is used if a certification request is the target of both a Modify Certification Request control and an Add Extensions control. ✨
6.5.2. Add Extensions Control 🌷
The Add Extensions control has been deprecated in favor of the Modify Certification Request control 🙊. It was replaced so that fields in the certification request other than extensions could be modified too 💜.
The Add Extensions control is how RAs specify additional extensions to be included in certificates ➕.
The Add Extensions control is identified by the OID:
id-cmc-addExtensions OBJECT IDENTIFIER ::= { id-cmc 8 }
The Add Extensions control has the ASN.1 definition:
AddExtensions ::= SEQUENCE {
pkiDataReference BodyPartID,
certReferences SEQUENCE OF BodyPartID,
extensions SEQUENCE OF Extension{{CertExtensions}}
}
Here's what the fields in AddExtensions mean 🧁:
- pkiDataReference contains the body part identity of the embedded certification request.
- certReferences is a list of references to one or more of the certification requests contained within a PKIData. Each body part identifier of the certReferences sequence MUST be equal to either the bodyPartID of a TaggedCertificationRequest (PKCS #10) or the certReqId of the CertRequest within a CertReqMsg (CRMF). By definition, the listed extensions are applied to every certification request referenced in the certReferences sequence. If a certification request corresponding to bodyPartID cannot be found, the CMCFailInfo with a value of
badRequestis returned referencing this control. 😬 - extensions is a sequence of extensions to be applied to the referenced certification requests.
Servers MUST be able to process all extensions defined, but not prohibited, in [PKIXCERT]. Servers are not required to be able to process every X.509v3 extension transmitted using this protocol, nor are they required to be able to process other, private extensions. Servers are not required to put all RA-requested extensions into a certificate. Servers are permitted to modify RA-requested extensions. Servers MUST NOT alter an extension so as to reverse the meaning of a client-requested extension. If a certification request is denied because the server can't handle a requested extension and a response is returned, the server MUST return a CMCFailInfo with the value of unsupportedExt. 🫶
If multiple Add Extensions controls exist in a Full PKI Request, the exact behavior is left up to the CA policy. However, it is recommended that the following policy be used. These rules are applied to individual extensions within an Add Extensions control (as opposed to an "all or nothing" approach) 🍬.
- If the conflict is within a single PKIData, the certification request would be rejected with a CMCFailInfo value of
badRequest. 🚫 - If the conflict is between different PKIData, the outermost version of the extension would be used (allowing an RA to override the requested extension). 👑
6.6. Transaction Identifier Control and Sender and Recipient Nonce Controls ✨
Okay bestie, so transactions get tracked with a transaction identifier 🎀 (it's only used if you're using one!). Clients generate these and hold onto the value until the server sends back a Full PKI Response that completes the transaction. The server then pops the received transaction identifiers right into that Full PKI Response 💖.
The Transaction Identifier control is identified by the OID:
id-cmc-transactionId OBJECT IDENTIFIER ::= { id-cmc 5 }
Here's the ASN.1 definition:
TransactionId ::= INTEGER
The Transaction Identifier control is basically how clients and servers know which transaction is which 🧚. It's used by both sides to manage the state of an operation. Clients MAY include a Transaction Identifier control in a request. If the original request contains a Transaction Identifier control, all subsequent requests and responses MUST include the same Transaction Identifier control. No switching IDs mid-convo, periodt 💅.
Replay protection is a whole vibe, and it's handled with the Sender and Recipient Nonce controls 🦋. If nonces are used, the first message of a transaction doesn't carry a Recipient Nonce control. Instead, the transaction originator includes a Sender Nonce control and hangs onto it for later reference. When the recipient gets a Sender Nonce control, it reflects that value right back to the originator as a Recipient Nonce control, and it adds its own Sender Nonce control. When the originator gets that response, it checks the Recipient Nonce control against the value it saved. If they match, the message can be accepted for further security processing ✅. The received value of a Sender Nonce control also gets saved, so it can be used in the next message of the same transaction 🌈.
The Sender Nonce and Recipient Nonce controls are identified by the OIDs:
id-cmc-senderNonce OBJECT IDENTIFIER ::= { id-cmc 6 }
id-cmc-recipientNonce OBJECT IDENTIFIER ::= { id-cmc 7 }
The Sender Nonce control has the ASN.1 definition:
SenderNonce ::= OCTET STRING
The Recipient Nonce control has the ASN.1 definition:
RecipientNonce ::= OCTET STRING
Clients MAY include a Sender Nonce control in the initial PKI Request. If a message includes a Sender Nonce control, the response MUST include the transmitted value of the previously received Sender Nonce control as a Recipient Nonce control and include a new value as its Sender Nonce control. Echo, echo, echo 🫶.
6.7. Encrypted and Decrypted POP Controls 🔐
Servers MAY require that this POP method be used only if another POP method is unavailable. Servers SHOULD reject all certification requests contained within a PKIData if any required POP is missing for any element within the PKIData 🙈.
Lots of servers want proof that the entity who made the certification request actually has the matching private component of the key pair 👑. For keys that can be used as signature keys, signing the certification request with the private key counts as a POP on that key pair ✍️. But for keys that can only do encryption, POP MUST be performed by making the client decrypt a value. Check out Section 5 of [CRMF] if you want the full tea on POP 🍵.
Honestly, POP for encryption-only keys can't happen in one round trip, because there are four distinct steps 💀:
- Client tells the server about the public component of a new encryption key pair.
- Server sends the client a POP challenge, encrypted with the presented public encryption key.
- Client decrypts the POP challenge using the private key that corresponds to the presented public key and uses it for computing a keyed hash value sent back to the server.
- Server validates the decrypted POP challenge and continues processing the certification request.
CMC defines two different controls for this 🌸. The first one deals with the encrypted challenge that the server sends to the user in Step 2. The second one deals with the value derived from the decrypted challenge that the client sends back to the server in Step 3.
The Encrypted POP control is used to send the encrypted challenge from the server to the client as part of the PKIResponse.
| Note: It is assumed that the message sent in Step 1 above is a
| Full PKI Request and that the response in Step 2 is a Full PKI
| Response including a CMCFailInfo specifying that a POP is
| explicitly required, and providing the POP challenge in the
| Encrypted POP control.
The Encrypted POP control is identified by the OID:
id-cmc-encryptedPOP OBJECT IDENTIFIER ::= { id-cmc 9 }
The Encrypted POP control has the ASN.1 definition:
EncryptedPOP ::= SEQUENCE {
request TaggedRequest,
cms ContentInfo,
thePOPAlgID AlgorithmIdentifier{MAC-ALGORITHM, {POPAlgs}},
witnessAlgID AlgorithmIdentifier{DIGEST-ALGORITHM,
{WitnessAlgs}},
witness OCTET STRING
}
The Decrypted POP control is identified by the OID:
id-cmc-decryptedPOP OBJECT IDENTIFIER ::= { id-cmc 10 }
The Decrypted POP control has the ASN.1 definition:
DecryptedPOP ::= SEQUENCE {
bodyPartID BodyPartID,
thePOPAlgID AlgorithmIdentifier{MAC-ALGORITHM, {POPAlgs}},
thePOP OCTET STRING
}
Okay, so here's how the encrypted POP algorithm works 🧠:
- The server randomly generates the POP Proof Value and associates it with the request.
- The server returns the Encrypted POP control with the following fields set:
- request is the original certification request (it is included here so the client need not keep a copy of the request).
- cms is an EnvelopedData or AuthEnvelopedData, the encapsulated content type being id-data and the content being the POP Proof Value; this value needs to be long enough that one cannot reverse the value from the witness hash. If the certification request contains a Subject Key Identifier (SKI) extension, then the recipient identifier SHOULD be the SKI. If the issuerAndSerialNumber form is used, the IssuerName MUST be encoded as NULL and the SerialNumber as the bodyPartID of the certification request.
- thePOPAlgID identifies the algorithm to be used in computing the return POP value.
- witnessAlgID identifies the hash algorithm used on the POP Proof Value to create the field witness.
- witness is the hashed value of the POP Proof Value.
- The client decrypts the cms field to obtain the POP Proof Value. The client computes H(POP Proof Value) using the witnessAlgID and compares to the value of witness. If the values do not compare or the decryption is not successful, the client MUST abort the enrollment process. The client aborts the process by sending a request containing an Extended CMC Status Info or a CMC Status Info control with CMCFailInfo value of popFailed. Yikes, no enrollment for you 😭.
- The client creates the Decrypted POP control as part of a new PKIData. The fields in the DecryptedPOP are:
- bodyPartID refers to the certification request in the new PKI Request.
- thePOPAlgID is copied from the encryptedPOP.
- thePOP contains the possession proof. This value is computed by thePOPAlgID using the POP Proof Value and the request.
- The server then re-computes the value of thePOP from its cached value and the request and compares to the value of thePOP. If the values do not match, the server MUST NOT issue the certificate. The server MAY reissue a new challenge or MAY fail the request altogether 🥀.
When defining the algorithms for thePOPAlgID and witnessAlgID, care must be taken to make sure the result of witnessAlgID isn't a useful value that shortcuts the computation with thePOPAlgID 🕵️♀️. The POP Proof Value is used as the secret value in the HMAC algorithm and the request is used as the data. If the POP Proof Value is greater than 64 bytes, only the first 64 bytes of the POP Proof Value is used as the secret.
One potential problem with the algorithm above is how much state a CA needs to keep in order to verify the returned POP value 📚. The following describes one of many possible ways to fix this by reducing the amount of state kept on the CA to a single (or small set) of values. Main character, stateless energy 👑.
- Server generates random seed x, constant across all requests. (The value of x would normally be altered on a regular basis and kept for a short time afterwards.)
- For certification request R, server computes y = F(x,R). F can be, for example,
HMAC-SHA256(x,R). All that's important for statelessness is that y be consistently computable with only known state constant x and function F, other inputs coming from the certification request structure. y should not be predictable based on knowledge of R, thus the use of a one-way function like HMAC-SHA256 🔒.
6.8. RA POP Witness Control 🦋
In a certification request scenario that involves an RA, the CA may allow (or require) that the RA perform the POP protocol with the entity that generated the certification request. In this case, the RA needs a way to tell the CA that it has already done the POP, and that's exactly what the RA POP Witness control is for 🫶.
The RA POP Witness control is identified by the OID:
id-cmc-lraPOPWitness OBJECT IDENTIFIER ::= { id-cmc 11 }
The RA POP Witness control has the ASN.1 definition:
LraPopWitness ::= SEQUENCE {
pkiDataBodyid BodyPartID,
bodyIds SEQUENCE OF BodyPartID
}
The fields in LraPopWitness have the following meaning:
- pkiDataBodyid contains the body part identifier of the nested TaggedContentInfo containing the client's Full PKI Request. pkiDataBodyid is set to 0 if the request is in the current PKIData.
- bodyIds is a list of certification requests for which the RA has performed an out-of-band authentication. The method of authentication could be archival of private key material, challenge-response, or other means.
If a certification server doesn't let an RA do the POP verification, it returns a CMCFailInfo with the value of popFailed. The CA MUST NOT start a challenge-response to reverify the POP itself. No double-checking, no drama 🚫.
6.9. Get Certificate Control 🧚
Everything described in this section is optional to implement. 🌷
The Get Certificate control is used to retrieve a previously issued certificate from a certificate repository 📥. A CA, an RA, or an independent service may provide this repository. The clients expected to use this facility are those where a fully deployed directory is either infeasible or undesirable 🍓.
The Get Certificate control is identified by the OID:
id-cmc-getCert OBJECT IDENTIFIER ::= { id-cmc 15 }
The Get Certificate control has the ASN.1 definition:
GetCert ::= SEQUENCE {
issuerName GeneralName,
serialNumber INTEGER }
The fields in GetCert have the following meaning:
- issuerName is the name of the certificate issuer.
- serialNumber identifies the certificate to be retrieved.
The server that responds to this request places the requested certificate in the certificates field of a SignedData. If the Get Certificate control is the only control in a Full PKI Request, the response should be a Simple PKI Response. Easy, breezy, beautiful 💖✨.
6.10. Get CRL Control 🧚
Everything in this section is optional to implement, so no pressure, bestie 🫶 The Get CRL control is how you grab CRLs from a repository of CRLs 📜 A CA, an RA, or an independent service can run that repository. It's for clients where a fully deployed directory is either infeasible or undesirable, so it's giving practical 💅
The Get CRL control is identified by the OID:
id-cmc-getCRL OBJECT IDENTIFIER ::= { id-cmc 16 }
The Get CRL control has the ASN.1 definition:
GetCRL ::= SEQUENCE {
issuerName Name,
cRLName GeneralName OPTIONAL,
time GeneralizedTime OPTIONAL,
reasons ReasonFlags OPTIONAL }
Here's what each field means 👀
issuerNameis the name of the CRL issuer.cRLNamemay be the value ofCRLDistributionPointsin the subject certificate, or an equivalent value in the event the certificate does not contain such a value.timeis how the client picks, from among potentially several issues of CRL, the one whosethisUpdatevalue is less than but nearest to the specified time. In the absence of a time component, the CA always returns the most recent CRL. ⏰reasonsis how the client picks, from among CRLs partitioned by revocation reason. Implementers should bear in mind that while a specific revocation request has a singleCRLReasoncode -- and consequently entries in the CRL would have a singleCRLReasoncode value -- a single CRL can aggregate information for one or morereasonFlags. 🧠
A server responding to this request places the requested CRL in the crls field of a SignedData. If the Get CRL control is the only control in a Full PKI Request, the response should be a Simple PKI Response. 🎀
6.11. Revocation Request Control 🚫
The Revocation Request control is how you ask for a certificate to be revoked 🙅♀️
The Revocation Request control is identified by the OID:
id-cmc-revokeRequest OBJECT IDENTIFIER ::= { id-cmc 17 }
The Revocation Request control has the ASN.1 definition:
RevokeRequest ::= SEQUENCE {
issuerName Name,
serialNumber INTEGER,
reason CRLReason,
invalidityDate GeneralizedTime OPTIONAL,
sharedSecret OCTET STRING OPTIONAL,
comment UTF8string OPTIONAL }
The fields of RevokeRequest mean the following:
issuerNameis the name of the certificate issuer.serialNumberis the serial number of the certificate to be revoked.reasonis the suggestedCRLReasoncode for why the certificate is being revoked. The CA can use this value at its discretion in building the CRL.invalidityDateis the suggested value for the Invalidity Date CRL Extension. The CA can use this value at its discretion in building the CRL.sharedSecretis a secret value registered by the EE when the certificate was obtained, so it can be revoked in the event of key loss. 🔑commentis a human-readable comment. 💬
Okay, the big deal here is proof. ngl, for a revocation request to be reliable in a dispute, you need a strong proof-of-origin 🕵️♀️ But if an EE has lost use of its signature private key, it can't produce a digital signature (until a new signature key pair is certified). That's where the Revoke Request control comes in clutch: it lets the EE send the CA a shared-secret that can act as an alternative authenticator when the signature private key is lost. Whether that's acceptable is a matter of local security policy.
It's also possible to sign the revocation for the lost certificate with a different certificate in some circumstances. A client can sign a revocation for an encryption key with a signing certificate if the name information matches. Similarly, an administrator or RA can be assigned the ability to revoke the certificate of a third party. The server's acceptance of the revocation depends on local policy in these cases. 👑
Now the rules 📋 Clients MUST provide the capability to produce a digitally signed Revocation Request control. Clients SHOULD be capable of producing an unsigned Revocation Request control containing the EE shared-secret (the unsigned message consisting of a SignedData with no signatures). If a client provides shared-secret-based self-revocation, the client MUST be capable of producing a Revocation Request control containing the shared-secret. Servers MUST be capable of accepting both forms of revocation requests.
The structure of an unsigned, shared-secret-based revocation request is a matter of local implementation. The shared-secret does not need to be encrypted when sent in a Revocation Request control. The shared-secret has a one-time use (i.e., it is used to request revocation of the certificate), and public knowledge of the shared-secret after the certificate has been revoked is not a problem. Clients need to inform users that the same shared-secret SHOULD NOT be used for multiple certificates. 🙅♀️🔑
A Full PKI Response MUST be returned for a revocation request. 💌
6.12. Registration and Response Information Controls 📝
The Registration Information control lets clients pass additional information as part of a Full PKI Request.
The Registration Information control is identified by the OID:
id-cmc-regInfo OBJECT IDENTIFIER ::= { id-cmc 18 }
The Registration Information control has the ASN.1 definition:
RegInfo ::= OCTET STRING
The content of this data is based on bilateral agreement between the client and server. 🤝
The Response Information control lets a server return additional information as part of a Full PKI Response.
The Response Information control is identified by the OID:
id-cmc-responseInfo OBJECT IDENTIFIER ::= { id-cmc 19 }
The Response Information control has the ASN.1 definition:
ResponseInfo ::= OCTET STRING
The content of this data is based on bilateral agreement between the client and server. 🤝
6.13. Query Pending Control ⏳
In some environments, manual intervention or other identity checks can delay the return of the certificate, and it's so annoying 🙄 The Query Pending control lets clients ask a server about the state of a pending certification request. The server returns a pendToken as part of the Extended CMC Status Info and the CMC Status Info controls (in the otherInfo field). The client copies that pendToken into the Query Pending control so the server knows exactly which certification request is being asked about. The server also returns a suggested time for the client to query the state of the pending certification request again. 🦋
The Query Pending control is identified by the OID:
id-cmc-queryPending OBJECT IDENTIFIER ::= { id-cmc 21 }
The Query Pending control has the ASN.1 definition:
QueryPending ::= OCTET STRING
If a server returns a pending or partial CMCStatusInfo (the transaction is still pending), the otherInfo MAY be omitted. If the otherInfo is not omitted, the value of pendInfo MUST be the same as the original pendInfo value. 🌸
6.14. Confirm Certificate Acceptance Control ✅
Some CAs want clients to give a positive confirmation that the certificates issued to the EE are acceptable. That's what the Confirm Certificate Acceptance control is for 💖 If the CMC Status Info on a PKI Response is confirmRequired, then the client MUST return a Confirm Certificate Acceptance control contained in a Full PKI Request.
Clients SHOULD wait for the PKI Response from the server saying the confirmation has been received before using the certificate for any purpose. Patience is a whole vibe 🧘♀️
The Confirm Certificate Acceptance control is identified by the OID:
id-cmc-confirmCertAcceptance OBJECT IDENTIFIER ::= { id-cmc 24 }
The Confirm Certificate Acceptance control has the ASN.1 definition:
CMCCertId ::= IssuerAndSerialNumber
CMCCertId contains the issuer and serial number of the certificate being accepted.
Servers MUST return a Full PKI Response for a Confirm Certificate Acceptance control.
Note that if the CA includes this control, there will be two full round trips of messages, as follows: 🔁
- The client sends the certification request to the CA.
- The CA returns a Full PKI Response with the certificate and this control.
- The client sends a Full PKI Request to the CA with an Extended CMC Status Info or a CMC Status Info control accepting and a Confirm Certificate Acceptance control, or an Extended CMC Status Info or a CMC Status Info control rejecting the certificate.
- The CA sends a Full PKI Response to the client with an Extended CMC Status Info of success.
6.15. Publish Trust Anchors Control 🛡️
The Publish Trust Anchors control lets a central authority distribute a set of trust anchors to an EE. The same control is also used to update that set of trust anchors 🌈 Trust anchors are distributed in the form of certificates. These are expected, but not required, to be self-signed certificates. Information is extracted from these certificates to set the inputs to the certificate validation algorithm in Section 6.1.1 of [PKIXCERT].
The Publish Trust Anchors control is identified by the OID:
id-cmc-trustedAnchors OBJECT IDENTIFIER ::= { id-cmc 26 }
The Publish Trust Anchors control has the ASN.1 definition:
PublishTrustAnchors ::= SEQUENCE {
seqNumber INTEGER,
hashAlgorithm AlgorithmIdentifier{DIGEST-ALGORITHM,
{HashAlgorithms}},
anchorHashes SEQUENCE OF OCTET STRING
}
The fields in PublishTrustAnchors mean the following:
seqNumberis an integer indicating the location within a sequence of updates. 🔢hashAlgorithmis the identifier and parameters for the hash algorithm used in computing the values of theanchorHashesfield. All implementations MUST implement SHA-256 for this field. 🔐anchorHashesare the hashes for the certificates that are to be treated as trust anchors by the client. The actual certificates are transported in thecertificatesfield of the containing SignedData structure.
While it is recommended that the sender place the certificates that are to be trusted in the PKI Response, it is not required, since the certificates should be obtainable using normal discovery techniques. 🔍
Before accepting the trust anchor's changes, a client MUST at least do the following: validate the signature on the PKI Response to a current trusted anchor, check with policy to ensure that the signer is permitted to use the control, validate that the authenticated publish time in the signature is near to the current time, and validate that the sequence number is greater than the previously used one. ✅
If multiple agents publish a set of trust anchors, it's up to local policy to decide how the different trust anchors should be combined. Clients SHOULD be able to handle the update of multiple trust anchors independently. 🧩
Heads up 🚨 Clients that handle this control must use extreme care in validating that the operation is permissible. Incorrect handling of this control allows an attacker to change the set of trust anchors on the client. Be careful out there, bestie 💀
6.16. Authenticated Data Control 🔐✨
Okay bestie, the Authenticated Data control lets a server send data back to the client in an authenticated way 🔐, so the client can validate that data 💅. It's for when the client already shares a secret and a secret identifier with the server, but the trust anchor hasn't been downloaded onto the client yet 🥺. That means the server's signing certificate can't be validated yet. This control was created for the Publish Trust Anchors control (Section 6.15), but it can totally be used in other cases too 💖.
The Authenticated Data control is identified by the OID:
id-cmc-authData OBJECT IDENTIFIER ::= { id-cmc 27 }
The Authenticated Data control has the ASN.1 definition:
AuthPublish ::= BodyPartID
AuthPublish is a body part identifier that refers to a member of the cmsSequence element for the current PKI Response or PKI Data 🎯. The cmsSequence element is AuthenticatedData, and the encapsulated content is an id-cct-PKIData. The controls in the controlSequence need to be processed if the authentication succeeds ✅.
Note: One example is the Publish Trust Anchors control in Section 6.15.
If the authentication operation fails, the CMCFailInfo authDataFail is returned 💀.
6.17. Batch Request and Response Controls 📦
These controls let an RA collect multiple requests together into a single Full PKI Request and forward it to a CA 📬. The server then processes them and sends the results back in a Full PKI Response 🫶.
The Batch Request control is identified by the OID:
id-cmc-batchRequests OBJECT IDENTIFIER ::= { id-cmc 28 }
The Batch Response control is identified by the OID:
id-cmc-batchResponses OBJECT IDENTIFIER ::= { id-cmc 29 }
Both the Batch Request and Batch Response controls have the ASN.1 definition:
BodyPartList ::= SEQUENCE OF BodyPartID
The data for these controls is a set of body part identifiers. Each request or response gets placed as its own entry in the cmcSequence of the new PKIData or PKIResponse 🗂️. Then the body part identifiers of those entries go into the body part list attached to the control.
When a server processes a Batch Request control, it MAY return the responses in one or more PKI Responses 🌸. A CMCStatus value of partial is returned on all but the last PKI Response. The CMCStatus would be success if the Batch Request control was processed, and the responses get their own CMCStatus codes. Errors on individual requests are not propagated up to the top level 🙈.
When a PKI Response with a CMCStatus value of partial comes back, the Query Pending control (Section 6.13) gets used to retrieve the additional results 🔁. The returned status includes a suggested time after which the client should ask for those additional results ⏰.
6.18. Publication Information Control 📰
The Publication Information control lets you modify the publication of certificates that have already been issued, whether that's publishing them or removing them from publication 🗞️. A super common use is removing an existing certificate from publication during a rekey operation 🔑. This control should always be processed after the issuance of new certificates and revocation requests. This control should not be processed if a certificate failed to be issued ❌.
The Publication Information control is identified by the OID:
id-cmc-publishCert OBJECT IDENTIFIER ::= { id-cmc 30 }
The Publication Information control has the ASN.1 definition:
CMCPublicationInfo ::= SEQUENCE {
hashAlg AlgorithmIdentifier{DIGEST-ALGORITHM,
{HashAlgorithms}},
certHashes SEQUENCE OF OCTET STRING,
pubInfo PKIPublicationInfo
}
PKIPublicationInfo ::= SEQUENCE {
action INTEGER {
dontPublish (0),
pleasePublish (1) },
pubInfos SEQUENCE SIZE (1..MAX) OF SinglePubInfo OPTIONAL }
-- pubInfos MUST NOT be present if action is "dontPublish"
-- (if action is "pleasePublish" and pubInfos is omitted,
-- "dontCare" is assumed)
SinglePubInfo ::= SEQUENCE {
pubMethod INTEGER {
dontCare (0),
x500 (1),
web (2),
ldap (3) },
pubLocation GeneralName OPTIONAL }
}
The fields in CMCPublicationInfo have the following meanings 🧾:
hashAlgis the algorithm identifier of the hash algorithm used to compute the values incertHashes.certHashesare the hashes of the certificates whose publication is about to change.pubInfois the info about where and how the certificates should be published. The fields inpubInfo(taken from [CRMF][ADD-ASN1]) have the following meanings:actionindicates the action the service should take. It has two values:dontPublishindicates that the PKI should not publish the certificate (this may indicate that the requester intends to publish the certificate themselves).dontPublishhas the added connotation of removing from publication the certificate if it is already published 🙅♀️.pleasePublishindicates that the PKI MAY publish the certificate using whatever means it chooses unlesspubInfosis present. Omission of the CMC Publication Info control results in the same behavior 🌈.
pubInfosindicates how (e.g., X.500, Web, IP Address) the PKI SHOULD publish the certificate 📣.
A single certificate SHOULD NOT appear in more than one Publication Information control. The behavior is undefined in the event that it does 👀.
6.19. Control Processed Control 🙋♀️
The Control Processed control lets an RA tell later control processors that a specific control has already been processed 🤝. That way an RA in the middle of a processing stream can handle a control that's defined either in a local context or in a later document 🧩.
The Control Processed control is identified by the OID:
id-cmc-controlProcessed OBJECT IDENTIFIER ::= { id-cmc 32 }
The Control Processed control has the ASN.1 definition:
ControlList ::= SEQUENCE {
bodyList SEQUENCE SIZE (1..MAX) OF BodyPartReference
}
bodyListis a series of body part identifiers that form a path to each of the controls that were processed by the RA. This control is only needed for those controls that are not part of this standard, and so would cause an error condition for a server trying to deal with a control not defined in this document 🧐. No error status is needed, since an error makes the RA return the request to the client with the error instead of passing it on to the next server in the processing list 🚫.
6.20. RA Identity Proof Witness Control 🕵️♀️💖
The RA Identity Proof Witness control lets an RA tell subsequent control processors that all of the Proof-of-Identity requirements have been met 🪪. This lets the Proof-of-Identity happen at a location closer to the EE 📍. For example, the Proof-of-Identity could be done at lots of physical locations, while the CA operates on a company-wide basis 🏢. The RA does the Proof-of-Identity, plus any other tasks that need the secret, and the CA is kept from ever knowing the secret 🤐. If checks related to Proof-of-Identity fail, then the RA returns an error to the client that says so 🚨.
The RA Identity Proof Witness control is identified by the OID:
id-cmc-raIdentityWitness OBJECT IDENTIFIER ::= { id-cmc 35 }
The RA Identity Proof Witness control has the ASN.1 definition:
cmc-raIdentityWitness CMC-CONTROL ::=
{ BodyPartPath IDENTIFIED BY id-cmc-raIdentityWitness }
cmc-raIdentityWitnessis a CMC-CONTROL associating the OIDid-cmc-raIdentityWitnessand the typeBodyPartPath. This object is omitted from the 1988 module. The object is added to the object setCmc-Control-Set. The control is permitted to appear only in the control sequence of a PKIData object. It MUST NOT appear in the control sequence of a PKIResponse. The control is permitted to be used only by an RA. The control may appear multiple times in a control sequence, with each occurrence pointing to a different object.id-cmc-raIdentityWitnessis the OID used to identify this CMC control 🏷️.BodyPartPathis the type structure associated with the control. The syntax ofBodyPartPathis defined in Section 3.2.2. The path contains a sequence of body part identifiers leading to one of the following items:- Identity Proof control if the RA verified the Proof-of-Identity in this control.
- Identity Proof Version 2 control if the RA verified the Proof-of-Identity in this control.
- Full PKI Request if the RA performed an out-of-band identity proof for this request. The request SHOULD NOT contain either Identity Proof control.
- Simple PKI Request if the RA performed an out-of-band identity proof for this request.
The RA Identity Proof Witness control will frequently be paired with a Modify Certification Request control, which changes the name fields in the associated certification requests ✏️. That's because the RA knows the actual name to be assigned to the entity requesting the certificate, and the EE doesn't have the name details yet 🫠.
Note: The association would be set up by the operator at the time the shared-secret was generated by the RA.
When this control is placed in a message, it is RECOMMENDED that the Control Processed control be placed in the body sequence as well 💅. Relying on the explicit new control, instead of implicitly relying on the Control Processed control, matters because it's crucial to know explicitly which Proof-of-Identity have been performed 🔍. The new control also lets an RA say that out-of-band Proof-of-Identity have been performed 🌟.
When the Proof-of-Identity is performed by an RA, the RA also MUST validate the linking between the Proof-of-Identity and the name information wrapped inside of the key proof-of-possession 🔗💜.
6.21. Response Body Control 🎀
okay so the Response Body control is how an RA tells an EE "hey, there's an embedded response message in here that MUST be processed as part of handling this message" 💌 It's built for cases where the RA did some extra work on the certification request, like key generation 🔑 When an RA generates a key pair for an EE, the RA MUST respond with both the original response message from the certificate issuer (the one with the actual certificate issuance) and the RA's own response (the one with the new key), so the EE gets everything it needs 🫶 Another case is when the secret is shared between the RA and the EE (instead of between the CA and the EE) and the RA returns the Publish Trust Anchors control to populate the correct trust points 📍
The Response Body control is identified by the OID:
id-cmc-responseBody OBJECT IDENTIFIER ::= { id-cmc 37 }
The Response Body control has the ASN.1 definition:
cmc-responseBody CMC-CONTROL ::=
{ BodyPartPath IDENTIFIED BY id-cmc-responseBody }
cmc-responseBodyis a CMC-CONTROL associating the OIDid-cmc-responseBodywith the typeBodyPartPath. This object is omitted from the 1988 module. The object is added to the object setCmc-Control-Set. The control is permitted to appear only in the control sequence of a PKIResponse. The control MUST NOT appear in the control sequence of a PKIData. It is expected that only an intermediary RA will use this control; a CA generally does not need the control as it is creating the original innermost message. 💅id-cmc-responseBodyis the OID used to identify this CMC control.BodyPartPathis the type structure associated with the control. The syntax ofBodyPartPathis defined in Section 3.2.2. The path contains a sequence of body part identifiers leading to a cmsSequence item, which contains a PKIResponse within it. 🧚
7. Other Attributes ✨
there are a bunch of places where different kinds of attributes can live, in either a CMC request or a CMC response message 🗺️ These places include the attribute sequence of a PKCS #10 request, controls in Section 6 of [CRMF], and the various CMS attribute sequences.
7.1. Change Subject Name Attribute 💖
The Client Name Change Request attribute is for when a client wants to ask for a name change as part of a certification request 🪄 Because of security issues, you can't just swap the requested subject's name in the certificate template, no matter how cute that sounds 🙅♀️ The name in the certification request MUST match the name in the certificate used to verify the request, so that identity and possession proofs get applied correctly 🔐
The relevant ASN.1 for the Client Name Change Request attribute is as follows:
at-cmc-changeSubjectName ATTRIBUTE ::= {
TYPE ChangeSubjectName IDENTIFIED BY id-cmc-changeSubjectName }
id-cmc-changeSubjectName OBJECT IDENTIFIER ::= { id-cmc 36 }
ChangeSubjectName ::= SEQUENCE {
subject Name OPTIONAL,
subjectAlt [1] GeneralNames OPTIONAL
}
(WITH COMPONENTS {..., subject PRESENT} |
WITH COMPONENTS {..., subjectAlt PRESENT} )
The attribute is designed to be used as an ATTRIBUTE object. So the attribute goes in one of these two places:
- The attributes field in a CertificationRequest.
- The controls field of a CertRequest for a CRMF.
The control is identified by the OID id-cmc-changeSubjectName.
The ASN.1 type associated with the control is ChangeSubjectName. The fields of the structure are set up like this:
subjectcontains the requested subject name for the new certificate.subjectAltcontains the requested subject alternative name for the new certificate.
At least one of the fields in the sequence MUST be present when encoding the structure. 🫶
When the CA processes this attribute in a certification request, it does the following:
- If present, the
subjectfield is copied to thenamefield of the template. If thesubjectfield is absent, thenamefield of the template will be set to an empty sequence. - If present, the
subjectAltfield is used as the content of a Subject Alternative Name extension in the certificate. If thesubjectAltfield is absent, the Subject Alternative Name extension is removed from the certificate template. 🎀
8. Registration Authorities 🌸
this spec allows the use of RAs 🙌 An RA sits between the EE and the CA. From the EE's perspective, the RA looks like the CA, and from the server's perspective, the RA looks like a client 🪞 RAs receive the PKI Requests, do some local processing, and then forward them to CAs. Some of the local processing an RA can do includes:
- Batching multiple PKI Requests together,
- Performing challenge/response POP proofs,
- Adding private or standardized certificate extensions to all certification requests,
- Archiving private key material,
- Routing requests to different CAs.
When an RA receives a PKI Request, it has three options: it may forward the PKI Request without modification, it may add a new wrapping layer to the PKI Request, or it may remove one or more existing layers and add a new wrapping layer. 🎁
When an RA adds a new wrapping layer to a PKI Request, it creates a new PKIData. The new layer holds any controls that are required (for example, if the RA does the POP proof for an encryption key, or the Add Extension control to modify a PKI Request) and the client PKI Request. The client PKI Request goes in the cmsSequence if it is a Full PKI Request, and in the reqSequence if it is a Simple PKI Request. If an RA is batching multiple client PKI Requests together, then each client PKI Request goes into the appropriate location in the RA's PKIData object, along with all the relevant controls. 📦
If multiple RAs sit in the path between the EE and the CA, this leads to multiple wrapping layers on the request. 🧅
In processing a PKI Request, an RA MUST NOT alter any certification requests (PKCS #10 or CRMF), because any alteration would invalidate the signature on the certification request and thus the POP for the private key. 🚫
Here's how that looks in the following figure:
SignedData (by RA)
PKIData
controlSequence
RA added control statements
reqSequence
Zero or more Simple PKI Requests from clients
cmsSequence
Zero or more Full PKI Requests from clients
SignedData (signed by client)
PKIData
Under some circumstances, an RA is required to remove wrapping layers. The following sections look at the processing required if encryption, signing, and authenticated encryption layers need to be removed. 🫧
8.1. Encryption Removal
There are two cases that require an RA to remove or change encryption in a PKI Request. Both cases are true regardless of whether EnvelopedData or AuthEnvelopedData is used. In the first case, the encryption was applied to protect the entire PKI Request from unauthorized entities. If the CA does not have a RecipientInfo entry in the encryption layer, the RA MUST remove the encryption layer. The RA MAY add a new encryption layer, with or without adding a new signing layer. 🔓
The second change of encryption that may be required is changing the encryption inside of a signing layer. In this case, the RA MUST remove all signing layers containing the encryption. All control statements MUST be merged according to local policy rules as each signing layer is removed, and the resulting merged controls MUST be placed in a new signing layer provided by the RA. If the signing layer provided by the EE also needs to be removed, the RA can remove this layer too. 🔁
8.2. Signature Layer Removal
There are only two instances where an RA should remove a signature layer on a Full PKI Request: if an encryption layer needs to be modified within the request, or if a CA will not accept secondary delegation (i.e., multiple RA signatures). In all other situations, RAs SHOULD NOT remove a signing layer from a PKI Request. 🙅♀️
If an RA removes a signing layer from a PKI Request, all control statements MUST be merged according to local policy rules. The resulting merged control statements MUST be placed in a new signing layer provided by the RA. 🧩
9. CMC Infrastructure Certificate Requirements 👑
Certificates for servers used in the CMC protocol SHOULD conform to the profile defined in [PKIXCERT]. This document defines some additional items that MAY appear in CMC server certificates. Section 9.1 defines some additional values for the EKU extension. Section 9.2 defines a Subject Information Access value that lets a CMC certificate publish information on how to contact the services it provides. 📇
9.1. Extended Key Usage
The EKU extension is used to restrict the use of a certificate to specific applications. This document defines three different EKUs. The ASN.1 for these EKUs is:
id-kp-cmcCA OBJECT IDENTIFIER ::= { id-kp 27 }
id-kp-cmcRA OBJECT IDENTIFIER ::= { id-kp 28 }
id-kp-cmcArchive OBJECT IDENTIFIER ::= { id-kp 29 }
Here's the usage description for each of the EKUs:
- CMC CAs are identified by the
id-kp-cmcCAEKU. The certificate may be the same as or different from the CA certificate. If a different certificate is used, the certificates containing theid-kp-cmcCAEKU SHOULD have the same name as the certificate used for issuing the certificates. (Using a separate key pair for CMC protocol operations and for issuing certificates and CRLs decreases the number of operations for which the private key used to sign certificates and CRLs would be used.) 🔑 - CMC Registration Authorities are identified by the
id-kp-cmcRAEKU. This usage is placed into RA certificates. 🌷 - CMC Archive Servers are identified by the
id-kp-cmcArchiveEKU. CMC Archive Servers and the associated protocol are to be defined in a future document. 🔮
9.2. Subject Information Access ✨
Okay so the Subject Information Access extension is where you say how to reach info and services about the certificate's subject 📍 This doc defines a value for this extension that points to where CMC services will be hanging out 🎀 If this value shows up in a certificate, an appropriate EKU from Section 9.1 MUST be included in that certificate too, no skipping bestie 🙅♀️
The id-ad-cmc OID is for when the subject offers certification services using the CMC protocol 💅 If the CMC services are on HTTP or FTP (see Section 2 of [CMC-TRANS] and Section 4 of [CMC-TRANS]), the accessLocation MUST be a uniformResourceIdentifier 🌐 If they're over electronic mail (see Section 3 of [CMC-TRANS]), accessLocation MUST be an rfc822Name 💌 If CMC services run over TCP/IP (see Section 5 of [CMC-TRANS]), then the dNSName or iPAddress name forms MUST be used 🔌
Here's the tea: GeneralName doesn't let you include a port number, so unless you've got other external configuration info, the value of 5318 should be used 🧚 (The port registration is in Section 7 of [CMC-TRANS].) As for other name forms of accessLocation when accessMethod is id-ad-cmc, this specification doesn't define their semantics, so don't go guessing 🙈
The ASN.1 type for this extension is GeneralName (see Section 4.2.1.8 of [PKIXCERT]) 🤓
id-ad-cmc OBJECT IDENTIFIER ::= { id-ad 12 }
10. Security Considerations 🔐
Replay attacks are a whole thing, bestie 🙀 Depending on the operational environment, you may need mechanisms for thwarting them in particular implementations of this protocol. If the CA keeps significant state information, replay attacks may be detectable even without the optional nonce mechanisms. Implementers need to think carefully about environmental conditions before deciding whether or not to implement the Sender Nonce and Recipient Nonce controls from Section 6.6. Developers of state-constrained PKI clients are strongly encouraged to use these controls 🫶
Be extremely careful when archiving a signing key 😬 Whoever holds the archived key might be able to use it to generate forged signatures. That said, there are real reasons a signing key should be archived 💀 An archived CA signing key can be recovered if the CA fails to keep producing CRLs after a disaster 🌪️
Due care must be taken before archiving keys 🗝️ Once a key is given to an archiving entity, that entity could use the keys in a way that isn't conducive to the archiving entity. Users should be made especially aware that proper verification is done on the certificate used to encrypt the private key material 🔍
Clients and servers need to run some checks on cryptographic parameters before issuing certificates, so weak parameters don't sneak through 🕵️♀️ The small subgroup attack is described in [X942], and methods of avoiding it can be found in [SMALL-GROUP]. CMC implementations ought to be aware of this attack when doing parameter validations 👑
When you're using a shared-secret for authentication, that shared-secret should be generated using good random number techniques [RANDOM] 🎲 If users pick the secret themselves, it allows dictionary attacks to be mounted, so, like, don't do that 🙅♀️
Extreme care must be used when processing the Publish Trust Anchors control 🚨 Incorrect processing can lead to slamming, where an attacker changes the set of trusted anchors in order to weaken security. Yikes 😭
Here's one way to control the use of the Publish Trust Anchors control 💜 The client needs to associate each trust anchor it accepts with the source of that trust anchor. The client should also associate each trust anchor with the types of messages it's valid for (i.e., is the trust anchor used for validating S/MIME messages, TLS, or CMC enrollment messages?) 🧠
When a new message comes in with a Publish Trust Anchors control, the client would accept the new set of trust anchors for specific applications only if the signature validates, the signer of the message has the required policy approval for updating the trust anchors, and local policy also allows updating the trust anchors. Three checks, no shortcuts 💅
The CMS AuthenticatedData structure gives you message integrity, but it doesn't give you message authentication in all cases 🥺 When using MACs in this document, the following restrictions need to be observed. All messages should be for a single entity. If two entities are placed in a single message, they can generate new messages that have a valid MAC and might be assumed to come from the original message sender. Every entity with access to the shared-secret can generate messages that pass MAC validation, so keep that value secret 🤫 Whenever possible, the SignedData structure should be used in preference to the AuthenticatedData structure 🌸
A bunch of controls, like the RA Identity Proof Witness control, let an RA either make assertions about or modify a certification request 📝 Any upstream request processor, such as a CA, MUST verify that the RA is fully identified and authorized to make the assertion or modification it's claiming. If the RA isn't identified or authorized, then any request MUST be rejected 🛑
CMC servers, both RAs and CAs, need to do their due diligence when checking the contents of a certification request 🧐 At an absolute minimum, all fields should be checked so the policies of the CA/RA are correctly enforced. Every field needs checking, but names, name forms, algorithm choices, and algorithm parameters deserve extra special care 💖
The vulnerability noted in [Str23] is mitigated in Full PKI Requests and Responses, because signed attributes are always present and id-data is always used with a media type ✅ The vulnerability noted in [Str23] isn't applicable to Simple PKI Requests or Responses, because no content encryption is applied 🦋
11. IANA Considerations 📋
This document defines a number of CMC-related control objects, ASN.1 modules, extended key purposes, and content types 🌈 All of them are identified by OIDs. The OIDs are defined from an arc delegated by IANA to the PKIX Working Group, with the notable exception of one S/MIME attribute. All registrations follow ✨
For the ASN.1 modules in Appendix A, IANA has assigned an OID for the module identifier 124 with a Description of id-mod-enrollMsgSyntax-2025 in Appendix A.1, and an OID for the module identifier 125 with a Description of id-mod-pbkdf2-prfs-2025 in Appendix A.2 🎀 The OIDs for the modules should be allocated in the "SMI Security for PKIX Module Identifier" registry [PKIX-MODIDS] 🗂️
IANA has replaced the references for the following S/MIME attributes found in the "SMI Security for S/MIME Attributes" registry [SMIME-ATTRS] with a pointer to this document 💌
id-aa-cmc-unsignedData
IANA has replaced the references for the following key purposes found in the "SMI Security for PKIX Extended Key Purpose" registry [PKIX-EKPS] with a pointer to this document 🔑
id-kp-cmcCAid-kp-cmcRAid-kp-cmcArchive
IANA has replaced the references for the following signature algorithm found in the "SMI Security for PKIX Algorithms" registry [IANA-PKIX-ALGS] with a pointer to this document 🧾
id-alg-noSignature
IANA has replaced the references for the following CMC controls found in the "SMI Security for PKIX CMC Controls" registry [CMC-CTRLS] with a pointer to this document 🫧
id-cmc-statusInfoid-cmc-identificationid-cmc-identityProofid-cmc-dataReturnid-cmc-transactionIdid-cmc-senderNonceid-cmc-recipientNonceid-cmc-addExtensionsid-cmc-encryptedPOPid-cmc-decryptedPOPid-cmc-lraPOPWitnessid-cmc-getCertid-cmc-getCRLid-cmc-revokeRequestid-cmc-regInfoid-cmc-responseInfoid-cmc-queryPendingid-cmc-popLinkRandomid-cmc-popLinkWitnessid-cmc-confirmCertAcceptanceid-cmc-statusInfoV2id-cmc-trustedAnchorsid-cmc-authDataid-cmc-batchRequestsid-cmc-batchResponsesid-cmc-publishCertid-cmc-modCertTemplateid-cmc-controlProcessedid-cmc-popLinkWitnessV2id-cmc-identityProofV2id-cmc-raIdentityWitnessid-cmc-changeSubjectNameid-cmc-responseBody
IANA has replaced the references for the following CMC content types found in the "SMI Security for PKIX CMC Content Types" registry [CMC-CTS] with a pointer to this document 📦
id-cct-PKIDataid-cct-PKIResponse
IANA has replaced the references for the following PKIX access descriptor found in the "SMI Security for PKIX Access Descriptor" registry [PKIX-ADS] with a pointer to this document 🛰️
id-ad-cmc
IANA is to note that the references for the following module OIDs in the "SMI Security for PKIX Module Identifier" registry [PKIX-MODIDS] are to remain unchanged, as these modules remain unchanged by this specification 🙌
id-mod-cmcid-mod-cmc2002id-mod-enrollMsgSyntax-2011-88id-mod-enrollMsgSyntax-2011-08
Likewise, the id-cmc-glaRR entry in the "SMI Security for PKIX CMC Controls" registry and all entries in the "SMI Security for PKIX CMC Controls" and "SMI Security for PKIX CMC GLA Requests and Responses" registries are to remain unchanged 💜
12. References 📚
12.1. Normative References ✨
okay bestie, these are the refs you actually need to read if you're building this stuff 📚💖
[ADD-ASN1]Hoffman, P. and J. Schaad, "New ASN.1 Modules for the Public Key Infrastructure Using X.509 (PKIX)", RFC 5912, DOI 10.17487/RFC5912, June 2010,<https://www.rfc-editor.org/info/rfc5912>.[ASN.1]ITU-T, "Information technology -- Abstract Syntax Notation One (ASN.1): Specification of basic notation", ITU-T Recommendation X.680, ISO/IEC 8824-1:2021, February 2021,<https://www.itu.int/rec/T-REC-X.680>.[CMS]Housley, R., "Cryptographic Message Syntax (CMS)", STD 70, RFC 5652, DOI 10.17487/RFC5652, September 2009,<https://www.rfc-editor.org/info/rfc5652>.[CMS-AE]Housley, R., "Cryptographic Message Syntax (CMS) Authenticated-Enveloped-Data Content Type", RFC 5083, DOI 10.17487/RFC5083, November 2007,<https://www.rfc-editor.org/info/rfc5083>.[CMS-ALGS]Hoffman, P. and J. Schaad, "New ASN.1 Modules for Cryptographic Message Syntax (CMS) and S/MIME", RFC 5911, DOI 10.17487/RFC5911, June 2010,<https://www.rfc-editor.org/info/rfc5911>.[CRMF]Schaad, J., "Internet X.509 Public Key Infrastructure Certificate Request Message Format (CRMF)", RFC 4211, DOI 10.17487/RFC4211, September 2005,<https://www.rfc-editor.org/info/rfc4211>.[DH-POP]Schaad, J. and H. Prafullchandra, "Diffie-Hellman Proof-of-Possession Algorithms", RFC 6955, DOI 10.17487/RFC6955, May 2013,<https://www.rfc-editor.org/info/rfc6955>.[HMAC-ALGS]Schaad, J. and S. Turner, "Additional New ASN.1 Modules for the Cryptographic Message Syntax (CMS) and the Public Key Infrastructure Using X.509 (PKIX)", RFC 6268, DOI 10.17487/RFC6268, July 2011,<https://www.rfc-editor.org/info/rfc6268>.[PKCS10]Nystrom, M. and B. Kaliski, "PKCS #10: Certification Request Syntax Specification Version 1.7", RFC 2986, DOI 10.17487/RFC2986, November 2000,<https://www.rfc-editor.org/info/rfc2986>.[PKIXCERT]Cooper, D., Santesson, S., Farrell, S., Boeyen, S., Housley, R., and W. Polk, "Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile", RFC 5280, DOI 10.17487/RFC5280, May 2008,<https://www.rfc-editor.org/info/rfc5280>.[RFC2119]Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997,<https://www.rfc-editor.org/info/rfc2119>.[RFC8174]Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017,<https://www.rfc-editor.org/info/rfc8174>.
12.2. Informative References 💅
these ones are the extra reading 🌸 the background stuff, the errata, and the registries
[CMC-COMPL]Mandel, J., Ed. and S. Turner, Ed., "Certificate Management over CMS (CMC): Compliance Requirements", RFC 10004, DOI 10.17487/RFC10004, July 2026,<https://www.rfc-editor.org/info/rfc10004>.[CMC-CTRLS]IANA, "SMI Security for PKIX CMC Controls",<https://www.iana.org/assignments/smi-numbers/>.[CMC-CTS]IANA, "SMI Security for PKIX CMC Content Types",<https://www.iana.org/assignments/smi-numbers/>.[CMC-PROTv1]Schaad, J. and M. Myers, "Certificate Management over CMS (CMC)", RFC 5272, DOI 10.17487/RFC5272, June 2008,<https://www.rfc-editor.org/info/rfc5272>.[CMC-TRANS]Mandel, J., Ed. and S. Turner, Ed., "Certificate Management over CMS (CMC): Transport Protocols", RFC 10003, DOI 10.17487/RFC10003, July 2026,<https://www.rfc-editor.org/info/rfc10003>.[CMC-Updates]Schaad, J., "Certificate Management over CMS (CMC) Updates", RFC 6402, DOI 10.17487/RFC6402, November 2011,<https://www.rfc-editor.org/info/rfc6402>.[CMS-KEM]Housley, R., Gray, J., and T. Okubo, "Using Key Encapsulation Mechanism (KEM) Algorithms in the Cryptographic Message Syntax (CMS)", RFC 9629, DOI 10.17487/RFC9629, August 2024,<https://www.rfc-editor.org/info/rfc9629>.[Err2063]RFC Errata, Erratum 2063, RFC 5272,<https://www.rfc-editor.org/errata/eid2063>.[Err2731]RFC Errata, Erratum 2731, RFC 5272,<https://www.rfc-editor.org/errata/eid2731>.[Err3943]RFC Errata, Erratum 3943, RFC 6402,<https://www.rfc-editor.org/errata/eid3943>.[Err4775]RFC Errata, Erratum 4775, RFC 5272,<https://www.rfc-editor.org/errata/eid4775>.[Err5931]RFC Errata, Erratum 5931, RFC 6402,<https://www.rfc-editor.org/errata/eid5931>.[Err6571]RFC Errata, Erratum 6571, RFC 6402,<https://www.rfc-editor.org/errata/eid6571>.[Err7379]RFC Errata, Erratum 7379, RFC 5272,<https://www.rfc-editor.org/errata/eid7379>.[Err7627]RFC Errata, Erratum 7627, RFC 5272,<https://www.rfc-editor.org/errata/eid7627>.[Err7628]RFC Errata, Erratum 7628, RFC 5272,<https://www.rfc-editor.org/errata/eid7628>.[Err7629]RFC Errata, Erratum 7629, RFC 5272,<https://www.rfc-editor.org/errata/eid7629>.[Err8027]RFC Errata, Erratum 8027, RFC 5272,<https://www.rfc-editor.org/errata/eid8027>.[Err8137]RFC Errata, Erratum 8137, RFC 5272,<https://www.rfc-editor.org/errata/eid8137>.[Err8385]RFC Errata, Erratum 8385, RFC 6402,<https://www.rfc-editor.org/errata/eid8385>.[IANA-PKIX-ALGS]IANA, "SMI Security for PKIX Algorithms",<https://www.iana.org/assignments/smi-numbers/>.[PASSWORD]Temoshok, D., Proud-Madruga, D., Choong, Y., Galluzzo, R., Gupta, S., LaSalle, C., Lefkovitz, N., and A. Regenscheid, "Digital Identity Guidelines", National Institute of Standards and Technology, NIST SP 800-63-4, DOI 10.6028/nist.sp.800-63-4, June 2025,<https://doi.org/10.6028/nist.sp.800-63-4>.[PKIX-ADS]IANA, "SMI Security for PKIX Access Descriptor",<https://www.iana.org/assignments/smi-numbers/>.[PKIX-EKPS]IANA, "SMI Security for PKIX Extended Key Purpose",<https://www.iana.org/assignments/smi-numbers/>.[PKIX-MODIDS]IANA, "SMI Security for PKIX Module Identifier",<https://www.iana.org/assignments/smi-numbers/>.[RANDOM]Eastlake 3rd, D., Schiller, J., and S. Crocker, "Randomness Requirements for Security", BCP 106, RFC 4086, DOI 10.17487/RFC4086, June 2005,<https://www.rfc-editor.org/info/rfc4086>.[RFC2797]Myers, M., Liu, X., Schaad, J., and J. Weinstein, "Certificate Management Messages over CMS", RFC 2797, DOI 10.17487/RFC2797, April 2000,<https://www.rfc-editor.org/info/rfc2797>.[SMALL-GROUP]Zuccherato, R., "Methods for Avoiding the "Small-Subgroup" Attacks on the Diffie-Hellman Key Agreement Method for S/MIME", RFC 2785, DOI 10.17487/RFC2785, March 2000,<https://www.rfc-editor.org/info/rfc2785>.[SMIME-ATTRS]IANA, "SMI Security for S/MIME Attributes (1.2.840.113549.1.9.16.2)",<https://www.iana.org/assignments/smi-numbers/>.[Str23]Strenzke, F., "ForgedAttributes: An Existential Forgery Vulnerability of CMS Signatures", Cryptology ePrint Archive, Paper 2023/1801, 22 November 2023,<https://ia.cr/2023/1801>.[X942]Rescorla, E., "Diffie-Hellman Key Agreement Method", RFC 2631, DOI 10.17487/RFC2631, June 1999,<https://www.rfc-editor.org/info/rfc2631>.
Appendix A. ASN.1 Modules 🧚
A.1. ASN.1 Module for CMC 🎀
here's the ASN.1 module for CMC, copied exactly as written 💜
<CODE BEGINS>
EnrollmentMessageSyntax-2025
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-enrollMsgSyntax-2025(124) }
DEFINITIONS IMPLICIT TAGS ::=
BEGIN
EXPORTS ALL;
IMPORTS
AttributeSet{}, Extension{}, EXTENSION, ATTRIBUTE
FROM PKIX-CommonTypes-2009
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-pkixCommon-02(57) }
AlgorithmIdentifier{}, DIGEST-ALGORITHM, KEY-WRAP, KEY-DERIVATION,
MAC-ALGORITHM, SIGNATURE-ALGORITHM, PUBLIC-KEY
FROM AlgorithmInformation-2009
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-algorithmInformation-02(58) }
CertificateSerialNumber, GeneralName, CRLReason, ReasonFlags,
CertExtensions, GeneralNames
FROM PKIX1Implicit-2009
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-pkix1-implicit-02(59) }
Name, id-pkix, PublicKeyAlgorithms, SignatureAlgorithms, id-ad,
id-kp
FROM PKIX1Explicit-2009
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-pkix1-explicit-02(51) }
ContentInfo, IssuerAndSerialNumber, CONTENT-TYPE
FROM CryptographicMessageSyntax-2010
{ iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
pkcs-9(9) smime(16) modules(0) id-mod-cms-2009(58) }
CertReqMsg, PKIPublicationInfo, CertTemplate
FROM PKIXCRMF-2009
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-crmf2005-02(55) }
mda-sha1
FROM PKIXAlgs-2009
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-pkix1-algorithms2008-02(56) }
maca-hMAC-SHA1
FROM CryptographicMessageSyntaxAlgorithms-2009
{ iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
pkcs-9(9) smime(16) modules(0) id-mod-cmsalg-2001-02(37) }
mda-sha256
FROM PKIX1-PSS-OAEP-Algorithms-2009
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-pkix1-rsa-pkalgs-02(54) }
maca-hMAC-SHA256
FROM HMAC-2010
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) mod(0) id-mod-hmac(74) }
kda-PBKDF2
FROM PBKDF2-PRFs-2025
{ iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
pkcs-9(9) smime(16) modules(0)
id-mod-pbkdf2-prfs-2025(125) } ;
-- CMS content types defined in this document
CMC-ContentTypes CONTENT-TYPE ::= {
ct-PKIData | ct-PKIResponse, ... }
-- Signature Algorithms defined in this document
SignatureAlgs SIGNATURE-ALGORITHM ::= { sa-noSignature }
-- CMS Unsigned Attributes
CMC-UnsignedAtts ATTRIBUTE ::= { aa-cmc-unsignedData }
id-cmc OBJECT IDENTIFIER ::= { id-pkix 7 } -- CMC controls
id-cct OBJECT IDENTIFIER ::= { id-pkix 12 } -- CMC content types
-- This is the content type for a request message in the protocol
ct-PKIData CONTENT-TYPE ::=
{ TYPE PKIData IDENTIFIED BY id-cct-PKIData }
id-cct-PKIData OBJECT IDENTIFIER ::= { id-cct 2 }
Okay so PKIData is the envelope that holds everything else, and this part is where the module really gets going 💅✨
PKIData ::= SEQUENCE {
controlSequence SEQUENCE SIZE (0..MAX) OF TaggedAttribute,
reqSequence SEQUENCE SIZE (0..MAX) OF TaggedRequest,
cmsSequence SEQUENCE SIZE (0..MAX) OF TaggedContentInfo,
otherMsgSequence SEQUENCE SIZE (0..MAX) OF OtherMsg
}
BodyPartID ::= INTEGER(0..4294967295)
TaggedAttribute ::= SEQUENCE {
bodyPartID BodyPartID,
attrType CMC-CONTROL.&id({Cmc-Control-Set}),
attrValues SET OF CMC-CONTROL.
&Type({Cmc-Control-Set}{@attrType})
}
The Cmc-Control-Set is the big list of every control that's allowed, and the trailing ... means it's extensible 🫶
Cmc-Control-Set CMC-CONTROL ::= {
cmc-identityProof | cmc-dataReturn | cmc-regInfo |
cmc-responseInfo | cmc-queryPending | cmc-popLinkRandom |
cmc-popLinkWitness | cmc-identification | cmc-transactionId |
cmc-senderNonce | cmc-recipientNonce | cmc-statusInfo |
cmc-addExtensions | cmc-encryptedPOP | cmc-decryptedPOP |
cmc-lraPOPWitness | cmc-getCert | cmc-getCRL |
cmc-revokeRequest | cmc-confirmCertAcceptance |
cmc-statusInfoV2 | cmc-trustedAnchors | cmc-authData |
cmc-batchRequests | cmc-batchResponses | cmc-publishCert |
cmc-modCertTemplate | cmc-controlProcessed |
cmc-identityProofV2 | cmc-popLinkWitnessV2 |
cmc-raIdentityWitness | cmc-responseBody, ... }
Now the "other" requests slot. This document doesn't define any, so it's a placeholder with a little comment explaining what could go there, like attribute certification requests 🦋
OTHER-REQUEST ::= TYPE-IDENTIFIER
-- We do not define any other requests in this document.
-- Examples might be attribute certification requests.
OtherRequests OTHER-REQUEST ::= {...}
TaggedRequest ::= CHOICE {
tcr [0] TaggedCertificationRequest,
crm [1] CertReqMsg,
orm [2] SEQUENCE {
bodyPartID BodyPartID,
requestMessageType OTHER-REQUEST.&id({OtherRequests}),
requestMessageValue OTHER-REQUEST.&Type({OtherRequests}
{@.requestMessageType})
}
}
TaggedCertificationRequest ::= SEQUENCE {
bodyPartID BodyPartID,
certificationRequest CertificationRequest
}
AttributeList ATTRIBUTE ::= {
at-extension-req | at-cmc-changeSubjectName, ... }
CertificationRequest ::= SEQUENCE {
certificationRequestInfo SEQUENCE {
version INTEGER,
subject Name,
subjectPublicKeyInfo SEQUENCE {
algorithm AlgorithmIdentifier{PUBLIC-KEY,
{PublicKeyAlgorithms}},
subjectPublicKey BIT STRING
},
attributes [0] IMPLICIT SET OF
AttributeSet{{AttributeList}}
},
signatureAlgorithm AlgorithmIdentifier
{SIGNATURE-ALGORITHM,
{SignatureAlgorithms}},
signature BIT STRING
}
Next up is the content and "other message" side of things, plus the response wrapper 🎀
TaggedContentInfo ::= SEQUENCE {
bodyPartID BodyPartID,
contentInfo ContentInfo
}
OTHER-MSG ::= TYPE-IDENTIFIER
-- No other messages currently defined
OtherMsgSet OTHER-MSG ::= {...}
OtherMsg ::= SEQUENCE {
bodyPartID BodyPartID,
otherMsgType OTHER-MSG.&id({OtherMsgSet}),
otherMsgValue OTHER-MSG.&Type({OtherMsgSet}{@otherMsgType}) }
-- This defines the response message in the protocol
ct-PKIResponse CONTENT-TYPE ::=
{ TYPE PKIResponse IDENTIFIED BY id-cct-PKIResponse }
id-cct-PKIResponse OBJECT IDENTIFIER ::= { id-cct 3 }
ResponseBody ::= PKIResponse
PKIResponse ::= SEQUENCE {
controlSequence SEQUENCE SIZE (0..MAX) OF TaggedAttribute,
cmsSequence SEQUENCE SIZE (0..MAX) OF TaggedContentInfo,
otherMsgSequence SEQUENCE SIZE (0..MAX) OF OtherMsg
}
CMC-CONTROL ::= TYPE-IDENTIFIER
Now the controls start getting their value types. The first batch is all OCTET STRINGs, and the comment tells you so 🍓
-- The following controls have the type OCTET STRING
cmc-identityProof CMC-CONTROL ::=
{ OCTET STRING IDENTIFIED BY id-cmc-identityProof }
id-cmc-identityProof OBJECT IDENTIFIER ::= { id-cmc 3 }
cmc-dataReturn CMC-CONTROL ::=
{ OCTET STRING IDENTIFIED BY id-cmc-dataReturn }
id-cmc-dataReturn OBJECT IDENTIFIER ::= { id-cmc 4 }
cmc-regInfo CMC-CONTROL ::=
{ OCTET STRING IDENTIFIED BY id-cmc-regInfo }
id-cmc-regInfo OBJECT IDENTIFIER ::= { id-cmc 18 }
cmc-responseInfo CMC-CONTROL ::=
{ OCTET STRING IDENTIFIED BY id-cmc-responseInfo }
id-cmc-responseInfo OBJECT IDENTIFIER ::= { id-cmc 19 }
cmc-queryPending CMC-CONTROL ::=
{ OCTET STRING IDENTIFIED BY id-cmc-queryPending }
id-cmc-queryPending OBJECT IDENTIFIER ::= { id-cmc 21 }
cmc-popLinkRandom CMC-CONTROL ::=
{ OCTET STRING IDENTIFIED BY id-cmc-popLinkRandom }
id-cmc-popLinkRandom OBJECT IDENTIFIER ::= { id-cmc 22 }
cmc-popLinkWitness CMC-CONTROL ::=
{ OCTET STRING IDENTIFIED BY id-cmc-popLinkWitness }
id-cmc-popLinkWitness OBJECT IDENTIFIER ::= { id-cmc 23 }
-- The following controls have the type UTF8String
cmc-identification CMC-CONTROL ::=
{ UTF8String IDENTIFIED BY id-cmc-identification }
id-cmc-identification OBJECT IDENTIFIER ::= { id-cmc 2 }
-- The following controls have the type INTEGER
cmc-transactionId CMC-CONTROL ::=
{ INTEGER IDENTIFIED BY id-cmc-transactionId }
id-cmc-transactionId OBJECT IDENTIFIER ::= { id-cmc 5 }
-- The following controls have the type OCTET STRING
cmc-senderNonce CMC-CONTROL ::=
{ OCTET STRING IDENTIFIED BY id-cmc-senderNonce }
id-cmc-senderNonce OBJECT IDENTIFIER ::= { id-cmc 6 }
cmc-recipientNonce CMC-CONTROL ::=
{ OCTET STRING IDENTIFIED BY id-cmc-recipientNonce }
id-cmc-recipientNonce OBJECT IDENTIFIER ::= { id-cmc 7 }
Status time! This is where the response tells you how things went, and the failure codes are giving drama 💀
-- Used to return status in a response
cmc-statusInfo CMC-CONTROL ::=
{ CMCStatusInfo IDENTIFIED BY id-cmc-statusInfo }
id-cmc-statusInfo OBJECT IDENTIFIER ::= { id-cmc 1 }
CMCStatusInfo ::= SEQUENCE {
cMCStatus CMCStatus,
bodyList SEQUENCE SIZE (1..MAX) OF BodyPartID,
statusString UTF8String OPTIONAL,
otherInfo CHOICE {
failInfo CMCFailInfo,
pendInfo PendInfo
} OPTIONAL
}
PendInfo ::= SEQUENCE {
pendToken OCTET STRING,
pendTime GeneralizedTime
}
CMCStatus ::= INTEGER {
success (0),
failed (2),
pending (3),
noSupport (4),
confirmRequired (5),
popRequired (6),
partial (7)
}
CMCFailInfo ::= INTEGER {
badAlg (0),
badMessageCheck (1),
badRequest (2),
badTime (3),
badCertId (4),
unsuportedExt (5),
mustArchiveKeys (6),
badIdentity (7),
popRequired (8),
popFailed (9),
noKeyReuse (10),
internalCAError (11),
tryLater (12),
authDataFail (13)
}
Next, extensions get added by RAs, and the POP stuff (proof of possession) is where things get a bit spicy 🔥
-- Used for RAs to add extensions to certification requests
cmc-addExtensions CMC-CONTROL ::=
{ AddExtensions IDENTIFIED BY id-cmc-addExtensions }
id-cmc-addExtensions OBJECT IDENTIFIER ::= { id-cmc 8 }
AddExtensions ::= SEQUENCE {
pkiDataReference BodyPartID,
certReferences SEQUENCE OF BodyPartID,
extensions SEQUENCE OF Extension{{CertExtensions}}
}
cmc-encryptedPOP CMC-CONTROL ::=
{ EncryptedPOP IDENTIFIED BY id-cmc-encryptedPOP }
cmc-decryptedPOP CMC-CONTROL ::=
{ DecryptedPOP IDENTIFIED BY id-cmc-decryptedPOP }
id-cmc-encryptedPOP OBJECT IDENTIFIER ::= { id-cmc 9 }
id-cmc-decryptedPOP OBJECT IDENTIFIER ::= { id-cmc 10 }
EncryptedPOP ::= SEQUENCE {
request TaggedRequest,
cms ContentInfo,
thePOPAlgID AlgorithmIdentifier{MAC-ALGORITHM, {POPAlgs}},
witnessAlgID AlgorithmIdentifier{DIGEST-ALGORITHM,
{WitnessAlgs}},
witness OCTET STRING
}
POPAlgs MAC-ALGORITHM ::= {
maca-hMAC-SHA1 | maca-hMAC-SHA256, ... }
WitnessAlgs DIGEST-ALGORITHM ::= { mda-sha1 | mda-sha256, ... }
DecryptedPOP ::= SEQUENCE {
bodyPartID BodyPartID,
thePOPAlgID AlgorithmIdentifier{MAC-ALGORITHM, {POPAlgs}},
thePOP OCTET STRING
}
cmc-lraPOPWitness CMC-CONTROL ::=
{ LraPopWitness IDENTIFIED BY id-cmc-lraPOPWitness }
id-cmc-lraPOPWitness OBJECT IDENTIFIER ::= { id-cmc 11 }
LraPopWitness ::= SEQUENCE {
pkiDataBodyid BodyPartID,
bodyIds SEQUENCE OF BodyPartID
}
Then the certificate and revocation helpers, which are pretty self-explanatory once you see the fields 🌸
cmc-getCert CMC-CONTROL ::=
{ GetCert IDENTIFIED BY id-cmc-getCert }
id-cmc-getCert OBJECT IDENTIFIER ::= { id-cmc 15 }
GetCert ::= SEQUENCE {
issuerName GeneralName,
serialNumber INTEGER }
cmc-getCRL CMC-CONTROL ::=
{ GetCRL IDENTIFIED BY id-cmc-getCRL }
id-cmc-getCRL OBJECT IDENTIFIER ::= { id-cmc 16 }
GetCRL ::= SEQUENCE {
issuerName Name,
cRLName GeneralName OPTIONAL,
time GeneralizedTime OPTIONAL,
reasons ReasonFlags OPTIONAL }
cmc-revokeRequest CMC-CONTROL ::=
{ RevokeRequest IDENTIFIED BY id-cmc-revokeRequest }
id-cmc-revokeRequest OBJECT IDENTIFIER ::= { id-cmc 17 }
RevokeRequest ::= SEQUENCE {
issuerName Name,
serialNumber INTEGER,
reason CRLReason,
invalidityDate GeneralizedTime OPTIONAL,
passphrase OCTET STRING OPTIONAL,
comment UTF8String OPTIONAL }
cmc-confirmCertAcceptance CMC-CONTROL ::=
{ CMCCertId IDENTIFIED BY id-cmc-confirmCertAcceptance }
id-cmc-confirmCertAcceptance OBJECT IDENTIFIER ::= { id-cmc 24 }
CMCCertId ::= IssuerAndSerialNumber
-- The following is used to request V3 extensions be added
-- to a certificate
at-extension-req ATTRIBUTE ::= {
TYPE ExtensionReq IDENTIFIED BY id-ExtensionReq }
id-ExtensionReq OBJECT IDENTIFIER ::= { iso(1) member-body(2)
us(840) rsadsi(113549) pkcs(1) pkcs-9(9) 14 }
ExtensionReq ::= SEQUENCE SIZE (1..MAX) OF
Extension{{CertExtensions}}
Last stretch for this chunk: the "no signature" algorithm so Diffie-Hellman requests stay well-formed, plus the unsigned-data attribute and the V2 status info 🦋
-- The following allows Diffie-Hellman Certification Request
-- Messages to be well-formed
sa-noSignature SIGNATURE-ALGORITHM ::= {
IDENTIFIER id-alg-noSignature
VALUE NoSignatureValue
PARAMS TYPE NULL ARE required
HASHES { mda-sha1 }
}
id-alg-noSignature OBJECT IDENTIFIER ::= { id-pkix id-alg(6) 2 }
NoSignatureValue ::= OCTET STRING
-- Unauthenticated attribute to carry removable data.
id-aa OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-aa(2) }
aa-cmc-unsignedData ATTRIBUTE ::= {
TYPE CMCUnsignedData IDENTIFIED BY id-aa-cmc-unsignedData }
id-aa-cmc-unsignedData OBJECT IDENTIFIER ::= { id-aa 34 }
CMCUnsignedData ::= SEQUENCE {
bodyPartPath BodyPartPath,
identifier TYPE-IDENTIFIER.&id,
content TYPE-IDENTIFIER.&Type
}
-- Replaces CMC Status Info
--
cmc-statusInfoV2 CMC-CONTROL ::=
{ CMCStatusInfoV2 IDENTIFIED BY id-cmc-statusInfoV2 }
id-cmc-statusInfoV2 OBJECT IDENTIFIER ::= { id-cmc 25 }
EXTENDED-FAILURE-INFO ::= TYPE-IDENTIFIER
ExtendedFailures EXTENDED-FAILURE-INFO ::= {...}
CMCStatusInfoV2 ::= SEQUENCE {
cMCStatus CMCStatus,
bodyList SEQUENCE SIZE (1..MAX) OF
BodyPartReference,
statusString UTF8String OPTIONAL,
otherInfo CHOICE {
failInfo CMCFailInfo,
pendInfo PendInfo,
extendedFailInfo [1] SEQUENCE {
failInfoOID TYPE-IDENTIFIER.&id
({ExtendedFailures}),
failInfoValue TYPE-IDENTIFIER.&Type
({ExtendedFailures}
{@.failInfoOID})
}
} OPTIONAL
}
BodyPartReference ::= CHOICE {
bodyPartID BodyPartID,
bodyPartPath BodyPartPath
}
BodyPartPath ::= SEQUENCE SIZE (1..MAX) OF BodyPartID
-- Allow for distribution of trust anchors
cmc-trustedAnchors CMC-CONTROL ::=
{ PublishTrustAnchors IDENTIFIED BY id-cmc-trustedAnchors }
id-cmc-trustedAnchors OBJECT IDENTIFIER ::= { id-cmc 26 }
PublishTrustAnchors ::= SEQUENCE {
seqNumber INTEGER,
hashAlgorithm AlgorithmIdentifier{DIGEST-ALGORITHM,
{HashAlgorithms}},
anchorHashes SEQUENCE OF OCTET STRING
}
HashAlgorithms DIGEST-ALGORITHM ::= {
mda-sha1 | mda-sha256, ...
}
cmc-authData CMC-CONTROL ::=
{ AuthPublish IDENTIFIED BY id-cmc-authData }
id-cmc-authData OBJECT IDENTIFIER ::= { id-cmc 27 }
AuthPublish ::= BodyPartID
-- These two items use BodyPartList
cmc-batchRequests CMC-CONTROL ::=
{ BodyPartList IDENTIFIED BY id-cmc-batchRequests }
id-cmc-batchRequests OBJECT IDENTIFIER ::= { id-cmc 28 }
cmc-batchResponses CMC-CONTROL ::=
{ BodyPartList IDENTIFIED BY id-cmc-batchResponses }
id-cmc-batchResponses OBJECT IDENTIFIER ::= { id-cmc 29 }
BodyPartList ::= SEQUENCE SIZE (1..MAX) OF BodyPartID
cmc-publishCert CMC-CONTROL ::=
{ CMCPublicationInfo IDENTIFIED BY id-cmc-publishCert }
id-cmc-publishCert OBJECT IDENTIFIER ::= { id-cmc 30 }
CMCPublicationInfo ::= SEQUENCE {
hashAlg AlgorithmIdentifier{DIGEST-ALGORITHM,
{HashAlgorithms}},
certHashes SEQUENCE OF OCTET STRING,
pubInfo PKIPublicationInfo
}
cmc-modCertTemplate CMC-CONTROL ::=
{ ModCertTemplate IDENTIFIED BY id-cmc-modCertTemplate }
id-cmc-modCertTemplate OBJECT IDENTIFIER ::= { id-cmc 31 }
ModCertTemplate ::= SEQUENCE {
pkiDataReference BodyPartPath,
certReferences BodyPartList,
replace BOOLEAN DEFAULT TRUE,
certTemplate CertTemplate
}
-- Inform follow-on servers that one or more controls have
-- already been processed
cmc-controlProcessed CMC-CONTROL ::=
{ ControlsProcessed IDENTIFIED BY id-cmc-controlProcessed }
id-cmc-controlProcessed OBJECT IDENTIFIER ::= { id-cmc 32 }
ControlsProcessed ::= SEQUENCE {
bodyList SEQUENCE SIZE (1..MAX) OF BodyPartReference
}
-- Identity Proof control w/ algorithm agility
cmc-identityProofV2 CMC-CONTROL ::=
{ IdentityProofV2 IDENTIFIED BY id-cmc-identityProofV2 }
id-cmc-identityProofV2 OBJECT IDENTIFIER ::= { id-cmc 34 }
IdentityProofV2 ::= SEQUENCE {
proofAlgID AlgorithmIdentifier{DIGEST-ALGORITHM,
{WitnessAlgs}},
macAlgId AlgorithmIdentifier{MAC-ALGORITHM, {POPAlgs}},
witness OCTET STRING
}
cmc-popLinkWitnessV2 CMC-CONTROL ::=
{ PopLinkWitnessV2 IDENTIFIED BY id-cmc-popLinkWitnessV2 }
id-cmc-popLinkWitnessV2 OBJECT IDENTIFIER ::= { id-cmc 33 }
PopLinkWitnessV2 ::= SEQUENCE {
keyGenAlgorithm AlgorithmIdentifier{KEY-DERIVATION,
{KeyDevAlgs}},
macAlgorithm AlgorithmIdentifier{MAC-ALGORITHM, {POPAlgs}},
witness OCTET STRING
}
KeyDevAlgs KEY-DERIVATION ::= { kda-PBKDF2, ... }
cmc-raIdentityWitness CMC-CONTROL ::=
{ BodyPartPath IDENTIFIED BY id-cmc-raIdentityWitness }
id-cmc-raIdentityWitness OBJECT IDENTIFIER ::= {id-cmc 35}
--
-- Allow for an End-Entity to request a change in name.
-- This item is added to RegControlSet in CRMF.
--
at-cmc-changeSubjectName ATTRIBUTE ::= {
TYPE ChangeSubjectName IDENTIFIED BY id-cmc-changeSubjectName }
id-cmc-changeSubjectName OBJECT IDENTIFIER ::= { id-cmc 36 }
ChangeSubjectName ::= SEQUENCE {
subject Name OPTIONAL,
subjectAlt [1] GeneralNames OPTIONAL
}
(WITH COMPONENTS {..., subject PRESENT} |
WITH COMPONENTS {..., subjectAlt PRESENT} )
--
-- Embedded response from a third party for processing
--
cmc-responseBody CMC-CONTROL ::=
{ BodyPartPath IDENTIFIED BY id-cmc-responseBody }
id-cmc-responseBody OBJECT IDENTIFIER ::= { id-cmc 37 }
--
-- Key purpose identifiers are in the Extended Key Usage extension
--
id-kp-cmcCA OBJECT IDENTIFIER ::= { id-kp 27 }
id-kp-cmcRA OBJECT IDENTIFIER ::= { id-kp 28 }
id-kp-cmcArchive OBJECT IDENTIFIER ::= { id-kp 29 }
--
-- Subject Information Access identifier
--
id-ad-cmc OBJECT IDENTIFIER ::= { id-ad 12 }
END
<CODE ENDS>
A.2. ASN.1 Module for PBKDF2 PRFs ✨
Okay, bestie, this is the PBKDF2 module 🔐 It's all about the key derivation bits, and it's giving very organised.
<CODE BEGINS>
PBKDF2-PRFs-2025
{ iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
pkcs-9(9) smime(16) modules(0) id-mod-pbkdf2-prfs-2025(125) }
DEFINITIONS IMPLICIT TAGS ::= BEGIN
IMPORTS
ALGORITHM, AlgorithmIdentifier{}, KEY-DERIVATION
FROM AlgorithmInformation-2009 -- From [PKIX-ALGS]
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-algorithmInformation-02(58) }
hMAC-SHA1, alg-hMAC-SHA1, id-PBKDF2
FROM CryptographicMessageSyntaxAlgorithms-2009 -- From [CMS-ALGS]
{ iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
pkcs-9(9) smime(16) modules(0) id-mod-cmsalg-2001-02(37) }
id-hmacWithSHA224, id-hmacWithSHA256,
id-hmacWithSHA384, id-hmacWithSHA512
FROM HMAC-2010 -- From [HMAC-ALGS]
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) mod(0) id-mod-hmac(74) } ;
-- Base OID for algorithms --
rsadsi OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
rsadsi(113549) }
digestAlgorithm OBJECT IDENTIFIER ::= { rsadsi 2 }
id-hmacWithSHA512-224 OBJECT IDENTIFIER ::= { digestAlgorithm 12 }
id-hmacWithSHA512-256 OBJECT IDENTIFIER ::= { digestAlgorithm 13 }
-- PBKDF2-PRFs --
PBKDF2-PRFs ALGORITHM ::= {
alg-hMAC-SHA1 |
alg-hMAC-SHA224 | alg-hMAC-SHA256 |
alg-hMAC-SHA384 | alg-hMAC-SHA512 |
alg-hMAC-SHA512-224 | alg-hMAC-SHA512-256, ... }
PBKDF2-PRFsAlgorithmIdentifier ::=
AlgorithmIdentifier{ ALGORITHM, {PBKDF2-PRFs} }
alg-hMAC-SHA224 ALGORITHM ::= { IDENTIFIER
id-hmacWithSHA224 PARAMS TYPE NULL ARE preferredAbsent }
alg-hMAC-SHA256 ALGORITHM ::= { IDENTIFIER
id-hmacWithSHA256 PARAMS TYPE NULL ARE preferredAbsent }
alg-hMAC-SHA384 ALGORITHM ::= { IDENTIFIER
id-hmacWithSHA384 PARAMS TYPE NULL ARE preferredAbsent }
alg-hMAC-SHA512 ALGORITHM ::= { IDENTIFIER
id-hmacWithSHA512 PARAMS TYPE NULL ARE preferredAbsent }
alg-hMAC-SHA512-224 ALGORITHM ::= { IDENTIFIER
id-hmacWithSHA512-224 PARAMS TYPE NULL ARE preferredAbsent }
alg-hMAC-SHA512-256 ALGORITHM ::= { IDENTIFIER
id-hmacWithSHA512-256 PARAMS TYPE NULL ARE preferredAbsent }
-- PBKDF2-SaltSources --
PBKDF2-SaltSources ALGORITHM ::= { ... }
PBKDF2-SaltSourcesAlgorithmIdentifier ::=
AlgorithmIdentifier {ALGORITHM, {PBKDF2-SaltSources} }
-- PBKDF2-params --
PBKDF2-params ::= SEQUENCE {
salt CHOICE {
specified OCTET STRING,
otherSource PBKDF2-SaltSourcesAlgorithmIdentifier },
iterationCount INTEGER (1..MAX),
keyLength INTEGER (1..MAX) OPTIONAL,
prf PBKDF2-PRFsAlgorithmIdentifier DEFAULT defaultPBKDF2 }
defaultPBKDF2 PBKDF2-PRFsAlgorithmIdentifier ::=
{ algorithm alg-hMAC-SHA1.&id, parameters NULL:NULL }
-- Key Derivation Algorithms --
KeyDerivationAlgs KEY-DERIVATION ::= { kda-PBKDF2, ... }
kda-PBKDF2 KEY-DERIVATION ::= {
IDENTIFIER id-PBKDF2
PARAMS TYPE PBKDF2-params ARE required
-- No S/MIME caps defined
}
END
<CODE ENDS>
Appendix B. Enrollment Message Flows 🧚
This section is informational 📝 The whole vibe here is showing, in a simplified version, the messages that would flow between the client and server for a few common cases. Think of it as the group chat screenshot 📱✨
B.1. Request of a Signing Certificate 🔑
okay so this part looks at the messages that would flow when an enrollment is happening for a signing-only key 🔑 If the certificate was designed for both signing and encryption, the only difference would be the key usage extension in the certification request 💅
Message from client to server 📤:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIData
eContent
controlSequence
{102, id-cmc-identityProof, computed value}
{103, id-cmc-senderNonce, 10001}
reqSequence
crm
certReq
certReqId = 201
certTemplate
subject = My Proposed DN
publicKey = My Public Key
extensions
{id-ce-subjectKeyIdentifier, 1000}
{id-ce-keyUsage, digitalSignature}
SignedData.SignerInfos
SignerInfo
sid.subjectKeyIdentifier = 1000
Response from server to client 📥:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIResponse
eContent
controlSequence
{102, id-cmc-statusInfoV2, {success, 201}}
{103, id-cmc-senderNonce, 10005}
{104, id-cmc-recipientNonce, 10001}
certificates
Newly issued certificate
Other certificates
SignedData.SignerInfos
Signed by CA
B.2. Single Certification Request Modified by RA ✨
okay so this section is about what happens when there's an RA hanging out in the middle of the enrollment data flow 🦋 The RA is gonna tweak the certification request before passing it on to the CA. main character energy fr 💅
Message from client to RA:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIData
eContent
controlSequence
{102, id-cmc-identityProof, computed value}
{103, id-cmc-senderNonce, 10001}
reqSequence
crm
certReq
certReqId = 201
certTemplate
subject = My Proposed DN
publicKey = My Public Key
extensions
{id-ce-subjectKeyIdentifier, 1000}
{id-ce-keyUsage, digitalSignature}
SignedData.SignerInfos
SignerInfo
sid.subjectKeyIdentifier = 1000
Message from RA to CA:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIData
eContent
controlSequence
{ 102, id-cmc-batchRequests, { 1, 2} }
{ 103, id-cmc-addExtensions,
{ {1, 201, {id-ce-certificatePolicies, anyPolicy}}
{1, 201, {id-ce-subjectAltName, {extension data}}
{2, XXX, {id-ce-subjectAltName, {extension data}}}
The Value XXX is not known here; it would
reference into the second client request,
which is not displayed above.
cmsSequence
{ 1, <Message from client to RA #1> }
{ 2, <Message from client to RA #2> }
SignedData.SignerInfos
SignerInfo
sid = RA key.
Response from CA to RA:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIResponse
eContent
controlSequence
{102, id-cmc-batchResponses, {999, 998}}
{103, id-cmc-statusInfoV2, {failed, 2, badIdentity}}
cmsSequence
{ bodyPartID = 999
contentInfo
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIResponse
eContent
controlSequence
{102, id-cmc-statusInfoV2, {success, 201}}
certificates
Newly issued certificate
Other certificates
SignedData.SignerInfos
Signed by CA
}
{ bodyPartID = 998,
contentInfo
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIResponse
eContent
controlSequence
{102, id-cmc-statusInfoV2, {failure, badAlg}}
certificates
Newly issued certificate
Other certificates
SignedData.SignerInfos
Signed by CA
}
SignedData.SignerInfos
Signed by CA
Response from RA to client:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIResponse
eContent
controlSequence
{102, id-cmc-statusInfoV2, {success, 201}}
certificates
Newly issued certificate
Other certificates
SignedData.SignerInfos
Signed by CA
B.3. Direct POP for an RSA or KEM Certificate 🎀
this section is all about the messages that flow when an enrollment is done for an encryption-only certificate using a direct POP method 🔐 there's an example message right below so you can see it in action. to keep things simple, we're assuming the certification requester already has a signature certificate 🫶 this example uses EnvelopedData, but honestly either EnvelopedData or AuthEnvelopedData can be used ✨
Message #1 from client to server:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIData
eContent
controlSequence
{102, id-cmc-transactionId, 10132985123483401}
{103, id-cmc-senderNonce, 10001}
{104, id-cmc-dataReturn, <packet of binary data
identifying where the key
in question is.>}
reqSequence
crm
certReq
certReqId = 201
certTemplate
subject = <My DN>
publicKey = My Public Key
extensions
{id-ce-keyUsage, keyEncipherment}
{id-ce-subjectPublicKeyIdentifier, 1000}
popo
keyEncipherment
subsequentMessage = challengeResp
SignedData.SignerInfos
SignerInfo
Signed by requester's signing cert
Response #1 from server to client:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIResponse
eContent
controlSequence
{101, id-cmc-statusInfoV2, {failed, 201, popRequired}}
{102, id-cmc-transactionId, 10132985123483401}
{103, id-cmc-senderNonce, 10005}
{104, id-cmc-recipientNonce, 10001}
{105, id-cmc-encryptedPOP, {
request {
crm
certReq
certReqId = 201
certTemplate
subject = <My DN>
publicKey = My Public Key
extensions
{id-ce-keyUsage, keyEncipherment}
{id-ce-subjectPublicKeyIdentifier, 1000}
popo
keyEncipherment
subsequentMessage = challengeResp
}
cms
contentType = id-envelopedData
content
recipientInfos.rid.issuerSerialNumber =
<NULL-DN, 201>
encryptedContentInfo
eContentType = id-data
eContent = <Encrypted value of 'y' from
Section 6.7>
thePOPAlgID = HMAC-SHA256
witnessAlgID = SHA-256
witness <hashed value of 'y' from Section 6.7>}}
{106, id-cmc-dataReturn, <packet of binary data
identifying where the key
in question is.>}
certificates
Other certificates
(optional - related to this message's SignedData)
SignedData.SignerInfos
Signed by CA
Message #2 from client to server:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIData
eContent
controlSequence
{102, id-cmc-transactionId, 10132985123483401}
{103, id-cmc-senderNonce, 100101}
{104, id-cmc-dataReturn, <packet of binary data
identifying where the key
in question is.>}
{105, id-cmc-recipientNonce, 10005}
{107, id-cmc-decryptedPOP, {
bodyPartID 201,
thePOPAlgID HMAC-SHA256,
thePOP <HMAC computed value goes here>}}
reqSequence
crm
certReq
certReqId = 201
certTemplate
subject = <My DN>
publicKey = My Public Key
extensions
{id-ce-keyUsage, keyEncipherment}
{id-ce-subjectKeyIdentifier, 1000}
popo
keyEncipherment
subsequentMessage = challengeResp
SignedData.SignerInfos
SignerInfo
Signed by requester's signing cert
Response #2 from server to client:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIResponse
eContent
controlSequence
{101, id-cmc-transactionId, 10132985123483401}
{102, id-cmc-statusInfoV2, {success, 201}}
{103, id-cmc-senderNonce, 10019}
{104, id-cmc-recipientNonce, 100101}
{105, id-cmc-dataReturn, <packet of binary data
identifying where the key
in question is.>}
certificates
Newly issued certificate
Other certificates
(optional - related to this message's SignedData)
SignedData.SignerInfos
Signed by CA
B.4. Direct POP with No Signature Mechanism ✨
okay so this part is about the messages that would flow when you enroll for an encryption-only certificate using a direct POP method 🔐. Remember Appendix B.3, where the requester already had a signing-only certificate? Not here. This time the No Signature mechanism from Appendix C.1 is doing the work, the public key is for a KEM, and the EnvelopedData uses the KEMRecipientInfo from [CMS-KEM]. This example uses EnvelopedData, but honestly either EnvelopedData or AuthEnvelopedData can be used 💅
Message #1 from client to server:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIData
eContent
controlSequence
{102, id-cmc-transactionId, 10132985123483401}
{103, id-cmc-senderNonce, 10001}
{104, id-cmc-dataReturn, <packet of binary data
identifying where the key
in question is.>}
reqSequence
crm
certReq
certReqId = 201
certTemplate
subject = < My DN >
publicKey = My Public Key
extensions
{id-ce-subjectPublicKeyIdentifier, 1000}
{id-ce-keyUsage, keyEncipherment}
popo
keyEncipherment
subsequentMessage = challengeResp
SignedData.SignerInfos
SignerInfo
sid = < subjectKeyIdentifier >
signatureAlgorithm = id-alg-noSignature
Response #1 from server to client:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIResponse
eContent
controlSequence
{101, id-cmc-statusInfoV2, {failed, 201, popRequired}}
{102, id-cmc-transactionId, 10132985123483401}
{103, id-cmc-senderNonce, 10005}
{104, id-cmc-recipientNonce, 10001}
{105, id-cmc-encryptedPOP, {
request {
crm
certReq
certReqId = 201
certTemplate
subject = < My DN >
publicKey = My Public Key
extensions
{id-ce-keyUsage, keyEncipherment}
{id-ce-subjectPublicKeyIdentifier, 1000}
popo
keyEncipherment
subsequentMessage = challengeResp
}
cms
contentType = id-envelopedData
content < uses ori.KEMRecipientInfo >
recipientInfos.ori.rid.issuerSerialNumber =
<NULL-DN, 201>
encryptedContentInfo
eContentType = id-data
eContent = <Encrypted value of 'y' from
Section 6.7>
thePOPAlgID = KmacWithSHAKE128
witnessAlgID = SHAKE128
witness <hashed value of 'y' from Section 6.7>}}
{106, id-cmc-dataReturn, <packet of binary data
identifying where the key
in question is.>}
certificates
Other certificates
(optional - related to this message's SignedData)
SignedData.SignerInfos
Signed by CA
Message #2 from client to server:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIData
eContent
controlSequence
{102, id-cmc-transactionId, 10132985123483401}
{103, id-cmc-senderNonce, 100101}
{104, id-cmc-dataReturn, <packet of binary data
identifying where the key
in question is.>}
{105, id-cmc-recipientNonce, 10005}
{107, id-cmc-decryptedPOP, {
bodyPartID 201,
thePOPAlgID KmacWithSHAKE128,
thePOP <KMAC computed value goes here>}}
reqSequence
crm
certReq
certReqId = 201
certTemplate
subject = < My DN >
publicKey = My Public Key
extensions
{id-ce-keyUsage, keyEncipherment}
{id-ce-subjectPublicKeyIdentifier, 1000}
popo
keyEncipherment
subsequentMessage = challengeResp
SignedData.SignerInfos
SignerInfo
sid = < subjectKeyIdentifier >
signatureAlgorithm = id-alg-noSignature
Response #2 from server to client:
ContentInfo.contentType = id-signedData
ContentInfo.content
SignedData.encapContentInfo
eContentType = id-cct-PKIResponse
eContent
controlSequence
{101, id-cmc-transactionId, 10132985123483401}
{102, id-cmc-statusInfoV2, {success, 201}}
{103, id-cmc-senderNonce, 10019}
{104, id-cmc-recipientNonce, 100101}
{105, id-cmc-dataReturn, <packet of binary data
identifying where the key
in question is.>}
certificates
Newly issued certificate
Other certificates
SignedData.SignerInfos
Signed by CA
Appendix C. Production of Diffie-Hellman Public Key Certification Requests 🎀
okay this one's a big deal bestie 👑 part of a certification request is a signature over the request, but DH and ECDH are key agreement algorithms, and the KEMs RSA-KEM and ML-KEM (Module-Lattic-Based KEM) can't be used to directly produce the required signature object 🙈 [DH-POP] gives three ways to make that signature value. This document also defines a signature algorithm that doesn't provide a POP value, but it can still be used to produce the necessary signature value ✨
C.1. No-Signature Signature Mechanism 🔐
key management (encryption/decryption) private keys can't always be used to make a signature, like on a decrypt-only device 💀 but certification requests need the signature field to be filled in. so this section gives us a signature algorithm made for exactly that purpose. the object identifier and signature value that identify this signature type are:
id-alg-noSignature OBJECT IDENTIFIER ::= { id-pkix id-alg(6) 2 }
NoSignatureValue ::= OCTET STRING
The parameters for id-alg-noSignature MUST be present and MUST be encoded as NULL. NoSignatureValue contains the SHA-1 hash of the certification request. The hash value given by NoSignatureValue SHOULD be ignored. Important: there is zero security associated with this signature type 🚨 If this signature type is on a certification request and the CA policy requires proof-of-possession of the private key, the POP mechanism defined in Section 6.7 MUST be used.
When the client generates the SignedData.SignerInfos.SignerInfo.sid field, it has two choices: issuerAndSerialNumber or subjectKeyIdentifier. The client doesn't have a certificate yet, so it can't fill in the issuerAndSerialNumber and MUST use the subjectKeyIdentifier choice 🫶
Acknowledgements 💜
The authors would like to thank Jim Schaad and Michael Myers for their work on RFC 5272 🙌
Thank you to Charlie Kaufman, Orie Steele, Paul Wouters, Éric Vyncke, Mike Bishop, Reese Enghardt, Mohamed Boucadair, Russ Housley, and Deb Cooley for reviewing the document and sharing comments 🌸
The Acknowledgements section from RFC 5272 follows:
The authors and the PKIX Working Group are grateful for the participation of Xiaoyi Liu and Jeff Weinstein in helping to author the original versions of this document. The authors would like to thank Brian LaMacchia for his work in developing and writing up many of the concepts presented in this document. The authors would also like to thank Alex Deacon and Barb Fox for their contributions.
Contributors 🧚
- Jim Schaad, August Cellars
- Michael Myers, TraceRoute Security, Inc.
Authors' Addresses 🦋
- Joseph Mandel (editor), AKAYLA, Inc., Email:
joe@akayla.com - Sean Turner (editor), sn3rd, Email:
sean@sn3rd.com
and that's the whole spec, bestie 🌈✨ we did it 😭🫶
📦 where this page comes from
- ietf: rfc10002 2026-07
- 💖 girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms