summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BKULocal/src/main/webapp/WEB-INF/applicationContext.xml11
-rw-r--r--BKUOnline/src/main/webapp/WEB-INF/applicationContext.xml9
-rw-r--r--bkucommon/pom.xml4
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureCommand.java34
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureResult.java33
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandFactory.java43
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImpl.java201
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureResultImpl.java117
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALPrivateKey.java34
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALSecurityProvider.java76
-rw-r--r--bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/Signature.java255
-rw-r--r--bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/testApplicationContext.xml9
-rw-r--r--pom.xml5
13 files changed, 830 insertions, 1 deletions
diff --git a/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml b/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml
index f295398..b75db26 100644
--- a/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml
+++ b/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml
@@ -147,6 +147,14 @@
value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" />
<constructor-arg value="CreateXMLSignatureRequest" />
</bean>
+ <bean id="createCMSSignatureCommandFactory"
+ class="at.gv.egiz.bku.slcommands.impl.CreateCMSSignatureCommandFactory"
+ parent="abstractCommandFactory" />
+ <bean id="createCMSSignatureRequest" class="javax.xml.namespace.QName">
+ <constructor-arg
+ value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" />
+ <constructor-arg value="CreateCMSSignatureRequest" />
+ </bean>
<bean id="getStatusCommandFactory" class="at.gv.egiz.bku.slcommands.impl.GetStatusCommandFactory"
parent="abstractCommandFactory" />
<bean id="getStatusRequest" class="javax.xml.namespace.QName">
@@ -163,6 +171,7 @@
<entry key-ref="infoboxReadRequest" value-ref="infoboxReadCommandFactory" />
<entry key-ref="infoboxUpdateRequest" value-ref="infoboxUpdateCommandFactory" />
<entry key-ref="createXMLSignatureRequest" value-ref="createXMLSignatureCommandFactory" />
+ <entry key-ref="createCMSSignatureRequest" value-ref="createCMSSignatureCommandFactory" />
<entry key-ref="getStatusRequest" value-ref="getStatusCommandFactory" />
</map>
</property>
@@ -215,4 +224,4 @@
<property name="bindingProcessorManager" ref="bindingProcessorManager" />
</bean>
-</beans> \ No newline at end of file
+</beans>
diff --git a/BKUOnline/src/main/webapp/WEB-INF/applicationContext.xml b/BKUOnline/src/main/webapp/WEB-INF/applicationContext.xml
index 8093232..f85875c 100644
--- a/BKUOnline/src/main/webapp/WEB-INF/applicationContext.xml
+++ b/BKUOnline/src/main/webapp/WEB-INF/applicationContext.xml
@@ -135,6 +135,14 @@
value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" />
<constructor-arg value="CreateXMLSignatureRequest" />
</bean>
+ <bean id="createCMSSignatureCommandFactory"
+ class="at.gv.egiz.bku.slcommands.impl.CreateCMSSignatureCommandFactory"
+ parent="abstractCommandFactory" />
+ <bean id="createCMSSignatureRequest" class="javax.xml.namespace.QName">
+ <constructor-arg
+ value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" />
+ <constructor-arg value="CreateCMSSignatureRequest" />
+ </bean>
<bean id="getStatusCommandFactory" class="at.gv.egiz.bku.slcommands.impl.GetStatusCommandFactory"
parent="abstractCommandFactory" />
<bean id="getStatusRequest" class="javax.xml.namespace.QName">
@@ -151,6 +159,7 @@
<entry key-ref="infoboxReadRequest" value-ref="infoboxReadCommandFactory" />
<entry key-ref="infoboxUpdateRequest" value-ref="infoboxUpdateCommandFactory" />
<entry key-ref="createXMLSignatureRequest" value-ref="createXMLSignatureCommandFactory" />
+ <entry key-ref="createCMSSignatureRequest" value-ref="createCMSSignatureCommandFactory" />
<entry key-ref="getStatusRequest" value-ref="getStatusCommandFactory" />
</map>
</property>
diff --git a/bkucommon/pom.xml b/bkucommon/pom.xml
index 96fe94f..f6e0f0c 100644
--- a/bkucommon/pom.xml
+++ b/bkucommon/pom.xml
@@ -91,6 +91,10 @@
</dependency>
<dependency>
<groupId>iaik</groupId>
+ <artifactId>iaik_cms</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>iaik</groupId>
<artifactId>iaik_pki</artifactId>
<scope>compile</scope>
</dependency>
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureCommand.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureCommand.java
new file mode 100644
index 0000000..a68c012
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureCommand.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2013 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.slcommands;
+
+import at.gv.egiz.bku.slexceptions.SLCommandException;
+import at.gv.egiz.bku.slexceptions.SLRequestException;
+
+public interface CreateCMSSignatureCommand extends SLCommand {
+
+ public void prepareCMSSignature(SLCommandContext commandContext) throws SLCommandException, SLRequestException;
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureResult.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureResult.java
new file mode 100644
index 0000000..8f21584
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureResult.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2013 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.slcommands;
+
+import org.w3c.dom.Element;
+
+public interface CreateCMSSignatureResult extends SLResult {
+
+ public Element getContent();
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandFactory.java
new file mode 100644
index 0000000..2a642f9
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandFactory.java
@@ -0,0 +1,43 @@
+/*
+ * 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.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 CreateCMSSignatureCommandFactory extends AbstractSLCommandFactory {
+
+ @Override
+ public SLCommand createSLCommand(JAXBElement<?> element) throws SLCommandException {
+ CreateCMSSignatureCommandImpl command = new CreateCMSSignatureCommandImpl();
+ command.init(element);
+ command.setConfiguration(configuration);
+ return command;
+ }
+}
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
new file mode 100644
index 0000000..4825351
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImpl.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2013 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.slcommands.impl;
+
+import iaik.cms.CMSException;
+
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.configuration.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.buergerkarte.namespaces.securitylayer._1_2_3.CreateCMSSignatureRequestType;
+import at.gv.egiz.bku.conf.MoccaConfigurationFacade;
+import at.gv.egiz.bku.slcommands.CreateCMSSignatureCommand;
+import at.gv.egiz.bku.slcommands.SLCommandContext;
+import at.gv.egiz.bku.slcommands.SLResult;
+import at.gv.egiz.bku.slcommands.impl.cms.Signature;
+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.InfoboxReadRequest;
+import at.gv.egiz.stal.STALRequest;
+
+/**
+ * This class implements the security layer command
+ * <code>CreateCMSSignatureRequest</code>.
+ *
+ * @author tkellner
+ */
+public class CreateCMSSignatureCommandImpl extends
+ SLCommandImpl<CreateCMSSignatureRequestType> implements
+ CreateCMSSignatureCommand {
+
+ /**
+ * Logging facility.
+ */
+ private final Logger log = LoggerFactory.getLogger(CreateCMSSignatureCommandImpl.class);
+
+ /**
+ * The signing certificate.
+ */
+ protected X509Certificate signingCertificate;
+
+ /**
+ * The keybox identifier of the key used for signing.
+ */
+ protected String keyboxIdentifier;
+
+ /**
+ * The to-be signed signature.
+ */
+ protected Signature signature;
+
+ /**
+ * 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);
+ }
+}
+
+ public void setConfiguration(Configuration configuration) {
+ configurationFacade.setConfiguration(configuration);
+ }
+
+ @Override
+ public void prepareCMSSignature(SLCommandContext commandContext) throws SLCommandException,
+ SLRequestException {
+
+ CreateCMSSignatureRequestType request = getRequestValue();
+
+ // DataObject, SigningCertificate, SigningTime
+ Date signingTime = new Date();
+ try {
+ signature = new Signature(request.getDataObject(), signingCertificate,
+ signingTime, configurationFacade.getUseStrongHash());
+ } catch (Exception e) {
+ log.error("Error creating CMS Signature.", e);
+ throw new SLCommandException(4000);
+ }
+ }
+
+ /**
+ * Gets the signing certificate from STAL.
+ * @param commandContext TODO
+ *
+ * @throws SLCommandException
+ * if getting the singing certificate fails
+ */
+ private void getSigningCertificate(SLCommandContext commandContext) throws SLCommandException {
+
+ CreateCMSSignatureRequestType request = getRequestValue();
+ keyboxIdentifier = request.getKeyboxIdentifier();
+
+ InfoboxReadRequest stalRequest = new InfoboxReadRequest();
+ stalRequest.setInfoboxIdentifier(keyboxIdentifier);
+
+ STALHelper stalHelper = new STALHelper(commandContext.getSTAL());
+
+ stalHelper.transmitSTALRequest(Collections.singletonList((STALRequest) stalRequest));
+ List<X509Certificate> certificates = stalHelper.getCertificatesFromResponses();
+ if (certificates == null || certificates.size() != 1) {
+ log.info("Got an unexpected number of certificates from STAL.");
+ throw new SLCommandException(4000);
+ }
+ signingCertificate = certificates.get(0);
+
+ }
+
+ /**
+ * Signs the signature.
+ * @param commandContext TODO
+ * @return the CMS signature
+ * @throws SLCommandException
+ * if signing the signature fails
+ * @throws SLViewerException
+ */
+ private byte[] signCMSSignature(SLCommandContext commandContext) throws SLCommandException, SLViewerException {
+
+ try {
+ return signature.sign(commandContext.getSTAL(), keyboxIdentifier);
+ } catch (CMSException e) {
+ log.error("Error creating CMSSignature", e);
+ throw new SLCommandException(4000);
+ }
+ }
+
+ @Override
+ public SLResult execute(SLCommandContext commandContext) {
+ try {
+
+ // get certificate in order to select appropriate algorithms for hashing
+ // and signing
+ log.info("Requesting signing certificate.");
+ getSigningCertificate(commandContext);
+ if (log.isDebugEnabled()) {
+ log.debug("Got signing certificate. {}", signingCertificate);
+ } else {
+ log.info("Got signing certificate.");
+ }
+
+ // prepare the CMSSignature for signing
+ log.info("Preparing CMS signature.");
+ prepareCMSSignature(commandContext);
+
+ // sign the CMSSignature
+ log.info("Signing CMS signature.");
+ byte[] sig = signCMSSignature(commandContext);
+ log.info("CMS signature signed.");
+
+ return new CreateCMSSignatureResultImpl(sig);
+
+ } catch (SLException e) {
+ return new ErrorResultImpl(e, commandContext.getLocale());
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "CreateCMSSignatureRequest";
+ }
+
+}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureResultImpl.java
new file mode 100644
index 0000000..66b24a8
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureResultImpl.java
@@ -0,0 +1,117 @@
+/*
+ * 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.slcommands.impl;
+
+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.CreateCMSSignatureResponseType;
+import at.buergerkarte.namespaces.securitylayer._1_2_3.ObjectFactory;
+import at.gv.egiz.bku.slcommands.CreateCMSSignatureResult;
+import at.gv.egiz.bku.slcommands.SLMarshallerFactory;
+import at.gv.egiz.bku.slexceptions.SLRuntimeException;
+
+/**
+ * This implements the result of the security layer command <code>CreateCMSSignature</code>.
+ *
+ * @author tkellner
+ */
+public class CreateCMSSignatureResultImpl extends SLResultImpl implements CreateCMSSignatureResult {
+
+ /**
+ * Logging facility.
+ */
+ private final Logger log = LoggerFactory.getLogger(CreateCMSSignatureResultImpl.class);
+
+ /**
+ * The CMSSignature data.
+ */
+ protected byte[] signature;
+
+ /**
+ * The CMSSignatureResponse.
+ */
+ private Element content;
+
+ /**
+ * Creates a new instance of this CreateCMSSignatureResultImpl with the given
+ * signature <code>signature</code>.
+ *
+ * @param document the signature document
+ *
+ * @throws NullPointerException if <code>document</code> is <code>null</code>
+ */
+ public CreateCMSSignatureResultImpl(byte[] signature) {
+ super();
+
+ if (signature == null)
+ throw new NullPointerException("Argument 'signature' must not be null.");
+ this.signature = signature;
+
+ marshallCreateCMSSignatureResponse();
+ }
+
+ /**
+ * Marshalls the <code>CreateCMSSignatureResponse</code>.
+ */
+ private void marshallCreateCMSSignatureResponse() {
+
+ ObjectFactory factory = new ObjectFactory();
+
+ CreateCMSSignatureResponseType createCreateCMSSignatureResponseType = factory.createCreateCMSSignatureResponseType();
+ createCreateCMSSignatureResponseType.setCMSSignature(signature);
+ JAXBElement<CreateCMSSignatureResponseType> createCreateCMSSignatureResponse = factory.createCreateCMSSignatureResponse(createCreateCMSSignatureResponseType);
+
+ DOMResult res = new DOMResult();
+
+ Marshaller marshaller = SLMarshallerFactory.getInstance().createMarshaller(false);
+ try {
+ marshaller.marshal(createCreateCMSSignatureResponse, res);
+ } catch (JAXBException e) {
+ log.error("Failed to marshall 'CreateCMSSignatureResponse'.", 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/cms/STALPrivateKey.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALPrivateKey.java
new file mode 100644
index 0000000..8da5222
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALPrivateKey.java
@@ -0,0 +1,34 @@
+package at.gv.egiz.bku.slcommands.impl.cms;
+
+import java.security.PrivateKey;
+
+/**
+ * Dummy PrivateKey implementation for CMS signing using STAL
+ * @author tkellner
+ */
+public class STALPrivateKey implements PrivateKey {
+
+ private static final long serialVersionUID = 1L;
+
+ private String algorithm;
+
+ public STALPrivateKey(String algorithm) {
+ this.algorithm = algorithm;
+ }
+
+ @Override
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ throw new UnsupportedOperationException("STALPrivateKey does not support the getEncoded() method.");
+ }
+
+ @Override
+ public String getFormat() {
+ return null;
+ }
+
+}
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
new file mode 100644
index 0000000..437d29e
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALSecurityProvider.java
@@ -0,0 +1,76 @@
+package at.gv.egiz.bku.slcommands.impl.cms;
+
+import iaik.asn1.structures.AlgorithmID;
+import iaik.cms.IaikProvider;
+import iaik.utils.Util;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.SignatureException;
+import java.util.Collections;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.bku.slcommands.impl.xsect.STALSignatureException;
+import at.gv.egiz.stal.ErrorResponse;
+import at.gv.egiz.stal.STAL;
+import at.gv.egiz.stal.STALRequest;
+import at.gv.egiz.stal.STALResponse;
+import at.gv.egiz.stal.SignRequest;
+import at.gv.egiz.stal.SignResponse;
+
+public class STALSecurityProvider extends IaikProvider {
+
+ private final Logger log = LoggerFactory.getLogger(STALSecurityProvider.class);
+
+ private String keyboxIdentifier;
+
+ private STAL stal;
+
+ public STALSecurityProvider(STAL stal, String keyboxIdentifier) {
+ this.keyboxIdentifier = keyboxIdentifier;
+ this.stal = stal;
+ }
+
+ /* (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);
+
+ SignRequest signRequest = new SignRequest();
+ signRequest.setKeyIdentifier(keyboxIdentifier);
+ log.debug("SignedAttributes: " + Util.toBase64String(signedAttributes));
+ signRequest.setSignedInfo(signedAttributes);
+ signRequest.setSignedInfoIsRawData(true);
+ signRequest.setSignatureMethod(privateKey.getAlgorithm());
+
+ log.debug("Sending STAL request");
+ List<STALResponse> responses =
+ stal.handleRequest(Collections.singletonList((STALRequest) signRequest));
+
+ if (responses == null || responses.size() != 1) {
+ throw new SignatureException("Failed to access STAL.");
+ }
+
+ STALResponse response = responses.get(0);
+ if (response instanceof SignResponse) {
+ log.debug("Got STAL response: " + Util.toBase64String(((SignResponse) response).getSignatureValue()));
+ return ((SignResponse) response).getSignatureValue();
+ } else if (response instanceof ErrorResponse) {
+ ErrorResponse err = (ErrorResponse) response;
+ STALSignatureException se = new STALSignatureException(err.getErrorCode(), err.getErrorMessage());
+ throw new SignatureException(se);
+ } else {
+ throw new SignatureException("Failed to access STAL.");
+ }
+ }
+
+}
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
new file mode 100644
index 0000000..9f97e36
--- /dev/null
+++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/Signature.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2013 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.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.CertificateIdentifier;
+import iaik.cms.ContentInfo;
+import iaik.cms.IssuerAndSerialNumber;
+import iaik.cms.SignedData;
+import iaik.cms.SignerInfo;
+import iaik.security.ecc.interfaces.ECDSAParams;
+import iaik.smime.ess.ESSCertID;
+import iaik.smime.ess.ESSCertIDv2;
+import iaik.x509.X509ExtensionException;
+
+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 org.apache.commons.lang.ArrayUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.buergerkarte.namespaces.securitylayer._1_2_3.CMSDataObjectRequiredMetaType;
+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;
+import at.gv.egiz.stal.STAL;
+
+/**
+ * This class represents a CMS-Signature as to be created by the
+ * security layer command <code>CreateCMSSignatureRequest</code>.
+ *
+ * @author tkellner
+ */
+public class Signature {
+ /**
+ * Logging facility.
+ */
+ private final Logger log = LoggerFactory.getLogger(Signature.class);
+
+ private SignedData signedData;
+ private SignerInfo signerInfo;
+ private AlgorithmID signatureAlgorithm;
+ private AlgorithmID digestAlgorithm;
+ private String signatureAlgorithmURI;
+ @SuppressWarnings("unused")
+ private String digestAlgorithmURI;
+
+ public Signature(CMSDataObjectRequiredMetaType dataObject,
+ X509Certificate signingCertificate, Date signingTime, boolean useStrongHash) throws NoSuchAlgorithmException, CertificateEncodingException, CertificateException, X509ExtensionException, InvalidParameterException, CodingException {
+ byte[] data = getContent(dataObject);
+ this.signedData = new SignedData(data, SignedData.EXPLICIT);
+ setAlgorithmIDs(signingCertificate, useStrongHash);
+ createSignerInfo(signingCertificate);
+ setSignerCertificate(signingCertificate);
+ setAttributes(dataObject.getMetaInfo().getMimeType(), signingCertificate, signingTime);
+ }
+
+ private void createSignerInfo(X509Certificate signingCertificate) throws CertificateEncodingException, CertificateException {
+ iaik.x509.X509Certificate sigcert =
+ new iaik.x509.X509Certificate(signingCertificate.getEncoded());
+ CertificateIdentifier signerIdentifier =
+ new IssuerAndSerialNumber(sigcert);
+ PrivateKey privateKey = new STALPrivateKey(signatureAlgorithmURI);
+ signerInfo = new SignerInfo(signerIdentifier, digestAlgorithm,
+ signatureAlgorithm, privateKey);
+ }
+
+ private void setSignerCertificate(X509Certificate signingCertificate) {
+ X509Certificate[] sigcerts = new X509Certificate[] { signingCertificate };
+ signedData.addCertificates(sigcerts);
+ }
+
+ private void setAttributes(String mimeType, X509Certificate signingCertificate, Date signingTime) throws CertificateException, NoSuchAlgorithmException, CodingException {
+ List<Attribute> attributes = new ArrayList<Attribute>();
+ setMimeTypeAttrib(attributes, mimeType);
+ setContentTypeAttrib(attributes);
+ setSigningCertificateAttrib(attributes, signingCertificate);
+ setSigningTimeAttrib(attributes, signingTime);
+ Attribute[] attributeArray = attributes.toArray(new Attribute[attributes.size()]);
+ signerInfo.setSignedAttributes(attributeArray);
+ }
+
+ private void setMimeTypeAttrib(List<Attribute> attributes, String mimeType) {
+ String oidStr = "0.4.0.1733.2.1";
+ String name = "mime-type";
+ ObjectID mimeTypeOID = new ObjectID(oidStr, name);
+
+ Attribute mimeTypeAtt = new Attribute(mimeTypeOID, new ASN1Object[] {new UTF8String(mimeType)});
+ attributes.add(mimeTypeAtt);
+ }
+
+ private void setContentTypeAttrib(List<Attribute> attributes) {
+ Attribute contentType = new Attribute(ObjectID.contentType, new ASN1Object[] {ObjectID.cms_data});
+ attributes.add(contentType);
+ }
+
+ private void setSigningCertificateAttrib(List<Attribute> attributes, X509Certificate signingCertificate) throws CertificateException, NoSuchAlgorithmException, CodingException {
+ ObjectID id;
+ ASN1Object value = new SEQUENCE();
+ if (digestAlgorithm.equals(AlgorithmID.sha1)) {
+ id = ObjectID.signingCertificate;
+ value.addComponent(new ESSCertID(signingCertificate, true).toASN1Object());
+ }
+ else {
+ id = ObjectID.signingCertificateV2;
+ value.addComponent(new ESSCertIDv2(digestAlgorithm, signingCertificate, true).toASN1Object());
+ }
+ ASN1Object signingCert = new SEQUENCE();
+ signingCert.addComponent(value);
+ Attribute signingCertificateAttrib = new Attribute(id, new ASN1Object[] {signingCert});
+ attributes.add(signingCertificateAttrib);
+ }
+
+ private void setSigningTimeAttrib(List<Attribute> attributes, Date date) {
+ Attribute signingTime = new Attribute(ObjectID.signingTime, new ASN1Object[] {new ChoiceOfTime(date).toASN1Object()});
+ attributes.add(signingTime);
+ }
+
+ private byte[] getContent(CMSDataObjectRequiredMetaType dataObject) throws InvalidParameterException {
+ byte[] data = dataObject.getContent().getBase64Content();
+ ExcludedByteRangeType ebr = dataObject.getExcludedByteRange();
+ if (ebr == null)
+ return data;
+
+ int from = dataObject.getExcludedByteRange().getFrom().intValue();
+ int to = dataObject.getExcludedByteRange().getTo().intValue();
+ if (from > data.length || to > data.length || from > to)
+ throw new InvalidParameterException("ExcludeByteRange contains invalid data: [" +
+ from + "-" + to + "], Content length: " + data.length);
+ byte[] first = null;
+ byte[] second = null;
+ if (from > 0)
+ first = Arrays.copyOfRange(data, 0, from);
+ if ((to + 1) < data.length)
+ second = Arrays.copyOfRange(data, to + 1, data.length);
+ data = ArrayUtils.addAll(first, second);
+ log.debug("ExcludeByteRange [" + from + "-" + to + "], Content length: " + data.length);
+ return data;
+ }
+
+ private void setSignerInfo() {
+ try {
+ signedData.addSignerInfo(signerInfo);
+ } catch (NoSuchAlgorithmException e) {
+ log.error("Error setting signer info", e);
+ }
+ }
+
+ 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();
+ 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();
+ }
+
+ if (useStrongHash && keyLength >= 2048) {
+ signatureAlgorithm = AlgorithmID.sha256WithRSAEncryption;
+ digestAlgorithm = AlgorithmID.sha256;
+ } else if (useStrongHash) {
+ 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 iaik.security.ecc.ecdsa.ECPublicKey) {
+ ECDSAParams params = ((iaik.security.ecc.ecdsa.ECPublicKey) publicKey).getParameter();
+ fieldSize = params.getG().getCurve().getField().getSize().bitLength();
+ } else if (publicKey instanceof ECPublicKey) {
+ ECParameterSpec params = ((ECPublicKey) publicKey).getParams();
+ fieldSize = params.getCurve().getField().getFieldSize();
+ }
+
+ if (useStrongHash && fieldSize >= 512) {
+ signatureAlgorithm = AlgorithmID.ecdsa_plain_With_SHA512;
+ digestAlgorithm = AlgorithmID.sha512;
+ } else if (useStrongHash && fieldSize >= 256) {
+ signatureAlgorithm = AlgorithmID.ecdsa_plain_With_SHA256;
+ digestAlgorithm = AlgorithmID.sha256;
+ } else if (useStrongHash) {
+ signatureAlgorithm = AlgorithmID.ecdsa_plain_With_RIPEMD160;
+ digestAlgorithm = AlgorithmID.ripeMd160;
+ } else {
+ signatureAlgorithm = AlgorithmID.ecdsa_plain_With_SHA1;
+ digestAlgorithm = AlgorithmID.sha1;
+ }
+ } else {
+ throw new NoSuchAlgorithmException("Public key algorithm '" + algorithm
+ + "' not supported.");
+ }
+ }
+
+ public byte[] sign(STAL stal, String keyboxIdentifier) throws CMSException {
+ signedData.setSecurityProvider(new STALSecurityProvider(stal, keyboxIdentifier));
+ setSignerInfo();
+ ContentInfo contentInfo = new ContentInfo(signedData);
+ return contentInfo.getEncoded();
+ }
+}
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 3ec4439..7d7c967 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
@@ -110,6 +110,14 @@
value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" />
<constructor-arg value="CreateXMLSignatureRequest" />
</bean>
+ <bean id="createCMSSignatureCommandFactory"
+ class="at.gv.egiz.bku.slcommands.impl.CreateCMSSignatureCommandFactory"
+ parent="abstractCommandFactory" />
+ <bean id="createCMSSignatureRequest" class="javax.xml.namespace.QName">
+ <constructor-arg
+ value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" />
+ <constructor-arg value="CreateCMSSignatureRequest" />
+ </bean>
<bean id="getStatusCommandFactory" class="at.gv.egiz.bku.slcommands.impl.GetStatusCommandFactory"
parent="abstractCommandFactory" />
<bean id="getStatusRequest" class="javax.xml.namespace.QName">
@@ -126,6 +134,7 @@
<entry key-ref="infoboxReadRequest" value-ref="infoboxReadCommandFactory" />
<entry key-ref="infoboxUpdateRequest" value-ref="infoboxUpdateCommandFactory" />
<entry key-ref="createXMLSignatureRequest" value-ref="createXMLSignatureCommandFactory" />
+ <entry key-ref="createCMSSignatureRequest" value-ref="createCMSSignatureCommandFactory" />
<entry key-ref="getStatusRequest" value-ref="getStatusCommandFactory" />
</map>
</property>
diff --git a/pom.xml b/pom.xml
index 213e080..906d3b3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -335,6 +335,11 @@
</dependency>
<dependency>
<groupId>iaik</groupId>
+ <artifactId>iaik_cms</artifactId>
+ <version>4.1</version>
+ </dependency>
+ <dependency>
+ <groupId>iaik</groupId>
<artifactId>iaik_pki</artifactId>
<version>1.0-MOCCA</version>
<scope>compile</scope>