From b9ccb62d35a755efb505d426ce924d5a8fbe937a Mon Sep 17 00:00:00 2001 From: "Bonato, Martin" Date: Thu, 8 Feb 2018 22:19:55 +0100 Subject: BulkSignature implementation --- .../gv/egiz/bku/online/applet/AppletBKUWorker.java | 8 +- .../egiz/bku/online/applet/AppletSecureViewer.java | 100 +- .../at/gv/egiz/stal/client/STALServiceTest.java | 4 +- .../bku/online/applet/GetCertificateBKUWorker.java | 2 + .../bku/online/applet/HardwareInfoBKUWorker.java | 2 + .../bku/online/applet/IdentityLinkBKUWorker.java | 2 + .../main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java | 21 +- .../main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java | 257 ++- .../egiz/bku/gui/hashdata/HashDataInputLoader.java | 16 + .../at/gv/egiz/bku/gui/viewer/SecureViewer.java | 58 + .../gv/egiz/stal/impl/ByteArrayHashDataInput.java | 20 +- .../at/gv/egiz/bku/gui/Messages.properties | 6 +- .../at/gv/egiz/bku/gui/Messages_de.properties | 6 +- .../test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java | 2 +- .../at/gv/egiz/bku/local/stal/LocalBKUWorker.java | 5 +- .../local/stal/LocalBulkSignRequestHandler.java | 82 + .../gv/egiz/bku/local/stal/LocalSecureViewer.java | 289 ++- .../src/main/webapp/WEB-INF/applicationContext.xml | 15 +- .../stal/service/impl/STALRequestBrokerImpl.java | 20 +- .../gv/egiz/stal/service/impl/STALServiceImpl.java | 42 +- .../src/main/webapp/WEB-INF/applicationContext.xml | 15 +- BKUOnline/src/main/webapp/WEB-INF/wsdl/stal.xsd | 19 + BKUOnline/src/main/wsdl/stal-service.xsd | 17 + .../egiz/stal/service/STALRequestBrokerTest.java | 24 + .../main/java/at/gv/egiz/stal/BulkSignRequest.java | 92 + .../java/at/gv/egiz/stal/BulkSignResponse.java | 91 + .../main/java/at/gv/egiz/stal/HashDataInput.java | 8 +- .../src/main/java/at/gv/egiz/stal/SignRequest.java | 56 + .../main/java/at/gv/egiz/stal/SignatureInfo.java | 84 + .../gv/egiz/stal/hashdata/StubHashDataInput.java | 101 + .../stal/service/translator/STALTranslator.java | 126 +- .../stal/service/types/BulkSignRequestType.java | 68 + .../stal/service/types/BulkSignResponseType.java | 69 + .../stal/service/types/GetHashDataInputType.java | 42 +- .../service/types/GetNextRequestResponseType.java | 52 +- .../stal/service/types/GetNextRequestType.java | 58 +- .../gv/egiz/stal/service/types/ObjectFactory.java | 40 + .../at/gv/egiz/stal/service/types/RequestType.java | 3 +- .../gv/egiz/stal/service/types/ResponseType.java | 3 +- .../egiz/stal/service/types/SignRequestType.java | 87 +- .../at/gv/egiz/stalx/service/STALServiceTest.java | 2 +- bkucommon/pom.xml | 5 + .../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 + pom.xml | 12 - .../java/at/gv/egiz/smcc/BulkSignException.java | 47 + .../gv/egiz/smcc/pin/gui/OverrulePinpadPINGUI.java | 7 + .../java/at/gv/egiz/smcc/pin/gui/PINProvider.java | 4 +- .../at/gv/egiz/smcc/reader/PinpadCardReader.java | 10 + .../java/at/gv/egiz/smcc/card/CreateSignature.java | 3 +- .../at/gv/egiz/smcc/pin/gui/CancelPINProvider.java | 3 +- .../gv/egiz/smcc/pin/gui/InterruptPINProvider.java | 3 +- .../gv/egiz/smcc/pin/gui/InvalidPINProvider.java | 3 +- .../gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java | 3 +- .../at/gv/egiz/smcc/test/AbstractCardTest.java | 5 +- .../test/ecard/ECardG3InfoboxContainerTest.java | 3 +- .../at/gv/egiz/bku/pin/gui/BulkSignPINGUI.java | 172 ++ .../java/at/gv/egiz/bku/pin/gui/SignPINGUI.java | 8 +- .../at/gv/egiz/bku/pin/gui/SignPINProvider.java | 13 +- .../at/gv/egiz/bku/pin/gui/VerifyPINProvider.java | 4 +- .../egiz/bku/smccstal/BulkSignRequestHandler.java | 273 +++ .../java/at/gv/egiz/bku/smccstal/SecureViewer.java | 53 - .../gv/egiz/bku/smccstal/SignRequestHandler.java | 13 +- .../_1_2_3/CMSDataObjectOptionalMetaType.java | 35 +- .../securitylayer/_1_2_3/CMSReferenceObject.java | 46 + .../_1_2_3/CreateCMSSignatureRequestType.java | 36 +- .../securitylayer/_1_2_3/DigestAndRefType.java | 128 ++ .../securitylayer/_1_2_3/ObjectFactory.java | 8 + .../FileURLProtocolHandlerImpl.java | 63 + .../resources/at/gv/egiz/bku/slschema/Core-1.2.xsd | 2267 ++++++++++---------- 96 files changed, 5609 insertions(+), 1579 deletions(-) create mode 100644 BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/hashdata/HashDataInputLoader.java create mode 100644 BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewer.java create mode 100644 BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalBulkSignRequestHandler.java create mode 100644 STAL/src/main/java/at/gv/egiz/stal/BulkSignRequest.java create mode 100644 STAL/src/main/java/at/gv/egiz/stal/BulkSignResponse.java create mode 100644 STAL/src/main/java/at/gv/egiz/stal/SignatureInfo.java create mode 100644 STAL/src/main/java/at/gv/egiz/stal/hashdata/StubHashDataInput.java create mode 100644 STALService/src/main/java/at/gv/egiz/stal/service/types/BulkSignRequestType.java create mode 100644 STALService/src/main/java/at/gv/egiz/stal/service/types/BulkSignResponseType.java 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 create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/BulkSignException.java create mode 100644 smcc/src/main/java/at/gv/egiz/smcc/pin/gui/OverrulePinpadPINGUI.java create mode 100644 smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/BulkSignPINGUI.java create mode 100644 smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/BulkSignRequestHandler.java delete mode 100644 smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SecureViewer.java create mode 100644 utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/CMSReferenceObject.java create mode 100644 utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/DigestAndRefType.java create mode 100644 utils/src/main/java/at/gv/egiz/bku/utils/urldereferencer/FileURLProtocolHandlerImpl.java diff --git a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java index 67c3f9af..d89611a6 100644 --- a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java +++ b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletBKUWorker.java @@ -25,8 +25,10 @@ package at.gv.egiz.bku.online.applet; import at.gv.egiz.bku.smccstal.AbstractBKUWorker; +import at.gv.egiz.bku.smccstal.BulkSignRequestHandler; import at.gv.egiz.bku.gui.BKUGUIFacade; import at.gv.egiz.bku.smccstal.SignRequestHandler; +import at.gv.egiz.stal.BulkSignRequest; import at.gv.egiz.stal.STALRequest; import at.gv.egiz.stal.STALResponse; import at.gv.egiz.stal.SignRequest; @@ -85,6 +87,8 @@ public class AppletBKUWorker extends AbstractBKUWorker implements Runnable { new AppletSecureViewer(gui, stalPort, sessionId); addRequestHandler(SignRequest.class, new SignRequestHandler(secureViewer)); + addRequestHandler(BulkSignRequest.class, + new BulkSignRequestHandler(secureViewer)); GetNextRequestResponseType nextRequestResp = stalPort.connect(sessionId); @@ -93,7 +97,7 @@ public class AppletBKUWorker extends AbstractBKUWorker implements Runnable { List> responses = new ArrayList>(); try { - requests = nextRequestResp.getInfoboxReadRequestOrSignRequestOrQuitRequest(); + requests = nextRequestResp.getInfoboxReadRequestOrSignRequestOrBulkSignRequest(); responses.clear(); // (rather use validator) @@ -167,7 +171,7 @@ public class AppletBKUWorker extends AbstractBKUWorker implements Runnable { } GetNextRequestType nextRequest = stalObjFactory.createGetNextRequestType(); nextRequest.setSessionId(sessionId); - nextRequest.getInfoboxReadResponseOrSignResponseOrErrorResponse().addAll(responses); + nextRequest.getInfoboxReadResponseOrSignResponseOrBulkSignResponse().addAll(responses); nextRequestResp = stalPort.getNextRequest(nextRequest); } } diff --git a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java index b2c084bd..9f7061b1 100644 --- a/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java +++ b/BKUApplet/src/main/java/at/gv/egiz/bku/online/applet/AppletSecureViewer.java @@ -32,27 +32,31 @@ import java.security.DigestException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.LinkedList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import at.gv.egiz.bku.gui.BKUGUIFacade; -import at.gv.egiz.bku.smccstal.SecureViewer; +import at.gv.egiz.bku.gui.hashdata.HashDataInputLoader; +import at.gv.egiz.bku.gui.viewer.SecureViewer; import at.gv.egiz.stal.HashDataInput; +import at.gv.egiz.stal.SignatureInfo; +import at.gv.egiz.stal.hashdata.StubHashDataInput; import at.gv.egiz.stal.impl.ByteArrayHashDataInput; import at.gv.egiz.stal.service.GetHashDataInputFault; import at.gv.egiz.stal.service.STALPortType; import at.gv.egiz.stal.service.types.GetHashDataInputResponseType; import at.gv.egiz.stal.service.types.GetHashDataInputType; import at.gv.egiz.stal.signedinfo.ReferenceType; -import at.gv.egiz.stal.signedinfo.SignedInfoType; /** * * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> */ -public class AppletSecureViewer implements SecureViewer { +public class AppletSecureViewer implements SecureViewer, HashDataInputLoader { private static final Logger log = LoggerFactory.getLogger(AppletSecureViewer.class); @@ -86,19 +90,19 @@ public class AppletSecureViewer implements SecureViewer { * @throws java.lang.Exception */ @Override - public void displayDataToBeSigned(SignedInfoType signedInfo, + public void displayDataToBeSigned(SignatureInfo signatureInfo, ActionListener okListener, String okCommand) throws DigestException, Exception { if (verifiedDataToBeSigned == null) { - log.info("Retrieve data to be signed for dsig:SignedInfo {}.", signedInfo.getId()); + log.info("Retrieve data to be signed for dsig:SignedInfo {}.", signatureInfo.getId()); List hdi = - getHashDataInput(signedInfo.getReference()); - verifiedDataToBeSigned = verifyHashDataInput(signedInfo.getReference(), + getHashDataInput(signatureInfo.getReference()); + verifiedDataToBeSigned = verifyHashDataInput(signatureInfo.getReference(), hdi); } if (verifiedDataToBeSigned.size() > 0) { - gui.showSecureViewer(verifiedDataToBeSigned, okListener, okCommand); + gui.showSecureViewer(verifiedDataToBeSigned, okListener, okCommand, this); } else { throw new Exception("No data to be signed (apart from any QualifyingProperties or a Manifest)"); } @@ -119,14 +123,16 @@ public class AppletSecureViewer implements SecureViewer { //don't get Manifest, QualifyingProperties, ... if (signedRef.getType() == null) { String signedRefId = signedRef.getId(); - if (signedRefId != null) { - log.trace("Requesting hashdata input for reference {}.", signedRefId); + byte[] digest = signedRef.getDigestValue(); + if (signedRefId != null || digest != null) { + log.trace("Requesting hashdata input for reference {}.", new String(digest)); GetHashDataInputType.Reference ref = new GetHashDataInputType.Reference(); ref.setID(signedRefId); + ref.setDigest(digest); request.getReference().add(ref); } else { - throw new Exception("Cannot resolve signature data for dsig:Reference without Id attribute"); + throw new Exception("Cannot resolve signature data for dsig:Reference without Id or digest attribute"); } } } @@ -259,4 +265,76 @@ public class AppletSecureViewer implements SecureViewer { } return md.digest(hashDataInput); } + + @Override + public void displayDataToBeSigned(List signatureInfoList, ActionListener okListener, String okCommand) + throws DigestException, Exception { + + log.trace("Creating referenceMap"); + + for (SignatureInfo signatureInfo : signatureInfoList) { + for (ReferenceType reference : signatureInfo.getReference()) { + log.trace("Adding entry {} : {} to referenceMap", reference.getDigestValue(), reference.getId()); + } + } + + ArrayList selectedHashDataInputs = new ArrayList(); + + log.trace("Adding empty hashDataInputs to selectedHashDataInputs"); + for (SignatureInfo nextSignatureInfo : signatureInfoList) { + log.trace("Adding {} : {} to selectedHashDataInputs", nextSignatureInfo.getId(), nextSignatureInfo.getReference().get(0).getDigestValue()); + selectedHashDataInputs.addAll(addEmptyHashDataInputs(nextSignatureInfo)); + } + + log.trace("Show Secure Viewer for selectedHashDataInputs"); + gui.showSecureViewer(selectedHashDataInputs, okListener, okCommand, this); + + } + + + @Override + public HashDataInput getHashDataInput(HashDataInput hashDataInput) throws Exception { + + if (hashDataInput instanceof StubHashDataInput) { + + StubHashDataInput stabHashDataInput = (StubHashDataInput) hashDataInput; + + ReferenceType reference = stabHashDataInput.getReference(); + + List hashDataInputs = new LinkedList(); + + if (reference != null) { + log.trace("Retrieve data to be signed for dsig:SignedInfo {}.", hashDataInput.getReferenceId()); + List hdi = getHashDataInput(Arrays.asList(reference)); + hashDataInputs = verifyHashDataInput(Arrays.asList(reference), hdi); + + if (hashDataInputs.size() == 0) { + throw new Exception("No data to be signed (apart from any QualifyingProperties or a Manifest)"); + } + + return hashDataInputs.get(0); + } + + throw new Exception("No reference found for hashDataInput with id " + hashDataInput.getReferenceId()); + } + return hashDataInput; + } + + private Collection addEmptyHashDataInputs(SignatureInfo signedInfo) throws Exception { + if (signedInfo.getReference().size() == 0) { + log.error("No hashdata input selected to be displayed: null."); + throw new Exception("No HashData Input selected to be displayed."); + } + + log.trace("Adding HashDataInputs from signedInfo"); + ArrayList selectedHashDataInputs = new ArrayList(); + for (ReferenceType dsigRef : signedInfo.getReference()) { + + if (dsigRef.getType() == null) { + log.trace("Adding HashDataInput with id {}, name {} of type {}",new Object[]{dsigRef.getId(), signedInfo.getDisplayName(), signedInfo.getMimeType()}); + selectedHashDataInputs.add(new StubHashDataInput(dsigRef, signedInfo.getDisplayName(), signedInfo.getMimeType())); + } + } + return selectedHashDataInputs; + } } diff --git a/BKUApplet/src/test/java/at/gv/egiz/stal/client/STALServiceTest.java b/BKUApplet/src/test/java/at/gv/egiz/stal/client/STALServiceTest.java index f3967619..057a9c90 100644 --- a/BKUApplet/src/test/java/at/gv/egiz/stal/client/STALServiceTest.java +++ b/BKUApplet/src/test/java/at/gv/egiz/stal/client/STALServiceTest.java @@ -69,8 +69,8 @@ public class STALServiceTest { // req.getResponse().add(new ErrorResponse(1234)); GetNextRequestResponseType nrResp = port.getNextRequest(nrReq); assertNotNull(nrResp); - System.out.println("got response: " + nrResp.getInfoboxReadRequestOrSignRequestOrQuitRequest().size()); - for (JAXBElement stalReqElt : nrResp.getInfoboxReadRequestOrSignRequestOrQuitRequest()) { + System.out.println("got response: " + nrResp.getInfoboxReadRequestOrSignRequestOrBulkSignRequest().size()); + for (JAXBElement stalReqElt : nrResp.getInfoboxReadRequestOrSignRequestOrBulkSignRequest()) { RequestType stalReq = stalReqElt.getValue(); if (stalReq instanceof InfoboxReadRequestType) { String ibid = ((InfoboxReadRequestType) stalReq).getInfoboxIdentifier(); diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/GetCertificateBKUWorker.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/GetCertificateBKUWorker.java index f05cccc4..f7fa584f 100644 --- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/GetCertificateBKUWorker.java +++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/GetCertificateBKUWorker.java @@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory; import at.gv.egiz.bku.gui.BKUGUIFacade; import at.gv.egiz.bku.gui.GetCertificateGUIFacade; import at.gv.egiz.bku.smccstal.GetCertificateRequestHandler; +import at.gv.egiz.stal.BulkSignRequest; import at.gv.egiz.stal.ErrorResponse; import at.gv.egiz.stal.InfoboxReadRequest; import at.gv.egiz.stal.QuitRequest; @@ -53,6 +54,7 @@ public class GetCertificateBKUWorker extends AppletBKUWorker { super(applet, gui); removeRequestHandler(InfoboxReadRequest.class); removeRequestHandler(SignRequest.class); + removeRequestHandler(BulkSignRequest.class); addRequestHandler(GetCertificateRequest.class, new GetCertificateRequestHandler()); } diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/HardwareInfoBKUWorker.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/HardwareInfoBKUWorker.java index 617b1612..15c584fe 100644 --- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/HardwareInfoBKUWorker.java +++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/HardwareInfoBKUWorker.java @@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory; import at.gv.egiz.bku.gui.BKUGUIFacade; import at.gv.egiz.bku.gui.GetHardwareInfoGUIFacade; import at.gv.egiz.bku.smccstal.GetHardwareInfoRequestHandler; +import at.gv.egiz.stal.BulkSignRequest; import at.gv.egiz.stal.ErrorResponse; import at.gv.egiz.stal.InfoboxReadRequest; import at.gv.egiz.stal.QuitRequest; @@ -52,6 +53,7 @@ public class HardwareInfoBKUWorker extends AppletBKUWorker { super(applet, gui); removeRequestHandler(InfoboxReadRequest.class); removeRequestHandler(SignRequest.class); + removeRequestHandler(BulkSignRequest.class); addRequestHandler(GetHardwareInfoRequest.class, new GetHardwareInfoRequestHandler()); } diff --git a/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/IdentityLinkBKUWorker.java b/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/IdentityLinkBKUWorker.java index 8ede2be1..1b5642ec 100644 --- a/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/IdentityLinkBKUWorker.java +++ b/BKUAppletExt/src/main/java/at/gv/egiz/bku/online/applet/IdentityLinkBKUWorker.java @@ -33,6 +33,7 @@ import org.slf4j.LoggerFactory; import at.gv.egiz.bku.gui.BKUGUIFacade; import at.gv.egiz.bku.gui.IdentityLinkGUIFacade; import at.gv.egiz.bku.smccstal.IdentityLinkRequestHandler; +import at.gv.egiz.stal.BulkSignRequest; import at.gv.egiz.stal.ErrorResponse; import at.gv.egiz.stal.InfoboxReadRequest; import at.gv.egiz.stal.QuitRequest; @@ -48,6 +49,7 @@ public class IdentityLinkBKUWorker extends AppletBKUWorker { super(applet, gui); removeRequestHandler(InfoboxReadRequest.class); removeRequestHandler(SignRequest.class); + removeRequestHandler(BulkSignRequest.class); addRequestHandler(IdentityLinkRequest.class, new IdentityLinkRequestHandler()); } diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java index 5de6a9e0..c128ceab 100644 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java @@ -24,8 +24,10 @@ package at.gv.egiz.bku.gui; - import at.gv.egiz.stal.HashDataInput; +import at.gv.egiz.bku.gui.hashdata.HashDataInputLoader; import at.gv.egiz.smcc.PinInfo; + import at.gv.egiz.stal.HashDataInput; + import java.awt.Color; import java.awt.event.ActionListener; import java.util.List; @@ -67,6 +69,7 @@ public interface BKUGUIFacade { public static final String TITLE_INSERTCARD = "title.insertcard"; public static final String TITLE_CARD_NOT_SUPPORTED = "title.cardnotsupported"; public static final String TITLE_VERIFY_PIN = "title.verify.pin"; + public static final String TITLE_OVERRULE_PINPAD = "title.overrule.pinpad"; public static final String TITLE_SIGN = "title.sign"; public static final String TITLE_VERIFY_PINPAD = "title.verify.pinpad"; public static final String TITLE_ERROR = "title.error"; @@ -74,6 +77,7 @@ public interface BKUGUIFacade { public static final String TITLE_ENTRY_TIMEOUT = "title.entry.timeout"; public static final String TITLE_RETRY = "title.retry"; public static final String TITLE_WAIT = "title.wait"; + public static final String TITLE_BULKSIGNATURE = "title.bulksign"; public static final String TITLE_SIGNATURE_DATA = "title.signature.data"; public static final String WINDOWTITLE_SAVE = "windowtitle.save"; public static final String WINDOWTITLE_ERROR = "windowtitle.error"; @@ -89,6 +93,7 @@ public interface BKUGUIFacade { public static final String MESSAGE_CARD_NOT_SUPPORTED = "cardnotsupported"; public static final String MESSAGE_ENTERPIN = "enterpin"; public static final String MESSAGE_ENTERPIN_PINPAD = "enterpin.pinpad"; + public static final String MESSAGE_OVERRULE_PINPAD = "overrule.pinpad"; public static final String MESSAGE_ENTERPIN_PINPAD_DIRECT = "enterpin.pinpad.direct"; public static final String MESSAGE_HASHDATALINK = "hashdatalink"; public static final String MESSAGE_HASHDATALINK_TINY = "hashdatalink.tiny"; @@ -103,6 +108,7 @@ public interface BKUGUIFacade { public static final String MESSAGE_LAST_RETRY_PINPAD = "retries.pinpad.last"; public static final String MESSAGE_OVERWRITE = "overwrite"; public static final String MESSAGE_HELP = "help"; + public static final String MESSAGE_BULKSIGN = "bulksign"; public static final String WARNING_XHTML = "warning.xhtml"; public static final String WARNING_CERT_NOTYETVALID = "warning.cert.notyetvalid"; @@ -165,6 +171,11 @@ public interface BKUGUIFacade { ActionListener cancelListener, String cancelCommand, ActionListener viewerListener, String viewerCommand); + public void showSignaturePINDialog(PinInfo pinSpec, int numRetries, int numSignatures, + ActionListener signListener, String signCommand, + ActionListener cancelListener, String cancelCommand, + ActionListener viewerListener, String viewerCommand); + public char[] getPin(); /** @@ -176,7 +187,7 @@ public interface BKUGUIFacade { * @param backCommand */ public void showSecureViewer(List dataToBeSigned, - ActionListener backListener, String backCommand); + ActionListener backListener, String backCommand, HashDataInputLoader hashDataInputLoader); public void showErrorDialog(String errorMsgKey, Object[] errorMsgParams, ActionListener okListener, String okCommand); @@ -196,8 +207,14 @@ public interface BKUGUIFacade { public void showMessageDialog(String titleKey, String msgKey, Object[] msgParams); + void updateMessageDialog(String titleKey, + String msgKey, Object[] msgParams, String buttonKey, ActionListener okListener, String okCommand); + public void showMessageDialog(String titleKey, String msgKey); public void getFocusFromBrowser(); + + public void showPinPadDeactivationDialog(ActionListener okListener, String okCommand, + ActionListener cancelListener, String cancelCommand); } diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java index 82513a0e..13e330bf 100644 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java @@ -25,6 +25,7 @@ package at.gv.egiz.bku.gui; +import at.gv.egiz.bku.gui.hashdata.HashDataInputLoader; import at.gv.egiz.bku.gui.viewer.FontProviderException; import at.gv.egiz.bku.gui.viewer.FontProvider; import at.gv.egiz.bku.gui.viewer.SecureViewerSaveDialog; @@ -67,6 +68,7 @@ import javax.swing.JPasswordField; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.LayoutStyle; +import javax.swing.LayoutStyle.ComponentPlacement; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.UIManager; @@ -90,7 +92,7 @@ public class BKUGUIImpl implements BKUGUIFacade { } protected Component primaryFocusHolder; - protected SecureViewerDialog secureViewer; + protected SecureViewerDialog secureViewerDialog; protected HelpListener helpListener; protected FontProvider fontProvider; @@ -155,7 +157,9 @@ public class BKUGUIImpl implements BKUGUIFacade { // protected HashDataInput storedSelection; protected List signedReferences; protected Integer referenceIndex; - private at.gv.egiz.bku.gui.BKUGUIImpl.SignedReferencesSelectionListener.SignedReferencesListDisplayer storedBackToListListener; + protected at.gv.egiz.bku.gui.BKUGUIImpl.SignedReferencesSelectionListener.SignedReferencesListDisplayer storedBackToListListener; + + protected HashDataInputLoader hashDataInputLoader; /** * set contentPane init message bundle configure the style register the help @@ -1205,6 +1209,15 @@ public class BKUGUIImpl implements BKUGUIFacade { final ActionListener signListener, final String signCommand, final ActionListener cancelListener, final String cancelCommand, final ActionListener hashdataListener, final String hashdataCommand) { + showSignaturePINDialog(pinSpec, numRetries, 1, signListener, signCommand, cancelListener, cancelCommand, + hashdataListener, hashdataCommand); + } + + @Override + public void showSignaturePINDialog(final PinInfo pinSpec, final int numRetries, final int numSignatures, + final ActionListener signListener, final String signCommand, + final ActionListener cancelListener, final String cancelCommand, + final ActionListener hashdataListener, final String hashdataCommand) { log.debug("Scheduling signature-pin dialog."); @@ -1228,7 +1241,9 @@ public class BKUGUIImpl implements BKUGUIFacade { if (renderHeaderPanel) { if (numRetries < 0) { - titleLabel.setText(getMessage(TITLE_SIGN)); + String msgPattern = getMessage(TITLE_SIGN); + String msg = MessageFormat.format(msgPattern, numSignatures); + titleLabel.setText(msg); } else { titleLabel.setText(getMessage(TITLE_RETRY)); } @@ -1571,6 +1586,35 @@ public class BKUGUIImpl implements BKUGUIFacade { showMessageDialog(titleKey, null, msgKey, msgParams, null, null, null); } + + @Override + public void updateMessageDialog(final String titleKey, final String msgKey, + final Object[] msgParams, String buttonKey, + final ActionListener okListener, final String okCommand) { + + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + + log.debug("[{}] Update message dialog.", Thread.currentThread().getName()); + + + if (renderHeaderPanel) { + titleLabel.setText(getMessage(titleKey)); + } + + helpListener.setHelpTopic(msgKey); + + String msgPattern = getMessage(msgKey); + String msg = MessageFormat.format(msgPattern, msgParams); + + msgLabel.setText(msg); + + } + }); + } + @Override public void showMessageDialog(final String titleKey, final String msgKey) { @@ -1718,6 +1762,158 @@ public class BKUGUIImpl implements BKUGUIFacade { }); } + + private void showOptionDialog(final String titleKey, final String msgKey, final Object[] msgParams, + final String cancelButtonKey, final String okButtonKey, final ActionListener cancelListener, + final String cancelCommand, final ActionListener okListener, final String okCommand) { + + log.debug("Scheduling message dialog."); + + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + + log.debug("[{}] Show option dialog.", Thread.currentThread().getName()); + + log.debug("ButtonKey: {}.", okButtonKey); + + log.debug("ButtonKey: {}.", cancelButtonKey); + + mainPanel.removeAll(); + buttonPanel.removeAll(); + + if (renderHeaderPanel) { + titleLabel.setText(getMessage(titleKey)); + } + + helpListener.setHelpTopic(msgKey); + + String msgPattern = getMessage(msgKey); + String msg = MessageFormat.format(msgPattern, msgParams); + + // we need to create a new JLabel object every time in order to + // ensure + // that screen reading software will read each updated label + msgLabel = new JLabel(); + + msgLabel.setFocusable(true); + + msgLabel.setFont(msgLabel.getFont().deriveFont( + msgLabel.getFont().getStyle() & ~Font.BOLD)); + msgLabel.setText(msg); + + GroupLayout mainPanelLayout = new GroupLayout(mainPanel); + mainPanel.setLayout(mainPanelLayout); + + GroupLayout.ParallelGroup mainHorizontal = mainPanelLayout + .createParallelGroup(GroupLayout.Alignment.LEADING); + GroupLayout.SequentialGroup mainVertical = mainPanelLayout + .createSequentialGroup(); + + String accessibleData = ""; + + if (!renderHeaderPanel) { + msgTitleLabel = new JLabel(); + msgTitleLabel.setFont(msgTitleLabel.getFont().deriveFont( + msgTitleLabel.getFont().getStyle() | Font.BOLD)); + msgTitleLabel.setText(getMessage(titleKey)); + + accessibleData = accessibleData + getMessage(titleKey); + + GroupLayout.SequentialGroup titleHorizontal = mainPanelLayout + .createSequentialGroup() + .addComponent(msgTitleLabel); + + GroupLayout.ParallelGroup titleVertical = mainPanelLayout + .createParallelGroup(GroupLayout.Alignment.LEADING) + .addComponent(msgTitleLabel); + + if (helpListener.implementsListener()) { + titleHorizontal.addPreferredGap( + LayoutStyle.ComponentPlacement.UNRELATED, 0, + Short.MAX_VALUE).addComponent(helpLabel); + titleVertical.addComponent(helpLabel); + } + + mainHorizontal.addGroup(titleHorizontal); + mainVertical.addGroup(titleVertical); + + } else { + + accessibleData = accessibleData + titleLabel.getText(); + } + + msgLabel.getAccessibleContext().setAccessibleName( + accessibleData + msgLabel.getText()); + msgLabel.getAccessibleContext().setAccessibleDescription( + accessibleData + msgLabel.getText()); + + mainPanelLayout.setHorizontalGroup(mainHorizontal + .addComponent(msgLabel)); + mainPanelLayout.setVerticalGroup(mainVertical + .addComponent(msgLabel)); + + + cancelButton.setFont(cancelButton.getFont().deriveFont(cancelButton.getFont().getStyle() & ~java.awt.Font.BOLD)); + cancelButton.setText(getMessage((cancelButtonKey != null) ? cancelButtonKey : BUTTON_CANCEL)); + cancelButton.setActionCommand(okCommand); + cancelButton.addActionListener(okListener); + + okButton.setFont(okButton.getFont().deriveFont(okButton.getFont().getStyle() & ~java.awt.Font.BOLD)); + okButton.setText(getMessage((okButtonKey != null) ? okButtonKey : BUTTON_OK)); + okButton.setActionCommand(cancelCommand); + okButton.addActionListener(okListener); + + primaryFocusHolder = okButton; + + renderShowOptionDialogueButtonPanel(); + + GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel); + buttonPanel.setLayout(buttonPanelLayout); + + buttonPanelLayout.setHorizontalGroup(buttonPanelLayout + .createSequentialGroup().addComponent(okButton, + GroupLayout.PREFERRED_SIZE, buttonSize, + GroupLayout.PREFERRED_SIZE)); + buttonPanelLayout.setVerticalGroup(buttonPanelLayout + .createSequentialGroup().addComponent(okButton)); + + // okListener might be null (up to windowCloseAdapter what to do) + if (windowCloseAdapter != null) { + windowCloseAdapter.registerListener(okListener, okCommand); + } + + updateMethodToRunAtResize("at.gv.egiz.bku.gui.BKUGUIImpl", + "renderShowOptionDialogueButtonPanel"); + + // put focus to msgLabel to guarantee that label is read by + // screen reader upon loading + msgLabel.requestFocus(); + msgLabel.setFocusable(false); + + contentPanel.validate(); + + resize(); + } + }); + } + + + public void renderShowOptionDialogueButtonPanel() { + + GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel); + buttonPanel.setLayout(buttonPanelLayout); + + buttonPanelLayout.setHorizontalGroup(buttonPanelLayout.createSequentialGroup() + .addComponent(cancelButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE) + .addComponent(okButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE) + .addPreferredGap(ComponentPlacement.UNRELATED)); + + buttonPanelLayout.setVerticalGroup(buttonPanelLayout.createParallelGroup().addComponent(cancelButton).addComponent(okButton)); + +} + public void renderShowMessageDialogueButtonPanel() { if (showMessageOKButton) { @@ -1757,7 +1953,9 @@ public class BKUGUIImpl implements BKUGUIFacade { */ @Override public void showSecureViewer(final List dataToBeSigned, - final ActionListener backListener, final String backCommand) { + final ActionListener backListener, final String backCommand, HashDataInputLoader hashDataInputLoader) { + + this.hashDataInputLoader = hashDataInputLoader; if (dataToBeSigned == null) { showErrorDialog(getMessage(ERR_NO_HASHDATA), @@ -1819,7 +2017,7 @@ public class BKUGUIImpl implements BKUGUIFacade { throws FontProviderException { log.debug("[{}] Show secure viewer.", Thread.currentThread().getName()); - secureViewer = new SecureViewerDialog(null, messages, closeListener, + secureViewerDialog = new SecureViewerDialog(null, messages, closeListener, closeCommand, fontProvider, helpListener, getResizeFactor()); // workaround for [#439] @@ -1829,56 +2027,55 @@ public class BKUGUIImpl implements BKUGUIFacade { //Window window = SwingUtilities.getWindowAncestor(contentPane); //if (window != null && window.isAlwaysOnTop()) { log.debug("Make secureViewer alwaysOnTop."); - secureViewer.setAlwaysOnTop(true); + secureViewerDialog.setAlwaysOnTop(true); //} - secureViewer.setContent(dataToBeSigned); + secureViewerDialog.setContent(dataToBeSigned); log.trace("Viewer setContent returned."); } private void openSecureViewerDialog() { - final HashDataInput storedSelection = signedReferences.get(referenceIndex); + try { + + log.trace("Opening SecureViewer dialog for list entry {}", referenceIndex); + final HashDataInput storedSelection = hashDataInputLoader.getHashDataInput(signedReferences.get(referenceIndex)); - if (SecureViewerDialog.SUPPORTED_MIME_TYPES.contains(storedSelection - .getMimeType())) { + if (SecureViewerDialog.SUPPORTED_MIME_TYPES.contains(storedSelection.getMimeType())) { log.debug("[{}] Scheduling secure viewer dialog.", Thread.currentThread().getName()); - showMessageDialog(TITLE_SIGNATURE_DATA, - MESSAGE_HASHDATA_VIEWER); + showMessageDialog(TITLE_SIGNATURE_DATA, MESSAGE_HASHDATA_VIEWER); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { try { - showSecureViewer(storedSelection, storedBackToListListener, - null); + showSecureViewer(storedSelection, storedBackToListListener, null); // SecureViewerDialog.showSecureViewer(selection, // messages, fontProvider, // helpMouseListener.getActionListener(), // false); } catch (FontProviderException ex) { log.error("Failed to display secure viewer.", ex); - showErrorDialog(BKUGUIFacade.ERR_VIEWER, - new Object[] { ex.getMessage() }, - storedBackToListListener, null); + showErrorDialog(BKUGUIFacade.ERR_VIEWER, new Object[] { ex.getMessage() }, storedBackToListListener, null); } } }); } else { - log.debug("[{}] Mime-type not supported by secure viewer, " + - "scheduling save dialog.", Thread.currentThread().getName()); - showMessageDialog(BKUGUIFacade.TITLE_SIGNATURE_DATA, - BKUGUIFacade.MESSAGE_UNSUPPORTED_MIMETYPE, + log.debug("[{}] Mime-type not supported by secure viewer, " + "scheduling save dialog.", Thread.currentThread() + .getName()); + showMessageDialog(BKUGUIFacade.TITLE_SIGNATURE_DATA, BKUGUIFacade.MESSAGE_UNSUPPORTED_MIMETYPE, new Object[] { storedSelection.getMimeType() }); - SecureViewerSaveDialog.showSaveDialog(contentPane, storedSelection, messages, - storedBackToListListener, null, + SecureViewerSaveDialog.showSaveDialog(contentPane, storedSelection, messages, storedBackToListListener, null, (int) (baseFontSize * getResizeFactor())); } - + } catch (Exception ex) { + log.error("Failed to display secure viewer.", ex); + showErrorDialog(BKUGUIFacade.ERR_VIEWER, new Object[] { ex.getMessage() }, storedBackToListListener, null); + } } private void showSignedReferencesListDialog( @@ -2446,9 +2643,9 @@ public class BKUGUIImpl implements BKUGUIFacade { } - if (secureViewer != null && secureViewer.isVisible()) { + if (secureViewerDialog != null && secureViewerDialog.isVisible()) { - secureViewer.resize(factor); + secureViewerDialog.resize(factor); } try { @@ -2682,4 +2879,12 @@ public class BKUGUIImpl implements BKUGUIFacade { } } } + + @Override + public void showPinPadDeactivationDialog(ActionListener okListener, String okCommand, ActionListener cancelListener, + String cancelCommand) { + + showOptionDialog(TITLE_OVERRULE_PINPAD, MESSAGE_OVERRULE_PINPAD, null, null, null, cancelListener, cancelCommand, okListener, okCommand); + + } } diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/hashdata/HashDataInputLoader.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/hashdata/HashDataInputLoader.java new file mode 100644 index 00000000..1946dd2d --- /dev/null +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/hashdata/HashDataInputLoader.java @@ -0,0 +1,16 @@ +package at.gv.egiz.bku.gui.hashdata; + +import at.gv.egiz.stal.HashDataInput; + +public interface HashDataInputLoader { + + + + /** + * Loads input data of referenced HashDataInput. + * @param hashDataInput HashDataInput without content that references a HashDataInput at server side with digest or referenceId. + * @return HashDataInput Referenced HashDataInput from server-side including content. + * @throws Exception + */ + HashDataInput getHashDataInput(HashDataInput hashDataInput) throws Exception; +} diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewer.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewer.java new file mode 100644 index 00000000..02e0ceb8 --- /dev/null +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewer.java @@ -0,0 +1,58 @@ +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * 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.gui.viewer; + +import at.gv.egiz.stal.SignatureInfo; + +import java.awt.event.ActionListener; +import java.util.List; + +/** + * + * @author Clemens Orthacker + */ +public interface SecureViewer { + + /** + * Displays the hashdata inputs for all provided dsig:SignedReferences. + * Implementations may verify the digest value if necessary. + * (LocalSignRequestHandler operates on DataObjectHashDataInput, + * other SignRequestHandlers should cache the HashDataInputs obtained by webservice calls, + * or simply forward to a HashDataInputServlet.) + * @param signedReferences The caller may select a subset of the references in SignedInfo to be displayed. + * @throws java.security.DigestException if digest values are verified and do not correspond + * (or any other digest computation error occurs) + * @throws java.lang.Exception + */ + void displayDataToBeSigned(SignatureInfo signatureInfo, + ActionListener okListener, String okCommand) + throws Exception; + + + void displayDataToBeSigned(List signatureInfo, + ActionListener okListener, String okCommand) + throws Exception; + +} diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/stal/impl/ByteArrayHashDataInput.java b/BKUCommonGUI/src/main/java/at/gv/egiz/stal/impl/ByteArrayHashDataInput.java index a28b3b56..ecf5f364 100644 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/stal/impl/ByteArrayHashDataInput.java +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/stal/impl/ByteArrayHashDataInput.java @@ -41,6 +41,7 @@ public class ByteArrayHashDataInput implements HashDataInput { private final Logger log = LoggerFactory.getLogger(ByteArrayHashDataInput.class); protected byte[] hashData; + protected byte[] digest; protected String id; protected String mimeType; protected String encoding; @@ -57,6 +58,18 @@ public class ByteArrayHashDataInput implements HashDataInput { this.filename = filename; } + public ByteArrayHashDataInput(byte[] hashData, String id, String mimeType, String encoding, String filename, byte[] digest) { + if (hashData == null) { + throw new NullPointerException("HashDataInput not provided."); + } + this.hashData = hashData; + this.id = id; + this.mimeType = mimeType; + this.encoding = encoding; + this.filename = filename; + this.digest = digest; + } + /** * caches the hashdata input's stream * @param hdi to be cached @@ -65,9 +78,9 @@ public class ByteArrayHashDataInput implements HashDataInput { if (hdi == null) { throw new NullPointerException("HashDataInput not provided."); } + try { InputStream is = hdi.getHashDataInput(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try { byte[] buffer = new byte[1024]; for (int i = is.read(buffer); i > -1; i = is.read(buffer)) { baos.write(buffer, 0, i); @@ -111,5 +124,10 @@ public class ByteArrayHashDataInput implements HashDataInput { return filename; } + @Override + public byte[] getDigest() { + return digest; + } + } diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties index 434798ee..f7907561 100644 --- a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties @@ -23,8 +23,10 @@ title.welcome=Welcome title.insertcard=No citizen card found title.cardnotsupported=This card is not supported title.verify.pin=Reading card -title.sign=Create signature +title.sign=Create {0,choice,1#signature|1<{0} signatures} +title.bulksign=Create bulk signature title.verify.pinpad=Enter PIN and confirm +title.overrule.pinpad=Allow keyboard input title.error=Error title.warning=Warning title.entry.timeout=Timeout @@ -41,11 +43,13 @@ windowtitle.help=Citizen card help # removed message.* prefix to reuse keys as help keys welcome=Please wait... wait=Please wait... +bulksign=Signing document {0} of {1} insertcard=Please insert your citizen card into the reader cardnotsupported=Please insert your citizen card into the reader enterpin=Enter {0} enterpin.pinpad=Enter PIN on card reader pinpad and confirm enterpin.pinpad.direct=Enter {0} ({1} digits) on card reader pinpad and confirm +overrule.pinpad=Pin input on smart card reader is not supported for bulk signature requests. hashdatalink=Display signature data hashdatalink.tiny=signature data hashdatalink.focus=[Display signature data] diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_de.properties b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_de.properties index 72da80ce..5d3def07 100644 --- a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_de.properties +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_de.properties @@ -23,8 +23,10 @@ title.welcome=Willkommen title.insertcard=Keine B\u00fcrgerkarte gefunden title.cardnotsupported=Die Karte wird nicht unterst\u00fctzt title.verify.pin=Karte wird gelesen -title.sign=Signatur erstellen +title.sign={0,choice,1#Signatur|1<{0} Signaturen} erstellen +title.bulksign=Stapelsignatur erstellen title.verify.pinpad=PIN eingeben und best\u00E4tigen +title.overrule.pinpad=Tastatureingabe freigeben title.error=Fehler title.warning=Achtung title.entry.timeout=Zeit\u00fcberschreitung @@ -41,11 +43,13 @@ windowtitle.help=Hilfe zur B\u00fcrgerkarte # removed message.* prefix to reuse keys as help keys welcome=Bitte warten... wait=Bitte warten... +bulksign=Signiere Dokument {0} von {1} cardnotsupported=Bitte die B\u00fcrgerkarte in den Kartenleser stecken insertcard=Bitte die B\u00fcrgerkarte in den Kartenleser stecken enterpin={0} eingeben enterpin.pinpad=PIN am Kartenleser eingeben und best\u00E4tigen enterpin.pinpad.direct={0} ({1} stellig) am Kartenleser eingeben und best\u00E4tigen +overrule.pinpad=Die Stapelsignatur unterst\u00ftzt keine Pin Eingabe am Kartenleser. hashdatalink=Signaturdaten anzeigen hashdatalink.tiny=Signaturdaten hashdatalink.focus=[Signaturdaten anzeigen] diff --git a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java index 36e5ea0d..6866f51d 100644 --- a/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java +++ b/BKUCommonGUI/src/test/java/at/gv/egiz/bku/gui/BKUGUIWorker.java @@ -120,7 +120,7 @@ public class BKUGUIWorker implements Runnable { // signedRefs.add(signedRef4); // signedRefs.add(signedRef4); // signedRefs = Collections.singletonList(signedRef1); - gui.showSecureViewer(signedRefs, returnListener, "return"); + gui.showSecureViewer(signedRefs, returnListener, "return", null); } }; diff --git a/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalBKUWorker.java b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalBKUWorker.java index afaad92d..c4125944 100644 --- a/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalBKUWorker.java +++ b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalBKUWorker.java @@ -30,6 +30,7 @@ import at.gv.egiz.bku.smccstal.GetCertificateRequestHandler; import at.gv.egiz.bku.smccstal.GetHardwareInfoRequestHandler; import at.gv.egiz.bku.smccstal.PINManagementRequestHandler; import at.gv.egiz.bku.smccstal.IdentityLinkRequestHandler; +import at.gv.egiz.stal.BulkSignRequest; import at.gv.egiz.stal.QuitRequest; import at.gv.egiz.stal.STALRequest; import at.gv.egiz.stal.STALResponse; @@ -53,8 +54,8 @@ public class LocalBKUWorker extends AbstractBKUWorker { public LocalBKUWorker(BKUGUIFacade gui, JFrame container) { super(gui); this.container = container; - addRequestHandler(SignRequest.class, - new LocalSignRequestHandler(new LocalSecureViewer(gui))); + addRequestHandler(SignRequest.class, new LocalSignRequestHandler(new LocalSecureViewer(gui))); + addRequestHandler(BulkSignRequest.class, new LocalBulkSignRequestHandler(new LocalSecureViewer(gui))); addRequestHandler(PINManagementRequest.class, new PINManagementRequestHandler()); addRequestHandler(IdentityLinkRequest.class, new IdentityLinkRequestHandler()); addRequestHandler(GetCertificateRequest.class, new GetCertificateRequestHandler()); diff --git a/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalBulkSignRequestHandler.java b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalBulkSignRequestHandler.java new file mode 100644 index 00000000..6ae4496d --- /dev/null +++ b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalBulkSignRequestHandler.java @@ -0,0 +1,82 @@ +/* + * 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.local.stal; + +import java.util.LinkedList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.bku.smccstal.BulkSignRequestHandler; +import at.gv.egiz.stal.BulkSignRequest; +import at.gv.egiz.stal.ErrorResponse; +import at.gv.egiz.stal.HashDataInput; +import at.gv.egiz.stal.STALRequest; +import at.gv.egiz.stal.STALResponse; +import at.gv.egiz.stal.SignRequest; + +/** + * + * @author szoescher + */ +public class LocalBulkSignRequestHandler extends BulkSignRequestHandler { + + private final Logger log = LoggerFactory.getLogger(LocalBulkSignRequestHandler.class); + + public LocalBulkSignRequestHandler(LocalSecureViewer secureViewer) { + super(secureViewer); + } + + /** + * If the request is a SIGN request, it contains a list of DataObjectHashDataInput + * providing the pre-digested input stream (that can be obtained repeatedly) if + * reference caching is enabled (or null otherwise). + * @param request + * @return + */ + @Override + public STALResponse handleRequest(STALRequest request) throws InterruptedException { + + if (request instanceof BulkSignRequest) { + + BulkSignRequest bulkSignRequest = (BulkSignRequest) request; + + List hashDataInputs = new LinkedList(); + + for(SignRequest signRequest : bulkSignRequest.getSignRequests()){ + + hashDataInputs.addAll(signRequest.getHashDataInput()); + } + + ((LocalSecureViewer) secureViewer).setDataToBeSigned(hashDataInputs); + + return super.handleRequest(request); + } else { + log.error("Got unexpected STAL request: {}.", request); + ErrorResponse err = new ErrorResponse(1000); + err.setErrorMessage("Got unexpected STAL request: " + request); + return err; + } + } +} diff --git a/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalSecureViewer.java b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalSecureViewer.java index 5e346aba..25f30463 100644 --- a/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalSecureViewer.java +++ b/BKULocal/src/main/java/at/gv/egiz/bku/local/stal/LocalSecureViewer.java @@ -24,31 +24,43 @@ package at.gv.egiz.bku.local.stal; -import at.gv.egiz.bku.slcommands.impl.DataObjectHashDataInput; -import at.gv.egiz.bku.smccstal.SecureViewer; -import java.io.IOException; -import java.util.ArrayList; +import iaik.me.security.CryptoException; +import iaik.me.security.MessageDigest; -import at.gv.egiz.bku.gui.BKUGUIFacade; -import at.gv.egiz.stal.HashDataInput; -import at.gv.egiz.stal.impl.ByteArrayHashDataInput; -import at.gv.egiz.stal.signedinfo.ReferenceType; -import at.gv.egiz.stal.signedinfo.SignedInfoType; import java.awt.event.ActionListener; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; +import java.security.DigestException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; + +import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import at.gv.egiz.bku.gui.BKUGUIFacade; +import at.gv.egiz.bku.gui.hashdata.HashDataInputLoader; +import at.gv.egiz.bku.gui.viewer.SecureViewer; +import at.gv.egiz.bku.slcommands.impl.DataObjectHashDataInput; +import at.gv.egiz.bku.slcommands.impl.cms.ReferencedHashDataInput; +import at.gv.egiz.stal.HashDataInput; +import at.gv.egiz.stal.SignatureInfo; +import at.gv.egiz.stal.hashdata.StubHashDataInput; +import at.gv.egiz.stal.impl.ByteArrayHashDataInput; +import at.gv.egiz.stal.signedinfo.ReferenceType; + /** * * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> */ -public class LocalSecureViewer implements SecureViewer { +public class LocalSecureViewer implements SecureViewer, HashDataInputLoader { - private final Logger log = LoggerFactory.getLogger(LocalSignRequestHandler.class); + private final Logger log = LoggerFactory.getLogger(LocalSecureViewer.class); private List hashDataInputs = Collections.emptyList(); protected BKUGUIFacade gui; @@ -69,48 +81,23 @@ public class LocalSecureViewer implements SecureViewer { * @throws java.lang.Exception */ @Override - public void displayDataToBeSigned(SignedInfoType signedInfo, + public void displayDataToBeSigned(SignatureInfo signedInfo, ActionListener okListener, String okCommand) throws Exception { - if (signedInfo.getReference().size() == 0) { - log.error("No hashdata input selected to be displayed: null."); - throw new Exception("No HashData Input selected to be displayed."); - } + + log.info("Retrieve data to be signed for dsig:SignedInfo {}.", signedInfo.getId()); + List hdi = getHashDataInputs(signedInfo); + List verifiedDataToBeSigned = verifyHashDataInput(signedInfo.getReference(), hdi.get(0)); ArrayList selectedHashDataInputs = new ArrayList(); - for (ReferenceType dsigRef : signedInfo.getReference()) { - // don't get Manifest, QualifyingProperties, ... - if (dsigRef.getType() == null) { - String dsigRefId = dsigRef.getId(); - if (dsigRefId != null) { - boolean hdiAvailable = false; - for (HashDataInput hashDataInput : hashDataInputs) { - if (dsigRefId.equals(hashDataInput.getReferenceId())) { - log.debug("Display hashdata input for dsig:SignedReference {}.", - dsigRefId); - selectedHashDataInputs.add( - ensureCachedHashDataInput(hashDataInput)); - hdiAvailable = true; - break; - } - } - if (!hdiAvailable) { - log.error("No hashdata input for dsig:SignedReference {}.", dsigRefId); - throw new Exception( - "No HashDataInput available for dsig:SignedReference " + dsigRefId); - } - } else { - throw new Exception( - "Cannot get HashDataInput for dsig:Reference without Id attribute"); - } - } - } + selectedHashDataInputs.addAll(verifiedDataToBeSigned); + if (selectedHashDataInputs.size() < 1) { log.error("dsig:SignedInfo does not contain a data reference."); throw new Exception("dsig:SignedInfo does not contain a data reference."); } - gui.showSecureViewer(selectedHashDataInputs, okListener, okCommand); + gui.showSecureViewer(selectedHashDataInputs, okListener, okCommand, this); } @@ -136,4 +123,218 @@ public class LocalSecureViewer implements SecureViewer { return hashDataInput; } + @Override + public void displayDataToBeSigned(List signedInfo, ActionListener okListener, String okCommand) + throws DigestException, Exception { + log.warn("Called displayDataToBeSigned"); + ArrayList selectedHashDataInputs = new ArrayList(); + + + for (SignatureInfo nextSignedInfo : signedInfo) { + selectedHashDataInputs.addAll(addEmptyHashDataInputs(nextSignedInfo)); + } + + gui.showSecureViewer(selectedHashDataInputs, okListener, okCommand, this); + + } + + + + private Collection addEmptyHashDataInputs(SignatureInfo signedInfo) throws Exception { + if (signedInfo.getReference().size() == 0) { + log.error("No hashdata input selected to be displayed: null."); + throw new Exception("No HashData Input selected to be displayed."); + } + + ArrayList selectedHashDataInputs = new ArrayList(); + for (ReferenceType dsigRef : signedInfo.getReference()) { + + if (dsigRef.getType() == null) { + selectedHashDataInputs.add(new StubHashDataInput(dsigRef, signedInfo.getDisplayName(), signedInfo.getMimeType())); + } + } + return selectedHashDataInputs; + } + + @Override + public HashDataInput getHashDataInput(HashDataInput hashDataInput) throws Exception { + + if (hashDataInput instanceof StubHashDataInput) { + String referenceId = hashDataInput.getReferenceId(); + byte[] digest = hashDataInput.getDigest(); + if (referenceId != null || digest != null) { + boolean hdiAvailable = false; + + for (HashDataInput currentHashDataInput : hashDataInputs) { + + if (Arrays.equals(digest, currentHashDataInput.getDigest())) { + log.debug("Display hashdata input for dsig:SignedReference {}.", referenceId); + + if (currentHashDataInput instanceof ReferencedHashDataInput) { + + ReferenceType reference = ((StubHashDataInput) hashDataInput).getReference(); + return verifyHashDataInput(Arrays.asList(reference), currentHashDataInput).get(0); + + } else { + return (ensureCachedHashDataInput(currentHashDataInput)); + } + + } + } + + if (!hdiAvailable) { + for (HashDataInput currentHashDataInput : hashDataInputs) { + if (referenceId.equals(hashDataInput.getReferenceId())) { + log.debug("Display hashdata input for dsig:SignedReference {}.", referenceId); + if (currentHashDataInput instanceof ReferencedHashDataInput) { + + ReferenceType reference = ((StubHashDataInput) hashDataInput).getReference(); + return verifyHashDataInput(Arrays.asList(reference), currentHashDataInput).get(0); + + } else { + return (ensureCachedHashDataInput(currentHashDataInput)); + } + } + } + } + + if (!hdiAvailable) { + log.error("No hashdata input for dsig:SignedReference {}.", referenceId); + throw new Exception("No HashDataInput available for dsig:SignedReference " + referenceId); + } + } else { + throw new Exception("Cannot get HashDataInput for dsig:Reference without Id or digest attribute"); + } + } + return hashDataInput; + } + + + public List getHashDataInputs(SignatureInfo signedInfo) throws Exception { + + ArrayList selectedHashDataInputs = new ArrayList(); + + if (signedInfo.getReference().size() == 0) { + log.error("No hashdata input selected to be displayed: null."); + throw new Exception("No HashData Input selected to be displayed."); + } + + for (ReferenceType dsigRef : signedInfo.getReference()) { + // don't get Manifest, QualifyingProperties, ... + if (dsigRef.getType() == null) { + HashDataInput emptyHashDataInput = new StubHashDataInput(dsigRef, signedInfo.getDisplayName(), + signedInfo.getMimeType()); + + + selectedHashDataInputs.add(getHashDataInput(emptyHashDataInput)); + + } + } + return selectedHashDataInputs; + } + + private List verifyHashDataInput(List signedReferences, HashDataInput hashDataInput) + throws DigestException, NoSuchAlgorithmException, Exception { + + ArrayList verifiedHashDataInputs = new ArrayList(); + + for (ReferenceType signedRef : signedReferences) { + if (signedRef.getType() == null) { + log.info("Verifying digest for signed reference {}.", signedRef.getId()); + + String signedRefId = signedRef.getId(); + byte[] signedDigest = signedRef.getDigestValue(); + String signedDigestAlg = null; + if (signedRef.getDigestMethod() != null) { + signedDigestAlg = signedRef.getDigestMethod().getAlgorithm(); + } else { + throw new NoSuchAlgorithmException("Failed to verify digest value for reference " + signedRefId + ": no digest algorithm"); + } + + + if (hashDataInput == null) { + throw new Exception("No hashdata input for reference " + signedRefId + " returned by service"); + } + + byte[] hdi = null; + + try { + hdi = IOUtils.toByteArray(hashDataInput.getHashDataInput()); + } catch (IOException e) { + throw new Exception("No hashdata input for reference " + signedRefId + " provided by service.", e); + } + + String mimeType = hashDataInput.getMimeType(); + String encoding = hashDataInput.getEncoding(); + String filename = hashDataInput.getFilename(); + + if (log.isDebugEnabled()) { + log.debug("Digesting reference " + signedRefId + " (" + mimeType + ";" + encoding + ")"); + } + + byte[] hashDataInputDigest; + if ((signedRef.getURI() != null) && signedRef.getURI().startsWith("CMSExcludedByteRange:")) { + String range = signedRef.getURI().substring(21); + int sep = range.indexOf('-'); + int from = Integer.parseInt(range.substring(0, sep)); + int to = Integer.parseInt(range.substring(sep+1)); + + Arrays.fill(hdi, from, to+1, (byte)0); + + + byte[] hashData = new byte[hdi.length - ((to+1) - from)]; + if (from > 0) + System.arraycopy(hdi, 0, hashData, 0, from); + if ((to+1) < hdi.length) + System.arraycopy(hdi, to+1, hashData, from, hdi.length - (to+1)); + hashDataInputDigest = digest(hashData, signedDigestAlg); + } else { + hashDataInputDigest = digest(hdi, signedDigestAlg); + } + + log.debug("Comparing digest to claimed digest value for reference {}.", signedRefId); + if (!Arrays.equals(hashDataInputDigest, signedDigest)) { + log.error("Bad digest value for reference {}.", signedRefId); + throw new DigestException("Bad digest value for reference " + signedRefId); + } + + verifiedHashDataInputs.add(new ByteArrayHashDataInput(hdi, signedRefId, mimeType, encoding, filename)); + } + } + + return verifiedHashDataInputs; +} + + private byte[] digest(byte[] hashDataInput, String mdAlg) throws NoSuchAlgorithmException { + if ("http://www.w3.org/2000/09/xmldsig#sha1".equals(mdAlg)) { + mdAlg = "SHA-1"; + } else if ("http://www.w3.org/2001/04/xmlenc#sha256".equals(mdAlg)) { + mdAlg = "SHA-256"; + } else if ("http://www.w3.org/2001/04/xmlenc#sha224".equals(mdAlg)) { + mdAlg = "SHA-224"; + } else if ("http://www.w3.org/2001/04/xmldsig-more#sha224".equals(mdAlg)) { + mdAlg = "SHA-224"; + } else if ("http://www.w3.org/2001/04/xmldsig-more#sha384".equals(mdAlg)) { + mdAlg = "SHA-384"; + } else if ("http://www.w3.org/2001/04/xmlenc#sha512".equals(mdAlg)) { + mdAlg = "SHA-512"; + } else if ("http://www.w3.org/2001/04/xmldsig-more#md2".equals(mdAlg)) { + mdAlg = "MD2"; + } else if ("http://www.w3.org/2001/04/xmldsig-more#md5".equals(mdAlg)) { + mdAlg = "MD5"; + } else if ("http://www.w3.org/2001/04/xmlenc#ripemd160".equals(mdAlg)) { + mdAlg = "RIPEMD160"; + } else { + throw new NoSuchAlgorithmException("Failed to verify digest value: unsupported digest algorithm " + mdAlg); + } + + MessageDigest md; + try { + md = MessageDigest.getInstance(mdAlg); + } catch (CryptoException e) { + throw new NoSuchAlgorithmException(e); + } + return md.digest(hashDataInput); + } + } diff --git a/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml b/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml index 49d4f57f..304fecfc 100644 --- a/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml +++ b/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml @@ -57,10 +57,10 @@ - - + + + @@ -156,6 +156,14 @@ value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" /> + + + + + @@ -173,6 +181,7 @@ + diff --git a/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALRequestBrokerImpl.java b/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALRequestBrokerImpl.java index eab5c62d..3746b8d1 100644 --- a/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALRequestBrokerImpl.java +++ b/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALRequestBrokerImpl.java @@ -25,6 +25,7 @@ package at.gv.egiz.stal.service.impl; +import at.gv.egiz.stal.BulkSignRequest; import at.gv.egiz.stal.ErrorResponse; import at.gv.egiz.stal.HashDataInput; import at.gv.egiz.stal.QuitRequest; @@ -115,8 +116,25 @@ public class STALRequestBrokerImpl implements STALRequestBroker { // and getHashDataInput() accesses request obj // (requests are cleared only when we receive the response) // DataObjectHashDataInput with reference caching enabled DataObject + + log.info("Adding HashdataInput with id {} and digsest {}", ((SignRequest) stalRequest).getHashDataInput() + .get(0).getReferenceId(), ((SignRequest) stalRequest).getHashDataInput().get(0).getDigest()); hashDataInputs.addAll(((SignRequest) stalRequest).getHashDataInput()); - } else if (stalRequest instanceof QuitRequest) { + } + + if (stalRequest instanceof BulkSignRequest) { + + BulkSignRequest bulkSignRequest = (BulkSignRequest) stalRequest; + + for (SignRequest signRequest : bulkSignRequest.getSignRequests()) { + log.info("Adding HashdataInput with id {} and digsest {}", signRequest.getHashDataInput().get(0) + .getReferenceId(), signRequest.getHashDataInput().get(0).getDigest()); + hashDataInputs.addAll(signRequest.getHashDataInput()); + } + + } + + else if (stalRequest instanceof QuitRequest) { log.trace("Received QuitRequest, do not wait for responses."); log.trace("notifying request consumers"); requests.notify(); diff --git a/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALServiceImpl.java b/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALServiceImpl.java index 836d6538..1819074a 100644 --- a/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALServiceImpl.java +++ b/BKUOnline/src/main/java/at/gv/egiz/stal/service/impl/STALServiceImpl.java @@ -120,7 +120,7 @@ public class STALServiceImpl implements STALPortType { if (stal != null) { List> requestsOut = ((STALRequestBroker) stal).connect(); - response.getInfoboxReadRequestOrSignRequestOrQuitRequest().addAll(requestsOut); + response.getInfoboxReadRequestOrSignRequestOrBulkSignRequest().addAll(requestsOut); if (log.isDebugEnabled()) { StringBuilder sb = new StringBuilder("Returning initial GetNextRequestResponse containing "); @@ -136,7 +136,7 @@ public class STALServiceImpl implements STALPortType { log.error("Failed to get STAL, returning QuitRequest."); QuitRequestType quitT = stalObjFactory.createQuitRequestType(); JAXBElement quit = stalObjFactory.createGetNextRequestResponseTypeQuitRequest(quitT); - response.getInfoboxReadRequestOrSignRequestOrQuitRequest().add(quit); + response.getInfoboxReadRequestOrSignRequestOrBulkSignRequest().add(quit); } return response; @@ -157,7 +157,7 @@ public class STALServiceImpl implements STALPortType { try { - List> responsesIn = request.getInfoboxReadResponseOrSignResponseOrErrorResponse(); + List> responsesIn = request.getInfoboxReadResponseOrSignResponseOrBulkSignResponse(); if (log.isDebugEnabled()) { StringBuilder sb = new StringBuilder("Received GetNextRequest containing "); @@ -186,7 +186,7 @@ public class STALServiceImpl implements STALPortType { if (stal != null) { List> requestsOut = ((STALRequestBroker) stal).nextRequest(responsesIn); - response.getInfoboxReadRequestOrSignRequestOrQuitRequest().addAll(requestsOut); + response.getInfoboxReadRequestOrSignRequestOrBulkSignRequest().addAll(requestsOut); if (log.isDebugEnabled()) { StringBuilder sb = new StringBuilder("Returning GetNextRequestResponse containing "); @@ -202,7 +202,7 @@ public class STALServiceImpl implements STALPortType { log.error("Failed to get STAL, returning QuitRequest."); QuitRequestType quitT = stalObjFactory.createQuitRequestType(); JAXBElement quit = stalObjFactory.createGetNextRequestResponseTypeQuitRequest(quitT); - response.getInfoboxReadRequestOrSignRequestOrQuitRequest().add(quit); + response.getInfoboxReadRequestOrSignRequestOrBulkSignRequest().add(quit); } return response; @@ -242,27 +242,51 @@ public class STALServiceImpl implements STALPortType { if (hashDataInputs != null) { Map hashDataIdMap = new HashMap(); + Map hashDataDigestMap = new HashMap(); for (HashDataInput hdi : hashDataInputs) { if (log.isTraceEnabled()) { log.trace("Provided HashDataInput for reference {}.", hdi.getReferenceId()); } + + + if(hdi.getDigest() != null) { + log.trace("Provided HashDataInput for digest {}.", hdi.getDigest()); + hashDataDigestMap.put(new String(hdi.getDigest()), hdi); + } + + log.trace("Provided HashDataInput for reference {}.", hdi.getReferenceId()); hashDataIdMap.put(hdi.getReferenceId(), hdi); } List reqRefs = request.getReference(); for (GetHashDataInputType.Reference reqRef : reqRefs) { String reqRefId = reqRef.getID(); - HashDataInput reqHdi = hashDataIdMap.get(reqRefId); + String digest = new String(reqRef.getDigest()); + + log.info("looking for digest {}", digest); + HashDataInput reqHdi = hashDataDigestMap.get(digest); + if (reqHdi == null) { + log.info("looking for referenceId {}", reqRefId); + reqHdi = hashDataIdMap.get(reqRefId); + } if (reqHdi == null) { String msg = "Failed to resolve HashDataInput for reference " + reqRefId; - log.error(msg); + log.info(msg); GetHashDataInputFaultType faultInfo = new GetHashDataInputFaultType(); faultInfo.setErrorCode(1); faultInfo.setErrorMessage(msg); throw new GetHashDataInputFault(msg, faultInfo); } - InputStream hashDataIS = reqHdi.getHashDataInput(); + InputStream hashDataIS; + try { + hashDataIS = reqHdi.getHashDataInput(); + } catch (IOException e) { + GetHashDataInputFaultType faultInfo = new GetHashDataInputFaultType(); + faultInfo.setErrorCode(1); + faultInfo.setErrorMessage(e.getMessage()); + throw new GetHashDataInputFault(e.getMessage(), faultInfo); + } if (hashDataIS == null) { //HashDataInput not cached? String msg = "Failed to obtain HashDataInput for reference " + reqRefId + ", reference not cached"; @@ -345,7 +369,7 @@ public class STALServiceImpl implements STALPortType { GetNextRequestResponseType response = new GetNextRequestResponseType(); response.setSessionId(TEST_SESSION_ID.toString()); - List> reqs = response.getInfoboxReadRequestOrSignRequestOrQuitRequest(); + List> reqs = response.getInfoboxReadRequestOrSignRequestOrBulkSignRequest(); if (responsesIn == null) { log.info("[TestSession] CONNECT"); diff --git a/BKUOnline/src/main/webapp/WEB-INF/applicationContext.xml b/BKUOnline/src/main/webapp/WEB-INF/applicationContext.xml index 7534a9c9..2ca9ce9c 100644 --- a/BKUOnline/src/main/webapp/WEB-INF/applicationContext.xml +++ b/BKUOnline/src/main/webapp/WEB-INF/applicationContext.xml @@ -50,10 +50,10 @@ - - + + + @@ -144,6 +144,14 @@ value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" /> + + + + + @@ -161,6 +169,7 @@ + diff --git a/BKUOnline/src/main/webapp/WEB-INF/wsdl/stal.xsd b/BKUOnline/src/main/webapp/WEB-INF/wsdl/stal.xsd index 750cf355..8dc20ec7 100644 --- a/BKUOnline/src/main/webapp/WEB-INF/wsdl/stal.xsd +++ b/BKUOnline/src/main/webapp/WEB-INF/wsdl/stal.xsd @@ -38,6 +38,7 @@ + @@ -87,6 +88,7 @@ + @@ -134,6 +136,8 @@ + + @@ -144,6 +148,20 @@ + + + + + + + + + + + + + + @@ -159,6 +177,7 @@ + diff --git a/BKUOnline/src/main/wsdl/stal-service.xsd b/BKUOnline/src/main/wsdl/stal-service.xsd index 59cebac6..0f452df9 100644 --- a/BKUOnline/src/main/wsdl/stal-service.xsd +++ b/BKUOnline/src/main/wsdl/stal-service.xsd @@ -47,6 +47,7 @@ + @@ -99,6 +100,7 @@ + @@ -143,6 +145,20 @@ + + + + + + + + + + + + + + @@ -158,6 +174,7 @@ + diff --git a/BKUOnline/src/test/java/at/gv/egiz/stal/service/STALRequestBrokerTest.java b/BKUOnline/src/test/java/at/gv/egiz/stal/service/STALRequestBrokerTest.java index bfbff5a4..c096fa8f 100644 --- a/BKUOnline/src/test/java/at/gv/egiz/stal/service/STALRequestBrokerTest.java +++ b/BKUOnline/src/test/java/at/gv/egiz/stal/service/STALRequestBrokerTest.java @@ -143,6 +143,12 @@ public class STALRequestBrokerTest { public String getFilename() { return "file.txt"; } + + @Override + public byte[] getDigest() { + return null; + } + }; r1.setHashDataInput(Collections.singletonList(hdi)); requests.add(r1); @@ -196,6 +202,12 @@ public class STALRequestBrokerTest { public String getFilename() { return "file.txt"; } + + @Override + public byte[] getDigest() { + return null; + } + }; r1.setHashDataInput(Collections.singletonList(hdi)); requests.add(r1); @@ -262,6 +274,12 @@ public class STALRequestBrokerTest { public String getFilename() { return "file.txt"; } + + @Override + public byte[] getDigest() { + return null; + } + }; r1.setHashDataInput(Collections.singletonList(hdi)); requests.add(r1); @@ -297,6 +315,12 @@ public class STALRequestBrokerTest { public String getFilename() { return "file.xml"; } + + @Override + public byte[] getDigest() { + return null; + } + }; r2.setHashDataInput(Collections.singletonList(hdi2)); requests2.add(r2); diff --git a/STAL/src/main/java/at/gv/egiz/stal/BulkSignRequest.java b/STAL/src/main/java/at/gv/egiz/stal/BulkSignRequest.java new file mode 100644 index 00000000..ce36a25c --- /dev/null +++ b/STAL/src/main/java/at/gv/egiz/stal/BulkSignRequest.java @@ -0,0 +1,92 @@ + +/* + * 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.stal; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for BulkSignRequestType complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="BulkSignRequestType">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence maxOccurs="unbounded">
+ *         <element name="SignRequests" type="{http://www.egiz.gv.at/stal}SignRequestType"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "BulkSignRequestType", propOrder = { + "signRequests" +}) +public class BulkSignRequest extends STALRequest { + + @XmlElement(name = "SignRequests", required = true) + protected List signRequests; + + /** + * Gets the value of the signRequests property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the signRequests property. + * + *

+ * For example, to add a new item, do as follows: + *

+     *    getSignRequests().add(newItem);
+     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link SignRequestType } + * + * + */ + public List getSignRequests() { + if (signRequests == null) { + signRequests = new ArrayList(); + } + return this.signRequests; + } + +} diff --git a/STAL/src/main/java/at/gv/egiz/stal/BulkSignResponse.java b/STAL/src/main/java/at/gv/egiz/stal/BulkSignResponse.java new file mode 100644 index 00000000..1cc6e73e --- /dev/null +++ b/STAL/src/main/java/at/gv/egiz/stal/BulkSignResponse.java @@ -0,0 +1,91 @@ +/* + * 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.stal; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for BulkSignResponseType complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="BulkSignResponseType">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence maxOccurs="unbounded">
+ *         <element name="SignResponse" type="{http://www.egiz.gv.at/stal}SignResponseType"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "BulkSignResponseType", propOrder = { + "signResponse" +}) +public class BulkSignResponse extends STALResponse { + + @XmlElement(name = "SignResponse", required = true) + protected List signResponse; + + /** + * Gets the value of the signResponse property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the signResponse property. + * + *

+ * For example, to add a new item, do as follows: + *

SignRequestType
+     *    getSignResponse().add(newItem);
+     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link SignResponseType } + * + * + */ + public List getSignResponse() { + if (signResponse == null) { + signResponse = new ArrayList(); + } + return this.signResponse; + } + +} diff --git a/STAL/src/main/java/at/gv/egiz/stal/HashDataInput.java b/STAL/src/main/java/at/gv/egiz/stal/HashDataInput.java index 05c9bf1e..06d47bc5 100644 --- a/STAL/src/main/java/at/gv/egiz/stal/HashDataInput.java +++ b/STAL/src/main/java/at/gv/egiz/stal/HashDataInput.java @@ -25,6 +25,7 @@ package at.gv.egiz.stal; +import java.io.IOException; import java.io.InputStream; /** @@ -34,7 +35,8 @@ import java.io.InputStream; public interface HashDataInput { public final static String CMS_DEF_REFERENCE_ID = "Reference-1"; - + public final static String DEFAULT_FILENAME = "SignatureData"; + public String getReferenceId(); public String getMimeType(); @@ -42,7 +44,9 @@ public interface HashDataInput { public String getEncoding(); public String getFilename(); + + public byte[] getDigest(); - public InputStream getHashDataInput(); + public InputStream getHashDataInput() throws IOException; } diff --git a/STAL/src/main/java/at/gv/egiz/stal/SignRequest.java b/STAL/src/main/java/at/gv/egiz/stal/SignRequest.java index d4212b24..37d43877 100644 --- a/STAL/src/main/java/at/gv/egiz/stal/SignRequest.java +++ b/STAL/src/main/java/at/gv/egiz/stal/SignRequest.java @@ -59,6 +59,8 @@ import javax.xml.bind.annotation.XmlValue; * </element> * <element name="SignatureMethod" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> * <element name="DigestMethod" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="displayName" type="{http://www.w3.org/2001/XMLSchema}string minOccurs="0"> + * <element name="mimeType" type="{http://www.w3.org/2001/XMLSchema}string minOccurs="0"/> * <element name="ExcludedByteRange" minOccurs="0"> * <complexType> * <complexContent> @@ -83,6 +85,7 @@ import javax.xml.bind.annotation.XmlValue; "signedInfo", "signatureMethod", "digestMethod", + "mimeType", "excludedByteRange" }) public class SignRequest @@ -96,6 +99,10 @@ public class SignRequest protected String signatureMethod; @XmlElement(name = "DigestMethod") protected String digestMethod; + @XmlElement(name = "displayName") + protected String displayName; + @XmlElement(name = "mimeType") + protected String mimeType; @XmlElement(name = "ExcludedByteRange") protected SignRequest.ExcludedByteRange excludedByteRange; @XmlTransient @@ -194,6 +201,55 @@ public class SignRequest public void setDigestMethod(String value) { this.digestMethod = value; } + + /** + * Sets the value of the displayName property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setDisplayName(String value) { + this.displayName = value; + } + + /** + * Gets the value of the displayName property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getDisplayName() { + return displayName; + } + + /** + * Gets the value of the mimeType property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMimeType() { + return mimeType; + } + + + /** + * Sets the value of the mimeType property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMimeType(String value) { + this.mimeType = value; + } /** * Gets the value of the excludedByteRange property. diff --git a/STAL/src/main/java/at/gv/egiz/stal/SignatureInfo.java b/STAL/src/main/java/at/gv/egiz/stal/SignatureInfo.java new file mode 100644 index 00000000..e0457b96 --- /dev/null +++ b/STAL/src/main/java/at/gv/egiz/stal/SignatureInfo.java @@ -0,0 +1,84 @@ +package at.gv.egiz.stal; + +import java.util.ArrayList; +import java.util.List; + +import at.gv.egiz.stal.signedinfo.ReferenceType; +import at.gv.egiz.stal.signedinfo.SignatureMethodType; +import at.gv.egiz.stal.signedinfo.SignedInfoType; + +/* + * 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. + */ + +/** + * This class wraps a {@link SignatureInfo} and adds the additional parameters displayName and mimeType. + * @author szoescher + * + */ +public class SignatureInfo { + + private SignedInfoType signedInfo; + + private String displayName; + + private String mimeType; + + public SignatureInfo(SignedInfoType signedInfo, String displayName, String mimeType) { + this.signedInfo = signedInfo; + this.displayName = displayName; + this.mimeType = mimeType; + } + + public SignedInfoType getSignedInfo() { + return signedInfo; + } + + public String getDisplayName() { + return displayName; + } + + public String getMimeType() { + return mimeType; + } + + public SignatureMethodType getSignatureMethod() { + if (signedInfo != null) { + return signedInfo.getSignatureMethod(); + } + return null; + } + + public String getId() { + if (signedInfo != null) { + return signedInfo.getId(); + } + return null; + } + + public List getReference() { + + if (signedInfo != null && signedInfo.getReference() != null) { + + return signedInfo.getReference(); + } + return new ArrayList(); + } +} diff --git a/STAL/src/main/java/at/gv/egiz/stal/hashdata/StubHashDataInput.java b/STAL/src/main/java/at/gv/egiz/stal/hashdata/StubHashDataInput.java new file mode 100644 index 00000000..3b74be50 --- /dev/null +++ b/STAL/src/main/java/at/gv/egiz/stal/hashdata/StubHashDataInput.java @@ -0,0 +1,101 @@ +/* + * 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.stal.hashdata; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import at.gv.egiz.stal.HashDataInput; +import at.gv.egiz.stal.signedinfo.ReferenceType; + +/** + * A StabHashDataInput is used as a placeholder at client side. + * The reference is used to load the corresponding HashDataInput from STAL. + * @author szoescher + */ +public class StubHashDataInput implements HashDataInput { + + private byte[] data; + private String mimeType; + private ReferenceType reference; + private String fileName; + + + public StubHashDataInput(ReferenceType reference, String fileName, String mimeType) { + this.mimeType = mimeType; + this.fileName = fileName; + this.reference = reference; + } + + @Override + public String getReferenceId() { + if (reference != null) { + return reference.getId(); + } + return null; + } + + @Override + public String getMimeType() { + return mimeType; + } + + @Override + public String getEncoding() { + return null; + } + + @Override + public String getFilename() { + if (fileName != null) { + return fileName; + } + return DEFAULT_FILENAME; + } + + @Override + public InputStream getHashDataInput() { + + if (data != null) { + return new ByteArrayInputStream(data); + } + + return null; + } + + @Override + public byte[] getDigest() { + if (reference != null) { + return reference.getDigestValue(); + } + return null; + } + + public void setFilename(String fileName) { + this.fileName = fileName; + } + + public ReferenceType getReference() { + return reference; + } + +} diff --git a/STALService/src/main/java/at/gv/egiz/stal/service/translator/STALTranslator.java b/STALService/src/main/java/at/gv/egiz/stal/service/translator/STALTranslator.java index 3f3d52c0..2564f88d 100644 --- a/STALService/src/main/java/at/gv/egiz/stal/service/translator/STALTranslator.java +++ b/STALService/src/main/java/at/gv/egiz/stal/service/translator/STALTranslator.java @@ -34,6 +34,8 @@ import javax.xml.bind.JAXBElement; 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; @@ -46,6 +48,8 @@ import at.gv.egiz.stal.SignRequest.SignedInfo; import at.gv.egiz.stal.SignResponse; import at.gv.egiz.stal.StatusRequest; import at.gv.egiz.stal.StatusResponse; +import at.gv.egiz.stal.service.types.BulkSignRequestType; +import at.gv.egiz.stal.service.types.BulkSignResponseType; import at.gv.egiz.stal.service.types.ErrorResponseType; import at.gv.egiz.stal.service.types.InfoboxReadRequestType; import at.gv.egiz.stal.service.types.InfoboxReadResponseType; @@ -197,18 +201,22 @@ public class STALTranslator { public List> getSupportedTypes() { return Arrays.asList(new Class[]{InfoboxReadRequest.class, SignRequest.class, + BulkSignRequest.class, QuitRequest.class, StatusRequest.class, InfoboxReadRequestType.class, SignRequestType.class, + BulkSignRequestType.class, QuitRequestType.class, StatusRequestType.class, InfoboxReadResponse.class, SignResponse.class, + BulkSignResponse.class, ErrorResponse.class, StatusResponse.class, InfoboxReadResponseType.class, SignResponseType.class, + BulkSignResponseType.class, ErrorResponseType.class, StatusResponseType.class }); @@ -218,22 +226,14 @@ public class STALTranslator { public JAXBElement translate(STALRequest request) throws TranslationException { log.trace("translate " + request.getClass()); if (request instanceof SignRequest) { - SignRequestType req = of.createSignRequestType(); - req.setKeyIdentifier(((SignRequest) request).getKeyIdentifier()); - SignRequestType.SignedInfo signedInfo = of.createSignRequestTypeSignedInfo(); - signedInfo.setValue(((SignRequest) request).getSignedInfo().getValue()); - signedInfo.setIsCMSSignedAttributes(((SignRequest) request).getSignedInfo().isIsCMSSignedAttributes()); - req.setSignedInfo(signedInfo); - req.setSignatureMethod(((SignRequest) request).getSignatureMethod()); - req.setDigestMethod(((SignRequest) request).getDigestMethod()); - if (((SignRequest) request).getExcludedByteRange() != null) { - SignRequestType.ExcludedByteRange excludedByteRange = of.createSignRequestTypeExcludedByteRange(); - excludedByteRange.setFrom(((SignRequest) request).getExcludedByteRange().getFrom()); - excludedByteRange.setTo(((SignRequest) request).getExcludedByteRange().getTo()); - req.setExcludedByteRange(excludedByteRange); + return translate((SignRequest) request); + } else if (request instanceof BulkSignRequest) { + BulkSignRequestType bulkReq = of.createBulkSignRequestType(); + BulkSignRequest bulkSignRequest = (BulkSignRequest) request; + for (SignRequest signReq : bulkSignRequest.getSignRequests()) { + bulkReq.getSignRequests().add(translate(signReq).getValue()); } - //TODO add hashdatainput (refactor signRequestType) - return of.createGetNextRequestResponseTypeSignRequest(req); + return of.createGetNextRequestResponseTypeBulkSignRequest(bulkReq); } else if (request instanceof InfoboxReadRequest) { InfoboxReadRequestType req = of.createInfoboxReadRequestType(); req.setInfoboxIdentifier(((InfoboxReadRequest) request).getInfoboxIdentifier()); @@ -256,19 +256,12 @@ public class STALTranslator { stalReq.setInfoboxIdentifier(((InfoboxReadRequestType) request).getInfoboxIdentifier()); return stalReq; } else if (request instanceof SignRequestType) { - SignRequest stalReq = new SignRequest(); - stalReq.setKeyIdentifier(((SignRequestType) request).getKeyIdentifier()); - SignedInfo signedInfo = new SignedInfo(); - signedInfo.setValue(((SignRequestType) request).getSignedInfo().getValue()); - signedInfo.setIsCMSSignedAttributes(((SignRequestType) request).getSignedInfo().isIsCMSSignedAttributes()); - stalReq.setSignedInfo(signedInfo); - stalReq.setSignatureMethod(((SignRequestType) request).getSignatureMethod()); - stalReq.setDigestMethod(((SignRequestType) request).getDigestMethod()); - if (((SignRequestType) request).getExcludedByteRange() != null) { - ExcludedByteRange excludedByteRange = new ExcludedByteRange(); - excludedByteRange.setFrom(((SignRequestType) request).getExcludedByteRange().getFrom()); - excludedByteRange.setTo(((SignRequestType) request).getExcludedByteRange().getTo()); - stalReq.setExcludedByteRange(excludedByteRange); + return translate((SignRequestType) request); + } else if (request instanceof BulkSignRequestType) { + BulkSignRequest stalReq = new BulkSignRequest(); + BulkSignRequestType bulkSignRequestType = (BulkSignRequestType) request; + for (SignRequestType requestType : bulkSignRequestType.getSignRequests()) { + stalReq.getSignRequests().add(translate(requestType)); } return stalReq; } else if (request instanceof QuitRequestType) { @@ -286,9 +279,14 @@ public class STALTranslator { resp.setInfoboxValue(((InfoboxReadResponse) response).getInfoboxValue()); return of.createGetNextRequestTypeInfoboxReadResponse(resp); } else if (response instanceof SignResponse) { - SignResponseType resp = of.createSignResponseType(); - resp.setSignatureValue(((SignResponse) response).getSignatureValue()); - return of.createGetNextRequestTypeSignResponse(resp); + return translate((SignResponse) response); + } else if (response instanceof BulkSignResponse) { + BulkSignResponseType resp = of.createBulkSignResponseType(); + BulkSignResponse bulkSignResponse = (BulkSignResponse) response; + for (SignResponse signResponse : bulkSignResponse.getSignResponse()) { + resp.getSignResponse().add(translate(signResponse).getValue()); + } + return of.createGetNextRequestTypeBulkSignResponse(resp); } else if (response instanceof ErrorResponse) { ErrorResponseType resp = of.createErrorResponseType(); resp.setErrorCode(((ErrorResponse) response).getErrorCode()); @@ -309,8 +307,13 @@ public class STALTranslator { stalResp.setInfoboxValue(((InfoboxReadResponseType) response).getInfoboxValue()); return stalResp; } else if (response instanceof SignResponseType) { - SignResponse stalResp = new SignResponse(); - stalResp.setSignatureValue(((SignResponseType) response).getSignatureValue()); + return translate((SignResponseType) response); + } else if (response instanceof BulkSignResponseType) { + BulkSignResponse stalResp = new BulkSignResponse(); + BulkSignResponseType bulkSignResponseType = (BulkSignResponseType) response; + for (SignResponseType responseType : bulkSignResponseType.getSignResponse()) { + stalResp.getSignResponse().add(translate(responseType)); + } return stalResp; } else if (response instanceof ErrorResponseType) { ErrorResponse stalResp = new ErrorResponse(); @@ -324,6 +327,63 @@ public class STALTranslator { } throw new TranslationException(response.getClass()); } + + private JAXBElement translate(SignRequest request) { + + SignRequestType req = of.createSignRequestType(); + req.setKeyIdentifier(((SignRequest) request).getKeyIdentifier()); + SignRequestType.SignedInfo signedInfo = of.createSignRequestTypeSignedInfo(); + signedInfo.setValue(((SignRequest) request).getSignedInfo().getValue()); + signedInfo.setIsCMSSignedAttributes(((SignRequest) request).getSignedInfo().isIsCMSSignedAttributes()); + req.setSignedInfo(signedInfo); + req.setSignatureMethod(((SignRequest) request).getSignatureMethod()); + req.setDigestMethod(((SignRequest) request).getDigestMethod()); + req.setMimeType(((SignRequest) request).getMimeType()); + req.setDisplayName(((SignRequest) request).getDisplayName()); + if (((SignRequest) request).getExcludedByteRange() != null) { + SignRequestType.ExcludedByteRange excludedByteRange = of.createSignRequestTypeExcludedByteRange(); + excludedByteRange.setFrom(((SignRequest) request).getExcludedByteRange().getFrom()); + excludedByteRange.setTo(((SignRequest) request).getExcludedByteRange().getTo()); + req.setExcludedByteRange(excludedByteRange); + } + return of.createGetNextRequestResponseTypeSignRequest(req); + } + + private SignRequest translate(SignRequestType request) { + + SignRequest stalReq = new SignRequest(); + stalReq.setKeyIdentifier(request.getKeyIdentifier()); + SignedInfo signedInfo = new SignedInfo(); + signedInfo.setValue(request.getSignedInfo().getValue()); + signedInfo.setIsCMSSignedAttributes(request.getSignedInfo().isIsCMSSignedAttributes()); + stalReq.setSignedInfo(signedInfo); + stalReq.setSignatureMethod(request.getSignatureMethod()); + stalReq.setDigestMethod(request.getDigestMethod()); + stalReq.setDisplayName(request.getDisplayName()); + stalReq.setMimeType(request.getMimeType()); + if (request.getExcludedByteRange() != null) { + ExcludedByteRange excludedByteRange = new ExcludedByteRange(); + excludedByteRange.setFrom(request.getExcludedByteRange().getFrom()); + excludedByteRange.setTo(request.getExcludedByteRange().getTo()); + stalReq.setExcludedByteRange(excludedByteRange); + } + return stalReq; + + } + + + private JAXBElement translate(SignResponse response) { + SignResponseType resp = of.createSignResponseType(); + resp.setSignatureValue(response.getSignatureValue()); + return of.createGetNextRequestTypeSignResponse(resp); + } + + private SignResponse translate(SignResponseType response) { + SignResponse stalResp = new SignResponse(); + stalResp.setSignatureValue(response.getSignatureValue()); + return stalResp; + } + } } diff --git a/STALService/src/main/java/at/gv/egiz/stal/service/types/BulkSignRequestType.java b/STALService/src/main/java/at/gv/egiz/stal/service/types/BulkSignRequestType.java new file mode 100644 index 00000000..4086e254 --- /dev/null +++ b/STALService/src/main/java/at/gv/egiz/stal/service/types/BulkSignRequestType.java @@ -0,0 +1,68 @@ +package at.gv.egiz.stal.service.types; + +import java.util.ArrayList; +import java.util.List; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for BulkSignRequestType complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="BulkSignRequestType">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence maxOccurs="unbounded">
+ *         <element name="SignRequests" type="{http://www.egiz.gv.at/stal}SignRequestType"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "BulkSignRequestType", propOrder = { + "signRequests" +}) +public class BulkSignRequestType extends RequestType { + + @XmlElement(name = "SignRequests", required = true) + protected List signRequests; + + /** + * Gets the value of the signRequests property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the signRequests property. + * + *

+ * For example, to add a new item, do as follows: + *

+     *    getSignRequests().add(newItem);
+     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link SignRequestType } + * + * + */ + public List getSignRequests() { + if (signRequests == null) { + signRequests = new ArrayList(); + } + return this.signRequests; + } + +} diff --git a/STALService/src/main/java/at/gv/egiz/stal/service/types/BulkSignResponseType.java b/STALService/src/main/java/at/gv/egiz/stal/service/types/BulkSignResponseType.java new file mode 100644 index 00000000..fbdcbdc0 --- /dev/null +++ b/STALService/src/main/java/at/gv/egiz/stal/service/types/BulkSignResponseType.java @@ -0,0 +1,69 @@ + +package at.gv.egiz.stal.service.types; + +import java.util.ArrayList; +import java.util.List; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for BulkSignResponseType complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="BulkSignResponseType">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence maxOccurs="unbounded">
+ *         <element name="SignResponse" type="{http://www.egiz.gv.at/stal}SignResponseType"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "BulkSignResponseType", propOrder = { + "signResponse" +}) +public class BulkSignResponseType extends ResponseType { + + @XmlElement(name = "SignResponse", required = true) + protected List signResponse; + + /** + * Gets the value of the signResponse property. + * + *

+ * This accessor method returns a reference to the live list, + * not a snapshot. Therefore any modification you make to the + * returned list will be present inside the JAXB object. + * This is why there is not a set method for the signResponse property. + * + *

+ * For example, to add a new item, do as follows: + *

SignRequestType
+     *    getSignResponse().add(newItem);
+     * 
+ * + * + *

+ * Objects of the following type(s) are allowed in the list + * {@link SignResponseType } + * + * + */ + public List getSignResponse() { + if (signResponse == null) { + signResponse = new ArrayList(); + } + return this.signResponse; + } + +} diff --git a/STALService/src/main/java/at/gv/egiz/stal/service/types/GetHashDataInputType.java b/STALService/src/main/java/at/gv/egiz/stal/service/types/GetHashDataInputType.java index 037e94eb..2a3a58bf 100644 --- a/STALService/src/main/java/at/gv/egiz/stal/service/types/GetHashDataInputType.java +++ b/STALService/src/main/java/at/gv/egiz/stal/service/types/GetHashDataInputType.java @@ -21,8 +21,6 @@ * that you distribute must include a readable copy of the "NOTICE" text file. */ - - package at.gv.egiz.stal.service.types; import java.util.ArrayList; @@ -49,6 +47,7 @@ import javax.xml.bind.annotation.XmlType; * <complexContent> * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <attribute name="ID" type="{http://www.w3.org/2001/XMLSchema}string" /> + * <attribute name="digest" type="{http://www.w3.org/2001/XMLSchema}base64Binary" //> * </restriction> * </complexContent> * </complexType> @@ -133,13 +132,14 @@ public class GetHashDataInputType { *

The following schema fragment specifies the expected content contained within this class. * *

-     * <complexType>
-     *   <complexContent>
-     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       <attribute name="ID" type="{http://www.w3.org/2001/XMLSchema}string" />
-     *     </restriction>
-     *   </complexContent>
-     * </complexType>
+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <attribute name="ID" type="{http://www.w3.org/2001/XMLSchema}string" />
+     *       <attribute name="digest" type="{http://www.w3.org/2001/XMLSchema}base64Binary" />
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
      * 
* * @@ -150,6 +150,8 @@ public class GetHashDataInputType { @XmlAttribute(name = "ID") protected String id; + @XmlAttribute + protected byte[] digest; /** * Gets the value of the id property. @@ -175,6 +177,28 @@ public class GetHashDataInputType { this.id = value; } + /** + * Gets the value of the digest property. + * + * @return + * possible object is + * byte[] + */ + public byte[] getDigest() { + return digest; + } + + /** + * Sets the value of the digest property. + * + * @param value + * allowed object is + * byte[] + */ + public void setDigest(byte[] value) { + this.digest = ((byte[]) value); + } + } } diff --git a/STALService/src/main/java/at/gv/egiz/stal/service/types/GetNextRequestResponseType.java b/STALService/src/main/java/at/gv/egiz/stal/service/types/GetNextRequestResponseType.java index 310190cc..9fcbe660 100644 --- a/STALService/src/main/java/at/gv/egiz/stal/service/types/GetNextRequestResponseType.java +++ b/STALService/src/main/java/at/gv/egiz/stal/service/types/GetNextRequestResponseType.java @@ -1,27 +1,3 @@ -/* - * Copyright 2011 by Graz University of Technology, Austria - * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint - * initiative of the Federal Chancellery Austria and Graz University of Technology. - * - * 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.stal.service.types; @@ -49,6 +25,7 @@ import javax.xml.bind.annotation.XmlType; * <choice maxOccurs="unbounded"> * <element name="InfoboxReadRequest" type="{http://www.egiz.gv.at/stal}InfoboxReadRequestType"/> * <element name="SignRequest" type="{http://www.egiz.gv.at/stal}SignRequestType"/> + * <element name="BulkSignRequest" type="{http://www.egiz.gv.at/stal}BulkSignRequestType"/> * <element name="QuitRequest" type="{http://www.egiz.gv.at/stal}QuitRequestType"/> * <element name="StatusRequest" type="{http://www.egiz.gv.at/stal}StatusRequestType"/> * <element ref="{http://www.egiz.gv.at/stal}OtherRequest"/> @@ -63,52 +40,55 @@ import javax.xml.bind.annotation.XmlType; */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "GetNextRequestResponseType", propOrder = { - "infoboxReadRequestOrSignRequestOrQuitRequest" + "infoboxReadRequestOrSignRequestOrBulkSignRequest" }) public class GetNextRequestResponseType { @XmlElementRefs({ - @XmlElementRef(name = "OtherRequest", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class), + @XmlElementRef(name = "BulkSignRequest", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class), @XmlElementRef(name = "QuitRequest", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class), @XmlElementRef(name = "InfoboxReadRequest", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class), + @XmlElementRef(name = "StatusRequest", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class), @XmlElementRef(name = "SignRequest", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class), - @XmlElementRef(name = "StatusRequest", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class) + @XmlElementRef(name = "OtherRequest", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class) }) - protected List> infoboxReadRequestOrSignRequestOrQuitRequest; + protected List> infoboxReadRequestOrSignRequestOrBulkSignRequest; @XmlAttribute(name = "SessionId") protected String sessionId; /** - * Gets the value of the infoboxReadRequestOrSignRequestOrQuitRequest property. + * Gets the value of the infoboxReadRequestOrSignRequestOrBulkSignRequest property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. - * This is why there is not a set method for the infoboxReadRequestOrSignRequestOrQuitRequest property. + * This is why there is not a set method for the infoboxReadRequestOrSignRequestOrBulkSignRequest property. * *

* For example, to add a new item, do as follows: *

-     *    getInfoboxReadRequestOrSignRequestOrQuitRequest().add(newItem);
+     *    getInfoboxReadRequestOrSignRequestOrBulkSignRequest().add(newItem);
      * 
* * *

* Objects of the following type(s) are allowed in the list - * {@link JAXBElement }{@code <}{@link RequestType }{@code >} + * {@link JAXBElement }{@code <}{@link BulkSignRequestType }{@code >} * {@link JAXBElement }{@code <}{@link QuitRequestType }{@code >} * {@link JAXBElement }{@code <}{@link InfoboxReadRequestType }{@code >} * {@link JAXBElement }{@code <}{@link StatusRequestType }{@code >} * {@link JAXBElement }{@code <}{@link SignRequestType }{@code >} + * {@link JAXBElement }{@code <}{@link ScriptType }{@code >} + * {@link JAXBElement }{@code <}{@link RequestType }{@code >} * * */ - public List> getInfoboxReadRequestOrSignRequestOrQuitRequest() { - if (infoboxReadRequestOrSignRequestOrQuitRequest == null) { - infoboxReadRequestOrSignRequestOrQuitRequest = new ArrayList>(); + public List> getInfoboxReadRequestOrSignRequestOrBulkSignRequest() { + if (infoboxReadRequestOrSignRequestOrBulkSignRequest == null) { + infoboxReadRequestOrSignRequestOrBulkSignRequest = new ArrayList>(); } - return this.infoboxReadRequestOrSignRequestOrQuitRequest; + return this.infoboxReadRequestOrSignRequestOrBulkSignRequest; } /** diff --git a/STALService/src/main/java/at/gv/egiz/stal/service/types/GetNextRequestType.java b/STALService/src/main/java/at/gv/egiz/stal/service/types/GetNextRequestType.java index 4b392aed..635c0a71 100644 --- a/STALService/src/main/java/at/gv/egiz/stal/service/types/GetNextRequestType.java +++ b/STALService/src/main/java/at/gv/egiz/stal/service/types/GetNextRequestType.java @@ -1,27 +1,3 @@ -/* - * Copyright 2011 by Graz University of Technology, Austria - * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint - * initiative of the Federal Chancellery Austria and Graz University of Technology. - * - * 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.stal.service.types; @@ -48,6 +24,7 @@ import javax.xml.bind.annotation.XmlType; * <choice maxOccurs="unbounded"> * <element name="InfoboxReadResponse" type="{http://www.egiz.gv.at/stal}InfoboxReadResponseType"/> * <element name="SignResponse" type="{http://www.egiz.gv.at/stal}SignResponseType"/> + * <element name="BulkSignResponse" type="{http://www.egiz.gv.at/stal}BulkSignResponseType"/> * <element name="ErrorResponse" type="{http://www.egiz.gv.at/stal}ErrorResponseType"/> * <element name="StatusResponse" type="{http://www.egiz.gv.at/stal}StatusResponseType"/> * <element ref="{http://www.egiz.gv.at/stal}OtherResponse"/> @@ -62,52 +39,55 @@ import javax.xml.bind.annotation.XmlType; */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "GetNextRequestType", propOrder = { - "infoboxReadResponseOrSignResponseOrErrorResponse" + "infoboxReadResponseOrSignResponseOrBulkSignResponse" }) public class GetNextRequestType { @XmlElementRefs({ - @XmlElementRef(name = "StatusResponse", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class), + @XmlElementRef(name = "SignResponse", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class), @XmlElementRef(name = "InfoboxReadResponse", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class), - @XmlElementRef(name = "OtherResponse", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class), + @XmlElementRef(name = "BulkSignResponse", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class), @XmlElementRef(name = "ErrorResponse", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class), - @XmlElementRef(name = "SignResponse", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class) + @XmlElementRef(name = "StatusResponse", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class), + @XmlElementRef(name = "OtherResponse", namespace = "http://www.egiz.gv.at/stal", type = JAXBElement.class) }) - protected List> infoboxReadResponseOrSignResponseOrErrorResponse; + protected List> infoboxReadResponseOrSignResponseOrBulkSignResponse; @XmlAttribute(name = "SessionId") protected String sessionId; /** - * Gets the value of the infoboxReadResponseOrSignResponseOrErrorResponse property. + * Gets the value of the infoboxReadResponseOrSignResponseOrBulkSignResponse property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. - * This is why there is not a set method for the infoboxReadResponseOrSignResponseOrErrorResponse property. + * This is why there is not a set method for the infoboxReadResponseOrSignResponseOrBulkSignResponse property. * *

* For example, to add a new item, do as follows: *

-     *    getInfoboxReadResponseOrSignResponseOrErrorResponse().add(newItem);
+     *    getInfoboxReadResponseOrSignResponseOrBulkSignResponse().add(newItem);
      * 
* * *

* Objects of the following type(s) are allowed in the list - * {@link JAXBElement }{@code <}{@link StatusResponseType }{@code >} - * {@link JAXBElement }{@code <}{@link at.gv.egiz.stal.service.types.ResponseType }{@code >} - * {@link JAXBElement }{@code <}{@link ErrorResponseType }{@code >} * {@link JAXBElement }{@code <}{@link SignResponseType }{@code >} * {@link JAXBElement }{@code <}{@link InfoboxReadResponseType }{@code >} + * {@link JAXBElement }{@code <}{@link BulkSignResponseType }{@code >} + * {@link JAXBElement }{@code <}{@link ErrorResponseType }{@code >} + * {@link JAXBElement }{@code <}{@link StatusResponseType }{@code >} + * {@link JAXBElement }{@code <}{@link at.buergerkarte.namespaces.cardchannel.service.ResponseType }{@code >} + * {@link JAXBElement }{@code <}{@link at.gv.egiz.stal.service.types.ResponseType }{@code >} * * */ - public List> getInfoboxReadResponseOrSignResponseOrErrorResponse() { - if (infoboxReadResponseOrSignResponseOrErrorResponse == null) { - infoboxReadResponseOrSignResponseOrErrorResponse = new ArrayList>(); + public List> getInfoboxReadResponseOrSignResponseOrBulkSignResponse() { + if (infoboxReadResponseOrSignResponseOrBulkSignResponse == null) { + infoboxReadResponseOrSignResponseOrBulkSignResponse = new ArrayList>(); } - return this.infoboxReadResponseOrSignResponseOrErrorResponse; + return this.infoboxReadResponseOrSignResponseOrBulkSignResponse; } /** diff --git a/STALService/src/main/java/at/gv/egiz/stal/service/types/ObjectFactory.java b/STALService/src/main/java/at/gv/egiz/stal/service/types/ObjectFactory.java index ea7ca837..e9b5ac92 100644 --- a/STALService/src/main/java/at/gv/egiz/stal/service/types/ObjectFactory.java +++ b/STALService/src/main/java/at/gv/egiz/stal/service/types/ObjectFactory.java @@ -64,6 +64,8 @@ public class ObjectFactory { private final static QName _GetNextRequestTypeInfoboxReadResponse_QNAME = new QName("http://www.egiz.gv.at/stal", "InfoboxReadResponse"); private final static QName _GetNextRequestResponseTypeStatusRequest_QNAME = new QName("http://www.egiz.gv.at/stal", "StatusRequest"); private final static QName _GetNextRequestTypeStatusResponse_QNAME = new QName("http://www.egiz.gv.at/stal", "StatusResponse"); + private final static QName _GetNextRequestTypeBulkSignResponse_QNAME = new QName("http://www.egiz.gv.at/stal", "BulkSignResponse"); + private final static QName _GetNextRequestResponseTypeBulkSignRequest_QNAME = new QName("http://www.egiz.gv.at/stal", "BulkSignRequest"); /** * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: at.gv.egiz.stal.service.types @@ -72,6 +74,15 @@ public class ObjectFactory { public ObjectFactory() { } + + /** + * Create an instance of {@link BulkSignResponseType } + * + */ + public BulkSignResponseType createBulkSignResponseType() { + return new BulkSignResponseType(); + } + /** * Create an instance of {@link StatusResponseType } * @@ -168,6 +179,15 @@ public class ObjectFactory { return new InfoboxReadResponseType(); } + /** + * Create an instance of {@link BulkSignRequestType } + * + */ + public BulkSignRequestType createBulkSignRequestType() { + return new BulkSignRequestType(); + } + + /** * Create an instance of {@link InfoboxReadRequestType } * @@ -326,6 +346,15 @@ public class ObjectFactory { return new JAXBElement(_GetNextRequestResponseTypeSignRequest_QNAME, SignRequestType.class, GetNextRequestResponseType.class, value); } + /** + * Create an instance of {@link JAXBElement }{@code <}{@link BulkSignResponseType }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.egiz.gv.at/stal", name = "BulkSignResponse", scope = GetNextRequestType.class) + public JAXBElement createGetNextRequestTypeBulkSignResponse(BulkSignResponseType value) { + return new JAXBElement(_GetNextRequestTypeBulkSignResponse_QNAME, BulkSignResponseType.class, GetNextRequestType.class, value); + } + /** * Create an instance of {@link JAXBElement }{@code <}{@link ErrorResponseType }{@code >}} * @@ -344,6 +373,17 @@ public class ObjectFactory { return new JAXBElement(_GetNextRequestTypeSignResponse_QNAME, SignResponseType.class, GetNextRequestType.class, value); } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link BulkSignRequestType }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://www.egiz.gv.at/stal", name = "BulkSignRequest", scope = GetNextRequestResponseType.class) + public JAXBElement createGetNextRequestResponseTypeBulkSignRequest(BulkSignRequestType value) { + return new JAXBElement(_GetNextRequestResponseTypeBulkSignRequest_QNAME, BulkSignRequestType.class, GetNextRequestResponseType.class, value); + } + + /** * Create an instance of {@link JAXBElement }{@code <}{@link InfoboxReadResponseType }{@code >}} * diff --git a/STALService/src/main/java/at/gv/egiz/stal/service/types/RequestType.java b/STALService/src/main/java/at/gv/egiz/stal/service/types/RequestType.java index 2cf88988..fcefbd09 100644 --- a/STALService/src/main/java/at/gv/egiz/stal/service/types/RequestType.java +++ b/STALService/src/main/java/at/gv/egiz/stal/service/types/RequestType.java @@ -55,7 +55,8 @@ import javax.xml.bind.annotation.XmlType; SignRequestType.class, InfoboxReadRequestType.class, QuitRequestType.class, - StatusRequestType.class + StatusRequestType.class, + BulkSignRequestType.class }) public abstract class RequestType { diff --git a/STALService/src/main/java/at/gv/egiz/stal/service/types/ResponseType.java b/STALService/src/main/java/at/gv/egiz/stal/service/types/ResponseType.java index 02a91ef0..26c3de96 100644 --- a/STALService/src/main/java/at/gv/egiz/stal/service/types/ResponseType.java +++ b/STALService/src/main/java/at/gv/egiz/stal/service/types/ResponseType.java @@ -54,7 +54,8 @@ import javax.xml.bind.annotation.XmlType; ErrorResponseType.class, InfoboxReadResponseType.class, SignResponseType.class, - StatusResponseType.class + StatusResponseType.class, + BulkSignResponseType.class }) public abstract class ResponseType { diff --git a/STALService/src/main/java/at/gv/egiz/stal/service/types/SignRequestType.java b/STALService/src/main/java/at/gv/egiz/stal/service/types/SignRequestType.java index 6688d720..b5920d0a 100644 --- a/STALService/src/main/java/at/gv/egiz/stal/service/types/SignRequestType.java +++ b/STALService/src/main/java/at/gv/egiz/stal/service/types/SignRequestType.java @@ -65,6 +65,8 @@ import javax.xml.bind.annotation.XmlValue; * </element> * <element name="SignatureMethod" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> * <element name="DigestMethod" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> + * <element name="displayName" type="{http://www.w3.org/2001/XMLSchema}string minOccurs="0"/> + * <element name="mimeType" type="{http://www.w3.org/2001/XMLSchema}string minOccurs="0"/> * <element name="ExcludedByteRange" minOccurs="0"> * <complexType> * <complexContent> @@ -89,6 +91,8 @@ import javax.xml.bind.annotation.XmlValue; "signedInfo", "signatureMethod", "digestMethod", + "displayName", + "mimeType", "excludedByteRange" }) public class SignRequestType @@ -103,6 +107,10 @@ public class SignRequestType protected String signatureMethod; @XmlElement(name = "DigestMethod") protected String digestMethod; + @XmlElement(name = "displayName", required = true) + protected String displayName; + @XmlElement(name = "mimeType", required = true) + protected String mimeType; @XmlElement(name = "ExcludedByteRange") protected SignRequestType.ExcludedByteRange excludedByteRange; @@ -190,6 +198,55 @@ public class SignRequestType return digestMethod; } + /** + * Sets the value of the displayName property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setDisplayName(String value) { + this.displayName = value; + } + + /** + * Gets the value of the displayName property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getDisplayName() { + return displayName; + } + + /** + * Gets the value of the mimeType property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMimeType() { + return mimeType; + } + + + /** + * Sets the value of the mimeType property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMimeType(String value) { + this.mimeType = value; + } + /** * Sets the value of the digestMethod property. * @@ -233,14 +290,14 @@ public class SignRequestType *

The following schema fragment specifies the expected content contained within this class. * *

-     * <complexType>
-     *   <complexContent>
-     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
-     *       <attribute name="from" use="required" type="{http://www.w3.org/2001/XMLSchema}unsignedLong" />
-     *       <attribute name="to" use="required" type="{http://www.w3.org/2001/XMLSchema}unsignedLong" />
-     *     </restriction>
-     *   </complexContent>
-     * </complexType>
+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <attribute name="from" use="required" type="{http://www.w3.org/2001/XMLSchema}unsignedLong" />
+     *       <attribute name="to" use="required" type="{http://www.w3.org/2001/XMLSchema}unsignedLong" />
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
      * 
* * @@ -313,13 +370,13 @@ public class SignRequestType *

The following schema fragment specifies the expected content contained within this class. * *

-     * <complexType>
-     *   <simpleContent>
-     *     <extension base="<http://www.w3.org/2001/XMLSchema>base64Binary">
-     *       <attribute name="IsCMSSignedAttributes" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
-     *     </extension>
-     *   </simpleContent>
-     * </complexType>
+     * <complexType>
+     *   <simpleContent>
+     *     <extension base="<http://www.w3.org/2001/XMLSchema>base64Binary">
+     *       <attribute name="IsCMSSignedAttributes" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
+     *     </extension>
+     *   </simpleContent>
+     * </complexType>
      * 
* * diff --git a/STALXService/src/test/java/at/gv/egiz/stalx/service/STALServiceTest.java b/STALXService/src/test/java/at/gv/egiz/stalx/service/STALServiceTest.java index efe084d3..0bf7a0fc 100644 --- a/STALXService/src/test/java/at/gv/egiz/stalx/service/STALServiceTest.java +++ b/STALXService/src/test/java/at/gv/egiz/stalx/service/STALServiceTest.java @@ -91,7 +91,7 @@ public class STALServiceTest { System.out.println("connecting to STAL WS [TestSession] ..."); GetNextRequestResponseType wsResponse = port.connect("TestSession"); - List> stalRequests = wsResponse.getInfoboxReadRequestOrSignRequestOrQuitRequest(); + List> stalRequests = wsResponse.getInfoboxReadRequestOrSignRequestOrBulkSignRequest(); System.out.println("Received " + wsResponse.getClass() + " containing " + stalRequests.size() + " requests"); for (JAXBElement jAXBElement : stalRequests) { System.out.println(" STALRequest " + jAXBElement.getValue().getClass()); diff --git a/bkucommon/pom.xml b/bkucommon/pom.xml index 9e036ec6..9038a26c 100644 --- a/bkucommon/pom.xml +++ b/bkucommon/pom.xml @@ -82,6 +82,11 @@ compile + commons-io + commons-io + 2.5 + + xerces xercesImpl 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 @@ + diff --git a/pom.xml b/pom.xml index 06653e87..325493ca 100644 --- a/pom.xml +++ b/pom.xml @@ -481,12 +481,6 @@ 2.3.1 test - - javax.activation - activation - ${activation.version} - test - com.sun.xml.bind jaxb-impl @@ -499,12 +493,6 @@ ${jaxb.version} test - - javax.xml.bind - jaxb-api - ${jaxb.version} - test - diff --git a/smcc/src/main/java/at/gv/egiz/smcc/BulkSignException.java b/smcc/src/main/java/at/gv/egiz/smcc/BulkSignException.java new file mode 100644 index 00000000..6acfd6c9 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/BulkSignException.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +/** + * @author szoescher szoescher + */ +package at.gv.egiz.smcc; + +public class BulkSignException extends SignatureCardException { + + private static final long serialVersionUID = 1L; + + public BulkSignException() { + super(); + } + + public BulkSignException(String message, Throwable cause) { + super(message, cause); + } + + public BulkSignException(String message) { + super(message); + } + + public BulkSignException(Throwable cause) { + super(cause); + } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/OverrulePinpadPINGUI.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/OverrulePinpadPINGUI.java new file mode 100644 index 00000000..3cfc7d98 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/OverrulePinpadPINGUI.java @@ -0,0 +1,7 @@ +package at.gv.egiz.smcc.pin.gui; + +public interface OverrulePinpadPINGUI extends PINGUI { + + boolean allowOverrulePinpad() throws InterruptedException; + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java index b740c0ad..4e7d72f2 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/PINProvider.java @@ -24,6 +24,7 @@ package at.gv.egiz.smcc.pin.gui; +import at.gv.egiz.smcc.BulkSignException; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.PinInfo; @@ -52,8 +53,9 @@ public interface PINProvider { * @return pin != null * @throws at.gv.egiz.smcc.CancelledException * @throws java.lang.InterruptedException + * @throws BulkSignException */ char[] providePIN(PinInfo pinSpec, int retries) - throws CancelledException, InterruptedException; + throws CancelledException, InterruptedException, BulkSignException; } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java b/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java index 48331278..45b70ca6 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/reader/PinpadCardReader.java @@ -49,6 +49,7 @@ import at.gv.egiz.smcc.SignatureCardException; import at.gv.egiz.smcc.TimeoutException; import at.gv.egiz.smcc.VerifyAPDUSpec; import at.gv.egiz.smcc.pin.gui.ModifyPINGUI; +import at.gv.egiz.smcc.pin.gui.OverrulePinpadPINGUI; import at.gv.egiz.smcc.pin.gui.PINGUI; import at.gv.egiz.smcc.util.SMCCHelper; @@ -597,6 +598,15 @@ public class PinpadCardReader extends DefaultCardReader { byte[] s = createPINVerifyStructure(apduSpec, pinSpec); Card icc = channel.getCard(); + if (pinGUI instanceof OverrulePinpadPINGUI && (VERIFY || VERIFY_DIRECT)) { + if (((OverrulePinpadPINGUI) pinGUI).allowOverrulePinpad()) { + return super.verify(channel, apduSpec, pinGUI, pinSpec, retries); + } else { + log.debug("The User prohibited deactivation of the pinPad."); + throw new CancelledException(); + } + } + if (VERIFY) { boolean regain = dropExclusive(icc); try { diff --git a/smcc/src/test/java/at/gv/egiz/smcc/card/CreateSignature.java b/smcc/src/test/java/at/gv/egiz/smcc/card/CreateSignature.java index 5acc7e10..a2204bb7 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/card/CreateSignature.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/card/CreateSignature.java @@ -35,6 +35,7 @@ import java.nio.charset.Charset; import java.util.Formatter; import java.util.Locale; +import at.gv.egiz.smcc.BulkSignException; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.PinInfo; import at.gv.egiz.smcc.SignatureCard; @@ -96,7 +97,7 @@ public class CreateSignature { @Override public char[] providePIN(PinInfo pinSpec, int retries) - throws CancelledException, InterruptedException { + throws CancelledException, InterruptedException, BulkSignException { System.out.print("Enter " + pinSpec.getLocalizedName() + ": "); BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String pin; diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelPINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelPINProvider.java index 281ef7b2..35dbafa8 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelPINProvider.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/CancelPINProvider.java @@ -24,6 +24,7 @@ package at.gv.egiz.smcc.pin.gui; +import at.gv.egiz.smcc.BulkSignException; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.PinInfo; @@ -31,7 +32,7 @@ public class CancelPINProvider extends DummyPINGUI implements PINGUI { @Override public char[] providePIN(PinInfo spec, int retries) - throws CancelledException, InterruptedException { + throws CancelledException, InterruptedException, BulkSignException { throw new CancelledException("cancelled by cancelPINProvider"); } } \ No newline at end of file diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InterruptPINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InterruptPINProvider.java index 184cabc5..9eaa2945 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InterruptPINProvider.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InterruptPINProvider.java @@ -24,6 +24,7 @@ package at.gv.egiz.smcc.pin.gui; +import at.gv.egiz.smcc.BulkSignException; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.PinInfo; @@ -34,7 +35,7 @@ public class InterruptPINProvider extends DummyPINGUI implements PINGUI { @Override public char[] providePIN(PinInfo spec, int retries) - throws CancelledException, InterruptedException { + throws CancelledException, InterruptedException, BulkSignException { throw new InterruptedException("interrupted by cancelPINProvider"); } diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidPINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidPINProvider.java index 22f155de..ab2f646b 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidPINProvider.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/InvalidPINProvider.java @@ -24,6 +24,7 @@ package at.gv.egiz.smcc.pin.gui; +import at.gv.egiz.smcc.BulkSignException; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.PinInfo; @@ -41,7 +42,7 @@ public class InvalidPINProvider extends DummyPINGUI implements PINGUI { @Override public char[] providePIN(PinInfo spec, int retries) - throws CancelledException, InterruptedException { + throws CancelledException, InterruptedException, BulkSignException { if (provided >= numWrongTries) { throw new CancelledException("Number of wrong tries reached: " + provided); } else { diff --git a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java index 05bbc9df..05e18d90 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/pin/gui/SMCCTestPINProvider.java @@ -24,6 +24,7 @@ package at.gv.egiz.smcc.pin.gui; +import at.gv.egiz.smcc.BulkSignException; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.PinInfo; @@ -38,7 +39,7 @@ public class SMCCTestPINProvider extends DummyPINGUI implements PINGUI { @Override public char[] providePIN(PinInfo spec, int retries) - throws CancelledException, InterruptedException { + throws CancelledException, InterruptedException, BulkSignException { provided++; return pin; } diff --git a/smcc/src/test/java/at/gv/egiz/smcc/test/AbstractCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/test/AbstractCardTest.java index f6faafe6..5012f34d 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/test/AbstractCardTest.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/test/AbstractCardTest.java @@ -36,6 +36,7 @@ import java.security.NoSuchAlgorithmException; import org.junit.Test; +import at.gv.egiz.smcc.BulkSignException; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.CardNotSupportedException; import at.gv.egiz.smcc.LockedException; @@ -176,7 +177,7 @@ public abstract class AbstractCardTest extends AbstractCardTestBase { PINGUI pinProvider = new DummyPINGUI() { @Override public char[] providePIN(PinInfo spec, int retries) - throws CancelledException, InterruptedException { + throws CancelledException, InterruptedException, BulkSignException { try { signatureCard.getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR, null); @@ -201,7 +202,7 @@ public abstract class AbstractCardTest extends AbstractCardTestBase { PINGUI pinProvider = new DummyPINGUI() { @Override public char[] providePIN(PinInfo spec, int retries) - throws CancelledException, InterruptedException { + throws CancelledException, InterruptedException, BulkSignException { try { signatureCard.getCertificate(KeyboxName.CERTIFIED_KEYPAIR, null); diff --git a/smcc/src/test/java/at/gv/egiz/smcc/test/ecard/ECardG3InfoboxContainerTest.java b/smcc/src/test/java/at/gv/egiz/smcc/test/ecard/ECardG3InfoboxContainerTest.java index 9351fa21..a625168e 100644 --- a/smcc/src/test/java/at/gv/egiz/smcc/test/ecard/ECardG3InfoboxContainerTest.java +++ b/smcc/src/test/java/at/gv/egiz/smcc/test/ecard/ECardG3InfoboxContainerTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.*; import org.junit.Test; +import at.gv.egiz.smcc.BulkSignException; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.PinInfo; import at.gv.egiz.smcc.SignatureCardException; @@ -44,7 +45,7 @@ public class ECardG3InfoboxContainerTest extends AbstractCardTestBase { PINGUI pinProvider = new DummyPINGUI() { @Override public char[] providePIN(PinInfo pinSpec, int retries) - throws CancelledException, InterruptedException { + throws CancelledException, InterruptedException, BulkSignException { // must not require a PIN! fail(); return null; diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/BulkSignPINGUI.java b/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/BulkSignPINGUI.java new file mode 100644 index 00000000..b792fed2 --- /dev/null +++ b/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/BulkSignPINGUI.java @@ -0,0 +1,172 @@ +/* + * 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.pin.gui; + +import at.gv.egiz.bku.gui.BKUGUIFacade; +import at.gv.egiz.bku.gui.viewer.SecureViewer; +import at.gv.egiz.smcc.BulkSignException; +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.PinInfo; +import at.gv.egiz.smcc.pin.gui.OverrulePinpadPINGUI; +import at.gv.egiz.stal.SignatureInfo; + +import java.security.DigestException; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This PinProvider is used for BulkSignatureRequests. + * The pin input field is called once and the pin is stored for further sign requests. + * + * + * @author szoescher + */ +public class BulkSignPINGUI extends SignPINGUI implements OverrulePinpadPINGUI { + + private final Logger log = LoggerFactory.getLogger(BulkSignPINGUI.class); + + private boolean retry = false; + + private char[] pin; + + private boolean showSignaturePINDialog; + + private int maxSignatures; + + private int signatureCount; + + List signedInfo; + + + + public BulkSignPINGUI(BKUGUIFacade gui, SecureViewer viewer, List signedInfo, int maxSignatures) { + super(gui, viewer, null); + + this.signedInfo = signedInfo; + this.maxSignatures = maxSignatures; + + showSignaturePINDialog = true; + signatureCount = 0; + } + + public int getSignatureCount() { + return signatureCount; + } + + public boolean isShowSignaturePINDialog() { + return showSignaturePINDialog; + } + + public void setShowSignaturePINDialog(boolean showSignaturePINDialog) { + this.showSignaturePINDialog = showSignaturePINDialog; + } + + + + @Override + public char[] providePIN(PinInfo spec, int retries) throws CancelledException, InterruptedException, BulkSignException { + + if (showSignaturePINDialog) { + + signatureCount = 1; + gui.showSignaturePINDialog(spec, (retry) ? retries : -1, maxSignatures, this, "sign", this, "cancel", this, "secureViewer"); + + do { + log.trace("[{}] wait for action.", Thread.currentThread().getName()); + waitForAction(); + log.trace("[{}] received action {}.", Thread.currentThread().getName(), action); + + if ("secureViewer".equals(action)) { + try { + + viewer.displayDataToBeSigned(signedInfo, this, "pinEntry"); + + } catch (DigestException ex) { + log.error("Bad digest value: {}", ex.getMessage()); + gui.showErrorDialog(BKUGUIFacade.ERR_INVALID_HASH, new Object[] { ex.getMessage() }, this, "error"); + } catch (Exception ex) { + log.error("Could not display hashdata inputs: {}", ex.getMessage()); + gui.showErrorDialog(BKUGUIFacade.ERR_DISPLAY_HASHDATA, new Object[] { ex.getMessage() }, this, "error"); + } + } else if ("sign".equals(action)) { + gui.showMessageDialog(BKUGUIFacade.TITLE_BULKSIGNATURE, BKUGUIFacade.MESSAGE_BULKSIGN, new Object[]{signatureCount,maxSignatures}, BKUGUIFacade.BUTTON_CANCEL, this, "cancel"); + retry = true; + pin = gui.getPin(); + return pin; + } else if ("pinEntry".equals(action)) { + gui.showSignaturePINDialog(spec, (retry) ? retries : -1, this, "sign", this, "cancel", this, "secureViewer"); + } else if ("cancel".equals(action) || "error".equals(action)) { + gui.showMessageDialog(BKUGUIFacade.TITLE_WAIT, BKUGUIFacade.MESSAGE_WAIT); + throw new CancelledException(spec.getLocalizedName() + " entry cancelled"); + } else { + log.error("Unknown action command {}.", action); + } + } while (true); + } else { + + signatureCount ++; + + if(signatureCount > maxSignatures) { + throw new BulkSignException("Limit of "+ signatureCount + "Signatures exceeded."); + } + + gui.updateMessageDialog(BKUGUIFacade.TITLE_BULKSIGNATURE, BKUGUIFacade.MESSAGE_BULKSIGN, new Object[]{signatureCount,maxSignatures}, BKUGUIFacade.BUTTON_CANCEL, this, "cancel"); + + if ("cancel".equals(action) || "error".equals(action)) { + gui.showMessageDialog(BKUGUIFacade.TITLE_WAIT, BKUGUIFacade.MESSAGE_WAIT); + throw new CancelledException(spec.getLocalizedName() + " entry cancelled"); + } + + return pin; + } + } + + @Override + public boolean allowOverrulePinpad() throws InterruptedException { + + if (showSignaturePINDialog) { + gui.showPinPadDeactivationDialog(this, "cancel", this, "ok"); + + do { + log.trace("[{}] wait for action.", Thread.currentThread().getName()); + waitForAction(); + log.trace("[{}] received action {}.", Thread.currentThread().getName(), action); + + if ("cancel".equals(action)) { + + return false; + + } else if ("ok".equals(action)) { + + return true; + + } else { + log.error("Unknown action command {}.", action); + } + } while (true); + } + + return true; + } +} diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/SignPINGUI.java b/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/SignPINGUI.java index bc49b85e..da6c39b0 100644 --- a/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/SignPINGUI.java +++ b/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/SignPINGUI.java @@ -25,12 +25,14 @@ package at.gv.egiz.bku.pin.gui; import at.gv.egiz.bku.gui.BKUGUIFacade; -import at.gv.egiz.bku.smccstal.SecureViewer; +import at.gv.egiz.bku.gui.viewer.SecureViewer; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.PinInfo; import at.gv.egiz.smcc.pin.gui.PINGUI; -import at.gv.egiz.stal.signedinfo.SignedInfoType; +import at.gv.egiz.stal.SignatureInfo; + import java.security.DigestException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,7 +53,7 @@ public class SignPINGUI extends SignPINProvider implements PINGUI { private boolean retry = false; - public SignPINGUI(BKUGUIFacade gui, SecureViewer viewer, SignedInfoType signedInfo) { + public SignPINGUI(BKUGUIFacade gui, SecureViewer viewer, SignatureInfo signedInfo) { super(gui, viewer, signedInfo); } diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/SignPINProvider.java b/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/SignPINProvider.java index f9dfe068..efda713c 100644 --- a/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/SignPINProvider.java +++ b/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/SignPINProvider.java @@ -25,12 +25,15 @@ package at.gv.egiz.bku.pin.gui; import at.gv.egiz.bku.gui.BKUGUIFacade; -import at.gv.egiz.bku.smccstal.SecureViewer; +import at.gv.egiz.bku.gui.viewer.SecureViewer; +import at.gv.egiz.smcc.BulkSignException; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.PinInfo; import at.gv.egiz.smcc.pin.gui.PINProvider; -import at.gv.egiz.stal.signedinfo.SignedInfoType; +import at.gv.egiz.stal.SignatureInfo; + import java.security.DigestException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,10 +54,10 @@ public class SignPINProvider extends AbstractPINProvider implements PINProvider protected BKUGUIFacade gui; protected SecureViewer viewer; - protected SignedInfoType signedInfo; + protected SignatureInfo signedInfo; private boolean retry = false; - public SignPINProvider(BKUGUIFacade gui, SecureViewer viewer, SignedInfoType signedInfo) { + public SignPINProvider(BKUGUIFacade gui, SecureViewer viewer, SignatureInfo signedInfo) { this.gui = gui; this.viewer = viewer; this.signedInfo = signedInfo; @@ -62,7 +65,7 @@ public class SignPINProvider extends AbstractPINProvider implements PINProvider @Override public char[] providePIN(PinInfo spec, int retries) - throws CancelledException, InterruptedException { + throws CancelledException, InterruptedException, BulkSignException { gui.showSignaturePINDialog(spec, (retry) ? retries : -1, this, "sign", diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/VerifyPINProvider.java b/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/VerifyPINProvider.java index 59ee0593..77528ecb 100644 --- a/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/VerifyPINProvider.java +++ b/smccSTAL/src/main/java/at/gv/egiz/bku/pin/gui/VerifyPINProvider.java @@ -25,9 +25,11 @@ package at.gv.egiz.bku.pin.gui; import at.gv.egiz.bku.gui.BKUGUIFacade; +import at.gv.egiz.smcc.BulkSignException; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.PinInfo; import at.gv.egiz.smcc.pin.gui.PINProvider; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,7 +57,7 @@ public class VerifyPINProvider extends AbstractPINProvider implements PINProvide @Override public char[] providePIN(PinInfo spec, int retries) - throws CancelledException, InterruptedException { + throws CancelledException, InterruptedException, BulkSignException { gui.showVerifyPINDialog(spec, (retry) ? retries : -1, this, "verify", diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/BulkSignRequestHandler.java b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/BulkSignRequestHandler.java new file mode 100644 index 00000000..6d0403f7 --- /dev/null +++ b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/BulkSignRequestHandler.java @@ -0,0 +1,273 @@ +/* + * 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.smccstal; + +import iaik.me.asn1.ASN1; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.SignatureException; +import java.util.LinkedList; +import java.util.List; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.bku.gui.BKUGUIFacade; +import at.gv.egiz.bku.gui.viewer.SecureViewer; +import at.gv.egiz.bku.pin.gui.BulkSignPINGUI; +import at.gv.egiz.smcc.BulkSignException; +import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.LockedException; +import at.gv.egiz.smcc.NotActivatedException; +import at.gv.egiz.smcc.SignatureCard; +import at.gv.egiz.smcc.SignatureCard.KeyboxName; +import at.gv.egiz.smcc.SignatureCardException; +import at.gv.egiz.smcc.TimeoutException; +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.STALRequest; +import at.gv.egiz.stal.STALResponse; +import at.gv.egiz.stal.SignRequest; +import at.gv.egiz.stal.SignResponse; +import at.gv.egiz.stal.SignatureInfo; +import at.gv.egiz.stal.signedinfo.CanonicalizationMethodType; +import at.gv.egiz.stal.signedinfo.DigestMethodType; +import at.gv.egiz.stal.signedinfo.ObjectFactory; +import at.gv.egiz.stal.signedinfo.ReferenceType; +import at.gv.egiz.stal.signedinfo.SignatureMethodType; +import at.gv.egiz.stal.signedinfo.SignedInfoType; + +/** + * @author szoescher + */ +public class BulkSignRequestHandler extends AbstractRequestHandler { + + private final static Logger log = LoggerFactory.getLogger(BulkSignRequestHandler.class); + + private final static String CMS_DEF_SIGNEDINFO_ID = "SignedInfo-1"; + private final static String OID_MESSAGEDIGEST = "1.2.840.113549.1.9.4"; + + private static JAXBContext jaxbContext; + + static { + try { + jaxbContext = JAXBContext.newInstance(ObjectFactory.class.getPackage().getName()); + } catch (JAXBException e) { + Logger log = LoggerFactory.getLogger(BulkSignRequestHandler.class); + log.error("Cannot init jaxbContext", e); + } + } + + protected SecureViewer secureViewer; + + public BulkSignRequestHandler(SecureViewer secureViewer) { + this.secureViewer = secureViewer; + } + + private static ErrorResponse errorResponse(int errorCode, String errorMessage, Exception e) { + log.error(errorMessage, e); + ErrorResponse err = new ErrorResponse(errorCode); + err.setErrorMessage(errorMessage + (e == null ? "" : " " + e)); + return err; + } + + @Override + public STALResponse handleRequest(STALRequest request) throws InterruptedException { + if (request instanceof BulkSignRequest) { + BulkSignRequest bulkSignRequest = (BulkSignRequest) request; + BulkSignResponse stalResp = new BulkSignResponse(); + + + LinkedList signatureInfoList = new LinkedList(); + try { + + for(SignRequest signRequest : bulkSignRequest.getSignRequests()){ + + byte[] signedInfoData = signRequest.getSignedInfo().getValue(); + + SignatureInfo signatureInfo; + if (signRequest.getSignedInfo().isIsCMSSignedAttributes()) { + signatureInfo = createCMSSignedInfo(signRequest); + } else { + + Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + InputStream is = new ByteArrayInputStream(signedInfoData); + @SuppressWarnings("unchecked") + JAXBElement si = (JAXBElement) unmarshaller.unmarshal(is); + + signatureInfo = new SignatureInfo(si.getValue(), signRequest.getDisplayName(), signRequest.getMimeType()); + } + signatureInfoList.add(signatureInfo); + } + + BulkSignPINGUI pinGUI = new BulkSignPINGUI(gui, secureViewer, signatureInfoList, bulkSignRequest.getSignRequests().size()); + + + for (int i = 0; i < bulkSignRequest.getSignRequests().size(); i++) { + SignRequest signRequest = bulkSignRequest.getSignRequests().get(i); + STALResponse response = handleSignRequest(signRequest, pinGUI, signatureInfoList.get(i)); + pinGUI.setShowSignaturePINDialog(false); + + if (response instanceof SignResponse) { + stalResp.getSignResponse().add((SignResponse) response); + } + + if (response instanceof ErrorResponse) { + return response; + } + + } + } catch (SignatureException e) { + return errorResponse(4000, "Error while parsing CMS signature.", e); + } catch (JAXBException e) { + return errorResponse(1000, "Cannot unmarshal signed info.", e); + } + + return stalResp; + } else { + return errorResponse(1000, "Got unexpected STAL request: " + request + ".", null); + } + } + + @Override + public boolean requireCard() { + return true; + } + + private STALResponse handleSignRequest(SignRequest request, BulkSignPINGUI pinGUI, SignatureInfo signatureInfo) throws InterruptedException { + if (request instanceof SignRequest) { + + SignRequest signReq = (SignRequest) request; + byte[] signedInfoData = signReq.getSignedInfo().getValue(); + try { + + String signatureMethod = signatureInfo.getSignatureMethod().getAlgorithm(); + log.debug("Found signature method: {}.", signatureMethod); + KeyboxName kb = SignatureCard.KeyboxName.getKeyboxName(signReq.getKeyIdentifier()); + + byte[] resp = card.createSignature(new ByteArrayInputStream(signedInfoData), kb, pinGUI, signatureMethod); + + if (resp == null) { + return errorResponse(6001, "Response is null", null); + } + + SignResponse stalResp = new SignResponse(); + stalResp.setSignatureValue(resp); + return stalResp; + } catch (NotActivatedException e) { + gui.showErrorDialog(BKUGUIFacade.ERR_CARD_NOTACTIVATED, null, this, null); + waitForAction(); + gui.showMessageDialog(BKUGUIFacade.TITLE_WAIT, BKUGUIFacade.MESSAGE_WAIT); + return errorResponse(6001, "Citizen card not activated.", e); + } catch (LockedException e) { + gui.showErrorDialog(BKUGUIFacade.ERR_CARD_LOCKED, null, this, null); + waitForAction(); + gui.showMessageDialog(BKUGUIFacade.TITLE_WAIT, BKUGUIFacade.MESSAGE_WAIT); + return errorResponse(6001, "Citizen card locked.", e); + } catch (CancelledException cx) { + return errorResponse(6001, "User cancelled request.", null); + }catch (BulkSignException cx) { + return errorResponse(6001, "Limit of Signatures exceeded.", null); + } catch (TimeoutException ex) { + gui.showMessageDialog(BKUGUIFacade.TITLE_ENTRY_TIMEOUT, BKUGUIFacade.ERR_PIN_TIMEOUT, null, + BKUGUIFacade.BUTTON_CANCEL, this, null); + waitForAction(); + gui.showMessageDialog(BKUGUIFacade.TITLE_WAIT, BKUGUIFacade.MESSAGE_WAIT); + return errorResponse(6001, "Timeout during pin entry.", null); + } catch (SignatureCardException e) { + return errorResponse(4000, "Error while creating signature.", e); + } catch (IOException e) { + return errorResponse(4000, "Error while creating signature.", e); + } + } else { + return errorResponse(1000, "Got unexpected STAL request: " + request + ".", null); + } + } + + private static SignatureInfo createCMSSignedInfo(SignRequest signReq) throws SignatureException { + SignedInfoType signedInfo = new SignedInfoType(); + + log.trace("createCMSSignedInfo from SignRequest"); + byte[] signedInfoData = signReq.getSignedInfo().getValue(); + + CanonicalizationMethodType canonicalizationMethod = new CanonicalizationMethodType(); + canonicalizationMethod.setAlgorithm(""); + signedInfo.setCanonicalizationMethod(canonicalizationMethod); + + SignatureMethodType signatureMethod = new SignatureMethodType(); + signatureMethod.setAlgorithm(signReq.getSignatureMethod()); + signedInfo.setSignatureMethod(signatureMethod); + + signedInfo.setId(CMS_DEF_SIGNEDINFO_ID); + + List references = signedInfo.getReference(); + ReferenceType reference = new ReferenceType(); + reference.setId(HashDataInput.CMS_DEF_REFERENCE_ID); + DigestMethodType digestMethod = new DigestMethodType(); + digestMethod.setAlgorithm(signReq.getDigestMethod()); + reference.setDigestMethod(digestMethod); + byte[] messageDigest = null; + try { + ASN1 signedAttributes = new ASN1(signedInfoData); + if (!signedAttributes.isConstructed()) + throw new SignatureException("Error while parsing CMS signature"); + for (int i = 0; i < signedAttributes.getSize(); ++i) { + ASN1 signedAttribute = signedAttributes.getElementAt(i); + if (!signedAttribute.isConstructed()) + throw new SignatureException("Error while parsing CMS signature"); + ASN1 oid = signedAttribute.getElementAt(0); + if (oid.gvObjectId().equals(OID_MESSAGEDIGEST)) { + ASN1 value = signedAttribute.getElementAt(1); + if (!value.isConstructed()) + throw new SignatureException("Error while parsing CMS signature"); + messageDigest = value.getElementAt(0).gvByteArray(); + break; + } + } + } catch (IOException e) { + throw new SignatureException(e); + } + reference.setDigestValue(messageDigest); + if (signReq.getExcludedByteRange() != null) { + // Abuse URI to store ExcludedByteRange + String range = "CMSExcludedByteRange:" + signReq.getExcludedByteRange().getFrom() + "-" + + signReq.getExcludedByteRange().getTo(); + reference.setURI(range); + } + + references.add(reference); + + log.trace("Added SignatureInfo {} with name {} of type{}", new Object[] { signedInfo.getId(), signReq.getDisplayName(), signReq.getMimeType() }); + return new SignatureInfo(signedInfo, signReq.getDisplayName(), signReq.getMimeType()); + } + +} diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SecureViewer.java b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SecureViewer.java deleted file mode 100644 index ea279f40..00000000 --- a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SecureViewer.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2011 by Graz University of Technology, Austria - * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint - * initiative of the Federal Chancellery Austria and Graz University of Technology. - * - * 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.smccstal; - -import at.gv.egiz.stal.signedinfo.SignedInfoType; -import java.awt.event.ActionListener; -import java.security.DigestException; - -/** - * - * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at> - */ -public interface SecureViewer { - - /** - * Displays the hashdata inputs for all provided dsig:SignedReferences. - * Implementations may verify the digest value if necessary. - * (LocalSignRequestHandler operates on DataObjectHashDataInput, - * other SignRequestHandlers should cache the HashDataInputs obtained by webservice calls, - * or simply forward to a HashDataInputServlet.) - * @param signedInfo The caller may select a subset of the references in SignedInfo to be displayed. - * @param okListener - * @param okCommand - * @throws java.security.DigestException if digest values are verified and do not correspond - * (or any other digest computation error occurs) - * @throws java.lang.Exception - */ - void displayDataToBeSigned(SignedInfoType signedInfo, - ActionListener okListener, String okCommand) - throws DigestException, Exception; -} diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SignRequestHandler.java b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SignRequestHandler.java index 3026d27a..31c63379 100644 --- a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SignRequestHandler.java +++ b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SignRequestHandler.java @@ -41,6 +41,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import at.gv.egiz.bku.gui.BKUGUIFacade; +import at.gv.egiz.bku.gui.viewer.SecureViewer; import at.gv.egiz.bku.pin.gui.SignPINGUI; import at.gv.egiz.smcc.CancelledException; import at.gv.egiz.smcc.LockedException; @@ -55,6 +56,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 at.gv.egiz.stal.SignatureInfo; import at.gv.egiz.stal.signedinfo.CanonicalizationMethodType; import at.gv.egiz.stal.signedinfo.DigestMethodType; import at.gv.egiz.stal.signedinfo.ObjectFactory; @@ -97,10 +99,12 @@ public class SignRequestHandler extends AbstractRequestHandler { @Override public STALResponse handleRequest(STALRequest request) throws InterruptedException { if (request instanceof SignRequest) { + SignRequest signReq = (SignRequest) request; + byte[] signedInfoData = signReq.getSignedInfo().getValue(); try { - SignedInfoType signedInfo; + SignatureInfo signedInfo; if (signReq.getSignedInfo().isIsCMSSignedAttributes()) { signedInfo = createCMSSignedInfo(signReq); } else { @@ -109,7 +113,8 @@ public class SignRequestHandler extends AbstractRequestHandler { @SuppressWarnings("unchecked") JAXBElement si = (JAXBElement) unmarshaller.unmarshal(is); - signedInfo = si.getValue(); + + signedInfo = new SignatureInfo(si.getValue(), signReq.getDisplayName(), signReq.getMimeType()); } String signatureMethod = signedInfo.getSignatureMethod().getAlgorithm(); log.debug("Found signature method: {}.", signatureMethod); @@ -159,7 +164,7 @@ public class SignRequestHandler extends AbstractRequestHandler { } } - private static SignedInfoType createCMSSignedInfo(SignRequest signReq) throws SignatureException { + private static SignatureInfo createCMSSignedInfo(SignRequest signReq) throws SignatureException { SignedInfoType signedInfo = new SignedInfoType(); byte[] signedInfoData = signReq.getSignedInfo().getValue(); @@ -210,7 +215,7 @@ public class SignRequestHandler extends AbstractRequestHandler { reference.setURI(range); } references.add(reference); - return signedInfo; + return new SignatureInfo(signedInfo, signReq.getDisplayName(), signReq.getMimeType()); } @Override diff --git a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/CMSDataObjectOptionalMetaType.java b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/CMSDataObjectOptionalMetaType.java index 325d8dbf..8e00e85d 100644 --- a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/CMSDataObjectOptionalMetaType.java +++ b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/CMSDataObjectOptionalMetaType.java @@ -26,7 +26,10 @@ import javax.xml.bind.annotation.XmlType; * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <sequence> * <element name="MetaInfo" type="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}MetaInfoType" minOccurs="0"/> - * <element name="Content" type="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}Base64OptRefContentType"/> + * <choice> + * <element name="Content" type="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}Base64OptRefContentType"/> + * <element name="DigestAndRef" type="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}DigestAndRefType"/> + * </choice> * <element name="ExcludedByteRange" type="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}ExcludedByteRangeType" minOccurs="0"/> * </sequence> * </restriction> @@ -40,10 +43,12 @@ import javax.xml.bind.annotation.XmlType; @XmlType(name = "CMSDataObjectOptionalMetaType", propOrder = { "metaInfo", "content", + "digestAndRef", "excludedByteRange" }) @XmlSeeAlso({ - CMSDataObjectRequiredMetaType.class + CMSReferenceObject.class, + CMSDataObjectRequiredMetaType.class }) public class CMSDataObjectOptionalMetaType { @@ -51,6 +56,8 @@ public class CMSDataObjectOptionalMetaType { protected MetaInfoType metaInfo; @XmlElement(name = "Content", required = true) protected Base64OptRefContentType content; + @XmlElement(name = "DigestAndRef") + protected DigestAndRefType digestAndRef; @XmlElement(name = "ExcludedByteRange") protected ExcludedByteRangeType excludedByteRange; @@ -101,6 +108,30 @@ public class CMSDataObjectOptionalMetaType { public void setContent(Base64OptRefContentType value) { this.content = value; } + + /** + * Ruft den Wert der digestAndRef-Eigenschaft ab. + * + * @return + * possible object is + * {@link DigestAndRefType } + * + */ + public DigestAndRefType getDigestAndRef() { + return digestAndRef; + } + + /** + * Legt den Wert der digestAndRef-Eigenschaft fest. + * + * @param value + * allowed object is + * {@link DigestAndRefType } + * + */ + public void setDigestAndRef(DigestAndRefType value) { + this.digestAndRef = value; + } /** * Gets the value of the excludedByteRange property. diff --git a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/CMSReferenceObject.java b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/CMSReferenceObject.java new file mode 100644 index 00000000..b7c18e6b --- /dev/null +++ b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/CMSReferenceObject.java @@ -0,0 +1,46 @@ +// +// Diese Datei wurde mit der JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.5 generiert +// Siehe http://java.sun.com/xml/jaxb +// Änderungen an dieser Datei gehen bei einer Neukompilierung des Quellschemas verloren. +// Generiert: 2015.09.28 um 04:08:24 PM CEST +// + +package at.buergerkarte.namespaces.securitylayer._1_2_3; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java-Klasse für CMSReferenceObject complex type. + * + *

Das folgende Schemafragment gibt den erwarteten Content an, der in dieser Klasse enthalten ist. + * + *

+ * <complexType name="CMSReferenceObject">
+ *   <complexContent>
+ *     <restriction base="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}CMSDataObjectOptionalMetaType">
+ *       <sequence>
+ *         <element name="MetaInfo" type="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}MetaInfoType"/>
+ *         <choice>
+ *           <element name="Content" type="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}Base64OptRefContentType"/>
+ *           <element name="DigestAndRef" type="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}DigestAndRefType"/>
+ *         </choice>
+ *         <element name="ExcludedByteRange" type="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}ExcludedByteRangeType" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "CMSReferenceObject") +public class CMSReferenceObject + extends CMSDataObjectOptionalMetaType +{ + + +} diff --git a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/CreateCMSSignatureRequestType.java b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/CreateCMSSignatureRequestType.java index 5c0d0a4b..9f1befe0 100644 --- a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/CreateCMSSignatureRequestType.java +++ b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/CreateCMSSignatureRequestType.java @@ -28,7 +28,10 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> * <sequence> * <element name="KeyboxIdentifier" type="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}BoxIdentifierType"/> - * <element name="DataObject" type="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}CMSDataObjectRequiredMetaType"/> + * <choice> + * <element name="DataObject" type="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}CMSDataObjectRequiredMetaType"/> + * <element name="ReferenceObject" type="{http://www.buergerkarte.at/namespaces/securitylayer/1.2#}CMSReferenceObject"/> + * </choice> * </sequence> * <attribute name="Structure" use="required"> * <simpleType> @@ -49,15 +52,18 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "CreateCMSSignatureRequestType", propOrder = { "keyboxIdentifier", - "dataObject" + "dataObject", + "referenceObject" }) public class CreateCMSSignatureRequestType { @XmlElement(name = "KeyboxIdentifier", required = true) @XmlJavaTypeAdapter(CollapsedStringAdapter.class) protected String keyboxIdentifier; - @XmlElement(name = "DataObject", required = true) + @XmlElement(name = "DataObject") protected CMSDataObjectRequiredMetaType dataObject; + @XmlElement(name = "ReferenceObject") + protected CMSReferenceObject referenceObject; @XmlAttribute(name = "Structure", required = true) protected String structure; @XmlAttribute(name = "PAdESCompatibility") @@ -110,6 +116,30 @@ public class CreateCMSSignatureRequestType { public void setDataObject(CMSDataObjectRequiredMetaType value) { this.dataObject = value; } + + /** + * Ruft den Wert der referenceObject-Eigenschaft ab. + * + * @return + * possible object is + * {@link CMSReferenceObject } + * + */ + public CMSReferenceObject getReferenceObject() { + return referenceObject; + } + + /** + * Legt den Wert der referenceObject-Eigenschaft fest. + * + * @param value + * allowed object is + * {@link CMSReferenceObject } + * + */ + public void setReferenceObject(CMSReferenceObject value) { + this.referenceObject = value; + } /** * Gets the value of the structure property. diff --git a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/DigestAndRefType.java b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/DigestAndRefType.java new file mode 100644 index 00000000..477925ca --- /dev/null +++ b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/DigestAndRefType.java @@ -0,0 +1,128 @@ +// +// Diese Datei wurde mit der JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.5 generiert +// Siehe http://java.sun.com/xml/jaxb +// Änderungen an dieser Datei gehen bei einer Neukompilierung des Quellschemas verloren. +// Generiert: 2015.09.29 um 11:17:38 AM CEST +// + + +package at.buergerkarte.namespaces.securitylayer._1_2_3; + + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlSchemaType; +import javax.xml.bind.annotation.XmlType; + +import org.w3._2000._09.xmldsig_.DigestMethodType; + + +/** + *

Java-Klasse für DigestAndRefType complex type. + * + *

Das folgende Schemafragment gibt den erwarteten Content an, der in dieser Klasse enthalten ist. + * + *

+ * <complexType name="DigestAndRefType">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element ref="{http://www.w3.org/2000/09/xmldsig#}DigestMethod"/>
+ *         <element ref="{http://www.w3.org/2000/09/xmldsig#}DigestValue"/>
+ *       </sequence>
+ *       <attribute name="Reference" type="{http://www.w3.org/2001/XMLSchema}anyURI" />
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "DigestAndRefType", propOrder = { + "digestMethod", + "digestValue" +}) +public class DigestAndRefType { + + @XmlElement(name = "DigestMethod", namespace = "http://www.w3.org/2000/09/xmldsig#", required = true) + protected DigestMethodType digestMethod; + @XmlElement(name = "DigestValue", namespace = "http://www.w3.org/2000/09/xmldsig#", required = true) + protected byte[] digestValue; + @XmlAttribute(name = "Reference") + @XmlSchemaType(name = "anyURI") + protected String reference; + + /** + * Ruft den Wert der digestMethod-Eigenschaft ab. + * + * @return + * possible object is + * {@link DigestMethodType } + * + */ + public DigestMethodType getDigestMethod() { + return digestMethod; + } + + /** + * Legt den Wert der digestMethod-Eigenschaft fest. + * + * @param value + * allowed object is + * {@link DigestMethodType } + * + */ + public void setDigestMethod(DigestMethodType value) { + this.digestMethod = value; + } + + /** + * Ruft den Wert der digestValue-Eigenschaft ab. + * + * @return + * possible object is + * byte[] + */ + public byte[] getDigestValue() { + return digestValue; + } + + /** + * Legt den Wert der digestValue-Eigenschaft fest. + * + * @param value + * allowed object is + * byte[] + */ + public void setDigestValue(byte[] value) { + this.digestValue = value; + } + + /** + * Ruft den Wert der reference-Eigenschaft ab. + * + * @return + * possible object is + * {@link String } + * + */ + public String getReference() { + return reference; + } + + /** + * Legt den Wert der reference-Eigenschaft fest. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setReference(String value) { + this.reference = value; + } + +} diff --git a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/ObjectFactory.java b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/ObjectFactory.java index 20d5b15d..b3be3b76 100644 --- a/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/ObjectFactory.java +++ b/utils/src/main/java/at/buergerkarte/namespaces/securitylayer/_1_2_3/ObjectFactory.java @@ -660,6 +660,14 @@ public class ObjectFactory { public CMSDataObjectRequiredMetaType createCMSDataObjectRequiredMetaType() { return new CMSDataObjectRequiredMetaType(); } + + /** + * Create an instance of {@link CMSReferenceObject } + * + */ + public CMSReferenceObject createCMSReferenceObject() { + return new CMSReferenceObject(); + } /** * Create an instance of {@link at.buergerkarte.namespaces.securitylayer._1_2_3.XMLContentType } diff --git a/utils/src/main/java/at/gv/egiz/bku/utils/urldereferencer/FileURLProtocolHandlerImpl.java b/utils/src/main/java/at/gv/egiz/bku/utils/urldereferencer/FileURLProtocolHandlerImpl.java new file mode 100644 index 00000000..1580eb48 --- /dev/null +++ b/utils/src/main/java/at/gv/egiz/bku/utils/urldereferencer/FileURLProtocolHandlerImpl.java @@ -0,0 +1,63 @@ +/* + * 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.utils.urldereferencer; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSocketFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FileURLProtocolHandlerImpl implements URLProtocolHandler { + + private final Logger log = LoggerFactory.getLogger(FileURLProtocolHandlerImpl.class); + + public final static String FILE = "file"; + + + @Override + public StreamData dereference(String url) + throws IOException { + + URL u = new URL(url); + URLConnection connection = u.openConnection(); + + log.trace("Successfully opened connection."); + return new StreamData(url.toString(), connection.getContentType(), connection.getInputStream()); + + } + + @Override + public void setHostnameVerifier(HostnameVerifier hostnameVerifier) { + log.warn("not implemented for {}", this.getClass().getName()); + } + + @Override + public void setSSLSocketFactory(SSLSocketFactory socketFactory) { + log.warn("not implemented for {}", this.getClass().getName()); + } + +} diff --git a/utils/src/main/resources/at/gv/egiz/bku/slschema/Core-1.2.xsd b/utils/src/main/resources/at/gv/egiz/bku/slschema/Core-1.2.xsd index a97a98a5..75b999c7 100644 --- a/utils/src/main/resources/at/gv/egiz/bku/slschema/Core-1.2.xsd +++ b/utils/src/main/resources/at/gv/egiz/bku/slschema/Core-1.2.xsd @@ -1,1120 +1,1147 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3