CMS is a general enveloping mechanism that enables both signed and encrypted transmission of arbitrary data. SCEP messages that require confidentiality use two layers of CMS, as shown using ASN.1-like pseudocode in
Figure 6. By applying both enveloping and signing transformations, the SCEP message is protected both for the integrity of its end-to-end transaction information and the confidentiality of its information portion.
pkiMessage {
contentType = signedData { pkcs-7 2 },
content {
digestAlgorithms,
encapsulatedContentInfo {
eContentType = data { pkcs-7 1 },
eContent { -- pkcsPKIEnvelope, optional
contentType = envelopedData { pkcs-7 3 },
content {
recipientInfo,
encryptedContentInfo {
contentType = data { pkcs-7 1 },
contentEncrAlgorithm,
encryptedContent {
messageData -- Typically PKCS #10 request
}
}
}
}
},
certificates, -- Optional
crls, -- Optional
signerInfo {
signedAttrs {
transactionID,
messageType,
pkiStatus,
failInfo, -- Optional
senderNonce / recipientNonce,
},
signature
}
}
}
When a particular SCEP message carries data, this data is carried in the messageData. CertRep messages will lack any signed content and consist only of a pkcsPKIEnvelope (
Section 3.2.2).
The remainder of this document will refer only to "messageData", but it is understood to always be encapsulated in the pkcsPKIEnvelope (
Section 3.2.2). The format of the data in the messageData is defined by the messageType attribute (see
Section 3.2) of the SignedData. If there is no messageData to be transmitted, the entire pkcsPKIEnvelope
MUST be omitted.
Samples of SCEP messages are available through the [
JSCEP] in the src/samples directory.
Creating a SCEP message consists of several stages. The content to be conveyed (in other words, the messageData) is first encrypted, and the encrypted content is then signed.
The form of encryption to be applied depends on the capabilities of the recipient's public key. If the key is encryption capable (for example, RSA), then the messageData is encrypted using the recipient's public key with the CMS KeyTransRecipientInfo mechanism. If the key is not encryption capable (for example, DSA or ECDSA), then the messageData is encrypted using the challengePassword with the CMS PasswordRecipientInfo mechanism.
Once the messageData has been encrypted, it is signed with the sender's public key. This completes the SCEP message, which is then sent to the recipient.
Note that some early implementations of this specification dealt with keys that were not encryption capable by omitting the encryption stage, based on the text in
Section 3 that indicated that "the EnvelopedData is omitted". This alternative processing mechanism
SHOULD NOT be used since it exposes in cleartext the challengePassword used to authorise the certificate issue.
The basic building block of all secured SCEP messages is the SCEP pkiMessage. It consists of a CMS SignedData content type. The following restrictions apply:
-
The eContentType in encapsulatedContentInfo MUST be data ({pkcs-7 1}).
-
The signed content, if present (FAILURE and PENDING CertRep messages will lack any signed content), MUST be a pkcsPKIEnvelope (Section 3.2.2) and MUST match the messageType attribute.
-
The SignerInfo MUST contain a set of authenticatedAttributes (Section 3.2.1).
At a minimum, all messages
MUST contain the following authenticatedAttributes:
If the message is a CertRep, it
MUST also include the following authenticatedAttributes:
-
A pkiStatus attribute (see Section 3.2.1.3).
-
failInfo and optional failInfoText attributes (see Section 3.2.1.4) if pkiStatus = FAILURE.
-
A recipientNonce attribute (see Section 3.2.1.5) copied from the senderNonce in the request that this is a response to.
The following transaction attributes are encoded as authenticated attributes and carried in the SignerInfo for this SignedData.
Attribute |
Encoding |
Comment |
transactionID |
PrintableString |
Unique ID for this transaction as a text string
|
messageType |
PrintableString |
Decimal value as a numeric text string
|
pkiStatus |
PrintableString |
Decimal value as a numeric text string
|
failInfo |
PrintableString |
Decimal value as a numeric text string
|
failInfoText |
UTF8String |
Descriptive text for the failInfo value
|
senderNonce |
OCTET STRING |
Random nonce as a 16-byte binary data string
|
recipientNonce |
OCTET STRING |
Random nonce as a 16-byte binary data string
|
Table 1: SCEP Attributes
The OIDs used for these attributes are as follows:
Name |
ASN.1 Definition |
id-VeriSign |
OBJECT_IDENTIFIER ::= {2 16 US(840) 1 VeriSign(113733)}
|
id-pki |
OBJECT_IDENTIFIER ::= {id-VeriSign pki(1)} |
id-attributes |
OBJECT_IDENTIFIER ::= {id-pki attributes(9)}
|
id-transactionID |
OBJECT_IDENTIFIER ::= {id-attributes transactionID(7)}
|
id-messageType |
OBJECT_IDENTIFIER ::= {id-attributes messageType(2)}
|
id-pkiStatus |
OBJECT_IDENTIFIER ::= {id-attributes pkiStatus(3)}
|
id-failInfo |
OBJECT_IDENTIFIER ::= {id-attributes failInfo(4)}
|
id-senderNonce |
OBJECT_IDENTIFIER ::= {id-attributes senderNonce(5)}
|
id-recipientNonce |
OBJECT_IDENTIFIER ::= {id-attributes recipientNonce(6)}
|
id-scep |
OBJECT IDENTIFIER ::= {id-pkix 24} |
id-scep-failInfoText |
OBJECT IDENTIFIER ::= {id-scep 1} |
Table 2: SCEP Attribute OIDs
The attributes are detailed in the following sections.
A PKI operation is a transaction consisting of the messages exchanged between a client and the CA. The transactionID is a text string provided by the client when starting a transaction. The client
MUST use a unique string as the transaction identifier, encoded as a PrintableString, which
MUST be used for all PKI messages exchanged for a given operation, such as a certificate issue.
Note that the transactionID must be unique, but not necessarily randomly generated. For example, it may be a value assigned by the CA to allow the client to be identified by their transactionID, using a value such as the client device's Extended Unique Identifier (EUI), Remote Terminal Unit (RTU) ID, or a similar unique identifier. This can be useful when the client doesn't have a preassigned Distinguished Name through which the CA can identify their request -- for example, when enrolling Supervisory Control and Data Acquisition (SCADA) devices.
The messageType attribute specifies the type of operation performed by the transaction. This attribute
MUST be included in all PKI messages. The following message types are defined:
Value |
Name |
Description |
0 |
Reserved |
|
3 |
CertRep |
Response to certificate or CRL request. |
17 |
RenewalReq |
PKCS #10 certificate request authenticated with an existing certificate. |
19 |
PKCSReq |
PKCS #10 certificate request authenticated with a shared secret. |
20 |
CertPoll |
Certificate polling in manual enrolment. |
21 |
GetCert |
Retrieve a certificate. |
22 |
GetCRL |
Retrieve a CRL. |
Table 3: SCEP Message Types
Message types not defined above
MUST be treated as errors unless their use has been negotiated through
Section 3.5.1.
All response messages
MUST include transaction status information, which is defined as a pkiStatus attribute:
Value |
Name |
Description |
0 |
SUCCESS |
Request granted. |
2 |
FAILURE |
Request rejected. In this case, the failInfo attribute, as defined in Section 3.2.1.4, MUST also be present.
|
3 |
PENDING |
Request pending for manual approval. |
Table 4: pkiStatus Attributes
PKI status values not defined above
MUST be treated as errors unless their use has been negotiated through
Section 3.5.1.
The failInfo attribute
MUST contain one of the following failure reasons:
Value |
Name |
Description |
0 |
badAlg |
Unrecognised or unsupported algorithm. |
1 |
badMessageCheck |
Integrity check (meaning signature verification of the CMS message) failed. |
2 |
badRequest |
Transaction not permitted or supported. |
3 |
badTime |
The signingTime attribute from the CMS authenticatedAttributes was not sufficiently close to the system time. This condition may occur if the CA is concerned about replays of old messages.
|
4 |
badCertId |
No certificate could be identified matching the provided criteria. |
Table 5: failInfo Attributes
Failure reasons not defined above
MUST be treated as errors unless their use has been negotiated through
Section 3.5.1.
The failInfoText is a free-form UTF-8 text string that provides further information in the case of pkiStatus = FAILURE. In particular, it may be used to provide details on why a certificate request was not granted that go beyond what's provided by the near-universal failInfo = badRequest status. Since this is a free-form text string intended for interpretation by humans, implementations
SHOULD NOT assume that it has any type of machine-processable content.
The senderNonce and recipientNonce attributes are each a 16-byte random number generated for each transaction. These are intended to prevent replay attacks.
When a sender sends a PKI message to a recipient, a fresh senderNonce
MUST be included in the message. The recipient
MUST copy the senderNonce into the recipientNonce of the reply as a proof of liveliness. The original sender
MUST verify that the recipientNonce of the reply matches the senderNonce it sent in the request. If the nonce does not match, then the message
MUST be rejected.
Note that since SCEP exchanges consist of a single request followed by a single response, the use of distinct sender and recipient nonces is redundant, since the client sends a nonce in its request and the CA responds with the same nonce in its reply. In effect, there's just a single nonce, identified as senderNonce in the client's request and recipientNonce in the CA's reply.
The information portion of a SCEP message is carried inside an EnvelopedData content type, as defined in CMS, with the following restrictions:
-
contentType in encryptedContentInfo MUST be data ({pkcs-7 1}).
-
encryptedContent MUST be the SCEP message being transported (see Section 4) and MUST match the messageType authenticated Attribute in the pkiMessage.
All of the messages in this section are pkiMessages (
Section 3.2), where the type of the message
MUST be specified in the "messageType" authenticated Attribute. Each section defines a valid message type, the corresponding messageData formats, and mandatory authenticated attributes for that type.
The messageData for this type consists of a PKCS #10 Certificate Request. The certificate request
MUST contain at least the following items:
-
The subject Distinguished Name.
-
The subject public key.
-
For a PKCSReq, if authorisation based on a shared secret is being used, a challengePassword attribute.
In addition, the message must contain the authenticatedAttributes specified in
Section 3.2.1.
The messageData for this type consists of a degenerate certificates-only CMS SignedData message (
Section 3.4). The exact content required for the reply depends on the type of request that this message is a response to. The request types are detailed in Sections [
3.3.2.1] and [
4]. In addition, the message must contain the authenticatedAttributes specified in
Section 3.2.1.
Earlier draft versions of this specification required that this message include a senderNonce alongside the recipientNonce, which was to be used to chain to subsequent polling operations. However, if a single message was lost during the potentially extended interval over which polling could take place (see
Section 5 for an example of this), then if the implementation were to enforce this requirement, the overall transaction would fail, even though nothing had actually gone wrong. Because of this issue, implementations mostly ignored the requirement to either carry this nonce over to subsequent polling messages or verify its presence. More recent versions of the specification no longer require the chaining of nonces across polling operations.
When the pkiStatus attribute is set to SUCCESS, the messageData for this message consists of a degenerate certificates-only CMS SignedData message (
Section 3.4). The content of this degenerate certificates-only SignedData message depends on what the original request was, as outlined in
Table 6.
Request-type |
Reply-contents |
PKCSReq |
The reply MUST contain at least the issued certificate in the certificates field of the SignedData. The reply MAY contain additional certificates, but the issued certificate MUST be the leaf certificate.
|
RenewalReq |
Same as PKCSReq |
CertPoll |
Same as PKCSReq |
GetCert |
The reply MUST contain at least the requested certificate in the certificates field of the SignedData. The reply MAY contain additional certificates, but the requested certificate MUST be the leaf certificate.
|
GetCRL |
The reply MUST contain the CRL in the crls field of the SignedData.
|
Table 6: CertRep Response Types
When the pkiStatus attribute is set to FAILURE, the reply
MUST also contain a failInfo (
Section 3.2.1.4) attribute set to the appropriate error condition describing the failure. The reply
MAY also contain a failInfoText attribute providing extended details on why the operation failed, typically to expand on the catchall failInfo = badRequest status. The pkcsPKIEnvelope (
Section 3.2.2)
MUST be omitted.
When the pkiStatus attribute is set to PENDING, the pkcsPKIEnvelope (
Section 3.2.2)
MUST be omitted.
This message is used for certificate polling. For unknown reasons, it was referred to as "GetCertInitial" in earlier draft versions of this specification. The messageData for this type consists of an IssuerAndSubject:
issuerAndSubject ::= SEQUENCE {
issuer Name,
subject Name
}
The issuer is set to the subjectName of the CA (in other words, the intended issuerName of the certificate that's being requested). The subject is set to the subjectName used when requesting the certificate.
Note that both of these fields are redundant; the CA is identified by the recipientInfo in the pkcsPKIEnvelope (or in most cases, simply by the server that the message is being sent to), and the client/transaction being polled is identified by the transactionID. Both of these fields can be processed by the CA without going through the cryptographically expensive process of unwrapping and processing the issuerAndSubject. For this reason, implementations
SHOULD assume that the polling operation will be controlled by the recipientInfo and transactionID rather than the contents of the messageData. In addition, the message must contain the authenticatedAttributes specified in
Section 3.2.1.
The messageData for these types consist of an IssuerAndSerialNumber, as defined in CMS, that uniquely identifies the certificate being requested, either the certificate itself for GetCert or its revocation status via a CRL for GetCRL. In addition, the message must contain the authenticatedAttributes specified in
Section 3.2.1.
These message types, while included here for completeness, apply unnecessary cryptography and messaging overhead to the simple task of transferring a certificate or CRL (see
Section 7.8). Implementations
SHOULD prefer [
RFC 4387] or LDAP over the use of these messages.
CMS includes a degenerate case of the SignedData content type in which there are no signers. The use of such a degenerate case is to disseminate certificates and CRLs. For SCEP, the content field of the ContentInfo value of a degenerate certificates-only SignedData
MUST be omitted. When carrying certificates, the certificates are included in the certificates field of the SignedData. When carrying a CRL, the CRL is included in the crls field of the SignedData.
In order to provide support for future enhancements to the protocol, CAs
MUST implement the GetCACaps message to allow clients to query which functionality is available from the CA.
This message requests capabilities from a CA, with the format as described in
Section 4.1:
"GET" SP SCEPPATH "?operation=GetCACaps" SP HTTP-version CRLF
The response for a GetCACaps message is a list of CA capabilities, in plain text and in any order, separated by <CR><LF> or <LF> characters. This specification defines the following keywords (quotation marks are not sent):
Keyword |
Description |
AES |
CA supports the AES128-CBC encryption algorithm.
|
DES3 |
CA supports the triple DES-CBC encryption algorithm.
|
GetNextCACert |
CA supports the GetNextCACert message.
|
POSTPKIOperation |
CA supports PKIOPeration messages sent via HTTP POST.
|
Renewal |
CA supports the Renewal CA operation. |
SHA-1 |
CA supports the SHA-1 hashing algorithm. |
SHA-256 |
CA supports the SHA-256 hashing algorithm. |
SHA-512 |
CA supports the SHA-512 hashing algorithm. |
SCEPStandard |
CA supports all mandatory-to-implement sections of the SCEP standard. This keyword implies "AES", "POSTPKIOperation", and "SHA-256", as well as the provisions of Section 2.9.
|
Table 7: GetCACaps Response Keywords
Table 7 lists all of the keywords that are defined in this specification. A CA
MAY provide additional keywords advertising further capabilities and functionality. A client
MUST be able to accept and ignore any unknown keywords that might be sent by a CA.
The CA
MUST use the text case specified here, but clients
SHOULD ignore the text case when processing this message. Clients
MUST accept the standard HTTP-style text delimited by <CR><LF> as well as the text delimited by <LF> specified in an earlier draft version of this specification.
The client
SHOULD use SHA-256 in preference to SHA-1 hashing and AES128-CBC in preference to triple DES-CBC if they are supported by the CA. Although the CMS format allows any form of AES and SHA-2 to be specified, in the interests of interoperability the de facto universal standards of AES128-CBC and SHA-256
SHOULD be used.
Announcing some of these capabilities individually is redundant, since they're required as mandatory-to-implement functionality (see
Section 2.9) whose presence as a whole is signalled by the "SCEPStandard" capability. However, it may be useful to announce them in order to deal with older implementations that would otherwise default to obsolete, insecure algorithms and mechanisms.
If the CA supports none of the above capabilities, it
SHOULD return an empty message. A CA
MAY simply return an HTTP error. A client that receives an empty message or an HTTP error
SHOULD interpret the response as if none of the capabilities listed are supported by the CA.
Note that at least one widely deployed server implementation supports several of the above operations but doesn't support the GetCACaps message to indicate that it supports them, and it will close the connection if sent a GetCACaps message. This means that the equivalent of GetCACaps must be performed through server fingerprinting, which can be done using the ID string "Microsoft-IIS". Newer versions of the same server, if sent a SCEP request using AES and SHA-2, will respond with an invalid response that can't be decrypted, requiring the use of 3DES and SHA-1 in order to obtain a response that can be processed, even if AES and/or SHA-2 are allegedly supported. In addition, the server will generate CA certificates that only have one, but not both, of the keyEncipherment and digitalSignature keyUsage flags set, requiring that the client ignore the keyUsage flags in order to use the certificates for SCEP.
The Content-type of the reply
SHOULD be "text/plain". Clients
SHOULD ignore the Content-type, as older implementations of SCEP may send various Content-types.
Example:
GET /cgi-bin/pkiclient.exe?operation=GetCACaps HTTP/1.1
might return:
AES
GetNextCACert
POSTPKIOperation
SCEPStandard
SHA-256
This means that the CA supports modern crypto algorithms, and the GetNextCACert message allows PKIOperation messages (PKCSReq/RenewalReq, GetCert, CertPoll, ...) to be sent using HTTP POST and is compliant with the final version of the SCEP standard.