Skip to content

Commit

Permalink
again fix protection of NESTED responses
Browse files Browse the repository at this point in the history
  • Loading branch information
Akretsch committed Jul 17, 2024
1 parent b9d51f3 commit bec1e1d
Show file tree
Hide file tree
Showing 11 changed files with 517 additions and 125 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,6 @@ feat: add logging while accessing configuration data

fix: handling of NestedEndpointContext.isIncomingRecipientValid

### 4.1.4 (Jul 10 2024)

fix: again fix protection of NESTED responses
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.3</version>
<version>4.1.4</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 @@ -177,19 +177,6 @@ protected CmsEncryptorBase buildEncryptor(
return new KeyTransportEncryptor(ckgConfiguration, recipientCert, initialRequestType, interfaceName);
}

private MsgOutputProtector getOutputProtector(final PersistencyContext persistencyContext, final int bodyType)
throws Exception {
return new MsgOutputProtector(
ConfigLogger.log(
INTERFACE_NAME,
"Configuration.getDownstreamConfiguration",
config::getDownstreamConfiguration,
persistencyContext.getCertProfile(),
bodyType),
INTERFACE_NAME,
persistencyContext);
}

/**
* special handling for CR, IR, KUR
*
Expand Down Expand Up @@ -395,7 +382,7 @@ PKIMessage handleInputMessage(final PKIMessage in) {
try {
try {
byte[] transactionId =
ifNotNull(in, m -> m.getHeader().getTransactionID().getEncoded());
ifNotNull(in, m -> m.getHeader().getTransactionID().getOctets());
if (transactionId == null) {
MsgOutputProtector protector = new MsgOutputProtector(
ConfigLogger.log(
Expand All @@ -411,14 +398,31 @@ PKIMessage handleInputMessage(final PKIMessage in) {
PkiMessageGenerator.generateErrorBody(
PKIFailureInfo.badDataFormat, "transactionId missing"));
}
persistencyContext = persistencyContextManager.loadCreatePersistencyContext(
in.getHeader().getTransactionID().getOctets());
persistencyContext = persistencyContextManager.loadCreatePersistencyContext(transactionId);
final int inBodyType = in.getBody().getType();
if (inBodyType == PKIBody.TYPE_NESTED) {
PersistencyContext nestedPersistencyContext = persistencyContext;
// suppress persistency update for NESTED messages
persistencyContext = null;
return handleNestedRequest(in, nestedPersistencyContext);
}
final InputValidator inputValidator = new InputValidator(
INTERFACE_NAME,
config::getDownstreamConfiguration,
config::isRaVerifiedAcceptable,
supportedMessageTypes,
persistencyContext);
inputValidator.validate(in);

PKIMessage responseFromUpstream = handleInputRequest(in, persistencyContext);
PKIMessage responseFromUpstream = handleValidatedRequest(in, persistencyContext);
// apply downstream protection and nesting
List<CMPCertificate> issuingChain = null;
responseBodyType = responseFromUpstream.getBody().getType();
switch (responseBodyType) {
case PKIBody.TYPE_NESTED:
// never nest a nested message
persistencyContext = null;
return responseFromUpstream;
case PKIBody.TYPE_INIT_REP:
case PKIBody.TYPE_CERT_REP:
case PKIBody.TYPE_KEY_UPDATE_REP:
Expand All @@ -432,25 +436,22 @@ PKIMessage handleInputMessage(final PKIMessage in) {
break;
default:
}

PKIMessage protectedResponse = getOutputProtector(persistencyContext, responseBodyType)
final CmpMessageInterface downstreamConfiguration = ConfigLogger.log(
INTERFACE_NAME,
"Configuration.getDownstreamConfiguration",
config::getDownstreamConfiguration,
ifNotNull(persistencyContext, PersistencyContext::getCertProfile),
responseBodyType);
PKIMessage protectedResponse = new MsgOutputProtector(
downstreamConfiguration, INTERFACE_NAME, persistencyContext)
.protectOutgoingMessage(
new PKIMessage(
responseFromUpstream.getHeader(),
responseFromUpstream.getBody(),
responseFromUpstream.getProtection(),
responseFromUpstream.getExtraCerts()),
issuingChain);
if (responseBodyType == PKIBody.TYPE_NESTED) {
// never nest a nested message
return protectedResponse;
}
final CmpMessageInterface downstreamConfiguration = ConfigLogger.log(
INTERFACE_NAME,
"Configuration.getDownstreamConfiguration",
config::getDownstreamConfiguration,
null,
responseBodyType);

final NestedEndpointContext nestedEndpointContext = ConfigLogger.logOptional(
INTERFACE_NAME,
"CmpMessageInterface.getNestedEndpointContext()",
Expand All @@ -465,19 +466,31 @@ PKIMessage handleInputMessage(final PKIMessage in) {
new PKIBody(PKIBody.TYPE_NESTED, new PKIMessages(protectedResponse)));
} catch (final BaseCmpException e) {
final PKIBody errorBody = e.asErrorBody();
return getOutputProtector(persistencyContext, responseBodyType)
final CmpMessageInterface downstreamConfiguration = ConfigLogger.log(
INTERFACE_NAME,
"Configuration.getDownstreamConfiguration",
config::getDownstreamConfiguration,
ifNotNull(persistencyContext, PersistencyContext::getCertProfile),
errorBody.getType());
return new MsgOutputProtector(downstreamConfiguration, INTERFACE_NAME, persistencyContext)
.generateAndProtectResponseTo(in, errorBody);
} catch (final RuntimeException ex) {
final PKIBody errorBody = new CmpProcessingException(INTERFACE_NAME, ex).asErrorBody();
return getOutputProtector(persistencyContext, responseBodyType)
final CmpMessageInterface downstreamConfiguration = ConfigLogger.log(
INTERFACE_NAME,
"Configuration.getDownstreamConfiguration",
config::getDownstreamConfiguration,
ifNotNull(persistencyContext, PersistencyContext::getCertProfile),
errorBody.getType());
return new MsgOutputProtector(downstreamConfiguration, INTERFACE_NAME, persistencyContext)
.generateAndProtectResponseTo(in, errorBody);
} finally {
if (persistencyContext != null) {
int offset = ConfigLogger.log(
INTERFACE_NAME,
"Configuration.getDownstreamTimeout",
config::getDownstreamTimeout,
ifNotNull(persistencyContext, PersistencyContext::getCertProfile),
persistencyContext.getCertProfile(),
responseBodyType);
if (offset == 0) {
offset = Integer.MAX_VALUE / 2;
Expand All @@ -493,71 +506,59 @@ PKIMessage handleInputMessage(final PKIMessage in) {
}
}

private PKIMessage handleInputRequest(final PKIMessage in, final PersistencyContext persistencyContext)
throws Exception {

final int inBodyType = in.getBody().getType();
if (inBodyType == PKIBody.TYPE_NESTED) {
final CmpMessageInterface downstreamConfiguration = ConfigLogger.log(
INTERFACE_NAME,
"Configuration.getDownstreamConfiguration",
config::getDownstreamConfiguration,
null,
PKIBody.TYPE_NESTED);
final NestedEndpointContext nestedEndpointContext = ConfigLogger.logOptional(
INTERFACE_NAME,
"CmpMessageInterface.getNestedEndpointContext()",
downstreamConfiguration::getNestedEndpointContext);
if (nestedEndpointContext != null) {
final MessageHeaderValidator nestedHeaderValidator = new MessageHeaderValidator(NESTED_INTERFACE_NAME);
nestedHeaderValidator.validate(in);
final ProtectionValidator nestedProtectionValidator = new ProtectionValidator(
NESTED_INTERFACE_NAME,
ConfigLogger.logOptional(
NESTED_INTERFACE_NAME,
"NestedEndpointContext.getInputVerification()",
nestedEndpointContext::getInputVerification));
nestedProtectionValidator.validate(in);
PKIHeader inHeader = in.getHeader();
boolean isIncomingRecipientValid = ConfigLogger.log(
NESTED_INTERFACE_NAME,
"NestedEndpointContext.isIncomingRecipientValid()",
() -> nestedEndpointContext.isIncomingRecipientValid(
inHeader.getRecipient().getName().toString()));
if (!isIncomingRecipientValid) {
return upstreamHandler.handleRequest(in, persistencyContext);
}
final PKIMessage[] embeddedMessages =
PKIMessages.getInstance(in.getBody().getContent()).toPKIMessageArray();
if (embeddedMessages == null || embeddedMessages.length == 0) {
throw new CmpProcessingException(
private PKIMessage handleNestedRequest(final PKIMessage in, final PersistencyContext persistencyContext)
throws BaseCmpException, CmpProcessingException, GeneralSecurityException, Exception {
final CmpMessageInterface downstreamConfiguration = ConfigLogger.log(
INTERFACE_NAME,
"Configuration.getDownstreamConfiguration",
config::getDownstreamConfiguration,
null,
PKIBody.TYPE_NESTED);
final NestedEndpointContext nestedEndpointContext = ConfigLogger.logOptional(
INTERFACE_NAME,
"CmpMessageInterface.getNestedEndpointContext()",
downstreamConfiguration::getNestedEndpointContext);
if (nestedEndpointContext != null) {
final MessageHeaderValidator nestedHeaderValidator = new MessageHeaderValidator(NESTED_INTERFACE_NAME);
nestedHeaderValidator.validate(in);
final ProtectionValidator nestedProtectionValidator = new ProtectionValidator(
NESTED_INTERFACE_NAME,
ConfigLogger.logOptional(
NESTED_INTERFACE_NAME,
PKIFailureInfo.badMessageCheck,
"no embedded messages inside NESTED message");
}
// wrapped protection case
if (embeddedMessages.length == 1) {
return handleInputMessage(embeddedMessages[0]);
}
// batching
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);
return nestedOutputProtector.generateAndProtectResponseTo(
in, new PKIBody(PKIBody.TYPE_NESTED, new PKIMessages(responses)));
"NestedEndpointContext.getInputVerification()",
nestedEndpointContext::getInputVerification));
nestedProtectionValidator.validate(in);
PKIHeader inHeader = in.getHeader();
boolean isIncomingRecipientValid = ConfigLogger.log(
NESTED_INTERFACE_NAME,
"NestedEndpointContext.isIncomingRecipientValid()",
() -> nestedEndpointContext.isIncomingRecipientValid(
inHeader.getRecipient().getName().toString()));
if (!isIncomingRecipientValid) {
return upstreamHandler.handleRequest(in, persistencyContext);
}
final PKIMessage[] embeddedMessages =
PKIMessages.getInstance(in.getBody().getContent()).toPKIMessageArray();
if (embeddedMessages == null || embeddedMessages.length == 0) {
throw new CmpProcessingException(
NESTED_INTERFACE_NAME,
PKIFailureInfo.badMessageCheck,
"no embedded messages inside NESTED message");
}
// wrapped protection case
if (embeddedMessages.length == 1) {
return handleInputMessage(embeddedMessages[0]);
}
// batching
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);
return nestedOutputProtector.generateAndProtectResponseTo(
in, new PKIBody(PKIBody.TYPE_NESTED, new PKIMessages(responses)));
}
final InputValidator inputValidator = new InputValidator(
INTERFACE_NAME,
config::getDownstreamConfiguration,
config::isRaVerifiedAcceptable,
supportedMessageTypes,
persistencyContext);
inputValidator.validate(in);
return handleValidatedRequest(in, persistencyContext);
return upstreamHandler.handleRequest(in, persistencyContext);
}

private PKIMessage handleP10CertificateRequest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,15 +189,17 @@ private void assertValueNotNull(final Object value, final int failInfo, final St
@Override
public String validate(final PKIMessage message) throws BaseCmpException {
try {
final ASN1GeneralizedTime messageTime = message.getHeader().getMessageTime();
if (messageTime != null) {
final long diffInMillis = messageTime.getDate().getTime() - new Date().getTime();
if (!ConfigLogger.log(
interfaceName,
"CmpMessageInterface.isMessageTimeDeviationAllowed(long)",
() -> cmpInterfaceConfig.isMessageTimeDeviationAllowed(diffInMillis / 1000L))) {
throw new CmpValidationException(
interfaceName, PKIFailureInfo.badTime, "message time out of allowed range");
if (cmpInterfaceConfig != null) {
final ASN1GeneralizedTime messageTime = message.getHeader().getMessageTime();
if (messageTime != null) {
final long diffInMillis = messageTime.getDate().getTime() - new Date().getTime();
if (!ConfigLogger.log(
interfaceName,
"CmpMessageInterface.isMessageTimeDeviationAllowed(long)",
() -> cmpInterfaceConfig.isMessageTimeDeviationAllowed(diffInMillis / 1000L))) {
throw new CmpValidationException(
interfaceName, PKIFailureInfo.badTime, "message time out of allowed range");
}
}
}

Expand Down Expand Up @@ -301,6 +303,7 @@ private void validateCrmfCertReq(
final CertRequest certReq = certReqMsg.getCertReq();
assertEnrollmentEqual(enrollmentType, certReq.getCertReqId(), ASN1INTEGER_0, CERT_REQ_ID_MUST_BE_0);
final CertTemplate certTemplate = certReq.getCertTemplate();
assertEnrollmentValueNotNull(enrollmentType, certTemplate, PKIFailureInfo.badCertTemplate, "cert template");
final int versionInTemplate = certTemplate.getVersion();
if (versionInTemplate != -1 && versionInTemplate != 2) {
throw new CmpEnrollmentException(
Expand Down
Loading

0 comments on commit bec1e1d

Please sign in to comment.