From b9ccb62d35a755efb505d426ce924d5a8fbe937a Mon Sep 17 00:00:00 2001 From: "Bonato, Martin" Date: Thu, 8 Feb 2018 22:19:55 +0100 Subject: BulkSignature implementation --- .../at/gv/egiz/bku/slcommands/BulkCommand.java | 27 ++ .../egiz/bku/slcommands/BulkSignatureResult.java | 31 ++ .../bku/slcommands/impl/BulkCommandFactory.java | 40 ++ .../egiz/bku/slcommands/impl/BulkCommandImpl.java | 439 +++++++++++++++++++++ .../slcommands/impl/BulkSignatureResultImpl.java | 138 +++++++ .../impl/CreateCMSSignatureCommandImpl.java | 5 +- .../slcommands/impl/DataObjectHashDataInput.java | 4 + .../impl/cms/BulkCollectionSecurityProvider.java | 114 ++++++ .../bku/slcommands/impl/cms/BulkSignature.java | 116 ++++++ .../bku/slcommands/impl/cms/BulkSignatureInfo.java | 104 +++++ .../bku/slcommands/impl/cms/CMSHashDataInput.java | 49 ++- .../impl/cms/ReferencedHashDataInput.java | 81 ++++ .../slcommands/impl/cms/STALSecurityProvider.java | 37 +- .../gv/egiz/bku/slcommands/impl/cms/Signature.java | 187 +++++---- .../impl/xsect/AlgorithmMethodFactory.java | 6 + .../impl/xsect/AlgorithmMethodFactoryImpl.java | 35 +- .../bku/spring/URLDereferencerFactoryBean.java | 75 ++++ .../slexceptions/SLExceptionMessages.properties | 3 + .../slexceptions/SLExceptionMessages_en.properties | 2 + bkucommon/src/site/apt/configuration.apt | 4 + .../bku/slcommands/impl/BulkCommandImplTest.java | 130 ++++++ .../impl/CreateCMSSignatureCommandImplTest.java | 33 +- .../bku/slcommands/impl/cms/SignatureTest.java | 130 ++++++ .../bku/slcommands/impl/xsect/SignatureTest.java | 12 +- .../test/java/at/gv/egiz/stal/dummy/DummySTAL.java | 65 ++- .../bulksignaturerequest/BulkSignatureRequest.xml | 34 ++ .../BulkSignatureRequestWithReference.xml | 37 ++ .../egiz/bku/slcommands/testApplicationContext.xml | 9 + 28 files changed, 1826 insertions(+), 121 deletions(-) create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkCommand.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkSignatureResult.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandFactory.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandImpl.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkSignatureResultImpl.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkCollectionSecurityProvider.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignature.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignatureInfo.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/ReferencedHashDataInput.java create mode 100644 bkucommon/src/main/java/at/gv/egiz/bku/spring/URLDereferencerFactoryBean.java create mode 100644 bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/BulkCommandImplTest.java create mode 100644 bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/cms/SignatureTest.java create mode 100644 bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/bulksignaturerequest/BulkSignatureRequest.xml create mode 100644 bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/bulksignaturerequest/BulkSignatureRequestWithReference.xml (limited to 'bkucommon/src') diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkCommand.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkCommand.java new file mode 100644 index 00000000..7deb8e22 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkCommand.java @@ -0,0 +1,27 @@ +/* + * Copyright 2015 Datentechnik Innovation and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.bku.slcommands; + + +public interface BulkCommand extends SLCommand { + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkSignatureResult.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkSignatureResult.java new file mode 100644 index 00000000..8670d635 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkSignatureResult.java @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Datentechnik Innovation and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.bku.slcommands; + +import org.w3c.dom.Element; + +public interface BulkSignatureResult extends SLResult { + + public Element getContent(); + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandFactory.java new file mode 100644 index 00000000..7f7d7f1e --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright 2015 Datentechnik Innovation and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.bku.slcommands.impl; + +import javax.xml.bind.JAXBElement; + +import at.gv.egiz.bku.slcommands.AbstractSLCommandFactory; +import at.gv.egiz.bku.slcommands.SLCommand; +import at.gv.egiz.bku.slexceptions.SLCommandException; + +public class BulkCommandFactory extends AbstractSLCommandFactory { + + @Override + public SLCommand createSLCommand(JAXBElement element) throws SLCommandException { + BulkCommandImpl command = new BulkCommandImpl(); + command.init(element); + command.setConfiguration(configuration); + return command; + } +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandImpl.java new file mode 100644 index 00000000..7094e284 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandImpl.java @@ -0,0 +1,439 @@ +/* + * Copyright 2015 Datentechnik Innovation GmbH and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.bku.slcommands.impl; + +import iaik.asn1.DerCoder; +import iaik.asn1.INTEGER; +import iaik.asn1.SEQUENCE; +import iaik.asn1.structures.AlgorithmID; +import iaik.cms.CMSException; +import iaik.cms.CMSSignatureException; +import iaik.utils.Util; + +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.SignatureException; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.BulkRequestType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.BulkRequestType.CreateSignatureRequest; +import at.buergerkarte.namespaces.securitylayer._1_2_3.CreateCMSSignatureRequestType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.ExcludedByteRangeType; +import at.gv.egiz.bku.conf.MoccaConfigurationFacade; +import at.gv.egiz.bku.slcommands.BulkCommand; +import at.gv.egiz.bku.slcommands.SLCommandContext; +import at.gv.egiz.bku.slcommands.SLResult; +import at.gv.egiz.bku.slcommands.impl.cms.BulkCollectionSecurityProvider; +import at.gv.egiz.bku.slcommands.impl.cms.BulkSignature; +import at.gv.egiz.bku.slcommands.impl.cms.BulkSignatureInfo; +import at.gv.egiz.bku.slcommands.impl.cms.CMSHashDataInput; +import at.gv.egiz.bku.slcommands.impl.xsect.STALSignatureException; +import at.gv.egiz.bku.slexceptions.SLCommandException; +import at.gv.egiz.bku.slexceptions.SLException; +import at.gv.egiz.bku.slexceptions.SLRequestException; +import at.gv.egiz.bku.slexceptions.SLViewerException; +import at.gv.egiz.stal.BulkSignRequest; +import at.gv.egiz.stal.BulkSignResponse; +import at.gv.egiz.stal.ErrorResponse; +import at.gv.egiz.stal.HashDataInput; +import at.gv.egiz.stal.InfoboxReadRequest; +import at.gv.egiz.stal.STALRequest; +import at.gv.egiz.stal.STALResponse; +import at.gv.egiz.stal.SignRequest; +import at.gv.egiz.stal.SignRequest.SignedInfo; + +/** + * This class implements the security layer command BulkRequest. + * + * @author szoescher + */ +public class BulkCommandImpl extends SLCommandImpl implements BulkCommand { + + private final static String ID_ECSIGTYPE = "1.2.840.10045.4"; + + /** + * Logging facility. + */ + private final static Logger log = LoggerFactory.getLogger(BulkCommandImpl.class); + + /** + * The signing certificate. + */ + protected X509Certificate signingCertificate; + + /** + * The keybox identifier of the key used for signing. + */ + protected String keyboxIdentifier; + + /** + * The configuration facade used to access the MOCCA configuration. + */ + private ConfigurationFacade configurationFacade = new ConfigurationFacade(); + + private class ConfigurationFacade implements MoccaConfigurationFacade { + private Configuration configuration; + + public static final String USE_STRONG_HASH = "UseStrongHash"; + + public void setConfiguration(Configuration configuration) { + this.configuration = configuration; + } + + public boolean getUseStrongHash() { + return configuration.getBoolean(USE_STRONG_HASH, true); + } + } + + @Override + public String getName() { + return "BulkRequest"; + } + + public void setConfiguration(Configuration configuration) { + configurationFacade.setConfiguration(configuration); + } + + @Override + public SLResult execute(SLCommandContext commandContext) { + + List signatures = new LinkedList(); + + try { + + List signatureRequests = getRequestValue().getCreateSignatureRequest(); + + + List requestIds = new LinkedList(); + + if (signatureRequests != null && signatureRequests.size() != 0) { + + BulkCollectionSecurityProvider securityProvider = new BulkCollectionSecurityProvider(); + + log.debug("get keyboxIdentifier from BulkSingatureRequest"); + keyboxIdentifier = setKeyboxIdentifier(signatureRequests); + + log.info("Requesting signing certificate."); + signingCertificate = requestSigningCertificate(keyboxIdentifier, commandContext); + log.debug("Got signing certificate. {}", signingCertificate); + + + for (int i=0; i signBulkRequest(List bulkSignatureInfo, SLCommandContext commandContext, + List signatures) throws SLCommandException, SLRequestException { + + try { + + List signatureValues; + + BulkSignRequest signRequest = getSTALSignRequest(bulkSignatureInfo); + + // send BulkStalRequest + List responses = commandContext.getSTAL().handleRequest( + Collections.singletonList((STALRequest) signRequest)); + + if (responses == null || responses.size() != 1) { + throw new SignatureException("Failed to access STAL."); + } + + STALResponse response = responses.get(0); + + // setSignatureValues from STALResponse + if (response instanceof BulkSignResponse) { + BulkSignResponse bulkSignatureResponse = ((BulkSignResponse) response); + + signatureValues = new LinkedList(); + for (int i = 0; i < bulkSignatureResponse.getSignResponse().size(); i++) { + byte[] sig = ((BulkSignResponse) response).getSignResponse().get(i).getSignatureValue(); + log.debug("Got signature response: " + Util.toBase64String(sig)); + signatures.get(i).getSignerInfo() + .setSignatureValue(wrapSignatureValue(sig, bulkSignatureInfo.get(i).getSignatureAlgorithm())); + signatureValues.add(signatures.get(i).getEncoded()); + } + + return signatureValues; + + } else if (response instanceof ErrorResponse) { + + ErrorResponse err = (ErrorResponse) response; + log.debug("Error signing bulk request. Error response code: " + err.getErrorCode() + " (" + err.getErrorMessage() + ")."); + throw new SLCommandException(err.getErrorCode()); + } + + } catch (SignatureException e) { + log.error("Error creating CMSSignature", e); + throw new SLCommandException(4000); + } catch (CMSException e) { + log.error("Error creating CMSSignature", e); + } + return null; + } + + private String setKeyboxIdentifier(List signatureRequests) throws SLCommandException { + + String keyboxIdentifier = null; + + for (CreateSignatureRequest request : signatureRequests) { + if (request.getCreateCMSSignatureRequest() != null) { + + if (keyboxIdentifier == null) { + keyboxIdentifier = request.getCreateCMSSignatureRequest().getKeyboxIdentifier(); + } else { + if (request.getCreateCMSSignatureRequest().getKeyboxIdentifier() == null) { + log.error("No keyboxIdentifier has been specified for this signature request."); + throw new SLCommandException(3003); + + } else if (!request.getCreateCMSSignatureRequest().getKeyboxIdentifier().equals(keyboxIdentifier)) { + + log.error("Error creating bulk signature. The bulkSignature value has to be the same fo all signature requests."); + throw new SLCommandException(3003); + } + } + } + } + + + return keyboxIdentifier; + } + + private BulkSignature prepareCMSSignatureRequests(BulkCollectionSecurityProvider securityProvieder, + CreateCMSSignatureRequestType request, SLCommandContext commandContext) throws SLCommandException, + SLRequestException, SLViewerException { + + BulkSignature signature; + + // prepare the CMSSignature for signing + log.debug("Preparing CMS signature."); + signature = prepareCMSSignature(request, commandContext); + + try { + + // update securityProvieder with parameters of the given signature + securityProvieder.updateBulkCollectionSecurityProvider(keyboxIdentifier, signature.getHashDataInput(), + signature.getExcludedByteRange()); + + // prepare the CMSSignatures of the Bulk Request + log.debug("Signing CMS signature."); + + + + return prepareStalRequest(securityProvieder, signature, commandContext); + + } catch (Exception e) { + log.error("Error creating CMS Signature.", e); + throw new SLCommandException(4000); + } + + } + + private BulkSignature prepareCMSSignature(CreateCMSSignatureRequestType request, SLCommandContext commandContext) + throws SLCommandException, SLRequestException { + + // DataObject, SigningCertificate, SigningTime + Date signingTime = new Date(); + try { + return new BulkSignature( + request.getDataObject() != null ? request.getDataObject() : request.getReferenceObject(), + request.getStructure(), signingCertificate, signingTime, commandContext.getURLDereferencer(), + configurationFacade.getUseStrongHash()); + } catch (SLCommandException e) { + log.error("Error creating CMS Signature.", e); + throw e; + } catch (InvalidParameterException e) { + log.error("Error creating CMS Signature.", e); + throw new SLCommandException(3004); + } catch (Exception e) { + log.error("Error creating CMS Signature.", e); + throw new SLCommandException(4000); + } + } + + private BulkSignature prepareStalRequest(BulkCollectionSecurityProvider securityProvieder, BulkSignature signature, + SLCommandContext commandContext) throws SLCommandException, SLViewerException { + + try { + + signature.sign(securityProvieder, commandContext.getSTAL(), keyboxIdentifier); + return signature; + } catch (CMSException e) { + log.error("Error creating CMSSignature", e); + throw new SLCommandException(4000); + } catch (CMSSignatureException e) { + log.error("Error creating CMSSignature", e); + throw new SLCommandException(4000); + } + } + + private X509Certificate requestSigningCertificate(String keyboxIdentifier, SLCommandContext commandContext) + throws SLCommandException { + + InfoboxReadRequest stalRequest = new InfoboxReadRequest(); + stalRequest.setInfoboxIdentifier(keyboxIdentifier); + + STALHelper stalHelper = new STALHelper(commandContext.getSTAL()); + + stalHelper.transmitSTALRequest(Collections.singletonList((STALRequest) stalRequest)); + List certificates = stalHelper.getCertificatesFromResponses(); + if (certificates == null || certificates.size() != 1) { + log.info("Got an unexpected number of certificates from STAL."); + throw new SLCommandException(4000); + } + return signingCertificate = certificates.get(0); + + } + + private static BulkSignRequest getSTALSignRequest(List bulkSignatureInfo) { + BulkSignRequest bulkSignRequest = new BulkSignRequest(); + + for (int i = 0; i< bulkSignatureInfo.size(); i++) { + + BulkSignatureInfo signatureInfo = bulkSignatureInfo.get(i); + SignRequest signRequest = new SignRequest(); + signRequest.setKeyIdentifier(signatureInfo.getKeyboxIdentifier()); + log.debug("SignedAttributes: " + Util.toBase64String(signatureInfo.getSignedAttributes())); + SignedInfo signedInfo = new SignedInfo(); + signedInfo.setValue(signatureInfo.getSignedAttributes()); + signedInfo.setIsCMSSignedAttributes(true); + signRequest.setSignedInfo(signedInfo); + log.info("set displayName for Request {}", signatureInfo.getHashDataInput().get(0).getFilename()); + signRequest.setDisplayName(signatureInfo.getHashDataInput().get(0).getFilename()); + signRequest.setMimeType(signatureInfo.getHashDataInput().get(0).getMimeType()); + + signRequest.setSignatureMethod(signatureInfo.getSignatureMethod()); + signRequest.setDigestMethod(signatureInfo.getDigestMethod()); + signRequest.setHashDataInput(signatureInfo.getHashDataInput()); + + ExcludedByteRangeType excludedByteRange = signatureInfo.getExcludedByteRange(); + if (excludedByteRange != null) { + SignRequest.ExcludedByteRange ebr = new SignRequest.ExcludedByteRange(); + ebr.setFrom(excludedByteRange.getFrom()); + ebr.setTo(excludedByteRange.getTo()); + signRequest.setExcludedByteRange(ebr); + } + + bulkSignRequest.getSignRequests().add(signRequest); + } + return bulkSignRequest; + } + + private static byte[] wrapSignatureValue(byte[] sig, AlgorithmID sigAlgorithmID) { + String id = sigAlgorithmID.getAlgorithm().getID(); + if (id.startsWith(ID_ECSIGTYPE)) // X9.62 Format ECDSA signatures + { + // Wrap r and s in ASN.1 SEQUENCE + byte[] r = Arrays.copyOfRange(sig, 0, sig.length / 2); + byte[] s = Arrays.copyOfRange(sig, sig.length / 2, sig.length); + SEQUENCE sigS = new SEQUENCE(); + sigS.addComponent(new INTEGER(new BigInteger(1, r))); + sigS.addComponent(new INTEGER(new BigInteger(1, s))); + return DerCoder.encode(sigS); + } else + return sig; + } + +} \ No newline at end of file diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkSignatureResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkSignatureResultImpl.java new file mode 100644 index 00000000..2a88b6be --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkSignatureResultImpl.java @@ -0,0 +1,138 @@ +/* + * Copyright 2015 Datentechnik Innovation and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.bku.slcommands.impl; + +import java.util.List; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.transform.Result; +import javax.xml.transform.Templates; +import javax.xml.transform.dom.DOMResult; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.BulkResponseType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.BulkResponseType.CreateSignatureResponse; +import at.buergerkarte.namespaces.securitylayer._1_2_3.CreateCMSSignatureResponseType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.ObjectFactory; +import at.gv.egiz.bku.slcommands.BulkSignatureResult; +import at.gv.egiz.bku.slcommands.SLMarshallerFactory; +import at.gv.egiz.bku.slexceptions.SLRuntimeException; + +/** + * This implements the result of the security layer command + * BulkRequest. + * + * @author szoescher + */ +public class BulkSignatureResultImpl extends SLResultImpl implements BulkSignatureResult { + + /** + * Logging facility. + */ + private final Logger log = LoggerFactory.getLogger(BulkSignatureResultImpl.class); + + /** + * The CMSSignatures data. + */ + protected List signatures; + + + protected List requestIds; + + + /** + * The BulkResponse. + */ + private Element content; + + /** + * Creates a new instance of this BulkSignatureResultImpl with the given + * signatures signatures. + */ + public BulkSignatureResultImpl(List signatures, List requestIds) { + super(); + + if (signatures == null || signatures.size() == 0) + throw new NullPointerException("Argument 'signature' must not be null."); + this.signatures = signatures; + + this.requestIds = requestIds; + + marshallBulkSignatureResponse(); + } + + /** + * Marshalls the BulkResponseType. + */ + private void marshallBulkSignatureResponse() { + + ObjectFactory factory = new ObjectFactory(); + + BulkResponseType bulkResponseType = factory.createBulkResponseType(); + + for (int i=0; i< signatures.size(); i++) { + + byte[] signature = signatures.get(i); + CreateSignatureResponse createSignatureResponse = factory.createBulkResponseTypeCreateSignatureResponse(); + + if (requestIds.get(i) != null) { + createSignatureResponse.setId(requestIds.get(i)); + } + CreateCMSSignatureResponseType createCreateCMSSignatureResponseType = factory + .createCreateCMSSignatureResponseType(); + createCreateCMSSignatureResponseType.setCMSSignature(signature); + createSignatureResponse.setCreateCMSSignatureResponse(createCreateCMSSignatureResponseType); + bulkResponseType.getCreateSignatureResponse().add(createSignatureResponse); + + + } + + JAXBElement createBulkResponse = factory.createBulkResponse(bulkResponseType); + DOMResult res = new DOMResult(); + + Marshaller marshaller = SLMarshallerFactory.getInstance().createMarshaller(false); + + try { + marshaller.marshal(createBulkResponse, res); + } catch (JAXBException e) { + log.error("Failed to marshall 'createBulkResponse'.", e); + throw new SLRuntimeException(e); + } + content = ((Document) res.getNode()).getDocumentElement(); + } + + @Override + public void writeTo(Result result, Templates templates, boolean fragment) { + writeTo(content, result, templates, fragment); + } + + @Override + public Element getContent() { + return content; + } +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImpl.java index eaf3e70a..93e0eee8 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImpl.java @@ -123,8 +123,9 @@ public class CreateCMSSignatureCommandImpl extends // DataObject, SigningCertificate, SigningTime Date signingTime = request.isPAdESCompatibility() ? null : new Date(); - signature = new Signature(request.getDataObject(), request.getStructure(), - signingCertificate, signingTime, commandContext.getURLDereferencer(), + signature = new Signature(request.getDataObject() != null ? request.getDataObject() + : request.getReferenceObject(), request.getStructure(), signingCertificate, signingTime, + commandContext.getURLDereferencer(), configurationFacade.getUseStrongHash()); } } catch (SLCommandException e) { diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java index d0451138..74a0b4da 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java @@ -76,4 +76,8 @@ public class DataObjectHashDataInput implements HashDataInput { return dataObject.getFilename(); } + @Override + public byte[] getDigest() { + return dataObject.getReference().getDigestValue(); + } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkCollectionSecurityProvider.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkCollectionSecurityProvider.java new file mode 100644 index 00000000..6bbdc682 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkCollectionSecurityProvider.java @@ -0,0 +1,114 @@ +/* + * Copyright 2015 Datentechnik Innovation GmbH and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + + +package at.gv.egiz.bku.slcommands.impl.cms; + +import iaik.asn1.structures.AlgorithmID; +import iaik.cms.IaikProvider; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.SignatureException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.ExcludedByteRangeType; +import at.gv.egiz.stal.HashDataInput; + + +/** + * This security Provider is used to collect multiple sign Requests to create one Stal BulkRequest. + * The related signature parameters are stored as a List of BulkSignatureInfo. + * @author szoescher + * + */ +public class BulkCollectionSecurityProvider extends IaikProvider { + + private final static Logger log = LoggerFactory.getLogger(BulkCollectionSecurityProvider.class); + + private String keyboxIdentifier; + private List hashDataInput; + private ExcludedByteRangeType excludedByteRange; + + private List bulkSignatureInfo; + + + public BulkCollectionSecurityProvider() { + bulkSignatureInfo = new LinkedList(); + } + + public BulkCollectionSecurityProvider(String keyboxIdentifier, HashDataInput hashDataInput, + ExcludedByteRangeType excludedByteRange) { + + bulkSignatureInfo = new LinkedList(); + updateBulkCollectionSecurityProvider(keyboxIdentifier, hashDataInput, excludedByteRange); + + } + + public void updateBulkCollectionSecurityProvider(String keyboxIdentifier, HashDataInput hashDataInput, + ExcludedByteRangeType excludedByteRange) { + + this.keyboxIdentifier = keyboxIdentifier; + this.hashDataInput = new ArrayList(); + this.hashDataInput.add(hashDataInput); + this.excludedByteRange = excludedByteRange; + + } + + /* (non-Javadoc) + * @see iaik.cms.IaikProvider#calculateSignatureFromSignedAttributes(iaik.asn1.structures.AlgorithmID, iaik.asn1.structures.AlgorithmID, java.security.PrivateKey, byte[]) + */ + @Override + public byte[] calculateSignatureFromSignedAttributes(AlgorithmID signatureAlgorithm, + AlgorithmID digestAlgorithm, PrivateKey privateKey, + byte[] signedAttributes) + throws SignatureException, InvalidKeyException, NoSuchAlgorithmException { + log.debug("calculateSignatureFromSignedAttributes: " + signatureAlgorithm + ", " + digestAlgorithm); + + + STALPrivateKey spk = (STALPrivateKey) privateKey; + + //Store signature information that is required to create a StalBulkSignatureRequest. + bulkSignatureInfo.add(new BulkSignatureInfo(privateKey, signatureAlgorithm, keyboxIdentifier, signedAttributes, + spk.getAlgorithm(), spk.getDigestAlgorithm(), hashDataInput, excludedByteRange)); + + //Size of placeholder doesn't matter + byte[] signaturePlaceholder = new byte[1]; + return signaturePlaceholder; + } + +public List getBulkSignatureInfo() { + return bulkSignatureInfo; +} + + + + + + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignature.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignature.java new file mode 100644 index 00000000..bf220034 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignature.java @@ -0,0 +1,116 @@ +/* + * Copyright 2015 Datentechnik Innovation GmbH and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + + +package at.gv.egiz.bku.slcommands.impl.cms; + +import iaik.asn1.CodingException; +import iaik.cms.CMSException; +import iaik.cms.CMSSignatureException; +import iaik.cms.ContentInfo; +import iaik.cms.SecurityProvider; +import iaik.cms.SignedData; +import iaik.cms.SignerInfo; +import iaik.x509.X509ExtensionException; + +import java.io.IOException; +import java.security.InvalidParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Date; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.CMSDataObjectOptionalMetaType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.ExcludedByteRangeType; +import at.gv.egiz.bku.slexceptions.SLCommandException; +import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; +import at.gv.egiz.stal.STAL; + +/** + * This class represents a CMS-Signature as to be created by the + * security layer command BulkSignatureRequest. + * + * @author szoescher + */ +public class BulkSignature extends Signature { + + public final static String ID_AA_ETS_MIMETYPE = "0.4.0.1733.2.1"; + + public BulkSignature(CMSDataObjectOptionalMetaType dataObject, String structure, + X509Certificate signingCertificate, Date signingTime, URLDereferencer urlDereferencer, + boolean useStrongHash) + throws NoSuchAlgorithmException, CertificateEncodingException, + CertificateException, X509ExtensionException, InvalidParameterException, + CodingException, SLCommandException, IOException, CMSException { + super(dataObject, structure, signingCertificate, signingTime, urlDereferencer, useStrongHash); + } + + /** + * Additionally to the sign() method from the supertype, + * contains a additional parameter to set a custom securityProvider. + * @param securityProvider The Security Provider that handles the sign request. + */ + public byte[] sign(SecurityProvider securityProvider, STAL stal, String keyboxIdentifier) throws CMSException, CMSSignatureException, SLCommandException { + signedData.setSecurityProvider(securityProvider); + try { + signedData.addSignerInfo(signerInfo); + } catch (NoSuchAlgorithmException e) { + throw new CMSSignatureException(e); + } + if (digestValue != null) { + try { + signedData.setMessageDigest(digestAlgorithm, digestValue); + } catch (NoSuchAlgorithmException e) { + throw new CMSSignatureException(e); + } + } + ContentInfo contentInfo = new ContentInfo(signedData); + return contentInfo.getEncoded(); + } + + + public ExcludedByteRangeType getExcludedByteRange() { + return excludedByteRange; + } + + public SignerInfo getSignerInfo() { + return signerInfo; + } + + public void setSignerInfo(SignerInfo signerInfo) { + this.signerInfo = signerInfo; + } + + + public SignedData getSignedData() { + return signedData; + } + + public byte[] getEncoded() throws CMSException{ + ContentInfo contentInfo = new ContentInfo(signedData); + return contentInfo.getEncoded(); + } + + +} + diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignatureInfo.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignatureInfo.java new file mode 100644 index 00000000..1d918f9f --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignatureInfo.java @@ -0,0 +1,104 @@ +/* + * Copyright 2015 Datentechnik Innovation GmbH and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.bku.slcommands.impl.cms; + +import iaik.asn1.structures.AlgorithmID; + +import java.security.PrivateKey; +import java.util.List; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.ExcludedByteRangeType; +import at.gv.egiz.stal.HashDataInput; + + +/** + * + * @author szoescher + * + */ +public class BulkSignatureInfo { + + AlgorithmID signatureAlgorithm; + + String keyboxIdentifier; + + byte[] signedAttributes; + + String signatureMethod; + + String digestMethod; + + List hashDataInput; + + ExcludedByteRangeType excludedByteRange; + + PrivateKey privateKey; + + public BulkSignatureInfo(PrivateKey privateKey, AlgorithmID signatureAlgorithm, String keyboxIdentifier, + byte[] signedAttributes, String signatureMethod, String digestMethod, List hashDataInput, + ExcludedByteRangeType excludedByteRange) { + this.privateKey = privateKey; + this.signatureAlgorithm = signatureAlgorithm; + this.keyboxIdentifier = keyboxIdentifier; + this.signedAttributes = signedAttributes; + this.signatureMethod = signatureMethod; + this.digestMethod = digestMethod; + this.hashDataInput = hashDataInput; + this.excludedByteRange = excludedByteRange; + } + + public String getKeyboxIdentifier() { + return keyboxIdentifier; + } + + public byte[] getSignedAttributes() { + return signedAttributes; + } + + public String getSignatureMethod() { + return signatureMethod; + } + + public String getDigestMethod() { + return digestMethod; + } + + public List getHashDataInput() { + return hashDataInput; + } + + public ExcludedByteRangeType getExcludedByteRange() { + return excludedByteRange; + } + + public AlgorithmID getSignatureAlgorithm() { + return signatureAlgorithm; + } + + public PrivateKey getPrivateKey() { + return privateKey; + } + + + + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/CMSHashDataInput.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/CMSHashDataInput.java index e51c5823..25162dc4 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/CMSHashDataInput.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/CMSHashDataInput.java @@ -25,6 +25,7 @@ package at.gv.egiz.bku.slcommands.impl.cms; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; import at.gv.egiz.bku.gui.viewer.MimeTypes; @@ -32,18 +33,33 @@ import at.gv.egiz.stal.HashDataInput; public class CMSHashDataInput implements HashDataInput { - private final static String DEFAULT_FILENAME = "SignatureData"; + public final static String DEFAULT_FILENAME = "SignatureData"; private byte[] data; - private String mimeType; + private byte[] digest; + protected String mimeType; + private String referenceId; + private String fileName; public CMSHashDataInput(byte[] data, String mimeType) { this.data = data; this.mimeType = mimeType; } + public CMSHashDataInput(byte[] data, String mimeType, byte[] digest) { + this.data = data; + this.mimeType = mimeType; + } + + public CMSHashDataInput() { + } + @Override public String getReferenceId() { + + if (referenceId != null) { + return referenceId; + } return CMS_DEF_REFERENCE_ID; } @@ -59,11 +75,38 @@ public class CMSHashDataInput implements HashDataInput { @Override public String getFilename() { + if (fileName != null) { + return fileName; + } + + if (mimeType != null) { return DEFAULT_FILENAME + MimeTypes.getExtension(mimeType); } + return DEFAULT_FILENAME; + } + @Override - public InputStream getHashDataInput() { + public InputStream getHashDataInput() throws IOException { return new ByteArrayInputStream(data); } + + @Override + public byte[] getDigest() { + return digest; + } + + + public void setFilename(String fileName) { + this.fileName = fileName; + } + + public void setDigest(byte[] digest) { + this.digest = digest; + } + + public void setReferenceId(String referenceId) { + this.referenceId = referenceId; + } + } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/ReferencedHashDataInput.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/ReferencedHashDataInput.java new file mode 100644 index 00000000..96e0e7de --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/ReferencedHashDataInput.java @@ -0,0 +1,81 @@ +/* + * Copyright 2015 Datentechnik Innovation GmbH and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.bku.slcommands.impl.cms; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.ArrayUtils; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.ExcludedByteRangeType; +import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; + +public class ReferencedHashDataInput extends CMSHashDataInput { + + private String urlReference; + private URLDereferencer urlDereferencer; + private ExcludedByteRangeType excludedByteRange; + + public ReferencedHashDataInput(String mimeType, URLDereferencer urlDereferencer, String urlReference, ExcludedByteRangeType excludedByteRange) { + super(null, mimeType); + this.urlDereferencer = urlDereferencer; + this.urlReference = urlReference; + this.excludedByteRange = excludedByteRange; + } + + + public URLDereferencer getUrlDereferencer() { + return urlDereferencer; + } + + + public void setUrlDereferencer(URLDereferencer urlDereferencer) { + this.urlDereferencer = urlDereferencer; + } + + public InputStream getHashDataInput() throws IOException { + + InputStream hashDataInputStream = urlDereferencer.dereference(urlReference).getStream(); + + try { + byte[] content = IOUtils.toByteArray(hashDataInputStream); + + if (excludedByteRange != null) { + + int from = excludedByteRange.getFrom().intValue(); + int to = excludedByteRange.getTo().intValue(); + + byte[] signedContent = ArrayUtils.addAll(ArrayUtils.subarray(content, 0, from), ArrayUtils.subarray(content, to, content.length)); + + return new ByteArrayInputStream(signedContent); + + } else { + return new ByteArrayInputStream(content); + } + + } finally { + hashDataInputStream.close(); + } + } +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALSecurityProvider.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALSecurityProvider.java index 87c00644..1dd6cc9e 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALSecurityProvider.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALSecurityProvider.java @@ -69,8 +69,8 @@ public class STALSecurityProvider extends IaikProvider { private ExcludedByteRangeType excludedByteRange; private STALSignatureException stalSignatureException; - public STALSecurityProvider(STAL stal, String keyboxIdentifier, - HashDataInput hashDataInput, ExcludedByteRangeType excludedByteRange) { + public STALSecurityProvider(STAL stal, String keyboxIdentifier, HashDataInput hashDataInput, + ExcludedByteRangeType excludedByteRange) { this.keyboxIdentifier = keyboxIdentifier; this.stal = stal; this.hashDataInput = new ArrayList(); @@ -78,23 +78,27 @@ public class STALSecurityProvider extends IaikProvider { this.excludedByteRange = excludedByteRange; } - /* (non-Javadoc) - * @see iaik.cms.IaikProvider#calculateSignatureFromSignedAttributes(iaik.asn1.structures.AlgorithmID, iaik.asn1.structures.AlgorithmID, java.security.PrivateKey, byte[]) + /* + * (non-Javadoc) + * + * @see + * iaik.cms.IaikProvider#calculateSignatureFromSignedAttributes(iaik.asn1. + * structures.AlgorithmID, iaik.asn1.structures.AlgorithmID, + * java.security.PrivateKey, byte[]) */ @Override - public byte[] calculateSignatureFromSignedAttributes(AlgorithmID signatureAlgorithm, - AlgorithmID digestAlgorithm, PrivateKey privateKey, - byte[] signedAttributes) - throws SignatureException, InvalidKeyException, NoSuchAlgorithmException { + public byte[] calculateSignatureFromSignedAttributes(AlgorithmID signatureAlgorithm, AlgorithmID digestAlgorithm, + PrivateKey privateKey, byte[] signedAttributes) throws SignatureException, InvalidKeyException, + NoSuchAlgorithmException { + stalSignatureException = null; log.debug("calculateSignatureFromSignedAttributes: " + signatureAlgorithm + ", " + digestAlgorithm); STALPrivateKey spk = (STALPrivateKey) privateKey; - SignRequest signRequest = getSTALSignRequest(keyboxIdentifier, signedAttributes, - spk.getAlgorithm(), spk.getDigestAlgorithm(), hashDataInput, excludedByteRange); + SignRequest signRequest = getSTALSignRequest(keyboxIdentifier, signedAttributes, spk.getAlgorithm(), + spk.getDigestAlgorithm(), hashDataInput, excludedByteRange); log.debug("Sending STAL request ({})", privateKey.getAlgorithm()); - List responses = - stal.handleRequest(Collections.singletonList((STALRequest) signRequest)); + List responses = stal.handleRequest(Collections.singletonList((STALRequest) signRequest)); if (responses == null || responses.size() != 1) { throw new SignatureException("Failed to access STAL."); @@ -114,9 +118,9 @@ public class STALSecurityProvider extends IaikProvider { } } - private static SignRequest getSTALSignRequest(String keyboxIdentifier, - byte[] signedAttributes, String signatureMethod, String digestMethod, - List hashDataInput, ExcludedByteRangeType excludedByteRange) { + private static SignRequest getSTALSignRequest(String keyboxIdentifier, byte[] signedAttributes, + String signatureMethod, String digestMethod, List hashDataInput, + ExcludedByteRangeType excludedByteRange) { SignRequest signRequest = new SignRequest(); signRequest.setKeyIdentifier(keyboxIdentifier); log.debug("SignedAttributes: " + Util.toBase64String(signedAttributes)); @@ -147,8 +151,7 @@ public class STALSecurityProvider extends IaikProvider { sigS.addComponent(new INTEGER(new BigInteger(1, r))); sigS.addComponent(new INTEGER(new BigInteger(1, s))); return DerCoder.encode(sigS); - } - else + } else return sig; } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/Signature.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/Signature.java index 7be546de..4a94ca7f 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/Signature.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/Signature.java @@ -24,48 +24,32 @@ package at.gv.egiz.bku.slcommands.impl.cms; -import iaik.asn1.ASN1Object; -import iaik.asn1.CodingException; -import iaik.asn1.ObjectID; -import iaik.asn1.SEQUENCE; -import iaik.asn1.UTF8String; -import iaik.asn1.structures.AlgorithmID; -import iaik.asn1.structures.Attribute; -import iaik.asn1.structures.ChoiceOfTime; -import iaik.cms.CMSException; -import iaik.cms.CMSSignatureException; -import iaik.cms.CertificateIdentifier; -import iaik.cms.ContentInfo; -import iaik.cms.IssuerAndSerialNumber; -import iaik.cms.SignedData; -import iaik.cms.SignerInfo; -import iaik.smime.ess.ESSCertID; -import iaik.smime.ess.ESSCertIDv2; -import iaik.x509.X509ExtensionException; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; import java.security.InvalidParameterException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; -import java.security.PublicKey; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.ECParameterSpec; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; +import javax.xml.crypto.dsig.DigestMethod; + import org.apache.commons.lang.ArrayUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.w3._2000._09.xmldsig_.DigestMethodType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.CMSDataObjectOptionalMetaType; import at.buergerkarte.namespaces.securitylayer._1_2_3.CMSDataObjectRequiredMetaType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.DigestAndRefType; import at.buergerkarte.namespaces.securitylayer._1_2_3.ExcludedByteRangeType; import at.gv.egiz.bku.slcommands.impl.xsect.AlgorithmMethodFactory; import at.gv.egiz.bku.slcommands.impl.xsect.AlgorithmMethodFactoryImpl; @@ -74,6 +58,24 @@ import at.gv.egiz.bku.slexceptions.SLCommandException; import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; import at.gv.egiz.stal.HashDataInput; import at.gv.egiz.stal.STAL; +import iaik.asn1.ASN1Object; +import iaik.asn1.CodingException; +import iaik.asn1.ObjectID; +import iaik.asn1.SEQUENCE; +import iaik.asn1.UTF8String; +import iaik.asn1.structures.AlgorithmID; +import iaik.asn1.structures.Attribute; +import iaik.asn1.structures.ChoiceOfTime; +import iaik.cms.CMSException; +import iaik.cms.CMSSignatureException; +import iaik.cms.CertificateIdentifier; +import iaik.cms.ContentInfo; +import iaik.cms.IssuerAndSerialNumber; +import iaik.cms.SignedData; +import iaik.cms.SignerInfo; +import iaik.smime.ess.ESSCertID; +import iaik.smime.ess.ESSCertIDv2; +import iaik.x509.X509ExtensionException; /** * This class represents a CMS-Signature as to be created by the @@ -90,25 +92,51 @@ public class Signature { */ private final Logger log = LoggerFactory.getLogger(Signature.class); - private SignedData signedData; - private SignerInfo signerInfo; - private byte[] signedDocument; - private String mimeType; - private AlgorithmID signatureAlgorithm; - private AlgorithmID digestAlgorithm; - private String signatureAlgorithmURI; - private String digestAlgorithmURI; - private ExcludedByteRangeType excludedByteRange; + protected SignedData signedData; + protected SignerInfo signerInfo; + protected byte[] signedDocument; + protected String mimeType; + protected AlgorithmID signatureAlgorithm; + protected AlgorithmID digestAlgorithm; + protected byte[] digestValue; + protected String signatureAlgorithmURI; + protected String digestAlgorithmURI; + protected ExcludedByteRangeType excludedByteRange; + private HashDataInput hashDataInput; + - public Signature(CMSDataObjectRequiredMetaType dataObject, String structure, +public Signature(CMSDataObjectOptionalMetaType dataObject, String structure, X509Certificate signingCertificate, Date signingTime, URLDereferencer urlDereferencer, boolean useStrongHash) throws NoSuchAlgorithmException, CertificateEncodingException, CertificateException, X509ExtensionException, InvalidParameterException, - CodingException, SLCommandException, IOException { - byte[] dataToBeSigned = getContent(dataObject, urlDereferencer); + CodingException, SLCommandException, IOException, CMSException { int mode = structure.equalsIgnoreCase("enveloping") ? SignedData.IMPLICIT : SignedData.EXPLICIT; + if (dataObject.getContent() != null) { + byte[] dataToBeSigned = getContent(dataObject, urlDereferencer); this.signedData = new SignedData(dataToBeSigned, mode); + if (dataObject.getMetaInfo() != null) { + this.mimeType = dataObject.getMetaInfo().getMimeType(); + } + + hashDataInput = new CMSHashDataInput(signedDocument, mimeType); + + } else { + DigestAndRefType digestAndRef = dataObject.getDigestAndRef(); + DigestMethodType digestMethod = digestAndRef.getDigestMethod(); + + hashDataInput = new ReferencedHashDataInput(dataObject.getMetaInfo().getMimeType(), urlDereferencer, + digestAndRef.getReference(), dataObject.getExcludedByteRange()); + + try { + digestAlgorithm = getAlgorithmID(digestMethod.getAlgorithm()); + } catch (URISyntaxException e) { + //TODO: choose proper execption + throw new NoSuchAlgorithmException(e); + } + digestValue = digestAndRef.getDigestValue(); + this.signedData = new SignedData(ObjectID.pkcs7_data); + } setAlgorithmIDs(signingCertificate, useStrongHash); createSignerInfo(signingCertificate); setSignerCertificate(signingCertificate); @@ -208,7 +236,7 @@ public class Signature { attributes.add(signingTime); } - private byte[] getContent(CMSDataObjectRequiredMetaType dataObject, URLDereferencer urlDereferencer) + private byte[] getContent(CMSDataObjectOptionalMetaType dataObject, URLDereferencer urlDereferencer) throws InvalidParameterException, SLCommandException, IOException { byte[] data = dataObject.getContent().getBase64Content(); if (data == null) { @@ -252,63 +280,36 @@ public class Signature { } private void setAlgorithmIDs(X509Certificate signingCertificate, boolean useStrongHash) throws NoSuchAlgorithmException { - PublicKey publicKey = signingCertificate.getPublicKey(); - String algorithm = publicKey.getAlgorithm(); AlgorithmMethodFactory amf = new AlgorithmMethodFactoryImpl(signingCertificate, useStrongHash); signatureAlgorithmURI = amf.getSignatureAlgorithmURI(); + signatureAlgorithm = amf.getSignatureAlgorithmID(); + if (digestAlgorithm != null) { + if (AlgorithmID.sha1.equals(digestAlgorithm)) { + digestAlgorithmURI = DigestMethod.SHA1; + } else if (AlgorithmID.sha256.equals(digestAlgorithm)) { + digestAlgorithmURI = DigestMethod.SHA256; + } else if (AlgorithmID.sha512.equals(digestAlgorithm)) { + digestAlgorithmURI = DigestMethod.SHA512; + } else if (AlgorithmID.ripeMd160.equals(digestAlgorithm)) { + digestAlgorithmURI = DigestMethod.RIPEMD160; + } else { + throw new NoSuchAlgorithmException("Algorithm '" + digestAlgorithm + "' not supported."); + } + } else { digestAlgorithmURI = amf.getDigestAlgorithmURI(); - - if ("DSA".equals(algorithm)) { - signatureAlgorithm = AlgorithmID.dsaWithSHA1; - } else if ("RSA".equals(algorithm)) { - - int keyLength = 0; - if (publicKey instanceof RSAPublicKey) { - keyLength = ((RSAPublicKey) publicKey).getModulus().bitLength(); + digestAlgorithm = amf.getDigestAlgorithmID(); } - - if (useStrongHash && keyLength >= 2048) { - signatureAlgorithm = AlgorithmID.sha256WithRSAEncryption; - digestAlgorithm = AlgorithmID.sha256; -// } else if (useStrongHash) { // Cannot be used if not enabled in AlgorithmMethodFactoryImpl -// signatureAlgorithm = AlgorithmID.rsaSignatureWithRipemd160; -// digestAlgorithm = AlgorithmID.ripeMd160; - } else { - signatureAlgorithm = AlgorithmID.sha1WithRSAEncryption; - digestAlgorithm = AlgorithmID.sha1; } - } else if (("EC".equals(algorithm)) || ("ECDSA".equals(algorithm))) { - int fieldSize = 0; - if (publicKey instanceof ECPublicKey) { - ECParameterSpec params = ((ECPublicKey) publicKey).getParams(); - fieldSize = params.getCurve().getField().getFieldSize(); - } else { - throw new NoSuchAlgorithmException("Public key type not supported."); - } + public HashDataInput getHashDataInput() { - if (useStrongHash && fieldSize >= 512) { - signatureAlgorithm = AlgorithmID.ecdsa_With_SHA512; - digestAlgorithm = AlgorithmID.sha512; - } else if (useStrongHash && fieldSize >= 256) { - signatureAlgorithm = AlgorithmID.ecdsa_With_SHA256; - digestAlgorithm = AlgorithmID.sha256; - } else if (useStrongHash) { - signatureAlgorithm = AlgorithmID.ecdsa_plain_With_RIPEMD160; - digestAlgorithm = AlgorithmID.ripeMd160; + if (hashDataInput != null) { + return hashDataInput; } else { - signatureAlgorithm = AlgorithmID.ecdsa_With_SHA1; - digestAlgorithm = AlgorithmID.sha1; - } - } else { - throw new NoSuchAlgorithmException("Public key algorithm '" + algorithm - + "' not supported."); + return new CMSHashDataInput(signedDocument, mimeType); } } - private HashDataInput getHashDataInput() { - return new CMSHashDataInput(signedDocument, mimeType); - } public byte[] sign(STAL stal, String keyboxIdentifier) throws CMSException, CMSSignatureException, SLCommandException { STALSecurityProvider securityProvider = new STALSecurityProvider(stal, keyboxIdentifier, getHashDataInput(), this.excludedByteRange); @@ -322,7 +323,29 @@ public class Signature { } throw new CMSSignatureException(e); } + if (digestValue != null) { + try { + signedData.setMessageDigest(digestAlgorithm, digestValue); + } catch (NoSuchAlgorithmException e) { + throw new CMSSignatureException(e); + } + } ContentInfo contentInfo = new ContentInfo(signedData); return contentInfo.getEncoded(); } + + protected AlgorithmID getAlgorithmID(String uri) throws URISyntaxException { + String oid = null; + URI urn = new URI(uri); + String scheme = urn.getScheme(); + if ("URN".equalsIgnoreCase(scheme)) { + String schemeSpecificPart = urn.getSchemeSpecificPart().toLowerCase(); + if (schemeSpecificPart.startsWith("oid:")) { + oid = schemeSpecificPart.substring(4, schemeSpecificPart.length()); +} + } + return new AlgorithmID(new ObjectID(oid)); + } } + + diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactory.java index d2484b56..1b801ec5 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactory.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactory.java @@ -32,6 +32,8 @@ import javax.xml.crypto.dsig.CanonicalizationMethod; import javax.xml.crypto.dsig.DigestMethod; import javax.xml.crypto.dsig.SignatureMethod; +import iaik.asn1.structures.AlgorithmID; + /** * A factory for creating {@link AlgorithmMethod}s. * @@ -87,4 +89,8 @@ public interface AlgorithmMethodFactory { public String getSignatureAlgorithmURI(); public String getDigestAlgorithmURI(); + + AlgorithmID getSignatureAlgorithmID(); + + AlgorithmID getDigestAlgorithmID(); } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactoryImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactoryImpl.java index 896552d8..c3fcd146 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactoryImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactoryImpl.java @@ -24,6 +24,7 @@ package at.gv.egiz.bku.slcommands.impl.xsect; +import iaik.asn1.structures.AlgorithmID; import iaik.xml.crypto.XmldsigMore; import java.security.InvalidAlgorithmParameterException; @@ -54,11 +55,21 @@ public class AlgorithmMethodFactoryImpl implements AlgorithmMethodFactory { */ private String signatureAlgorithmURI; + /** + * The signature algorithm ID. + */ + private AlgorithmID signatureAlgorithmID; + /** * the digest algorithm URI. */ private String digestAlgorithmURI = DigestMethod.SHA1; + /** + * The digest algorithm ID. + */ + private AlgorithmID digestAlgorithmID = AlgorithmID.sha1; + /** * The algorithm parameters for the signature algorithm. */ @@ -82,6 +93,7 @@ public class AlgorithmMethodFactoryImpl implements AlgorithmMethodFactory { if ("DSA".equals(algorithm)) { signatureAlgorithmURI = SignatureMethod.DSA_SHA1; + signatureAlgorithmID = AlgorithmID.dsaWithSHA1; } else if ("RSA".equals(algorithm)) { int keyLength = 0; @@ -91,12 +103,12 @@ public class AlgorithmMethodFactoryImpl implements AlgorithmMethodFactory { if (useStrongHash && keyLength >= 2048) { signatureAlgorithmURI = XmldsigMore.SIGNATURE_RSA_SHA256; + signatureAlgorithmID = AlgorithmID.sha256WithRSAEncryption; digestAlgorithmURI = DigestMethod.SHA256; -// } else if (useStrongHash) { -// signatureAlgorithmURI = XmldsigMore.SIGNATURE_RSA_RIPEMD160_ERRATA; -// digestAlgorithmURI = DigestMethod.RIPEMD160; + digestAlgorithmID = AlgorithmID.sha256; } else { signatureAlgorithmURI = SignatureMethod.RSA_SHA1; + signatureAlgorithmID = AlgorithmID.sha1WithRSAEncryption; } } else if (("EC".equals(algorithm)) || ("ECDSA".equals(algorithm))) { @@ -111,15 +123,22 @@ public class AlgorithmMethodFactoryImpl implements AlgorithmMethodFactory { if (useStrongHash && fieldSize >= 512) { signatureAlgorithmURI = XmldsigMore.SIGNATURE_ECDSA_SHA512; + signatureAlgorithmID = AlgorithmID.ecdsa_With_SHA512; digestAlgorithmURI = DigestMethod.SHA512; + digestAlgorithmID = AlgorithmID.sha512; } else if (useStrongHash && fieldSize >= 256) { signatureAlgorithmURI = XmldsigMore.SIGNATURE_ECDSA_SHA256; + signatureAlgorithmID = AlgorithmID.ecdsa_With_SHA256; digestAlgorithmURI = DigestMethod.SHA256; + digestAlgorithmID = AlgorithmID.sha256; } else if (useStrongHash) { signatureAlgorithmURI = XmldsigMore.SIGNATURE_ECDSA_RIPEMD160; + signatureAlgorithmID = AlgorithmID.ecdsa_plain_With_RIPEMD160; digestAlgorithmURI = DigestMethod.RIPEMD160; + digestAlgorithmID = AlgorithmID.ripeMd160; } else { signatureAlgorithmURI = XmldsigMore.SIGNATURE_ECDSA_SHA1; + signatureAlgorithmID = AlgorithmID.ecdsa_With_SHA1; } } else { @@ -185,4 +204,14 @@ public class AlgorithmMethodFactoryImpl implements AlgorithmMethodFactory { return digestAlgorithmURI; } + @Override + public AlgorithmID getSignatureAlgorithmID() { + return signatureAlgorithmID; + } + + @Override + public AlgorithmID getDigestAlgorithmID() { + return digestAlgorithmID; + } + } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/spring/URLDereferencerFactoryBean.java b/bkucommon/src/main/java/at/gv/egiz/bku/spring/URLDereferencerFactoryBean.java new file mode 100644 index 00000000..1a95a146 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/spring/URLDereferencerFactoryBean.java @@ -0,0 +1,75 @@ +package at.gv.egiz.bku.spring; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSocketFactory; + +import org.apache.commons.configuration.Configuration; +import org.springframework.beans.factory.FactoryBean; + +import at.gv.egiz.bku.conf.MoccaConfigurationFacade; +import at.gv.egiz.bku.utils.urldereferencer.FileURLProtocolHandlerImpl; +import at.gv.egiz.bku.utils.urldereferencer.URLDereferencerImpl; + +public class URLDereferencerFactoryBean implements FactoryBean { + + private HostnameVerifier hostnameVerifier; + private SSLSocketFactory sslSocketFactory; + + protected final ConfigurationFacade configurationFacade = new ConfigurationFacade(); + + public class ConfigurationFacade implements MoccaConfigurationFacade { + + private Configuration configuration; + public static final String ENABLE_FILEURIS = "enableFileURIs"; + + public boolean isEnableFileURIs() { + return configuration.getBoolean(ENABLE_FILEURIS, false); + } + + } + + public void setConfiguration(Configuration configuration) { + configurationFacade.configuration = configuration; + } + + @Override + public Object getObject() throws Exception { + + URLDereferencerImpl urlDereferencer = URLDereferencerImpl.getInstance(); + urlDereferencer.setHostnameVerifier(hostnameVerifier); + urlDereferencer.setSSLSocketFactory(sslSocketFactory); + + if(!configurationFacade.isEnableFileURIs()) { + urlDereferencer.registerHandler(FileURLProtocolHandlerImpl.FILE, new FileURLProtocolHandlerImpl()); + } + + return urlDereferencer; + } + + @Override + public Class getObjectType() { + return URLDereferencerImpl.class; + } + + @Override + public boolean isSingleton() { + return true; + } + + public HostnameVerifier getHostnameVerifier() { + return hostnameVerifier; + } + + public void setHostnameVerifier(HostnameVerifier hostnameVerifier) { + this.hostnameVerifier = hostnameVerifier; + } + + public SSLSocketFactory getSslSocketFactory() { + return sslSocketFactory; + } + + public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) { + this.sslSocketFactory = sslSocketFactory; + } + +} diff --git a/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages.properties b/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages.properties index de54e9b2..92955fc9 100644 --- a/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages.properties +++ b/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages.properties @@ -108,3 +108,6 @@ ec4011.notimplemented=Befehl {0} ist nicht implementiert. lec2901.notimplemented=Die in der Anfrage verwendete Version des Security-Layer Protokolls ({0}) wird nicht mehr unterstützt. +# custom error messages for bulk signature +ec4124= XML Signatur Requests werden aktuell in der Stapelsignatur nicht unterstützt. + diff --git a/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages_en.properties b/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages_en.properties index 471f4a13..4d90f71c 100644 --- a/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages_en.properties +++ b/bkucommon/src/main/resources/at/gv/egiz/bku/slexceptions/SLExceptionMessages_en.properties @@ -106,3 +106,5 @@ ec4011.notimplemented=Command {0} not implemented. # Legacy error codes # lec2901.notimplemented=The version ({0}) of the security-layer protocol used in the request is not supported. +# custom error messages for bulk signature +ec4124= XML signature requests are currently not supported in bulk signature requests. diff --git a/bkucommon/src/site/apt/configuration.apt b/bkucommon/src/site/apt/configuration.apt index ec6b7cd0..2aca5dc7 100644 --- a/bkucommon/src/site/apt/configuration.apt +++ b/bkucommon/src/site/apt/configuration.apt @@ -54,6 +54,10 @@ MOCCA Configuration Default: <<>> + [<<>>] Whether to allow dereferencing of "file" URIs. + + Default: <<>> + [<<>>] The following two configuration elements must provide an URL which resolves to a directory in the file system. It may either be an absolute URL or a relative URL, which is resolved using the URL of the configuration file. diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/BulkCommandImplTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/BulkCommandImplTest.java new file mode 100644 index 00000000..b91bec98 --- /dev/null +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/BulkCommandImplTest.java @@ -0,0 +1,130 @@ +/* + * Copyright 2015 Datentechnik Innovation and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.bku.slcommands.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import iaik.asn1.ObjectID; +import iaik.cms.SignedData; +import iaik.xml.crypto.XSecProvider; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; + +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.BulkResponseType; +import at.gv.egiz.bku.slcommands.BulkCommand; +import at.gv.egiz.bku.slcommands.BulkSignatureResult; +import at.gv.egiz.bku.slcommands.SLCommand; +import at.gv.egiz.bku.slcommands.SLCommandContext; +import at.gv.egiz.bku.slcommands.SLCommandFactory; +import at.gv.egiz.bku.slcommands.SLResult; +import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; +import at.gv.egiz.stal.STAL; +import at.gv.egiz.stal.STALFactory; + +public class BulkCommandImplTest { + + protected static ApplicationContext appCtx; + private SLCommandFactory factory; + + private STAL stal; + + private URLDereferencer urlDereferencer; + + @BeforeClass + public static void setUpClass() { + appCtx = new ClassPathXmlApplicationContext("at/gv/egiz/bku/slcommands/testApplicationContext.xml"); + XSecProvider.addAsProvider(true); + } + + @Before + public void setUp() throws JAXBException { + + Object bean = appCtx.getBean("slCommandFactory"); + assertTrue(bean instanceof SLCommandFactory); + + factory = (SLCommandFactory) bean; + + bean = appCtx.getBean("stalFactory"); + assertTrue(bean instanceof STALFactory); + + stal = ((STALFactory) bean).createSTAL(); + + bean = appCtx.getBean("urlDereferencer"); + assertTrue(bean instanceof URLDereferencer); + + urlDereferencer = (URLDereferencer) bean; + + } + + @Test + public void testCreateCMSSignatureRequest() throws Exception { + InputStream inputStream = getClass().getClassLoader().getResourceAsStream( + "at/gv/egiz/bku/slcommands/bulksignaturerequest/BulkSignatureRequest.xml"); + assertNotNull(inputStream); + + SLCommand command = factory.createSLCommand(new StreamSource(new InputStreamReader(inputStream))); + assertTrue(command instanceof BulkCommand); + + SLCommandContext context = new SLCommandContext(stal, urlDereferencer, null); + SLResult result = command.execute(context); + + assertTrue(result instanceof BulkSignatureResult); + + BulkSignatureResult bulkResult = (BulkSignatureResult) result; + System.out.println(bulkResult.getContent()); + + bulkResult.getContent(); + + // unmarshall response + Unmarshaller unmarshaller = factory.getJaxbContext().createUnmarshaller(); + + BulkResponseType response = unmarshaller.unmarshal(bulkResult.getContent(), BulkResponseType.class).getValue(); + + // verify ContentType of singature + byte[] cmsSignature = response.getCreateSignatureResponse().get(0).getCreateCMSSignatureResponse() + .getCMSSignature(); + SignedData signedData = new SignedData(new ByteArrayInputStream(cmsSignature)); + + assertNotNull(signedData); + assertEquals(ObjectID.pkcs7_signedData, signedData.getContentType()); + assertNotNull(response.getCreateSignatureResponse()); + assertEquals(2, response.getCreateSignatureResponse().size()); + + result.writeTo(new StreamResult(System.out), false); + + } + +} diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImplTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImplTest.java index b1ec7777..09b70f09 100644 --- a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImplTest.java +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImplTest.java @@ -24,13 +24,21 @@ package at.gv.egiz.bku.slcommands.impl; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import iaik.asn1.ObjectID; +import iaik.cms.CMSParsingException; +import iaik.cms.SignedData; import iaik.xml.crypto.XSecProvider; +import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; @@ -40,7 +48,9 @@ import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import at.buergerkarte.namespaces.securitylayer._1_2_3.CreateCMSSignatureResponseType; import at.gv.egiz.bku.slcommands.CreateCMSSignatureCommand; +import at.gv.egiz.bku.slcommands.CreateCMSSignatureResult; import at.gv.egiz.bku.slcommands.SLCommand; import at.gv.egiz.bku.slcommands.SLCommandContext; import at.gv.egiz.bku.slcommands.SLCommandFactory; @@ -89,8 +99,11 @@ public class CreateCMSSignatureCommandImplTest { } @Test - public void testCreateCMSSignatureRequest() throws SLCommandException, SLRuntimeException, SLRequestException, SLVersionException { - InputStream inputStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/createcmssignaturerequest/CreateCMSSignatureRequest.xml"); + public void testCreateCMSSignatureRequest() throws SLCommandException, SLRuntimeException, SLRequestException, + SLVersionException, JAXBException, CMSParsingException, IOException { + + InputStream inputStream = getClass().getClassLoader().getResourceAsStream( + "at/gv/egiz/bku/slcommands/createcmssignaturerequest/CreateCMSSignatureRequest.xml"); assertNotNull(inputStream); SLCommand command = factory.createSLCommand(new StreamSource(new InputStreamReader(inputStream))); @@ -98,6 +111,22 @@ public class CreateCMSSignatureCommandImplTest { SLCommandContext context = new SLCommandContext(stal, urlDereferencer, null); SLResult result = command.execute(context); + + assertTrue(result instanceof CreateCMSSignatureResult); + CreateCMSSignatureResult sigResult = (CreateCMSSignatureResult) result; + + //unmarshall response + Unmarshaller unmarshaller = factory.getJaxbContext().createUnmarshaller(); + + CreateCMSSignatureResponseType response = unmarshaller.unmarshal(sigResult.getContent(), CreateCMSSignatureResponseType.class).getValue(); + + //verify ContentType of singature + byte[] cmsSignature = response.getCMSSignature(); + SignedData signedData = new SignedData(new ByteArrayInputStream(cmsSignature)); + + assertNotNull(signedData); + assertEquals(ObjectID.pkcs7_signedData, signedData.getContentType()); + result.writeTo(new StreamResult(System.out), false); } } diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/cms/SignatureTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/cms/SignatureTest.java new file mode 100644 index 00000000..56229b83 --- /dev/null +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/cms/SignatureTest.java @@ -0,0 +1,130 @@ +package at.gv.egiz.bku.slcommands.impl.cms; + +import static org.junit.Assert.*; + +import java.io.ByteArrayInputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.Charset; +import java.security.MessageDigest; +import java.util.Date; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.w3._2000._09.xmldsig_.DigestMethodType; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.Base64OptRefContentType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.CMSDataObjectRequiredMetaType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.DigestAndRefType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.MetaInfoType; +import at.gv.egiz.stal.dummy.DummySTAL; +import iaik.asn1.ObjectID; +import iaik.asn1.structures.AlgorithmID; +import iaik.cms.InvalidSignatureValueException; +import iaik.cms.SignedData; +import iaik.cms.SignerInfo; +import iaik.security.ecc.provider.ECCProvider; +import iaik.security.provider.IAIK; +import iaik.x509.X509Certificate; + +public class SignatureTest { + + private DummySTAL stal = new DummySTAL(); + + @BeforeClass + public static void setUpClass() { + IAIK.addAsProvider(); + ECCProvider.addAsProvider(); + } + + @Test + public void testSignCMSDataObject() throws Exception { + + byte[] plaintext = "Plaintext".getBytes(Charset.forName("UTF-8")); + + CMSDataObjectRequiredMetaType dataObject = new CMSDataObjectRequiredMetaType(); + Base64OptRefContentType base64OptRefContentType = new Base64OptRefContentType(); + base64OptRefContentType.setBase64Content(plaintext); + dataObject.setContent(base64OptRefContentType); + MetaInfoType metaInfoType = new MetaInfoType(); + metaInfoType.setMimeType("text/plain"); + dataObject.setMetaInfo(metaInfoType); + + Signature signature = new Signature(dataObject, "detached", stal.getCert(), new Date(), null, true); + byte[] cmsSignature = signature.sign(stal, "SecureSignatureKeypair"); + + SignedData signedData = new SignedData(new ByteArrayInputStream(cmsSignature)); + signedData.setContent(plaintext); + assertEquals(ObjectID.pkcs7_data, signedData.getEncapsulatedContentType()); + SignerInfo[] signerInfos = signedData.getSignerInfos(); + assertEquals(1, signerInfos.length); + SignerInfo signerInfo = signerInfos[0]; + signedData.verify((X509Certificate) stal.getCert()); + assertEquals(AlgorithmID.sha1, signerInfo.getDigestAlgorithm()); + assertEquals(AlgorithmID.sha1WithRSAEncryption, signerInfo.getSignatureAlgorithm()); + + System.out.println(AlgorithmID.sha1); + + } + + @Test + public void testSignCMSReferenceSha1() throws Exception { + testSignCMSReference(AlgorithmID.sha1); + } + + //TODO Why doesn't it work this way?? + @Test(expected = InvalidSignatureValueException.class) + public void testSignCMSReferenceSha256() throws Exception { + testSignCMSReference(AlgorithmID.sha256); + } + + private void testSignCMSReference(AlgorithmID digestAlgorithmID) throws Exception { + + byte[] plaintext = "Plaintext".getBytes(Charset.forName("UTF-8")); + + MessageDigest messageDigest = MessageDigest.getInstance(digestAlgorithmID.getImplementationName()); + byte[] digestValue = messageDigest.digest(plaintext); + + CMSDataObjectRequiredMetaType dataObject = new CMSDataObjectRequiredMetaType(); + DigestAndRefType digestAndRefType = new DigestAndRefType(); + DigestMethodType digestMethodType = new DigestMethodType(); + digestMethodType.setAlgorithm("URN:OID:" + digestAlgorithmID.getAlgorithm().getID()); + digestAndRefType.setDigestMethod(digestMethodType); + digestAndRefType.setDigestValue(digestValue); + dataObject.setDigestAndRef(digestAndRefType); + MetaInfoType metaInfoType = new MetaInfoType(); + metaInfoType.setMimeType("text/plain"); + dataObject.setMetaInfo(metaInfoType); + + Signature signature = new Signature(dataObject, "detached", stal.getCert(), new Date(), null, true); + byte[] cmsSignature = signature.sign(stal, "SecureSignatureKeypair"); + + SignedData signedData = new SignedData(new ByteArrayInputStream(cmsSignature)); + signedData.setContent(plaintext); + assertEquals(ObjectID.pkcs7_data, signedData.getEncapsulatedContentType()); + SignerInfo[] signerInfos = signedData.getSignerInfos(); + assertEquals(1, signerInfos.length); + SignerInfo signerInfo = signerInfos[0]; + signedData.verify((X509Certificate) stal.getCert()); + assertEquals(digestAlgorithmID, signerInfo.getDigestAlgorithm()); + assertEquals(AlgorithmID.sha1WithRSAEncryption, signerInfo.getSignatureAlgorithm()); + + } + + @Test + public void test() throws URISyntaxException { + + String oid = null; + URI uri = new URI("URN:OID:1.3.14.3.2.26"); + String scheme = uri.getScheme(); + if ("URN".equalsIgnoreCase(scheme)) { + String schemeSpecificPart = uri.getSchemeSpecificPart().toLowerCase(); + if (schemeSpecificPart.startsWith("oid:")) { + oid = schemeSpecificPart.substring(4, schemeSpecificPart.length()); + } + } + assertEquals("1.3.14.3.2.26", oid); + + } + +} diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java index 6e5612f6..04cf3552 100644 --- a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/xsect/SignatureTest.java @@ -27,7 +27,7 @@ package at.gv.egiz.bku.slcommands.impl.xsect; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; - +import iaik.asn1.structures.AlgorithmID; import iaik.xml.crypto.XSecProvider; import java.io.IOException; @@ -140,6 +140,16 @@ public class SignatureTest { return DigestMethod.SHA1; } + @Override + public AlgorithmID getSignatureAlgorithmID() { + return null; + } + + @Override + public AlgorithmID getDigestAlgorithmID() { + return null; + } + } private static final String RESOURCE_PREFIX = "at/gv/egiz/bku/slcommands/impl/"; diff --git a/bkucommon/src/test/java/at/gv/egiz/stal/dummy/DummySTAL.java b/bkucommon/src/test/java/at/gv/egiz/stal/dummy/DummySTAL.java index 61d0d480..0f054cf0 100644 --- a/bkucommon/src/test/java/at/gv/egiz/stal/dummy/DummySTAL.java +++ b/bkucommon/src/test/java/at/gv/egiz/stal/dummy/DummySTAL.java @@ -36,9 +36,13 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.List; +import javax.xml.crypto.dsig.SignatureMethod; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import at.gv.egiz.stal.BulkSignRequest; +import at.gv.egiz.stal.BulkSignResponse; import at.gv.egiz.stal.ErrorResponse; import at.gv.egiz.stal.InfoboxReadRequest; import at.gv.egiz.stal.InfoboxReadResponse; @@ -47,6 +51,7 @@ import at.gv.egiz.stal.STALRequest; import at.gv.egiz.stal.STALResponse; import at.gv.egiz.stal.SignRequest; import at.gv.egiz.stal.SignResponse; +import iaik.xml.crypto.XmldsigMore; public class DummySTAL implements STAL { @@ -58,11 +63,9 @@ public class DummySTAL implements STAL { public DummySTAL() { try { KeyStore ks = KeyStore.getInstance("pkcs12"); - InputStream ksStream = getClass().getClassLoader().getResourceAsStream( - "at/gv/egiz/bku/slcommands/impl/Cert.p12"); + InputStream ksStream = getClass().getClassLoader().getResourceAsStream("at/gv/egiz/bku/slcommands/impl/Cert.p12"); ks.load(ksStream, "1622".toCharArray()); - for (Enumeration aliases = ks.aliases(); aliases - .hasMoreElements();) { + for (Enumeration aliases = ks.aliases(); aliases.hasMoreElements();) { String alias = aliases.nextElement(); log.debug("Found alias " + alias + " in keystore"); if (ks.isKeyEntry(alias)) { @@ -78,25 +81,28 @@ public class DummySTAL implements STAL { } + public X509Certificate getCert() { + return cert; + } + @Override public List handleRequest(List requestList) { List responses = new ArrayList(); for (STALRequest request : requestList) { - log.debug("Got STALRequest " + request + "."); + log.info("Got STALRequest " + request + "."); if (request instanceof InfoboxReadRequest) { - String infoboxIdentifier = ((InfoboxReadRequest) request) - .getInfoboxIdentifier(); + String infoboxIdentifier = ((InfoboxReadRequest) request).getInfoboxIdentifier(); InputStream stream = getClass().getClassLoader().getResourceAsStream( "at/gv/egiz/stal/dummy/infoboxes4/" + infoboxIdentifier + ".bin"); STALResponse response; if (stream != null) { - log.debug("Infobox " + infoboxIdentifier + " found."); + log.info("Infobox " + infoboxIdentifier + " found."); byte[] infobox; try { @@ -114,7 +120,8 @@ public class DummySTAL implements STAL { infoboxReadResponse.setInfoboxValue(infobox); response = infoboxReadResponse; - } else if ((infoboxIdentifier.equals("SecureSignatureKeypair")) ||(infoboxIdentifier.equals("CertifiedKeypair"))) { + } else if ((infoboxIdentifier.equals("SecureSignatureKeypair")) + || (infoboxIdentifier.equals("CertifiedKeypair"))) { try { InfoboxReadResponse infoboxReadResponse = new InfoboxReadResponse(); infoboxReadResponse.setInfoboxValue(cert.getEncoded()); @@ -135,7 +142,13 @@ public class DummySTAL implements STAL { try { SignRequest signReq = (SignRequest) request; - Signature s = Signature.getInstance("SHA1withRSA"); + String signatureMethod = ((SignRequest) request).getSignatureMethod(); + Signature s = null; + if (SignatureMethod.RSA_SHA1.equals(signatureMethod)) { + s = Signature.getInstance("SHA1withRSA"); + } else if (XmldsigMore.SIGNATURE_RSA_SHA256.equals(signatureMethod)) { + s = Signature.getInstance("SHA256withRSA"); + } s.initSign(privateKey); s.update(signReq.getSignedInfo().getValue()); byte[] sigVal = s.sign(); @@ -147,7 +160,37 @@ public class DummySTAL implements STAL { responses.add(new ErrorResponse()); } - } else { + } + + //dummy handler for BulkSignRequest + else if (request instanceof BulkSignRequest) { + + try { + BulkSignRequest bulkSignReq = (BulkSignRequest) request; + + BulkSignResponse bulkSignResp = new BulkSignResponse(); + + for (int i = 0; i < bulkSignReq.getSignRequests().size(); i++) { + + Signature s = Signature.getInstance("SHA1withRSA"); + s.initSign(privateKey); + s.update(bulkSignReq.getSignRequests().get(i).getSignedInfo().getValue()); + byte[] sigVal = s.sign(); + SignResponse resp = new SignResponse(); + resp.setSignatureValue(sigVal); + bulkSignResp.getSignResponse().add(resp); + } + + responses.add(bulkSignResp); + + } catch (Exception e) { + log.error("Failed to create signature.", e); + responses.add(new ErrorResponse()); + } + + } + + else { log.debug("Request not implemented."); diff --git a/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/bulksignaturerequest/BulkSignatureRequest.xml b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/bulksignaturerequest/BulkSignatureRequest.xml new file mode 100644 index 00000000..7fa39f57 --- /dev/null +++ b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/bulksignaturerequest/BulkSignatureRequest.xml @@ -0,0 +1,34 @@ + + + + + SecureSignatureKeypair + + + text/plain + + + QW5kIG5vdyB0byBzb21ldGhpbmcgY29tcGxldGx5IGRpZmZlcmVudA== + + + + + + + + SecureSignatureKeypair + + + text/plain + + + Vm9uIGRlciBTaWduYXR1ciB1bXNjaGxvc3NlbmUgRGF0ZW4u + + + + + + \ No newline at end of file diff --git a/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/bulksignaturerequest/BulkSignatureRequestWithReference.xml b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/bulksignaturerequest/BulkSignatureRequestWithReference.xml new file mode 100644 index 00000000..a506d50c --- /dev/null +++ b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/bulksignaturerequest/BulkSignatureRequestWithReference.xml @@ -0,0 +1,37 @@ + + + + + SecureSignatureKeypair + + + text/plain + + + + j6lwx3rvEPO0vKtMup4NbeVu8nk= + + + + + + + SecureSignatureKeypair + + + text/plainheis + + + + j6lwx3rvEPO0vKtMup4NbeVu8nk= + + + + + \ No newline at end of file diff --git a/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/testApplicationContext.xml b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/testApplicationContext.xml index fffabb47..9a76291c 100644 --- a/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/testApplicationContext.xml +++ b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/testApplicationContext.xml @@ -118,6 +118,14 @@ + + + + + @@ -136,6 +144,7 @@ + -- cgit v1.2.3