CMP

The Certificate Management Protocol (CMP) is an Internet protocol used for obtaining X.509 digital certificates in a public key infrastructure (PKI). It is described in RFC4210 and is one of two protocols to use the Certificate Request Message Format (CRMF), described in RFC4211. This section covers the following:

EJBCA supports the following messages of the complex CMP protocol (RFC4210):

  • Initialization request (ir)

  • Certification request (cr)

  • Certification confirm (certConf)

  • Revocation request (rr)

  • NestedMessageContent (nested)

  • Key Update Request (kur)

Certificate requests use the CRMF (RFC4211).

EJBCA can work in the following modes with CMP:

  • Client mode: Default. Client mode works like any other enrollment in EJBCA. When a request comes in, EJBCA verifies the request (see CMP Message Authentication) and issues a certificate to a user that has been previously registered in EJBCA.

  • RA mode: Used when the CMP client acts as an RA to EJBCA (the RA sends a certificate request to EJBCA). No user is pre-registered in EJBCA, but when authenticated RA CMP messages arrive, a user is created in EJBCA and a certificate is issued.

In RA mode, EJBCA supports several CAs and profiles based on the use of configuration alias specified in the URL used (see CMP over HTTP).

CMP and 3GPP/4G/LTE Configuration Guide

PrimeKey has created a detailed CMP configuration guide, with details how to configure EJBCA for 3GPP/4G/LTE networks using CMP. The guide is available together with a support subscription from PrimeKey. For more information, refer to www.primekey.com.

The following displays an example cmpforopenssl command to test Vendor CA authentication with a three level Vendor CA PKI:

./cmpclient --server 127.0.0.1 --port 8080 --path ejbca/publicweb/cmp/vendor --srvcert 3GPPCA.cacert.pem --ir --subject "C=SE,O=Test,CN=Network Element 32" --clcert nevcert.pem --newclcert nev-op-crt.der --newkey nev-op-key.pem --key nevkey.pem --extracert casubnevcert.pem

CMP Alias Configuration

  • CMP Operational Mode: Client mode

  • CMP Authentication Module: EndEntityCertificate

  • Extract Username Component: CN

  • Use Vendor Certificate Mode: Use and add CANevRoot as Vendor CA

Configuration

Configuring CMP is done in the Admin GUI, under CMP Configuration. To be able to edit the CMP configuration, you require edit_systemconfiguration access.

CMP over HTTP

By default, EJBCA supports CMP over the http transport protocol. The URL for the CMP servlet is: http://127.0.0.1:8080/ejbca/publicweb/cmp/ALIAS.

ALIAS is a configuration alias specifying the set of CMP configurations to be used when handling a request sent through this specific URL. ALIAS can be any alphanumeric string and you can specify as many aliases as you need in the Admin GUI.

Example: http://127.0.0.1:8080/ejbca/publicweb/cmp/cmpalias

Any CMP request sent through this URL will use the CMP configurations associated with the alias cmpalias.

CMP over TCP

You can enable a CMP TCP service by changing the option cmp.tcp.enabled in the conf/cmptcp.properties file. Ensure to copy the conf/cmptcp.properties.sample to conf/cmptcp.properties first. When re-deploying EJBCA, a TCP listener is started on the default port for CMP over TCP. You must run the application server as root to use the default port, since it is a low port (<1024). Refer to the documentation in conf/cmp.properties for information about configuration options for TCP. We recommend using a non standard port > 1024.

CMP requests sent over TCP will be using CMP configurations associated with the configuration alias tcp. Note that a CMP configuration alias with the name tcp does not exist per default. It has to be created (and/or altered) using the Admin GUI before any CMP request arrives through TCP.

EJBCA will cease to support CMP over TCP, and it is strongly recommended to use CMP over HTTP instead.

CMP Message Authentication

EJBCA supports four modules for message authentication, configured in the Admin GUI under CMP Configuration.

The supported modules are either password extractors or PKIMessage verifiers:

Module

Description

Password extractors (client mode only)

RegTokenPwd

Extracts the password from the CMP request through the means of a regToken control (id-regCtrl-regToken) in the CRMF message. The regToken is a UTF8String containing the user password as registered in EJBCA. This module requires no parameters.

DnPartPwd

Extracts the password from the subjectDN of the user the request concerns. As a parameter, the DN part that contains the password should be specified. For example, if the subjectDN is "CN=name,C=se,UID=PASSWORD", the parameters should be set to "UID".

PKIMessage verifiers

HMAC

This module uses a shared secret to authenticate the CMP message:

  • In RA mode, the shared secret is set as a parameter to this module. If no parameter is specified, EJBCA uses the shared secret specified in the CA under CMP RA Authentication Secret.

  • In client mode, the pre-registered end entity will be looked up in the database, and if there was a clear text password there, this password will be used to authenticate the message. If there is no clear text password associated with that end entity, the authentication will fail.

EndEntityCertificate

When the EndEntityCertificate module is used, the request sender should attach his certificate in the extraCert field in the PKIMessage and then sign the message with his private key.

  • In client mode, a user may only send a CMP request regarding his/her own certificate. EJBCA will then check if the certificate in extraCert does exist in its database and verifies that it belongs to the sender before verifying the signature. No parameters should be specified for this module in client mode.

  • In RA mode, as a parameter, this module expects the name of the CA that has issued the certificate in the extraCert field. If a parameter is specified, EJBCA checks if the certificate in extraCert does exist in the database, that it was issued by the right CA (the CA specified as a parameter), and that it belongs to a registered administrator in EJBCA with the right authorizations to perform the operations required in the request. If no parameter is specified, none of the mentioned checks will be performed. However, EJBCA will expect the CMP request to have been previously authenticated by other ways, for example, by sending the request inside a signed NestedMessageContent.

You can specify more than one module in the Admin GUI CMP Configuration by separating the modules with a semicolon ";". If specifying multiple modules, the first module is used for authentication testing. If the first module fails, the second module is used for authentication testing, and so on until a successful authentication is done or all alternatives fail.

CMP Response Message

When a CMP request is successful, EJBCA returns a protected CMP response message. The protection type of the response message can also be configured in the Admin GUI under CMP Configuration. EJBCA supports the following types of response message protection: pbe and signature.

If a CMP request fails, EJBCA returns an unprotected, unencrypted CMP error message.

pbe

This type of protection of the response message can be used only when the request was authenticated using HMAC authentication module. The parameters used for the pbe protection are based on the parameters used in the received HMAC authentication.

signature

The CA used to handle the CMP request signs the CMP response message using the same protection algorithm specified in the CMP request. If a conflict occurs between the protection algorithm in the request and the CA's signature algorithm, the CA's key algorithm will be used in combination with a digest algorithm based on the protection algorithm in the CMP request. If a conflict occurs even on the digest algorithm level, a default digest algorithm will be used. For example, if the CMP request uses the protection algorithm ECDSA with SHA1 and the CA's signature algorithm is RSA with SHA256, the CMP response will be signed using RSA with SHA1.

The signature type of response protection can be used regardless of what authentication module was used to authenticate the CMP request.

CMP messages are signed using the CAs signature key. Verification of the signed CMP messages hence typically assumes that overly strict enforcement of Key Usage in CA certificate is not in place (similar to allow signing of OCSP responses under the CRLSign Key Usage).

The CA certificates returned with the CMP response message can be configured in the CMP configuration. For a list of CMP error codes, see CMP Error Messages.

CMP Response Additional CA Certificates

Additional CA certificates available in EJBCA can be added to the CMP response message (CertRepMessage.caPubs). Independent from the additional CA certificates configured, the signing CA certificate is returned at index 0 every time.

PKI Message Response Additional CA Certificates

Additional CA certificates available in EJBCA can be added to the CMP response wrapping PKI message (PKIMessage.extraCerts). Independent from the additional CA certificates configured, the response message signing CA certificate chain is included from index 0 every time.

Client Mode for CMP

Client mode is used when the CMP client will act as an End Entity to EJBCA. This means that the End Entity must be pre-registered in EJBCA and that the client request is authenticated with this pre-registered end entity before a certificate is issued. This is the same authentication model as for regular enrollment, i.e. browser enrollment, using a username/password combination.

  • The users DN is deducted from the request according to rules configured.

  • The username in EJBCA must be pre-registered.

  • The password for the user in EJBCA must be passed in the request (one-time password).

  • If the Certificate Profile allows it, keyUsage, validity and extensions are also taken from the CertTemplate in the request message.

  • Signature POPO is used.

After the user has been authenticated in EJBCA, a certificate is generated as usual and sent back to the client.

To use client mode, no particular configuration is needed, since this is the default mode.

User look-up

Initialization and certification requests uses the CRMF request message (RFC4211).

Users can be looked up from the request in different ways, as configured in the Admin GUI under CMP Configuration. By default the subject DN from the certTemplate in the request is used to look up the used in EJBCA. You can also configure EJBCA to use the CN or the UID from the subject DN as the username in EJBCA.

Vendor CA Authentication (EJBCA Enterprise only)

If the end entity has a Vendor certificate with which it should identify itself for initial enrollment, as specified in 3GPP for example, it can also do that. In this case the CA issuing the end entity certificate is not the same as the Vendor CA. The vendor CA must be imported in EJBCA as an External CA (Import CA certificate in the admin GUI). This is described in detail in the integration guide for 3GPP available with EJBCA Enterprise.

RA mode for CMP

RA mode is used when the CMP client will act as an RA to EJBCA. When the RA sends a certificate request to EJBCA, no user needs to be pre-registered in EJBCA. When EJBCA receives the request, the message will be authenticated. After it has been authenticated, a user is created and a certificate is issued.

  • The users DN is taken from the CertTemplate in the request message send from the RA (i.e. the DN requested by the RA).

  • The username in EJBCA is generated according to the options configured

  • The password for the user in EJBCA is random.

  • If the Certificate Profile allows it, keyUsage, validity and extensions are also taken from the CertTemplate in the request message.

  • raVerify POPO is used.

  • Messages are authenticated using one of the configured authentication modules.

After the user has been created in EJBCA, a certificate is generated as usual and sent back to the RA, who will distribute it to the end-user.

If the same username is constructed (for example UID) as an already existing user, the existing user will be modified with new values for profile etc, and a new certificate will be issued for that user.

KeyID

Instead of specifying an RA End Entity Profile, RA Certificate Profile, and/or RA CA Name explicitly when creating a CMP alias, you can choose the KeyID option. When this option is selected, the value of the senderKID field in the CMP request is used instead of the corresponding entry in the CMP alias (which is set to KeyID). The client sending the CMP request must ensure the correctness of the CMP request, for example. that the CA and Certificate Profile is authorized by the End Entity profile.

Note that KeyID is only visible when the number of available options is at least two.

KeyID is useful when you want to issue different types of certificates using a single CMP alias. The EJBCA cmpclient tool allows you to set KeyID explicitly using the --keyid argument.

Multiprotection Support

In RA mode, it is also possible to send a CMP request with multiple signatures. EJBCA implements this feature following the specifications in RFC4210. In cases where an end entity sends a protected PKI message to an RA, the RA forwards that message to a CA, attaching its own signature for protection. This is accomplished by nesting the entire message sent by the end entity within a new PKI message.

Sample code for a signature protected NestedMessageContent message:

String subjectDN = "CN=bogusSubjectNested";
final byte[] nonce = "sendernonce".getBytes();
final byte[] transid = "trandis".getBytes();
 
PKIMessage crmfMsg = createCrmfReq();
//Signing crmfMsg
KeyPair eeKeys = getAdminKeys();
Certificate adminCert = getAdminCertificate();
ByteArrayInputStream bIn = new ByteArrayInputStream(adminCert.getEncoded());
ASN1InputStream dIn = new ASN1InputStream(bIn);
ASN1Sequence extraAdminCertSeq = (ASN1Sequence)dIn.readObject();
X509CertificateStructure extraCert = new X509CertificateStructure(ASN1Sequence.getInstance(extraAdminCertSeq));
crmfMsg.addExtraCert(extraCert);
 
final Signature sig = Signature.getInstance(PKCSObjectIdentifiers.sha256WithRSAEncryption.getId(), BouncyCastleProvider.PROVIDER_NAME);
sig.initSign(eekeys.getPrivate());
sig.update(crmfMsg.getProtectedBytes());
byte[] eeSignature = sig.sign();
crmfMsg.setProtection(new DERBitString(eeSignature));
 
PKIHeader myPKIHeader = new PKIHeader(new DERInteger(2), new GeneralName(new X509Name(subjectDN)), new GeneralName(new X509Name(((X509Certificate)cacert).getSubjectDN().getName())));
myPKIHeader.setMessageTime(new DERGeneralizedTime(new Date()));
// senderNonce
myPKIHeader.setSenderNonce(new DEROctetString(nonce));
// TransactionId
myPKIHeader.setTransactionID(new DEROctetString(transid));
 
PKIBody myPKIBody = new PKIBody(crmfMsg, 20); // NestedMessageContent
PKIMessage myPKIMessage = new PKIMessage(myPKIHeader, myPKIBody);
//Signing myPKIMessage
KeyPair raKeys = getRAKeys();
final Signature sig = Signature.getInstance(PKCSObjectIdentifiers.sha256WithRSAEncryption.getId(), BouncyCastleProvider.PROVIDER_NAME);
sig.initSign(rakeys.getPrivate());
sig.update(myPKIMessage.getProtectedBytes());
byte[] eeSignature = sig.sign();
myPKIMessage.setProtection(new DERBitString(eeSignature));
 
final ByteArrayOutputStream bao = new ByteArrayOutputStream();
final DEROutputStream out = new DEROutputStream(bao);
out.writeObject(myPKIMessage);
final byte[] ba = bao.toByteArray();
// Send request and receive response
final byte[] resp = sendCmpHttp(ba, 200);

Sample Config

A sample configuration of EJBCA to allow an RA to request certificates for users. The RA uses password based mac (pbe) protection of CMP messages with password 'password'. Users will be created using UID from the request DN and with a prefix, so the resulting username will be: cmp<UsersUID>. End entity profiles names CMP_ENTITY and CMP_CERT is created in EJBCA allowing the request DN.

CMP Operational Mode : RA Mode
Allow RA Verify Proof-of-Possession : check
CMP Response Protection : pbe
CMP Authentication Module : HMAC
CMP Authentication Parameters : password
RA Name Generation Scheme : DN
RA Name Generation Parameters : UID
RA Name Generation Prefix : cmp
RA End Entity Profile : CMP_ENTITY
RA Certificate Profile : CMP_CERT
RA CA Name : ManagementCA

Using one authentication secret per CA

Edit each CAs that should be used for CMP certificate issuance and enter new CMP RA Authentication Secret. There should be no parameter specified for the HMAC authentication module, otherwise, this parameter will override the CA specific configuration.

Key Update Request (kur)

Also known as the Certificate Update request. When a key pair is due to expire, the relevant end entity may request a key update. The CMP request is signed and the sender attaches their certificate in the extraCert field in the CMP message.

In Client Mode

In client mode, the only end entity that is allowed to send a KeyUpdate request is the end entity that owns the certificate to be renewed. This end entity should be the one signing the request and attaching its "old" certificate (that has not been expired yet) to the CMP message. The CA will only look into the certificate in extraCert to find which certificate is to be updated.

In RA Mode

In RA mode, an administrator is allowed to send a KeyUpdate request on behalf of an end entity. The adminstrator should be the one signing the request and attaching his own certificate to the CMP message. Either only the subjectDN or both the subjectDN and the issuerDN of the certificate to be updated are specified in the CertificateTemplate field in the CMP message.

In order for this request to succeed, the administrator sending the update request has to be authorized to perform this operation. Also, EndEntityCertificate authentication module would have to be set among the configured authentication modules.

Proof of Possession

Proof of Possession (POP) is another part where CMP has gazillions of different options. The following POPs in the CRMF are supported by EJBCA:

  • raVerify: If Allow RA Verify Proof-of-Possession is selected, EJBCA will support the raVerify POP and in that case not do any verification of POP. By default false, because the standard does not recommend this option.

  • signature: here the PublicKey is in the CertTemplate and the signature is calculated over the CertReqMsg.certReq (the standard procedure when the CertTemplate contains the subject and publicKey values).

  • signature with POPOSigningKeyInput: here the PublicKey and subject DN is in POPOSigningKeyInput, possibly just copied from the CertTemplate. The signature is calculated over the POPOSigningKeyInput (if the values are also in the CertTemplate they must be identical).

Currently these are the POPOs supported by EJBCA, so if you do not use raVerify or signature your request will fail because POPO is not verified.

Server Generated Keys

CMP allows clients to request server generated keys, using one of the following in the CRMF certificate request:

  • Leaving out the (optional) request public key in the CRMF request.

  • Adding a subjectPublicKeyInfo containing an AlgorithmIdentifier followed by a zero-length BIT STRING for the subjectPublicKey (RFC4210 Appendix D.4).

These options enable a large number of choices and taking into consideration that the server wants to restrict what type of keys the clients can request and certify, there are a number of rather strict rules and business logic used by EJBCA. The following list highlights these choices.

Note that the following only applies if server generated keys are enabled in the CMP alias configuration. Use of server generated keys are by default disabled, and the default behavior is thus that all request for server generated keys are denied.

  • If the request does not contain a request public key, key generation options are taken from the certificate profile that will be used to issue the certificate:

    • The certificate profile must contain only one allowed key algorithm and one allowed key specification, for example RSA 1024 or ECDSA secp256r1.

    • If there is not a single distinct choice, the request will be denied and an error returned to the client.

  • If the certificate profile contains a subjectPublicKeyInfo with the RSA algorithmId (rsaEncryption = 1.2.840.113549.1.1.1) the certificate profile must contain a single choice of key sizes allowed.

    • If there is not a single distinct choice, the request will be denied

  • If the certificate profile contains a subjectPublicKeyInfo with the ECDSA algorithmId (id_ecPublicKey = 1.2.840.10045.2.1), the subjectPublicKeyInfo must contain parameters where two choices are allowed:

    • implicitlyCA: The certificate profile must contain a single choice of curves allowed, otherwise the request will be denied.

    • namedCurve: With the OID of a supported named curve, which is among the allowed curves in the certificate profile.

These rules allow the CA administrator to control what server generated keys the CA will generate and return to the client, and can be summarized as:

  • A distinct choice of a single key algorithm and key size/curve, defined in the certificate profile.

  • A choice of a single RSA key size and a set of EC curves, defined in the certificate profile and selected by the client in the request.

Currently, RSA and EC keys are supported.

In order to support server generated, the client must include a id_regCtrl_protocolEncrKey in the request, containing a public key that the server will use to encrypt the private key returned in the response.

Server generated keys are returned in the CertifiedKeyPair.privateKey field in the response, as defined in the RFC4210 sections 5.3.4 and D.4. The EncryptedValue will contain the private key, encrypted using AES256 with a random symmetric key, in turn wrapped using the public key in id_regCtrl_protocolEncrKey (RFC4211 Appendix B have more details on the EncryptedValue).

Code example in Java for requesting server generated keys can be found in the test method CrmfRequestTest.test12ServerGeneratedKeys().

Certificate Validity

Generally, the validity period of issued certificates are controlled by the certificate profile. If you enable Allow validity override in the certificate profile, and the CMP initialization- or certification request contains a validity time in the CRMF request template, this validity period will be used.

Certificate Key Usage

Generally, the key usage extension of issued certificates are controlled by the certificate profile. If you enable Allow Key Usage Override in the certificate profile, and the CMP initialization- or certification request contains a key usage in the CRMF request template, this key usage will be used.

Interoperability

EJBCA cmpclient

ENTERPRISE EDITION This is an EJBCA Enterprise Edition (EE) feature.

EJBCA Enterprise includes a java command line client for CMP, used to request, renew and revoke certificates.

To build and run the cmpclient client, use the following:

ant cmpclient
cd dist/cmpclient
java -jar cmpclient.jar
java -jar cmpclient.jar crmf --help

An example work-flow when you have one CMP alias in RA mode (raalias), using password based authentication of the RA, and another CMP alias (clientupdate) in client mode allowing updates using certificate authentication.

java -jar cmpclient.jar crmf --dn "CN=tomas" --url http://192.168.122.230:8080/cmpProxy/raalias --authparam password --reqnewkeyspec RSA2048
openssl pkcs12 -export -inkey dest/tomas-key.pem -in /dest/tomas.pem -certfile ManagementCA.cacert.pem -name tomas -out dest/tomas.p12
java -jar cmpclient.jar update --dn "CN=tomas" --url http://192.168.122.230:8080/cmpProxy/clientupdate --keystore dest/tomas.p12 --keystorepwd foo123 --extraCertsFriendlyName tomas --includepopo --reqnewkeyspec RSA2048
openssl x509 -in dest/tomas.pem -text
java -jar cmpclient.jar revoke --issuer "CN=ManagementCA,O=EJBCA Sample,C=SE" --serno 17b9a7b8ce44b3fa --url http://192.168.122.230:8080/cmpProxy/raalias --authparam password

AET BlueX

CMP has been tested with BlueX from AET Europe. From EJBCA's point of view BlueX functions as an RA with the same configuration options as for jCert.

Aventra

CMP has been tested with Aventra card management system. Same configuration as above.

BouncyCastle

CMP has been tested with BouncyCastle CMP classes, available in BC 1.46 or later. Both client and RA mode should work.

Sample code for a HMAC protected (RA mode) certificate request (initial) message:

// Just preparations
final BigInteger certReqId = BigInteger.valueOf(1);
final byte[] senderNonce = "12345".getBytes();
final byte[] transactionId = "23456".getBytes();
KeyPairGenerator kpi = KeyPairGenerator.getInstance("RSA");
kpi.initialize(1024);
KeyPair keyPair = kpi.generateKeyPair();
// Now on to the CMP
CertificateRequestMessageBuilder msgbuilder = new CertificateRequestMessageBuilder(certReqId);
X500Name issuerDN = new X500Name("CN=ManagementCA");
X500Name subjectDN = new X500Name("CN=user");
msgbuilder.setIssuer(issuerDN);
msgbuilder.setSubject(subjectDN);
final byte[] bytes = keyPair.getPublic().getEncoded();
final ByteArrayInputStream bIn = new ByteArrayInputStream(bytes);
final ASN1InputStream dIn = new ASN1InputStream(bIn);
final SubjectPublicKeyInfo keyInfo = new SubjectPublicKeyInfo((ASN1Sequence)dIn.readObject());
dIn.close();
msgbuilder.setPublicKey(keyInfo);
GeneralName sender = new GeneralName(subjectDN);
msgbuilder.setAuthInfoSender(sender);
// RAVerified POP
msgbuilder.setProofOfPossessionRaVerified();
CertificateRequestMessage msg = msgbuilder.build();
org.bouncycastle.asn1.crmf.CertReqMessages msgs = new org.bouncycastle.asn1.crmf.CertReqMessages(msg.toASN1Structure());
org.bouncycastle.asn1.cmp.PKIBody pkibody = new org.bouncycastle.asn1.cmp.PKIBody(org.bouncycastle.asn1.cmp.PKIBody.TYPE_INIT_REQ, msgs);
// Message protection and final message
GeneralName recipient = new GeneralName(issuerDN);
ProtectedPKIMessageBuilder pbuilder = new ProtectedPKIMessageBuilder(sender, recipient);
pbuilder.setMessageTime(new Date());
// senderNonce
pbuilder.setSenderNonce(senderNonce);
// TransactionId
pbuilder.setTransactionID(transactionId);
// Key Id used (required) by the recipient to do a lot of stuff
pbuilder.setSenderKID("KeyID".getBytes());
pbuilder.setBody(pkibody);
JcePKMACValuesCalculator jcePkmacCalc = new JcePKMACValuesCalculator();
final AlgorithmIdentifier digAlg = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.3.14.3.2.26")); // SHA1
final AlgorithmIdentifier macAlg = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.840.113549.2.7")); // HMAC/SHA1
jcePkmacCalc.setup(digAlg, macAlg);
PKMACBuilder macbuilder = new PKMACBuilder(jcePkmacCalc);
MacCalculator macCalculator = macbuilder.build("password".toCharArray());
ProtectedPKIMessage message = pbuilder.build(macCalculator);

Sample code for a HMAC protected (RA mode) revocation request message:

// Just preparations
final byte[] senderNonce = "12345".getBytes();
final byte[] transactionId = "23456".getBytes();
BigInteger serNo = new BigInteger("aabbccdd");
X500Name issuerDN = new X500Name("CN=ManagementCA");
X500Name userDN = new X500Name("CN=user");
// Cert template too tell which cert we want to revoke
CertTemplateBuilder myCertTemplate = new CertTemplateBuilder();
myCertTemplate.setIssuer(issuerDN);
myCertTemplate.setSubject(userDN);
myCertTemplate.setSerialNumber(new ASN1Integer(serNo));
// Extension telling revocation reason
ExtensionsGenerator extgen = new ExtensionsGenerator();
CRLReason crlReason = CRLReason.lookup(CRLReason.cessationOfOperation);
extgen.addExtension(Extension.reasonCode, false, crlReason);
Extensions exts = extgen.generate();
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(myCertTemplate.build());
v.add(exts);
ASN1Sequence seq = new DERSequence(v);
RevDetails myRevDetails = RevDetails.getInstance(seq);
RevReqContent myRevReqContent = new RevReqContent(myRevDetails);
PKIBody myPKIBody = new PKIBody(PKIBody.TYPE_REVOCATION_REQ, myRevReqContent); // revocation request
// Message protection and final message
GeneralName sender = new GeneralName(userDN);
GeneralName recipient = new GeneralName(issuerDN);
ProtectedPKIMessageBuilder pbuilder = new ProtectedPKIMessageBuilder(sender, recipient);
pbuilder.setMessageTime(new Date());
// senderNonce
pbuilder.setSenderNonce(senderNonce);
// TransactionId
pbuilder.setTransactionID(transactionId);
// Key Id used (required) by the recipient to do a lot of stuff
pbuilder.setSenderKID("KeyId".getBytes());
pbuilder.setBody(myPKIBody);
JcePKMACValuesCalculator jcePkmacCalc = new JcePKMACValuesCalculator();
final AlgorithmIdentifier digAlg = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.3.14.3.2.26")); // SHA1
final AlgorithmIdentifier macAlg = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.840.113549.2.7")); // HMAC/SHA1
jcePkmacCalc.setup(digAlg, macAlg);
PKMACBuilder macbuilder = new PKMACBuilder(jcePkmacCalc);
MacCalculator macCalculator = macbuilder.build("password".toCharArray());
ProtectedPKIMessage message = pbuilder.build(macCalculator);

Sample code for a signature protected (Client mode) message:

CertificateRequestMessageBuilder msgbuilder = new CertificateRequestMessageBuilder(BigInteger.valueOf(certReqId));
X509NameEntryConverter dnconverter = new X509DefaultEntryConverter();
X500Name issuerDN = X500Name.getInstance(new X509Name("CN=ManagementCA").toASN1Object());
X500Name subjectDN = X500Name.getInstance(new X509Name("CN=user", dnconverter).toASN1Object());
msgbuilder.setIssuer(issuerDN);
msgbuilder.setSubject(subjectDN);
final byte[] bytes = keyPair.getPublic().getEncoded();
final ByteArrayInputStream bIn = new ByteArrayInputStream(bytes);
final ASN1InputStream dIn = new ASN1InputStream(bIn);
final SubjectPublicKeyInfo keyInfo = new SubjectPublicKeyInfo((ASN1Sequence)dIn.readObject());
msgbuilder.setPublicKey(keyInfo);
GeneralName sender = new GeneralName(subjectDN);
msgbuilder.setAuthInfoSender(sender);
Control control = new RegTokenControl("foo123");
msgbuilder.addControl(control);
Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
ContentSigner popsigner = new JcaContentSignerBuilder("SHA1withRSA").setProvider(prov).build(keyPair.getPrivate());
msgbuilder.setProofOfPossessionSigningKeySigner(popsigner);
CertificateRequestMessage msg = msgbuilder.build();
GeneralName recipient = new GeneralName(issuerDN);
ProtectedPKIMessageBuilder pbuilder = new ProtectedPKIMessageBuilder(sender, recipient);
pbuilder.setMessageTime(new Date());
// senderNonce
pbuilder.setSenderNonce(senderNonce);
// TransactionId
pbuilder.setTransactionID(transactionId);
org.bouncycastle.asn1.crmf.CertReqMessages msgs = new org.bouncycastle.asn1.crmf.CertReqMessages(msg.toASN1Structure());
org.bouncycastle.asn1.cmp.PKIBody pkibody = new org.bouncycastle.asn1.cmp.PKIBody(org.bouncycastle.asn1.cmp.PKIBody.TYPE_INIT_REQ, msgs);
pbuilder.setBody(pkibody);
ContentSigner msgsigner = new JcaContentSignerBuilder("SHA1withRSA").setProvider(prov).build(keyPair.getPrivate());
ProtectedPKIMessage message = pbuilder.build(msgsigner);

CMP for OpenSSL

CMP has been tested with cmpforopenssl. Cmpforopenssl is submitted for inclusion in OpenSSL and will hopefully be a part of OpenSSL in the future. Meanwhile, the code can be found on GitHub:

There is also a Quick Qtart guide, that has been tested with EJBCA.

The old client tool in cmpforopenssl was called cmpclient, while the new one is in the openssl command itself. It works with EJBCA CMP in both RA mode and client mode.

RA mode

Cmpforopenssl works with EJBCA in RA mode with the following EJBCA configuration, using for example alias "opensslra" (unmentioned configurations = default):

CMP Operational Mode : RA Mode
CMP Response Protection : pbe
CMP Authentication Module : HMAC
CMP Authentication Parameters : password

You can then use cmpforopenssl (as an RA):

./openssl cmp -cmd ir -server localhost:8080 -path ejbca/publicweb/cmp/opensslra -srvcert ManagementCA.cacert.pem -user NewUser -pass password -certout clcert1.pem -newkey key1.pem -keyfmt PEM -certfmt PEM -subject "/CN=NewUser/O=My Organization/C=SE"

or, with other version of cmpforopenssl:

./cmpclient --server localhost --port 8080 --path ejbca/publicweb/cmp --srvcert ManagementCA.cacert.crt --ir --user mykeyid --password password --newclcert clcert.der --newkey key.pem --subject "CN=User Name;O=My Organization;C=SE"

This requests a certificate, defining the subject DN that will be used. The CA used to sign the certificate is specified in the EJBCA cmp configuration, and can be taken from the keyid. EJBCA authenticated the request using the HMAC protection with the password, and accepts any request upon correct authentication.

RA mode, Server Generated Keys

You can request server generated keys by omitting the public key in the certificate request, using the same request as an ir, but without public key. Note however that the cmpclient cannot be used since no cmpclient parameters support omitting the public key. For example Java code, refer to the test class CrmfRequestTest.test12ServerGeneratedKeys().

Client mode, HMAC Password Authentication

Cmpforopenssl works with with EJBCA in client mode, with HMAC password authentication, using the following EJBCA configuration with alias tex. "opensslclient" (unmentioned configurations = default):

CMP Authentication Module : HMAC
CMP Authentication Parameters : password
Extract Username Component : CN

You can now add a new user in EJBCA:

bin/ejbca.sh ra addendentity user1 --password password "CN=user1,O=My Organization,C=SE" ManagementCA 1 USERGENERATED
bin/ejbca.sh ra setclearpwd user1 password
bin/ejbca.sh ra setendentitystatus user1 10

You can then use cmpforopenssl (as a client):

./openssl cmp -cmd ir -server localhost:8080 -path ejbca/publicweb/cmp/opensslclient -srvcert ManagementCA.cacert.pem -user user1 -pass password -certout clcert1.pem -newkey key1.pem -keyfmt PEM -certfmt PEM -subject "/CN=user1/O=My Organization/C=SE"

or, with other version of cmpforopenssl:

./cmpclient --server localhost --port 8080 --path ejbca/publicweb/cmp --srvcert ManagementCA.der --ir --user mykeyid --password password --newclcert clcert.der --newkey key.pem --subject "CN=user1;O=My Organization;C=SE"

This requests a certificate, and the requested subject DN must match the registered subject DN. EJBCA authenticates the request using the HMAC protection with the password of the registered user. See the CMP documentation above for more advanced configuration.

Client mode, client certificate authentication

Cmpforopenssl works with with EJBCA in client mode, with certificate authentication, using the following EJBCA configuration with alias tex. "openssleec" (unmentioned configurations = default):

CMP Authentication Module : EndEntityCertificate
CMP Authentication Parameters : ManagementCA (use the CA that issues your client authentication certificate)
Extract Username Component : CN

You can now issue a certificate using certificate authentication in EJBCA (the end entity needs a certificate before so we re-use user1 from above):

bin/ejbca.sh ra setclearpwd user1 password
bin/ejbca.sh ra setendentitystatus user1 10

You can then use cmpforopenssl (as a client):

./openssl cmp -cmd ir -server localhost:8080 -path ejbca/publicweb/cmp/openssleec -srvcert ManagementCA.cacert.pem -cert clcert.pem -key key.pem -certout clcert1.pem -newkey key1.pem -keyfmt PEM -certfmt PEM -subject "/CN=user1/O=My Organization/C=SE"

This requests a certificate, and the requested subject DN must match the registered subject DN. EJBCA authenticates the request using the signature protection with the certificate of the registered user. See the CMP documentation above for more advanced configuration.

You can also use a 'cr' instead of an 'ir';

bin/ejbca.sh ra setendentitystatus user1 10
./openssl cmp -cmd cr -server localhost:8080 -path ejbca/publicweb/cmp/openssleec -srvcert ManagementCA.cacert.pem -cert clcert.pem -key key.pem -certout clcert1.pem -newkey key1.pem -keyfmt PEM -certfmt PEM -subject "/CN=user1/O=My Organization/C=SE"

Client mode, Vendor certificate authentication (EJBCA Enterprise only)

If the end entity has a Vendor certificate with which it should identify itself for initial enrollment, as specified in 3GPP for example, it can also do that. In this case the CA issuing the end entity certificate is not the same as the Vendor CA. The vendor CA must be imported in EJBCA as an External CA ('Import CA certificate' in the admin GUI). To enable vendor certificate authentication add the following to the CMP configuration with alias tex. "3gpp" for client certificate authentication:

Use Vendor Certificate Mode : checked
Vendor CA : 3GPP-CA

With this configuration you can now request an initial certificate with the following command:

./openssl cmp -cmd ir -server localhost:8080 -path ejbca/publicweb/cmp/3gpp -srvcert ManagementCA.cacert.pem -cert devicecert.pem -key devicekey.pem -certout clcert1.pem -newkey key1.pem -keyfmt PEM -certfmt PEM -subject "/CN=device/O=My Organization/C=SE"

In this configuration 'devicecert.pem' and 'devicekey.pem' are the device's private key and the certificate issued by the Vendor CA (3GPP-CA). ManagementCA.cacert.pem is the CA certificate of the CA in EJBCA issuing the new certificate for the device.
It is possible to specify more than one vendor CA. The vendor CA names should, in this case, be separated by ';'.

Cryptlib

CMP has been tested with CryptLib. An old test program for running CryptLib against EJBCA can be downloaded from download.primekey.com.

RSA jCert

CMP has been tested using RSA jCert toolkit for initialization requests. To run this as an RA you should configure CMP with:

  • CMP Operational Mode : RA Mode

  • Allow RA Verify Proof-of-Possession : check

  • CMP Response Protection : pbe

  • CMP Authentication Module : HMAC

  • CMP Authentication Parameters : your shared password

  • and other configurations you want for your RA.

Sample CMP workflow

Enrolling Device with HMAC password

A typical PKI work-flow using CMP involves enrolling a device with a certificate and then having the device automatically renew the certificate when it is about to expire.

  1. Generate a key pair

  2. Initial enrollment of client certificate using a one-time enrollment code

  3. Generate a new key pair

  4. Renew with a new certificate for the new key pair, authenticated using the old key pair and certificate

The above steps can be simulated in reality using the openssl and cmpforopenssl client, but also using the EJBCA cmpclient (Enterprise only)

This works with a default cmpalias (named cmp) configured with parameters:

CMP Authentication Module : HMAC
CMP Authentication Parameters : password
Extract Username Component : CN

  1. Generate a key pair:

    $ ./openssl genrsa -out certs/cl_key.pem 2048
  2. Initial enrollment:
    Before initial enrollment you add a new End Entity in EJBCA, in this example with user name cmptest and subject DN 'CN=cmptest', and enrollment code 'CMP-pwd'.

    $ ./openssl cmp -cmd ir \
    -server ejbca-server:8080 \
    -path ejbca/publicweb/cmp \
    -srvcert certs/3GPPCA.pem \
    -user cmptest \
    -pass CMP-pwd \
    -newkey certs/cl_key.pem \
    -certout certs/cl_cert.pem \
    -subject "/CN=cmptest"
  3. Generate a new key pair:

    $ ./openssl genrsa -out certs/cl_new_key.pem 2048
  4. Renew with a new certificate:

    $ ./openssl cmp -cmd kur \
    -server ejbca-server:8080 \
    -path ejbca/publicweb/cmp \
    -srvcert certs/3GPPCA.pem \
    -key certs/cl_key.pem \
    -cert certs/cl_cert.pem \
    -newkey certs/cl_new_key.pem \
    -certout certs/cl_new_cert.pem

Enrolling Device with Vendor Certificate

A PKI work-flow as specified in the 3GPP standard uses CMP to enroll a device, authenticating the initial request using a Vendor certificate added to the device at manufacturing. After initial enrollment the device can automatically renew the certificate when it is about to expire.

  1. The is a Vendor Root CA and a Vendor Sub CA that issues a Vendor Certificate to the device, with which is comes pre-provisioned from the factory.

  2. The Vendor Root CA is trusted for initial enrollment, for devices pre-registered in EJBCA with parts of the DN (usually device serial number).

  3. We want to generate two certificates for the device, one for IPSEC and one for TLS, and thus the Vendor Certificate is used for multiple authentications to different end entities.

  4. Generate two new key pairs on the device

  5. Initial enrollment of an IPSEC Certificate for the new key on the device uses certificate authentication with the Vendor Certificate on the device.

  6. Initial enrollment of a TLS Certificate for the new key on the device uses certificate authentication with the Vendor Certificate on the device.

  7. Generate two new key pairs on the device

  8. Renew the IPSEC certificate for the new key pair, authenticated using the old key pair and certificate

  9. Renew thl TLS certificate for the new key pair, authenticated using the old key pair and certificate

The above steps can be simulated in reality using the cmpforopenssl client, but also using the EJBCA cmpclient (Enterprise only)

This works with two cmpaliases configured with parameters:

CMP Alias: aliasIPSEC
CMP Operational Mode: Client
CMP Authentication Module : EndEntityCertificate
Extract Username Component : CN
RA Name Generation Postfix : _IPSEC
Vendor Certificate Mode: Use
List Of Vendor CAs: Add Vendor Root CA (imported as External CA in EJBCA)
 
CMP Alias: aliasTLS
CMP Operational Mode: Client
CMP Authentication Module : EndEntityCertificate
Extract Username Component : CN
RA Name Generation Postfix : _TLS
Vendor Certificate Mode: Use
List Of Vendor CAs: Add Vendor Root CA (imported as External CA in EJBCA

The Vendor Certificate is issued (suggested as a keystore with the private key) from Vendor Sub CA the with subjectDN: CN=1234.primekey.com,O=PrimeKey,C=SE

  1. Generate key pairs:

    $ ./openssl genrsa -out certs/ipsec_key.pem 2048
    $ ./openssl genrsa -out certs/tls_key.pem 2048
  2. Initial enrollment:
    Before initial enrollment you add two new End Entities in EJBCA, in this example with user name 1234.primekey.com_IPSEC and 1234.primekey.com_TLS with subject DN 'CN=ipsec1234' resp. 'CN=hostname1234'.

    $ openssl cmp -cmd ir -server localhost:8080 -path ejbca/publicweb/cmp/aliasIPSEC \
    -cert VendorCert.pem -key VendorKey.pem -certout ipsec_cert.pem -newkey ipsec_key.pem \
    -subject "/CN=ipsec1234" -extracerts VendorExtraCerts.pem -trusted IPSECROOTRSA.cacert.pem \
    -implicitconfirm
     
    $ openssl cmp -cmd ir -server localhost:8080 -path ejbca/publicweb/cmp/aliasTLS \
    -cert VendorCert.pem -key VendorKey.pem -certout tls_cert.pem -newkey tls_key.pem \
    -subject "/CN=hostname1234" -extracerts VendorExtraCerts.pem -trusted TLSROOTRSA.cacert.pem \
    -implicitconfirm
  3. Generate new key pairs:

    $ ./openssl genrsa -out certs/ipsec_new_key.pem 2048
    $ ./openssl genrsa -out certs/tls_new_key.pem 2048
  4. Renew with new certificates:

    $ openssl cmp -cmd kur -server localhost:8080 -path ejbca/publicweb/cmp/aliasIPSEC \
    -cert ipsec_cert.pem -key ipsec_key.pem -certout ipsec_new_cert.pem -newkey ipsec_new_key.pem \
    -subject "/CN=ipsec1234" -extracerts IPSECCAcerts.pem -trusted IPSECROOTRSA.cacert.pem \
    -implicitconfirm
     
    $ openssl cmp -cmd kur -server localhost:8080 -path ejbca/publicweb/cmp/aliasTLS \
    -cert tls_cert.pem -key tls_key.pem -certout tls_new_cert.pem -newkey tls_new_key.pem \
    -subject "/CN=hostname1234" -extracerts TLSCAcerts.pem -trusted TLSROOTRSA.cacert.pem \
    -implicitconfir

Custom handling of certificate request

A custom plug-in class can be added to handle a certificate request. The class implementing this plug-in must implement the org.ejbca.core.protocol.ExtendedUserDataHandler interface.

The implementation uses information from the certificate profile or name, and the request itself to manipulate the request before it is processed the normal way. This is done when the processRequestMessage is called (refer to the source code of the interface). The used certificate profile name is passed as otherData.

To enable the plug-in, go to Admin GUI>CMP Configuration and set Certificate Request Handler Class to the name of the plug-in. You can then add additional properties to be used in the implementation.

EJBCA includes an implementation that writes to the unid-fnr DB (see www.ejbca.org/docs/unid). To activate this plug-in, specify the following configuration:

Certificate Request Handler Class : org.ejbca.core.protocol.unid.UnidFnrHandler
Unid Data Source : java:/UnidDS

Note that you have to set this using the CLI (as it is not possible in the Admin GUI), according to the following:

bin/ejbca.sh config cmp updatealias --alias cmpalias --key certreqhandler.class --value org.ejbca.core.protocol.unid.UnidFnrHandler
bin/ejbca.sh config cmp updatealias --alias cmpalias --key uniddatasource --value java:/UnidDS

Additionally, the Unid mapping database needs to be created. For more information, refer to www.ejbca.org/docs/unid.

CMP Error Messages

If issues occur during CMP processing, different CMP error messages or HTTP error codes are returned depending on issue type and when it is encountered.

The following lists examples of CMP error codes:

Error Description

Error Type

Error Code

The received request did not contain a DER object.

HTTP

400 Bad Request

The DER object contained in request could not be parsed to a CMP message.

Unsigned CMP

BAD_REQUEST (2)

Signature verification on a nested message failed.

Unsigned CMP

BAD_REQUEST (2)

Received CMP message was of an unknown type

Unsigned CMP

BAD_REQUEST (2)

Submitting a request with a URL that does not match an existing CMP alias

HTTP

404 Not Found

Submitting a CMP RA message with a signing certificate which was revoked or expired.

Unsigned CMP

BAD_REQUEST (2)

Submitting a CMP RA message that could not be authenticated.

Unsigned CMP

BAD_MESSAGE_CHECK (1)

Trying to revoke a certificate that was already revoked

Signed CMP

CERT_REVOKED (10)

Trying to revoke a certificate whose revocation is is waiting for approval

Unsigned CMP

BAD_REQUEST (2)

Trying to revoke a certificate from a nonexistant CA.

Unsigned CMP

BAD_REQUEST (2)

Trying to revoke a non existing certificate

Signed CMP

BAD_CERTIFICATE_ID (4)

Trying to revoke a certificate, but serial number or issuer were missing from request.

Signed CMP

BAD_CERTIFICATE_ID (4)

Revocation reason could not be parsed from CMP message

Unsigned CMP

INCORRECT_DATA (7)

Trying to issue or request a certificate from a non existing CA

Unsigned CMP

WRONG_AUTHORITY (6)

Submitting a CMP request with bad POP

Unsigned CMP

BAD_POP (9)

Submitting a CMP client mode enrollment request with invalid certificate extensions specified.

Unsigned CMP

BAD_REQUEST (2)

Submitting a CMP client mode enrollment request with invalid enrollment code.

Unsigned CMP

NOT_AUTHORIZED (23)

Attempting a key update request without the end entity authentication module configured.

Unsigned CMP

BAD_REQUEST (2)

A key update request without could not be authenticated/verified.

Unsigned CMP

BAD_REQUEST (2)

A key update request was submitted without a subject DN

Unsigned CMP

BAD_REQUEST (2)

A key update request for an end entity which wasn't found in the database.

Unsigned CMP

BAD_MESSAGE_CHECK (1)

A key update request was submitted using the same keypair.

Unsigned CMP

BAD_MESSAGE_CHECK (1)

Any other failures that may have occurred during key renewal.

Unsigned CMP

BAD_MESSAGE_CHECK (1)

Submitting a CMP client mode enrollment request with wrong user/enrollment code

Unsigned CMP

NOT_AUTHORIZED (23)

A request for server generated keys when this is not enabled in CMP alias

Unsigned CMP

BAD_REQUEST (2)

A request for server generated keys when the certificate profile does not exist

Unsigned CMP

BAD_REQUEST (2)

A request for server generated keys when the key algorithm, key size (RSA) or curve (ECDSA) is not allowed

Unsigned CMP

BAD_REQUEST (2)

A request for server generated keys with invalid or unsupported key parameters

Unsigned CMP

BAD_REQUEST (2)

Other internal errors

Unsigned CMP

Various

CMP Proxy

ENTERPRISE EDITION This is an EJBCA Enterprise Edition (EE) feature.

In some installations it may be desirable to terminate the client connection in a DMZ before connecting further to the CA. In this case the client never has a direct network connection to the CA machine. In such a scenario you can use the CMP proxy module. Clients use the CMP proxy, as it would otherwise use EJBCA. The proxy in turn connects to EJBCA gets the answer and forwards it back to the client.

The proxy is a stand alone module that runs on another machine than the CA itself.

See EJBCA_HOME/modules/cmpProxy/resources/README for information how to build and use the proxy.

Backends

The CMP Proxy can use different connection backends to the CA. The most usable are:

  • Direct HTTP connection. The CMP proxy creates a new HTTP connection to the CA, and return the response to the client, through the client connection, after receiving the response from the CA.

  • External RA connection. The CMP proxy creates an external RA msg in an external RA database, which the CA polls. When the CA stores a return message in the external RA database, this is picked up by the CMP proxy and returned to the client.

CMP Proxy Message Validation

The CMP proxy have options for verifying CMP message protection in the proxy, before passing the message to the CA. Password based MAC and Signature protection can be verifies. These validations can be activated in _cmpProxy.properties{_}. CMP message headers only allow one form of protection per message, so activating both modes will allow messages to use either form. Rejected messages will never pass the CMP Proxy, but will rejected in the same form as if they had been rejected from the CA.

Password based MAC

Password based MAC verification can be activated by setting the following value to true in cmpProxy.properties:

mp.backend.hmacPasswordValidationRequired=true

In addition to this, KeyId/password pairs need to be defined, where they KeyID is the name of the CA and the password is the CMP RA Authentication Secret for that CA.

cmp.backend.hmacPassword.keylist=[ca1:foo][ca2:bar]

Signature

This form can be activated by setting the following value:

cmp.backend.signatureRequired=true

In addition to this, the following value needs to be defined:

cmp.backend.issuerchainpath

This value can either be set to a single PEM file or to a directory containing multiple PEM files, representing one or more valid issuers of signing certificates.

CMP Proxy Error Messages

The CMP Proxy will return error messages, partly as a result of problems inherent to the proxy in itself, and partly due to evaluating CMP requests directly on the proxy before passing them on. The messages listed here are those returned by the proxy independently of the CA, as listed in the CMP Error Messages section.

Error Description

Error Type

Error Code

The received request did not contain a DER object.

Unsigned CMP

BAD_REQUEST (2)

Submitting a request with a URL that does not match an existing CMP alias

HTTP

404 Not Found

Sending a response over TCP failed.

HTTP

500 Internal Server Error

Signature/HMAC protection was required in configuration, but no protection was present.

Unsigned CMP

BAD_REQUEST (2)

HMAC/Signature verification failed.

Unsigned CMP

BAD_REQUEST (2)

Message signature was required, but no signing certificate was supplied.

Unsigned CMP

BAD_REQUEST (2)

Message signature was required, but revocation check could not be performed.

Unsigned CMP

SYSTEM_UNAVAILABLE (24)

Message signature was required, if a cache failure occurred during revocation check.

Unsigned CMP

SYSTEM_UNAVAILABLE (24)

Message signature was required, but no certificate chains defined on proxy

Unsigned CMP

SYSTEM_UNAVAILABLE (24)

Message signature was required, but signer certificate was revoked.

Unsigned CMP

BAD_REQUEST (2)