Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Config recipient #76

Merged
merged 6 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Set up JDK 11
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: 11
java-version: 17
distribution: 'temurin'
- name: Cache SonarCloud packages
uses: actions/cache@v3
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,7 @@ feat: provide CMP client implementation
### 3.0.1 (Nov 07 2023)

fix: update some dependencies

### 4.0.0 (Nov 8 2023)

feat: implement configurable recipient
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<groupId>com.siemens.pki</groupId>
<artifactId>CmpRaComponent</artifactId>
<packaging>jar</packaging>
<version>3.0.1</version>
<version>4.0.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<parent.basedir>.</parent.basedir>
Expand Down Expand Up @@ -171,7 +171,7 @@
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://s01.oss.sonatype.org/</nexusUrl>
<autoReleaseAfterClose>true</autoReleaseAfterClose>
<autoReleaseAfterClose>false</autoReleaseAfterClose>
</configuration>
</plugin>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,6 @@ public interface ClientContext {
*/
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
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,20 @@

import com.siemens.pki.cmpclientcomponent.configuration.ClientContext;
import com.siemens.pki.cmpracomponent.configuration.CmpMessageInterface;
import com.siemens.pki.cmpracomponent.configuration.CredentialContext;
import com.siemens.pki.cmpracomponent.configuration.NestedEndpointContext;
import com.siemens.pki.cmpracomponent.configuration.VerificationContext;
import com.siemens.pki.cmpracomponent.cryptoservices.CertUtility;
import com.siemens.pki.cmpracomponent.main.CmpRaComponent.UpstreamExchange;
import com.siemens.pki.cmpracomponent.msggeneration.HeaderProvider;
import com.siemens.pki.cmpracomponent.msggeneration.MsgOutputProtector;
import com.siemens.pki.cmpracomponent.msggeneration.PkiMessageGenerator;
import com.siemens.pki.cmpracomponent.msgvalidation.BaseCmpException;
import com.siemens.pki.cmpracomponent.msgvalidation.CmpProcessingException;
import com.siemens.pki.cmpracomponent.msgvalidation.CmpValidationException;
import com.siemens.pki.cmpracomponent.msgvalidation.MessageBodyValidator;
import com.siemens.pki.cmpracomponent.msgvalidation.MessageHeaderValidator;
import com.siemens.pki.cmpracomponent.msgvalidation.ProtectionValidator;
import com.siemens.pki.cmpracomponent.msgvalidation.ValidatorIF;
import com.siemens.pki.cmpracomponent.protection.ProtectionProvider;
import com.siemens.pki.cmpracomponent.protection.ProtectionProviderFactory;
import com.siemens.pki.cmpracomponent.util.FileTracer;
import com.siemens.pki.cmpracomponent.util.MessageDumper;
import java.security.GeneralSecurityException;
Expand All @@ -57,7 +56,6 @@
import org.bouncycastle.asn1.cmp.PKIMessages;
import org.bouncycastle.asn1.cmp.PKIStatus;
import org.bouncycastle.asn1.cmp.PollRepContent;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.GeneralName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -71,7 +69,7 @@ class ClientRequestHandler {

class ValidatorAndProtector {

private final ProtectionProvider outputProtection;
private final MsgOutputProtector outputProtection;

private final ProtectionValidator protectionValidator;

Expand All @@ -81,46 +79,31 @@ class ValidatorAndProtector {

private final VerificationContext inputVerification;

public ValidatorAndProtector(NestedEndpointContext nestedEndpoint) throws GeneralSecurityException {
this(
NESTED_INTERFACE_NAME,
nestedEndpoint.getInputVerification(),
nestedEndpoint.getOutputCredentials(),
null);
public ValidatorAndProtector(NestedEndpointContext nestedEndpoint)
throws GeneralSecurityException, CmpProcessingException {
final VerificationContext inputVerification = nestedEndpoint.getInputVerification();
headerValidator = new MessageHeaderValidator(NESTED_INTERFACE_NAME);
outputProtection = new MsgOutputProtector(nestedEndpoint, NESTED_INTERFACE_NAME);
this.inputVerification = inputVerification;
protectionValidator = new ProtectionValidator(NESTED_INTERFACE_NAME, inputVerification);
bodyValidator = new MessageBodyValidator(NESTED_INTERFACE_NAME, (x, y) -> false, null, certProfile);
}

private ValidatorAndProtector(String certProfile, final CmpMessageInterface upstreamConfiguration)
throws GeneralSecurityException {
this(
INTERFACE_NAME,
upstreamConfiguration.getInputVerification(),
upstreamConfiguration.getOutputCredentials(),
upstreamConfiguration);
}

private ValidatorAndProtector(
String intefaceName,
VerificationContext inputVerification,
CredentialContext outputCredentials,
CmpMessageInterface upstreamConfiguration)
throws GeneralSecurityException {
headerValidator = new MessageHeaderValidator(intefaceName);
outputProtection = ProtectionProviderFactory.createProtectionProvider(outputCredentials);
this.inputVerification = inputVerification;
protectionValidator = new ProtectionValidator(intefaceName, inputVerification);
if (upstreamConfiguration != null) {
bodyValidator =
new MessageBodyValidator(intefaceName, (x, y) -> false, upstreamConfiguration, certProfile);
} else {
bodyValidator = DUMMY_VALIDATOR;
}
throws GeneralSecurityException, CmpProcessingException {
this.inputVerification = upstreamConfiguration.getInputVerification();
headerValidator = new MessageHeaderValidator(INTERFACE_NAME);
outputProtection = new MsgOutputProtector(upstreamConfiguration, INTERFACE_NAME, null);
protectionValidator = new ProtectionValidator(INTERFACE_NAME, inputVerification);
bodyValidator =
new MessageBodyValidator(INTERFACE_NAME, (x, y) -> false, upstreamConfiguration, certProfile);
}

public VerificationContext getInputVerification() {
return inputVerification;
}

public ProtectionProvider getOutputProtection() {
public MsgOutputProtector getOutputProtection() {
return outputProtection;
}

Expand All @@ -132,8 +115,6 @@ private void validateResponse(final PKIMessage response) throws BaseCmpException
}
}

private static final ValidatorIF<String> DUMMY_VALIDATOR = messageToValidate -> null;

private static final int DEFAULT_PVNO = PKIHeader.CMP_2000;

private static final String INTERFACE_NAME = "ClientUpstream";
Expand All @@ -147,8 +128,6 @@ private void validateResponse(final PKIMessage response) throws BaseCmpException

private final UpstreamExchange upstreamExchange;

private final GeneralName recipient;

private final String certProfile;

private final ValidatorAndProtector nestedValidatorAndProtector;
Expand All @@ -165,16 +144,15 @@ private void validateResponse(final PKIMessage response) throws BaseCmpException
* towards the CA
*
* @param clientContext client specific configuration
* @throws GeneralSecurityException
* @throws Exception
*/
ClientRequestHandler(
String certProfile,
final UpstreamExchange upstreamExchange,
final CmpMessageInterface upstreamConfiguration,
final ClientContext clientContext)
throws GeneralSecurityException {
throws Exception {
this.upstreamExchange = upstreamExchange;
recipient = ifNotNull(clientContext.getRecipient(), r -> new GeneralName(new X500Name(r)));
this.certProfile = certProfile;
validatorAndProtector = new ValidatorAndProtector(certProfile, upstreamConfiguration);
nestedValidatorAndProtector =
Expand Down Expand Up @@ -234,7 +212,7 @@ public int getPvno() {

@Override
public GeneralName getRecipient() {
return recipient;
return null;
}

@Override
Expand All @@ -257,15 +235,14 @@ public ASN1OctetString getTransactionID() {
return transactionId;
}
};
return PkiMessageGenerator.generateAndProtectMessage(
headerProvider, validatorAndProtector.getOutputProtection(), body);
return validatorAndProtector.getOutputProtection().createOutgoingMessage(headerProvider, body);
}

public VerificationContext getInputVerification() {
return validatorAndProtector.getInputVerification();
}

public ProtectionProvider getOutputProtection() {
public MsgOutputProtector getOutputProtection() {
return validatorAndProtector.getOutputProtection();
}

Expand Down Expand Up @@ -307,10 +284,11 @@ PKIBody sendReceiveInitialBody(final PKIBody body, final boolean withImplicitCon

PKIMessage sendReceiveValidateMessage(PKIMessage request, final int firstRequestType) throws Exception {
if (nestedValidatorAndProtector != null) {
request = PkiMessageGenerator.generateAndProtectMessage(
PkiMessageGenerator.buildForwardingHeaderProvider(request),
nestedValidatorAndProtector.getOutputProtection(),
new PKIBody(PKIBody.TYPE_NESTED, new PKIMessages(request)));
request = nestedValidatorAndProtector
.getOutputProtection()
.createOutgoingMessage(
PkiMessageGenerator.buildForwardingHeaderProvider(request),
new PKIBody(PKIBody.TYPE_NESTED, new PKIMessages(request)));
}
FileTracer.logMessage(request, INTERFACE_NAME);
byte[] rawresponse = upstreamExchange.sendReceiveMessage(request.getEncoded(), certProfile, firstRequestType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import com.siemens.pki.cmpracomponent.util.MessageDumper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
Expand Down Expand Up @@ -149,14 +148,14 @@ public interface EnrollmentResult {
* towards the CA
*
* @param clientContext client specific configuration
* @throws GeneralSecurityException in case of error
* @throws Exception in case of error
*/
public CmpClient(
String certProfile,
final UpstreamExchange upstreamExchange,
final CmpMessageInterface upstreamConfiguration,
final ClientContext clientContext)
throws GeneralSecurityException {
throws Exception {
requestHandler = new ClientRequestHandler(certProfile, upstreamExchange, upstreamConfiguration, clientContext);
this.clientContext = clientContext;
}
Expand Down Expand Up @@ -498,7 +497,8 @@ public EnrollmentResult invokeEnrollment() {
if (enrollmentType != PKIBody.TYPE_P10_CERT_REQ && enrolledPrivateKey == null) {
// central key generation in place, decrypt private key
CmsDecryptor decryptor = null;
final ProtectionProvider outputProtection = requestHandler.getOutputProtection();
final ProtectionProvider outputProtection =
requestHandler.getOutputProtection().getProtector();
if (outputProtection instanceof SignatureBasedProtection) {
final SignatureBasedProtection sigProtector = (SignatureBasedProtection) outputProtection;
decryptor = new CmsDecryptor(sigProtector.getEndCertificate(), sigProtector.getPrivateKey(), null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,24 @@
*/
public interface CmpMessageInterface {

/**
* the {@link ReprotectMode} controls how an outgoing message is protected
*/
enum ReprotectMode {
/**
* the outgoing message will be reprotected in any case.
*/
reprotect,
/**
* any protection is removed from the outgoing message
*/
strip,
/**
* an existing protection of a forwarded message is preserved, if possible
*/
keep
}

/**
* configure trust for protection validation of incoming messages
*
Expand All @@ -48,6 +66,15 @@ public interface CmpMessageInterface {
*/
CredentialContext getOutputCredentials();

/**
* allow to set new recipient for outgoing messages. The recipient is only updated if no or
* a new protection will be applied.
* @return new recipient in RDN notation or <code>null</code> if already set recipient should remain.
*/
default String getRecipient() {
return null;
}

/**
* provide configuration for protection mode of outgoing messages
*
Expand Down Expand Up @@ -82,22 +109,4 @@ public interface CmpMessageInterface {
* @return allowed time offset in seconds
*/
boolean isMessageTimeDeviationAllowed(long deviation);

/**
* the {@link ReprotectMode} controls how an outgoing message is protected
*/
enum ReprotectMode {
/**
* the outgoing message will be reprotected in any case.
*/
reprotect,
/**
* any protection is removed from the outgoing message
*/
strip,
/**
* an existing protection of a forwarded message is preserved, if possible
*/
keep
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,19 @@ public interface NestedEndpointContext {
/**
* configure protection for outgoing messages
*
* @return a protection configuration, if outgoing message should be wrapped in
* nested messages or <code>null</code> if outgoing messaged shouldn't
* be wrapped.
* @return a protection configuration for the wrapping message or <code>null</code> if the wrapping message shouldn't
* be protected.
*/
CredentialContext getOutputCredentials();

/**
* allow to set new recipient for outgoing nested messages.
* @return new recipient in RDN notation or <code>null</code> if the recipient of the wrapped message should be used.
*/
default String getRecipient() {
return null;
}

/**
* configure handling of incoming nested messages per recipient.
*
Expand Down
Loading