aboutsummaryrefslogtreecommitdiff
path: root/moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/server/invoke/CMSSignatureCreationInvoker.java
diff options
context:
space:
mode:
Diffstat (limited to 'moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/server/invoke/CMSSignatureCreationInvoker.java')
-rw-r--r--moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/server/invoke/CMSSignatureCreationInvoker.java437
1 files changed, 437 insertions, 0 deletions
diff --git a/moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/server/invoke/CMSSignatureCreationInvoker.java b/moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/server/invoke/CMSSignatureCreationInvoker.java
new file mode 100644
index 0000000..718673a
--- /dev/null
+++ b/moaSig/moa-sig-lib/src/main/java/at/gv/egovernment/moa/spss/server/invoke/CMSSignatureCreationInvoker.java
@@ -0,0 +1,437 @@
+/*
+ * Copyright 2003 Federal Chancellery Austria
+ * MOA-SPSS has been developed in a cooperation between BRZ, the Federal
+ * Chancellery Austria - ICT staff unit, 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.egovernment.moa.spss.server.invoke;
+
+import iaik.server.modules.algorithms.HashAlgorithms;
+import iaik.server.modules.cmssign.CMSSignature;
+import iaik.server.modules.cmssign.CMSSignatureCreationException;
+import iaik.server.modules.cmssign.CMSSignatureCreationModule;
+import iaik.server.modules.cmssign.CMSSignatureCreationModuleFactory;
+import iaik.server.modules.cmssign.CMSSignatureCreationProfile;
+import iaik.server.modules.keys.KeyEntryID;
+import iaik.server.modules.keys.KeyModule;
+import iaik.server.modules.keys.KeyModuleFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.security.Principal;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import at.gv.egovernment.moa.logging.LogMsg;
+import at.gv.egovernment.moa.logging.Logger;
+import at.gv.egovernment.moa.spss.MOAApplicationException;
+import at.gv.egovernment.moa.spss.MOAException;
+import at.gv.egovernment.moa.spss.MOASystemException;
+import at.gv.egovernment.moa.spss.api.cmssign.CreateCMSSignatureRequest;
+import at.gv.egovernment.moa.spss.api.cmssign.CreateCMSSignatureResponse;
+import at.gv.egovernment.moa.spss.api.cmssign.DataObjectInfo;
+import at.gv.egovernment.moa.spss.api.cmssign.SingleSignatureInfo;
+import at.gv.egovernment.moa.spss.api.cmsverify.CMSContent;
+import at.gv.egovernment.moa.spss.api.cmsverify.CMSContentExcplicit;
+import at.gv.egovernment.moa.spss.api.cmsverify.CMSContentReference;
+import at.gv.egovernment.moa.spss.api.cmsverify.CMSDataObject;
+import at.gv.egovernment.moa.spss.api.common.MetaInfo;
+import at.gv.egovernment.moa.spss.api.impl.CreateCMSSignatureResponseImpl;
+import at.gv.egovernment.moa.spss.server.config.ConfigurationProvider;
+import at.gv.egovernment.moa.spss.server.config.KeyGroupEntry;
+import at.gv.egovernment.moa.spss.server.iaik.cmssign.CMSSignatureCreationProfileImpl;
+import at.gv.egovernment.moa.spss.server.logging.TransactionId;
+import at.gv.egovernment.moa.spss.server.transaction.TransactionContext;
+import at.gv.egovernment.moa.spss.server.transaction.TransactionContextManager;
+import at.gv.egovernment.moa.spss.util.MessageProvider;
+import at.gv.egovernment.moa.util.Constants;
+
+/**
+ * A class providing an API based interface to the
+ * <code>CMSSignatureCreationModule</code>.
+ *
+ * This class performs the invocation of the
+ * <code>iaik.server.modules.cmssign.CMSSignatureCreationModule</code> from a
+ * <code>CreateCMSSignatureRequest</code> given as an API object. The result of
+ * the invocation is integrated into a <code>CreateCMSSignatureResponse</code>
+ * and returned.
+ *
+ * @version $Id$
+ */
+public class CMSSignatureCreationInvoker {
+
+ private static Map HASH_ALGORITHM_MAPPING;
+
+ static {
+ HASH_ALGORITHM_MAPPING = new HashMap();
+ HASH_ALGORITHM_MAPPING.put(Constants.SHA1_URI, HashAlgorithms.SHA1);
+ HASH_ALGORITHM_MAPPING.put(Constants.SHA256_URI, HashAlgorithms.SHA256);
+ HASH_ALGORITHM_MAPPING.put(Constants.SHA384_URI, HashAlgorithms.SHA384);
+ HASH_ALGORITHM_MAPPING.put(Constants.SHA512_URI, HashAlgorithms.SHA512);
+ }
+
+
+ /** The single instance of this class. */
+ private static CMSSignatureCreationInvoker instance = null;
+
+ /**
+ * Get the only instance of this class.
+ *
+ * @return The only instance of this class.
+ */
+ public static synchronized CMSSignatureCreationInvoker getInstance() {
+ if (instance == null) {
+ instance = new CMSSignatureCreationInvoker();
+ }
+ return instance;
+ }
+
+ /**
+ * Create a new <code>CMSSignatureCreationInvoker</code>.
+ *
+ * Protected to disallow multiple instances.
+ */
+ protected CMSSignatureCreationInvoker() {
+ }
+
+
+
+ /**
+ * Process the <code>CreateCMSSignatureRequest<code> message and invoke the
+ * <code>XMLSignatureCreationModule</code> for every
+ * <code>SingleSignatureInfo</code> contained in the request.
+ *
+ * @param request A <code>CreateCMSSignatureRequest<code> API object
+ * containing the information for creating the signature(s).
+ * @param reserved A <code>Set</code> of reserved object IDs.
+ *
+ * @return A <code>CreateCMSSignatureResponse</code> API object containing
+ * the created signature(s). The response contains either a
+ * <code>SignatureEnvironment</code> or a <code>ErrorResponse</code>
+ * for each <code>SingleSignatureInfo</code> in the request.
+ * @throws MOAException An error occurred during signature creation.
+ */
+ public CreateCMSSignatureResponse createCMSSignature(
+ CreateCMSSignatureRequest request,
+ Set reserved)
+ throws MOAException {
+
+ TransactionContext context = TransactionContextManager.getInstance().getTransactionContext();
+ //LoggingContext loggingCtx = LoggingContextManager.getInstance().getLoggingContext();
+
+ CreateCMSSignatureResponseBuilder responseBuilder = new CreateCMSSignatureResponseBuilder();
+ CreateCMSSignatureResponse response = new CreateCMSSignatureResponseImpl();
+
+ boolean isSecurityLayerConform = false;
+ String structure = null;
+ String mimetype = null;
+
+ // select the SingleSignatureInfo elements
+ Iterator singleSignatureInfoIter = request.getSingleSignatureInfos().iterator();
+
+ // iterate over all the SingleSignatureInfo elements in the request
+ while (singleSignatureInfoIter.hasNext()) {
+ SingleSignatureInfo singleSignatureInfo = (SingleSignatureInfo) singleSignatureInfoIter.next();
+ isSecurityLayerConform = singleSignatureInfo.isSecurityLayerConform();
+
+
+ DataObjectInfo dataObjectInfo = singleSignatureInfo.getDataObjectInfo();
+ structure = dataObjectInfo.getStructure();
+
+ CMSDataObject dataobject = dataObjectInfo.getDataObject();
+ MetaInfo metainfo = dataobject.getMetaInfo();
+ mimetype = metainfo.getMimeType();
+
+ CMSContent content = dataobject.getContent();
+ InputStream contentIs = null;
+ // build the content data
+ switch (content.getContentType()) {
+ case CMSContent.EXPLICIT_CONTENT :
+ contentIs = ((CMSContentExcplicit) content).getBinaryContent();
+ break;
+ case CMSContent.REFERENCE_CONTENT :
+ String reference = ((CMSContentReference) content).getReference();
+ if (!"".equals(reference)) {
+ ExternalURIResolver resolver = new ExternalURIResolver();
+ contentIs = resolver.resolve(reference);
+ } else {
+ throw new MOAApplicationException("2301", null);
+ }
+ break;
+ default : {
+ throw new MOAApplicationException("2301", null);
+ }
+ }
+
+ // create CMSSignatureCreationModuleFactory
+ CMSSignatureCreationModule module = CMSSignatureCreationModuleFactory.getInstance();
+
+ List signedProperties = null;
+ boolean includeData = true;
+ if (structure.compareTo("enveloping") == 0)
+ includeData = true;
+ if (structure.compareTo("detached") == 0)
+ includeData = false;
+
+ ConfigurationProvider config = context.getConfiguration();
+
+ // get the key group id
+ String keyGroupID = request.getKeyIdentifier();
+ // set the key set
+ Set keySet = buildKeySet(keyGroupID);
+ if (keySet == null) {
+ throw new MOAApplicationException("2231", null);
+ } else if (keySet.size() == 0) {
+ throw new MOAApplicationException("2232", null);
+ }
+
+ // get digest algorithm
+ String digestAlgorithm = getDigestAlgorithm(config, keyGroupID);
+
+ // create CMSSignatureCreation profile:
+ CMSSignatureCreationProfile profile = new CMSSignatureCreationProfileImpl(
+ keySet,
+ digestAlgorithm,
+ signedProperties,
+ isSecurityLayerConform,
+ includeData,
+ mimetype);
+
+ // create CMSSignature from the CMSSignatureCreationModule
+ // build the additionalSignedProperties
+ List additionalSignedProperties = buildAdditionalSignedProperties();
+ TransactionId tid = new TransactionId(context.getTransactionID());
+ try {
+ CMSSignature signature = module.createSignature(profile, additionalSignedProperties, tid);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ // get CMS SignedData output stream from the CMSSignature and wrap it around out
+ boolean base64 = true;
+ OutputStream signedDataStream = signature.getSignature(out, base64);
+
+ // now write the data to be signed to the signedDataStream
+
+ int byteRead;
+ BigDecimal counter = new BigDecimal("0");
+ BigDecimal one = new BigDecimal("1");
+
+ while ((byteRead=contentIs.read()) >= 0) {
+ //System.out.println("counterXX: " + counter);
+
+ if (inRange(counter, dataobject)) {
+ //System.out.println("Lösche...");
+ // set byte to 0x00
+ signedDataStream.write(0);
+ }
+ else
+ signedDataStream.write(byteRead);
+
+ counter = counter.add(one);
+ }
+
+
+// byte[] buf = new byte[4096];
+// int bytesRead;
+// while ((bytesRead = contentIs.read(buf)) >= 0) {
+// signedDataStream.write(buf, 0, bytesRead);
+// }
+//
+ // finish SignedData processing by closing signedDataStream
+ signedDataStream.close();
+ String base64value = out.toString();
+
+ responseBuilder.addCMSSignature(base64value);
+
+
+ } catch (CMSSignatureCreationException e) {
+ MOAException moaException = IaikExceptionMapper.getInstance().map(e);
+
+ responseBuilder.addError(
+ moaException.getMessageId(),
+ moaException.getMessage());
+ Logger.warn(moaException.getMessage(), e);
+
+ }
+ catch (IOException e) {
+ throw new MOAApplicationException("2301", null, e);
+ }
+
+ }
+
+
+ return responseBuilder.getResponse();
+ }
+
+ private boolean inRange(BigDecimal counter, CMSDataObject dataobject) {
+ BigDecimal from = dataobject.getExcludeByteRangeFrom();
+ BigDecimal to = dataobject.getExcludeByteRangeTo();
+
+ if ( (from == null) || (to == null))
+ return false;
+
+ int compare = counter.compareTo(from);
+ if (compare == -1)
+ return false;
+ else {
+ compare = counter.compareTo(to);
+ if (compare == 1)
+ return false;
+ else
+ return true;
+ }
+
+
+
+ }
+
+
+ private String getDigestAlgorithm(ConfigurationProvider config, String keyGroupID) throws MOASystemException {
+ // get digest method on key group level (if configured)
+ String configDigestMethodKG = config.getKeyGroup(keyGroupID).getDigestMethodAlgorithm();
+ // get default digest method (if configured)
+ String configDigestMethod = config.getDigestMethodAlgorithmName();
+
+
+ String digestMethod = null;
+ if (configDigestMethodKG != null) {
+ // if KG specific digest method is configured
+ digestMethod = (String) HASH_ALGORITHM_MAPPING.get(configDigestMethodKG);
+ if (digestMethod == null) {
+ error(
+ "config.17",
+ new Object[] { configDigestMethodKG});
+ throw new MOASystemException("2900", null);
+ }
+ Logger.debug("Digest algorithm: " + digestMethod + "(configured in KeyGroup)");
+ }
+ else {
+ // else get default configured digest method
+ digestMethod = (String) HASH_ALGORITHM_MAPPING.get(configDigestMethod);
+ if (digestMethod == null) {
+ error(
+ "config.17",
+ new Object[] { configDigestMethod});
+ throw new MOASystemException("2900", null);
+ }
+ Logger.debug("Digest algorithm: " + digestMethod + "(default)");
+
+ }
+ return digestMethod;
+ }
+
+ /**
+ * Utility function to issue an error message to the log.
+ *
+ * @param messageId The ID of the message to log.
+ * @param parameters Additional message parameters.
+ */
+ private static void error(String messageId, Object[] parameters) {
+ MessageProvider msg = MessageProvider.getInstance();
+
+ Logger.error(new LogMsg(msg.getMessage(messageId, parameters)));
+ }
+
+ /**
+ * Build the set of <code>KeyEntryID</code>s available to the given
+ * <code>keyGroupID</code>.
+ *
+ * @param keyGroupID The keygroup ID for which the available keys should be
+ * returned.
+ * @return The <code>Set</code> of <code>KeyEntryID</code>s
+ * identifying the available keys.
+ */
+ private Set buildKeySet(String keyGroupID) {
+ TransactionContext context =
+ TransactionContextManager.getInstance().getTransactionContext();
+ ConfigurationProvider config = context.getConfiguration();
+ Set keyGroupEntries;
+
+ // get the KeyGroup entries from the configuration
+ if (context.getClientCertificate() != null) {
+ X509Certificate cert = context.getClientCertificate()[0];
+ Principal issuer = cert.getIssuerDN();
+ BigInteger serialNumber = cert.getSerialNumber();
+
+ keyGroupEntries =
+ config.getKeyGroupEntries(issuer, serialNumber, keyGroupID);
+ } else {
+ keyGroupEntries = config.getKeyGroupEntries(null, null, keyGroupID);
+ }
+
+ // map the KeyGroup entries to a set of KeyEntryIDs
+ if (keyGroupEntries == null) {
+ return null;
+ } else if (keyGroupEntries.size() == 0) {
+ return Collections.EMPTY_SET;
+ } else {
+ KeyModule module =
+ KeyModuleFactory.getInstance(
+ new TransactionId(context.getTransactionID()));
+ Set keyEntryIDs = module.getPrivateKeyEntryIDs();
+ Set keySet = new HashSet();
+ Iterator iter;
+
+ // filter out the keys that do not exist in the IAIK configuration
+ // by walking through the key entries and checking if the exist in the
+ // keyGroupEntries
+ for (iter = keyEntryIDs.iterator(); iter.hasNext();) {
+ KeyEntryID entryID = (KeyEntryID) iter.next();
+ KeyGroupEntry entry =
+ new KeyGroupEntry(
+ entryID.getModuleID(),
+ entryID.getCertificateIssuer(),
+ entryID.getCertificateSerialNumber());
+ if (keyGroupEntries.contains(entry)) {
+ keySet.add(entryID);
+ }
+ }
+ return keySet;
+ }
+ }
+
+ /**
+ * Build the list of additional signed properties.
+ *
+ * Based on the generic configuration setting
+ * <code>ConfigurationProvider.TEST_SIGNING_TIME_PROPERTY</code>, a
+ * constant <code>SigningTime</code> will be added to the properties.
+ *
+ * @return The <code>List</code> of additional signed properties.
+ */
+ private List buildAdditionalSignedProperties() {
+ TransactionContext context =
+ TransactionContextManager.getInstance().getTransactionContext();
+ ConfigurationProvider config = context.getConfiguration();
+ List additionalSignedProperties = Collections.EMPTY_LIST;
+
+ return additionalSignedProperties;
+ }
+
+} \ No newline at end of file