diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cbca55a..7820dfe5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 + diff --git a/pom.xml b/pom.xml index 1d9b2acf..2480f038 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.siemens.pki CmpRaComponent jar - 4.1.4 + 4.2.0 UTF-8 . diff --git a/src/main/java/com/siemens/pki/cmpclientcomponent/main/ClientRequestHandler.java b/src/main/java/com/siemens/pki/cmpclientcomponent/main/ClientRequestHandler.java index f873ba5f..603f26c2 100644 --- a/src/main/java/com/siemens/pki/cmpclientcomponent/main/ClientRequestHandler.java +++ b/src/main/java/com/siemens/pki/cmpclientcomponent/main/ClientRequestHandler.java @@ -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()", diff --git a/src/main/java/com/siemens/pki/cmpracomponent/msggeneration/MsgOutputProtector.java b/src/main/java/com/siemens/pki/cmpracomponent/msggeneration/MsgOutputProtector.java index 514ba40c..01fd36ba 100644 --- a/src/main/java/com/siemens/pki/cmpracomponent/msggeneration/MsgOutputProtector.java +++ b/src/main/java/com/siemens/pki/cmpracomponent/msggeneration/MsgOutputProtector.java @@ -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; @@ -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; @@ -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()", @@ -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); } /** @@ -105,7 +115,8 @@ 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; @@ -113,10 +124,13 @@ public MsgOutputProtector(final NestedEndpointContext config, final String inter 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); } /** diff --git a/src/main/java/com/siemens/pki/cmpracomponent/msgprocessing/CmpRaUpstream.java b/src/main/java/com/siemens/pki/cmpracomponent/msgprocessing/CmpRaUpstream.java index a1bb81d0..1977f9f0 100644 --- a/src/main/java/com/siemens/pki/cmpracomponent/msgprocessing/CmpRaUpstream.java +++ b/src/main/java/com/siemens/pki/cmpracomponent/msgprocessing/CmpRaUpstream.java @@ -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; @@ -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( @@ -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( diff --git a/src/main/java/com/siemens/pki/cmpracomponent/msgprocessing/RaDownstream.java b/src/main/java/com/siemens/pki/cmpracomponent/msgprocessing/RaDownstream.java index 765dfe21..e33cf454 100644 --- a/src/main/java/com/siemens/pki/cmpracomponent/msgprocessing/RaDownstream.java +++ b/src/main/java/com/siemens/pki/cmpracomponent/msgprocessing/RaDownstream.java @@ -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; @@ -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; @@ -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 { @@ -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 issuingChain = null; responseBodyType = responseFromUpstream.getBody().getType(); @@ -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(), @@ -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))); @@ -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(); @@ -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) { @@ -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, @@ -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))); } @@ -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: @@ -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; } diff --git a/src/main/java/com/siemens/pki/cmpracomponent/msgprocessing/ServiceImplementation.java b/src/main/java/com/siemens/pki/cmpracomponent/msgprocessing/ServiceImplementation.java index d3eae4e8..bb2b7328 100644 --- a/src/main/java/com/siemens/pki/cmpracomponent/msgprocessing/ServiceImplementation.java +++ b/src/main/java/com/siemens/pki/cmpracomponent/msgprocessing/ServiceImplementation.java @@ -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; @@ -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]; @@ -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; } @@ -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; diff --git a/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/InputValidator.java b/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/InputValidator.java index 4fe32afb..305d6d4f 100644 --- a/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/InputValidator.java +++ b/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/InputValidator.java @@ -18,6 +18,7 @@ package com.siemens.pki.cmpracomponent.msgvalidation; import com.siemens.pki.cmpracomponent.configuration.CmpMessageInterface; +import com.siemens.pki.cmpracomponent.configuration.CredentialContext; import com.siemens.pki.cmpracomponent.persistency.PersistencyContext; import com.siemens.pki.cmpracomponent.util.ConfigLogger; import com.siemens.pki.cmpracomponent.util.MessageDumper; @@ -30,7 +31,7 @@ /** * validator for an incoming message */ -public class InputValidator implements ValidatorIF { +public class InputValidator implements ValidatorIF { private final Collection supportedMessageTypes; private final String interfaceName; @@ -68,11 +69,11 @@ public InputValidator( * message types * * @param in message to validate - * @return nothing + * @return a message context * @throws CmpProcessingException if validation failed */ @Override - public Void validate(final PKIMessage in) throws BaseCmpException { + public MessageContext validate(final PKIMessage in) throws BaseCmpException { if (!supportedMessageTypes.contains(in.getBody().getType())) { throw new CmpValidationException( interfaceName, @@ -97,8 +98,8 @@ public Void validate(final PKIMessage in) throws BaseCmpException { interfaceName, "CmpMessageInterface.getInputVerification()", cmpInterface::getInputVerification)); - protectionValidator.validate(in); - return null; + CredentialContext protectionCredentials = protectionValidator.validate(in); + return new MessageContext(persistencyContext, protectionCredentials); } catch (final BaseCmpException ce) { throw ce; } catch (final Exception e) { diff --git a/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/MacValidator.java b/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/MacValidator.java index d321aba8..e5b1bf23 100644 --- a/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/MacValidator.java +++ b/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/MacValidator.java @@ -17,6 +17,7 @@ */ package com.siemens.pki.cmpracomponent.msgvalidation; +import com.siemens.pki.cmpracomponent.configuration.CredentialContext; import com.siemens.pki.cmpracomponent.configuration.VerificationContext; import com.siemens.pki.cmpracomponent.util.ConfigLogger; import com.siemens.pki.cmpracomponent.util.NullUtil; @@ -27,7 +28,7 @@ /** * base class for all MAC based validators */ -public abstract class MacValidator implements ValidatorIF { +public abstract class MacValidator implements ValidatorIF { protected final VerificationContext config; private final String interfaceName; diff --git a/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/MessageContext.java b/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/MessageContext.java new file mode 100644 index 00000000..c0680aba --- /dev/null +++ b/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/MessageContext.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024 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.cmpracomponent.msgvalidation; + +import com.siemens.pki.cmpracomponent.configuration.CredentialContext; +import com.siemens.pki.cmpracomponent.persistency.PersistencyContext; + +/** + * Container class to store @link{PersistencyContext} and @link{CredentialContext} of a PKI message + */ +public class MessageContext { + + final PersistencyContext persistencyContext; + final CredentialContext credentialContext; + + /** + * Class constructor + * @param persistency a persistency context + * @param credentials a credential context + */ + public MessageContext(PersistencyContext persistency, CredentialContext credentials) { + persistencyContext = persistency; + credentialContext = credentials; + } + + /** + * provide a persistency context + * @return a persistency context + */ + public PersistencyContext getPersistencyContext() { + return persistencyContext; + } + + /** + * provide a credential context configuration usable for message protection + * @return a credential context + */ + public CredentialContext getCredentialContext() { + return credentialContext; + } +} diff --git a/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/PBMAC1ProtectionValidator.java b/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/PBMAC1ProtectionValidator.java index 0b451401..0a83ec51 100644 --- a/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/PBMAC1ProtectionValidator.java +++ b/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/PBMAC1ProtectionValidator.java @@ -17,10 +17,12 @@ */ package com.siemens.pki.cmpracomponent.msgvalidation; +import com.siemens.pki.cmpracomponent.configuration.CredentialContext; import com.siemens.pki.cmpracomponent.configuration.VerificationContext; import com.siemens.pki.cmpracomponent.cryptoservices.AlgorithmHelper; import com.siemens.pki.cmpracomponent.cryptoservices.WrappedMac; import com.siemens.pki.cmpracomponent.cryptoservices.WrappedMacFactory; +import com.siemens.pki.cmpracomponent.protection.OutputSharedSecretCredentials; import java.util.Arrays; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; @@ -50,7 +52,7 @@ public PBMAC1ProtectionValidator(final String interfaceName, final VerificationC } @Override - public Void validate(final PKIMessage message) throws BaseCmpException { + public CredentialContext validate(final PKIMessage message) throws BaseCmpException { try { final PKIHeader header = message.getHeader(); final byte[] passwordAsBytes = getSharedSecret(header); @@ -81,12 +83,16 @@ public Void validate(final PKIMessage message) throws BaseCmpException { throw new CmpValidationException( getInterfaceName(), PKIFailureInfo.badMessageCheck, "PBMAC1 protection check failed"); } + return new OutputSharedSecretCredentials( + params, + pbmac1Params.getMessageAuthScheme().getAlgorithm().getId(), + header.getSenderKID().getOctets(), + passwordAsBytes); } catch (final BaseCmpException cex) { throw cex; } catch (final Exception ex) { throw new CmpProcessingException( getInterfaceName(), PKIFailureInfo.badMessageCheck, ex.getLocalizedMessage()); } - return null; } } diff --git a/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/PasswordBasedMacValidator.java b/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/PasswordBasedMacValidator.java index 5e4f6260..e5ebd892 100644 --- a/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/PasswordBasedMacValidator.java +++ b/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/PasswordBasedMacValidator.java @@ -17,8 +17,10 @@ */ package com.siemens.pki.cmpracomponent.msgvalidation; +import com.siemens.pki.cmpracomponent.configuration.CredentialContext; import com.siemens.pki.cmpracomponent.configuration.VerificationContext; import com.siemens.pki.cmpracomponent.cryptoservices.AlgorithmHelper; +import com.siemens.pki.cmpracomponent.protection.OutputSharedSecretCredentials; import java.security.MessageDigest; import java.util.Arrays; import javax.crypto.Mac; @@ -48,7 +50,7 @@ public PasswordBasedMacValidator(final String interfaceName, final VerificationC } @Override - public Void validate(final PKIMessage message) throws BaseCmpException { + public CredentialContext validate(final PKIMessage message) throws BaseCmpException { try { final PKIHeader header = message.getHeader(); // Construct the base key according to rfc4210, section 5.1.3.1 @@ -79,12 +81,13 @@ public Void validate(final PKIMessage message) throws BaseCmpException { throw new CmpValidationException( getInterfaceName(), PKIFailureInfo.badMessageCheck, "PasswordBasedMac protection check failed"); } + return new OutputSharedSecretCredentials( + pbmParameter, header.getSenderKID().getOctets(), passwordAsBytes); } catch (final BaseCmpException cex) { throw cex; } catch (final Exception ex) { throw new CmpProcessingException( getInterfaceName(), PKIFailureInfo.badMessageCheck, ex.getLocalizedMessage()); } - return null; } } diff --git a/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/ProtectionValidator.java b/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/ProtectionValidator.java index 4c92e8b7..351dc728 100644 --- a/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/ProtectionValidator.java +++ b/src/main/java/com/siemens/pki/cmpracomponent/msgvalidation/ProtectionValidator.java @@ -17,6 +17,7 @@ */ package com.siemens.pki.cmpracomponent.msgvalidation; +import com.siemens.pki.cmpracomponent.configuration.CredentialContext; import com.siemens.pki.cmpracomponent.configuration.VerificationContext; import com.siemens.pki.cmpracomponent.util.MessageDumper; import org.bouncycastle.asn1.ASN1BitString; @@ -33,7 +34,7 @@ * This class validates the signature or password based protection of all * incoming messages and generates proper error responses on failed validation. */ -public class ProtectionValidator implements ValidatorIF { +public class ProtectionValidator implements ValidatorIF { private static final Logger LOGGER = LoggerFactory.getLogger(ProtectionValidator.class); @@ -59,11 +60,12 @@ public ProtectionValidator(final String interfaceName, final VerificationContext * validation */ @Override - public Void validate(final PKIMessage message) throws BaseCmpException { + public CredentialContext validate(final PKIMessage message) throws BaseCmpException { if (config == null) { // protection validation is not needed return null; } + final CredentialContext credentialContext; final ASN1BitString protection = message.getProtection(); final AlgorithmIdentifier protectionAlg = message.getHeader().getProtectionAlg(); if (protection == null || protectionAlg == null) { @@ -83,12 +85,13 @@ public Void validate(final PKIMessage message) throws BaseCmpException { } } if (CMPObjectIdentifiers.passwordBasedMac.equals(protectionAlg.getAlgorithm())) { - new PasswordBasedMacValidator(interfaceName, config).validate(message); + credentialContext = new PasswordBasedMacValidator(interfaceName, config).validate(message); } else if (PKCSObjectIdentifiers.id_PBMAC1.equals(protectionAlg.getAlgorithm())) { - new PBMAC1ProtectionValidator(interfaceName, config).validate(message); + credentialContext = new PBMAC1ProtectionValidator(interfaceName, config).validate(message); } else { new SignatureProtectionValidator(interfaceName, config).validate(message); + credentialContext = null; } - return null; + return credentialContext; } } diff --git a/src/main/java/com/siemens/pki/cmpracomponent/protection/OutputSharedSecretCredentials.java b/src/main/java/com/siemens/pki/cmpracomponent/protection/OutputSharedSecretCredentials.java new file mode 100644 index 00000000..5f9ef89f --- /dev/null +++ b/src/main/java/com/siemens/pki/cmpracomponent/protection/OutputSharedSecretCredentials.java @@ -0,0 +1,101 @@ +package com.siemens.pki.cmpracomponent.protection; + +import com.siemens.pki.cmpracomponent.configuration.SharedSecretCredentialContext; +import org.bouncycastle.asn1.cmp.CMPObjectIdentifiers; +import org.bouncycastle.asn1.cmp.PBMParameter; +import org.bouncycastle.asn1.pkcs.PBKDF2Params; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; + +/** + * an instance implementing {@link com.siemens.pki.cmpracomponent.configuration.SharedSecretCredentialContext} + * provides all attributes needed for shared secret based CMP protection of outgoing messages + */ +public class OutputSharedSecretCredentials implements SharedSecretCredentialContext { + + final int iterationCount; + final int keyLength; + final String macAlgorithm; + final String passwordBasedMacAlgorithm; + final String prf; + final byte[] salt; + final byte[] senderKID; + final byte[] sharedSecret; + + /** + * Constructor for password-based MAC protection + * @param pbmParameter PBM parameter + * @param senderKID sender key identifier + * @param sharedSecret shared secret + */ + public OutputSharedSecretCredentials( + final PBMParameter pbmParameter, final byte[] senderKID, final byte[] sharedSecret) { + this.iterationCount = pbmParameter.getIterationCount().getValue().intValue(); + this.macAlgorithm = pbmParameter.getMac().getAlgorithm().getId(); + this.passwordBasedMacAlgorithm = CMPObjectIdentifiers.passwordBasedMac.getId(); + this.prf = pbmParameter.getOwf().getAlgorithm().getId(); + this.salt = pbmParameter.getSalt().getOctets(); + this.senderKID = senderKID; + this.sharedSecret = sharedSecret; + + this.keyLength = 0; + } + + /** + * Constructor for PMAC1 protection + * @param pbkdf2Params parameters for PBKDF2 key derivation function + * @param macAlgorithm MAC algorithm + * @param senderKID sender key identifer + * @param sharedSecret shared secret + */ + public OutputSharedSecretCredentials( + PBKDF2Params pbkdf2Params, String macAlgorithm, byte[] senderKID, byte[] sharedSecret) { + this.iterationCount = pbkdf2Params.getIterationCount().intValue(); + this.macAlgorithm = macAlgorithm; + this.keyLength = pbkdf2Params.getKeyLength().intValue(); + this.passwordBasedMacAlgorithm = PKCSObjectIdentifiers.id_PBMAC1.getId(); + this.prf = pbkdf2Params.getPrf().getAlgorithm().getId(); + this.salt = pbkdf2Params.getSalt(); + this.senderKID = senderKID; + this.sharedSecret = sharedSecret; + } + + @Override + public int getIterationCount() { + return iterationCount; + } + + @Override + public int getkeyLength() { + return keyLength; + } + + @Override + public String getMacAlgorithm() { + return macAlgorithm; + } + + @Override + public String getPasswordBasedMacAlgorithm() { + return passwordBasedMacAlgorithm; + } + + @Override + public String getPrf() { + return prf; + } + + @Override + public byte[] getSalt() { + return salt; + } + + @Override + public byte[] getSenderKID() { + return senderKID; + } + + @Override + public byte[] getSharedSecret() { + return sharedSecret; + } +} diff --git a/src/test/java/com/siemens/pki/cmpracomponent/test/MacProtectionTestcaseBase.java b/src/test/java/com/siemens/pki/cmpracomponent/test/MacProtectionTestcaseBase.java new file mode 100644 index 00000000..83b6bdee --- /dev/null +++ b/src/test/java/com/siemens/pki/cmpracomponent/test/MacProtectionTestcaseBase.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2024 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.cmpracomponent.test; + +import static org.junit.Assert.assertEquals; + +import com.siemens.pki.cmpracomponent.configuration.Configuration; +import com.siemens.pki.cmpracomponent.msggeneration.PkiMessageGenerator; +import com.siemens.pki.cmpracomponent.protection.MacProtection; +import com.siemens.pki.cmpracomponent.protection.ProtectionProvider; +import com.siemens.pki.cmpracomponent.test.framework.ConfigurationFactory; +import com.siemens.pki.cmpracomponent.test.framework.EnrollmentResult; +import com.siemens.pki.cmpracomponent.test.framework.HeaderProviderForTest; +import com.siemens.pki.cmpracomponent.util.MessageDumper; +import java.security.KeyPair; +import java.util.function.Function; +import org.bouncycastle.asn1.cmp.CMPCertificate; +import org.bouncycastle.asn1.cmp.CertRepMessage; +import org.bouncycastle.asn1.cmp.PKIBody; +import org.bouncycastle.asn1.cmp.PKIMessage; +import org.bouncycastle.asn1.crmf.CertTemplateBuilder; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.junit.Before; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MacProtectionTestcaseBase extends OnlineEnrollmentTestcaseBase { + + private static final Logger LOGGER = LoggerFactory.getLogger(MacProtectionTestcaseBase.class); + + @Before + public void setUp() throws Exception { + ConfigurationFactory.resetConfiguration(); + Configuration config = ConfigurationFactory.buildMixedDownstreamConfiguration(); + launchCmpCaAndRa(config); + } + + public static EnrollmentResult executeCrmfCertificateRequest( + final int requestMessageType, + final int expectedResponseMessageType, + final ProtectionProvider protectionProvider, + final String expectedResponseProtection, + final Function cmpClient) + throws Exception { + final KeyPair keyPair = ConfigurationFactory.getKeyGenerator().generateKeyPair(); + final CertTemplateBuilder ctb = new CertTemplateBuilder() + .setPublicKey( + SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded())) + .setSubject(new X500Name("CN=Subject")); + + final PKIBody crBody = + PkiMessageGenerator.generateIrCrKurBody(requestMessageType, ctb.build(), null, keyPair.getPrivate()); + + final PKIMessage cr = PkiMessageGenerator.generateAndProtectMessage( + new HeaderProviderForTest("theCertProfileForOnlineEnrollment"), protectionProvider, crBody); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("send:\n" + MessageDumper.dumpPkiMessage(cr)); + } + final PKIMessage crResponse = cmpClient.apply(cr); + + if (LOGGER.isDebugEnabled()) { + // avoid unnecessary string processing, if debug isn't enabled + LOGGER.debug("got:\n" + MessageDumper.dumpPkiMessage(crResponse)); + } + assertEquals( + "message type", + expectedResponseMessageType, + crResponse.getBody().getType()); + + if (protectionProvider instanceof MacProtection) { + assertEquals( + "protection type", + expectedResponseProtection, + crResponse.getHeader().getProtectionAlg().getAlgorithm().getId()); + } + + if (expectedResponseMessageType == PKIBody.TYPE_ERROR) { + return new EnrollmentResult(null, null); + } else { + final CMPCertificate enrolledCertificate = ((CertRepMessage) + crResponse.getBody().getContent()) + .getResponse()[0] + .getCertifiedKeyPair() + .getCertOrEncCert() + .getCertificate(); + + final PKIMessage certConf = PkiMessageGenerator.generateAndProtectMessage( + new HeaderProviderForTest(crResponse.getHeader()), + protectionProvider, + PkiMessageGenerator.generateCertConfBody(enrolledCertificate)); + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("send:\n" + MessageDumper.dumpPkiMessage(certConf)); + } + final PKIMessage pkiConf = cmpClient.apply(certConf); + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("got:\n" + MessageDumper.dumpPkiMessage(pkiConf)); + } + assertEquals("message type", PKIBody.TYPE_CONFIRM, pkiConf.getBody().getType()); + + return new EnrollmentResult(enrolledCertificate, keyPair.getPrivate()); + } + } +} diff --git a/src/test/java/com/siemens/pki/cmpracomponent/test/OnlineEnrollmentTestcaseBase.java b/src/test/java/com/siemens/pki/cmpracomponent/test/OnlineEnrollmentTestcaseBase.java index 74c02552..98fdd967 100644 --- a/src/test/java/com/siemens/pki/cmpracomponent/test/OnlineEnrollmentTestcaseBase.java +++ b/src/test/java/com/siemens/pki/cmpracomponent/test/OnlineEnrollmentTestcaseBase.java @@ -21,6 +21,7 @@ import com.siemens.pki.cmpracomponent.cryptoservices.AlgorithmHelper; import com.siemens.pki.cmpracomponent.msggeneration.PkiMessageGenerator; +import com.siemens.pki.cmpracomponent.protection.MacProtection; import com.siemens.pki.cmpracomponent.protection.ProtectionProvider; import com.siemens.pki.cmpracomponent.test.framework.ConfigurationFactory; import com.siemens.pki.cmpracomponent.test.framework.EnrollmentResult; @@ -78,6 +79,13 @@ public static EnrollmentResult executeCrmfCertificateRequest( expectedResponseMessageType, crResponse.getBody().getType()); + if (protectionProvider instanceof MacProtection) { + assertEquals( + "protection type", + cr.getHeader().getProtectionAlg().getAlgorithm().getId(), + crResponse.getHeader().getProtectionAlg().getAlgorithm().getId()); + } + final CMPCertificate enrolledCertificate = ((CertRepMessage) crResponse.getBody().getContent()) .getResponse()[0] diff --git a/src/test/java/com/siemens/pki/cmpracomponent/test/PasswordEnrollmentTestcasebase.java b/src/test/java/com/siemens/pki/cmpracomponent/test/PasswordEnrollmentTestcasebase.java index eead61a5..e1254106 100644 --- a/src/test/java/com/siemens/pki/cmpracomponent/test/PasswordEnrollmentTestcasebase.java +++ b/src/test/java/com/siemens/pki/cmpracomponent/test/PasswordEnrollmentTestcasebase.java @@ -25,6 +25,7 @@ public class PasswordEnrollmentTestcasebase extends OnlineEnrollmentTestcaseBase @Before public void setUp() throws Exception { + ConfigurationFactory.resetConfiguration(); final Configuration config = ConfigurationFactory.buildPasswordbasedDownstreamConfiguration(); launchCmpCaAndRa(config); } diff --git a/src/test/java/com/siemens/pki/cmpracomponent/test/Pbmac1EnrollmentTestcasebase.java b/src/test/java/com/siemens/pki/cmpracomponent/test/Pbmac1EnrollmentTestcasebase.java new file mode 100644 index 00000000..f07a3647 --- /dev/null +++ b/src/test/java/com/siemens/pki/cmpracomponent/test/Pbmac1EnrollmentTestcasebase.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 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.cmpracomponent.test; + +import com.siemens.pki.cmpracomponent.configuration.Configuration; +import com.siemens.pki.cmpracomponent.test.framework.ConfigurationFactory; +import org.junit.Before; + +public class Pbmac1EnrollmentTestcasebase extends OnlineEnrollmentTestcaseBase { + + @Before + public void setUp() throws Exception { + final Configuration config = ConfigurationFactory.buildPbmac1DownstreamConfiguration(); + launchCmpCaAndRa(config); + } +} diff --git a/src/test/java/com/siemens/pki/cmpracomponent/test/TestMacProtectedIp.java b/src/test/java/com/siemens/pki/cmpracomponent/test/TestMacProtectedIp.java new file mode 100644 index 00000000..96b4048f --- /dev/null +++ b/src/test/java/com/siemens/pki/cmpracomponent/test/TestMacProtectedIp.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 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.cmpracomponent.test; + +import com.siemens.pki.cmpracomponent.test.framework.ConfigurationFactory; +import org.bouncycastle.asn1.cmp.PKIBody; +import org.junit.Test; + +public class TestMacProtectedIp extends MacProtectionTestcaseBase { + + @Test + public void testFailedProtectionIp() throws Exception { + executeCrmfCertificateRequest( + PKIBody.TYPE_INIT_REQ, + PKIBody.TYPE_ERROR, + ConfigurationFactory.getEeWrongPasswordbasedProtectionProvider(), + "1.2.840.10045.4.3.2", // signature based protection + getEeClient()); + } + + @Test + public void testPasswordbasedIp() throws Exception { + executeCrmfCertificateRequest( + PKIBody.TYPE_INIT_REQ, + PKIBody.TYPE_INIT_REP, + ConfigurationFactory.getEePasswordbasedProtectionProvider(), + "1.2.840.113533.7.66.13", + getEeClient()); + } + + /** + * Enrolling an End Entity to a New PKI/Using MAC-Based Protection for + * Enrollment + * + * @throws Exception in case of error + */ + @Test + public void testPbmac1Ip() throws Exception { + executeCrmfCertificateRequest( + PKIBody.TYPE_INIT_REQ, + PKIBody.TYPE_INIT_REP, + ConfigurationFactory.getEePbmac1ProtectionProvider(), + "1.2.840.113549.1.5.14", + getEeClient()); + } +} diff --git a/src/test/java/com/siemens/pki/cmpracomponent/test/TestPasswordbasedIr.java b/src/test/java/com/siemens/pki/cmpracomponent/test/TestPasswordbasedIr.java index b05e81d5..4b7f59a9 100644 --- a/src/test/java/com/siemens/pki/cmpracomponent/test/TestPasswordbasedIr.java +++ b/src/test/java/com/siemens/pki/cmpracomponent/test/TestPasswordbasedIr.java @@ -31,19 +31,4 @@ public void testPasswordbasedIr() throws Exception { ConfigurationFactory.getEePasswordbasedProtectionProvider(), getEeClient()); } - - /** - * Enrolling an End Entity to a New PKI/Using MAC-Based Protection for - * Enrollment - * - * @throws Exception in case of error - */ - @Test - public void testPbmac1Ir() throws Exception { - executeCrmfCertificateRequest( - PKIBody.TYPE_INIT_REQ, - PKIBody.TYPE_INIT_REP, - ConfigurationFactory.getEePbmac1ProtectionProvider(), - getEeClient()); - } } diff --git a/src/test/java/com/siemens/pki/cmpracomponent/test/TestPbmac1Ir.java b/src/test/java/com/siemens/pki/cmpracomponent/test/TestPbmac1Ir.java new file mode 100644 index 00000000..7ad248f0 --- /dev/null +++ b/src/test/java/com/siemens/pki/cmpracomponent/test/TestPbmac1Ir.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 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.cmpracomponent.test; + +import com.siemens.pki.cmpracomponent.test.framework.ConfigurationFactory; +import org.bouncycastle.asn1.cmp.PKIBody; +import org.junit.Test; + +public class TestPbmac1Ir extends PasswordEnrollmentTestcasebase { + + /** + * Enrolling an End Entity to a New PKI/Using MAC-Based Protection for + * Enrollment + * + * @throws Exception in case of error + */ + @Test + public void testPbmac1Ir() throws Exception { + executeCrmfCertificateRequest( + PKIBody.TYPE_INIT_REQ, + PKIBody.TYPE_INIT_REP, + ConfigurationFactory.getEePbmac1ProtectionProvider(), + getEeClient()); + } +} diff --git a/src/test/java/com/siemens/pki/cmpracomponent/test/framework/ConfigurationFactory.java b/src/test/java/com/siemens/pki/cmpracomponent/test/framework/ConfigurationFactory.java index 2b476cc9..469680e6 100644 --- a/src/test/java/com/siemens/pki/cmpracomponent/test/framework/ConfigurationFactory.java +++ b/src/test/java/com/siemens/pki/cmpracomponent/test/framework/ConfigurationFactory.java @@ -82,6 +82,26 @@ public class ConfigurationFactory { private static SharedSecret eeSharedSecretCredentials; public static Configuration buildPasswordbasedDownstreamConfiguration() throws Exception { + final CredentialContext downstreamCredentials = new SharedSecret("PASSWORDBASEDMAC", TestUtils.PASSWORD); + final VerificationContext downstreamTrust = new PasswordValidationCredentials(TestUtils.PASSWORD); + + final CredentialContext upstreamCredentials = + new TrustChainAndPrivateKey("credentials/CMP_LRA_UPSTREAM_Keystore.p12", "Password".toCharArray()); + final VerificationContext upstreamTrust = + new SignatureValidationCredentials("credentials/CMP_CA_Root.pem", null); + final SignatureValidationCredentials enrollmentTrust = + new SignatureValidationCredentials("credentials/ENROLL_Root.pem", null); + + return buildSimpleRaConfiguration( + downstreamCredentials, + ReprotectMode.reprotect, + downstreamTrust, + upstreamCredentials, + upstreamTrust, + enrollmentTrust); + } + + public static Configuration buildPbmac1DownstreamConfiguration() throws Exception { final CredentialContext downstreamCredentials = new SharedSecret("PBMAC1", TestUtils.PASSWORD); final VerificationContext downstreamTrust = new PasswordValidationCredentials(TestUtils.PASSWORD); @@ -101,6 +121,27 @@ public static Configuration buildPasswordbasedDownstreamConfiguration() throws E enrollmentTrust); } + public static Configuration buildMixedDownstreamConfiguration() throws Exception { + final TrustChainAndPrivateKey downstreamCredentials = + new TrustChainAndPrivateKey("credentials/CMP_LRA_DOWNSTREAM_Keystore.p12", "Password".toCharArray()); + final VerificationContext downstreamTrust = new PasswordValidationCredentials(TestUtils.PASSWORD); + + final CredentialContext upstreamCredentials = + new TrustChainAndPrivateKey("credentials/CMP_LRA_UPSTREAM_Keystore.p12", "Password".toCharArray()); + final VerificationContext upstreamTrust = + new SignatureValidationCredentials("credentials/CMP_CA_Root.pem", null); + final SignatureValidationCredentials enrollmentTrust = + new SignatureValidationCredentials("credentials/ENROLL_Root.pem", null); + + return buildSimpleRaConfiguration( + downstreamCredentials, + ReprotectMode.reprotect, + downstreamTrust, + upstreamCredentials, + upstreamTrust, + enrollmentTrust); + } + public static Configuration buildSignatureBasedDownstreamConfiguration() throws Exception { final TrustChainAndPrivateKey downstreamCredentials = new TrustChainAndPrivateKey("credentials/CMP_LRA_DOWNSTREAM_Keystore.p12", "Password".toCharArray()); @@ -746,6 +787,15 @@ public static ProtectionProvider getEePasswordbasedProtectionProvider() return eePasswordbasedProtectionProvider; } + public static ProtectionProvider getEeWrongPasswordbasedProtectionProvider() + throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException { + if (eePasswordbasedProtectionProvider == null) { + eePasswordbasedProtectionProvider = ProtectionProviderFactory.createProtectionProvider( + getEeWrongSharedSecretCredentials(), INTERFACE_NAME); + } + return eePasswordbasedProtectionProvider; + } + public static ProtectionProvider getEePbmac1ProtectionProvider() throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException { if (eePbmac1ProtectionProvider == null) { @@ -762,6 +812,13 @@ private static SharedSecret getEeSharedSecretCredentials() { return eeSharedSecretCredentials; } + private static SharedSecret getEeWrongSharedSecretCredentials() { + if (eeSharedSecretCredentials == null) { + eeSharedSecretCredentials = new SharedSecret("PASSWORDBASEDMAC", TestUtils.WRONG_PASSWORD); + } + return eeSharedSecretCredentials; + } + public static TrustChainAndPrivateKey getEeSignaturebasedCredentials() throws Exception { if (eeSignaturebasedCredentials == null) { eeSignaturebasedCredentials = new TrustChainAndPrivateKey( @@ -796,5 +853,14 @@ public static KeyPairGenerator getKeyGenerator() { return keyGenerator; } + public static void resetConfiguration() { + eeSignaturebasedProtectionProvider = null; + eePbmac1ProtectionProvider = null; + keyGenerator = null; + eePasswordbasedProtectionProvider = null; + eeSignaturebasedCredentials = null; + eeSharedSecretCredentials = null; + } + private ConfigurationFactory() {} } diff --git a/src/test/java/com/siemens/pki/cmpracomponent/test/framework/TestUtils.java b/src/test/java/com/siemens/pki/cmpracomponent/test/framework/TestUtils.java index 69e57667..6d62e72a 100644 --- a/src/test/java/com/siemens/pki/cmpracomponent/test/framework/TestUtils.java +++ b/src/test/java/com/siemens/pki/cmpracomponent/test/framework/TestUtils.java @@ -26,6 +26,9 @@ public class TestUtils { public static final String PASSWORD = "Password"; public static final char[] PASSWORD_AS_CHAR_ARRAY = PASSWORD.toCharArray(); + + public static final String WRONG_PASSWORD = "WrongPassword"; + public static final char[] WRONG_PASSWORD_AS_CHAR_ARRAY = WRONG_PASSWORD.toCharArray(); static final SecureRandom RANDOM = new SecureRandom(); // utility class, never create an instance