RFC 2797
Certificate Management Messages over CMS
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 Notice Β©οΈ
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:
- The need for an interface to public key certification products and services based on [CMS] and [PKCS10], and
- 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:
- All Control Attributes,
- All certification requests,
- All CMS objects,
- 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 π:
- 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 πͺͺ.
- 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 π.
- 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:
- 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.
- a SHA1 hash of the token is computed.
- 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.
- 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:
- the identification attribute MUST be included, and it MUST contain the hardware-generated token.
- the shared secret value used above is the same hardware-generated token.
- all certification requests MUST have a subject name, and the subject name MUST contain the fields required to identify the holder of the hardware token device.
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:
- The client generates a random byte-string, R, which SHOULD be at least 512 bits in length. π²
- A SHA1 hash of the token is computed.
- 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.
- The random value produced in Step 1 is encoded as the value of an
idPOPLinkRandomcontrol attribute. This control attribute MUST be included in the Full PKI Request message. π - The 160-bit HMAC-SHA1 result from Step 3 is encoded as the value of an
idPOPLinkWitnessextension to the certificate request.- a. For CRMF,
idPOPLinkWitnessis included in the controls section of theCertRequeststructure. - b. For PKCS#10,
idPOPLinkWitnessis included in the attributes section of theCertificationRequeststructure.
- a. For CRMF,
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:
- 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. π«
- 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 π):
- If the conflict is within a single PKIData object, the certificate request would be rejected with an error of
badRequest. - 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 π¦:
- Client tells the server about the public component of a new encryption key pair.
- Server sends the client a POP challenge, encrypted with the presented public encryption key, which the client must decrypt.
- Client decrypts the POP challenge and sends it back to the server.
- 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 π§:
- The server generates a random value y and associates it with the request.
- 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
IsserNameMUST be encoded as NULL and theSerialNumberas 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.
- 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.
- 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).
- 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) π₯Ί.
- 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.)
- 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
Full Copyright Statement π
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
- ietf: rfc2797 2000-04
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms