Skip to content

Commit

Permalink
provide CMP client implementation (#61)
Browse files Browse the repository at this point in the history
  • Loading branch information
Akretsch authored Oct 4, 2023
1 parent ad5039a commit 7201b31
Show file tree
Hide file tree
Showing 65 changed files with 5,554 additions and 302 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
*.bak

/target/
/path_accumulator_ps.tmp
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,8 @@ fix: Add test credential generation, fix key usage in test credentials

### 2.6.7 (Sept 28 2023)

fix: Bouncy Castle Provider initialized within the component only if not already registered in the current process
fix: Bouncy Castle Provider initialized within the component only if not already registered in the current process

### 3.0.0 (Oct 04 2023)

feat: provide CMP client implementation
152 changes: 140 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,16 @@

# Features of the generic CMP RA component

The generic CMP RA component supports the implementation of
applications that provides CMP Registration Authority (RA) functions.

The generic CMP RA component supports the implementation of applications
that provide CMP Registration Authority (RA) functions.
It implements the RA features specified in the
[Lightweight Certificate Management Protocol (CMP) Profile](
https://datatracker.ietf.org/doc/draft-ietf-lamps-lightweight-cmp-profile/),
reflecting the updates to CMP (RFC 4210) and CRMF (RFC 4211) given in
[Certificate Management Protocol (CMP) Updates](
https://datatracker.ietf.org/doc/draft-ietf-lamps-cmp-updates/)
and [Certificate Management Protocol (CMP) Algorithms](
https://datatracker.ietf.org/doc/draft-ietf-lamps-cmp-algorithms/).

## Basic features for use in PoCs, reference implementations, and in production

Expand Down Expand Up @@ -38,7 +45,7 @@ applications that provides CMP Registration Authority (RA) functions.
* The Configuration interface of the generic CMP RA component supports
setting options also dynamically and dependent on certificate profiles.
* The upstream message transfer interface of the component
* provides optional routing information via the certificate profile and
* provides optional routing information dependent on the certificate profile
* supports legacy servers by using PKCS#10 requests
and X.509 responses as alternative to CMP.
* The component has an interface for authorizing and optionally
Expand All @@ -63,8 +70,9 @@ The picture below shows the overall design and relation to JAVA base components:
Java libraries and runtime environment, including Java crypto provider (JCE).
* Errors, warnings and information on internal message processing are logged
using the framework [SLF4J](http://www.slf4j.org/).
* The implementation uses the
[Bouncy Castle library](https://www.bouncycastle.org/) (providing low-level CMP) internally.
* The implementation uses internally the
[Bouncy Castle library](https://www.bouncycastle.org/),
which providesd a low-level CMP implementation.
* As far as possible, errors are reported at application level
as CMP error messages.
Otherwise Java exceptions are thrown,
Expand All @@ -88,7 +96,7 @@ 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
* 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.
Expand All @@ -112,13 +120,11 @@ 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`](src/main/java/com/siemens/pki/cmpracomponent/main/CmpRaComponent.java).

The UML diagram
component and interface design](doc/componentandinterfacedesign.uml)
The UML diagram [component and interface design](doc/componentandinterfacedesignra.uml)
gives an overview about external components and interactions.
![component and interface design](doc/componentandinterfacedesign.png)
![component and interface design](doc/componentandinterfacedesignra.png)

### Dynamic message exchange behavior on the downstream CMP interface and
upstream PKCS#10/X.509 interface
### 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](doc/Sequence_instantiateP10X509CmpRaComponent.uml)
Expand Down Expand Up @@ -185,3 +191,125 @@ 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`.

# Features of the generic CMP client component

The client extends the
[generic CMP RA component](#features-of-the-generic-cmp-client-component).
It implements the End Entity features specified in the
[Lightweight Certificate Management Protocol (CMP) Profile](
https://datatracker.ietf.org/doc/draft-ietf-lamps-lightweight-cmp-profile/)
reflecting the updates to CMP (RFC 4210) and CRMF (RFC 4211) given in
[Certificate Management Protocol (CMP) Updates](
https://datatracker.ietf.org/doc/draft-ietf-lamps-cmp-updates/)
and [Certificate Management Protocol (CMP) Algorithms](
https://datatracker.ietf.org/doc/draft-ietf-lamps-cmp-algorithms/).

## Basic feature​s for use in PoCs, reference implementations, and in production

* The generic CMP client component component implements
the following CMP functions and features:
* Build, parse, and process CMP messages and validate their contents.
* Provide and validate CMP message protection,
based on signatures or shared secrets (MAC).
* Support all CMP use cases (including ir, cr, p10cr, kur, and rr)
defined in the [Lightweight CMP Profile](
https://datatracker.ietf.org/doc/html/draft-ietf-lamps-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 client 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 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).
* Java interface is based on Bouncy Castle (low-level CMP)
and the Java crypto provider (JCE).

## Advanced features, in particular for productive use

* 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

# Structure of the generic CMP client component

The picture below shows the overall design and relation to JAVA base components:

![Structure of the generic CMP client component](doc/CmpEeComponentDesign.png)


## Overall software design

* The API for instantiating an CMP client component is specified as a Java class.
* The API to access the generic CMP client 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](http://www.slf4j.org/).
* The implementation uses internally the
[Bouncy Castle library](https://www.bouncycastle.org/),
which providesd a low-level CMP implementation.
* Errors are reported as Java exceptions,
also in case of invalid configuration and on other fatal errors.


## Message exchange API design

For simplicity, there is only one upstream interface towards server (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.

## Component and interface design

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`](src/main/java/com/siemens/pki/cmpclientcomponent/main/CmpClient.java).

The UML diagram [component and interface design](doc/componentandinterfacedesignclient.uml)
gives an overview about external components and interactions.
![component and interface design](doc/componentandinterfacedesignclient.png)

### Dynamic message exchange behavior for downstream and upstream CMP interface

The UML diagram [Sequence diagram for CMP](doc/Sequence_instantiateCmpClientComponent.uml)
gives an overview about instantiation and message exchange
between CMP Client component and upstream interface:

![Sequence diagram for CMP](doc/Sequence_instantiateCmpClientComponent.png)

## Configuration interface design

* Each CMP client instance is controlled by providing implementations of
* [`com.siemens.pki.cmpclientcomponent.main.CmpClient.ClientContext`](src/main/java/com/siemens/pki/cmpclientcomponent/main/CmpClient.java)
* [`com.siemens.pki.cmpracomponent.main.CmpRaComponent.UpstreamExchange`](src/main/java/com/siemens/pki/cmpracomponent/main/CmpRaComponent.java) and
* [`com.siemens.pki.cmpracomponent.configuration.CmpMessageInterface`](src/main/java/com/siemens/pki/cmpracomponent/configuration/CmpMessageInterface.java)

For configuration interface details see [RA Configuration interface design](#configuration-interface-design) which is partly reused for client configuration.

3 changes: 3 additions & 0 deletions doc/Sequence_instantiateCmpClientComponent.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions doc/Sequence_instantiateCmpClientComponent.uml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
@startuml

entity "**Embedding Application**" as embedapp

activate embedapp

participant "Client Instance" as Client
participant "UpstreamExchange interface" as Upstream

activate Upstream

embedapp <-> Client : new CmpClient()

activate Client

hnote over embedapp, Client
synchronous call of getCaCertificates(),
getCertificateRequestTemplate(), getCrls(),
getRootCaCertificateUpdate(),
invokeEnrollment() or invokeRevocation()
end note

embedapp -> Client : invoke CmpClient method

Client -> Upstream : sendReceiveMessage(**byte[]** request, **String** certProfile, **int** bodyTypeOfFirstRequest)

alt synchronous
Upstream --> Client : **byte[]** sendReceiveMessage (response)

else asynchronous: delayed delivery

Upstream --> Client : **byte[]** sendReceiveMessage (response with waiting indication)
loop
Client -> Upstream : sendReceiveMessage(**byte[]** pollRequest, **String** certProfile, **int** bodyTypeOfFirstRequest)
alt
Upstream --> Client : **byte[]** sendReceiveMessage (pollResponse)
else
break
end

end
end

Upstream --> Client : **byte[]** sendReceiveMessage (response)
end
opt sucessfull enrollment without implicit confirm
Client -> Upstream : sendReceiveMessage(**byte[]** certConf, **String** certProfile, **int** bodyTypeOfFirstRequest)
Upstream --> Client : **byte[]** sendReceiveMessage (pkiConf)
end
hnote over embedapp, Client
response of getCaCertificates(), getCertificateRequestTemplate()
getCrls(), getRootCaCertificateUpdate(),
invokeEnrollment() or invokeRevocation()
end note

Client -> embedapp: CmpClient method call returns
@enduml
3 changes: 0 additions & 3 deletions doc/componentandinterfacedesign.png

This file was deleted.

3 changes: 3 additions & 0 deletions doc/componentandinterfacedesignclient.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions doc/componentandinterfacedesignclient.uml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@startuml


artifact embedding as "Embedding Application" {

(**Upstream Interface**\n- provided by Embedding Application) as upif
[**CmpClient Component**\n- instantiated by Embedding Application] as Client

database "**Configuration Interface**\n- provided by Embedding Application" as config

Client <= config : new CmpClient(config)

left to right direction

Client <--> upif : byte[] UpstreamExchange::sendReceiveMessage(byte[] request, String certProfile, int bodyTypeOfFirstRequest)
}
@enduml
3 changes: 3 additions & 0 deletions doc/componentandinterfacedesignra.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ left to right direction
downif <--> RA : byte[] processRequest(byte[] request) or\nFunction<byte[], byte[]>(byte[] request)

RA <-- upif : void gotResponseAtUpstream(byte[] response)
RA <--> upif : byte[] upstreamExchange(byte[] request, String certificateProfile) or\nBiFunction<byte[], String, byte[]>(byte[] p10csr, String certificateProfile)
RA <--> upif : byte[] UpstreamExchange::sendReceiveMessage(byte[] request, String certProfile, int bodyTypeOfFirstRequest) throws Exception; or\nBiFunction<byte[], String, byte[]>(byte[] p10csr, String certificateProfile)
}
@enduml
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.siemens.pki</groupId>
<artifactId>CmpRaComponent</artifactId>
<version>2.6.7</version>
<packaging>jar</packaging>
<version>3.0.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<parent.basedir>.</parent.basedir>
Expand Down Expand Up @@ -243,7 +243,7 @@
<url>www.siemens.com</url>
</organization>
<name>CMP RA Component</name>
<description>A generic CMP Registration Authority component library</description>
<description>A generic CMP Registration Authority and Client component library</description>
<url>https://github.com/siemens/cmp-ra-component/</url>
<licenses>
<license>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2022 Siemens AG
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package com.siemens.pki.cmpclientcomponent.configuration;

/**
*
* generic client configuration
*/
public interface ClientContext {

/**
* get enrollment specific configuration
*
* @return enrollment specific configuration
*/
EnrollmentContext getEnrollmentContext();

/**
* CMP message recipient or <code>null</code> if NULL_DN should be used
*
* @return CMP message recipient
*/
default String getRecipient() {
return null;
}

/**
* get revocation specific configuration
*
* @return revocation specific configuration
*/
RevocationContext getRevocationContext();
}
Loading

0 comments on commit 7201b31

Please sign in to comment.