RFC 2797

Certificate Management Messages over CMS

πŸ“… published April 2000, from ietf

RFC 2797: Certificate Management Messages over CMS πŸŽ€

Okay bestie, this is RFC 2797, "Certificate Management Messages over CMS" πŸ’–. It's a Standards Track doc from the Network Working Group, dated April 2000 πŸ“…. The authors are M. Myers (VeriSign), X. Liu (Cisco), J. Schaad (Microsoft), and J. Weinstein. The header doesn't list anything it obsoletes or updates, so there's nothing to add there ✨.


Status of This Memo πŸ“œ

This doc specifies an Internet standards track protocol for the Internet community, and it wants your discussion and suggestions for improvements 🫢. For the standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1) πŸ”. Distribution of this memo is unlimited 🌈.

Copyright (C) The Internet Society (2000). All Rights Reserved. πŸ’œ

Abstract πŸ¦‹

So this doc defines a Certificate Management protocol that runs on CMS, and it calls that protocol CMC πŸ’…. It tackles two urgent needs in the Internet PKI community:

  1. The need for an interface to public key certification products and services based on [CMS] and [PKCS10], and
  2. The need in [SMIMEV3] for a certificate enrollment protocol for DSA-signed certificates with Diffie-Hellman public keys.

A small number of additional services are defined to supplement the core certificate request service ✨.

Throughout this spec, "CMS" is used to mean both [CMS] and [PKCS7] 🧚. For both signedData and envelopedData, CMS is a superset of PKCS7. In general, the way this doc uses PKCS7 lines up with the Cryptographic Message Syntax [CMS], which provides a superset of the PKCS7 syntax. "CMC" refers to this specification πŸŽ€.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119] πŸ”₯.


1. Protocol Requirements ✨

  • The protocol is to be based as much as possible on the existing CMS, PKCS#10 and CRMF specifications πŸ’….
  • The protocol must support the current industry practice of a PKCS#10 request followed by a PKCS#7 response as a subset of the protocol πŸ“.
  • The protocol needs to easily support the multi-key enrollment protocols required by S/MIME and other groups 🌸.
  • The protocol must supply a way of doing all operations in a single-round trip. When this is not possible, the number of round trips is to be minimized ⭐.
  • The protocol will be designed such that all key generation can occur on the client πŸ”‘.
  • The mandatory algorithms must superset the required algorithms for S/MIME πŸ‘‘.
  • The protocol will contain POP methods. Optional provisions for multiple-round trip POP will be made if necessary πŸ¦‹.
  • The protocol will support deferred and pending responses to certificate requests, for cases where external procedures are required to issue a certificate ⏳.
  • The protocol needs to support arbitrary chains of local registration authorities as intermediaries between certificate requesters and issuers 🧚.

2. Protocol Overview 🌈

An enrollment transaction in this spec is generally made up of a single round trip of messages πŸ’–. In the simplest case, an enrollment request is sent from the client to the server, and an enrollment response is sent back from the server to the client. In some more complicated cases, like delayed certificate issuance and polling for responses, more than one round trip is required πŸ™ˆ.

This spec supports two different request messages and two different response messages πŸ’….

Public key certification requests can be based on either the PKCS10 or CRMF object. The two different request messages are (a) the bare PKCS10 (when no other services are needed), and (b) the PKCS10 or CRMF message wrapped in a CMS encapsulation as part of a PKIData object πŸŽ€.

Public key certification responses are based on the CMS signedData object. The response may be either (a) a degenerate CMS signedData object (when no other services are needed), or (b) a ResponseBody object wrapped in a CMS signedData object 🫢.

No special services are provided for renewal (new certificates with the same key) or re-keying (new certificates on new keys) of clients. Instead, a renewal/re-key message looks the same as any enrollment message, with the identity proof supplied by existing certificates from the CA πŸ”.

There's a provision for Local Registration Authorities (LRAs) to join the protocol. They take client enrollment messages, wrap them in a second layer of enrollment message with extra requirements or statements from the LRA, and then pass this expanded request on to the Certification Authority πŸ§šβ€β™€οΈ.

This spec makes no assumptions about the underlying transport mechanism. The use of CMS is not meant to imply an email-based transport πŸ“­.

Optional services available through this spec are transaction management, replay detection (through nonces), deferred certificate issuance, certificate revocation requests, and certificate/CRL retrieval ✨.

2.1. Terminology πŸ“š

There are several terms, abbreviations and acronyms used in this doc. We define them here so everyone uses them the same way πŸ’œ:

  • "End-Entity" (EE) refers to the entity that owns a key pair and for whom a certificate is issued πŸ§‘.
  • "LRA" or "RA" refers to a (Local) Registration Authority. A registration authority acts as an intermediary between an End-Entity and a Certification Authority. Multiple RAs can exist between the End-Entity and the Certification Authority πŸŒ‰.
  • "CA" refers to a Certification Authority. A Certification Authority is the entity that actually performs the issuance of a certificate πŸ›οΈ.
  • "Client" refers to an entity that creates a PKI request. In this document, both RAs and End-Entities can be clients πŸ“¨.
  • "Server" refers to the entities that process PKI requests and create PKI responses. CAs and RAs can be servers in this document πŸ–₯️.
  • "PKCS#10" refers to the Public Key Cryptography Standard #10. This is one of a set of standards defined by RSA Laboratories in the 1980s. PKCS#10 defines a Certificate Request Message syntax πŸ•°οΈ.
  • "CRMF" refers to the Certificate Request Message Format RFC [CRMF]. We use the certificate request message format defined in that document as part of our management protocol πŸ“.
  • "CMS" refers to the Cryptographic Message Syntax RFC [CMS]. That document provides basic cryptographic services, including encryption and signing with and without key management πŸ”.
  • "POP" is an acronym for "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 of, and can be used by, an end-entity πŸ—οΈ.
  • "Transport wrapper" refers to the outermost CMS wrapping layer 🎁.

2.2. Protocol Flow Charts πŸ—ΊοΈ

Figure 1 shows the Simple Enrollment Request and Response messages. The contents of these messages are detailed in Sections 4.1 and 4.3 below πŸ’….

 Simple PKI Request                      Simple PKI Response
 -------------------------               --------------------------

 +----------+                            +------------------+
 | PKCS #10 |                            | CMS "certs-only" |
 +----------+--------------+             |     message      |
 |                         |             +------------------+------+
 |                         |             |                         |
 | Certificate Request     |             | CMS Signed Data,        |
 |                         |             |   no signerInfo         |
 | Subject Name            |             |                         |
 | Subject Public Key Info |             | signedData contains one |
 |   (K_PUB)               |             | or more certificates in |
 | Attributes              |             | the "certificates"      |
 |                         |             | portion of the          |
 |                         |             | signedData.             |
 +-----------+-------------+             |                         |
             | signed with |             | encapsulatedContentInfo |
             | matching    |             | is empty.               |
             | K_PRIV      |             |                         |
             +-------------+             +--------------+----------+
                                                        | unsigned |
                                                        +----------+

            Figure 1: Simple PKI Request and Response Messages

 Full PKI Request                        Full PKI Response
 -----------------------                 ------------------------

 +----------------+                      +----------------+
 | CMS signedData |                      | CMS signedData |
 |     object     |                      |     object     |
 +----------------+--------+             +----------------+--------+
 |                         |             |                         |
 | PKIData object          |             | ResponseBody object     |
 |                         |             |                         |
 | Sequence of:            |             | Sequence of:            |
 | <enrollment attribute>* |             | <enrollment attribute>* |
 | <certification request>*|             | <CMS object>*           |
 | <CMS objects>*          |             | <other message>*        |
 | <other message>*        |             |                         |
 |                         |             | where * == zero or more |
 | where * == zero or more |             |                         |
 |                         |             | All certificates issued |
 | Certificate requests    |             | as part of the response |
 | are CRMF or PKCS#10     |             | are included in the     |
 | objects. Attributes are |             | "certificates" portion  |
 | (OID, ANY defined by    |             | of the signedData.      |
 | OID) pairs.             |             | Relevant CA certs and   |
 |                         |             | CRLs can be included as |
 +-------+-----------------+             | well.                   |
         | signed (keypair |             |                         |
         | used may be pre-|             +---------+---------------+
         | existing or     |                       | signed by the |
         | identified in   |                       | CA or an LRA  |
         | the request)    |                       +---------------+
         +-----------------+

            Figure 2: Full PKI Request and Response Messages

Figure 2 shows the Full Enrollment Request and Response messages. The contents of these messages are detailed in Sections 4.2 and 4.4 below πŸŽ€.


3. Protocol Elements 🧩

This section covers each of the different elements that may be used to build enrollment request and enrollment response messages 🫢. Section 4 covers how to build the enrollment request and response messages themselves πŸ’–.

3.1. PKIData Object ✨

okay so a brand new content object called PKIData got created just for this protocol πŸ’– it's the body that goes inside the full PKI request message. its identifier is:

id-cct-PKIData  OBJECT IDENTIFIER ::= { id-cct 2 }

here's the ASN.1 structure for this new content type πŸŽ€

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
}

-- controlSequence consists of a sequence of control attributes.  The
control attributes defined in this document are found in section 5.
As control sequences are defined by OIDs, other parties can define
additional control attributes. Unrecognized OIDs MUST result in no
part of the request being successfully processed.

-- reqSequence consists of a sequence of certificate requests.  The
certificate requests can be either a CertificateRequest (PKCS10
request) or a CertReqMsg.  Details on each of these request types are
found in sections 3.3.1 and 3.3.2 respectively.

-- cmsSequence consists of a sequence of [CMS] message objects.  This
protocol only uses EnvelopedData, SignedData and EncryptedData.  See
section 3.6 for more details.

-- otherMsgSequence allows for other arbitrary data items to be
placed into the enrollment protocol.  The {OID, any} pair of values
allows for arbitrary definition of material.  Data objects are placed
here while control objects are placed in the controlSequence field.
See section 3.7 for more details.

the controlSequence is a list of control attributes 🧁 this doc's control attributes live in section 5, but since they're identified by OIDs, other parties can make their own too. heads up bestie: any unrecognized OID means no part of the request gets successfully processed πŸ’€

the reqSequence holds certificate requests, which can be a CertificateRequest (a PKCS10 request) or a CertReqMsg. the details for each one are in sections 3.3.1 and 3.3.2 respectively πŸ¦‹

the cmsSequence holds [CMS] message objects. this protocol only uses EnvelopedData, SignedData and EncryptedData, so check section 3.6 for the deets 🌸

the otherMsgSequence is the catch-all for any other arbitrary data items. the {OID, any} pair lets you define material however you want 🧚 data objects go here, and control objects go in the controlSequence field instead. see section 3.7 for more 🫢


3.2. ResponseBody Object πŸ’œ

the new content object ResponseBody was also created for this protocol πŸŽ€ it's the body that goes inside the full PKI response message, and its identifier is:

id-cct-PKIResponse OBJECT IDENTIFIER ::= { id-cct 3 }

the ASN.1 structure for this body content type looks like this ✨

ResponseBody ::= SEQUENCE {
    controlSequence   SEQUENCE SIZE(0..MAX) OF TaggedAttribute,
    cmsSequence       SEQUENCE SIZE(0..MAX) OF TaggedContentInfo,
    otherMsgSequence  SEQUENCE SIZE(0..MAX) OF OtherMsg
}

-- controlSequence consists of a sequence of control attributes.  The
control attributes defined in this document are found in section 3.5.
Other parties can define additional control attributes.

-- cmsSequence consists of a sequence of [CMS] message objects.  This
protocol only uses EnvelopedData, SignedData and EncryptedData.  See
section 3.6 for more details.

-- otherMsgSequence allows for other arbitrary items to be placed
into the enrollment protocol.  The {OID, any} pair of values allows
for arbitrary definition of material.  Data objects are placed here
while control objects are placed in the controlSequence field. See
section 3.7 for more details.

the controlSequence here has the control attributes that are defined in section 3.5 🌈 other parties can add their own control attributes too. the cmsSequence works the same way as before: [CMS] message objects, only EnvelopedData, SignedData and EncryptedData, details in section 3.6. and the otherMsgSequence is the arbitrary-items bin, with data going there and controls going in the controlSequence, per section 3.7 πŸ“


3.3. Certification Requests (PKCS10/CRMF) πŸ”₯

certification requests are built on either PKCS10 or CRMF messages πŸ’… section 3.3.1 covers the mandatory and optional stuff for clients and servers handling PKCS10 request messages. section 3.3.2 covers the same for CRMF request messages.

3.3.1. PKCS10 Request Body 🧁

servers MUST be able to understand and process PKCS10 request bodies πŸ’– clients MUST produce a PKCS10 request body when using the Simple Enrollment Request message. clients MAY produce a PKCS10 request body when using the Full Enrollment Request message.

when a client produces a PKCS10 request body, it MUST produce a PKCS10 message body that contains a subject name and public key ✨ some certification products run off a central repository that assigns subject names once it gets a public key for certification. to make that work, the subject name in a CertificationRequest MAY be NULL, but it MUST still be present. CAs that get a CertificationRequest with a NULL subject name MAY reject it πŸ™ˆ if they reject it and send back a response, the CA MUST respond with the failInfo attribute of badRequest.

the client MAY put one or more standard X.509 v3 extensions in any PKCS10 request as an ExtensionReq attribute πŸ¦‹ an ExtensionReq attribute is defined like this:

ExtensionReq ::= SEQUENCE OF Extension

where Extension is imported from [PKIXCERT], and ExtensionReq is identified by {pkcs-9 14}.

servers MUST be able to process all extensions defined in [PKIXCERT] 🫢 servers are not required to process other V3 X.509 extensions sent through this protocol, and they're also not required to process other private extensions. servers are not required to put every client-requested extension into a certificate, and they're allowed to modify client-requested extensions πŸ‘‘ but servers MUST NOT alter an extension in a way that invalidates the original intent of a client-requested extension. (for example, changing key usage from key exchange to signing πŸ’€). if a certification request gets denied because the server can't handle a requested extension and a response is returned, the server MUST respond with the failInfo attribute of unsupportedExt.

3.3.2. CRMF Request Body 🌸

servers MUST be able to understand and process CRMF request bodies ✨ clients MAY produce a CRMF message body when using the Full Enrollment Request message.

this memo adds a few more rules for building and processing CRMF messages πŸŽ€

  • when CRMF message bodies are used in the Full Enrollment Request message, each CRMF message MUST include both the subject and publicKey fields in the CertTemplate. same as with PKCS10 requests, the subject can be encoded as NULL, but it MUST be present.
  • in general, when both CRMF and CMC controls do the same job, the CMC control SHOULD be used. the CMC control MUST override any CRMF control.
  • the regInfo field MUST NOT be used on a CRMF message. the same functionality is provided by the regInfo control attribute (section 5.12).
  • the indirect method of proving POP is not supported in this protocol πŸ™… one of the other methods (including the direct method described in this document) MUST be used instead if POP is wanted. the value of encrCert in SubsequentMessage MUST NOT be used.
  • since the subject and publicKey values are always present, the POPOSigningKeyInput MUST NOT be used when computing the value for POPSigningKey.

a server doesn't have to use all of the values the client suggests in the certificate template 🧚 servers MUST be able to process all extensions defined in [PXIXCERT] (yes, that's how the citation is written in the original πŸ™ˆ). servers are not required to process other V3 X.509 extensions sent through this protocol, and they're not required to process other private extensions either. servers are permitted to modify client-requested extensions, but they MUST NOT alter an extension so as to invalidate the original intent of a client-requested extension (for example, changing key usage from key exchange to signing). if a certificate request gets denied because the server can't handle a requested extension, the server MUST respond with a failInfo attribute of unsupportedExt.

3.3.3. Production of Diffie-Hellman Public Key Certification Requests πŸ”₯

part of a certification request is a signature over the request πŸ’… Diffie-Hellman is a key agreement algorithm, so it can't directly produce the required signature object. [DH-POP] gives two ways to produce the necessary 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 ✨

3.3.3.1. No-Signature Signature Mechanism πŸ™ˆ

key management (encryption/decryption) private keys can't always be used to produce a signature value, like when they're in a decrypt-only device πŸ” certification requests require the signature field to be populated, so this section provides a signature algorithm for exactly that purpose. the following object identifier and signature value identify this signature type:

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 hash of the certification request.

this is important, bestie: there is no security associated with this signature type πŸ’€ if it's on a certification request and the Certification Authority policy requires proof-of-possession of the private key, the POP mechanism defined in section 5.7 MUST be used.

3.3.3.2. Diffie-Hellman POP Signature πŸ’œ

CMC compliant implementations MUST support section 5 of [DH-POP] πŸ‘‘

3.3.3.3. Diffie-Hellman MAC signature πŸ¦‹

CMC compliant implementations MAY support section 4 of [DH-POP] 🌈


3.4. Body Part Identifiers πŸ“

every element of a PKIData or PKIResponse message has an associated body part identifier 🧁 the Body Part Identifier is a 4-octet integer. it's encoded in the certReqIds field for CertReqMsg objects (inside a TaggedRequest), or in the bodyPartId field of the other objects. the Body Part Identifier MUST be unique within a single PKIData or PKIResponse object. body part identifiers CAN be duplicated across different layers (like a CMC message embedded inside another one), since the spec doesn't forbid that 🧚

the Body Part Id of zero is reserved to point at the current PKIData object 🫢 this value is used in control attributes like the Add Extensions Control, in the pkiDataReference field, to refer to a request in the current PKIData object.

some control attributes, like the CMC Status Info attribute, also use Body Part Identifiers to refer to elements in the previous message πŸ’– that way an error can be explicit about which attribute or request it applies to.


3.5. Control Attributes πŸŽ€

the overall control flow for how a message gets processed in this document is based on control attributes ✨ each control attribute has an object identifier and a value based on that object identifier.

servers MUST fail the processing of an entire PKIData message if any included control attribute isn't recognized πŸ™… the response MUST be the error badRequest, and bodyList MUST contain the bodyPartID of the invalid or unrecognized control attribute.

the syntax of a control attribute is:

TaggedAttribute ::= SEQUENCE {
    bodyPartID         BodyPartId,
    attrType           OBJECT IDENTIFIER,
    attrValues         SET OF AttributeValue
}
-- bodyPartId is a unique integer that is used to reference this
control attribute. The id of 0 is reserved for use as the
reference to the current PKIData object.

-- attrType is the OID defining the associated data in attrValues

-- attrValues contains the set of data values used in processing
the control attribute.

the set of control attributes this memo defines lives in section 5 🌸

3.6. Content Info objects ✨

okay so the cmsSequence field in PKIRequest and PKIResponse messages holds zero or more tagged content info objects πŸ“¦. Here's the structure:

TaggedContentInfo ::= SEQUENCE {
    bodyPartID              BodyPartId,
    contentInfo             ContentInfo
}

 -- bodyPartId is a unique integer that is used to reference this
 content info object. The id of 0 is reserved for use as the
 reference to the current PKIData object.

 -- contentInfo contains a ContentInfo object (defined in [CMS]).
 The three contents used in this location are SignedData,
 EnvelopedData and Data.

So the three contents you can stick in there are SignedData, EnvelopedData, and Data πŸŽ€. EnvelopedData is for shrouding (hiding) your data πŸ™ˆ, and Data is for general transport of unstructured data, no drama needed.

The SignedData object from [CMS] also shows up in this spec for authentication πŸ”, and it doubles as the general transport wrapper for requests and responses. Iconic multitasking πŸ’…

3.6.1. Signed Data

The signedData object shows up in two places when you're building enrollment messages πŸ¦‹. First, it wraps a PKIData as part of the enrollment request message. Second, it's the outer part of an enrollment response message.

For the enrollment response, the signedData wrapper lets the server sign the returning data (if there is any) and carry the certificates and CRLs for the enrollment request πŸ“œ. If there's nothing being returned beyond the certificates, then no signerInfo objects go in the signedData object. Clean and simple ✨

3.6.2. Enveloped Data

EnvelopedData is the main way this protocol gives confidentiality to sensitive info πŸ”’. Right now the protocol uses EnvelopedData to encrypt an entire request (see section 4.5). The envelopedData object would also be used to wrap private key material for key archival πŸ—οΈ.

Servers MUST implement envelopedData according to [CMS]. Heads up though: there's an ambiguity in the PKCS7 spec about encrypting content types other than id-data, and it has led to non-interoperability πŸ’€. So be careful, bestie!

3.7. Other Message Bodies 🎁

The other message body portion lets you carry arbitrary data objects as part of a message 🧚. It's meant for stuff that isn't already wrapped in a CMS contentInfo object. The data gets ignored unless a control attribute references it by bodyPartId πŸ‘€.

OtherMsg ::= SEQUENCE {
    bodyPartID        BodyPartID,
    otherMsgType      OBJECT IDENTIFIER,
    otherMsgValue     ANY DEFINED BY otherMsgType }

 -- bodyPartID contains the unique id of this object

 -- otherMsgType contains the OID defining both the usage of this body
 part and the syntax of the value associated with this body part

 -- otherMsgValue contains the data associated with the message body
 part.

4. PKI Messages πŸ’Œ

This section is all about how to put together the different enrollment request and response messages 🧩. Let's get into it!

4.1. Simple Enrollment Request 🌸

The simplest enrollment request is a plain PKCS10 message πŸ“. If you're using this form for a private key that can generate a signature, the PKCS10 MUST be signed with that private key. And if this form is used for a D-H key, the D-H POP mechanism described in [DH-POP] MUST be used. Non-negotiable, periodt πŸ’…

Servers MUST support the Simple Enrollment Request message. If the Simple Enrollment Request message is used, servers MUST return the Simple Enrollment Response message (see Section 4.3) if the enrollment request is granted ✨. If the enrollment request fails, the Full Enrollment Response MAY be returned, or no response MAY be returned. Options, options πŸ¦‹.

Many advanced services specified in this memo aren't supported by the Simple Enrollment Request message, so it's the basic version, not the glam one πŸ₯².

4.2. Full PKI Request πŸ‘‘

The Full Enrollment Request gives you the most functionality and flexibility πŸ’–. Clients SHOULD use the Full Enrollment Request message when enrolling. Servers MUST support the Full Enrollment Request message. An enrollment response (full or simple, as appropriate) MUST be returned to all Full Enrollment Requests πŸ“¬.

The Full Enrollment Request message is a PKIData object wrapped in a signedData CMS object. The objects in the PKIData are ordered like this:

  1. All Control Attributes,
  2. All certification requests,
  3. All CMS objects,
  4. All other messages.

Every element in a Full Enrollment Request is identified by a Body Part Identifier 🏷️. If duplicate ids turn up, the server MUST return the error badRequest with a bodyPartID of 0. Duplicates are NOT the vibe πŸ™…β€β™€οΈ.

The signedData object wrapping the PKIData may be signed either with the private key material of the signature certification request, or by a previously certified signature key πŸ”‘. If the private key of a signature certification request is being used, then:

a) the certification request containing the corresponding public key MUST include a Subject Key Identifier extension request, b) the subjectKeyIdentifier form of signerInfo MUST be used, and c) 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 been issued for the signing key yet 🧸.) If the request key is used for signing, there MUST be only one signerInfo object in the signedData object. One and only one, no exceptions πŸ’….

When you're creating a message to renew a certificate, keep these in mind πŸ”„:

  1. The identification and identityProof control statements are not required. The same info is provided by using an existing certificate from the CA when signing the enrollment message πŸͺͺ.
  2. CAs and LRAs may impose additional restrictions on the signing certificate used. They may require that the most recently issued signing certificate for an entity be used πŸ“œ.
  3. A renewal message may occur either by creating a new set of keys, or by re-using an existing set of keys. Some CAs may prevent re-use of keys by policy. In this case the CA MUST return NOKEYREUSE as the failure code πŸ™ƒ.

4.3. Simple Enrollment Response ✨

Servers SHOULD use the simple enrollment response message whenever possible πŸ’«. Clients MUST be able to process the simple enrollment response message. It's a signedData object with no signerInfo objects on it, and the requested certificates come back in the certificate bag of the signedData object πŸ“¦.

Clients MUST NOT assume the certificates are in any order πŸŒ€. Servers SHOULD include all intermediate certificates needed to form complete chains to one or more self-signed certificates, not just the newly issued certificate(s) πŸ”—. The server MAY additionally return CRLs in the CRL bag. Servers MAY include the self-signed certificates. Clients MUST NOT implicitly trust included self-signed certificate(s) just because they're in the certificate bag 🚫. If clients get a new self-signed certificate from the server, they SHOULD provide a mechanism that lets the user explicitly trust it πŸ›‘οΈ.

4.4. Full PKI Response 🌈

Servers MUST return full PKI response messages if a) a full PKI request message failed, or b) additional services other than returning certificates are required. Servers MAY return full PKI responses with failure information for simple PKI requests. Following section 4.3 above, servers that return only certificates and a success status to the client SHOULD use the simple PKI response message πŸ₯°.

Clients MUST be able to process a full PKI response message βœ….

The full enrollment response message is a signedData object encapsulating a responseBody object. In a responseBody object, all Control Attributes MUST precede all CMS objects 🧾. The certificates granted in an enrollment response are returned in the certificates field of the immediately encapsulating signedData object πŸŽ€.

Clients MUST NOT assume the certificates are in any order πŸŒ€. Servers SHOULD include all intermediate certificates needed to form complete chains to one or more self-signed certificates, not just the newly issued certificate(s) πŸ”—. The server MAY additionally return CRLs in the CRL bag. Servers MAY include the self-signed certificates. Clients MUST NOT implicitly trust included self-signed certificate(s) just because they're in the certificate bag 🚫. If clients get a new self-signed certificate from the server, they SHOULD provide a mechanism that lets the user explicitly trust it πŸ›‘οΈ.

4.5. Application of Encryption to a PKI Message πŸ”

Sometimes a PKI request or response message has to be encrypted so that no info about the enrollment is visible to unauthorized entities πŸ‘€. This section describes how to encrypt a PKI message. It doesn't apply to a simple enrollment message, so don't bother with it there πŸ™…β€β™€οΈ.

Confidentiality comes from wrapping the PKI message (a signedData object) in a CMS EnvelopedData object 🎁. The nested content type inside the EnvelopedData is id-signedData. This is different from S/MIME, where a MIME layer sits between the encrypted and signed data objects, so don't mix them up! πŸ™ˆ It is recommended that if an enveloped data layer is applied to a PKI message, a second signing layer be placed outside of the enveloped data layer. Here's how the nesting works πŸͺ†:

  Normal              Option 1                  Option 2
  ------              --------                  --------
  SignedData          EnvelopedData             SignedData
   PKIData             SignedData                EnvelopedData
                        PKIData                   SignedData
                                                   PKIData

Options 1 and 2 keep sensitive data from leaking, since the info gets encrypted πŸ”’. LRAs can remove the enveloped data wrapping, then replace or forward the message without further processing πŸ¦‹. Section 6 has more about LRA processing.

PKI Messages MAY be encrypted or transmitted in the clear. Servers MUST provide support for all three versions πŸ’œ.

Alternatively, an authenticated, secure channel could exist between the parties that need encryption 🌷. Clients and servers MAY use such channels instead of the technique described above to provide secure, private communication of PKI request and response messages 🫢.

5. Control Attributes ✨

okay so control attributes are the little extras riding along in both PKI requests and responses πŸ’… each one is written as a unique Object Identifier, then the data for that attribute. the OID tells you how to read the data that follows, and processing systems check the OID first and handle that attribute before they touch the message body. it's giving organized πŸŽ€

here's the full lineup of control attributes this memo covers, with their names, OIDs, and syntax:

Control Attribute         OID            Syntax
-----------------       ----------     --------------
cMCStatusInfo           id-cmc 1       CMCStatusInfo
identification          id-cmc 2       UTF8String
identityProof           id-cmc 3       OCTET STRING
dataReturn              id-cmc 4       OCTET STRING
transactionId           id-cmc 5       INTEGER
senderNonce             id-cmc 6       OCTET STRING
recipientNonce          id-cmc 7       OCTET STRING
addExtensions           id-cmc 8       AddExtensions
encryptedPOP            id-cmc 9       EncryptedPOP
decryptedPOP            id-cmc 10      DecryptedPOP
lraPOPWitness           id-cmc 11      LraPOPWitness
getCert                 id-cmc 15      GetCert
getCRL                  id-cmc 16      GetCRL
revokeRequest           id-cmc 17      RevokeRequest
regInfo                 id-cmc 18      OCTET STRING
responseInfo            id-cmc 19      OCTET STRING
QueryPending            id-cmc 21      OCTET STRING
idPOPLinkRandom         id-cmc 22      OCTET STRING
idPOPLinkWitness        id-cmc 23      OCTET STRING
idConfirmCertAcceptance id-cmc 24      CMCCertId

5.1. CMC Status Info Control Attribute

the CMC status info control is the one used in full PKI Response messages to report back on a client's request πŸ¦‹ servers MAY emit multiple CMC status info controls that point at one single body part. clients MUST be able to handle multiple CMC status info controls in a response message. here's the ASN.1 definition for this one:

   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 is described in section 5.1.1

   -- bodyList contains the list of body parts in the request message
   to which this status information applies.  If an error is being
   returned for a simple enrollment message, body list will contain a
   single integer of value '1'.

   -- statusString contains a string with additional description
   information.  This string is human readable.

   -- failInfo is described in section 5.1.2. It provides a detailed
   error on what the failure was.  This choice is present only if
   cMCStatus is failed.

   -- pendToken is the token to be used in the queryPending control
   attribute.

   -- pendTime contains the suggested time the server wants to be
   queried about the status of the request.

ngl the rule for success is the chill part 😌 if the cMCStatus field says success, the CMC Status Info Control MAY be omitted, unless it's the only item in the response message. and if there's no status for a certificate request or some other item that needs processing, success is just assumed. no drama πŸ’œ

5.1.1. CMCStatus values

the cMCStatus field lives inside the CMCStatusInfo structure πŸ“ it holds a code for whether a specific operation worked or didn't. here's its ASN.1 structure:

   CMCStatus ::= INTEGER {
        success                (0),
        -- request was granted
        -- reserved            (1),
        -- not used, defined where the original structure was defined
        failed                 (2),
        -- you don't get what you want, more information elsewhere in
   the message
        pending                (3),
        -- the request body part has not yet been processed,
        -- requester is responsible to poll back on this
        -- pending may only be return for certificate request
   operations.
        noSupport              (4),
        -- the requested operation is not supported
        confirmRequired        (5)
        -- conformation using the idConfirmCertAcceptance control is
   required
        -- before use of certificate
   }

5.1.2. CMCFailInfo

CMCFailInfo is the detail-level tea β˜• it tells you about the reason behind a failure condition. the CMCFailInfo has this ASN.1 structure:

   CMCFailInfo ::= INTEGER {
        badAlg            (0)
        -- Unrecognized or unsupported algorithm
        badMessageCheck   (1)
        -- integrity check failed
        badRequest        (2)
        -- transaction not permitted or supported
        badTime           (3)
        -- Message time field was not sufficiently close to the system
   time
        badCertId         (4)
        -- No certificate could be identified matching the provided
   criteria
        unsuportedExt     (5)
        -- A requested X.509 extension is not supported by the
   recipient CA.
        mustArchiveKeys   (6)
        -- Private key material must be supplied
        badIdentity       (7)
        -- Identification Attribute failed to verify
        popRequired       (8)
        -- Server requires a POP proof before issuing certificate
        popFailed         (9)
        -- POP processing failed
        noKeyReuse        (10)
        -- Server policy does not allow key re-use
        internalCAError   (11)
        tryLater          (12)
   }

additional failure reasons MAY be defined for closed environments that have a need for them 🌈

5.2. Identification and IdentityProof Control Attributes

some CAs and LRAs want proof of identity baked into a certification request πŸ” there are tons of ways to do this, with different levels of security and reliability. most of us already know the bank move where they ask for your mother's maiden name as proof it's you πŸ™ˆ

CMC gives you one method for proving the client's identity, and it's based on a shared secret between the certificate requestor and the verifying authority. if clients support full request messages, clients MUST implement this method of identity proof. servers MUST provide this method, and they MAY also have a bilateral method of similar strength available.

the CMC method starts with an out-of-band transfer of a token, which is the shared secret. how that token gets distributed is beyond the scope of this document 🧚 the client then uses the token for identity proof like this:

  1. the reqSequence field of the PKIData object (encoded exactly as it appears in the request message, including the sequence type and length) is the value to be validated.
  2. a SHA1 hash of the token is computed.
  3. an HMAC-SHA1 value is then computed over the value produced in Step 1, as described in [HMAC], using the hash of the token from Step 2 as the shared secret value.
  4. the 160-bit HMAC-SHA1 result from Step 3 is then encoded as the value of the identityProof attribute.

when the server verifies the identityProof attribute, it computes the HMAC-SHA1 value the same way and compares it to the identityProof attribute contained in the enrollment request πŸ‘‘

if a server fails the verification of an identityProof attribute and returns a response message, the failInfo attribute MUST be present in the response and MUST have a value of badIdentity. no skipping this one, bestie πŸ’€

optionally, servers MAY require the inclusion of the unprotected identification attribute along with an identification attribute 🫢 the identification attribute is meant to hold either a text string or a numeric quantity, like a random number, that helps the server find the shared secret it needs to validate the contents of the identityProof attribute. numeric values MUST be converted to text string representations before they get encoded as UTF8-STRINGs in this attribute. if the identification control attribute is in the message, the derivation of the shared secret in step 2 changes, so the hash covers the concatenation of the token and the identity value, instead of just the token. it's a whole glow-up 🌸

5.2.1. Hardware Shared Secret Token Generation

sometimes the shared secret between the end-entity and the identity verifier gets transferred using a hardware device that spits out a series of tokens based on some shared secret value πŸ”₯ so the user can prove who they are by sending that token in plain text along with a name string. the protocol above can be used with a hardware shared-secret token generation device, with these modifications:

  1. the identification attribute MUST be included, and it MUST contain the hardware-generated token.
  2. the shared secret value used above is the same hardware-generated token.
  3. 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.

5.3. Linking Identity and POP Information

in a PKI Full Request message, identity info about the creator/author of the message is carried in the signature of the CMS SignedData object that holds all of the certificate requests πŸ’œ proof-of-possession info for the key pairs requesting certification, though, gets carried separately for each PKCS#10 or CRMF message. (for keys that can generate a digital signature, the POP is provided by the signature on the PKCS#10 or CRMF request. for encryption-only keys, the controls described in Section 5.7 below are used.) to stop substitution-style attacks, we must guarantee that the same entity generated both the POP and the proof-of-identity information. this is the main character moment for security 😭

this section describes two ways to link identity and POP info: witness values that are cryptographically derived from the shared secret (Section 5.3.1), and shared-secret/subject DN matching (Section 5.3.2). clients and servers MUST support the witness value technique. clients and servers MAY support shared-secret/subject DN matching or other bilateral techniques of similar strength. the idea behind both mechanisms is to make the client sign some data into each certificate request that can be directly tied back to the shared secret. that way, attempts to slip certificate requests from different entities into a single Full PKI Request message get shut down 🚫✨

5.3.1. Witness values derived from the shared-secret πŸ”

okay so the first way to do identity-POP linking is lowkey genius 🧠. The client has to tuck a piece of info, cryptographically derived from the shared-secret token, into a signed extension on every certificate request (PKCS#10 or CRMF) message πŸ’Œ. This is super useful when null subject DNs are used, because the server can build the subject DN using only the shared secret 🧚. It all starts when the client gets the shared-secret token out-of-band from the server πŸ“¦. Then the client computes these values:

  1. The client generates a random byte-string, R, which SHOULD be at least 512 bits in length. 🎲
  2. A SHA1 hash of the token is computed.
  3. An HMAC-SHA1 value is then computed over the random value produced in Step 1, as described in [HMAC], using the hash of the token from Step 2 as the shared secret.
  4. The random value produced in Step 1 is encoded as the value of an idPOPLinkRandom control attribute. This control attribute MUST be included in the Full PKI Request message. πŸ’–
  5. The 160-bit HMAC-SHA1 result from Step 3 is encoded as the value of an idPOPLinkWitness extension to the certificate request.
    • a. For CRMF, idPOPLinkWitness is included in the controls section of the CertRequest structure.
    • b. For PKCS#10, idPOPLinkWitness is included in the attributes section of the CertificationRequest structure.

Once the server receives everything, servers MUST verify that each certificate request contains a copy of the idPOPLinkWitness, and that its value was derived the specified way from the shared secret and the random string in the idPOPLinkRandom control attribute. No skipping this check, bestie πŸ™…β€β™€οΈβœ¨

5.3.2. Shared-secret/subject DN matching πŸŽ€

the second technique is to link one specific subject distinguished name (subject DN) to the shared secrets that get distributed out-of-band. Then clients using that shared secret to prove identity have to include that exact subject DN in every certificate request πŸ“. Honestly, a LOT of client-server connections using shared-secret proof-of-identity are going to use this one πŸ™Œ. (It's also super common to keep the subject DN info in certificate request messages, so don't leave it out πŸ’….)

When the shared secret is generated and sent out-of-band to kick off registration (Section 5.2), a particular subject DN gets attached to it and handed to the client too 🎁. (The subject DN generated MUST be unique per entity under CA policy, so a null subject DN cannot be used. A common practice is to put the identification value inside the subject DN πŸͺͺ.) When the client builds the Full PKI Request message, it MUST use these two pieces of info like this:

  1. The client MUST include the specific subject DN it received along with the shared secret as the subject name in every certificate request (PKCS#10 and/or CRMF) in the Full PKI Request. The subject names in the requests MUST NOT be null. 🚫
  2. The client MUST include the identityProof control attribute (Section 5.2), derived from the shared secret, in the Full PKI Request.

The server receiving this message MUST (a) validate the identityProof control attribute and then, (b) check that the subject DN in each certificate request matches the one tied to the shared secret. If either check fails, the certificate request MUST be rejected. Nope, no exceptions 😀

5.3.3. Renewal and Re-Key Messages πŸ”„

in a renewal or re-key message, the subject DN in (a) the certificate referenced by the CMS SignerInfo object and (b) all certificate requests inside the request message MUST match, following the standard name match rules described in [PKIXCERT]. Matching is the whole vibe here πŸ’œ

5.4. Data Return Control Attribute πŸ“¬

the data return control attribute lets clients send arbitrary data (usually some kind of internal state info) to the server and get that same data back as part of the enrollment response πŸ”. Whatever's in a data return statement is opaque to the server, so it can't peek inside πŸ™ˆ. The same control is used for both requests and responses. If the data return statement shows up in an enrollment message, the server MUST return it as part of the enrollment response message. No ghosting allowed πŸ‘»

If the info in the data return statement needs to stay confidential, the client is expected to encrypt it somehow, but the details are outside the scope of this spec πŸ”’ (not our job here, bestie).

An example would be a client putting in an identifier that marks the exact source of the private key material. That might be the identifier of a hardware device holding the private key πŸ”‘πŸ’»

5.5. Add Extensions Control Attribute βž•

the Add Extensions control attribute is how LRAs specify extra extensions to be placed on certificates πŸŽ€. This attribute uses the following ASN.1 definition:

     AddExtensions ::= SEQUENCE {
         pkiDataReference             BodyPartID
         certReferences               SEQUENCE OF BodyPartID,
         extensions                   SEQUENCE OF Extension
     }

      -- pkiDataReference field contains the body part id of the
      embedded request message.

      -- certReferences field is a list of references to one or more of
      the payloads contained within a PKIData.  Each element of the
      certReferences sequence MUST be equal to either the bodyPartID of
      a TaggedCertificationRequest or the certReqId of the CertRequest
      within a CertReqMsg.   By definition, the listed extensions are to
      be applied to every element referenced in the certReferences
      sequence.  If a request corresponding to bodyPartID cannot be
      found, the error badRequest is returned referencing this control
      attribute.

      -- extensions field contains the sequence of extensions to be
      applied to the referenced certificate requests.

Servers MUST be able to process all extensions defined in [PKIXCERT]. They are not required to handle every V3 X.509 extension sent over this protocol, and they're not required to handle other private extensions either πŸ€·β€β™€οΈ. Servers are also not required to put every LRA-requested extension into a certificate. They are allowed to modify LRA-requested extensions πŸ› οΈ, but servers MUST NOT alter an extension so that it reverses the meaning of a client-requested extension. That would be a major no πŸ™…β€β™€οΈπŸ’€. If a certification request gets denied because the server can't handle a requested extension and a response is returned, the server MUST return a failInfo attribute with the value unsupportedExt.

If there are multiple Add Extensions statements in an enrollment message, the exact behavior is left up to the certificate issuer policy. However, it is recommended to use the following policy πŸ“‹. These rules get applied to individual extensions inside an Add Extensions control attribute (not an "all or nothing" thing πŸ™Œ):

  1. If the conflict is within a single PKIData object, the certificate request would be rejected with an error of badRequest.
  2. If the conflict is between different PKIData objects, the outermost version of the extension would be used. This lets an LRA override the extension the end-entity requested πŸ‘‘

5.6. Transaction Management Control Attributes 🧾

transactions get identified and tracked using a transaction identifier πŸͺͺ. If it's used, clients generate transaction identifiers and hold onto the value until the server responds with a message that completes the transaction. Servers then include the received transaction identifiers in the response πŸ”.

The transactionId attribute identifies a given transaction. It's how client and server manage the state of an operation 🧚. Clients MAY include a transactionID attribute in request messages. If the original request has a transactionID attribute, all subsequent request and response messages MUST include that same transactionID attribute. A server MUST use only transactionIds in the outermost PKIdata object. TransactionIds on inner PKIdata objects are for intermediate entities πŸ§ƒ

Replay protection can be supported with sender and recipient nonces πŸ›‘οΈ. If nonces are used, the first message of a transaction carries no recipientNonce. Instead, a senderNonce is created by the message originator and kept for later reference πŸ“Œ. The recipient of a sender nonce reflects that value back to the originator as a recipientNonce, and includes its own senderNonce. When the transaction originator gets this message, it compares the recipientNonce to its saved value. If they match, the message can be accepted for further security processing βœ…. The received senderNonce is also kept so it can be included in the next message of the same transaction.

The senderNonce and recipientNonce attributes can provide application-level replay prevention πŸ’…. Clients MAY include a senderNonce in the initial request message. Originating messages include only a value for senderNonce. If a message includes a senderNonce, the response MUST include the transmitted value of the previously received senderNonce as recipientNonce, and include a new value for senderNonce. A server MUST use only nonces in the outermost PKIdata object. Nonces on inner PKIdata objects are for intermediate entities 🫢

5.7 Proof-of-possession (POP) for encryption-only keys πŸ”

Okay bestie, everything in this section is totally optional to implement, for servers AND clients πŸ’…. Servers MAY require this POP method be used only if another POP method is unavailable. Servers SHOULD reject all requests contained within a PKIData if any required POP is missing for any element within the PKIData. πŸ™ˆ

So a lot of servers want proof that whoever is asking for a cert for a public key actually has the matching private half πŸ—οΈ. For keys that can be used as signature keys, signing the certification request with the private key counts as the POP, iconic. But for keys that can only do encryption, POP MUST be performed by forcing the client to decrypt a value. ✨ If you want the full tea on POP, go read Section 5 of [CRMF].

This one can't happen in one round-trip, because there are four distinct phases πŸ¦‹:

  1. Client tells the server about the public component of a new encryption key pair.
  2. Server sends the client a POP challenge, encrypted with the presented public encryption key, which the client must decrypt.
  3. Client decrypts the POP challenge and sends it back to the server.
  4. Server validates the decrypted POP challenge and continues processing the certificate request.

CMC defines two different attributes πŸ’œ. The first one deals with the encrypted challenge sent from the server to the user in step 2. The second one deals with the decrypted challenge sent from the client to the server in step 3.

The encryptedPOP attribute is how the encrypted challenge gets from the server to the client πŸŽ€. It's encoded as a tagged attribute within the controlSequence of a ResponseBody. (Also, we're assuming the message in Step 1 is an enrollment request, and the response in step 2 is a Full Enrollment Response with a failureInfo saying a POP is explicitly required, plus the POP challenge in the encryptedPOP attribute. Main character set-up, honestly πŸ‘‘.)

   EncryptedPOP ::= SEQUENCE {

        request        TaggedRequest,
        cms            contentInfo,
        thePOPAlgID    AlgorithmIdentifier,
        witnessAlgID   AlgorithmIdentifier,
        witness        OCTET STRING

   }

   DecryptedPOP ::= SEQUENCE {
        bodyPartID     BodyPartID,
        thePOPAlgID    AlgorithmIdentifier,
        thePOP         OCTET STRING
   }

Okay, so the encrypted POP algorithm goes like this 🧚:

  1. The server generates a random value y and associates it with the request.
  2. The server returns the encrypted pop with the following fields set:
    • a. request is the certificate request in the original request message. (It's included here so the client doesn't need to keep a copy of the request, which is so considerate 🫢.)
    • b. cms is an EnvelopedData object, the content type being id-data and the content being the value y. If the certificate request contains a subject key identifier (SKI) extension, then the recipient identifier SHOULD be the SKI. If the issuerAndSerialNumber form is used, the IsserName MUST be encoded as NULL and the SerialNumber as the bodyPartId of the certificate request.
    • c. thePOPAlgID contains the algorithm to be used in computing the return POP value.
    • d. witnessAlgID contains the hash algorithm used on y to create the field witness.
    • e. witness contains the hashed value of y.
  3. The client decrypts the cms field to get the value y. The client computes H(y) using the witnessAlgID and compares it to the value of witness. If the values don't compare, or the decryption isn't successful, the client MUST abort the enrollment process 😭. The client aborts by sending a request message containing a CMCStatusInfo control attribute with failInfo value of popFailed.
  4. The client creates the decryptedPOP as part of a new PKIData message. The fields in the decryptedPOP are:
    • a. bodyPartID refers to the certificate request in the new enrollment message.
    • b. thePOPAlgID is copied from the encryptedPOP.
    • c. thePOP contains the possession proof. This value is computed by thePOPAlgID using the value y and request referenced in (4a).
  5. The server then re-computes the value of thePOP from its cached value of y and the request, and compares it to the value of thePOP. If the values do not match, the server MUST NOT issue the certificate 🚫. The server MAY re-issue a new challenge or MAY fail the request altogether.

When you're defining the algorithms for thePOPAlgID and witnessAlgID, care must be taken to make sure the result of witnessAlgID is not a useful value for shortcutting the computation with thePOPAlgID πŸ‘€. Clients MUST implement SHA-1 for witnessAlgID. Clients MUST implement HMAC-SHA1 for thePOPAlgID. The value of y is used as the secret value in the HMAC algorithm, and the request referenced in (4a) is used as the data. If y is greater than 64 bytes, only the first 64 bytes of y are 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. This describes one of many possible ways to fix it by cutting the state kept on the CA down to a single value (or a small set of values) πŸ₯Ί.
  1. Server generates random seed x, constant across all requests. (The value of x would normally be changed on a regular basis and kept for a short time afterwards.)
  2. For certificate request R, server computes y = F(x,R). F can be, for example, HMAC-SHA1(x,R). All that matters for statelessness is that y can be consistently computed from only the known constant state x and function F, with other inputs coming from the cert request structure. y should not be predictable from knowledge of R, which is why we use a OWF like HMAC-SHA1 🧠.

5.8 LRA POP Witnesses Control Attribute 🌸

In an enrollment scenario involving an LRA, the CA may allow (or require) the LRA to perform the POP protocol with the entity requesting certification. In that case, the LRA needs a way to tell the CA it has done the POP, so this control attribute was created to handle exactly that πŸ’….

The ASN.1 structure for the LRA POP witness looks like this:

   LraPopWitness ::= SEQUENCE {
       pkiDataBodyid   BodyPartID,
       bodyIds         SEQUENCE of BodyPartID
   }

   -- pkiDataBodyid field contains the body part id of the nested CMS
   body object containing the client's full request message.
   pkiDataBodyid is set to 0 if the request is in the current
   PKIRequest body.

   -- bodyIds contains a list of certificate requests for which the
   LRA 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 certificate server doesn't allow an LRA to do the POP verification, it returns an error of POPFAILURE πŸ™…. The CA MUST NOT start a challenge-response to re-verify the POP itself. Bestie, no double-checking allowed πŸ’€.


5.9 Get Certificate Control Attribute πŸ“

Everything described in this section is optional to implement ✨.

The get certificate control attribute is used to retrieve previously issued certificates from a repository of certificates πŸ“‚. A Certificate Authority, an LRA, or an independent service may provide this repository. The clients expected to use this facility are the ones operating in a resource-constrained environment. (An example of a resource-constrained client would be a low-end IP router that doesn't keep its own certificate in non-volatile memory πŸ€–.)

The get certificate control attribute has the following ASN.1 structure:

   GetCert ::= SEQUENCE {
       issuerName    GeneralName,
       serialNumber  INTEGER }

The service responding to the request puts the requested certificate in the certificates field of a SignedData object. If the get certificate attribute is the only control in a Full PKI Request message, the response will be a Simple Enrollment Response πŸ¦‹.


5.10 Get CRL Control Attribute πŸ’œ

Everything described in this section is optional to implement 🌈.

The get CRL control attribute is used to retrieve CRLs from a repository of CRLs πŸ“œ. A Certification Authority, an LRA, or an independent service may provide this repository. The clients expected to use this facility are the ones where a fully deployed directory is either infeasible or undesirable πŸ™ƒ.

The get CRL control attribute has the following ASN.1 structure:

   GetCRL ::= SEQUENCE {
       issuerName    Name,
       cRLName       GeneralName OPTIONAL,
       time          GeneralizedTime OPTIONAL,
       reasons       ReasonFlags OPTIONAL }

The fields in a GetCRL have these meanings:

  • issuerName is the name of the CRL issuer.
  • cRLName may be the value of CRLDistributionPoints in the subject certificate, or an equivalent value in the event the certificate doesn't contain such a value.
  • time is used by the client to pick, from among potentially several issues of CRL, the one whose thisUpdate value is less than but nearest to the specified time. If there's no time component, the CA always returns the most recent CRL ⏰.
  • reasons is used to specify from among CRLs partitioned by revocation reason. Implementers should keep in mind that while a specific revocation request has a single CRLReason code (so entries in the CRL would have a single CRLReason code value), a single CRL can aggregate information for one or more reasonFlags 🧩.

A service responding to the request puts the requested CRL in the crls field of a SignedData object. If the get CRL attribute is the only control in a full enrollment message, the response will be a simple enrollment response πŸŽ€.

5.11. Revocation Request Control Attribute πŸ’€

Okay bestie, this is the control attribute you use when you need a certificate revoked πŸ₯€ It's giving "I want this cert gone, and I want it on the record."

      RevRequest ::= SEQUENCE {
          issuerName      Name,
          serialNumber    INTEGER,
          reason          CRLReason,
          invalidityDate  GeneralizedTime OPTIONAL,
          sharedSecret    OCTET STRING OPTIONAL,
          comment         UTF8string OPTIONAL }

      -- issuerName contains the issuerName of the certificate to be
      revoked.

      -- serialNumber contains the serial number of the certificate to
      be revoked

      -- reason contains the suggested CRLReason code for why the
      certificate is being revoked.  The CA can use this value at its
      discretion in building the CRL.

      -- invalidityDate contains the suggested value for the Invalidity
      Date CRL Extension.  The CA can use this value at its discretion
      in building the CRL.

      -- sharedSecret contains a secret value registered by the EE when
      the certificate was obtained to allow for revocation of a
      certificate in the event of key loss.

      -- comment contains a human readable comment.

Okay so here's the tea πŸ«– If a revocation request is gonna hold up in a dispute, it needs strong proof of originator authenticity, no cap. But what if the end-entity lost its signature private key? Then it literally can't sign anything, at least until it gets a brand new signature key pair certified. 😭 That's where the sharedSecret comes in: the RevRequest lets the end-entity optionally send the CA a shared secret as a backup authenticator for when the key is lost. Whether that's acceptable is up to your local security policy, so check with your admins πŸ™ˆ

(Quick side note πŸ¦‹: sometimes a Registration Authority gets delegated power to revoke certs for some group inside its scope. In that case the CA accepts the LRA's digital signature on the request, even if the end entity still has its private key.)

Now the requirements, bestie πŸ“‹ Clients MUST be able to produce a digitally signed revocation request control attribute. Clients SHOULD be able to produce an unsigned revocation request that carries the end-entity's shared secret. If a client does shared-secret self-revocation, it MUST be able to produce a revocation request containing that shared secret. Servers MUST be able to accept both kinds of revocation request. Iconic behavior from everyone involved πŸ’…

For the unsigned, shared-secret version, the structure is up to whoever's implementing it πŸ› οΈ The shared secret doesn't have to be encrypted when it's sent in a revocation request. It's a one-time-use thing: its only job is to get the certificate revoked. So if the secret becomes public after the cert is revoked, honestly, not a problem ✨ Clients do need to tell users that the same shared secret SHOULD NOT be reused across multiple certificates, so please, tell your users 🫢

A full response message MUST be returned for a revocation request. πŸŽ€


5.12. Registration and Response Information Control Attributes 🌸

The regInfo control attribute is how clients and LRAs slip extra info into a PKI request. Its ASN.1 structure is:

      RegInfo ::= OCTET STRING

What goes inside is up to a bilateral agreement between the client and the server, so the two of you get to decide 🀝

If a server (or LRA) needs to send information back to the requestor in response to what showed up in a regInfo attribute, that comes back as a responseInfo control attribute. The contents of that OCTET STRING are also based on bilateral agreement between client and server πŸ’œ


5.13. Query Pending Control Attribute ⏳

Sometimes the cert gets delayed because someone has to manually check something, or do some other identity check, and that's just life πŸ™ƒ The query pending attribute lets a client ask the server what's up with a pending certificate request. The server hands back a token inside the CMCStatusInfo attribute (in the otherInfo field), and the client puts that token into the query pending attribute so the server knows exactly which request it means. The server can also suggest a time for the client to check back on the status πŸ•°οΈ

The ASN.1 structure is:

      QueryPending ::= OCTET STRING

If the server says the transaction is still pending, the otherInfo MAY be left out. If it's not left out, then the same value MUST be returned, because the token MUST NOT change during the request. No shape-shifting tokens allowed 😀


5.14. Confirm Certificate Acceptance πŸ¦„

Some Certification Authorities want clients to give a clear yes that the certs they were issued are acceptable. That's what the Confirm Certificate Acceptance control attribute is for πŸ’– If the CMCStatusInfo on a certificate request is confirmRequired, the client MUST return a Confirm Certificate Acceptance before using the certificate for anything at all. Clients SHOULD wait for the server's reply confirming that the acceptance got received πŸ™Œ

The confirm certificate acceptance structure is:

      CMCCertId ::= IssuerSerial

      -- CMCCertId contains the issuer and serial number of the
      certificate being accepted.

Servers MUST return a full enrollment response for a confirm certificate acceptance control. πŸŽ€


6. Local Registration Authorities πŸ‘‘

This spec lets you use Local Registration Authorities (LRAs) 🧚 An LRA sits between the end-entity and the Certification Authority. To the end-entity, the LRA looks like the CA, and to the server, the LRA looks like a client. LRAs receive enrollment messages, do some local processing, and then forward them along to the Certificate Authorities. Some of the local processing an LRA can do includes:

  • batching multiple enrollment messages together,
  • challenge/response POP proofs,
  • addition of private or standardized certificate extensions to all requests,
  • archival of private key material,
  • routing of requests to different CAs.

When an LRA gets an enrollment message, it has three options: it can forward the message without changing it, it can add a new wrapping layer to the message, or it can remove one or more existing layers and add a new wrapping layer. Choose your fighter πŸ₯Š

When an LRA adds a new wrapping layer, it creates a brand new PKIData object πŸ“¦ The new layer holds any control attributes that are needed (like if the LRA does the POP proof for an encryption key, or uses the addExtension control attribute to change an enrollment request) plus the client's enrollment message. The client's enrollment message goes into the cmsSequence if it's a Full Enrollment message, and into the reqSequence if it's a Simple Enrollment message. If the LRA is batching several client messages, each one goes into the right spot in the LRA's PKIData object, along with all of its relevant control attributes.

(If there are multiple LRAs between the end-entity and the Certification Authority, you'll end up with multiple wrapping layers on the message. Layers upon layers, like a parfait πŸ“)

When an LRA processes an enrollment message, it MUST NOT alter any certificate request body (PKCS #10 or CRMF). Any change would break the signature on the request, which would break the POP for the private key, and nobody wants that drama πŸ’€

Here's what it looks like, visually:

      SignedData (by LRA)
        PKIData
          controlSequence
                  LRA added control statements
          reqSequence
                  Zero or more Simple CertificationRequests from clients
          cmsSequence
                  Zero or more Full PKI messages from clients
                     SignedData (by client)
                         PKIData

Sometimes an LRA has to peel off wrapping layers. The next sections walk through what to do when encryption layers and signing layers need removing πŸ”


6.1. Encryption Removal πŸ”

There are two situations where an LRA has to remove or change encryption in an enrollment message. In the first one, the encryption was there to protect the whole enrollment request from unauthorized eyes. If the CA doesn't have a recipient info entry in that encryption layer, the LRA MUST remove the encryption layer. The LRA MAY add a new encryption layer, with or without adding a new signing layer, bestie πŸ’…

The second situation is changing the encryption inside a signing layer. Here the LRA MUST remove all signing layers that contain the encryption. Every control statement MUST be merged according to local policy rules as each signing layer gets removed, and the merged result MUST go into a new signing layer provided by the LRA. If the end-entity's signing layer needs to come off, the LRA is allowed to remove that layer too 🫧


6.2. Signature Layer Removal βœ‚οΈ

There are only two times an LRA should remove a signature layer from a Full Enrollment message πŸ™…β€β™€οΈ One is when encryption needs to be changed inside the message. The other is when a Certificate Authority won't accept secondary delegation (which means multiple LRA signatures). In every other case, LRAs SHOULD NOT remove a signing layer from a message. Keep those layers, babe πŸ’œ

If an LRA does remove a signing layer, all control statements MUST be merged according to local policy rules. The merged control statements MUST then go into a new signing layer provided by the LRA. ✨


7. Transport Wrapping 🎁

Not every transport can handle unlabeled raw binary data, so standard encoding methods can really help out here πŸ™Œ These methods usually wrap some identification of the content around the binary data, maybe apply an encoding to it, and label it. This spec documents three different wrapping methods for use:

  • MIME wrapping is for transports that are natively MIME based, such as HTTP and E-mail.
  • Binary file transport is defined since floppy disk transport is still very common. File transport can be done either as MIME wrapped (section 7.1) or bare (section 7.2).
  • Socket based transport uses the raw BER encoded object.

Floppy disks are still a thing in this spec, and honestly that's iconic πŸ’ΎπŸ¦‹

7.1 MIME Wrapping πŸ’Œ

okay so MIME wrapping is for the environments that are MIME native πŸŽ€, and that includes email-based protocols and HTTP too, bestie 🫢

The basic MIME wrapping here is borrowed from [SMIMEV2] and [SMIMEV3] ✨. Simple enrollment requests get encoded with the application/pkcs10 content type. A file name MUST be included in a content type or a content disposition statement (either one works, periodt πŸ’…). The extension for the file MUST be .p10.

Simple enrollment response messages MUST be encoded as application/pkcs7-mime 🌸. An smime-type parameter MUST be on the content-type statement with a value of "certs-only." A file name with the .p7c extension MUST be specified as part of the content-type or content-disposition.

Full enrollment request messages MUST be encoded as application/pkcs7-mime πŸ¦‹. The smime-type parameter MUST be included with a value of "CMC-enroll". A file name with the .p7m extension MUST be specified as part of the content-type or content-disposition statement.

Full enrollment response messages MUST be encoded as application/pkcs7-mime too πŸ’œ. The smime-type parameter MUST be included with a value of "CMC-response." A file name with the .p7m extensions MUST be specified as part of the content-type or content-disposition.

Here's the cheat sheet, obsessed with how clean this is 🧚:

MIME TYPE                       File Extension        SMIME-TYPE

application/pkcs10                .p10                  N/A
(simple PKI request)

application/pkcs7-mime            .p7m                  CMC-request
(full PKI request)

application/pkcs7-mime            .p7c                  certs-only
(simple PKI response)

application/pkcs7-mime            .p7m                  CMC-response
(full PKI response)

7.2 File-Based Transport πŸ“

Enrollment messages and responses can also move between clients and servers using file system-based mechanisms πŸ“. This comes in handy when enrollment is done for an off-line client. When files carry binary, BER-encoded Full Enrollment Request and Response messages, the following file type extensions SHOULD be used:

Message Type                   File Extension

Full PKI Request                 .crq

Full PKI Response                .crp

7.3 Socket-Based Transport πŸ”Œ

When enrollment messages and responses go over sockets, no wrapping is required, so no extra packaging needed, iconic ✨. Messages SHOULD be sent in their binary, BER-encoded form.

8. Interoperability πŸ‘‘

8.1 Mandatory and Optional Algorithms πŸ”

CMC clients and servers MUST be capable of producing and processing message signatures using the Digital Signature Algorithm [DSA]. DSA signatures MUST be indicated by the DSA AlgorithmIdentifier value (as specified in section 7.2.2 of [PKIXCERT]). PKI clients and servers SHOULD also be capable of producing and processing RSA signatures (as specified in section 7.2.1 of [PKIXCERT]) 🌈.

CMC clients and servers MUST be capable of protecting and accessing message encryption keys using the Diffie-Hellman (D-H) key exchange algorithm 🫧. D-H/3DES protection MUST be indicated by the D-H AlgorithmIdentifier value specified in [CMS]. PKI clients and servers SHOULD also be capable of producing and processing RSA key transport. When used for PKI messages, RSA key transport MUST be indicated as specified in section 7.2.1 of [PKIXCERT].

8.2 Minimum Conformance Requirements πŸ“‹

A minimally compliant CMC server πŸ’–:

  • a) MUST accept a Full PKI Request message
    • i) MUST accept CRMF Request Bodies within a Full PKI Request
    • ii) MUST accept PKCS#10 Request Bodies within a Full PKI Request
  • b) MUST accept a Simple Enrollment Request message
  • c) MUST be able to return a Full PKI Response. (A Full PKI Response is always a valid response, but for interoperability with downlevel clients a compliant server SHOULD use the Simple Enrollment Response whenever possible.)

A minimally compliant CMC client πŸ¦„:

  • a) MAY use either the Simple Enrollment Message or the Full PKI Request.
    • i) clients MUST use PKCS#10 with the Simple Enrollment Message
    • ii) clients MAY use either PKCS#10 or CRMF with the Full PKI Request
  • b) MUST understand the Simple Enrollment Response.
  • c) MUST understand the Full PKI Response.

9. Security Considerations 🚨

Okay, this part is SERIOUS, so read it carefully, bestie 😭. Starting a secure communications channel between an end-entity and a CA or LRA (and, similarly, between an LRA and another LRA or CA) necessarily requires an out-of-band trust initiation mechanism. For example, a secure channel may be constructed between the end-entity and the CA via IPSEC or TLS. Many such schemes exist, and picking any particular scheme for trust initiation is outside the scope of this document. Implementers of this protocol are strongly encouraged to consider generally accepted principles of secure key management when integrating this capability within an overall security architecture πŸ”’.

Mechanisms for thwarting replay attacks may be required in particular implementations of this protocol, depending on the operational environment. In cases where the CA maintains significant state information, replay attacks may be detectable without the inclusion of the optional nonce mechanisms. Implementers of this protocol need to carefully consider environmental conditions before choosing whether or not to implement the senderNonce and recipientNonce attributes described in section 5.6. Developers of state-constrained PKI clients are strongly encouraged to incorporate the use of these attributes πŸ›‘οΈ.

Under no circumstances should a signing key be archived. Doing so allows the archiving entity to potentially use the key for forging signatures. πŸ’€

Due care must be taken prior to archiving keys. Once a key is given to an archiving entity, the archiving entity could use the keys in a way not conducive to the archiving entity. Users should be made especially aware that proper verification is made of the certificate used to encrypt the private key material πŸ™ˆ.

Clients and servers need to do some checks on cryptographic parameters prior to issuing certificates, to make sure that weak parameters are not used. A description of the small subgroup attack is provided in [X942]. CMC implementations ought to be aware of this attack when doing parameter validations πŸ”₯.

10. Acknowledgments 🫢

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 πŸ’œ.

11. References πŸ“š

[CMS]      Housley, R., "Cryptographic Message Syntax", RFC 2630,
           June 1999.

[CRMF]     Myers, M., Adams, C., Solo, D. and D. Kemp, "Internet
           X.509 Certificate Request Message Format", RFC 2511, March
           1999.

[DH]       B. Kaliski, "PKCS 3: Diffie-Hellman Key Agreement v1.4"

[DH-POP]   H. Prafullchandra, J. Schaad, "Diffie-Hellman Proof-of-
           Possession Algorithms", Work in Progress.

[HMAC]     Krawczyk, H., Bellare, M. and R. Canetti, "HMAC: Keyed-
           Hashing for Message Authentication", RFC 2104, February
           1997.

[PKCS1]    Kaliski, B., "PKCS #1: RSA Encryption, Version 1.5", RFC
           2313, March 1998.

[PKCS7]    Kaliski, B., "PKCS #7: Cryptographic Message Syntax v1.5",
           RFC 2315, October 1997.

[PKCS8]    RSA Laboratories, "PKCS#8: Private-Key Information Syntax
           Standard, Version 1.2", November 1, 1993.

[PKCS10]   Kaliski, B., "PKCS #10: Certification Request Syntax
           v1.5", RFC 2314, October 1997.

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

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

[SMIMEV2]  Dusse, S., Hoffman, P., Ramsdell, B., Lundblade, L. and L.
           Repka, "S/MIME Version 2 Message Specification", RFC 2311,
           March 1998.

[SMIMEV3]  Ramsdell, B., "S/MIME Version 3 Message Specification",
           RFC 2633, June 1999.

[X942]     Rescorla, E., "Diffie-Hellman Key Agreement Method", RFC
           2631, June 1999.

12. Authors' Addresses πŸ–‹οΈ

Michael Myers
VeriSign Inc.
1350 Charleston Road
Mountain View, CA, 94043

Phone: (650) 429-3402
EMail: mmyers@verisign.com


Xiaoyi Liu
Cisco Systems
170 West Tasman Drive
San Jose, CA 95134

Phone: (480) 526-7430
EMail: xliu@cisco.com


Jim Schaad

EMail:  jimsch@nwlink.com


Jeff Weinstein

EMail: jsw@meer.net

Appendix A ASN.1 Module 🧩

EnrollmentMessageSyntax
   { iso(1) identified-organization(3) dod(4) internet(1)
   security(5) mechansims(5) pkix(7) id-mod(0) id-mod-cmc(6) }

   DEFINITIONS IMPLICIT TAGS ::=
   BEGIN

   -- EXPORTS All --
   -- The types and values defined in this module are exported for use
   -- in the other ASN.1 modules.  Other applications may use them for
   -- their own purposes.

   IMPORTS

     -- Information Directory Framework (X.501)
           Name
              FROM InformationFramework { joint-iso-itu-t ds(5)
                   modules(1) informationFramework(1) 3 }

     -- Directory Authentication Framework (X.509)
           AlgorithmIdentifier, AttributeCertificate, Certificate,
           CertificateList, CertificateSerialNumber
              FROM AuthenticationFramework { joint-iso-itu-t ds(5)
                   module(1) authenticationFramework(7) 3 }

     -- PKIX Part 1 - Implicit
        GeneralName, CRLReason, ReasonFlags
        FROM PKIX1Implicit88 {iso(1) identified-organization(3) dod(6)
                internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
                id-pkix1-implicit-88(2)}

     -- PKIX Part 1 - Explicit
        SubjectPublicKeyInfo, Extension
        FROM PKIX1Explicit88 {iso(1) identified-organization(3) dod(6)
                internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
                id-pkix1-explicit-88(1)}

     -- Cryptographic Message Syntax
        ContentInfo, Attribute
          FROM CryptographicMessageSyntax { 1 2 840 113549 1 9 16 0 1}

     -- CRMF
        CertReqMsg
        FROM CRMF { 1 3 6 1 5 5 7 0 5 };

    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}   -- CMC controls
        id-cct OBJECT IDENTIFIER ::= {id-pkix 12}  -- CMC content types

    -- The following controls have simple type content (usually OCTET
STRING)

    id-cmc-identification OBJECT IDENTIFIER ::= {id-cmc 2}
    id-cmc-identityProof OBJECT IDENTIFIER ::= {id-cmc 3}
    id-cmc-dataReturn OBJECT IDENTIFIER ::= {id-cmc 4}
    id-cmc-transactionId OBJECT IDENTIFIER ::= {id-cmc 5}
    id-cmc-senderNonce OBJECT IDENTIFIER ::= {id-cmc 6}
    id-cmc-recipientNonce OBJECT IDENTIFIER ::= {id-cmc 7}
    id-cmc-regInfo OBJECT IDENTIFIER ::= {id-cmc 18}
    id-cmc-responseInfo OBJECT IDENTIFIER ::= {id-cmc 19}
    id-cmc-queryPending OBJECT IDENTIFIER ::= {id-cmc 21}
    id-cmc-popLinkRandom OBJECT IDENTIFIER ::= {id-cmc 22)
    id-cmc-popLinkWitness OBJECT IDENTIFIER ::= (id-cmc 23)

    -- This is the content type used for a request message in the

okay, the ASN.1 module wraps up here, so here's the final stretch πŸ’…

protocol

    id-cct-PKIData OBJECT IDENTIFIER ::= { id-cct 2 }


    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
    }

    bodyIdMax INTEGER ::= 4294967295

    BodyPartID ::= INTEGER(0..bodyIdMax)

    TaggedAttribute ::= SEQUENCE {
        bodyPartID         BodyPartId,
        attrType           OBJECT IDENTIFIER,
        attrValues         SET OF AttributeValue
    }

    AttributeValue ::= ANY

    TaggedRequest ::= CHOICE {
        tcr               [0] TaggedCertificationRequest,
        crm               [1] CertReqMsg

    }

    TaggedCertificationRequest ::= SEQUENCE {
        bodyPartID            BodyPartID,
        certificationRequest  CertificationRequest
    }

    CertificationRequest ::= SEQUENCE {
      certificationRequestInfo  SEQUENCE {
        version                   INTEGER,
        subject                   Name,
        subjectPublicKeyInfo      SEQUENCE {
          algorithm                 AlgorithmIdentifier,
          subjectPublicKey          BIT STRING },
        attributes                [0] IMPLICIT SET OF Attribute },
      signatureAlgorithm        AlgorithmIdentifier,
      signature                 BIT STRING
    }

    TaggedContentInfo ::= SEQUENCE {
        bodyPartID              BodyPartId,
        contentInfo             ContentInfo
    }

    OtherMsg ::= SEQUENCE {
        bodyPartID        BodyPartID,
        otherMsgType      OBJECT IDENTIFIER,
        otherMsgValue     ANY DEFINED BY otherMsgType }

    --  This defines the response message in the protocol
    id-cct-PKIResponse OBJECT IDENTIFIER ::= { id-cct 3 }

    ResponseBody ::= SEQUENCE {
        controlSequence   SEQUENCE SIZE(0..MAX) OF TaggedAttribute,
        cmsSequence       SEQUENCE SIZE(0..MAX) OF TaggedContentInfo,
        otherMsgSequence  SEQUENCE SIZE(0..MAX) OF OtherMsg
    }

    -- Used to return status state in a response

    id-cmc-cMCStatusInfo OBJECT IDENTIFIER ::= {id-cmc 1}

    CMCStatusInfo ::= SEQUENCE {
        cMCStatus       CMCStatus,
        bodyList        SEQUENCE SIZE (1..MAX) OF INTEGER,
        statusString    UTF8String OPTIONAL,
        otherInfo        CHOICE {
          failInfo         CMCFailInfo,
          pendInfo         PendInfo } OPTIONAL
    }

    PendInfo ::= SEQUENCE {
        pendToken        INTEGER,
        pendTime         GENERALIZEDTIME
    }

    CMCStatus ::= INTEGER {
        success         (0),
        -- you got exactly what you asked for
        failed          (2),
        -- you don't get it, more information elsewhere in the message
        pending         (3),
        -- the request body part has not yet been processed,
        -- requester is responsible to poll back on this
        noSupport       (4)
        -- the requested operation is not supported
    }

    CMCFailInfo ::= INTEGER {
        badAlg          (0),
        -- Unrecognized or unsupported algorithm
        badMessageCheck (1),
        -- integrity check failed
        badRequest      (2),
        -- transaction not permitted or supported
        badTime         (3),
        -- Message time field was not sufficiently close to the system
time
        badCertId       (4),
        -- No certificate could be identified matching the provided
criteria
        unsuportedExt   (5),
        -- A requested X.509 extension is not supported by the recipient
CA.
        mustArchiveKeys (6),
        -- Private key material must be supplied
        badIdentity     (7),
        -- Identification Attribute failed to verify
        popRequired     (8),
        -- Server requires a POP proof before issuing certificate
        popFailed       (9),
        -- Server failed to get an acceptable POP for the request
        noKeyReuse      (10)
        -- Server policy does not allow key re-use
        internalCAError (11)
        tryLater        (12)

    }

    -- Used for LRAs to add extensions to certificate requests
    id-cmc-addExtensions OBJECT IDENTIFIER ::= {id-cmc 8}

    AddExtensions ::= SEQUENCE {
        pkiDataReference    BodyPartID,
        certReferences      SEQUENCE OF BodyPartID,
        extensions          SEQUENCE OF Extension
    }


    id-cmc-encryptedPOP OBJECT IDENTIFIER ::= {id-cmc 9}
    id-cmc-decryptedPOP OBJECT IDENTIFIER ::= {id-cmc 10}

    EncryptedPOP ::= SEQUENCE {
                request       TaggedRequest,
        cms             ContentInfo,
        thePOPAlgID     AlgorithmIdentifier,
        witnessAlgID    AlgorithmIdentifier,
        witness         OCTET STRING
    }

    DecryptedPOP ::= SEQUENCE {
        bodyPartID      BodyPartID,
        thePOPAlgID     AlgorithmIdentifier,
        thePOP          OCTET STRING
    }

    id-cmc-lraPOPWitness OBJECT IDENTIFIER ::= {id-cmc 11}

    LraPopWitness ::= SEQUENCE {
        pkiDataBodyid   BodyPartID,
        bodyIds         SEQUENCE OF BodyPartID
    }


    --
    id-cmc-getCert OBJECT IDENTIFIER ::= {id-cmc 15}

    GetCert ::= SEQUENCE {
        issuerName      GeneralName,
        serialNumber    INTEGER }


    id-cmc-getCRL OBJECT IDENTIFIER ::= {id-cmc 16}

    GetCRL ::= SEQUENCE {

        issuerName    Name,
        cRLName       GeneralName OPTIONAL,
        time          GeneralizedTime OPTIONAL,
        reasons       ReasonFlags OPTIONAL }

    id-cmc-revokeRequest OBJECT IDENTIFIER ::= {id-cmc 17}

    RevRequest ::= SEQUENCE {
        issuerName            Name,
        serialNumber          INTEGER,
        reason                CRLReason,
       invalidityDate         GeneralizedTime OPTIONAL,
        passphrase            OCTET STRING OPTIONAL,
        comment               UTF8String OPTIONAL }

   id-cmc-confirmCertAcceptance OBJECT IDENTIFIER ::= {pkix-cmc 24}

   CMCCertId ::= IssuerSerial

   -- The following is used to request V3 extensions be added to a
certificate

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

   ExtensionReq ::= SEQUENCE OF Extension

   -- The following exists to allow Diffie-Hellman Certificate Requests
Messages to be
   -- well-formed

   id-alg-noSignature OBJECT IDENTIFIER ::= {id-pkix id-alg(6) 2}

   NoSignatureValue ::= OCTET STRING

END

Now the legal bits, which I'm keeping word-for-word so nothing gets lost in translation 🫢

Copyright (C) The Internet Society (2000). All Rights Reserved.

This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English.

The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns.

This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.


Acknowledgement πŸ’–

Okay bestie, the last bit is a thank-you to whoever keeps the lights on 🌈 Funding for the RFC Editor function is currently provided by the Internet Society. ✨

πŸ“¦ where this page comes from