The generic CMP component supports the implementation of Java applications that provide CMP Registration Authority (RA) and/or CMP client functions.
It implements the CMP features specified in the Lightweight Certificate Management Protocol (CMP) Profile, reflecting the updates to CMP (RFC 4210) and CRMF (RFC 4211) given in Certificate Management Protocol (CMP) Updates and Certificate Management Protocol (CMP) Algorithms.
It has been used as a reference implementation for the standardization of CMP Updates, CMP Algorithms, and the Lightweight CMP Profile (LCMPP) and is being used for PoC developments for the standardization of RFC4210bis.
It serves as the core of productive Java-based CMP developments.
It is also used in the
Lightweight CMP RA and CMP Client
Java application for demonstration and test purposes.
- The generic RA and CMP client component implements the following CMP functions and features:
- Build, parse, and process CMP messages and validate their contents.
- Validate, modify, and add CMP message protection, based on signatures or shared secrets (MAC).
- Support all CMP use cases (including ir, cr, p10cr, kur, rr, and nested messages) defined in the Lightweight CMP Profile.
- Support all general CMP features defined in Lightweight CMP Profile, including error handling within CMP, local/central key generation, and delayed delivery of all message types.
- The component is usable in server contexts and in standalone applications.
- Use of the component is as simple as possible, not requiring specific (crypto, CMP, etc.) detailed knowledge.
- The component supports very flexible configuration, allowing to set all relevant options, with reasonable defaults.
- The component provides error reporting and logging towards the embedding application or execution environment.
- All messages are ASN.1 DER-encoded for maximal interoperability.
- The component allows using any type of message transfer, such as HTTP(S).
- Message transfer supports also asynchronous delivery.
- Java interface is based on Bouncy Castle (low-level CMP) and the Java crypto provider (JCE).
- The generic CMP RA component is usable as servlet in typical web server frameworks, such as Apache Tomcat.
- The configuration interface of the generic CMP component supports setting options also dynamically and dependent on certificate profiles.
- The upstream message transfer interface of the RA component and the message transfer interface of the CMP client component provides optional routing information dependent on the CMP operation (message body type) and the certificate profile.
- The upstream message transfer interface of the RA component supports legacy servers by using PKCS#10 requests and X.509 responses as alternative to CMP.
- The RA component has an interface for authorizing and optionally modifying certificate requests (e.g., using an external inventory).
- The RA component has an interface for reporting (also intermediate) enrollment state to external entities (e.g., inventory).
- The RA component has an interface for persisting internal state (e.g., using a database) supporting long-lasting transactions with application recovery, to support restart on failure and load balancing.
- The Configuration interface of the generic CMP client component supports setting options also dynamically and dependent on certificate profiles in a similar way as for the CMP RA component.
- The message transfer interface of the component provides optional routing information dependent on the certificate profile
- The API for instantiating an CMP RA component is specified as Java interfaces.
For the CMP client component it is specified as a Java class. - The API to access the generic CMP component is based just on common Java libraries and runtime environment, including Java crypto provider (JCE).
- Errors, warnings and information on internal message processing are logged using the framework SLF4J.
- The implementation uses internally the Bouncy Castle library, which provides a low-level CMP implementation.
- As far as possible, the RA component reports errors at application level using CMP error messages. For all other errors Java exceptions are thrown, also in case of invalid configuration and on other fatal errors.
The picture below shows the overall design and relation to the Java base components:
For simplicity, there is only one downstream interface towards clients (EEs) and one upstream interface towards server (CA). In case multiple downstream or upstream interfaces are desired:
- Differentiation in transport/routing can be achieved by the embedding application multiplexing channels.
- Differentiation in message protection or inventory behavior can be achieved via the certificate profile mechanism.
- If any further differentiation in CMP/application-level processing is required, multiple RA instances are needed.
All messages, also PKCS#10 and X.509 structures, are exchanged as ASN.1 DER-encoded byte strings.
- The transfer layer typically does not need to look into the contents of the request/response messages but can simply forward and return them as opaque data.
- The byte-string level is the least common denominator for representing PKIX-related data structures. Using it avoids the error-prone handling of inadequate class definitions provided by the standard Java RE.
The transport layer in the embedding RA server application is responsible for the following:
- Extract request message received from the client side and feed them the to RA downstream interface.
- Forward request message provided by the RA upstream interface towards the server.
- Collect response messages from server side and provide them to the RA upstream interface.
- Take resulting response message from the RA downstream interface and return it to the client.
The embedding application does not need to know CMP specifics.
It can regard incoming and outgoing CMP messages
simply as opaque Java byte arrays.
The externally usable interface is specified in com.siemens.pki.cmpracomponent.main.CmpRaComponent
.
The UML diagram component and interface design gives an overview about external components and interactions.
Dynamic message exchange behavior on the downstream CMP interface and upstream PKCS#10/X.509 interface
In the PKCS#10 case the upstream communication (towards the CA) is synchronous. The UML diagram Sequence diagram for PKCS#10/X.509 gives an overview about instantiation and message exchange between CMP RA component, downstream interface and upstream interface:
- The "Configuration Interface" activates the "Downstream Interface" when instantiating the "RA Component" by calling the instantiateP10X509CmpRaComponent() method.
- The "Downstream Interface" sends a DER-encoded CMP p10cr as a byte array to the "RA Component" by calling the Function<byte[], byte[]> method.
- The "RA Component" activates the "Upstream Interface" by calling the upstreamP10X509Exchange method with a byte array containing a DER-encoded PKCS#10 CSR and a certificate profile.
- The "Upstream Interface" processes the request, returning a byte array containing an X.509 certificate response to the "RA Component."
- The "RA Component" then responds to the Function<byte[], byte[]> method call of the "Downstream Interface" in step 2 with a byte array response containing an CMP cp message. Overall, the diagram details the method calls and message exchanges involved in the interaction between the "Configuration Interface," "Downstream Interface," "RA Component," and "Upstream Interface" for certificate management operations.
In this case the upstream CMP communication (towards the CA) may be synchronous and/or asynchronous. The UML diagram Sequence diagram for CMP gives an overview about instantiation and message exchange between CMP RA component, downstream interface, and upstream interface:
The diagram outlines an interaction between components in a system, involving the "Configuration Interface", "Downstream Interface", "RA Component", and "Upstream Interface". Here's a detailed breakdown of the steps involved:
- The "Configuration Interface" activates the "Downstream Interface" to instantiate the "RA Component" by calling the instantiateCmpRaComponent() method.
- The "Downstream Interface" sends a DER-encoded CMP request to the "RA Component" using the processRequest() method.
- The "RA Component" activates the "Upstream Interface" to perform the upstreamExchange operation with a DER-encoded CMP request and a certificate profile.
- If the interaction is synchronous, the "Upstream Interface" directly sends a DER-encoded CMP response to the "RA Component," which then responds to the "Downstream Interface" with a DER-encoded CMP response using the processRequest() method.
- If the interaction is asynchronous with delayed delivery, the "Upstream Interface" sends a null response to the "RA Component" due to the absence of the response. The "RA Component" then responds to the "Downstream Interface" with DER-encoded CMP cr/ir/kur/error response indicating a waiting indication.
- In a loop, the "Downstream Interface" sends a DER-encoded CMP polling request to the "RA Component," which responds with a DER-encoded CMP polling poll response.
- If the "Upstream Interface" got a DER-encoded CMP response by calling gotResponseAtUpstream() the "RA Component" responds DER-encoded CMP response to the "Downstream Interface."
- Each RA instance is controlled by providing an implementation of the RA configuration interface.
- The configuration interface has a nested hierarchy of configuration items:
- Verification context (trusted root certificates, intermediate certificates, certificate verification options, and options for CRL-based and OCSP-based certificate status checking; optionally also shared secrets)
- Credential context (a private key with corresponding certificate and its chain; optionally also shared secrets)
- Inventory interface, can be used for authorizing, modifying, and logging certificate management operations
- Persistence interface, used to encode pending RA activity as a dynamic map of transaction IDs to messages
- The embedding application needs to
provide getter methods for primitive and nested items.
- It may take required data from a static configuration file and credential file contents.
- It is responsible for protecting integrity and/or confidentiality of the configuration items as far as needed.
- The getter functions are called in the moment configuration items are needed,
which supports dynamic changes.
- Where appropriate, they may depend on a certificate profile optionally given in CMP request headers.
- If accessing the configuration interface shall be logged, the SLF4J-Logger of com.siemens.pki.cmpracomponent.util.ConfigLogger must be set to DEBUG, e.g. start with -Dorg.slf4j.simpleLogger.log.com.siemens.pki.cmpracomponent.util.ConfigLogger=debug
and status updates, and for persistency
- The interface to an external inventory component is specified in InventoryInterface.
- The interface to an external persistency provider is specified in PersistencyInterface.
- Implementations of both interfaces are part of the
configuration parameter
given at CMP RA component instantiation in
com.siemens.pki.cmpracomponent.main.CmpRaComponent
.
The client extends the generic CMP RA component. It implements the end-entity features specified in the Lightweight Certificate Management Protocol (CMP) Profile.
The picture below shows the overall design and relation to the Java base components:
For simplicity, there is only one interface towards the server (RA or CA). In case multiple upstream interfaces are desired:
- Differentiation in transport/routing can be achieved by the embedding application multiplexing channels.
- Differentiation in message protection or inventory behavior can be achieved via the certificate profile mechanism.
- If any further differentiation in CMP/application-level processing is required, multiple CMP client instances are needed.
All CMP messages are exchanged as ASN.1 DER-encoded byte strings.
- The transfer layer typically does not need to look into the contents of the request/response messages but can simply forward and return them as opaque data.
- The byte-string level is the least common denominator for representing PKIX-related data structures. Using it avoids the error-prone handling of inadequate class definitions provided by the standard Java RE.
The transport layer in the embedding client application is responsible for the following:
- Forward request message provided by the client upstream interface towards the server.
- Collect response messages from server side and provide them to the client upstream interface.
The embedding application does not need to know CMP specifics.
It can regard incoming and outgoing CMP messages
simply as opaque Java byte arrays.
The externally usable interface is specified in com.siemens.pki.cmpclientcomponent.main.CmpClient
.
The UML diagram component and interface design gives an overview about external components and interactions.
The UML diagram Sequence diagram for CMP gives an overview about instantiation and message exchange between CMP Client component and upstream interface:
The diagram describes the interaction between an "Embedding Application" and a "Client Instance" using the "UpstreamExchange interface" to perform actions related to certificate management. Here's a detailed explanation of the steps involved in the interaction:
- The "Embedding Application" activates and interacts with the "Client Instance" to perform certificate management operations.
- The "Client Instance" interacts with the "UpstreamExchange interface" to send and receive messages related to certificate management.
- The "Embedding Application" makes a synchronous call to the "Client Instance" to execute the getCACertificates(), getCertificateRequestTemplate(), getCRLs(), getRootCACertificateUpdate(), invokeEnrollment(), or invokeRevocation() methods.
- The "Embedding Application" sends a request to the "Client Instance" to invoke the CmpClient method.
- The "Client Instance" interacts with the "UpstreamExchange interface" to send and receive messages using the sendReceiveMessage() method. This includes sending a request with specific parameters and receiving a response.
- If the communication is synchronous, the "UpstreamExchange interface" directly sends a response to the "Client Instance". If it's asynchronous, there may be a delayed delivery, and the response includes a waiting indication.
- In the case of asynchronous communication, the "Client Instance" loops back to the "UpstreamExchange interface" to send a poll request and receive a poll response until the response is received.
- After successful enrollment without implicit confirmation, the "Client Instance" sends a certificate confirmation, and the "UpstreamExchange interface" responds with a PKI confirmation.
- The "Client Instance" then sends the response of the method call back to the "Embedding Application".
- Each CMP client instance is controlled by providing implementations of
For configuration interface details see RA Configuration interface design which is partly reused for client configuration.
After the javadoc documentation has been generated locally by invoking
mvn javadoc:javadoc
, it can be found
at target/site/apidocs/com/siemens/pki/cmpracomponent/main/CmpRaComponent.html
.
This work was partly funded by the German Federal Ministry of Education and Research in the project Quoryptan through grant number 16KIS2033.