Skip to content

Commit

Permalink
Use same credentials for MAC based protection at Downstream (#106)
Browse files Browse the repository at this point in the history
* Use verification credentials for MAC based protection of outgoing messages at RaDownstream
  • Loading branch information
kiron-mx authored Sep 10, 2024
1 parent 79eb00a commit 041ef55
Show file tree
Hide file tree
Showing 23 changed files with 583 additions and 68 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,8 @@ fix: handling of NestedEndpointContext.isIncomingRecipientValid
### 4.1.4 (Jul 23 2024)

fix: again fix protection of NESTED responses

### 4.2.0 (Sep 10 2024)

feat: Use same credentials for MAC based protection at Downstream

2 changes: 1 addition & 1 deletion 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>4.1.4</version>
<version>4.2.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<parent.basedir>.</parent.basedir>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class ValidatorAndProtector {
public ValidatorAndProtector(NestedEndpointContext nestedEndpoint)
throws GeneralSecurityException, CmpProcessingException {
headerValidator = new MessageHeaderValidator(NESTED_INTERFACE_NAME);
outputProtection = new MsgOutputProtector(nestedEndpoint, NESTED_INTERFACE_NAME);
outputProtection = new MsgOutputProtector(nestedEndpoint, NESTED_INTERFACE_NAME, null);
this.inputVerification = ConfigLogger.logOptional(
NESTED_INTERFACE_NAME,
"NestedEndpointContext.getInputVerification()",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
import com.siemens.pki.cmpracomponent.configuration.CmpMessageInterface.ReprotectMode;
import com.siemens.pki.cmpracomponent.configuration.CredentialContext;
import com.siemens.pki.cmpracomponent.configuration.NestedEndpointContext;
import com.siemens.pki.cmpracomponent.configuration.SharedSecretCredentialContext;
import com.siemens.pki.cmpracomponent.msgvalidation.CmpProcessingException;
import com.siemens.pki.cmpracomponent.msgvalidation.MessageContext;
import com.siemens.pki.cmpracomponent.persistency.PersistencyContext;
import com.siemens.pki.cmpracomponent.protection.ProtectionProvider;
import com.siemens.pki.cmpracomponent.protection.ProtectionProviderFactory;
Expand Down Expand Up @@ -61,6 +63,8 @@ public class MsgOutputProtector {
private final ProtectionProvider protector;
private final PersistencyContext persistencyContext;

private final CredentialContext protectionCredentials;

private final boolean suppressRedundantExtraCerts;

private final GeneralName recipient;
Expand All @@ -69,15 +73,15 @@ public class MsgOutputProtector {
* ctor
* @param config specific configuration
* @param interfaceName name of interface used in logging messages
* @param persistencyContext reference to transaction specific
* {@link PersistencyContext}
* @param messageContext reference to transaction specific
* {@link MessageContext}
* @throws CmpProcessingException in case of inconsistent configuration
* @throws GeneralSecurityException in case of broken configuration
*/
public MsgOutputProtector(
final CmpMessageInterface config, final String interfaceName, final PersistencyContext persistencyContext)
final CmpMessageInterface config, final String interfaceName, final MessageContext messageContext)
throws CmpProcessingException, GeneralSecurityException {
this.persistencyContext = persistencyContext;
persistencyContext = ifNotNull(messageContext, MessageContext::getPersistencyContext);
suppressRedundantExtraCerts = ConfigLogger.log(
interfaceName,
"CmpMessageInterface.getSuppressRedundantExtraCerts()",
Expand All @@ -87,15 +91,21 @@ public MsgOutputProtector(
recipient = ifNotNull(
ConfigLogger.logOptional(interfaceName, "CmpMessageInterface.getRecipient()", config::getRecipient),
rec -> new GeneralName(new X500Name(rec)));
final CredentialContext outputCredentials = ConfigLogger.logOptional(
interfaceName, "CmpMessageInterface.getOutputCredentials()", config::getOutputCredentials);
if (reprotectMode == ReprotectMode.reprotect && outputCredentials == null) {
throw new CmpProcessingException(
interfaceName,
PKIFailureInfo.wrongAuthority,
"reprotectMode is reprotect, but no output credentials are given");
final CredentialContext verificationCredentials =
ifNotNull(messageContext, MessageContext::getCredentialContext);
if (verificationCredentials instanceof SharedSecretCredentialContext) {
protectionCredentials = verificationCredentials;
} else {
protectionCredentials = ConfigLogger.logOptional(
interfaceName, "CmpMessageInterface.getOutputCredentials()", config::getOutputCredentials);
if (reprotectMode == ReprotectMode.reprotect && protectionCredentials == null) {
throw new CmpProcessingException(
interfaceName,
PKIFailureInfo.wrongAuthority,
"reprotectMode is reprotect, but no output credentials are given");
}
}
protector = ProtectionProviderFactory.createProtectionProvider(outputCredentials, interfaceName);
protector = ProtectionProviderFactory.createProtectionProvider(protectionCredentials, interfaceName);
}

/**
Expand All @@ -105,18 +115,22 @@ public MsgOutputProtector(
* @throws CmpProcessingException in case of inconsistent configuration
* @throws GeneralSecurityException in case of broken configuration
*/
public MsgOutputProtector(final NestedEndpointContext config, final String interfaceName)
public MsgOutputProtector(
final NestedEndpointContext config, final String interfaceName, final CredentialContext credentialContext)
throws CmpProcessingException, GeneralSecurityException {
this.persistencyContext = null;
suppressRedundantExtraCerts = false;
reprotectMode = ReprotectMode.reprotect;
recipient = ifNotNull(
ConfigLogger.logOptional(interfaceName, "NestedEndpointContext.getRecipient()", config::getRecipient),
rec -> new GeneralName(new X500Name(rec)));
protector = ProtectionProviderFactory.createProtectionProvider(
ConfigLogger.logOptional(
interfaceName, "NestedEndpointContext.getOutputCredentials()", config::getOutputCredentials),
interfaceName);
if (credentialContext instanceof SharedSecretCredentialContext) {
protectionCredentials = credentialContext;
} else {
protectionCredentials = ConfigLogger.logOptional(
interfaceName, "NestedEndpointContext.getOutputCredentials()", config::getOutputCredentials);
}
protector = ProtectionProviderFactory.createProtectionProvider(protectionCredentials, interfaceName);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.siemens.pki.cmpracomponent.msgvalidation.CmpProcessingException;
import com.siemens.pki.cmpracomponent.msgvalidation.CmpValidationException;
import com.siemens.pki.cmpracomponent.msgvalidation.InputValidator;
import com.siemens.pki.cmpracomponent.msgvalidation.MessageContext;
import com.siemens.pki.cmpracomponent.msgvalidation.MessageHeaderValidator;
import com.siemens.pki.cmpracomponent.msgvalidation.ProtectionValidator;
import com.siemens.pki.cmpracomponent.persistency.PersistencyContext;
Expand Down Expand Up @@ -131,8 +132,8 @@ public PKIMessage handleRequest(final PKIMessage in, final PersistencyContext pe
// never re-protect a KUR
sentMessage = in;
} else {
final MsgOutputProtector outputProtector =
new MsgOutputProtector(upstreamConfiguration, INTERFACE_NAME, persistencyContext);
final MsgOutputProtector outputProtector = new MsgOutputProtector(
upstreamConfiguration, INTERFACE_NAME, new MessageContext(persistencyContext, null));
sentMessage = outputProtector.protectOutgoingMessage(in, null);
}
final NestedEndpointContext nestedEndpointContext = ConfigLogger.logOptional(
Expand All @@ -141,7 +142,7 @@ public PKIMessage handleRequest(final PKIMessage in, final PersistencyContext pe
upstreamConfiguration::getNestedEndpointContext);
if (nestedEndpointContext != null) {
final MsgOutputProtector nestedProtector =
new MsgOutputProtector(nestedEndpointContext, "NESTED CMP upstream");
new MsgOutputProtector(nestedEndpointContext, "NESTED CMP upstream", null);
// wrap into nested message
sentMessage = nestedProtector.protectOutgoingMessage(
new PKIMessage(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.siemens.pki.cmpracomponent.configuration.CkgContext;
import com.siemens.pki.cmpracomponent.configuration.CmpMessageInterface;
import com.siemens.pki.cmpracomponent.configuration.Configuration;
import com.siemens.pki.cmpracomponent.configuration.CredentialContext;
import com.siemens.pki.cmpracomponent.configuration.InventoryInterface;
import com.siemens.pki.cmpracomponent.configuration.NestedEndpointContext;
import com.siemens.pki.cmpracomponent.configuration.SignatureCredentialContext;
Expand All @@ -41,6 +42,7 @@
import com.siemens.pki.cmpracomponent.msgvalidation.CmpProcessingException;
import com.siemens.pki.cmpracomponent.msgvalidation.CmpValidationException;
import com.siemens.pki.cmpracomponent.msgvalidation.InputValidator;
import com.siemens.pki.cmpracomponent.msgvalidation.MessageContext;
import com.siemens.pki.cmpracomponent.msgvalidation.MessageHeaderValidator;
import com.siemens.pki.cmpracomponent.msgvalidation.ProtectionValidator;
import com.siemens.pki.cmpracomponent.persistency.PersistencyContext;
Expand Down Expand Up @@ -377,6 +379,7 @@ private PKIMessage handleCrmfCertificateRequest(
*/
PKIMessage handleInputMessage(final PKIMessage in) {
PersistencyContext persistencyContext = null;
MessageContext messageContext = null;
int responseBodyType = PKIBody.TYPE_ERROR;
int retryAfterTime = 0;
try {
Expand Down Expand Up @@ -412,9 +415,9 @@ PKIMessage handleInputMessage(final PKIMessage in) {
config::isRaVerifiedAcceptable,
supportedMessageTypes,
persistencyContext);
inputValidator.validate(in);
messageContext = inputValidator.validate(in);

PKIMessage responseFromUpstream = handleValidatedRequest(in, persistencyContext);
PKIMessage responseFromUpstream = handleValidatedRequest(in, messageContext);
// apply downstream protection and nesting
List<CMPCertificate> issuingChain = null;
responseBodyType = responseFromUpstream.getBody().getType();
Expand Down Expand Up @@ -443,7 +446,7 @@ PKIMessage handleInputMessage(final PKIMessage in) {
ifNotNull(persistencyContext, PersistencyContext::getCertProfile),
responseBodyType);
PKIMessage protectedResponse = new MsgOutputProtector(
downstreamConfiguration, INTERFACE_NAME, persistencyContext)
downstreamConfiguration, INTERFACE_NAME, messageContext)
.protectOutgoingMessage(
new PKIMessage(
responseFromUpstream.getHeader(),
Expand All @@ -460,7 +463,8 @@ PKIMessage handleInputMessage(final PKIMessage in) {
// no nesting required
return protectedResponse;
}
return new MsgOutputProtector(nestedEndpointContext, NESTED_INTERFACE_NAME)
return new MsgOutputProtector(
nestedEndpointContext, NESTED_INTERFACE_NAME, messageContext.getCredentialContext())
.createOutgoingMessage(
PkiMessageGenerator.buildForwardingHeaderProvider(protectedResponse),
new PKIBody(PKIBody.TYPE_NESTED, new PKIMessages(protectedResponse)));
Expand All @@ -472,7 +476,7 @@ PKIMessage handleInputMessage(final PKIMessage in) {
config::getDownstreamConfiguration,
ifNotNull(persistencyContext, PersistencyContext::getCertProfile),
errorBody.getType());
return new MsgOutputProtector(downstreamConfiguration, INTERFACE_NAME, persistencyContext)
return new MsgOutputProtector(downstreamConfiguration, INTERFACE_NAME, messageContext)
.generateAndProtectResponseTo(in, errorBody);
} catch (final RuntimeException ex) {
final PKIBody errorBody = new CmpProcessingException(INTERFACE_NAME, ex).asErrorBody();
Expand All @@ -482,7 +486,7 @@ PKIMessage handleInputMessage(final PKIMessage in) {
config::getDownstreamConfiguration,
ifNotNull(persistencyContext, PersistencyContext::getCertProfile),
errorBody.getType());
return new MsgOutputProtector(downstreamConfiguration, INTERFACE_NAME, persistencyContext)
return new MsgOutputProtector(downstreamConfiguration, INTERFACE_NAME, messageContext)
.generateAndProtectResponseTo(in, errorBody);
} finally {
if (persistencyContext != null) {
Expand Down Expand Up @@ -529,7 +533,7 @@ private PKIMessage handleNestedRequest(final PKIMessage in, final PersistencyCon
NESTED_INTERFACE_NAME,
"NestedEndpointContext.getInputVerification()",
nestedEndpointContext::getInputVerification));
nestedProtectionValidator.validate(in);
CredentialContext credentialContext = nestedProtectionValidator.validate(in);
PKIHeader inHeader = in.getHeader();
boolean isIncomingRecipientValid = ConfigLogger.log(
NESTED_INTERFACE_NAME,
Expand All @@ -555,7 +559,8 @@ private PKIMessage handleNestedRequest(final PKIMessage in, final PersistencyCon
final PKIMessage[] responses =
Arrays.stream(embeddedMessages).map(this::handleInputMessage).toArray(PKIMessage[]::new);
// batched responses needs to be wrapped in a new NESTED response
MsgOutputProtector nestedOutputProtector = new MsgOutputProtector(nestedEndpointContext, INTERFACE_NAME);
MsgOutputProtector nestedOutputProtector =
new MsgOutputProtector(nestedEndpointContext, INTERFACE_NAME, credentialContext);
return nestedOutputProtector.generateAndProtectResponseTo(
in, new PKIBody(PKIBody.TYPE_NESTED, new PKIMessages(responses)));
}
Expand Down Expand Up @@ -651,12 +656,12 @@ private PKIMessage handleRevocationRequest(PKIMessage incomingRequest, Persisten
return incomingRequest;
}

private PKIMessage handleValidatedRequest(
final PKIMessage incomingRequest, final PersistencyContext persistencyContext)
private PKIMessage handleValidatedRequest(final PKIMessage incomingRequest, final MessageContext messageContext)
throws BaseCmpException, IOException {
// request pre processing
// by default there is no pre processing
PKIMessage preprocessedRequest = incomingRequest;
final PersistencyContext persistencyContext = messageContext.getPersistencyContext();
switch (incomingRequest.getBody().getType()) {
case PKIBody.TYPE_INIT_REQ:
case PKIBody.TYPE_CERT_REQ:
Expand All @@ -682,8 +687,8 @@ private PKIMessage handleValidatedRequest(
case PKIBody.TYPE_GEN_MSG:
// try to handle locally
persistencyContext.setRequestType(incomingRequest.getBody().getType());
final PKIMessage genmResponse = new ServiceImplementation(config)
.handleValidatedInputMessage(incomingRequest, persistencyContext);
final PKIMessage genmResponse =
new ServiceImplementation(config).handleValidatedInputMessage(incomingRequest, messageContext);
if (genmResponse != null) {
return genmResponse;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import com.siemens.pki.cmpracomponent.msggeneration.MsgOutputProtector;
import com.siemens.pki.cmpracomponent.msgvalidation.BaseCmpException;
import com.siemens.pki.cmpracomponent.msgvalidation.CmpProcessingException;
import com.siemens.pki.cmpracomponent.msgvalidation.MessageContext;
import com.siemens.pki.cmpracomponent.persistency.PersistencyContext;
import com.siemens.pki.cmpracomponent.util.ConfigLogger;
import java.io.IOException;
Expand Down Expand Up @@ -229,7 +230,7 @@ private PKIBody handleGetRootCaCertificateUpdate(
new GenRepContent(new InfoTypeAndValue(CMPObjectIdentifiers.id_it_rootCaKeyUpdate)));
}

protected PKIMessage handleValidatedInputMessage(final PKIMessage msg, final PersistencyContext persistencyContext)
protected PKIMessage handleValidatedInputMessage(final PKIMessage msg, final MessageContext messageContext)
throws BaseCmpException {
try {
final InfoTypeAndValue itav = ((GenMsgContent) msg.getBody().getContent()).toInfoTypeAndValueArray()[0];
Expand All @@ -238,7 +239,8 @@ protected PKIMessage handleValidatedInputMessage(final PKIMessage msg, final Per
final SupportMessageHandlerInterface messageHandler = ConfigLogger.logOptional(
INTERFACE_NAME,
"com.siemens.pki.cmpracomponent.configuration.Configuration.getSupportMessageHandler(String, String)",
() -> config.getSupportMessageHandler(persistencyContext.getCertProfile(), infoType.getId()));
() -> config.getSupportMessageHandler(
messageContext.getPersistencyContext().getCertProfile(), infoType.getId()));
if (messageHandler == null) {
return null;
}
Expand All @@ -264,10 +266,10 @@ protected PKIMessage handleValidatedInputMessage(final PKIMessage msg, final Per
INTERFACE_NAME,
"Configuration.getDownstreamConfiguration",
config::getDownstreamConfiguration,
ifNotNull(persistencyContext, PersistencyContext::getCertProfile),
ifNotNull(messageContext.getPersistencyContext(), PersistencyContext::getCertProfile),
body.getType()),
INTERFACE_NAME,
persistencyContext);
messageContext);
return protector.generateAndProtectResponseTo(msg, body);
} catch (final BaseCmpException ex) {
throw ex;
Expand Down
Loading

0 comments on commit 041ef55

Please sign in to comment.