From 535a04fa05f739ec16dd81666e3b0f82dfbd442d Mon Sep 17 00:00:00 2001 From: tknall Date: Wed, 9 Jan 2013 15:41:29 +0000 Subject: pdf-as-lib maven project files moved to pdf-as-lib git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/pdf-as/trunk@926 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c --- .../at/knowcenter/wag/egov/egiz/sig/Connector.java | 67 + .../wag/egov/egiz/sig/ConnectorFactory.java | 372 ++++ .../wag/egov/egiz/sig/ConnectorInformation.java | 97 + .../knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java | 100 + .../at/knowcenter/wag/egov/egiz/sig/LDAPAPI.java | 50 + .../wag/egov/egiz/sig/LocalConnector.java | 127 ++ .../wag/egov/egiz/sig/SignatureBlock.java | 316 +++ .../wag/egov/egiz/sig/SignatureData.java | 82 + .../wag/egov/egiz/sig/SignatureDataImpl.java | 130 ++ .../wag/egov/egiz/sig/SignatureEntry.java | 163 ++ .../egov/egiz/sig/SignatureFieldDefinition.java | 88 + .../wag/egov/egiz/sig/SignatureObject.java | 2108 ++++++++++++++++++++ .../wag/egov/egiz/sig/SignatureResponse.java | 559 ++++++ .../wag/egov/egiz/sig/SignatureSeparator.java | 146 ++ .../wag/egov/egiz/sig/SignatureTypeDefinition.java | 605 ++++++ .../wag/egov/egiz/sig/SignatureTypes.java | 515 +++++ .../at/knowcenter/wag/egov/egiz/sig/X509Cert.java | 490 +++++ .../wag/egov/egiz/sig/connectors/A1Connector.java | 63 + .../wag/egov/egiz/sig/connectors/BKUConnector.java | 896 +++++++++ .../egiz/sig/connectors/BKUPostConnection.java | 157 ++ .../wag/egov/egiz/sig/connectors/Connector.java | 77 + .../egov/egiz/sig/connectors/ConnectorChooser.java | 353 ++++ .../sig/connectors/ConnectorConfigurationKeys.java | 55 + .../egiz/sig/connectors/ConnectorEnvironment.java | 52 + .../egov/egiz/sig/connectors/LocalConnector.java | 91 + .../wag/egov/egiz/sig/connectors/MOAConnector.java | 921 +++++++++ .../egov/egiz/sig/connectors/TemplateReplaces.java | 172 ++ .../egov/egiz/sig/connectors/bku/BKUHelper.java | 695 +++++++ .../egiz/sig/connectors/bku/BKUPostConnection.java | 179 ++ .../sig/connectors/bku/DetachedBKUConnector.java | 823 ++++++++ .../bku/EnvelopedBase64BKUConnector.java | 666 +++++++ .../connectors/bku/LocRefDetachedBKUConnector.java | 46 + .../bku/MultipartDetachedBKUConnector.java | 42 + .../bku/OldEnvelopingBase64BKUConnector.java | 135 ++ .../sig/connectors/bku/SignSignatureObject.java | 272 +++ .../connectors/bku/SignSignatureObjectHelper.java | 76 + .../connectors/moa/DetachedLocRefMOAConnector.java | 661 ++++++ .../moa/EnvelopingBase64MOAConnector.java | 638 ++++++ .../egov/egiz/sig/connectors/moa/FilePartMR.java | 152 ++ .../egov/egiz/sig/connectors/moa/MOAHelper.java | 228 +++ .../egiz/sig/connectors/moa/MOASoapConnection.java | 277 +++ .../moa/MOASoapWithAttachmentConnector.java | 745 +++++++ .../sig/connectors/moa/MultipartRelatedEntity.java | 79 + .../egov/egiz/sig/connectors/moa/StringPartMR.java | 189 ++ .../mocca/LocRefDetachedMOCCAConnector.java | 623 ++++++ .../egiz/sig/connectors/mocca/MOCCAHelper.java | 223 +++ .../egov/egiz/sig/sigid/DetachedIdFormatter.java | 101 + .../sig/sigid/DetachedLocRefMOAIdFormatter.java | 80 + .../egiz/sig/sigid/DetachedMOCIdFormatter.java | 78 + .../wag/egov/egiz/sig/sigid/HotfixIdFormatter.java | 74 + .../wag/egov/egiz/sig/sigid/IdFormatter.java | 34 + .../wag/egov/egiz/sig/sigid/OldMOAIdFormatter.java | 42 + .../wag/egov/egiz/sig/sigid/SimpleIdFormatter.java | 48 + .../wag/egov/egiz/sig/sigkz/SigKZIDHelper.java | 262 +++ .../signaturelayout/SignatureLayoutHandler.java | 45 + .../SignatureLayoutHandlerFactory.java | 147 ++ .../atrust/ATrustSignatureLayoutHandler.java | 47 + .../mocca/MOCCASignatureLayout10Handler.java | 48 + .../mocca/OldMOCCASignatureLayoutHandler.java | 48 + .../td/TrustDeskSignatureLayoutHandler.java | 46 + .../AdditionalSignatureInformation.java | 41 + .../AlgorithmSignatureInformation.java | 33 + .../ConnectorSignatureInformation.java | 34 + .../MandatorySignatureInformation.java | 40 + .../sig/signatureobject/SignatureObjectHelper.java | 81 + 65 files changed, 16930 insertions(+) create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/Connector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorFactory.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorInformation.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LDAPAPI.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureBlock.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureData.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureDataImpl.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureEntry.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureFieldDefinition.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureResponse.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureSeparator.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypeDefinition.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/A1Connector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/Connector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorChooser.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorConfigurationKeys.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorEnvironment.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/LocalConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/TemplateReplaces.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUPostConnection.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/LocRefDetachedBKUConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/MultipartDetachedBKUConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/OldEnvelopingBase64BKUConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObject.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObjectHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/FilePartMR.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOAHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapConnection.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MultipartRelatedEntity.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/StringPartMR.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/MOCCAHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedIdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedLocRefMOAIdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedMOCIdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/HotfixIdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/IdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/OldMOAIdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/SimpleIdFormatter.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandler.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandlerFactory.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/atrust/ATrustSignatureLayoutHandler.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MOCCASignatureLayout10Handler.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/OldMOCCASignatureLayoutHandler.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/td/TrustDeskSignatureLayoutHandler.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AdditionalSignatureInformation.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AlgorithmSignatureInformation.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/ConnectorSignatureInformation.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/MandatorySignatureInformation.java create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/SignatureObjectHelper.java (limited to 'pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig') diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/Connector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/Connector.java new file mode 100644 index 0000000..f70f19c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/Connector.java @@ -0,0 +1,67 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: Connector.java,v 1.3 2006/10/11 07:54:03 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +/** + * The basic interface for all connectors. + * + * @author wprinz + */ +public interface Connector +{ + + /** + * Performs a sign. + * + * @param sig_type + * The signature type/profile. + * @param user_name + * The user name for user logging. + * @param text_to_sign + * The text to be signed. + * @return Returns the signed SignatureObject. + * @throws SignatureException + * F.e. + */ + public SignatureObject doSign(String sig_type, String user_name, + String text_to_sign) throws SignatureException; + + /** + * Performs a verify. + * + * @param signed_text + * The signed text to be verified. + * @param sig_obj + * The Signature object. + * @return Returns the SignatureResponse. + * @throws SignatureException + * F.e. + */ + public SignatureResponse doVerify(String signed_text, SignatureObject sig_obj) throws SignatureException; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorFactory.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorFactory.java new file mode 100644 index 0000000..fa019b9 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorFactory.java @@ -0,0 +1,372 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: ConnectorFactory.java,v 1.4 2006/10/31 08:18:12 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.lang.reflect.Field; + +import org.apache.log4j.Logger; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorFactoryException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.connectors.A1Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorConfigurationKeys; +import at.knowcenter.wag.egov.egiz.sig.connectors.MOAConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.LocRefDetachedMOCCAConnector; + +/** + * This is a factory for creating the appropriate connector according to the + * connector identifier. + * + * @deprecated this code is far too complicated + * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorInformation + * @author wprinz + */ +public abstract class ConnectorFactory +{ + /** + * The name of the field that holds the Connector implementation's unique + * identifier. + * + *

+ * This must be a public static final String on the Connector implementation + * class. + *

+ */ + protected static final String CONNECTOR_INFORMATION_FIELD_NAME = "CONNECTOR_INFORMATION"; + + /** + * The list of available Connector implementations. + * + *

+ * Note that this could also be generated dynamically from a config file, + * preferably enveloped by a Singleton. + *

+ */ + protected static Class[] AVAILABLE_CONNECTORS = { MOAConnector.class, + BKUConnector.class, A1Connector.class }; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(ConnectorFactory.class); + + + + /** + * Retrieves the ConnectorInformation from the connector Class. + * + * @param connector_class + * The connector Class. + * @return Returns the ConnectorInformation. + * @throws IllegalArgumentException + * F.e. + * @throws IllegalAccessException + * F.e. + * @throws SecurityException + * F.e. + * @throws NoSuchFieldException + * F.e. + */ + protected static ConnectorInformation getConnectorInformationFromClass( + Class connector_class) throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException + { + Field type_field = connector_class.getField(CONNECTOR_INFORMATION_FIELD_NAME); + ConnectorInformation connector_information = (ConnectorInformation) type_field.get(null); + return connector_information; + } + + /** + * Gathers the ConnectorInformation objects of all registered connectors. + * + *

+ * This is used by the user interface to provide a list of all available + * connectors. + *

+ * + * @return Returns the ConnectorInformation objects. + * @throws ConnectorFactoryException + * F.e. + */ + public static ConnectorInformation[] getConnectorInformationArray() throws ConnectorFactoryException + { + ConnectorInformation[] coninf = new ConnectorInformation[AVAILABLE_CONNECTORS.length]; + + for (int i = 0; i < coninf.length; i++) + { + try + { + coninf[i] = getConnectorInformationFromClass(AVAILABLE_CONNECTORS[i]); + } + catch (Exception e) + { + throw new ConnectorFactoryException(e); + } + } + + return coninf; + } + + /** + * Retrieves the connector Class belonging to the connector id. + * + * @param connector_identifier + * The connector id. + * @return Returns the corresponding connector class. + * @throws ConnectorFactoryException + * Thrown, if the id is invalid. + */ + protected static Class getConnectorClass(String connector_identifier) throws ConnectorFactoryException + { + ConnectorInformation[] conids = getConnectorInformationArray(); + for (int i = 0; i < conids.length; i++) + { + String connector_id = conids[i].getIdentifier(); + + if (connector_id.equals(connector_identifier)) + { + Class conn_class = AVAILABLE_CONNECTORS[i]; + + return conn_class; + } + } + + throw new ConnectorFactoryException("The connector '" + connector_identifier + "' couldn't be found in the list of available connectors."); + } + + /** + * Creates a new connector given by the connector_identifier. + * + * @param connector_identifier + * The connector identifier of the new connector. + * @return Returns the new connector. + * @throws ConnectorFactoryException + * F.e. + */ + public static Connector createConnector(String connector_identifier) throws ConnectorFactoryException + { + + Class conn_class = getConnectorClass(connector_identifier); + + try + { + Connector connector_obj = (Connector) conn_class.newInstance(); + return connector_obj; + } + catch (Exception e) + { + throw new ConnectorFactoryException(e); + } + } + + /** + * Tells, if the given connector identifier is valid. + * + * @param connector_identifier + * The connector identifier. + * @return Returns true, if the identifier is valid, false otherwise. + * @throws ConnectorFactoryException + * F.e. + */ + public static boolean isValidConnectorIdentifier(String connector_identifier) throws ConnectorFactoryException + { + ConnectorInformation[] conids = getConnectorInformationArray(); + for (int i = 0; i < conids.length; i++) + { + if (conids[i].getIdentifier().equals(connector_identifier)) + { + return true; + } + } + return false; + } + + /** + * Retrieves the availability of the connector from the flags specified in the + * config file. + * + * @param connector_identifier + * The connector. + * @param availability_key + * The key of the availability flag to be retrieved. + * @param default_value + * The default value to be used if the flag is not set in the config + * file. + * @return Returns true, if the flag was set to true, false, if the flag was + * set otherwise, or the default_value if the flag wasn't set at all. + * @throws ConnectorFactoryException + * Thrown, if the connector is invalid. + */ + protected static boolean getAvailabilityUsingDefault(String connector_identifier, + String availability_key, boolean default_value) throws ConnectorFactoryException + { + if (!isValidConnectorIdentifier(connector_identifier)) + { + throw new ConnectorFactoryException("The connector '" + connector_identifier + "' couldn't be found in the list of available connectors."); + } + + SettingsReader settings_ = null; + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new RuntimeException(e); + } + + String value = settings_.getValueFromKey(connector_identifier + "." + availability_key); + if (value == null) + { + return default_value; + } + return value.equals("true"); + } + + /** + * Tells, if the connector is available for being used in the Commandline + * (synchron) environment. + * + *

+ * A connector is available for commandline processing if it requires no + * active user interaction for being executed or if it handles the user + * interaction itself. + *

+ *

+ * A commandline connector is executed synchronously. The client waits until + * the Connector has finished. + *

+ *

+ * Usually a synchron connector can also be used in a web environment. + *

+ *

+ * Examples for commandline connectors are: MOA, BKU. A1 is not suitible for + * commandline because it requires HTTP/HTML interaction, log in, etc. + *

+ * + * @return Returns true, if the Connector is available for Commandline + * processing. + */ + public static boolean isAvailableForCommandline(String connector_identifier) throws ConnectorFactoryException + { + return getAvailabilityUsingDefault(connector_identifier, ConnectorConfigurationKeys.AVAILABLE_FOR_COMMANDLINE, false); + } + + /** + * Tells, if the Connector is available for being used in a Web (asynchron, + * local) environment. + * + *

+ * A connector is available for Web if it can be used in a web environment. + * Often a web connector is also a local connector. + *

+ *

+ * Typical examples are the local BKU and A1. The later requires HTML log in + * and session handling. + *

+ * + * @return Returns true, if the Connector is available for the Web + * application. + */ + public static boolean isAvailableForWeb(String connector_identifier) throws ConnectorFactoryException + { + return getAvailabilityUsingDefault(connector_identifier, ConnectorConfigurationKeys.AVAILABLE_FOR_WEB, false); + } + + /** + * Tells, if the given connector is local. + * + * @param connector_identifier + * The connector. + * @return Returns true, if the given connector is local, false otherwise. + * @throws ConnectorFactoryException + * F.e. + */ + public static boolean isConnectorLocal(String connector_identifier) throws ConnectorFactoryException + { + return connector_identifier.equals(Constants.SIGNATURE_DEVICE_BKU) || connector_identifier.equals(Constants.SIGNATURE_DEVICE_A1) || connector_identifier.equals(Constants.SIGNATURE_DEVICE_MOC); + } + + /** + * Key value in property file + */ + // dferbas: not used anymore with dynamic algorithm support. + // field has to be showed/embedded except for default algorithm suites + // use signature block layout to show/hide + //public static final String MOA_ID_VISIBLE_PROPERTY_KEY = "moa.id.field.visible"; + + // dferbas: not used anymore +// /** +// * Tells, if the given connector needs or produces SIG_IDs. +// * +// *

+// * This method is used when pre formatted signature blocks have to be created +// * that have to know if there will be a SIG_ID field or not. +// *

+// *

+// * Connectors like BKU produce SIG_IDs when signing that are needed when +// * verifying. +// *

+// * +// * @param connector +// * The connector. +// * @return Returns true, if the given connector uses SIG_IDs, false otherwise. +// */ +// public static boolean needsSIG_ID(String connector) +// { +// // all modernn detached signatures have the SIG_ID field. +// if(connector.equals("moa")) +// { +// String is_id_field_visible = null; +// +// try +// { +// is_id_field_visible = SettingsReader.getInstance().getValueFromKey(MOA_ID_VISIBLE_PROPERTY_KEY); +// } catch (SettingsException e) +// { +// logger_.error(e.getMessage(), e); +// } +// +// // if not setted in config, show it +// if(is_id_field_visible == null) +// return true; +// if(is_id_field_visible.equals("true")) +// return true; +// else +// return false; +// } +// +// return true; +// //return !connector.equals("moa"); +// } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorInformation.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorInformation.java new file mode 100644 index 0000000..efd6c53 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/ConnectorInformation.java @@ -0,0 +1,97 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: ConnectorInformation.java,v 1.2 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; + +/** + * Holds the information of one connectior. + * + *

+ * An implementation of the Connector interface must provide a public static + * final ConnectorInformation field named + * ConnectorFactory#CONNECTOR_INFORMATION_FIELD_NAME that provides the + * information about this connector to the system. + *

+ * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory + * + * @author wprinz + */ +public class ConnectorInformation implements Serializable +{ + /** + * SVUID. + */ + private static final long serialVersionUID = 5692836392376853268L; + + /** + * The short identifier of the connector (e.g. "bku"). + */ + protected String connector_identifiert = null; + + /** + * The user suitable description of the connector (e.g. + * "Bürgerkartenumgebung"). + */ + protected String connector_description = null; + + /** + * Constructor that initializes this object. + * + * @param identifier + * The short identifier of the connector (e.g. "bku"). + * @param description + * The user suitable description of the connector (e.g. + * "Bürgerkartenumgebung"). + */ + public ConnectorInformation(String identifier, String description) + { + this.connector_identifiert = identifier; + this.connector_description = description; + } + + /** + * Returns the identifier of this connector. + * + * @return Returns the identifier of this connector. + */ + public String getIdentifier() + { + return this.connector_identifiert; + } + + /** + * Returns the description if this connector. + * + * @return Returns the description if this connector. + */ + public String getDescription() + { + return this.connector_description; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java new file mode 100644 index 0000000..d15f1a9 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/DummyLDAPAPI.java @@ -0,0 +1,100 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: DummyLDAPAPI.java,v 1.2 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.File; +import java.io.FileInputStream; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIException; +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPIssuerNameFilter; + +/** + * This is just a dummy implementation until the real Egiz LDAP API is + * implemented. + * + * @author wprinz + * @author modified by Thomas Knall + * @deprecated Use {@link at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIFactory#createLDAPAPI()} instead. + */ +public class DummyLDAPAPI implements LDAPAPI +{ + String url_ = null; + + /** + * The Logger. + */ + protected static Log logger = LogFactory.getLog(DummyLDAPAPI.class); + + public DummyLDAPAPI(String url) + { + this.url_ = url; + } + + /* (non-Javadoc) + * @see at.knowcenter.wag.egov.egiz.sig.LDAPAPI#getURL(String) + */ + public String getURL(String issuer) + { + return this.url_; + } + + /* (non-Javadoc) + * @see at.knowcenter.wag.egov.egiz.sig.LDAPAPI#loadCertificateFromLDAP(java.lang.String, java.lang.String) + */ +public byte[] loadBase64CertificateFromLDAP(String serial_number, String issuer) + { + //System.out.println("LDAP: serial_number = " + serial_number); + //System.out.println("LDAP: issuer = " + issuer); + + byte[] data = null; + if (serial_number.equals("153868") && issuer.equals("CN=a-sign-TEST-Premium-Sig-01,OU=a-sign-TEST-Premium-Sig-01,O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH,C=AT")) + { + try + { + File test_file = new File(SettingsReader.CERT_PATH + File.separator + "ldap_test_cert.der"); + data = new byte[(int) test_file.length()]; + FileInputStream fis = new FileInputStream(test_file); + fis.read(data); + fis.close(); + } + catch (Exception e) + { + logger.error(e.getMessage(), e); + data = null; + } + } + + return data; + } + + public void setIssuerNameFilter(LDAPIssuerNameFilter filter) throws LDAPAPIException { + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LDAPAPI.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LDAPAPI.java new file mode 100644 index 0000000..4269e28 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LDAPAPI.java @@ -0,0 +1,50 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig; + +import at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIException; +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPIssuerNameFilter; + +/** + * @author Thomas Knall + */ +public interface LDAPAPI { + + public static final String SYS_PROP_IMPLEMENTATION = "pdfas.ldapapi.impl"; + + /** + * Retrieves an certificate from the ldap server identified by serial number and issuer name. + * @param serialNumber The serial number. + * @param issuer The issuer name. + * @return BASE64 encoded certificate + */ + public byte[] loadBase64CertificateFromLDAP(String serialNumber, String issuer); + + /** + * Sets the filter that has to be applied before trying to match the issuer name. + * @param filter The filter. + */ + public void setIssuerNameFilter(LDAPIssuerNameFilter filter) throws LDAPAPIException; + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java new file mode 100644 index 0000000..1c254e2 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/LocalConnector.java @@ -0,0 +1,127 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: LocalConnector.java,v 1.2 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.util.Properties; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +/** + * A local connector is a refinement of a "normal" Connector that allows to + * explicitely do the request on a local client. + * + *

+ * Basically the sign and verify procedures of this connector are split into + * three groups: + *

+ *
    + *
  1. Prepare the request to the local service.
  2. + *
  3. Carry out the request on the local client.
  4. + *
  5. Analyze the response from the local client.
  6. + *
+ *

+ * Usually the preparation and the analyzation are carried out on the server, + * whereas the connection to the local service is made from the local client. + *

+ * + * @deprecated use the new connectory instead + * + * @author wprinz + */ +public interface LocalConnector extends Connector +{ + /** + * Prepares the sign request string. + * + * @param user_name + * The user name. + * @param sign_text + * The text to be signed. + * @param signature_type + * The type of the signature. + * @return Returns the request string to be sent to the local service. + * @throws SignatureException + * F.e. + */ + public String prepareSignRequest(String user_name, String sign_text, + String signature_type) throws SignatureException; + + /** + * Prepares the verify request string. + * + * @param signed_text + * The signed text to be verified. + * @param signature_object + * The SignatureObject. + * @return Returns the request string. + * @throws SignatureException + * F.e. + */ + public String prepareVerifyRequest(String signed_text, + SignatureObject signature_object) throws SignatureException; + + /** + * Analyzes the sign response string. + * + * @param signature_type + * The type of the signature. + * @return Returns the SignatureObject of the sign request. + * @throws SignatureException + * F.e. + */ + // TODO hotfix - already deprecated + public SignatureObject analyzeSignResponse(Properties response_properties, + String signature_type) throws SignatureException; + + /** + * Analyzes the verify response string. + * + * @return Returns the SignatureResponse of the verify request. + * @throws SignatureException + * F.e. + */ + // TODO hotfix - already deprecated + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws SignatureException; + + /** + * Returns the sign URL of the local service. + * + * @param profile + * The signature type the URL should be retrieved from. + * @return Returns the sign URL of the local service. + */ + public String getSignURL(String profile); + + /** + * Returns the verify URL of the local service. + * + * @param profile + * The signature type the URL should be retrieved from. + * @return Returns the verify URL of the local service. + */ + public String getVerifyURL(String profile); + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureBlock.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureBlock.java new file mode 100644 index 0000000..c9e3b98 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureBlock.java @@ -0,0 +1,316 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: SignatureBlock.java,v 1.4 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; + +/** + * This method is to analyse a signature block string. It searches for + * configured signature types while compairing defined key words with the text. + * + * @deprecated Use AbsoluteTextSignature instead. + * + * @author wlackner + */ +public class SignatureBlock +{ + + /** + * Start index of the signature block text. + */ + private int startIndex_ = -1; + + /** + * End index of the signature block text. + */ + private int endIndex_ = -1; + + /** + * The type of the signature block. + */ + private String type_ = null; + + /** + * The signature type definition object. + */ + private SignatureTypeDefinition sigTypeDef_ = null; + + /** + * The signature block string. + */ + private String signatureString_ = null; + + /** + * The signature object build by the signature string using the signture + * definition. + */ + private SignatureObject signatureObject_ = null; + + /** + * A list of configured signature types. + */ + List signatureTypes_ = null; + + /** + * A list of found keys in the signature block string. + */ + Map foundKeys_ = new HashMap(); + + int maxSize_ = -1; + + /** + * The default constructor to analyse a signature block string. It uses a + * predefined signature type list to assign the text block to signature type. + * The analyse method have to be call separately --> + * separateBlockFromRawText() + * + * @param signatureTypes + */ + public SignatureBlock(List signatureTypes) + { + signatureTypes_ = signatureTypes; + } + + /** + * This method checks if all required keys are found in the signature block + * string. + * + * @param foundKeys + * the keys that are found in the singnature block string + * @return true if all required keys are found, false otherwise + */ + private boolean checkRequiredFields(Map foundKeys) + { + String[] req_keys = SignatureTypes.REQUIRED_SIG_KEYS; + for (int req_idx = 0; req_idx < req_keys.length; req_idx++) + { + String key = req_keys[req_idx]; + // SIG_ID could be optional --> only set in BKU signed documents + if (key.equals(SignatureTypes.SIG_ID)) + { + continue; + } + // logger.debug("check:" + key + "=" + foundKeys.get(key)); + if (foundKeys.get(key) == null) + { + return false; + } + } + return true; + } + + /** + * This method is the base method to analyse a raw text separating a signature + * block string from the raw text. It searches for corresponding signature + * types from back to front in the raw text. Therefore a revert list of + * multiple signations can be extracted calling this method more than one + * times. The method extracts the start and end postition of a found signature + * block and extracts all keys used in that block. If all required fields are + * found a successful separation is done and can be access calling the method + * getStartIndex, getEndIndex, getType, getSignatureObject. + * + * @param rawText + * the raw text to separate a signature block from + * @return true if a separation has done successful false if no signature + * block can be found + */ + public boolean separateBlockFromRawText(String rawText, boolean old_style) + { + endIndex_ = rawText.length(); + boolean found_type = false; + for (int sig_type_idx = 0; sig_type_idx < signatureTypes_.size(); sig_type_idx++) + { + int last_index = endIndex_; + SignatureTypeDefinition sig_type_def = (SignatureTypeDefinition) signatureTypes_.get(sig_type_idx); + //logger.debug("Try sep type:" + sig_type_def.getType()); + + Vector keys = sig_type_def.getRevertSortedKeys(); + Vector captions = sig_type_def.getRevertSortedCaptions(); + Map found_keys = new HashMap(); + for (int key_idx = 0; key_idx < keys.size(); key_idx++) + { + String key = (String) keys.get(key_idx); + if (old_style && key.equals(SignatureTypes.SIG_KZ)) + { + // If separating the old style way - skip The "Kennzeichnung" + // key, because it wasn't present in old profiles. + continue; + } + String caption = (String) captions.get(key_idx); + int found_idx = rawText.lastIndexOf(caption); + //logger.debug("Try find:" + sig_type_def.getType() + "." + key + "." + caption + " at=" + found_idx); + if (found_idx >= 0 && found_idx < last_index) + { + if (key.equals(SignatureTypes.SIG_ID)) + { + //logger.debug("store SIG_ID, but don't decrease last index:" + sig_type_def.getType() + "." + key + "." + caption + " at=" + found_idx); + found_keys.put(key, new Integer(found_idx)); + // don't decrease last index as SIG_ID is not necessarily persistent + } + else + { + //logger.debug("store:" + sig_type_def.getType() + "." + key + "." + caption + " at=" + found_idx); + found_keys.put(key, new Integer(found_idx)); + last_index = found_idx; + } + } + } + if (checkRequiredFields(found_keys) && found_keys.size() > maxSize_) + { + foundKeys_ = found_keys; + sigTypeDef_ = sig_type_def; + type_ = sig_type_def.getType(); + startIndex_ = last_index; + signatureString_ = rawText.substring(startIndex_, endIndex_); + maxSize_ = found_keys.size(); + found_type = true; + } + } + return found_type; + } + + /** + * @return Returns the endIndex. + */ + public int getEndIndex() + { + return endIndex_; + } + + /** + * @return Returns the signatureObject of the separated signature block. + * @throws SignatureException + */ + public SignatureObject getSignatureObject() throws SignatureException + { + if (signatureObject_ == null && foundKeys_ != null) + { + signatureObject_ = new SignatureObject(); + try + { + signatureObject_.setSigType(type_); + signatureObject_.initByType(); + } + catch (SignatureTypesException e) + { + SignatureException se = new SignatureException(101, "Can ot set signation type:" + type_, e); + throw se; + } + String sig_text = signatureString_; + Vector revert_keys = sigTypeDef_.getRevertSortedKeys(); + Vector revert_captions = sigTypeDef_.getRevertSortedCaptions(); + for (int key_idx = 0; key_idx < revert_keys.size(); key_idx++) + { + String key = (String) revert_keys.get(key_idx); + String caption = (String) revert_captions.get(key_idx); + int start_idx = sig_text.lastIndexOf(caption); + if (start_idx >= 0) + { + int sep_idx = start_idx + caption.length(); + // logger.debug(sig_text); + // logger.debug("caption:" + caption + " start_idx:" + start_idx + // + " length:" + + // sig_text.length()); + String value = sig_text.substring(sep_idx); + // logger.debug("key:" + key + " value:" + value); + signatureObject_.setSigValueCaption(key, value, caption); + sig_text = sig_text.substring(0, start_idx); + } + } + } + return signatureObject_; + } + + /** + * @return Returns the startIndex. + */ + public int getStartIndex() + { + return startIndex_; + } + + /** + * @return Returns the type. + */ + public String getType() + { + return type_; + } + +// /** +// * @param endIndex +// * The endIndex to set. +// */ +// private void setEndIndex(int endIndex) +// { +// endIndex_ = endIndex; +// } +// +// /** +// * @param startIndex +// * The startIndex to set. +// */ +// private void setStartIndex(int startIndex) +// { +// startIndex_ = startIndex; +// } +// +// /** +// * @param type +// * The type to set. +// */ +// private void setType(String type) +// { +// type_ = type; +// } + + /** + * The standard toString method. Used for interal tests only. + */ + public String toString() + { + String strg = ""; + strg += "Type:" + type_ + "\n"; + strg += "Start index:" + startIndex_ + "\n"; + strg += "End index:" + endIndex_ + "\n"; + strg += signatureString_ + "\n"; + strg += sigTypeDef_ + "\n"; + try + { + strg += getSignatureObject().toString(); + } + catch (SignatureException e) + { + } + return strg; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureData.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureData.java new file mode 100644 index 0000000..18f4fe8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureData.java @@ -0,0 +1,82 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig; + +import at.gv.egiz.pdfas.framework.input.DataSource; + +/** + * This encapsuilates the content data to be signed or verified. + * + *

+ * For a text signature this would be the text to be signed or verified. For a + * binary signature this would be the PDF to be signed or verified. + *

+ * + *

+ * This is an abstract reprsenation of data: the binary data, its mime type and + * (if appropriate according to the mime type) the charset the data is encoded. + *

+ * + * @author wprinz + */ +public interface SignatureData +{ + /** + * Returns the DataSource that provides the data for this SignatureData. + * + * @return Returns the DataSource. + */ + public DataSource getDataSource(); + + /** + * Returns the mime type of the data. + * + *

+ * E.g. "text/plain" for text data or "application/pdf" for a PDF. + *

+ * + * @return Returns the mime type of the data. + */ + public String getMimeType(); + + /** + * Returns the character encoding (charset) of the data if appropriate. + * + *

+ * This is only appropriate if the mime type suggests that the data contained + * in here is textually encoded. Usually text/plain or similar data types will + * have a character encoding present. + *

+ *

+ * If no character encoding is present, null is returned here. + *

+ *

+ * E.g. "UTF-8" is the most common encoding for textual data. + *

+ * + * @return Returns the character encoding (charset) of the data if + * appropriate. + */ + public String getCharacterEncoding(); +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureDataImpl.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureDataImpl.java new file mode 100644 index 0000000..cbd2408 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureDataImpl.java @@ -0,0 +1,130 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; + +import at.gv.egiz.pdfas.framework.input.DataSource; + +/** + * Generic implementation of the SignatureData interface for being used by + * signators and verificators. + * + * @author wprinz + */ +public class SignatureDataImpl implements SignatureData, Serializable +{ + /** + * SVUID. + */ + private static final long serialVersionUID = -8652845539968684408L; + + /** + * The signature data. + */ + protected DataSource data = null; + + /** + * The mime type of the data. + */ + protected String mimeType = null; + + /** + * The character encoding of the data if appropriate, or null if not. + */ + protected String characterEncoding = null; + + /** + * Constructor that fills the SignatureData. + * + *

+ * The charactor encoding is set to null, so this constructor is primarily for + * signature data that has no character encoding (e.g. binary data). + *

+ * + * @param data + * The signature data. + * @param mime_type + * The mime type of the data. + */ + public SignatureDataImpl(DataSource data, String mime_type) + { + this.data = data; + this.mimeType = mime_type; + this.characterEncoding = null; + } + +// /** +// * Constructor that fills the SignatureData. +// * +// *

+// * Use this constructor for textual data as it allows to provide the character +// * encoding. +// *

+// * +// * @param data +// * The signature data. +// * @param mime_type +// * The mime type of the data. +// * @param character_encoding +// * The character encoding of the data if appropriate, or null if not. +// */ +// public SignatureDataImpl(byte[] data, String mime_type, String character_encoding) +// { +// this.data = data; +// this.mimeType = mime_type; +// this.characterEncoding = character_encoding; +// } + public SignatureDataImpl(DataSource data, String mime_type, String character_encoding) + { + this.data = data; + this.mimeType = mime_type; + this.characterEncoding = character_encoding; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.SignatureData#getDataSource() + */ + public DataSource getDataSource() + { + return this.data; + } + + + /** + * @see at.knowcenter.wag.egov.egiz.sig.SignatureData#getMimeType() + */ + public String getMimeType() + { + return this.mimeType; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.SignatureData#getCharacterEncoding() + */ + public String getCharacterEncoding() + { + return this.characterEncoding; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureEntry.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureEntry.java new file mode 100644 index 0000000..078f80f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureEntry.java @@ -0,0 +1,163 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: SignatureEntry.java,v 1.3 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; + +/** + * This class is to store a signature entry. The signature entry is 3-tupel. A key that is defined + * or declarated in the settings file, an optional caption or a value.
+ * An additional helper value is a marker for the start index of the key, if the key is found in an + * analysing process extracting captions and values from a raw signature text. + * + * @author wlackner + * @see at.knowcenter.wag.egov.egiz.sig.SignatureObject + */ +public class SignatureEntry implements Serializable { + + /** + * SVUID. + */ + private static final long serialVersionUID = 4640380069301731879L; + + /** + * The signature key. + */ + private String key_ = null; + /** + * The signature caption for the key found or set in the signature text. + */ + private String caption_ = null; + /** + * The signature value for the key found or set in the signature text. + */ + private String value_ = null; + /** + * The starting index position of the key if it is found in the signature text. + */ + private int startIndex_ = -1; + + public boolean isPlaceholder = false; + + /** + * The empty constructor. + */ + public SignatureEntry() { + } + + /** + * A new SignatureEntry init with the key. + * + * @param key + */ + public SignatureEntry(String key) { + key_ = key; + } + + /** + * Returns the caption off the current key. + * + * @return Returns the caption. + */ + public String getCaption() { + return caption_; + } + + /** + * Set the caption of the current key. + * + * @param caption The caption to set. + */ + public void setCaption(String caption) { + caption_ = caption; + } + + /** + * Return the current key. + * + * @return Returns the key. + */ + public String getKey() { + return key_; + } + + /** + * Set the current key. + * + * @param key The key to set. + */ + public void setKey(String key) { + key_ = key; + } + + /** + * Return the start position of the key that caption is found in the signature text. + * + * @return Returns the startIndex. + */ + public int getStartIndex() { + return startIndex_; + } + + /** + * Set the start position of the current key. + * + * @param startIndex The startIndex to set. + */ + public void setStartIndex(int startIndex) { + startIndex_ = startIndex; + } + + /** + * Return the value of the current key. + * + * @return Returns the value. + */ + public String getValue() { + return value_; + } + + /** + * Set the value of the current key. + * + * @param value The value to set. + */ + public void setValue(String value) { + value_ = value; + } + + /** + * The toString method, used for tests or debugging. + */ + public String toString() { + String the_string = ""; + the_string += "\n Key:" + key_; + the_string += "\nCaption:" + caption_; + the_string += "\n Value:" + value_; +// the_string += "\nStart I:" + startIndex_; + return the_string; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureFieldDefinition.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureFieldDefinition.java new file mode 100644 index 0000000..3c16599 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureFieldDefinition.java @@ -0,0 +1,88 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: SignatureFieldDefinition.java,v 1.1 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; + +/** + * This class contains the information about one field in the signature block. + * + *

+ * E.g. Field "Issuer" could have the caption "Aussteller", the value null and + * the placeholder length of 500. + *

+ * + * @author wprinz + */ +public class SignatureFieldDefinition implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = -46020173047777315L; + + /** + * The key identifier of this field. + */ + public String field_name = null; + + /** + * The static caption of the field. + */ + public String caption = null; + + /** + * The static value of the field. + * + *

+ * Null means that this field has no static value and must be filled out. + *

+ */ + public String value = null; + + /** + * If the field is not static and has to be filled out, this gives the + * length of the placeholder that is reserved for filling out. + * + *

+ * This has to be large enough so that it can hold the whole value to be + * filled out. + *

+ */ + public int placeholder_length = -1; + + /** + * Stores the three byte abbreviation code of this field's field name. + */ + //public byte [] brev = null; + + public String toString() + { + return this.field_name + ": caption=" + this.caption + ", value=" + this.value + ", phlen=" + this.placeholder_length; + } + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java new file mode 100644 index 0000000..8855b86 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java @@ -0,0 +1,2108 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: SignatureObject.java,v 1.7 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import iaik.asn1.structures.Name; +import iaik.asn1.structures.RDN; +import iaik.utils.RFC2253NameParser; +import iaik.utils.RFC2253NameParserException; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.OverridePropertyHolder; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException; +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIException; +import at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIFactory; +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPIssuerNameFilter; +import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper; +import at.knowcenter.wag.egov.egiz.table.Entry; +import at.knowcenter.wag.egov.egiz.table.Style; +import at.knowcenter.wag.egov.egiz.table.Table; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; +import at.knowcenter.wag.egov.egiz.tools.Normalizer; + +/** + * This class represents the abstract signature object. It contains all methods + * reading the definitions from the settings file, analyse them and build the + * abstract signature table.
+ * All values that build or used by the signation creation process, call the + * external services, can read or set separately. All other values are defined + * in the settings file. + * + * @author wlackner + * @author modified by Thomas Knall + */ +public class SignatureObject implements Serializable +{ + +// 03.11.2010 changed by exthex - added default for defaultValueStyle_.hAlign since we had to remove the hardcoded default in Style +// 04.11.2010 changed by exthex - setSigValue no longer removes multiple newlines from value + + /** + * SVUID. + */ + private static final long serialVersionUID = -3535189232362254713L; + + /** + * The system file separator char + */ + private static final String FILE_SEP = System.getProperty("file.separator"); + + /** + * The certificate extension + */ + private static final String CERT_FILE_EXTENSION = ".der"; + + /** + * certificate import dir + */ + private static final String CERT_ADD_DIR = "tobeadded"; + + /** + * The default style definition for images. + */ + private Style defaultImageStyle_ = new Style(); + + /** + * The default style definition for captions. + */ + private Style defaultCaptionStyle_ = new Style(); + + /** + * The default style definition for values. + */ + private Style defaultValueStyle_ = new Style(); + + /** + * Standard key get/set the signature meta informations + */ + public static final String SIG_META = "SIG_META"; + + /** + * Standard key get/set the certification value + */ + public static final String SIG_CER = "SIG_CER"; + + /** + * Standard key get/set the certification digest value + */ + public static final String SIG_CER_DIG = "SIG_CER_DIG"; + + private X509Cert x509Cert_ = null; + + private String timeStamp = null; + + // public static final String SIG_RES = "SIG_RES"; + // dummy value for debugging only + private String sigResponse_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(SignatureObject.class); + + /** + * The normalizer reference + */ + private Normalizer normalizer_ = null; + + /** + * The settings reader reference + */ + private SettingsReader settings_ = null; + + // /** + // * The reference to the settings property tree + // */ + // private PropertyTree pTree_ = null; + /** + * The current signature type used reading and analysing the property tree + */ + private String sigType_ = null; + + /** + * Reference from signature key to there corresponding value + */ + private Hashtable sigEntries_ = new Hashtable(8); + + /** + * The abstract table representation + */ + private Table sigTable_ = null; + + // private HashMap sigIndexMap_ = new HashMap(); + + /** + * Path value storing and fetching the certificates + */ + private String certPath_ = null; + + /** + * the signature definition object + */ + private SignatureTypeDefinition signatureDefinition_ = null; + + /** + * The raw xml response from the connector that was used to set the values in + * this SignatureObject. + * + *

+ * This is set by the Connector so that signing Applications can use the + * returned XML values. + *

+ */ + protected String raw_signature_response = null; + + /** + * Filters the issuer name in order to find matches. + * @author tknall + * @see #normalizeIssuer + */ + private LDAPIssuerNameFilter issuerNameFilter = new LDAPIssuerNameFilter() { + public Name applyFilter(Name name) { + RFC2253NameParser parser = new RFC2253NameParser(normalizeIssuer(name.getName())); + try { + name = parser.parse(); + } catch (RFC2253NameParserException e) { + logger_.error(e.getMessage(), e); + } + return name; + } + }; + + /** + * The empty constructor. It initilize the normlizer, load the settings and + * set the default styles. + * + * @throws SignatureException + * ErrorCode:101, 400 + */ + public SignatureObject() throws SignatureException + { + initNormalizer(); + loadSettings(); + setDefaultStyles(); + } + + /** + * This method initialize the normalizer + * + * @throws SignatureException + * ErrorCode:400 + */ + private void initNormalizer() throws SignatureException + { + try + { + normalizer_ = new Normalizer(); + } + catch (NormalizeException e) + { + SignatureException se = new SignatureException(400, "Normalizer can not be initialized", e); + throw se; + } + } + + /** + * This method load the signature definitions + * + * @throws SignatureException + * ErrorCode:101 + */ + private void loadSettings() throws SignatureException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load pdf signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new SignatureException(101, log_message, e); + } + } + // pTree_ = settings_.getPTree(); + + certPath_ = SettingsReader.CERT_PATH; + } + + /** + * This method set the default styles for images, captions and values. + */ + private void setDefaultStyles() + { + defaultImageStyle_.setPadding(3); + defaultImageStyle_.setHAlign(Style.CENTER); + defaultImageStyle_.setVAlign(Style.MIDDLE); + + defaultCaptionStyle_.setHAlign(Style.CENTER); + defaultCaptionStyle_.setVAlign(Style.MIDDLE); + + defaultValueStyle_.setHAlign(Style.LEFT); + defaultValueStyle_.setVAlign(Style.MIDDLE); + } + + /** + * Dummy getter Method for debugging only + * + * @return response string + */ + public String getSigResponse() + { + return sigResponse_; + } + + /** + * Dummy setter Method for debugging only + * + * @param sigRespone + * store the response string + */ + public void setSigResponse(String sigRespone) + { + sigResponse_ = sigRespone; + } + + /** + * This method set the signature type. + * + * @param sigType + * the signature type to be set + * @throws SignatureTypesException + */ + public void setSigType(String sigType) throws SignatureTypesException + { + SignatureTypes sig_types = SignatureTypes.getInstance(); + signatureDefinition_ = sig_types.getSignatureTypeDefinition(sigType_); + sigType_ = sigType; + } + + /** + * Returns the default signation type + * + * @return the key for the default signature definition, if the key is not + * found it returns null + */ + private String getDefaultSigType() + { + return settings_.getSetting(SignatureTypes.DEFAULT_TYPE, null); + } + + /** + * This method checks if a given signature key is realy a defined signature + * key. + * + * @param sigKey + * the key to check + * @return true if the key is correct, false if the given key is not defined + */ + public boolean isSigKey(String sigKey) + { + return signatureDefinition_.contains(sigKey); + } + + /** + * This method adds an sig value to the entry cache. If a key is not in + * the cache a new signature entry is created. Therefore the method return + * true.
+ * The value that has to be set would be normalized!
+ * If the key equals to SIG_VALUE all whitespaces are + * removed!
+ * + * @param key + * the key to be set + * @param value + * the value to be set + * @return true if a new signature value is created, + * false otherwise + */ + public boolean setSigValue(String key, String value) { + return setSigValue(key, value, false); + } + + public boolean setSigValue(String key, String value, boolean placeholder) + { + SignatureEntry sig_entry = null; + boolean is_new = false; + if (sigEntries_.containsKey(key)) + { + sig_entry = (SignatureEntry) sigEntries_.get(key); + } + else + { + sig_entry = new SignatureEntry(key); + sigEntries_.put(key, sig_entry); + is_new = true; + } + value = normalizer_.normalize(value, true); + if (SignatureTypes.SIG_VALUE.equals(key) || SignatureTypes.SIG_ID.equals(key) || SignatureTypes.SIG_NUMBER.equals(key)) + { + value = removeAllWhiteSpaces(value); + } + sig_entry.setValue(value); + sig_entry.isPlaceholder = placeholder; + return is_new; + } + + public boolean setValueBruteForce(String key, String value) + { + SignatureEntry sig_entry = null; + boolean is_new = false; + if (sigEntries_.containsKey(key)) + { + sig_entry = (SignatureEntry) sigEntries_.get(key); + } + else + { + sig_entry = new SignatureEntry(key); + sigEntries_.put(key, sig_entry); + is_new = true; + } + sig_entry.setValue(value); + return is_new; + } + + /** + * Set the value and the caption to given key. + * + * @param key + * the key of the signature object + * @param value + * the value of the given key + * @param caption + * the caption of the given key + */ + public void setSigValueCaption(String key, String value, String caption) + { + setSigValue(key, value); + SignatureEntry sig_entry = (SignatureEntry) sigEntries_.get(key); + sig_entry.setCaption(caption); + } + + /** + * This method returns a value for a given signature key. If the key equals to + * SIG_NORM and the value is null the version + * string of the current normalizer is returned! + * + * @param key + * the key to get the value for + * @return a value for the given key + */ + public String getSigValue(String key) + { + + String value = null; + SignatureEntry sigEntry = null; + if (sigEntries_.containsKey(key)) + { + sigEntry = (SignatureEntry) sigEntries_.get(key); + value = sigEntry.getValue(); + } + if (value == null && SignatureTypes.SIG_NORM.equals(key)) + { + value = normalizer_.getVersion(); + } + + String overrideVal = OverridePropertyHolder.getProperty(key); + if (value != null && sigEntry != null && !sigEntry.isPlaceholder && overrideVal != null) { // TODO this!! SignatureEntry.isPlaceholder + value = overrideVal; + if (logger_.isDebugEnabled()) { + logger_.debug("Using override property for key '" + key + "' = " + value); + } + } + + return value; + } + + /** + * Sets the "Kennzeichnung". + * + * @param kz + * The "Kennzeichnung" to be set. + */ + public void setKZ(PdfASID kz) + { + setSigValue(SignatureTypes.SIG_KZ, kz.toString()); + } + + /** + * Returns the "Kennzeichnung" of this signature. + * + * @return Returns the "Kennzeichnung" of this signature. Returns null if + * there is no "Kennzeichnung" or it is not recognized by this + * application. + */ + public PdfASID getKZ() throws InvalidIDException + { + String kz_string = getSigValue(SignatureTypes.SIG_KZ); + if (kz_string == null) + { + return null; + } + PdfASID kz = null; + try + { + kz = new PdfASID(kz_string); + } + catch (InvalidIDException e) + { + logger_.error(e.getMessage(), e); + } + return kz; + } + + /** + * This method returns a caption for a given signature key. If the key exists + * and the coresponding value is null the key itself is + * returned as caption! If the key does not exist the method returns + * null. + * + * @param key + * the key to get the caption for + * @return a caption for the given key + */ + private String getSigCaption(String key) + { + + String caption = null; + if (sigEntries_.containsKey(key)) + { + caption = ((SignatureEntry) sigEntries_.get(key)).getCaption(); + if (caption == null) + { + caption = key; + } + } + return caption; + } + + /** + * @return Returns the SignationType. + */ + public String getSignationType() + { + if (sigType_ == null) + { + sigType_ = getDefaultSigType(); + } + return sigType_; + } + + /** + * @return Returns the SignationDate. + */ + public String getSignationDate() + { + return getSigValue(SignatureTypes.SIG_DATE); + } + + /** + * @param sigDate + * The SignationDate to set. + */ + public void setSignationDate(String sigDate) + { + setSigValue(SignatureTypes.SIG_DATE, sigDate); + } + + /** + * @return Returns the SignationName. + */ + public String getSignationName() + { + return getSigValue(SignatureTypes.SIG_NAME); + } + + /** + * @param sigName + * The SignationName to set. + */ + public void setSignationName(String sigName) + { + setSigValue(SignatureTypes.SIG_NAME, sigName); + } + + /** + * @return Returns the SignationNormVersion. + */ + public String getSignationNormVersion() + { + return getSigValue(SignatureTypes.SIG_NORM); + } + + /** + * @param sigNormVersion + * The SignationNormVersion to set. + */ + public void setSignationNormVersion(String sigNormVersion) + { + setSigValue(SignatureTypes.SIG_NORM, sigNormVersion); + } + + /** + * This method removes whitespaces around RDNs. Whitespaces may be assumed by the algorithm that + * re-merges multiple lines from a binary signature when line breaks occur after commas. Without + * correction this will result in broken signatures.
+ * e.g this + * invalid IssuerName (note the space before the second RND CN): + * serialNumber=863532247989, CN=BMUKK - Amtssignatur Schulen,OU=Abt. IT/2,O=Bundesministerium für Unterricht, Kunst und Kultur,C=AT + * will be normalized to: + * serialNumber=863532247989,CN=BMUKK - Amtssignatur Schulen,OU=Abt. IT/2,O=Bundesministerium für Unterricht, Kunst und Kultur,C=AT + * @param The invalid RFC2253 name as string. + * @return The normalized RFC2253 name without spaces prior to RDNs. + */ + public static String prepareRFC2253Name(String name) { + if (name == null) { + return null; + } + StringTokenizer tokenizer = new StringTokenizer(name, ",", false); + StringBuffer result = new StringBuffer(); + // iterate over all alleged RND=value-pairs + while (tokenizer.hasMoreTokens()) { + String rdnExpression = tokenizer.nextToken(); + try { + // try to parse RDN=value + new RFC2253NameParser(rdnExpression.trim()).parse(); + // rdnExpression is a RDN=value pair -> remove whitespaces before and after RDN=value + rdnExpression = rdnExpression.trim(); + } catch (RFC2253NameParserException e) { + // this is not a RDN=value pair + // e.g. " Kunst und Kultur" from the javadoc example + // do not trim, otherwise resulting RFC2253Name will be invalid + } + // re-insert delimiter + if (result.length() > 0) { + result.append(","); + } + // add token (either trimmed RND=value pair, or not trimmed text token) + result.append(rdnExpression); + } + String cleanedName = result.toString(); + if (logger_.isDebugEnabled()) { + logger_.debug("Cleaning RFC2253 name: \"" + name + "\" -> \"" + cleanedName + "\"."); + } + return cleanedName; + } + + /** + * This method depicts a workaround for a bug with RFC2253 names with RDNs that have not been + * resolved from ObjectID at signing time (this results from a BKU that could not resolve + * the respective OID).
+ * e.g. 2.5.4.5=#1306323030383034, CN=ForeignerCA,C=BE
+ * The example above shows a RDN "2.5.4.5" which should have been resolved to "serialNumber" at + * signing time. We also recognize that the name shows spaces prior to RDNs and that the space + * which between "Foreigner" and "CA" is missing due to text extraction/reconstruction. + * The naive approach would be to take the complete RFC2253 name from the certificate, since that + * name has also been used for signature. But this does not work in some cases because while + * the bku was not able to resolve 2.5.4.5 on signing time, the entity invoking pdfas for + * verification might be, so that taking the name from certificate on verification time, may not + * result in the name we had at signing time.
+ * e.g. at signing time: 2.5.4.5=#1306323030383034,CN=Foreigner CA,C=BE
+ * after text extraction: 2.5.4.5=#1306323030383034, CN=ForeignerCA,C=BE
+ * from certificate: serialNumber=863532247989,CN=Foreigner CA,C=BE
+ * This method provides a workaround for that problem, by merging information from text extraction + * with information from the certificate. The method takes all RDNs from the extracted text and + * merges them with the values from the certificate (considering the case where the textual + * version shows BER encoded values (e.g. #1306323030383034). + * @param nameFromText The extracted RFC2253 name from the text (e.g. 2.5.4.5=#1306323030383034, CN=ForeignerCA,C=BE). + * @param nameFromCertificate The RFC2253 name from the certificate (e.g. serialNumber=863532247989,CN=Foreigner CA,C=BE) + * @return The RFC2253 name that was used for signature (e.g. 2.5.4.5=#1306323030383034,CN=Foreigner CA,C=BE). + */ + public static String prepareRFC2253Name(String nameFromText, String nameFromCertificate) { + + // do not invoke the workaround for performance reasons when both the extracted name and the + // name from certificate are equal + if (StringUtils.equals(nameFromText, nameFromCertificate)) { + return nameFromText; + } + + logger_.debug("Checking RFC2253 name."); + + // if we do not have a name from certificate just return the name from text + if (nameFromCertificate == null) { + logger_.debug("No certificate RFC2253 name provided. Applying less sophisticated workaround (does not cover all cases) without certificate usage."); + return prepareRFC2253Name(nameFromText); + } + + // no name from text extraction available, just return name from certificate + if (nameFromText == null) { + logger_.debug("No extracted/reconstructed name available. Just returning the name from certificate: \"" + nameFromCertificate + "\"."); + return nameFromCertificate; + } + + // helper class + final class RDNValuePair { + + private String rdn; + private String value; + + public RDNValuePair(String rdn, String value) { + this.rdn = rdn; + this.value = value; + } + + public String getRdn() { + return this.rdn; + } + + public String getValue() { + return this.value; + } + + public String toString() { + return rdn + "=" + value; + } + } + + // retrieve RDNs from text based name + List rdnList = new ArrayList(); + StringTokenizer tokenizer = new StringTokenizer(nameFromText, ",", false); + while (tokenizer.hasMoreTokens()) { + String rdnExpression = tokenizer.nextToken().trim(); + try { + new RFC2253NameParser(rdnExpression).parse(); + // token is RDN=value pair + // split RDN from value + String[] split = rdnExpression.split("=", 2); + rdnList.add(new RDNValuePair(split[0].trim(), split[1].trim())); + } catch (RFC2253NameParserException e) { + // no RDN in token + } + } + + // get values from certificate name + Name nCert; + try { + nCert = new RFC2253NameParser(nameFromCertificate).parse(); + } catch (RFC2253NameParserException e) { + // should never happen + logger_.warn("Unable to parse RFC2253 name \"" + nameFromCertificate + "\". Applying less sophisticated workaround (does not cover all cases) without certificate usage."); + return prepareRFC2253Name(nameFromText); + } + RDN[] values = nCert.getRDNs(); + + // check if results are mergeable + if (values.length != rdnList.size()) { + // unable to merge names; returning nameFromCertificate (since this should be normal + // behavior) + logger_.warn("Number of parsed text based RDNs from \"" + nameFromText + "\" does not fit the number of RDN values from certificate name \"" + nameFromCertificate + "\". Returning name from certificate."); + return nameFromCertificate; + } + + // merge textual based RDNs with values from certificate + StringBuffer result = new StringBuffer(); + for (int i = 0; i < values.length; i++) { + if (i > 0) { + result.append(","); + } + // take rdn from textual representation + RDNValuePair rdnVP = (RDNValuePair) rdnList.get(i); + // Note: Do not take RDN from extraction but from certificate + // (Bug-Fix for EMAIL/EMAILADDRESS problem in ZID documents) + + // take value from certificate but make sure that we do not have a + // BER encoding + if (rdnVP.getValue().startsWith("#")) { + + // take rdn from textual representation + result.append(rdnVP.getRdn()).append("="); + // BER encoding -> take value from text representation + result.append(rdnVP.getValue()); + } else { + // no BER encoding -> take value from certificate + // also take RDN from certificate if possible + String certValue = values[values.length - 1 - i].getAVA() + .getValueAsString(); + String rdn = resolveRDN(nameFromCertificate, certValue, rdnVP.getRdn()); + result.append(rdn + "=").append(certValue); + } + + } + String merged = result.toString(); + if (logger_.isDebugEnabled()) { + if (merged.equals(nameFromText)) { + logger_.debug("Taking name from text: \"" + nameFromText + "\""); + } else if (merged.equals(nameFromCertificate)) { + logger_.debug("Taking name from certificate: \"" + nameFromText + "\""); + } else { + logger_.debug("Name has been fixed."); + logger_.debug("Name from text : \"" + nameFromText + "\""); + logger_.debug("Name from certificate : \"" + nameFromCertificate + "\""); + logger_.debug("Fixed name : \"" + merged + "\""); + } + } + return merged; + } + + /** + * This method tries to resolve the RDN corresponding to a given value from the certificate String. + * As values might occur multiple times for different RDNs, an unambiguous resolving cannot be assured. + * In case of ambiguity, the RDN extracted from text is returned by default. + * + * This method is a bug fix for a problem that caused the verification of ZID documents to fail as the RDN + * from the extracted text ("EMAILADDRESS") was different to the RDN in the certificate ("EMAIL") + * + * @param certString + * The String obtained from the certificate + * @param value + * The RDN's value + * @param extractedRDN + * The RDN extracted from the given text + * @return + * The resolved RDN from the certificate, or the RDN from text extraction + */ + private static String resolveRDN(String certString, String value, String extractedRDN) { + + if(!certString.contains(value)) { + + // given value cannot be found in certificate string + return extractedRDN; + } + + if(certString.indexOf(value) != certString.lastIndexOf(value)) { + + // given value is ambiguous - cannot resolve RDN from certificate string + return extractedRDN; + } + + String[] parts = certString.split(",|;"); + String val = value.trim(); + + for(int i=0; i + * It stores back the SignationIssuer, X509Certificate and + * X509CertificateDigest + */ + private void loadCurrentCert() + { + X509Cert cert = loadCertificate(getSignationSerialNumber(), getSignationIssuer()); + if (cert != null) + { + // merge RDNs from file with values from certificate + if (getSigValue(SignatureTypes.SIG_ISSUER) != null) { + this.setSignationIssuer(prepareRFC2253Name(getSigValue(SignatureTypes.SIG_ISSUER), cert.getIssuerName())); + } else { + this.setSignationIssuer(cert.getIssuerName()); + } + /* + if (getSigValue(SignatureTypes.SIG_ISSUER) == null) { + this.setSignationIssuer(cert.getIssuerName()); + } + */ + setSigValue(SIG_CER, cert.getCertString()); + // setSigValue(SIG_CER_DIG, cert.getCertDigest()); + x509Cert_ = cert; + } + } + + /** + * @return the current X509CertificateDigest value (as SHA1 digest). + */ + public String getX509CertificateDigest() + { + String dig = getSigValue(SIG_CER_DIG); + if (dig == null) + { + loadCurrentCert(); + byte[] cert_b64 = CodingHelper.decodeBase64(x509Cert_.getCertString()); + byte[] cert_hash = CodingHelper.buildDigest(cert_b64, "SHA"); + dig = new String(CodingHelper.encodeBase64(cert_hash)); + setSigValue(SIG_CER_DIG, dig); + } + return dig; + } + + /** + * @return the current X509v3 certificate string + */ + public String getX509CertificateString() + { + String cert = getSigValue(SIG_CER); + if (cert == null) + { + loadCurrentCert(); + cert = getSigValue(SIG_CER); + } + return cert; + } + + /** + * @param x509Certificate + * The X509v3 certificate of the signature to set + */ + public void setX509Certificate(String x509Certificate) + { + setSigValue(SIG_CER, x509Certificate); + storeCertificate(getSignationSerialNumber(), getSignationIssuer(), x509Certificate); + } + + public void setX509Certificate(X509Certificate cert) + { + try + { +// byte [] der = cert.getEncoded(); +// String certStr = CodingHelper.encodeBase64(der); +// setX509Certificate(certStr); + X509Cert knowcenterCert = X509Cert.initByX509Certificate(cert); + setSigValue(SIG_CER, knowcenterCert.getCertString()); + storeCertificate(cert.getSerialNumber().toString(), knowcenterCert.getIssuerName(), knowcenterCert.getCertString()); + } + catch (CertificateEncodingException e) + { + logger_.error(e.getMessage(), e); + } + } + + /** + * return the 509v3 certificate of the given serialNumber and the given issuer + * string + * + * @param serialNumber + * the serialNumber which the certificates should load + * @param issuer + * the issuer which the certificates should load + * @return the X509v3 certificate string + */ + public String getX509CertificateString(String serialNumber, String issuer) + { + X509Cert cert = loadCertificate(serialNumber, issuer); + if (cert != null) + { + return cert.getCertString(); + } + return null; + } + + public X509Cert getX509Cert(String serialNumber, String issuer) + { + return loadCertificate(serialNumber, issuer); + } + + public X509Cert getX509Cert() + { + if (x509Cert_ == null) + { + loadCurrentCert(); + } + return x509Cert_; + } + + /** + * Set the signation id's build by a BKU signated SignatureObject. + * + * @param sigIds + * the string to store. + */ + public void setSignationIDs(String sigIds) + { + if (sigIds != null) + { + setSigValue(SignatureTypes.SIG_ID, sigIds); + } + } + + // /** + // * Set the signation id's build by a BKU signated SignatureObject. + // * + // * @param sigIds + // * The sination id's are defined into five parts, that have the same + // * base as prefix. Therefore the ids's are reduced by the base prefix + // * and stored in the SignatureObject. + // */ + // public void setSignationIDs(String[] sigIds) + // { + // String join = ""; + // String base = null; + // for (int arr_idx = 0; arr_idx < sigIds.length; arr_idx++) + // { + // String id = sigIds[arr_idx]; + // if (logger_.isDebugEnabled()) + // { + // logger_.debug("Set BKU id:" + id); + // } + // int id_idx = id.lastIndexOf("-"); + // if (arr_idx == 0) + // { + // base = id.substring(0, id_idx); + // } + // String cur_id = id.substring(id_idx + 1); + // join += "-" + cur_id; + // } + // setSignationIDs(base + "@" + join.substring(1)); + // } + + // TODO hotfix + public static String formatSigIds(Properties response_properties, + String[] sigIds) throws SignatureException + { + // ids algorithm: + String join = ""; + String base = null; + for (int arr_idx = 0; arr_idx < sigIds.length; arr_idx++) + { + String id = sigIds[arr_idx]; + if (logger_.isDebugEnabled()) + { + logger_.debug("Set BKU id:" + id); + } + int id_idx = id.lastIndexOf("-"); + if (arr_idx == 0) + { + base = id.substring(0, id_idx); + } + String cur_id = id.substring(id_idx + 1); + join += "-" + cur_id; + } + // setSignationIDs(base + "@" + join.substring(1)); + String ids = base + "@" + join.substring(1); + // :ids algorithm + + String productName = response_properties.getProperty("productName"); + logger_.debug("productName = " + productName); +// if (!productName.equals("trustDeskbasic")) + // modified by tknall + if (!productName.startsWith("trustDeskbasic")) + { + final String msg = "The BKU environment " + productName + " is not trustDeskbasic and therefore the productVersion cannot be decided."; + logger_.error(msg); + // uncomment the following line in order to check new bkus + throw new SignatureException(0, msg); + } + + String productVersion = response_properties.getProperty("productVersion"); + logger_.debug("productVersion = " + productVersion); + boolean new_etsi = decideNewEtsiByBKUVersion(productVersion); + logger_.debug("verwende neue etsi properties = " + new_etsi); + + String etsi_prefix = ""; + if (new_etsi) + { + // TODO hotfix + etsi_prefix = "etsi-bka-1.0@"; + } + + String final_ids = etsi_prefix + ids; + logger_.debug("final_ids = " + final_ids); + + return final_ids; + } + + // TODO hotfix + public static boolean decideNewEtsiByBKUVersion(String productVersion) + { + boolean new_etsi = true; + // TODO hotfix + if (productVersion.startsWith("2.5") || productVersion.startsWith("2.4") || productVersion.startsWith("2.3") || productVersion.startsWith("2.2") || productVersion.startsWith("2.1") || productVersion.startsWith("1") || productVersion.startsWith("0")) + { + new_etsi = false; + } + return new_etsi; + } + + /** + * Checks if the current SignatureObject is siganted by MOA. It checks if the + * current SignatureObject has a signation id value. + * + * @return true if no signation id value is found, false otherwise + */ + public boolean isMOASigned() + { + try + { + PdfASID sig_kz = getKZ(); + String sig_id = getSignationIds(); + return SigKZIDHelper.isMOASigned(sig_kz, sig_id); + //return getSignationIds() == null; + } + catch (InvalidIDException e) + { + logger_.error(e.getMessage(), e); + return false; + } + } + + /** + * Tells if this SignatureObject is textual. + * + * @return Returns true, if it is textual. + */ + public boolean isTextual() + { + PdfASID kz = null; + try + { + kz = getKZ(); + } + catch (InvalidIDException e) + { + logger_.error(e.getMessage(), e); + } + return SigKZIDHelper.isTextual(kz); + } + + /** + * Tells, if this SignatureObject is binary. + * + * @return Returns true, if it is binary. + */ + public boolean isBinary() + { + PdfASID kz = null; + try + { + kz = getKZ(); + } + catch (InvalidIDException e) + { + logger_.error(e.getMessage(), e); + } + + return SigKZIDHelper.isBinary(kz); + } + + /** + * Takes the signation id value of the current SignatureObject and split them + * into the corresponding id array added with the id-base. + * + * @return the id array + */ + // TODO hotifx + public String getSignationIds() + { + String sig_ids = getSigValue(SignatureTypes.SIG_ID); + return sig_ids; + + // if (sig_ids == null || sig_ids.length() == 0) + // { + // return null; + // } + // + // // int index = sig_ids.indexOf(PdfAS.IDS); + // // if (index < 0) + // // { + // // return null; + // // } + // // sig_ids = sig_ids.substring(index + PdfAS.IDS.length()); + // // + // // if (sig_ids == null || sig_ids.length() == 0) + // // { + // // return null; + // // } + // + // String[] ids_str = sig_ids.split("@"); + // String base = ids_str[0]; + // String[] ids = ids_str[1].split("-"); + // String[] real_ids = new String[5]; + // real_ids[0] = base + "-" + ids[0]; + // real_ids[1] = "0-" + base + "-" + ids[1]; + // real_ids[2] = "0-" + base + "-" + ids[2]; + // real_ids[3] = "0-" + base + "-" + ids[3]; + // real_ids[4] = "0-" + base + "-" + ids[4]; + // if (logger_.isDebugEnabled()) + // { + // for (int id_idx = 0; id_idx < real_ids.length; id_idx++) + // { + // logger_.debug("Set BKU id:" + real_ids[id_idx]); + // } + // } + // return real_ids; + } + + // TODO hotfix + public static String[] parseSigIds(String sig_ids) + { + if (sig_ids == null || sig_ids.length() == 0) + { + return null; + } + + // int index = sig_ids.indexOf(PdfAS.IDS); + // if (index < 0) + // { + // return null; + // } + // sig_ids = sig_ids.substring(index + PdfAS.IDS.length()); + // + // if (sig_ids == null || sig_ids.length() == 0) + // { + // return null; + // } + + String[] ids_str = sig_ids.split("@"); + + String etsi_string = null; + if (ids_str.length == 3) + { + etsi_string = ids_str[0]; + String[] rest_ids = new String[] { ids_str[1], ids_str[2] }; + ids_str = rest_ids; + } + + String base = ids_str[0]; + String[] ids = ids_str[1].split("-"); + String[] real_ids = new String[6]; // the last one contains the etsi string + real_ids[0] = base + "-" + ids[0]; + real_ids[1] = "0-" + base + "-" + ids[1]; + real_ids[2] = "0-" + base + "-" + ids[2]; + real_ids[3] = "0-" + base + "-" + ids[3]; + real_ids[4] = "0-" + base + "-" + ids[4]; + real_ids[5] = etsi_string; + + if (logger_.isDebugEnabled()) + { + for (int id_idx = 0; id_idx < real_ids.length; id_idx++) + { + logger_.debug("real_ids[" + id_idx + "] = " + real_ids[id_idx]); + } + } + + return real_ids; + } + + /** + * This method normalizes the issuer string to support unique issuer string + * for equition. Used to store and find corresponting certificates. + * Normalzing: normalizing the string using the normalizer, remove all white + * spaces, encode as base64 and replace all "/" chars with "_". + * + * @param issuer + * the issuer string to normalize + * @return the normalized issuer string + * @author modified by tknall + */ + private String getIssuerFileHash(String issuer) + { + try + { + if (issuer != null) + { + // use explicit method for normalization + issuer = normalizeIssuer(issuer); + /* this block may be used to enhance normalization (tknall) + try { + Name issuerName = new RFC2253NameParser(issuer).parse(); + issuer = issuerName.getRFC2253String(); + } catch (RFC2253NameParserException e) { + logger_.error(e); + } + */ + // added the ("UTF-8") + issuer = CodingHelper.encodeBase64(CodingHelper.buildDigest(issuer.getBytes("UTF-8"), "sha1")); + issuer = issuer.replaceAll("/", "_"); + } + return issuer; + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + /** + * Prepares issuer for further processing (e.g. calculation of certificate store location or + * comparison with registered ldap mappings.) + * @param issuer The issuer. + * @return normalized issuer + * @see #issuerNameFilter + * @author tknall + */ + private String normalizeIssuer(String issuer) { + issuer = normalizer_.normalize(issuer, false); + issuer = removeAllWhiteSpaces(issuer); + return issuer; + } + + /** + * This method imports new certificates into the certstore path. + */ + private void addNewCertificates() + { + String cert_add_path = certPath_ + CERT_ADD_DIR; + File cert_add_dir = new File(cert_add_path); + if (cert_add_dir.isDirectory()) + { + File[] cert_files = cert_add_dir.listFiles(); + for (int cert_file_idx = 0; cert_file_idx < cert_files.length; cert_file_idx++) + { + File cert_file = cert_files[cert_file_idx]; + if (cert_file.isFile() && cert_file.canRead()) + { + X509Cert cert = X509Cert.initByFile(cert_file); + // System.err.println("isCert:" + cert.isX509Cert() + ":" + + // cert_file.getAbsolutePath()); + if (cert.isX509Cert()) + { + String issuer = cert.getIssuerName(); + String serial_number = cert.getSerialNumber(); + String iss_hash = getIssuerFileHash(issuer); + String cert_store_path = certPath_ + iss_hash; + + File cert_store_dir = new File(cert_store_path); + if (!cert_store_dir.exists()) + { + cert_store_dir.mkdir(); + } + if (cert_store_dir.isDirectory()) + { + String cert_file_name = cert_store_path + FILE_SEP + serial_number + CERT_FILE_EXTENSION; + logger_.debug("Adding cert (issuer=\"" + cert.getIssuerName() + "\", sn=\"" + cert.getSerialNumber() + "\") to certstore: \"" + cert_file_name + "\"."); + // boolean store = + FileHelper.writeToFile(cert_file_name, cert.getCertString()); + // System.err.println("store:" + store + ":" + + // cert_file.getAbsolutePath()); + } + } + boolean deleted = cert_file.delete(); + if (deleted == false) + { + logger_.error("couldn't delete:" + cert_file.getAbsolutePath()); + } + } + } + } + } + + private X509Cert loadCertificateFromCertstore(String serialNumber, String issuer) { + String iss_hash = getIssuerFileHash(issuer); + String cert_store_path = certPath_ + iss_hash; + String cert_file_name = cert_store_path + FILE_SEP + serialNumber + CERT_FILE_EXTENSION; + if (logger_.isDebugEnabled()) { + logger_.debug("Trying to load cert (issuer=\"" + (issuer != null ? normalizeIssuer(issuer) : issuer) + "\", sn=\"" + serialNumber + "\") from certstore: \"" + cert_file_name + "\"."); + } + return X509Cert.initByFilePath(cert_file_name); + } + + /** + * This method load a X509v3 certificate from the filesystem. The reference to + * the stored certificate is build by the serialNumber and the issuer string. + * The issuer string is normalized because if getting this value from a pdf + * extraction it can be splited into more sections or necessary spaces are + * removed. The real issuer value is stored in the certificates meta file. The + * certficate is devided into two files: certificate.der (the binary value) + * and the meta information used in SignatureObjects as well in + * SignatureImages of a signed pdf-document. The storing path of the + * certificate is build by: + *
    + *
  1. normalize the issuer string
  2. + *
  3. reduce all white spaces in the normalized issuer string
  4. + *
  5. build a hash value of this reduced string
  6. + *
  7. code this hash value as base64 value
  8. + *
  9. add the base64 normalized issuer hash value to the certificate base + * store path
  10. + *
  11. add the serialNumber to the cert path
  12. + *
  13. add the .der extension to get the certificate binary
  14. + *
  15. add the .txt extension to get the meta information of + * the certificate
  16. + *
+ * + * The certificate meta file is build by the base64 coded issuer string and + * the cert digest value devided by the @ char. + * + * @param serialNumber + * the file name of the certificate .der|.txt + * @param issuer + * the file path value of the certificate + * @return String array: [0]--> issuer string; [1]-->certificate binary; + * [2]--> cert digest value + */ + private X509Cert loadCertificate(String serialNumber, String issuer) + { + addNewCertificates(); + X509Cert cert = null; + if (issuer != null && serialNumber != null) + { + cert = loadCertificateFromCertstore(serialNumber, issuer); + if (cert == null) { + logger_.debug("Certificate not found. Trying alternative normalization method."); + try { + Name issuerName = new RFC2253NameParser(issuer).parse(); + cert = loadCertificateFromCertstore(serialNumber, issuerName.getRFC2253String(false)); + } catch (RFC2253NameParserException e) { + logger_.error(e.getMessage(), e); + } + } + + if (cert == null) + { + logger_.info("The certificate '" + issuer + "', '" + serialNumber + "' wasn't found in the local certificate store - connecting to LDAP."); + + // the certificate wasn't found in the local store + // - load it from the LDAP server. + + byte[] cert_data = loadCertificateFromLDAP(serialNumber, issuer); + if (cert_data == null) + { + logger_.info("The certificate '" + issuer + "', '" + serialNumber + "' wasn't found on the LDAP server either."); + + return null; + } + + storeNewCertificateInLocalStore(cert_data); + + cert = X509Cert.initByByteArray(cert_data); + if (cert == null) + { + logger_.debug("The certificate should be loaded here, but is null - something's wrong."); + } + } + } else { + logger_.warn("loadCertificate(\"" + serialNumber + "\", \"" + issuer + "\")"); + } + return cert; + } + + /** + * This is an internal counter for added certificates. + */ + protected static int new_cert_num = 0; + + /** + * Writes the certificate data to a file and stores the file in the local + * certificate store. + * + * @param cert_data + * The binary certificate data. + */ + public void storeNewCertificateInLocalStore(byte[] cert_data) + { + // write the loaded certificate to the add directory + String cert_add_path = certPath_ + CERT_ADD_DIR; + File cert_add_dir = new File(cert_add_path); + if (!cert_add_dir.exists()) + { + cert_add_dir.mkdirs(); + } + File save_file = new File(cert_add_dir, "newcert_" + new_cert_num + ".der"); + new_cert_num++; + try + { + FileOutputStream fos = new FileOutputStream(save_file); + fos.write(cert_data); + fos.close(); + // fixed by tknall: if serialnumber or issuername is omitted (binary signature) the + // certificate could not be found in the certstore. The fix sets the issuername and + // serialnumber as long the are known. + X509Cert cert = X509Cert.initByByteArray(cert_data); + if (cert.isX509Cert()) { + this.setSignationSerialNumber(cert.getSerialNumber()); + this.setSignationIssuer(cert.getIssuerName()); + } + } catch (IOException e) { + logger_.error(e.getMessage(), e); + return; + } + + // add the new certificate to the local store + addNewCertificates(); + } + + /** + * Connects to the LDAP server to look for the certificate. + * + * @param serialNumber + * The serial number String of the certificate being sought. E.g. + * "123455676744123432". + * @param issuer + * The issuer String of the certificate being sought. + * + * @return Returns the DER certificate file as can be stored in the local + * repository. Returns null, if the document wasn't found on the + * server. + * @throws ClassNotFoundException + */ + protected byte[] loadCertificateFromLDAP(String serialNumber, String issuer) { + // START modification by TK + String implClassURI = System.getProperty(LDAPAPI.SYS_PROP_IMPLEMENTATION); + LDAPAPI ldapAPIImpl; + try { + // note: in case of implClassURI==null the default implementation + // at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIImpl is used + ldapAPIImpl = LDAPAPIFactory.getInstance(issuerNameFilter).createLDAPAPI(implClassURI); + } catch (LDAPAPIException e) { + throw new RuntimeException(e); + } + return ldapAPIImpl.loadBase64CertificateFromLDAP(serialNumber, issuer); + // STOP modification by TK + } + + /** + * This method stores a X509v3 certificate to the filesystem. The reference to + * the stored certificate is build by the serialNumber and the issuer string. + * The issuer string is normalized because if getting this value from a pdf + * extraction it can be splited into more sections or necessary spaces are + * removed. The real issuer value is stored in the certificates meta file. The + * certficate is devided into two files: certificate.der (the binary value) + * and the meta information used in SignatureObjects as well in + * SignatureImages of a signed pdf-document. The storing path of the + * certificate is build by: + *
    + *
  1. normalize the issuer string
  2. + *
  3. reduce all white spaces in the normalized issuer string
  4. + *
  5. build a hash value of this reduced string
  6. + *
  7. code this hash value as base64 value
  8. + *
  9. add the base64 normalized issuer hash value to the certificate base + * store path
  10. + *
  11. add the serialNumber to the cert path
  12. + *
  13. add the .der extension to get the certificate binary
  14. + *
  15. add the .txt extension to get the meta information of + * the certificate
  16. + *
+ * + * The certificate meta file is build by the base64 coded issuer string and + * the cert digest value devided by the @ char. + * + * @param serialNumber + * the file name of the certificate .der|.txt + * @param issuer + * the issuer string for the file path value of the certificate and + * for metainformation + * @param x509Certificate + * the x509v3 binary string + * @param x509Digest + * the digest value of the given x509Certificate + * @return true the certificate is stored completely, false otherwise + * @deprecated Use {@link #storeCertificate(String, String, String)} instead. + */ + private boolean storeCertificate(String serialNumber, String issuer, + String x509Certificate, String x509Digest) + { + return storeCertificate(serialNumber, issuer, x509Certificate); + } + + /** + * This method stores a X509v3 certificate to the filesystem. The reference to + * the stored certificate is build by the serialNumber and the issuer string. + * The issuer string is normalized because if getting this value from a pdf + * extraction it can be splited into more sections or necessary spaces are + * removed. The real issuer value is stored in the certificates meta file. The + * certficate is devided into two files: certificate.der (the binary value) + * and the meta information used in SignatureObjects as well in + * SignatureImages of a signed pdf-document. The storing path of the + * certificate is build by: + *
    + *
  1. normalize the issuer string
  2. + *
  3. reduce all white spaces in the normalized issuer string
  4. + *
  5. build a hash value of this reduced string
  6. + *
  7. code this hash value as base64 value
  8. + *
  9. add the base64 normalized issuer hash value to the certificate base + * store path
  10. + *
  11. add the serialNumber to the cert path
  12. + *
  13. add the .der extension to get the certificate binary
  14. + *
  15. add the .txt extension to get the meta information of + * the certificate
  16. + *
+ * + * The certificate meta file is build by the base64 coded issuer string and + * the cert digest value devided by the @ char. + * + * @param serialNumber + * the file name of the certificate .der|.txt + * @param issuer + * the issuer string for the file path value of the certificate and + * for metainformation + * @param x509Certificate + * the x509v3 binary string + * @return true the certificate is stored completely, false otherwise + */ + private boolean storeCertificate(String serialNumber, String issuer, + String x509Certificate) + { + boolean store_complete = false; + if (issuer != null && serialNumber != null) + { + logger_.debug("Storing certificate."); + // String issuer_b64 = CodingHelper.encodeBase64(issuer.getBytes()); + String iss_hash = getIssuerFileHash(issuer); + File cert_path_dir = new File(certPath_); + if (!cert_path_dir.exists()) + { + logger_.debug("Certstore path \"" + cert_path_dir + "\" does not exist. Creating."); + cert_path_dir.mkdir(); + } + String cert_store_path = certPath_ + iss_hash; + File cert_store_dir = new File(cert_store_path); + if (!cert_store_dir.exists()) + { + logger_.debug("Certstore dir \"" + cert_store_dir + "\" does not exist. Creating."); + cert_store_dir.mkdir(); + } + if (cert_store_dir.isDirectory()) + { + String cert_file_name = cert_store_path + FILE_SEP + serialNumber + CERT_FILE_EXTENSION; + if (logger_.isInfoEnabled()) + { + logger_.info("store certificate:" + cert_file_name); + } + boolean store_cert_file = FileHelper.writeToFile(cert_file_name, x509Certificate); + store_complete = store_cert_file;// && store_cert_meta; + } else { + logger_.warn("Certstore dir \"" + cert_store_dir + "\" is not a directory. Skipping storage."); + } + } + return store_complete; + } + + /** + * @return Returns the AbstractTable. + * @see at.knowcenter.wag.egov.egiz.table.Table + */ + public Table getAbstractTable() + { + if (sigTable_ == null) + { + sigTable_ = createSigTable(SignatureTypes.MAIN_TABLE); + } + return sigTable_; + } + + /** + * This method read the style definitions from the settings file. + * + * @param styleKey + * the key to read the style definitions + * @return the defined style informations + * @see at.knowcenter.wag.egov.egiz.table.Style + */ + private Style readStyle(String styleKey) + { + ArrayList styles = settings_.getKeys(styleKey); + Style style = new Style(); + for (int style_idx = 0; style_idx < styles.size(); style_idx++) + { + String style_id = (String) styles.get(style_idx); + String style_val = settings_.getSetting(styleKey + "." + style_id, null); + style.setStyle(style_id, style_val); + } + return style; + } + + /** + * This method creates an abstract signature table object. It takes all keys + * and values set by the signature object to create the corresponding abstract + * table object. The table definition is read from the settings file. + * + * @param tableKey + * is the name of the table definition in the settings file + * @return a new abstract signature table + * @see at.knowcenter.wag.egov.egiz.table.Style + * @see at.knowcenter.wag.egov.egiz.table.Table + * @see at.knowcenter.wag.egov.egiz.table.Entry + */ + private Table createSigTable(String tableKey) + { + String table_key_prefix = SignatureTypes.SIG_OBJ + getSignationType() + "." + SignatureTypes.TABLE; + String table_key = table_key_prefix + tableKey; + // String caption_prefix = SignatureTypes.SIG_OBJ + getSignationType() + + // ".key."; + // String value_prefix = SignatureTypes.SIG_OBJ + getSignationType() + + // ".value."; + // ArrayList table_def_keys = settings_.getKeys(table_key); + Vector table_def_keys = settings_.getSettingKeys(table_key); + if (table_def_keys == null) + { + return null; + } + Table sig_table = new Table(tableKey); + boolean found_style = false; + for (int table_key_idx = table_def_keys.size() - 1; table_key_idx >= 0; table_key_idx--) + { + String table_def = (String) table_def_keys.get(table_key_idx); + int dot_idx = (table_def.indexOf(".") > 0 ? table_def.indexOf(".") : table_def.length()); + table_def = table_def.substring(0, dot_idx); + String table_def_keys_prefix = table_key + "." + table_def; + String table_def_string = settings_.getSetting(table_def_keys_prefix, null); + if (table_def.matches("\\D*")) + { + // if the table key is not a number (row number index) + if (SignatureTypes.COLS_WITH.equals(table_def)) + { + String[] cols_s = table_def_string.split(" "); + float[] cols_f = new float[cols_s.length]; + for (int i = 0; i < cols_s.length; i++) + { + cols_f[i] = Float.parseFloat(cols_s[i]); + } + sig_table.setColsRelativeWith(cols_f); + } + if (SignatureTypes.STYLE.equals(table_def) && !found_style) + { + Style style = readStyle(table_def_keys_prefix); + sig_table.setStyle(style); + found_style = true; + } + continue; + } + if (table_def_string != null) + { + // analyse the row definition + String[] elems = table_def_string.split("\\|"); + ArrayList row = new ArrayList(); + for (int elem_idx = 0; elem_idx < elems.length; elem_idx++) + { + String elem = elems[elem_idx]; + String[] key_type = elem.split("-"); + if (key_type.length < 2) + { + return null; + } + String key = key_type[0]; + String type = key_type[1]; + if (SignatureTypes.TYPE_TABLE.equals(key)) + { + // add a table entry + Table table = createSigTable(type); + if (table != null) + { + Entry entry = new Entry(Entry.TYPE_TABLE, table, key); + row.add(entry); + } + } + if (SignatureTypes.TYPE_IMAGE.equals(type)) + { + // add an image entry + String value = getSigValue(key); + if (value != null) + { + Entry entry = new Entry(Entry.TYPE_IMAGE, value, key); + entry.setStyle(defaultImageStyle_); + row.add(entry); + } + } + if (SignatureTypes.TYPE_VALUE.equals(type)) + { + // add a single value entry + String value = getSigValue(key); + Entry entry = new Entry(Entry.TYPE_VALUE, value, key); + if (entry != null) + { + entry.setColSpan(2); + entry.setStyle(defaultValueStyle_); + row.add(entry); + } + } + if ((SignatureTypes.TYPE_VALUE + SignatureTypes.TYPE_CAPTION).equals(type) || (SignatureTypes.TYPE_CAPTION + SignatureTypes.TYPE_VALUE).equals(type)) + { + // add a caption value pair + String caption = getSigCaption(key); + String value = getSigValue(key); + if (value != null) + { + Entry c_entry = new Entry(Entry.TYPE_CAPTION, caption, key); + c_entry.setNoWrap(true); // dferbas fix bug #331 + c_entry.setStyle(defaultCaptionStyle_); + + Entry v_entry = new Entry(Entry.TYPE_VALUE, value, key); + v_entry.setStyle(defaultValueStyle_); + if (c_entry != null && v_entry != null) + { + row.add(c_entry); + row.add(v_entry); + } + } + } + } + sig_table.addRow(table_def, row); + } + } + + return sig_table; + } + + /** + * This method inits the signature object by the given type. It loads the + * configured values and captions from the config.properties file. + */ + public void initByType() throws SignatureTypesException + { + if (sigType_ == null) + { + sigType_ = getDefaultSigType(); + } + SignatureTypes sig_types = SignatureTypes.getInstance(); + signatureDefinition_ = sig_types.getSignatureTypeDefinition(sigType_); + if (signatureDefinition_ == null) + { + final String msg = "The SignatureObject's sigType '" + sigType_ + "' wasn't found in the configuration file's specified signature profiles. This usually happens if the sig_obj.type.default object has been turned off or is misspelled."; + logger_.error(msg); + throw new SignatureTypesException(msg); + } + Map key_cap_map = signatureDefinition_.getKeyCaptionMap(); + if (key_cap_map != null) + { + Iterator key_cap = key_cap_map.entrySet().iterator(); + while (key_cap.hasNext()) + { + Map.Entry entry = (Map.Entry) key_cap.next(); + String key = (String) entry.getKey(); + String caption = (String) entry.getValue(); + SignatureEntry sig_entry = null; + if (sigEntries_.containsKey(key)) + { + sig_entry = (SignatureEntry) sigEntries_.get(key); + } + else + { + sig_entry = new SignatureEntry(key); + sigEntries_.put(key, sig_entry); + } + sig_entry.setCaption(caption); + } + } + + Map key_val_map = signatureDefinition_.getKeyValueMap(); + if (key_val_map != null) + { + Set key_val_set = key_val_map.entrySet(); + Iterator key_val = key_val_set.iterator(); + while (key_val.hasNext()) + { + Map.Entry entry = (Map.Entry) key_val.next(); + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + if (SignatureTypes.SIG_NORM.equals(key)) + { + try + { + normalizer_.setVersion(value); + } + catch (NormalizeException e) + { + throw new SignatureTypesException(e); + } + } + // value = new String(CodingHelper.encodeUTF8(value)); + // if (logger_.isDebugEnabled()) + // { + // logger_.debug("key:" + key + " value:" + value); + // } + setSigValue(key, value); + } + } + } + + /** + * This method returns a signature entry object. + * + * @param key + * the corresponding key + * @return the signature entry object of the given key, null if the key does + * not exist + */ + public SignatureEntry getSigEntry(String key) + { + return (SignatureEntry) sigEntries_.get(key); + } + + /** + * This method is a helper function to remove all white spaces from a text. + * + * @param text + * the white spaces should remove from + * @return a text without white spaces + */ + private static String removeAllWhiteSpaces(String text) + { + return text.replaceAll("\\s", ""); + } + + public SignatureTypeDefinition getSignatureTypeDefinition() + { + return this.signatureDefinition_; + } + + /** + * + * @param placeholder + * @return Returns the list of SignatureFieldDefinitions that's values in the + * SignatureObject have been filled out with placeholders. + */ + public List fillValues(final char placeholder, boolean has_SIG_ID, boolean baikEnabled) + { + List variable_fields = new ArrayList(); + + List field_definitions = this.signatureDefinition_.getFieldDefinitions(); + Iterator it = field_definitions.iterator(); + while (it.hasNext()) + { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) it.next(); + String value_string = null; + if (sfd.placeholder_length > 0) + { + if (sfd.field_name.equals(SignatureTypes.SIG_ID) && has_SIG_ID == false) + { + setValueBruteForce(SignatureTypes.SIG_ID, null); + continue; + } + + if (sfd.field_name.equals(SignatureTypes.SIG_ALG) && !baikEnabled) { + setValueBruteForce(SignatureTypes.SIG_ID, null); + continue; + } + + char[] placeholder_chars = new char[sfd.placeholder_length]; + for (int i = 0; i < placeholder_chars.length; i++) + { + placeholder_chars[i] = placeholder; + } + value_string = new String(placeholder_chars); + + variable_fields.add(sfd); + + setSigValue(sfd.field_name, value_string, true); + } + } + + return variable_fields; + } + + /** + * Returns the raw signature response XML string as set by the signing + * Connector. + * + * @return Returns the XML response String. + */ + public String getRawSignatureResponse() + { + return this.raw_signature_response; + } + + /** + * Sets the raw signature response XML string. + * + *

+ * This should be used by the Connector to pass the response String to the + * signer. + *

+ * + * @param raw_response_string + * The new raw signature response string. + */ + public void setRawSignatureResponse(String raw_response_string) + { + this.raw_signature_response = raw_response_string; + } + + + + /** + * get timestamp if available + * @return + */ + public String getTimeStamp() { + return this.timeStamp; + } + + /** + * set timestamp + * @param timeStamp + */ + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + +/** + * The toString method, used for tests or debugging. + */ + public String toString() + { + String strg = ""; + Iterator it = sigEntries_.values().iterator(); + while (it.hasNext()) + { + SignatureEntry sig_entry = (SignatureEntry) it.next(); + String key = sig_entry.getKey(); + String caption = sig_entry.getCaption(); + String value = sig_entry.getValue(); + strg += key + "=" + caption + ":" + value + "\n"; + } + strg += "Signation Type:" + getSignationType() + "\n"; + return strg; + } + + public Map getSigEntries() { + return sigEntries_; + } + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureResponse.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureResponse.java new file mode 100644 index 0000000..0c733f6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureResponse.java @@ -0,0 +1,559 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: SignatureResponse.java,v 1.4 2006/08/03 07:43:04 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.apache.log4j.Logger; + +import at.gv.egiz.pdfas.api.exceptions.PdfAsException; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.PropertyTree; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +/** + * The response of a verification. + * + * @author wlackner + */ +public class SignatureResponse +{ + /** + * The siganture response config key + */ + private static String SIG_RESP_KEY = "signature.response."; + + /** + * Default response message + */ + private static String SIG_RESP_DEFAULT_INFO = "Es ist leider keine nähere Information verfügbar:"; + + /** + * Response value for x509SubjectName_ + */ + private String x509SubjectName_ = null; + + /** + * Response value for x509IssuerName + */ + private String x509IssuerName = null; + + /** + * Response value for x509SerialNumber + */ + private String x509SerialNumber = null; + + /** + * Response value for signatureCheckCode_ + */ + private String signatureCheckCode_ = null; + + /** + * Response value for signatureCheckInfo_ + */ + private String signatureCheckInfo_ = null; + + /** + * Response value for signatureManifestCheckCode_ + */ + private String signatureManifestCheckCode_ = null; + + /** + * Response value for signatureManifestCheckInfo_ + */ + private String signatureManifestCheckInfo_ = null; + + /** + * Response value for certificateCheckCode_ + */ + private String certificateCheckCode_ = null; + + /** + * Response value for certificateCheckInfo_ + */ + private String certificateCheckInfo_ = null; + + /** + * The X.509 certificated parsed from the response string. + */ + protected X509Cert certificate_ = null; + + // [tknall] start qualified certificate + private boolean qualifiedCertificate = false; + // [tknall] stop qualified certificate + + private boolean publicAuthority = false; + private String publicAuthorityCode = null; + + protected String hashInputData = null; + + private PdfAsException verificationImpossibleEx = null; + + // /** + // * Flag the marks that the response is an error response + // */ + // private boolean isError_ = false; + // + // /** + // * The error code of an external application + // */ + // private String errorCode_ = null; + + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(SignatureResponse.class); + + /** + * + * + */ + public SignatureResponse() + { + try + { + loadSettings(); + } + catch (SignatureException e) + { + logger_.warn(e.getMessage(), e); + } + } + + /** + * load the inital signature settings + * + * @throws SignatureException + * @see SettingsReader + */ + private void loadSettings() throws SignatureException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new SignatureException(101, log_message, e); + } + } + } + + /** + * @return Returns the certificateCheckCode. + */ + public String getCertificateCheckCode() + { + return certificateCheckCode_; + } + + /** + * @param certificateCheckCode + * The certificateCheckCode to set. + */ + public void setCertificateCheckCode(String certificateCheckCode) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setCertificateCheckCode:" + certificateCheckCode); + } + certificateCheckCode_ = certificateCheckCode; + } + + /** + * @return Returns the signatureCheckCode. + */ + public String getSignatureCheckCode() + { + return signatureCheckCode_; + } + + /** + * @param signatureCheckCode + * The signatureCheckCode to set. + */ + public void setSignatureCheckCode(String signatureCheckCode) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setSignatureCheckCode:" + signatureCheckCode); + } + signatureCheckCode_ = signatureCheckCode; + } + + /** + * @return Returns the signatureManifestCheckCode. + */ + public String getSignatureManifestCheckCode() + { + return signatureManifestCheckCode_; + } + + /** + * Returns {@code true} if the underlying certificate indicates public authority. + * @return {@code true} if public authority, {@code false} if not. + */ + public boolean isPublicAuthority() { + return this.publicAuthority; + } + + /** + * Sets the public authority flag. + * @param publicAuthority The public authority flag. + */ + public void setPublicAuthority(boolean publicAuthority) { + this.publicAuthority = publicAuthority; + } + + /** + * Returns the public authority code of {@code null} if no code was provided. + * @return The public authority code. + */ + public String getPublicAuthorityCode() { + return this.publicAuthorityCode; + } + + /** + * Sets the public authority code. + * @param publicAuthorityCode The public authority code. + */ + public void setPublicAuthorityCode(String publicAuthorityCode) { + this.publicAuthorityCode = publicAuthorityCode; + } + +/** + * @param signatureManifestCheckCode + * The signatureManifestCheckCode to set. + */ + public void setSignatureManifestCheckCode(String signatureManifestCheckCode) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setSignatureManifestCheckCode:" + signatureManifestCheckCode); + } + signatureManifestCheckCode_ = signatureManifestCheckCode; + } + + /** + * @return Returns the x509IssuerName. + */ + public String getX509IssuerName() + { + return x509IssuerName; + } + + /** + * @param issuerName + * The x509IssuerName to set. + */ + public void setX509IssuerName(String issuerName) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setX509IssuerName:" + issuerName); + } + x509IssuerName = issuerName; + } + + /** + * @return Returns the x509SerialNumber. + */ + public String getX509SerialNumber() + { + return x509SerialNumber; + } + + /** + * @param serialNumber + * The x509SerialNumber to set. + */ + public void setX509SerialNumber(String serialNumber) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setX509SerialNumber:" + serialNumber); + } + x509SerialNumber = serialNumber; + } + + /** + * @return Returns the x509SubjectName. + */ + public String getX509SubjectName() + { + return x509SubjectName_; + } + + /** + * @param subjectName + * The x509SubjectName to set. + */ + public void setX509SubjectName(String subjectName) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setX509SubjectName:" + subjectName); + } + x509SubjectName_ = subjectName; + } + + /** + * @return Returns the certificateCheckInfo. + */ + public String getCertificateCheckInfo() + { + if (certificateCheckInfo_ == null) + { + if (settings_ != null) + { + certificateCheckInfo_ = settings_.getValueFromKey(SIG_RESP_KEY + "certificateCheckInfo." + getCertificateCheckCode()); + } + } + if (certificateCheckInfo_ == null) + { + certificateCheckInfo_ = SIG_RESP_DEFAULT_INFO + getCertificateCheckCode(); + } + return certificateCheckInfo_; + } + + /** + * @param certificateCheckInfo + * The certificateCheckInfo to set. + */ + public void setCertificateCheckInfo(String certificateCheckInfo) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setCertificateCheckInfo:" + certificateCheckInfo); + } + certificateCheckInfo_ = certificateCheckInfo; + } + + // [tknall] start qualified certificate + + /** + * Returns true if certificate is qualified, false if not. + * @return true if certificate is qualified, false if not. + */ + public boolean isQualifiedCertificate() { + return this.qualifiedCertificate; + } + + /** + * Sets the flag for qualified certificate. + * @param qualifiedCertificate The new qualified certificate status. + */ + public void setQualifiedCertificate(boolean qualifiedCertificate) { + this.qualifiedCertificate = qualifiedCertificate; + } + // [tknall] stop qualified certificate + + /** + * @return Returns the signatureCheckInfo. + */ + public String getSignatureCheckInfo() + { + if (signatureCheckInfo_ == null) + { + if (settings_ != null) + { + signatureCheckInfo_ = settings_.getValueFromKey(SIG_RESP_KEY + "signatureCheckInfo." + getSignatureCheckCode()); + } + } + if (signatureCheckInfo_ == null) + { + signatureCheckInfo_ = SIG_RESP_DEFAULT_INFO + getSignatureCheckCode(); + } + return signatureCheckInfo_; + } + + /** + * @param signatureCheckInfo + * The signatureCheckInfo to set. + */ + public void setSignatureCheckInfo(String signatureCheckInfo) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setSignatureCheckInfo:" + signatureCheckInfo); + } + signatureCheckInfo_ = signatureCheckInfo; + } + + /** + * @return Returns the signatureManifestCheckInfo. + */ + public String getSignatureManifestCheckInfo() + { + if (signatureManifestCheckInfo_ == null) + { + if (settings_ != null) + { + signatureManifestCheckInfo_ = settings_.getValueFromKey(SIG_RESP_KEY + "signatureManifestCheckInfo." + getSignatureManifestCheckCode()); + } + } + if (signatureManifestCheckInfo_ == null) + { + signatureManifestCheckInfo_ = SIG_RESP_DEFAULT_INFO + getSignatureManifestCheckCode(); + } + return signatureManifestCheckInfo_; + } + + /** + * @param signatureManifestCheckInfo + * The signatureManifestCheckInfo to set. + */ + public void setSignatureManifestCheckInfo(String signatureManifestCheckInfo) + { + if (logger_.isDebugEnabled()) + { + logger_.debug("setSignatureManifestCheckInfo:" + signatureManifestCheckInfo); + } + signatureManifestCheckInfo_ = signatureManifestCheckInfo; + } + + /** + * Returns the X.509 certificate of this response. + * + * @return Returns the X.509 certificate of this response. + */ + public X509Cert getCertificate() + { + return certificate_; + } + + /** + * Sets the X.509 certificate of this response. + * + * @param certificate + * The X.509 certificate to be set. + */ + public void setCertificate(X509Cert certificate) + { + this.certificate_ = certificate; + } + + public String getHashInputData() + { + return this.hashInputData; + } + + public void setHashInputData(String hashInputData) + { + this.hashInputData = hashInputData; + } + + public PdfAsException getVerificationImpossibleEx() { + return verificationImpossibleEx; + } + + public void setVerificationImpossibleEx(PdfAsException verificationImpossibleEx) { + this.verificationImpossibleEx = verificationImpossibleEx; + } + +/** + * Returns a list of Strings each stating one public property of the + * certificate. + * + *

+ * Such public properties are certificate extensions each being assigned an + * own OID. For example the public property "Verwaltungseigenschaft" has the + * OID "1.2.40.0.10.1.1.1". + *

+ *

+ * This methods reads out the list of possible properties from the config file + * and compares these to the extensions defined on the certificate. If they + * match, a String containing useful information about the property is added + * to the list returned. + *

+ * + * @return Returns the list of Strings representing the public properties of + * this certificate, if any. + * @throws SettingNotFoundException + */ + public List getPublicProperties() throws SettingNotFoundException + { + List props = new ArrayList(); + + SettingsReader settings = this.settings_; + + String root_oid = settings.getSetting("oid.root"); + + PropertyTree oids = settings.getPTree().getSubTree("oid"); + + Set non_critial_oids = this.certificate_.getX509Certificate().getNonCriticalExtensionOIDs(); + Iterator ext_it = non_critial_oids.iterator(); + while (ext_it.hasNext()) + { + String oid = (String) ext_it.next(); + + if (oid.startsWith(root_oid)) + { + String key = oid.replaceAll("\\.", "_"); + + String value = oids.getLastValue(key); + if (value == null) + { + value = oid; + } + + props.add(value); + } + } + + return props; + } + + /** + * The toString method + */ + public String toString() + { + String str = ""; + str += "\nSignator:" + getX509SubjectName(); + str += "\nAusteller:" + getX509IssuerName(); + str += "\nSeriennummer:" + getX509SerialNumber(); + str += "\nZertifikat-Code:" + getCertificateCheckCode() + "=" + getCertificateCheckInfo(); + str += "\nSignatur-Check-Code:" + getSignatureCheckCode() + "=" + getSignatureCheckInfo(); + str += "\nManifest-Check-Code:" + getSignatureManifestCheckCode() + "=" + getSignatureManifestCheckInfo(); + return str; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureSeparator.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureSeparator.java new file mode 100644 index 0000000..5b80490 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureSeparator.java @@ -0,0 +1,146 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: SignatureSeparator.java,v 1.4 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.util.List; +import java.util.Stack; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; + +/** + * This class separates all signature blocks in a raw text. + * @deprecated This process of separating signature blocks is obsolete - use AbsoluteTextSignature etc. instead. + */ +public class SignatureSeparator { + /** + * The signature block stack. On top of the stack is the first signature block that can be + * extracted. First means nearest to the document text. + */ + private Stack signatureBlocks_ = null; + /** + * A list of signature type definitions. + */ + private List signatureTypes_ = null; + /** + * Indicator that shows that a raw text is signated + */ + private boolean hasSignatureBlock_ = false; + + /** + * The empty constructor. It loads all signature type infos to extract the signature block from + * the raw text. + * + * @throws SignatureTypesException + */ + public SignatureSeparator() throws SignatureTypesException { + SignatureTypes sig_types = SignatureTypes.getInstance(); + signatureTypes_ = sig_types.getSignatureTypeDefinitions(); + } + + /** + * This method takes a raw text as input and trys to separate all signature blocks. It returns + * true if a signature block is found. + * + * @param rawText + * @return true if a signature block is found false otherwise + */ + public boolean separateBlock(String rawText) { + signatureBlocks_ = new Stack(); + hasSignatureBlock_ = separateBlock(rawText, rawText.length()); + return hasSignatureBlock_; + } + + /** + * This method calls itself rekursively while signature blocks can be extracted. If a signature + * block is found (search from the bottom of the raw text) the raw text would be reduced by the + * length of the found signature block text. + * + * @param rawText the text to be separated + * @param endIndex the index to cut the tail from the raw text + * @return true if a signature block is found false otherwise + */ + private boolean separateBlock(String rawText, int endIndex) { + boolean found = false; + boolean can_separate = true; + while (can_separate) { + SignatureBlock sig_block = new SignatureBlock(signatureTypes_); + String raw_text = rawText.substring(0, endIndex); + can_separate = sig_block.separateBlockFromRawText(raw_text, true); + if (can_separate) { + signatureBlocks_.push(sig_block); + endIndex = sig_block.getStartIndex(); + found = true; + } + } + return found; + } + + /** + * This method returns the start index of the first signature block. It is used to separate the + * real document text from the signature block texts. + * + * @return the start index of the first signature block + */ + public int getStartIndex() { + int start_index = -1; + if (signatureBlocks_ != null && signatureBlocks_.size() > 0) { + SignatureBlock sig_block = (SignatureBlock) signatureBlocks_.peek(); + return sig_block.getStartIndex(); + } + return start_index; + } + + /** + * @return the first found signature object in the given raw text or null if the raw text does not + * contain any signature objects + */ + public SignatureObject getFirstSignatureObject() { + if (signatureBlocks_ != null && signatureBlocks_.size() > 0) { + SignatureBlock sig_block = (SignatureBlock) signatureBlocks_.peek(); + try { + return sig_block.getSignatureObject(); + } catch (SignatureException e) { + return null; + } + } + return null; + } + + /** + * @return all separated signature blocks as stack, first is on top + */ + public Stack getSignatureBlocks() { + return signatureBlocks_; + } + + /** + * @return true if a signature block is found false otherwise + */ + public boolean hasSignatureBlock() { + return hasSignatureBlock_; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypeDefinition.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypeDefinition.java new file mode 100644 index 0000000..de099bf --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypeDefinition.java @@ -0,0 +1,605 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: SignatureTypeDefinition.java,v 1.3 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; + +public class SignatureTypeDefinition implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 1327407307346061147L; + + /** + * The log. + */ + private static final Log logger_ = LogFactory.getLog(SignatureTypeDefinition.class); + + /** + * The type of this definition + */ + protected String type_ = null; + + /** + * A map of all key to caption tupls. + */ + private Map keyCaptionMap_ = new HashMap(); + + /** + * A map of all key to value tupls. + */ + private Map keyValueMap_ = new HashMap(); + + /** + * A list of sorted keys + */ + private Vector sortedKeys_ = null; + + /** + * A list of sorted captions + */ + private Vector sortedCaptions_ = null; + + /** + * A revert of sorted keys + */ + private Vector revertSortedKeys_ = new Vector(); + + /** + * A revert list of sorted captions + */ + private Vector revertSortedCaptions_ = new Vector(); + + /** + * The settings reader reference + */ + private SettingsReader settings_ = null; + + /** + * List of (visible) field definitions. + */ + protected Map field_definitions_ = null; + + /** + * List of invisible field definitions. + * + *

+ * If empty, all definitions are visible. + *

+ */ + protected Map invisible_field_definitions = null; + + + + /** + * The constructor of the signature type definition. It reads the configured + * table definition of the signature block and load the type definition of a + * given type. + * + * @param settings + * a SettingsReader instance + * @param type + * the signature type to load + * @throws SignatureException + * @see SettingsReader + */ + public SignatureTypeDefinition(SettingsReader settings, String type) throws SignatureException + { + settings_ = settings; + type_ = type; + readSigTable(SignatureTypes.MAIN_TABLE); + loadTypeDefinition(); + readFieldDefinitions(); + readInvisibleFieldDefinitions(); + } + + protected void readInvisibleFieldDefinitions() + { + this.invisible_field_definitions = new HashMap(); + for (int i = 0; i < SignatureTypes.REQUIRED_SIG_KEYS.length; i++) + { + String requiredKey = SignatureTypes.REQUIRED_SIG_KEYS[i]; + if (!this.sortedKeys_.contains(requiredKey)) + { + SignatureFieldDefinition sfd = readFieldDefinition(requiredKey); + this.invisible_field_definitions.put(sfd.field_name, sfd); + } + } + } + + /** + * Returns the List of invisible field definitions, if any. + * + *

+ * Invisible field definitions are the field definitions of required fields that are not explicitely specified in the signature profile. + *

+ *

+ * Note that the concept of invisible fields can only be used by binary signatures. + *

+ * + * @return Returns the List of invisible field definitions, if any. + */ + public List getInvisibleFieldDefinitions() + { + return new ArrayList(this.invisible_field_definitions.values()); + } + + /** + * Tells, if the signature type is text-extractable, which means that all required fields are visible. + * + * @return Returns true, if the signature type is text-extractable. + */ + public boolean isTextExtractable() + { + if (logger_.isDebugEnabled()) { + Iterator it = this.invisible_field_definitions.values().iterator(); + StringBuffer buffer = new StringBuffer(); + while (it.hasNext()) { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) it.next(); + buffer.append(sfd.field_name); + if (it.hasNext()) { + buffer.append(", "); + } + } + if (buffer.length() != 0) { + logger_.debug("Invisible field definitions for profile \"" + this.type_ + "\" = " + buffer.toString()); + } + } + return this.invisible_field_definitions.isEmpty(); + } + + /** + * Load the configured signature type definitions. It reads all key-captions + * tupls that are used in the signature table. It also reads all key-value + * tupls. + * + * @throws SignatureException + */ + private void loadTypeDefinition() throws SignatureException + { + if (sortedKeys_ == null) + { + sortKeys(); + } + + String key_prefix = SignatureTypes.SIG_OBJ + type_ + ".key"; + ArrayList keys = settings_.getKeys(key_prefix); + if (keys == null) + { + // exthex: no exception to enable invisible signatures + logger_.debug("There is no key defined for type:" + type_ +". assuming invisible signature"); + return; +// keep this incredible wprinz(?) lines as a puzzle: Can anyone do same thing in just one line? +// SignatureException se = new SignatureException(100, "There is no key defined for type:" + type_); +// ; +// throw se; + } + for (int key_idx = 0; key_idx < keys.size(); key_idx++) + { + String sig_key = (String) keys.get(key_idx); + String sig_key_val = settings_.getValueFromKey(key_prefix + "." + sig_key); + if (sortedKeys_.contains(sig_key)) + { + keyCaptionMap_.put(sig_key, sig_key_val); + } + } + String value_prefix = SignatureTypes.SIG_OBJ + type_ + ".value"; + ArrayList values = settings_.getKeys(value_prefix); + if (values != null) + { + for (int key_idx = 0; key_idx < values.size(); key_idx++) + { + String val_key = (String) values.get(key_idx); + String val_key_val = settings_.getValueFromKey(value_prefix + "." + val_key); + keyValueMap_.put(val_key, val_key_val); + } + } + } + + /** + * This method reads the table definition of singature type. It takes care + * about the linearization of the defined key-value pairs or sub tables. The + * linearisation is done reading a table from left to right and top to bottom. + * A sub table is alwais a normal cell element in the linearisation prozess. + * If a sub table exists therefore the linearisation of the subtable is taken + * es cell element in the parent table. t This method stores a revert sorted + * linearisation list of used keys in the table. This method is called + * recursivley if defined nested tables. + * + * @param tableKey + * the name of the table definition + */ + private void readSigTable(String tableKey) + { + // System.err.println("read table:" + type_ + "." + tableKey); + String table_key_prefix = SignatureTypes.SIG_OBJ + type_ + "." + SignatureTypes.TABLE; + String table_key = table_key_prefix + tableKey; + String key_prefix = SignatureTypes.SIG_OBJ + type_ + ".key."; + + // ArrayList table_def_keys = settings_.getKeys(table_key); + Vector table_def_keys = settings_.getSettingKeys(table_key); + if (table_def_keys != null) + { + for (int table_key_idx = 0; table_key_idx < table_def_keys.size(); table_key_idx++) + { + String table_row_id = (String) table_def_keys.get(table_key_idx); + String table_def_keys_name = table_key + "." + table_row_id; + String table_def_string = settings_.getValueFromKey(table_def_keys_name); + if (table_row_id.matches("\\D*")) + { + continue; + } + if (table_def_string != null) + { + // analyse the row definition + String[] elems = table_def_string.split("\\|"); + // ArrayList row = new ArrayList(); + int elem_idx = elems.length; + while (elem_idx > 0) + { + elem_idx--; + String elem = elems[elem_idx]; + String[] key_type = elem.split("-"); + if (key_type.length < 2) + { + return; + } + String key = key_type[0]; + String type = key_type[1]; + // System.err.println("key:" + type_ + "." + tableKey + + // "." + key + "=" + type); + + if (SignatureTypes.TYPE_TABLE.equals(key)) + { + // read sub table + readSigTable(type); + } + if (SignatureTypes.TYPE_IMAGE.equals(type)) + { + // ignore images + } + if (SignatureTypes.TYPE_VALUE.equals(type)) + { + String sig_key_val = settings_.getValueFromKey(key_prefix + key); + if (sig_key_val != null) + { + revertSortedKeys_.add(key); + revertSortedCaptions_.add(sig_key_val); + } + // ignore values without caption + } + if ((SignatureTypes.TYPE_VALUE + SignatureTypes.TYPE_CAPTION).equals(type) || (SignatureTypes.TYPE_CAPTION + SignatureTypes.TYPE_VALUE).equals(type)) + { + String sig_key_val = settings_.getValueFromKey(key_prefix + key); + if (sig_key_val != null) + { + revertSortedKeys_.add(key); + revertSortedCaptions_.add(sig_key_val); + } + } + } + } + } + } + } + + /** + * @return Returns the keys. + */ + public Map getKeyCaptionMap() + { + return keyCaptionMap_; + } + + /** + * @return Returns the keyValueMap. + */ + public Map getKeyValueMap() + { + return keyValueMap_; + } + + /** + * Returns a caption to a given key + * + * @param key + * @return the caption or null if the key is not found + */ + public String getCaptionFromKey(String key) + { + return (String) keyCaptionMap_.get(key); + } + + /** + * Returns a value to given key + * + * @param key + * @return the value or null if the key is not found + */ + public String getValueFromKey(String key) + { + return (String) keyValueMap_.get(key); + } + + /** + * @return Returns the sortedKeys. + */ + public Vector getSortedKeys() + { + if (sortedKeys_ == null) + { + sortKeys(); + } + return sortedKeys_; + } + + /** + * @return Returns the sortedCaptions. + */ + public Vector getSortedCaptions() + { + if (sortedCaptions_ == null) + { + sortKeys(); + } + return sortedCaptions_; + } + + /** + * @return Returns the revertSortedCaptions. + */ + public Vector getRevertSortedCaptions() + { + return revertSortedCaptions_; + } + + /** + * @return Returns the revertSortedKeys. + */ + public Vector getRevertSortedKeys() + { + return revertSortedKeys_; + } + + /** + * This method sort the reverted sorted key-caption and key-value lists. + * + */ + private void sortKeys() + { + // String key_prefix = SignatureTypes.SIG_OBJ + type_ + ".key."; + sortedKeys_ = new Vector(revertSortedKeys_.size()); + sortedCaptions_ = new Vector(revertSortedCaptions_.size()); + for (int key_idx = revertSortedKeys_.size() - 1; key_idx >= 0; key_idx--) + { + sortedKeys_.add(revertSortedKeys_.get(key_idx)); + sortedCaptions_.add(revertSortedCaptions_.get(key_idx)); + } + } + + /** + * This method checks if a given key is defined. + * + * @param key + * to find + * @return true if the key is find false otherwise + */ + public boolean contains(String key) + { + return (keyValueMap_.get(key) != null); + } + + /** + * The standard toString method. Used for internal tests only. + */ + public String toString() + { + String strg = this.type_ + "\n"; + Vector sk = getSortedKeys(); + Vector sc = getSortedCaptions(); + for (int i = 0; i < sk.size(); i++) + { + strg += sk.get(i) + "=" + sc.get(i) + "\n"; + } + return strg; + } + + /** + * @return Returns the signature type string. + */ + public String getType() + { + return type_; + } + + /** + * @return Returns the signature type description. + */ + public String getDescription() + { + String descr_key = SignatureTypes.SIG_OBJ + type_ + ".description"; + return settings_.getValueFromKey(descr_key); + } + + protected String getSettingsKeyBase() + { + return getSettingsKeyBase(type_); + } + + /** + * Gets the field definition of the given Field. + * + * @param field_name + * The name of the field. + * @return Returns the field's definition. + */ + public SignatureFieldDefinition readFieldDefinition(String field_name) + { + SignatureFieldDefinition sfd = new SignatureFieldDefinition(); + + sfd.field_name = field_name; + sfd.caption = this.settings_.getValueFromKey(getSettingsKeyBase() + ".key." + field_name); + sfd.value = this.settings_.getValueFromKey(getSettingsKeyBase() + ".value." + field_name); + //sfd.value = this.settings_.getValueFromKey(getSettingsKeyBase() + type_ + ".value." + field_name); + sfd.placeholder_length = -1; + String phlen_str = readPhLenStringFromSettings(this.settings_, this.type_, field_name); + if (phlen_str != null) + { + sfd.placeholder_length = Integer.parseInt(phlen_str); + } + + return sfd; + } + + protected static String getSettingsKeyBase (String type) + { + return SignatureTypes.SIG_OBJ + type; + } + + public static String readPhLenStringFromSettings(SettingsReader settings, String profile, String field_name) + { + String phlen_str = settings.getValueFromKey(getSettingsKeyBase(profile) + ".phlength." + field_name); + if (phlen_str == null) + { + phlen_str = settings.getValueFromKey("defaults.phlength." + field_name); + } + return phlen_str; + } + + protected void readFieldDefinitions() + { + this.field_definitions_ = new HashMap(); + for (int i = 0; i < this.sortedKeys_.size(); i++) + { + String key = (String) this.sortedKeys_.get(i); + SignatureFieldDefinition sfd = readFieldDefinition(key); + // sfd.brev = SignatureTypes.ALL_SIG_BREV[i]; + this.field_definitions_.put(sfd.field_name, sfd); + } + } + + /** + * Returns the list of field definitions of this Signature profile. + * + * @return Returns the list of field definitions of this Signature profile. + */ + public List getFieldDefinitions() + { + return new ArrayList(this.field_definitions_.values()); + } + + /** + * Tells if this signature profile is semantically equal to the other + * signature profile. + * + *

+ * One profile is semantically equal to another one if the captions and keys + * of both profiles are equal and have the same order. + *

+ * + * @param other + * The other signature profile. + * @return Returns true, if this profile is semantically equivalent to the + * other profile. + */ + public boolean isSemanticallyEqual(SignatureTypeDefinition other) + { + List this_keys = filterOutNonRequiredFoundKeys(this.sortedKeys_); + List other_keys = filterOutNonRequiredFoundKeys(other.sortedKeys_); + + if (this_keys.size() != other_keys.size()) + { + return false; + } + + for (int i = 0; i < this_keys.size(); i++) + { + String this_key = (String) this_keys.get(i); + String other_key = (String) other_keys.get(i); + + if (!this_key.equals(other_key)) + { + return false; + } + + String this_caption = this.getCaptionFromKey(this_key); + String other_caption = other.getCaptionFromKey(other_key); + + if (!this_caption.equals(other_caption)) + { + return false; + } + } + + return true; + } + + /** + * Filters out all non required keys from the List of keys. + * + * @param keys The List of keys. + * + * @return Returns the subset List which contains only the required keys. + */ + protected static List filterOutNonRequiredFoundKeys (List keys) + { + List required_keys = new ArrayList(keys.size()); + for (int i = 0; i < keys.size(); i++) + { + String this_key = (String) keys.get(i); + + if (!SignatureTypes.isRequiredKey(this_key)) + { + continue; + } + + required_keys.add(this_key); + } + return required_keys; + } + + public SignatureFieldDefinition getSignatureFieldDefinition(String key) { + SignatureFieldDefinition res = (SignatureFieldDefinition) this.field_definitions_.get(key); + if (res == null) { + res = (SignatureFieldDefinition) this.invisible_field_definitions.get(key); + } + return res; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java new file mode 100644 index 0000000..783512c --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureTypes.java @@ -0,0 +1,515 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: SignatureTypes.java,v 1.5 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.exactparser.ByteArrayUtils; + +public class SignatureTypes +{ + +// 03.11.2010 changed by exthex - commented unneeded setDefaultStyles method to reduce confusion + + /** + * The settings key prefix for signature definitions. "sig_obj." + */ + public static final String SIG_OBJ = "sig_obj."; + + /** + * The settings key prefix for signature object types + */ + public static final String TYPES = SIG_OBJ + "types"; + + /** + * The settings key prefix for the default signature object type + */ + public static final String DEFAULT_TYPE = SIG_OBJ + "type.default"; + + /** + * The settings key postfix for the type description + */ + public static final String SIG_DESCR = "description"; + + /** + * The state value activating an signature definition + */ + private static final String STATE_ON = "on"; + + // /** + // * The state value de activating an signature definition + // */ + // private static final String STATE_OFF = "off"; + + /** + * The settings key prefix for the signature table object definition + */ + public static final String TABLE = "table."; + + /** + * The settings key sub prefix getting the main table definition + */ + public static final String MAIN_TABLE = "main"; + + /** + * The settings value refering to a table + */ + public final static String TYPE_TABLE = "TABLE"; + + /** + * The settings value refering to an image + */ + public final static String TYPE_IMAGE = "i"; + + /** + * The settings value refering to a text caption + */ + public final static String TYPE_CAPTION = "c"; + + /** + * The settings value refering to a text value + */ + public final static String TYPE_VALUE = "v"; + + /** + * The settings key sub prefix getting the width of columns for a table + * definition + */ + public final static String COLS_WITH = "ColsWidth"; + + /** + * The settings key sub prefix getting the style definition + */ + public final static String STYLE = "Style"; + +// /** +// * The default style definition for images. +// */ +// private Style defaultImageStyle_ = new Style(); +// +// /** +// * The default style definition for captions. +// */ +// private Style defaultCaptionStyle_ = new Style(); +// +// /** +// * The default style definition for values. +// */ +// private Style defaultValueStyle_ = new Style(); + + /** + * Standard key get/set the singature name + */ + public static final String SIG_NAME = "SIG_NAME"; + + /** + * Standard key get/set the signature date + */ + public static final String SIG_DATE = "SIG_DATE"; + + /** + * Standard key get/set the signator issuer + */ + public static final String SIG_ISSUER = "SIG_ISSUER"; + + /** + * Standard key get/set the siganture value + */ + public static final String SIG_VALUE = "SIG_VALUE"; + + /** + * Standard key get/set the normalisation method used + */ + public static final String SIG_NORM = "SIG_NORM"; + + /** + * Standard key get/set the signation id's used by BKU signated documents + */ + public static final String SIG_ID = "SIG_ID"; + + /** + * The EGIZ Algorithm "Kennzeichnung". + */ + public static final String SIG_KZ = "SIG_KZ"; + + /** + * Standard key get/set the reference to the signature label (image mark) + */ + public static final String SIG_LABEL = "SIG_LABEL"; + + /** + * Standard key get/set the serial number of the signature + */ + public static final String SIG_NUMBER = "SIG_NUMBER"; + + // public static final String SIG_TYPE = "SIG_TYPE"; + /** + * Standard key get/set the signature meta informations + */ + public static final String SIG_META = "SIG_META"; + + /** + * Standard key get/set the signature algorithm (sign + hash) + */ + public static final String SIG_ALG = "SIG_ALG"; + + /** + * Standard key get/set the signature note + * added by rpiazzi + */ + public static final String SIG_NOTE = "SIG_NOTE"; + + + /** + * Standard key get/set the signature subject + * Added to be able to define static signator name within config file + * added by rpiazzi + */ + public static final String SIG_SUBJECT = "SIG_SUBJECT"; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(SignatureTypes.class); + + // /** + // * The normalizer reference + // */ + // private Normalizer normalizer_ = null; + + /** + * The settings reader reference + */ + private SettingsReader settings_ = null; + + + // /** + // * The reference to the settings property tree + // */ + // private PropertyTree pTree_ = null; + + // /** + // * The current signature type used reading and analysing the property tree + // */ + // private String sigType_ = null; + + // /** + // * List of all keys used in the current signature definition + // */ + // private ArrayList sigKeys_ = null; + + /** + * Array of required signature keys + */ + // public static String[] REQUIRED_SIG_KEYS = new String[]{SIG_NAME, SIG_DATE, + // SIG_ISSUER, SIG_VALUE, SIG_NUMBER, SIG_ID}; + public static String[] REQUIRED_SIG_KEYS = new String[] { SIG_DATE, + SIG_ISSUER, SIG_VALUE, SIG_NUMBER, SIG_ID, SIG_KZ }; + + /** + * Tells, if the given key is a required key. + *

+ * Note that the SIG_KZ is a required key. + *

+ * @param key The key to be tested if it is a required key. + * @return Returns true, if the key is required, false otherwise. + */ + public static boolean isRequiredKey (String key) + { + if (key.equals(SIG_KZ)) + { + return true; + } + + for (int i = 0; i < REQUIRED_SIG_KEYS.length; i++) + { + if (key.equals(REQUIRED_SIG_KEYS[i])) + { + return true; + } + } + return false; + } + + public static String[] ALL_SIG_KEYS = new String[] { SIG_NAME, SIG_DATE, + SIG_ISSUER, SIG_VALUE, SIG_NORM, SIG_ID, SIG_LABEL, SIG_NUMBER, SIG_META , SIG_ALG, SIG_NOTE}; + + public static byte [][] ALL_SIG_BREV = new byte[][] { { 'n', 'a', 'm' }, + { 'd', 'a', 't' }, { 'i', 's', 's' }, { 'v', 'a', 'l' }, + { 'n', 'o', 'r' }, { 's', 'i', 'd' }, { 'l', 'a', 'b' }, + { 's', 'n', 'r' }, { 'm', 'e', 't' }, { 'a', 'l', 'g' } }; + + // /** + // * Sorted representation of keys defined in rows + // */ + // private ArrayList sortedSigKeys_ = new ArrayList(); + + // /** + // * Reference from signature key to there corresponding value + // */ + // private Hashtable sigEntries_ = new Hashtable(8); + +// /** +// * A list of all configured signature type definitions +// */ +// private List signatureTypeDefinitions_ = new Vector(); + + /** + * A type-name to type-definition map + */ + private Map typeDefMap_ = new HashMap(); + + // /** + // * A map of required keys used to reconstruct a signature block + // */ + // private static HashMap requiredSigKeys_ = new HashMap(); + + /** + * A plain list of signature type names + */ +// ArrayList typeList_ = new ArrayList(4); + + /** + * Used as singleton to read the singnature type definitions only one times of + * a session + */ + private static SignatureTypes instance_ = null; + + /** + * This is the private constructor method to provide a singleton instance of + * this class. It inits a normalizer, the settings reader, read the default + * styles and load the configured signature types. + * + * @throws SignatureTypesException + * @see SettingsReader + */ + private SignatureTypes() throws SignatureTypesException + { + try + { + loadSettings(); + } + catch (SettingsException e) + { + throw new SignatureTypesException(e); + } +// setDefaultStyles(); + loadSignatureTypes(); + } + + /** + * This static method returns the stored instance of this class. If the + * singleton does not exist, this method creates a new singleton and gives + * this instance back to the caller. + * + * @return the stored instance of this class + * @throws SignatureTypesException + */ + public static SignatureTypes getInstance() throws SignatureTypesException + { + if (instance_ == null) + { + instance_ = new SignatureTypes(); + } + return instance_; + } + + /** + * Reloads the instance. + * @throws SignatureTypesException + */ + public static void createInstance() throws SignatureTypesException + { + instance_ = null; + getInstance(); + } + + /** + * This method load the signature definitions + * + * @throws SettingsException + * + * @throws SettingsException + * ErrorCode:101 + */ + private void loadSettings() throws SettingsException + { + if (settings_ == null) + { + settings_ = SettingsReader.getInstance(); + } + // pTree_ = settings_.getPTree(); + } + +// /** +// * This method set the default styles for images, captions and values. +// */ +// private void setDefaultStyles() +// { +// defaultImageStyle_.setPadding(3); +// defaultImageStyle_.setHAlign(Style.CENTER); +// defaultImageStyle_.setVAlign(Style.MIDDLE); +// defaultImageStyle_.setBgColor(new Color(255, 255, 255)); +// +// defaultCaptionStyle_.setHAlign(Style.CENTER); +// defaultCaptionStyle_.setVAlign(Style.MIDDLE); +// +// defaultValueStyle_.setVAlign(Style.MIDDLE); +// } + + /** + * This method load the configured signature types. It stores the definition + * representations only if the type is set to ON. It stores the type + * definition object, the definition map and the simple type name list. + */ + private void loadSignatureTypes() + { + if (settings_ != null) + { + ArrayList types = settings_.getKeys(TYPES); + for (int type_idx = 0; type_idx < types.size(); type_idx++) + { + String type = (String) types.get(type_idx); + addSignatureType(type); + } + } + } + + public void removeSignatureType(String typeName) { + this.typeDefMap_.remove(typeName); + } + + /** + * Create and add {@link SignatureTypeDefinition} from its name + * @param typeName + */ + public void addSignatureType(String typeName) { + + if (STATE_ON.equals(settings_.getSetting(TYPES + "." + typeName, null))) + { + SignatureTypeDefinition sig_type_def; + try + { + sig_type_def = new SignatureTypeDefinition(settings_, typeName); + //signatureTypeDefinitions_.add(sig_type_def); + typeDefMap_.put(typeName, sig_type_def); + //typeList_.add(type); + } + catch (SignatureException e) + { + logger_.error(e.getMessage(), e); + } + } + } + + /** + * @return a arrayList (String) of signature types names + */ + public Set getSignatureTypes() + { + return this.typeDefMap_.keySet(); + } + + /** + * @return a list of signature type definitions + */ + public List getSignatureTypeDefinitions() + { + return new ArrayList(this.typeDefMap_.values()); + } + + /** + * This method returns the corresponding signature type definition to a given + * type key + * + * @param type + * the key to get the signature type definition + * @return the stored signature type definition + */ + public SignatureTypeDefinition getSignatureTypeDefinition(String type) + { + return (SignatureTypeDefinition) typeDefMap_.get(type); + } + + public static String convertBrevToType (final byte [] brev) + { + for (int i = 0; i < ALL_SIG_BREV.length; i++) + { + if (ByteArrayUtils.compareByteArrays(ALL_SIG_BREV[i], 0, brev)) + { + return ALL_SIG_KEYS[i]; + } + } + return null; + } + + public static byte [] convertTypeToBrev (final String type) + { + for (int i = 0; i < ALL_SIG_KEYS.length; i++) + { + if (ALL_SIG_KEYS.equals(type)) + { + return ALL_SIG_BREV[i]; + } + } + return null; + } + + public static boolean isRequredSigTypeKey(String name) { + return ArrayUtils.contains(REQUIRED_SIG_KEYS, name); + } + + /** + * The standard toString method. Used for testing only. + * + * @return the string representation of the class + */ + public String toString() + { + String strg = ""; + for (Iterator it = this.typeDefMap_.values().iterator(); it.hasNext();) { + SignatureTypeDefinition std = (SignatureTypeDefinition) it.next(); + + strg += "----------TYPE:" + std.getType() + "----------\n"; + strg += std.toString(); + } + return strg; + } + +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java new file mode 100644 index 0000000..7b4e463 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java @@ -0,0 +1,490 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: X509Cert.java,v 1.4 2006/08/25 17:09:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.Serializable; +import java.security.PublicKey; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.List; + +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; + +public class X509Cert implements Serializable +{ + + /** + * SVUID. + */ + private static final long serialVersionUID = 6945327015386694557L; + + /** + * The x509 certificate binary string Base64 coded + */ + private String certString_ = null; + + /** + * The name value of the issuer + */ + private String issuerName_ = null; + + /** + * The serial number of the certificate + */ + private String serialNumber_ = null; + + /** + * The digest value of the certificate + */ + private String certDigest_ = null; + + /** + * The name value of the subject + */ + private String subjectName_ = null; + + /** + * The X509Certificate object + */ + private X509Certificate x509Cert_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(X509Cert.class); + + /** + * The empty constructor not acessible from outside --> use the static init + * methods instead + */ + private X509Cert() + { + } + + /** + * Normalize the base64 coded .cer or .der string. Remove the begin and end + * statement and remove all whitespaces in the string. The result string + * (base64) is used by reconstructing the certiface sign by the verification + * process. + * + * @param certString + * the string to normalize + * @return the normalized cert string + */ + private static String normalizeCertString(String certString) + { + certString = certString.replaceAll("-----BEGIN CERTIFICATE-----", ""); + certString = certString.replaceAll("-----END CERTIFICATE-----", ""); + certString = certString.replaceAll("\\s", ""); + return certString; + } + + /** + * This method initialzes a X509Certificate by a string value. It must be + * coded Base64 or as plain binary stream. + * + * @param certString + * the certificate string to analyse + * @return the X509Cert object + * @see CertificateFactory + * @see X509Certificate + */ + public static X509Cert initByString(String certString) + { + if (certString == null) + { + return null; + } + certString = normalizeCertString(certString); + X509Cert x509_cert = new X509Cert(); + x509_cert.setCertString(certString); + try + { + byte[] b64_dec = certString.getBytes("US-ASCII"); + if (CodingHelper.isB64(b64_dec)) + { + b64_dec = CodingHelper.decodeBase64(b64_dec); + } + else + { + b64_dec = CodingHelper.encodeBase64(b64_dec).getBytes("US-ASCII"); + } + ByteArrayInputStream bais = new ByteArrayInputStream(b64_dec); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); + bais.close(); + x509_cert.setX509Cert(cert); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + issuer = issuer.replaceAll(", ", ","); + String subject_name = cert.getSubjectDN().toString(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) + { + logger_.debug("Serial number from certificate:" + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + subject_name); + } + } + catch (java.security.cert.CertificateException ce) + { + // nothing to do, cause certString is not X509 conformc + logger_.error(ce.getMessage(), ce); + } + catch (IOException ioe) + { + // nothing to do, cause certString is not X509 conform + logger_.error(ioe.getMessage(), ioe); + } + return x509_cert; + } + + public static X509Cert initByX509Certificate(X509Certificate cert) throws CertificateEncodingException { + X509Cert x509_cert = new X509Cert(); + x509_cert.setX509Cert(cert); + x509_cert.setCertString(CodingHelper.encodeBase64(cert.getEncoded())); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + issuer = issuer.replaceAll(", ", ","); + String subject_name = cert.getSubjectDN().toString(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) + { + logger_.debug("Serial number from certificate:" + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + subject_name); + } + return x509_cert; + } + + public static X509Cert initByByteArray(byte[] data) + { + X509Cert x509_cert = new X509Cert(); + try + { + ByteArrayInputStream bais = new ByteArrayInputStream(data); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); + bais.close(); + + x509_cert.setX509Cert(cert); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + issuer = issuer.replaceAll(", ", ","); + String subject_name = cert.getSubjectDN().toString(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) + { + logger_.debug("Serial number from certificate:" + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + subject_name); + } + } + catch (java.security.cert.CertificateException ce) + { + // nothing to do, cause certString is not X509 conformc + logger_.error(ce.getMessage(), ce); + + } + catch (IOException ioe) + { + // nothing to do, cause certString is not X509 conform + logger_.error(ioe.getMessage(), ioe); + } + + return x509_cert; + } + + /** + * This method initialzes a X509Certificate by a file path value. The file + * must be a plain binary file like .cer format. + * + * @param filePath + * the certificate file to analyse + * @return the X509Cert object + * @see CertificateFactory + * @see X509Certificate + */ + public static X509Cert initByFilePath(String filePath) + { + if (filePath == null) + { + return null; + } + X509Cert x509_cert = new X509Cert(); + try + { + FileInputStream fis = new FileInputStream(filePath); + X509Certificate cert = null; + try + { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + cert = (X509Certificate) cf.generateCertificate(fis); + } + catch (java.security.cert.CertificateException ce) + { + fis.close(); + String cert_string = FileHelper.readFromFile(filePath); + return initByString(cert_string); + } + fis.close(); + x509_cert.setX509Cert(cert); + String cert_string = FileHelper.readFromFile(filePath); + x509_cert.setCertString(normalizeCertString(cert_string)); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + issuer = issuer.replaceAll(", ", ","); + String subject_name = cert.getSubjectDN().toString(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) + { + logger_.debug("Serial number from certificate:" + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + subject_name); + } + } + catch (IOException ioe) + { + String cert_string = FileHelper.readFromFile(filePath); + return initByString(cert_string); + } + return x509_cert; + + } + + /** + * This method initialzes a X509Certificate by a file value. The file must be + * a plain binary file like .cer format. + * + * @param certFile + * the certificate file to analyse + * @return the X509Cert object + * @see CertificateFactory + * @see X509Certificate + */ + public static X509Cert initByFile(File certFile) + { + return initByFilePath(certFile.getAbsolutePath()); + } + + /** + * This method checks if a certificate file is X509 conform. + * + * @return true if a certificate file is X509 conform, false otherwise + */ + public boolean isX509Cert() + { + return x509Cert_ != null; + } + + /** + * @return Returns the certificate digest value. + * @deprecated Should not be used any more. + */ + public String getCertDigest() + { + if (certDigest_ == null) + { + if (certString_ != null) + { + byte[] cert_b64 = CodingHelper.decodeBase64(certString_); + String sigAlgName = this.x509Cert_.getSigAlgName(); + String digestAlg = sigAlgName.split("/")[0]; + if (sigAlgName.toLowerCase().indexOf("with") != -1 ) { + digestAlg = sigAlgName.substring(0,sigAlgName.toLowerCase().indexOf("with")); + } + byte[] cert_hash = CodingHelper.buildDigest(cert_b64, digestAlg); + certDigest_ = new String(CodingHelper.encodeBase64(cert_hash)); + } + } + return certDigest_; + } + + /** + * @return Returns the certificate Base64 binary string. + */ + public String getCertString() + { + return certString_; + } + + /** + * @return Returns the issuer string. + */ + public String getIssuerName() + { + return issuerName_; + } + + /** + * @return Returns the serial number. + */ + public String getSerialNumber() + { + return serialNumber_; + } + + /** + * @return Returns the real X509Certifcate object. + * @see X509Certificate + */ + public X509Certificate getX509Certificate() + { + return x509Cert_; + } + + /** + * @return Returns the subject name. + */ + public String getSubjectName() + { + return subjectName_; + } + + // /** + // * @param certDigest + // * The certDigest to set. + // */ + // private void setCertDigest(String certDigest) + // { + // certDigest_ = certDigest; + // } + + /** + * @param certString + * The certString to set. + */ + private void setCertString(String certString) + { + certString_ = certString; + } + + /** + * @param issuerString + * The issuerString to set. + */ + private void setIssuerName(String issuerString) + { + issuerName_ = issuerString; + } + + /** + * @param serialNumber + * The serialNumber to set. + */ + private void setSerialNumber(String serialNumber) + { + serialNumber_ = serialNumber; + } + + /** + * @param cert + * The x509Cert to set. + */ + private void setX509Cert(X509Certificate cert) + { + x509Cert_ = cert; + } + + /** + * @param subjectName + * The subjectName to set. + */ + private void setSubjectName(String subjectName) + { + subjectName_ = subjectName; + } + + public byte[] getTBSCertificate() throws CertificateEncodingException + { + return x509Cert_.getTBSCertificate(); + } + + public String getSigAlgName() + { + return x509Cert_.getSigAlgName(); + } + + public String getSigAlgOID() + { + return x509Cert_.getSigAlgOID(); + } + + public List getExtendedKeyUsage() + { + List list = null; + try + { + list = x509Cert_.getExtendedKeyUsage(); + } + catch (CertificateParsingException e) + { + logger_.error(e.getMessage(), e); + } + return null; + } + + /** + * @return the public key of the X509Certificate + */ + public PublicKey getPublicKey() + { + return x509Cert_.getPublicKey(); + } + + /** + * This method checks, if a X509Certificate has a public key with the rsa + * algorithm. + * + * @return true if the public key is produced with rsa, false otherwise + */ + public boolean isRSA() + { + return (x509Cert_.getPublicKey().getAlgorithm()).indexOf("RSA") >= 0; + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/A1Connector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/A1Connector.java new file mode 100644 index 0000000..aab8e6b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/A1Connector.java @@ -0,0 +1,63 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: A1Connector.java,v 1.2 2006/08/25 17:09:17 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; + +/** + * @author wprinz + */ +public class A1Connector extends BKUConnector +{ + /** + * ConnectorInformation that identifies this Connector to the system. + * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory + * @see ConnectorInformation + */ + public static final ConnectorInformation CONNECTOR_INFORMATION = new ConnectorInformation("a1", "A-1"); + + /** + * Constructor. + * + * @throws SignatureException + * F.e. + */ + public A1Connector() throws SignatureException + { + super(); + } + + /** + * Overrides the type of the BKUConnector to use the A1 settings. + */ + protected String getType() + { + return CONNECTOR_INFORMATION.getIdentifier(); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java new file mode 100644 index 0000000..c3b6421 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUConnector.java @@ -0,0 +1,896 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: BKUConnector.java,v 1.5 2006/10/31 08:18:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import java.io.UnsupportedEncodingException; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.external.ExternalErrorException; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; +import at.knowcenter.wag.egov.egiz.sig.LocalConnector; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Connector for communicating with BKU. + * + * @deprecated use the new connectors. + * + * @author wlackner + * @author wprinz + */ +public class BKUConnector implements LocalConnector +{ + /** + * ConnectorInformation that identifies this Connector to the system. + * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory + * @see ConnectorInformation + */ + public static final ConnectorInformation CONNECTOR_INFORMATION = new ConnectorInformation("bku", "BKU"); + + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(BKUConnector.class); + + /** + * The empty constructor + */ + public BKUConnector() //throws SignatureException + { + //loadSettings(); + } + + /** + * load the inital signature settings + * + * @see SettingsReader + */ + public void loadSettings() throws SignatureException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new SignatureException(101, log_message, e); + } + } + } + + /** + * This method calls the BKU signing a given text. The signaton type is to + * used initializing the corresponding SigantureObject. The initialized + * SignatureObject is filled out by the parsed BKU-Response.
+ * If an error request is send back from BKU, an error message is generated an + * an exception is thrown. + * + * @param sigType + * the type of the SignatureObject that should be returned + * @param userName + * the name of the user calling this method + * @param signText + * the text that shoulf be signed from BKU + * @return the complete SingatureObject of the given type filled by values + * from the BKU-Request + * @throws SignatureException + * @see SignatureObject + */ + public SignatureObject doSign(String sigType, String userName, String signText) throws SignatureException + { + String request_string = prepareSignRequest(userName, signText, sigType); + + String sign_url = getSignURL(sigType); + Properties response_properties = sendRequest(sign_url, request_string); + + return analyzeSignResponse(response_properties, sigType); + } + + /** + * This method generates the BKU verify prozess. It checks if the given + * SignatureObject is signed by MOA or BKU. The verify template string is + * filled out by the corresponding method. + * + * @param normalizedText + * the normalized text to verify + * @param sigObject + * the SignatureObject holding the singature values + * @return a SignatureResponse object if the verify prozess does not fails + * @throws SignatureException + * @see SignatureResponse + */ + public SignatureResponse doVerify(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + String request_string = prepareVerifyRequest(normalizedText, sigObject); + + String verify_url = getVerifyURL(sigObject.getSignationType()); + Properties response_properties = sendRequest(verify_url, request_string); + + return analyzeVerifyResponse(response_properties); + } + + /** + * This method parses the BKU-Response string. It separates the + * SignatureValue, X509IssuerName, SigningTime, X509SerialNumber, + * X509Certificate, CertDigest, DigestValue and the signation id-s. If the + * X509Certificate is extracted it would be stored in the certificates + * directory. + * + * @param xmlResponse + * the response string from the BKU sign-request + * @param sigObj + * the SignatureObject that should be filled + * @throws SignatureException + * ErrorCode (303, 304) + * @see SignatureObject + * @see CodingHelper + * @see X509Cert + */ + private void parseCreateXMLResponse(Properties response_properties, SignatureObject sigObj) throws SignatureException + { + String xmlResponse = response_properties.getProperty("response_string"); + + Pattern sig_val_p_s = Pattern.compile("<[\\w]*:?SignatureValue>"); + Pattern sig_val_p_e = Pattern.compile(""); + Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName>"); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern sig_tim_p_s = Pattern.compile("<[\\w]*:?SigningTime>"); + Pattern sig_tim_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile("<[\\w]*:?X509SerialNumber>"); + Pattern ser_num_p_e = Pattern.compile(""); + Pattern sig_cer_p_s = Pattern.compile("<[\\w]*:?X509Certificate>"); + Pattern sig_cer_p_e = Pattern.compile(""); + + Pattern sig_cer_d_p_s = Pattern.compile("<[\\w]*:?CertDigest>"); + Pattern sig_cer_d_p_e = Pattern.compile(""); + Pattern dig_val_p_s = Pattern.compile("<[\\w]*:?DigestValue>"); + Pattern dig_val_p_e = Pattern.compile(""); + + Matcher sig_val_m_s = sig_val_p_s.matcher(xmlResponse); + Matcher sig_val_m_e = sig_val_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher sig_tim_m_s = sig_tim_p_s.matcher(xmlResponse); + Matcher sig_tim_m_e = sig_tim_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + Matcher sig_cer_m_s = sig_cer_p_s.matcher(xmlResponse); + Matcher sig_cer_m_e = sig_cer_p_e.matcher(xmlResponse); + + Matcher sig_cer_d_m_s = sig_cer_d_p_s.matcher(xmlResponse); + Matcher sig_cer_d_m_e = sig_cer_d_p_e.matcher(xmlResponse); + + String sig_val = ""; + String iss_nam = ""; + String ser_num = ""; + String sig_tim = ""; + String sig_cer = ""; + String sig_dig = ""; + + // SignatureValue + if (sig_val_m_s.find() && sig_val_m_e.find()) + { + sig_val = xmlResponse.substring(sig_val_m_s.end(), sig_val_m_e.start()); + sig_val = sig_val.replaceAll("\\s", ""); + sigObj.setSignationValue(sig_val); + } + // X509IssuerName + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sigObj.setSignationIssuer(iss_nam); + } + // X509SerialNumber + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sigObj.setSignationSerialNumber(ser_num); + } + // SigningTime + if (sig_tim_m_s.find() && sig_tim_m_e.find()) + { + sig_tim = xmlResponse.substring(sig_tim_m_s.end(), sig_tim_m_e.start()); + sigObj.setSignationDate(sig_tim); + } + // CertDigest + if (sig_cer_d_m_s.find() && sig_cer_d_m_e.find()) + { + String cert_digest = xmlResponse.substring(sig_cer_d_m_s.end(), sig_cer_d_m_e.start()); + Matcher dig_val_m_s = dig_val_p_s.matcher(cert_digest); + Matcher dig_val_m_e = dig_val_p_e.matcher(cert_digest); + if (dig_val_m_s.find() && dig_val_m_e.find()) + { + sig_dig = cert_digest.substring(dig_val_m_s.end(), dig_val_m_e.start()); + sigObj.setX509CertificateDigest(sig_dig); + } + } + // extract Subject Name from X509Certificate + if (sig_cer_m_s.find() && sig_cer_m_e.find()) + { + sig_cer = xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start()); + sig_cer = sig_cer.replaceAll("\\s", ""); + sigObj.setX509Certificate(sig_cer); + X509Cert cert = X509Cert.initByString(sig_cer); + if (cert.isX509Cert()) + { + sigObj.setX509Certificate(cert.getCertString()); + String serial_num = cert.getSerialNumber(); + String subject_name = cert.getSubjectName(); + if (!ser_num.equals(serial_num)) + { + SignatureException se = new SignatureException(303, "Serialnumber of certificate and tag X509SerialNumber differs!"); + throw se; + } + sigObj.setSignationName(subject_name); + } + } + + // extract Signature Id's + String[] ids = new String[5]; + ids[0] = extractId(xmlResponse, "signature-"); + ids[1] = extractId(xmlResponse, "signed-data-reference-"); + ids[2] = extractId(xmlResponse, "signed-data-object-"); + ids[3] = extractId(xmlResponse, "etsi-data-reference-"); + ids[4] = extractId(xmlResponse, "etsi-data-object-"); + + //TODO hotfix - already deprecated + String final_ids =SignatureObject.formatSigIds(response_properties, ids); + //sigObj.setSignationIDs(ids); + sigObj.setSignationIDs(final_ids); + } + + /** + * This emthod extracts id-values from a text. The id is given by the name. + * + * @param text + * the id-value that should extract from + * @param name + * the id-key + * @return the value of the given key in the text + */ + private String extractId(String text, String name) + { + String id = null; + int start_idx = text.indexOf(name) + name.length(); + int end_idx = text.indexOf("\"", start_idx); + + // TODO hotfix! - already deprecated + final int quot_end_idx = end_idx; + final int squot_end_idx = text.indexOf("'", start_idx); + end_idx = Math.min(quot_end_idx, squot_end_idx); + // TODO hotfix end! - already deprecated + + id = text.substring(start_idx, end_idx); + if (logger_.isDebugEnabled()) + { + logger_.debug("extract id:" + name + id); + } + return id; + } + + /** + * This method reads the verify template from the file system and fills out + * the template with the SignatureObject values. + * + * @param normalizedText + * the normalized text to veryfied + * @param sigObject + * the SignatureObject holding the singature values + * @return the filled verify template string + * @throws SignatureException + * ErrorCode (311, 312, 313) + * @see SignatureObject + * @see CodingHelper + */ + public String getVerifyTemplate(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + try + { + if (normalizedText == null || normalizedText.length() == 0) + { + SignatureException se = new SignatureException(311, "Document can not be verified because normalized text is empty."); + throw se; + } + if (sigObject == null) + { + SignatureException se = new SignatureException(312, "Document can not be verified because no signature object are set."); + throw se; + } + + String verify_template = getVerifyTemplateFileName(sigObject.getSignationType()); + String sig_prop_filename = getSigPropFileName(sigObject.getSignationType()); + + String ids_string = sigObject.getSignationIds(); + logger_.debug("ids_string = " + ids_string); + String[] ids = SignatureObject.parseSigIds(ids_string); + + // TODO hotfix - already deprecated + final boolean neue_bku = ids[5] != null; + logger_.debug("ids[5] = " + ids[5]); + logger_.debug("neue_bku = " + neue_bku); + if (neue_bku) + { + verify_template = getConnectorValueFromProfile(sigObject.getSignationType(), "bku.verify.template2"); //"./templates/BKUVerifyTemplateB64_neueBKU.xml"; + sig_prop_filename = getConnectorValueFromProfile(sigObject.getSignationType(), "bku.verify.template2.SP"); //"./templates/BKUVerifyTemplateSP_neueBKU.xml"; + } + + + //String ver_temp_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_template)); + String ver_temp_str = this.settings_.readInternalResourceAsString(verify_template); + //String sig_prop_str = FileHelper.readFromFile(SettingsReader.relocateFile(sig_prop_filename)); + String sig_prop_str = this.settings_.readInternalResourceAsString(sig_prop_filename); + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_template); + logger_.debug(sig_prop_filename); + } + + String x509_cert_string = sigObject.getX509CertificateString(); + if (x509_cert_string == null) + { + SignatureException se = new SignatureException(ErrorCode.CERTIFICATE_NOT_FOUND, "Document certificate is not defined."); + throw se; + } + String cert_alg = settings_.getValueFromKey("cert.alg.ecdsa"); + X509Cert x509_cert = sigObject.getX509Cert(); + if (x509_cert.isRSA()) + { + cert_alg = settings_.getValueFromKey("cert.alg.rsa"); + } + + sig_prop_str = sig_prop_str.replaceFirst("SigningTimeReplace", sigObject.getSignationDate()); + + String issuer_name = sigObject.getSignationIssuer(); + // The issuer is already unicode, so it mustn't be encoded again. + //byte[] issuer_name = CodingHelper.encodeUTF8(sigObject.getSignationIssuer()); + // new String(issuer_name); // this would double encode the String, not to mention the missing encoding + sig_prop_str = sig_prop_str.replaceFirst("X509IssuerNameReplace", issuer_name); + + sig_prop_str = sig_prop_str.replaceFirst("X509SerialNumberReplace", sigObject.getSignationSerialNumber()); + sig_prop_str = sig_prop_str.replaceFirst("DigestValueX509CertificateReplace", sigObject.getX509CertificateDigest()); + sig_prop_str = sig_prop_str.replaceFirst("SigIdReplace", ids[0]); + sig_prop_str = sig_prop_str.replaceFirst("SigDataRefReplace", ids[1]); + + ver_temp_str = ver_temp_str.replaceFirst("CertAlgReplace", cert_alg); + ver_temp_str = ver_temp_str.replaceFirst("TemplateQualifyingPropertiesReplace", sig_prop_str); + byte[] sig_prop_code = CodingHelper.buildDigest(sig_prop_str.getBytes("UTF-8"), "sha1"); + + // TODO hotfix - already deprecated + if (neue_bku) + { + final String ETSI_SIGNED_PROPERTIES_START_TAG = "= 0; + final int hash_end = sig_prop_str.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = sig_prop_str.substring(hash_start, hash_end); + logger_.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed); + + logger_.debug("\n--------------------- ETSI properties string to be hashed: start ---------------------"); + logger_.debug(string_to_be_hashed); + logger_.debug("\n--------------------- ETSI properties string to be hashed: stop ---------------------"); + + final byte [] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); + sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, "sha1"); + } + + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + ver_temp_str = ver_temp_str.replaceFirst("DigestValueSignedPropertiesReplace", sig_prop_hash); + if (logger_.isDebugEnabled()) + { + logger_.debug("build digest from QualifyingProperties:start"); + //logger_.debug("DATA :" + sig_prop_str); + logger_.debug("DIGEST:" + sig_prop_hash); + logger_.debug("build digest from QualifyingProperties:end"); + } + + ver_temp_str = ver_temp_str.replaceFirst("SignatureValueReplace", sigObject.getSignationValue()); + ver_temp_str = ver_temp_str.replaceFirst("X509CertificateReplace", x509_cert_string); + byte[] data_value = normalizedText.getBytes("UTF-8"); + byte[] data_value_hash = CodingHelper.buildDigest(data_value, "sha1"); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + // String object_data = new String(data_value); + if (logger_.isDebugEnabled()) + { + logger_.debug("build digest from data object:start"); + //logger_.debug("DATA :" + normalizedText); + logger_.debug("DIGEST:" + object_data_hash); + logger_.debug("build digest from data object:end"); + } + + //String raw_b64 = CodingHelper.encodeUTF8AsBase64(normalizedText); + String raw_b64 = CodingHelper.encodeBase64(data_value); + + ver_temp_str = ver_temp_str.replaceFirst("Base64ContentReplace", raw_b64); + ver_temp_str = ver_temp_str.replaceFirst("DigestValueSignedDataReplace", object_data_hash); + + ver_temp_str = ver_temp_str.replaceAll("SigIdReplace", ids[0]); + ver_temp_str = ver_temp_str.replaceAll("SigDataRefReplace", ids[1]); + ver_temp_str = ver_temp_str.replaceAll("SigDataObjURIReplace", ids[2]); + ver_temp_str = ver_temp_str.replaceAll("EtsiDataRefReplace", ids[3]); + ver_temp_str = ver_temp_str.replaceAll("EtsiDataObjURIReplace", ids[4]); + if (logger_.isDebugEnabled()) + { + //logger_.debug("VERIFY REQUEST:" + ver_temp_str); + } + + return ver_temp_str; + } + catch (UnsupportedEncodingException e) + { + throw new SignatureException(310, e); + } + } + + /** + * This method parses the verify response string and return a + * SignatureResponse object. The SignatureResponse object is filled out by the + * response values from the BKU-response. + * + * @param xmlResponse + * the response values from the BKU-verify request + * @return SignatureResponse object + * @see SignatureResponse + */ + private SignatureResponse parseVerifyXMLResponse(String xmlResponse) + { + if (logger_.isInfoEnabled()) + { + logger_.info("Try parsing the verify response"); + } + + Pattern sub_nam_p_s = Pattern.compile(""); + Pattern sub_nam_p_e = Pattern.compile(""); + Pattern iss_nam_p_s = Pattern.compile(""); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile(""); + Pattern ser_num_p_e = Pattern.compile(""); + + Pattern sig_chk_p_s = Pattern.compile(""); + Pattern sig_chk_p_e = Pattern.compile(""); + Pattern man_chk_p_s = Pattern.compile(""); + Pattern man_chk_p_e = Pattern.compile(""); + Pattern cer_chk_p_s = Pattern.compile(""); + Pattern cer_chk_p_e = Pattern.compile(""); + + // [tknall] start qualified certificate + Pattern cert_qualified_p = Pattern.compile(""); + Matcher cert_qualified_m = cert_qualified_p.matcher(xmlResponse); + // [tknall] stop qualified certificate + + Pattern code_p_s = Pattern.compile(""); + Pattern code_p_e = Pattern.compile(""); + Pattern info_p_s = Pattern.compile(""); + Pattern info_p_e = Pattern.compile(""); + + Pattern cert_p_s = Pattern.compile(""); + Pattern cert_p_e = Pattern.compile(""); + + Matcher sub_nam_m_s = sub_nam_p_s.matcher(xmlResponse); + Matcher sub_nam_m_e = sub_nam_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + + Matcher sig_chk_m_s = sig_chk_p_s.matcher(xmlResponse); + Matcher sig_chk_m_e = sig_chk_p_e.matcher(xmlResponse); + Matcher man_chk_m_s = man_chk_p_s.matcher(xmlResponse); + Matcher man_chk_m_e = man_chk_p_e.matcher(xmlResponse); + Matcher cer_chk_m_s = cer_chk_p_s.matcher(xmlResponse); + Matcher cer_chk_m_e = cer_chk_p_e.matcher(xmlResponse); + + Matcher cert_m_s = cert_p_s.matcher(xmlResponse); + Matcher cert_m_e = cert_p_e.matcher(xmlResponse); + + SignatureResponse sig_res = new SignatureResponse(); + + // [tknall] start qualified certificate + sig_res.setQualifiedCertificate(cert_qualified_m.find()); + // [tknall] stop qualified certificate + + if (sub_nam_m_s.find() && sub_nam_m_e.find()) + { + String sub_nam = xmlResponse.substring(sub_nam_m_s.end(), sub_nam_m_e.start()); + sig_res.setX509SubjectName(sub_nam); + } + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + String iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sig_res.setX509IssuerName(iss_nam); + } + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + String ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sig_res.setX509SerialNumber(ser_num); + } + if (sig_chk_m_s.find() && sig_chk_m_e.find()) + { + String sig_chk = xmlResponse.substring(sig_chk_m_s.end(), sig_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(sig_chk); + Matcher code_m_e = code_p_e.matcher(sig_chk); + Matcher info_m_s = info_p_s.matcher(sig_chk); + Matcher info_m_e = info_p_e.matcher(sig_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = sig_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = sig_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setSignatureCheckInfo(info); + } + } + if (man_chk_m_s.find() && man_chk_m_e.find()) + { + String man_chk = xmlResponse.substring(man_chk_m_s.end(), man_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(man_chk); + Matcher code_m_e = code_p_e.matcher(man_chk); + Matcher info_m_s = info_p_s.matcher(man_chk); + Matcher info_m_e = info_p_e.matcher(man_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = man_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureManifestCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = man_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setSignatureManifestCheckInfo(info); + } + } + if (cer_chk_m_s.find() && cer_chk_m_e.find()) + { + String cer_chk = xmlResponse.substring(cer_chk_m_s.end(), cer_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(cer_chk); + Matcher code_m_e = code_p_e.matcher(cer_chk); + Matcher info_m_s = info_p_s.matcher(cer_chk); + Matcher info_m_e = info_p_e.matcher(cer_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = cer_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setCertificateCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = cer_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setCertificateCheckInfo(info); + } + } + if (cert_m_s.find() && cert_m_e.find()) + { + String cert_string = xmlResponse.substring(cert_m_s.end(), cert_m_e.start()); + + X509Cert resp_cert = X509Cert.initByString(cert_string); + sig_res.setCertificate(resp_cert); + } + + return sig_res; + } + + + + public String prepareSignRequest(String userName, String signText, + String signType) throws SignatureException + { + if (logger_.isInfoEnabled()) + { + logger_.info("Call " + getType() + " connector from user:" + userName); + } + String keybox_identifier = getSignKeyboxIdentifier(signType); + String sign_request_filename = getSignRequestTemplateFileName(signType); + + //String sign_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + String sign_req_str = this.settings_.readInternalResourceAsString(sign_request_filename); + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + if (logger_.isDebugEnabled()) + { + //logger_.debug(sign_request_filename + "_signText.xml :" + signText); + } + String raw_b64 = CodingHelper.encodeUTF8AsBase64(signText); + if (sign_req_str == null || raw_b64 == null) + { + throw new SignatureException(300, "Can not read the create xml request template"); + } + sign_req_str = sign_req_str.replaceFirst("KeyboxIdentifierReplace", keybox_identifier); + sign_req_str = sign_req_str.replaceFirst("Base64ContentReplace", raw_b64); + if (logger_.isDebugEnabled()) + { + //logger_.debug(sign_request_filename + "_request.xml :"+ sign_req_str); + } + + return sign_req_str; + } + + public String prepareVerifyRequest(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + String verify_request = getVerifyRequestTemplateFileName(sigObject.getSignationType()); + + //String verify_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request)); + String verify_req_str = this.settings_.readInternalResourceAsString(verify_request); + + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_request); + } + + String verify_template_str = null; + if (sigObject.isMOASigned()) + { + MOAConnector moa_conn = new MOAConnector(); + // get the MOA-template + verify_template_str = moa_conn.getVerifyTemplate(normalizedText, sigObject); + } + else + { + // get the BKU-template + verify_template_str = getVerifyTemplate(normalizedText, sigObject); + } + verify_req_str = verify_req_str.replaceFirst("XMLContentReplace", verify_template_str); + if (logger_.isDebugEnabled()) + { + logger_.debug("verify_req_str.xml : " + verify_req_str); + } + + return verify_req_str; + } + + /** + * Sends the request to the given URL. + * + * @param url + * The URL. + * @param request_string + * The request string. + * @return Returns the response string. + * @throws SignatureException + * F.e. + */ + protected Properties sendRequest(String url, String request_string) throws SignatureException + { + try + { + Properties response_properties = BKUPostConnection.doPostRequest(url, request_string); + return response_properties; + } + catch (Exception e) + { + SignatureException se = new SignatureException(320, e); + throw se; + } + } + + public SignatureObject analyzeSignResponse(Properties response_properties, + String sigType) throws SignatureException + { + //String sign_request_filename = getSignRequestTemplateFileName(sigType); + + // TODO hotfix - already deprecated + String response_string = response_properties.getProperty("response_string"); + + SignatureObject sig_obj = new SignatureObject(); + sig_obj.setRawSignatureResponse(response_string); + try + { + sig_obj.setSigType(sigType); + sig_obj.initByType(); + } + catch (SignatureTypesException e) + { + SignatureException se = new SignatureException(300, "Cannot init signature object with type:" + sigType, e); + throw se; + } + if (logger_.isDebugEnabled()) + { + logger_.debug("Signature Type is:" + sig_obj.getSignationType()); + } + + if (!response_string.equals("")) + { + Pattern erc_p_s = Pattern.compile("<[\\w]*:?ErrorCode>"); + Pattern erc_p_e = Pattern.compile(""); + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + // System.err.println(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + //logger_.debug(sign_request_filename + "_response.xml : " + response_string); + logger_.error("BKU Error response: " + response_string); + } + Pattern erm_p_s = Pattern.compile("<[\\w]*:?Info>"); + Pattern erm_p_e = Pattern.compile(""); + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + String error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + String error_mess = null; + if (erm_m_s.find() && erm_m_e.find()) + { + error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + } + throw new SignatureException(new ExternalErrorException(error_code, error_mess)); + } + else + { + if (logger_.isDebugEnabled()) + { + logger_.debug("signature_response_string: " + response_string); + } + parseCreateXMLResponse(response_properties, sig_obj); + } + } + sig_obj.setSigResponse(response_string); + return sig_obj; + } + + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws SignatureException + { + String response_string = response_properties.getProperty("response_string"); + + if (!response_string.equals("")) + { + Pattern erc_p_s = Pattern.compile("<[\\w]*:?ErrorCode>"); + Pattern erc_p_e = Pattern.compile(""); + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + //logger_.debug(getType() + "_response.xml : " + response_string); + logger_.error(getType() + "_response.xml : " + response_string); + } + Pattern erm_p_s = Pattern.compile("<[\\w]*:?Info>"); + Pattern erm_p_e = Pattern.compile(""); + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + String error_code = null; + if (erc_m_s.find() && erc_m_e.find()) + { + error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + } + String error_mess = null; + if (erm_m_s.find() && erm_m_e.find()) + { + error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + } + throw new SignatureException(new ExternalErrorException(error_code, error_mess)); + } + else + { + if (logger_.isDebugEnabled()) + { + //logger_.debug(getType() + "_response.xml : " + response_string); + } + return parseVerifyXMLResponse(response_string); + } + } + return null; + } + + protected String getConnectorValueFromProfile(String profile, String key) + { + String value = settings_.getValueFromKey("sig_obj." + profile + "." + key); + if (value == null) + { + value = settings_.getValueFromKey(key); + } + return value; + } + + public String getSignURL(String profile) + { + final String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".url"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSignRequestTemplateFileName(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".request"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSignKeyboxIdentifier(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".KeyboxIdentifier"; + return getConnectorValueFromProfile(profile, key); + } + + public String getVerifyURL(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".url"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyRequestTemplateFileName(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".request"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyTemplateFileName(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".template"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSigPropFileName(String profile) + { + String key = getType() + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".template.SP"; + return getConnectorValueFromProfile(profile, key); + } + + /** + * Returns the type of this BKU-like connector. + * + *

+ * All settings keys will be prefixed by this type. So to reuse the BKU + * connector, a deriving class has to implement this method specifying an own + * type. + *

+ * + * @return Returns the type of this BKU-like connector. + */ + protected String getType() + { + return CONNECTOR_INFORMATION.getIdentifier(); + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java new file mode 100644 index 0000000..b676ed8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/BKUPostConnection.java @@ -0,0 +1,157 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: BKUPostConnection.java,v 1.3 2006/10/11 07:56:10 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import java.io.IOException; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.NameValuePair; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; + +/** + * @author wprinz + */ +public abstract class BKUPostConnection +{ + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(BKUPostConnection.class); + + /** + * This method connects the BKU server getting the request and the url. The + * request is an XML Message send and recieve by the HttpClient module. The + * Response message of the BKU server is is send back to the calling method. + * + * @param url + * the URL which the BKU server is running + * @param request + * the request string (XML) to send. + * @return the response string (XML) of the BKU server + * @throws IOException + * @throws HttpException + * ErrorCode:320 + */ + public static Properties doPostRequest(String url, String request) throws HttpException, IOException + { + + PostMethod post_method = new PostMethod(url); + + // It is very important to specify the charset of the content (the request) + // as UTF-8 this way. + // The HttpClient will then perform the URL encoding assuming that the + // request is UTF-8 as the BKU expects. + // If the MethodParams are omitted, the HttpClient will assume that the + // request is ISO-8859-1 and thereby the BKU cannot properly decode it. + HttpMethodParams method_params = new HttpMethodParams(); + method_params.setContentCharset("UTF-8"); + post_method.setParams(method_params); + + // This is just a hint: do not set the content-type this way or the BKU will + // assume it as text/XML, but the HttpClient sends it as URL-encoded. + // The HttpClient will automatically generate the proper Content-Type: + // application/x-www-form-urlencoded + // post.addRequestHeader(new Header("Content-Type", + // "text/xml;charset=UTF-8")); + + NameValuePair[] data = { new NameValuePair("XMLRequest", request) }; + post_method.setRequestBody(data); + + HttpClient http_client = new HttpClient(); + int method_response = http_client.executeMethod(post_method); + logger_.debug("method_response = " + method_response); + + Properties response_properties = new Properties(); + + if (logger_.isDebugEnabled()) + { + Header[] response_headers = post_method.getResponseHeaders(); + logger_.debug("#" + response_headers.length + " headers in response:"); + for (int i = 0; i < response_headers.length; i++) + { + logger_.debug(" response_header[" + i + "]: name = " + response_headers[i].getName() + ", value = " + response_headers[i].getValue()); + } + } + + Header server_header = post_method.getResponseHeader("Server"); + logger_.debug("server_header: name = " + server_header.getName() + ", value = " + server_header.getValue()); + + parseBKUVersion(server_header.getValue(), response_properties); + + + byte[] response_body = post_method.getResponseBody(); + String response_string = new String(response_body, "UTF-8"); + + // Alternatively this could be used. + // The HttpClient is assumed to use the Content-Type provided by the + // response. + // String response_string = post.getResponseBodyAsString(); + + response_properties.setProperty("response_string", response_string); + + return response_properties; + } + + // TODO hotfix + public static void parseBKUVersion(String header_value, Properties properties) + { + // dummy bku header starts with Apache Coyote... + //Pattern pattern = Pattern.compile("^citizen-card-environment/(\\d+\\.\\d+) (.+)/(\\d+\\.\\d+\\.\\d+)$"); + //Pattern pattern = Pattern.compile("^.*citizen-card-environment/(\\d+\\.\\d+) (.+)/(\\d+\\.\\d+\\.\\d+)$"); + Pattern pattern = Pattern.compile("^.*citizen-card-environment/(\\d+\\.\\d+) (.+)/(\\d+\\.\\d+\\.\\d+)(.*)$"); + Matcher m = pattern.matcher(header_value); + + m.matches(); + + logger_.debug("group count = " + m.groupCount()); + + for (int i = 0; i <= m.groupCount(); i++) + { + logger_.debug(" group[" + i + "] = " + m.group(i)); + } + + final String cceVersion = m.group(1); + final String productName = m.group(2); + final String productVersion = m.group(3); + + logger_.debug("cceVersion = " + cceVersion); + logger_.debug("productName = " + productName); + logger_.debug("productVersion = " + productVersion); + + properties.setProperty("cceVersion", cceVersion); + properties.setProperty("productName", productName); + properties.setProperty("productVersion", productVersion); + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/Connector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/Connector.java new file mode 100644 index 0000000..24dd728 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/Connector.java @@ -0,0 +1,77 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors; + +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; + +/** + * @author wprinz + * + */ +public interface Connector +{ +//23.11.2010 changed by exthex - added reconstructXMLDsig(SignatureData data, SignSignatureObject so) + + /** + * Performs a sign. + * + * @param data + * The data to be signed. + * @return Returns the signature object containing the signature data. + * @throws ConnectorException + * Thrown if something goes wrong. + */ + + public SignSignatureObject doSign(SignatureData data) throws ConnectorException; + + /** + * Performs a verification. + * + * @param data + * The data to be verified. + * @param so + * The signature object with the signature information. + * @param dsig + * The xmldsig info which will be enveloped in the verify request. + * @return Returns the SignatureResponse with the result of the verification. + * @throws ConnectorException + * Thrown if something goes wrong. + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException; + + /** + * Reconstruct the xmldsig info of the given {@link SignSignatureObject} + * + * @param data + * @param so + * @return + * @throws ConnectorException + */ + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorChooser.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorChooser.java new file mode 100644 index 0000000..2fee4da --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorChooser.java @@ -0,0 +1,353 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.EnvelopedBase64BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.LocRefDetachedBKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.MultipartDetachedBKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.OldEnvelopingBase64BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.EnvelopingBase64MOAConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.MOASoapWithAttachmentConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.LocRefDetachedMOCCAConnector; +import at.knowcenter.wag.egov.egiz.sig.sigid.HotfixIdFormatter; + +/** + * Helper class that provides static methods that help the application to + * "choose" the right connector for a given task. + * + * @deprecated functionality split to ConnectorChooser implementations in framework commandline and web + * + * @author wprinz + */ +public final class ConnectorChooser +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(ConnectorChooser.class); + + public static LocalConnector chooseLocalConnectorForSign(String connector, + String profile, String loc_ref_url) throws ConnectorException + { + log.debug("Choosing LocalConnector for signation..."); + + log.debug("connector type = " + connector); + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + + if (Constants.SIGNATURE_DEVICE_MOC.equals(connector)) { + + return new LocRefDetachedMOCCAConnector(cp, loc_ref_url); + + } else if (Constants.SIGNATURE_DEVICE_BKU.equals(connector)){ + + return new LocRefDetachedBKUConnector(cp, loc_ref_url); + + } + + log.error("Currently only the BKU connector is fully implemented."); + return new LocRefDetachedBKUConnector(cp, loc_ref_url); + } + + public static Connector chooseWebConnectorForSign(String connector, + String profile, String loc_ref_url) throws ConnectorException + { + log.debug("Choosing Connector for WEB signation..."); + + log.debug("connector type = " + connector); + + if (!connector.equals(Constants.SIGNATURE_DEVICE_MOA)) + { + log.error("Currently only the MOA connector is available for non local WEB signation."); + } + + log.debug("choosing locref detached MOA connector."); + + //TODO TR: Hier umschalten, um von SwA-Requests zurueckzuwechseln. + // Loc_Ref-Connector +// return new DetachedLocRefMOAConnector(profile, loc_ref_url); + // SwA-Connector + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new MOASoapWithAttachmentConnector(cp); + } + +// public static Connector chooseCommandlineConnectorForSign(String connector, +// String profile) throws ConnectorException +// { +// log.debug("Choosing Connector for commandline signation..."); +// +// log.debug("connector type = " + connector); +// +// if (connector.equals(BKU)) +// { +// log.debug("sig_app is BKU ==> MultipartDetachedBKUConnector"); //$NON-NLS-1$ +// +// return new MultipartDetachedBKUConnector(profile); +// } +// if (connector.equals(MOA)) +// { +// // TODO MOA detached signing is not allowed at the commandline +// log.warn("Detached MOA is not supported on the commandline. -> choosing Base64 temporarily."); +// return new EnvelopingBase64MOAConnector(profile); +// } +// +// throw new ConnectorException(300, "Unknown connector type '" + connector + "' specified."); +// } + + public static LocalConnector chooseLocalConnectorForVerify(String connector, + PdfASID sig_kz, String sig_id, String profile, String loc_ref_url) throws ConnectorException + { + log.debug("Choosing LocalConnector for verification..."); + + log.debug("connector type = " + connector); + log.debug("sig_kz = " + sig_kz); + log.debug("sig_id = " + sig_id); + + if (!connector.equals("bku")) + { + log.error("Currently only the BKU connector is fully implemented."); + } + + if (sig_kz == null) + { + log.debug("sig_kz is null -> must be old signature -> choosing old Base64 connector."); + + return new OldEnvelopingBase64BKUConnector(profile); + } + + log.debug("sig_kz is not null -> must be one of the newer ... base64, base64 hotfix, or detached"); + + if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) + { + log.debug("sig_kz version is 1.0.0 -> choosing base64 (old or hotfix)"); + + if (sig_id == null) + { + log.debug("sig_id is null, which means that it is a MOA signature -> choose a hotfix base64 connector (thus it is moa - it doesn't matter)."); + + return new EnvelopedBase64BKUConnector(profile); + } + + String[] sig_id_parts = sig_id.split("@"); + if (sig_id_parts.length == 2) + { + log.debug("sig_id has 2 @-separated parts -> choosing old base64 connector"); + + return new OldEnvelopingBase64BKUConnector(profile); + } + if (sig_id_parts[0].equals(HotfixIdFormatter.SIG_ID_PREFIX)) + { + log.debug("sig_id prefix is hotfix -> choosing hotfix base64 connector"); + + return new EnvelopedBase64BKUConnector(profile); + } + + throw new ConnectorException(300, "The SIG_KZ version is 1.0.0, but SIG_ID is neither MOA nor Old base64 nor Hotfix base64 ???'"); + } + if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_1_0) || sig_kz.getVersion().equals(SignatorFactory.VERSION_1_2_0)) + { + log.debug("sig_kz version is 1.1.0/1.2.0 -> choosing detached (loc ref) connector."); + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new LocRefDetachedBKUConnector(cp, loc_ref_url); + } + throw new ConnectorException(ErrorCode.UNSUPPORTED_SIGNATURE, "The SIG_KZ version '" + sig_kz.getVersion() + "' is unknown. Please get a new version of PDF-AS. Your version is: " + PdfAS.PDFAS_VERSION); + } + + public static Connector chooseWebConnectorForVerify(String connector, + PdfASID sig_kz, String sig_id, String profile, String loc_ref_url) throws ConnectorException + { + log.debug("Choosing Connector for WEB verification..."); + + log.debug("connector type = " + connector); + log.debug("sig_kz = " + sig_kz); + log.debug("sig_id = " + sig_id); + + if (!connector.equals("moa")) + { + log.error("Currently only the MOA connector is available for non local WEB signation."); + } + + if (sig_kz == null || sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) + { + log.debug("sig_kz is null or sig_kz version is 1.0.0 -> choosing Base64 connector."); + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new EnvelopingBase64MOAConnector(cp); + } + + if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_1_0) || sig_kz.getVersion().equals(SignatorFactory.VERSION_1_2_0)) + { + log.debug("sig_kz version is 1.1.0/1.2.0 -> choosing detached (loc ref) connector."); + + //throw new ConnectorException(ErrorCode.DETACHED_SIGNATURE_NOT_SUPPORTED, "The MOA detached connector is not suitable for verification."); + // TODO TR: Switch her for SwA or Detached-URL Connector + // the following line is used in connection with LocRef-Connector +// return new DetachedLocRefMOAConnector(profile, loc_ref_url); + // the following line is uesed in connection with SwA-Connector + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new MOASoapWithAttachmentConnector(cp); + } + throw new ConnectorException(ErrorCode.UNSUPPORTED_SIGNATURE, "The SIG_KZ version '" + sig_kz.getVersion() + "' is unknown. Please get a new version of PDF-AS. Your version is: " + PdfAS.PDFAS_VERSION); + } + +// public static Connector chooseCommandlineConnectorForVerify(String connector, +// PdfASID sig_kz, String sig_id, String profile) throws ConnectorException +// { +// log.debug("Choosing Connector for Commandline verification..."); +// +// log.debug("connector type = " + connector); +// log.debug("sig_kz = " + sig_kz); //$NON-NLS-1$ +// log.debug("sig_id = " + sig_id); //$NON-NLS-1$ +// +// if (sig_kz == null) +// { +// log.debug("sig_kz is null -> chose an old enveloped base64 connector"); //$NON-NLS-1$ +// +// return chooseEnvelopedBase64ConnectorOld(profile, connector); +// } +// +// log.debug("sig_kz is not null -> one of the newer signatures"); +// +// if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) +// { +// log.debug("Version is 1.0.0 -> Base64 Signatur (old or Hotfix)."); +// +// if (sig_id == null) +// { +// log.debug("sig_id is null, which means that it is a MOA signature -> choose a hotfix base64 connector (thus it is moa - it doesn't matter)."); +// +// return chooseEnvelopedBase64ConnectorHotfix(profile, connector); +// } +// +// String[] sig_id_parts = sig_id.split("@"); +// if (sig_id_parts.length == 2) +// { +// log.debug("sig_id has 2 @-separated parts -> choosing old base64 connector"); +// +// return chooseEnvelopedBase64ConnectorOld(profile, connector); +// } +// if (sig_id_parts[0].equals(HotfixIdFormatter.SIG_ID_PREFIX)) +// { +// log.debug("sig_id prefix is hotfix -> choosing hotfix base64 connector"); +// +// return chooseEnvelopedBase64ConnectorHotfix(profile, connector); +// } +// +// throw new ConnectorException(300, "The SIG_KZ version is 1.0.0, but SIG_ID is neither MOA nor Old base64 nor Hotfix base64 ???'"); +// } +// if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_1_0)) +// { +// log.debug("Version is 1.1.0 -> chose a detached connector."); +// +// return chooseDetachedMultipartConnector(profile, connector); +// } +// +// throw new ConnectorException(310, "The SIG_KZ version '" + sig_kz.getVersion() + "' is unknown."); +// } + + protected static final String BKU = "bku"; //$NON-NLS-1$ + + protected static final String MOA = "moa"; //$NON-NLS-1$ + + protected static Connector chooseEnvelopedBase64ConnectorOld(String profile, + String sig_app) throws ConnectorException + { + if (sig_app.equals(BKU)) + { + log.debug("sig_app is BKU ==> OldEnvelopingBase64BKUConnector"); //$NON-NLS-1$ + + return new OldEnvelopingBase64BKUConnector(profile); + } + if (sig_app.equals(MOA)) + { + log.debug("sig_app is MOA ==> EnvelopingBase64MOAConnector"); //$NON-NLS-1$ + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new EnvelopingBase64MOAConnector(cp); + } + throw new ConnectorException(310, "Unknown sig_app '" + sig_app + "'."); //$NON-NLS-1$ //$NON-NLS-2$ + + } + + protected static Connector chooseEnvelopedBase64ConnectorHotfix( + String profile, String sig_app) throws ConnectorException + { + if (sig_app.equals(BKU)) + { + log.debug("sig_app is BKU ==> EnvelopedBase64BKUConnector"); //$NON-NLS-1$ + + return new EnvelopedBase64BKUConnector(profile); + } + if (sig_app.equals(MOA)) + { + log.debug("sig_app is MOA ==> EnvelopedBase64MOAConnector"); //$NON-NLS-1$ + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new EnvelopingBase64MOAConnector(cp); + } + throw new ConnectorException(310, "Unknown sig_app '" + sig_app + "'."); //$NON-NLS-1$ //$NON-NLS-2$ + + } + + protected static Connector chooseDetachedMultipartConnector(String profile, + String sig_app) throws ConnectorException + { + if (sig_app.equals(BKU)) + { + log.debug("sig_app is BKU ==> DetachedMultipartBKUConnector"); //$NON-NLS-1$ + + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(profile); + return new MultipartDetachedBKUConnector(cp); + } + if (sig_app.equals(MOA)) + { + log.debug("sig_app is MOA ==> DetachedMOAConnector"); //$NON-NLS-1$ + + String msg = "A Detached signature cannot be verified with the MOA connector (yet)."; //$NON-NLS-1$ + log.error(msg); + throw new ConnectorException(ErrorCode.DETACHED_SIGNATURE_NOT_SUPPORTED, msg); + } + throw new ConnectorException(310, "Unknown sig_app '" + sig_app + "'."); //$NON-NLS-1$ //$NON-NLS-2$ + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorConfigurationKeys.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorConfigurationKeys.java new file mode 100644 index 0000000..fa340cd --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorConfigurationKeys.java @@ -0,0 +1,55 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors; + +/** + * This class contains the key constants used by the Connectors to retrieve + * templates etc. from the Configuration. + * + * @author wprinz + */ +public abstract class ConnectorConfigurationKeys +{ + + /** + * The application mode sign + */ + public static final String VALUE_MODE_SIGN = "sign"; + + /** + * The application mode verify + */ + public static final String VALUE_MODE_VERIFY = "verify"; + + /** + * The key used to read out the available for web property. + */ + public static final String AVAILABLE_FOR_WEB = "available_for_web"; + + /** + * The key used to read out the available for commandline property. + */ + public static final String AVAILABLE_FOR_COMMANDLINE = "available_for_commandline"; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorEnvironment.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorEnvironment.java new file mode 100644 index 0000000..451f367 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/ConnectorEnvironment.java @@ -0,0 +1,52 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors; + +import java.security.cert.X509Certificate; + +/** + * Base class for connector environments + * + * @author dferbas + * + */ +public abstract class ConnectorEnvironment { + + public abstract String getCertAlgEcdsa(); + + public abstract String getCertAlgRsa(); + + public abstract String getVerifyTemplate(); + + public String getDefaultAlgForCert(X509Certificate cert) { + String cert_alg; + cert_alg = getCertAlgEcdsa(); + if (cert.getPublicKey().getAlgorithm().indexOf("RSA") >= 0) //$NON-NLS-1$ + { + cert_alg = getCertAlgRsa(); + } + return cert_alg; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/LocalConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/LocalConnector.java new file mode 100644 index 0000000..5279a03 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/LocalConnector.java @@ -0,0 +1,91 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors; + +import java.util.Properties; + +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; + +/** + * @author wprinz + */ +public interface LocalConnector +{ +//23.11.2010 changed by exthex - added XMLDsigData parameter to prepareVerifyRequest to allow reuse + + /** + * Prepares the sign request xml to be sent using the sign request template. + * + * @param data + * The SignatureData. + * @return Returns the sign request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareSignRequest(SignatureData data) throws ConnectorException; + + /** + * Analyzes the sign response xml and extracts the signature data. + * + * @param response_properties + * The response properties containing the response String and + * transport related information. + * @return Returns the extracted data encapsulated in a SignatureObject. + * @throws ConnectorException + * f.e. + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException; + + /** + * Prepares the verify request xml to be sent using the verify request + * template. + * + * @param data + * The SignatureData. + * @param so + * The signature information object. + * @param dsigData + * The previously recreated xmldsig block of the signature + * @return Returns the verify request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException; + + /** + * Analyzes the verify response string. + * + * @param response_properties + * The response properties containing the response XML. + * @return Returns the SignatureResponse containing the verification result. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java new file mode 100644 index 0000000..ef355a0 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/MOAConnector.java @@ -0,0 +1,921 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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. + * + * $Id: MOAConnector.java,v 1.5 2006/10/31 08:18:41 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig.connectors; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; +import java.util.Vector; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.rpc.Call; +import javax.xml.rpc.Service; +import javax.xml.rpc.ServiceFactory; + +import org.apache.axis.message.SOAPBodyElement; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.xml.serialize.OutputFormat; +import org.apache.xml.serialize.XMLSerializer; +import org.w3c.dom.Document; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.external.ExternalErrorException; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.exceptions.WebException; +import at.knowcenter.wag.egov.egiz.sig.Connector; +import at.knowcenter.wag.egov.egiz.sig.ConnectorInformation; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Connector to access the MOA service. + * + * @deprecated + * @author wlackner + * @author wprinz + */ +public class MOAConnector implements Connector +{ + /** + * ConnectorInformation that identifies this Connector to the system. + * + * @see at.knowcenter.wag.egov.egiz.sig.ConnectorFactory + * @see ConnectorInformation + */ + public static final ConnectorInformation CONNECTOR_INFORMATION = new ConnectorInformation("moa", "MOA"); + + /** + * The class type value. + * + *

+ * Just for convenience. + *

+ */ + private static final String TYPE = CONNECTOR_INFORMATION.getIdentifier(); + + /** + * The connector description. + */ + public static final String DESCRIPTION = "MOA"; + + /** + * The SettingsReader instance + */ + private SettingsReader settings_ = null; + + /** + * MOA siganture verification mode + */ + public static final String SERVICE_VERIFY = "SignatureVerification"; + + /** + * MOA siganture creation mode + */ + public static final String SERVICE_SIGN = "SignatureCreation"; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(MOAConnector.class); + + /** + * The empty constructor + */ + public MOAConnector() throws SignatureException + { + loadSettings(); + } + + /** + * load the inital signature settings + * + * @see SettingsReader + */ + private void loadSettings() throws SignatureException + { + if (settings_ == null) + { + try + { + settings_ = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + String log_message = "Can not load signature settings. Cause:\n" + e.getMessage(); + logger_.error(log_message); + throw new SignatureException(101, log_message, e); + } + } + } + + /** + * This method calls the MOA signing a given text. The signaton type is to + * used initializing the corresponding SigantureObject. The initialized + * SignatureObject is filled out by the parsed MOA-Response.
+ * If an error request is send back from MOA, an error message is generated an + * an exception is thrown. + * + * @param sigType + * the type of the SignatureObject that should be returned + * @param userName + * the name of the user calling this method + * @param signText + * the text that shoulf be signed from MOA + * @return the complete SingatureObject of the given type filled by values + * from the MOA-Request + * @throws SignatureException + * ErrorCode 300 + * @see SignatureObject + */ + public SignatureObject doSign(String sigType, String userName, String signText) throws SignatureException + { + SignatureObject sig_obj = new SignatureObject(); + try + { + sig_obj.setSigType(sigType); + sig_obj.initByType(); + } + catch (SignatureTypesException e) + { + SignatureException se = new SignatureException(300, "Can ot init signature object with type:" + sigType, e); + throw se; + } + if (logger_.isDebugEnabled()) + { + logger_.debug("Signature Type is:" + sig_obj.getSignationType()); + } + if (logger_.isInfoEnabled()) + { + logger_.info("Call " + TYPE + " from user:" + userName); + } + + String url = getSignURL(sigType); + + String sign_request_filename = getSignRequestTemplateFileName(sigType); + String key_ident = getSignKeyIdentifier(sigType); + + //String sign_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + String sign_req_str = this.settings_.readInternalResourceAsString(sign_request_filename); + if (sign_req_str == null) + { + SignatureException se = new SignatureException(300, "File not found:" + sign_request_filename); + throw se; + } + + sign_req_str = sign_req_str.replaceFirst("KeyIdentifierReplace", key_ident); + if (logger_.isDebugEnabled()) + { + //logger_.debug("error_signature_response = " + sign_req_str); + // FileHelper.writeToFile(sign_request_filename + "_signText.xml", + // signText); + } + // sign_req_str = sign_req_str.replaceFirst("XMLContentReplace", signText); + // now use the the base64 Template + signText = CodingHelper.encodeUTF8AsBase64(signText); + sign_req_str = sign_req_str.replaceFirst("Base64ContentReplace", signText); + if (logger_.isDebugEnabled()) + { + //logger_.debug(sign_req_str); + // FileHelper.writeToFile(sign_request_filename + "_request.xml", + // sign_req_str); + } + + String response_string = ""; + try + { + response_string = MOAConnector.connectMOA(sign_req_str, MOAConnector.SERVICE_SIGN, url); + sig_obj.setRawSignatureResponse(response_string); + } + catch (WebException we) + { + SignatureException se = new SignatureException(we.getErrorCode(), we); + throw se; + } + + if (!response_string.equals("")) + { + if (logger_.isInfoEnabled()) + { + logger_.info("get MOA response"); + } + Pattern erc_p_s = Pattern.compile(""); + Pattern erc_p_e = Pattern.compile(""); + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + // System.err.println(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + logger_.error("error_signature_response = " + response_string); + // FileHelper.writeToFile(sign_request_filename + "_response.xml", + // response_string); + //logger_.error("Write error response to file:" + sign_request_filename + "_response.xml"); + } + Pattern erm_p_s = Pattern.compile(""); + Pattern erm_p_e = Pattern.compile(""); + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + + String error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + logger_.debug("error_code = " + error_code); + String error_mess = ""; + if (erm_m_s.find() && erm_m_e.find()) + { + error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + logger_.debug(error_mess); + } + throw new SignatureException(new ExternalErrorException(error_code, error_mess)); + } + else + { + if (logger_.isDebugEnabled()) + { + //logger_.debug("response_string = " + response_string); + // FileHelper.writeToFile(sign_request_filename + "_response.xml", + // response_string); + } + parseCreateXMLResponse(response_string, sig_obj); + } + } + sig_obj.setSigResponse(response_string); + return sig_obj; + } + + /** + * This method parses the MOA-Response string. It separates the + * SignatureValue, X509IssuerName, SigningTime, X509SerialNumber, + * X509Certificate, CertDigest and DigestValues. If the X509Certificate is + * extracted it would be stored in the certificates directory. + * + * @param xmlResponse + * the response string from the MOA sign-request + * @param sigObj + * the SignatureObject that should be filled + * @throws SignatureException + * ErrorCode (303, 304) + * @see SignatureObject + * @see CodingHelper + * @see X509Cert + */ + private void parseCreateXMLResponse(String xmlResponse, SignatureObject sigObj) throws SignatureException + { + Pattern sig_val_p_s = Pattern.compile("<[\\w]*:?SignatureValue>"); + Pattern sig_val_p_e = Pattern.compile(""); + Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName>"); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern sig_tim_p_s = Pattern.compile("<[\\w]*:?SigningTime>"); + Pattern sig_tim_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile("<[\\w]*:?X509SerialNumber>"); + Pattern ser_num_p_e = Pattern.compile(""); + Pattern sig_cer_p_s = Pattern.compile("<[\\w]*:?X509Certificate>"); + Pattern sig_cer_p_e = Pattern.compile(""); + + Pattern sig_cer_d_p_s = Pattern.compile("<[\\w]*:?CertDigest>"); + Pattern sig_cer_d_p_e = Pattern.compile(""); + Pattern dig_val_p_s = Pattern.compile("<[\\w]*:?DigestValue>"); + Pattern dig_val_p_e = Pattern.compile(""); + + Matcher sig_val_m_s = sig_val_p_s.matcher(xmlResponse); + Matcher sig_val_m_e = sig_val_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher sig_tim_m_s = sig_tim_p_s.matcher(xmlResponse); + Matcher sig_tim_m_e = sig_tim_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + Matcher sig_cer_m_s = sig_cer_p_s.matcher(xmlResponse); + Matcher sig_cer_m_e = sig_cer_p_e.matcher(xmlResponse); + + Matcher sig_cer_d_m_s = sig_cer_d_p_s.matcher(xmlResponse); + Matcher sig_cer_d_m_e = sig_cer_d_p_e.matcher(xmlResponse); + + String sig_val = ""; + String iss_nam = ""; + String ser_num = ""; + String sig_tim = ""; + String sig_cer = ""; + String sig_dig = ""; + + // SignatureValue + if (sig_val_m_s.find() && sig_val_m_e.find()) + { + sig_val = xmlResponse.substring(sig_val_m_s.end(), sig_val_m_e.start()); + sig_val = sig_val.replaceAll("\\s", ""); + sigObj.setSignationValue(sig_val); + } + // X509IssuerName + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sigObj.setSignationIssuer(iss_nam); + } + // X509SerialNumber + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sigObj.setSignationSerialNumber(ser_num); + } + // SigningTime + if (sig_tim_m_s.find() && sig_tim_m_e.find()) + { + sig_tim = xmlResponse.substring(sig_tim_m_s.end(), sig_tim_m_e.start()); + sigObj.setSignationDate(sig_tim); + } + // CertDigest + if (sig_cer_d_m_s.find() && sig_cer_d_m_e.find()) + { + String cert_digest = xmlResponse.substring(sig_cer_d_m_s.end(), sig_cer_d_m_e.start()); + Matcher dig_val_m_s = dig_val_p_s.matcher(cert_digest); + Matcher dig_val_m_e = dig_val_p_e.matcher(cert_digest); + if (dig_val_m_s.find() && dig_val_m_e.find()) + { + sig_dig = cert_digest.substring(dig_val_m_s.end(), dig_val_m_e.start()); + sigObj.setX509CertificateDigest(sig_dig); + } + } + // extract Subject Name from X509Certificate + if (sig_cer_m_s.find() && sig_cer_m_e.find()) + { + sig_cer = xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start()); + sig_cer = sig_cer.replaceAll("\\s", ""); + X509Cert cert = X509Cert.initByString(sig_cer); + if (cert.isX509Cert()) + { + sigObj.setX509Certificate(cert.getCertString()); + String serial_num = cert.getSerialNumber(); + String subject_name = cert.getSubjectName(); + if (!ser_num.equals(serial_num)) + { + SignatureException se = new SignatureException(303, "Serialnumber of certificate and tag X509SerialNumber differs!"); + throw se; + } + sigObj.setSignationName(subject_name); + } + } + } + + /** + * This method reads the verify template from the file system and fills out + * the template with the SignatureObject values. + * + * @param normalizedText + * the normalized text to veryfied + * @param sigObject + * the SignatureObject holding the singature values + * @return the filled verify template string + * @throws SignatureException + * ErrorCode (311, 312, 313) + * @see SignatureObject + * @see CodingHelper + */ + public String getVerifyTemplate(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + try + { + if (normalizedText == null || normalizedText.length() == 0) + { + SignatureException se = new SignatureException(311, "Document can not be verified because normalized text is empty."); + throw se; + } + if (sigObject == null) + { + SignatureException se = new SignatureException(312, "Document can not be verified because no signature object are set."); + throw se; + } + String verify_template = getVerifyTemplateFileName(sigObject.getSignationType()); + String sig_prop_template = getSigPropFileName(sigObject.getSignationType()); + + //String verify_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_template)); + String verify_req_str = this.settings_.readInternalResourceAsString(verify_template); + + //String sig_prop_str = FileHelper.readFromFile(SettingsReader.relocateFile(sig_prop_template)); + String sig_prop_str = this.settings_.readInternalResourceAsString(sig_prop_template); + + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_template); + //logger_.debug(sig_prop_template); + } + + String x509Certificate = sigObject.getX509CertificateString(); + if (x509Certificate == null) + { + SignatureException se = new SignatureException(ErrorCode.CERTIFICATE_NOT_FOUND, "Document certificate is not defined."); + throw se; + } + String cert_alg = settings_.getValueFromKey("cert.alg.ecdsa"); + X509Cert x509_cert = sigObject.getX509Cert(); + if (x509_cert.isRSA()) + { + cert_alg = settings_.getValueFromKey("cert.alg.rsa"); + } + + sig_prop_str = sig_prop_str.replaceFirst("SigningTimeReplace", sigObject.getSignationDate()); + // The issuer is already a valid Unicode String. + // No need to convert it - not to mention the missing encoding. + // byte[] issuer_name = + // CodingHelper.encodeUTF8(sigObject.getSignationIssuer()); + // new String(issuer_name) + sig_prop_str = sig_prop_str.replaceFirst("X509IssuerNameReplace", sigObject.getSignationIssuer()); + sig_prop_str = sig_prop_str.replaceFirst("X509SerialNumberReplace", sigObject.getSignationSerialNumber()); + sig_prop_str = sig_prop_str.replaceFirst("DigestValueX509CertificateReplace", sigObject.getX509CertificateDigest()); + + verify_req_str = verify_req_str.replaceFirst("CertAlgReplace", cert_alg); + verify_req_str = verify_req_str.replaceFirst("TemplateSignedPropertiesReplace", sig_prop_str); + byte[] sig_prop_code = CodingHelper.buildDigest(sig_prop_str.getBytes("UTF-8"), "sha1"); // added + // the + // ("UTF-8") + // encoding + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + verify_req_str = verify_req_str.replaceFirst("DigestValueSignedPropertiesReplace", sig_prop_hash); + if (logger_.isDebugEnabled()) + { + logger_.debug("build digest from SignedProperties:start"); + //logger_.debug("DATA :" + sig_prop_str); + logger_.debug("DIGEST:" + sig_prop_hash); + logger_.debug("build digest from SignedProperties:end"); + } + + verify_req_str = verify_req_str.replaceFirst("SignatureValueReplace", sigObject.getSignationValue()); + verify_req_str = verify_req_str.replaceFirst("X509CertificateReplace", x509Certificate); + byte[] data_value = normalizedText.getBytes("UTF-8"); + byte[] data_value_hash = CodingHelper.buildDigest(data_value, "sha1"); + // byte[] data_value_hash = + // CodingHelper.buildDigest(normalizedText.getBytes()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + //String object_data = normalizedText; // new String(data_value); + // System.err.println(object_data_hash); + // very_req_str = very_req_str.replaceFirst("ObjectDataReplace", + // object_data); + String raw_b64 = CodingHelper.encodeBase64(data_value); + verify_req_str = verify_req_str.replaceFirst("Base64ContentReplace", raw_b64); + + verify_req_str = verify_req_str.replaceFirst("DigestValueSignedDataReplace", object_data_hash); + if (logger_.isDebugEnabled()) + { + // FileHelper.writeToFile(verify_template + "_verifyText.xml", + // normalizedText); + logger_.debug("build digest from data object:start"); + //logger_.debug("DATA :" + object_data); + logger_.debug("DIGEST:" + object_data_hash); + logger_.debug("build digest from data object:end"); + } + return verify_req_str; + } + catch (UnsupportedEncodingException e) + { + throw new SignatureException(310, e); + } + } + + /** + * This method generates the MOA verify prozess. It checks if the given + * SignatureObject is signed by MOA or BKU. The verify template string is + * filled out by the corresponding method. + * + * @param normalizedText + * the normalized text to verify + * @param sigObject + * the SignatureObject holding the singature values + * @return a SignatureResponse object if the verify prozess does not fails + * @throws SignatureException + * @see SignatureResponse + */ + public SignatureResponse doVerify(String normalizedText, + SignatureObject sigObject) throws SignatureException + { + String verify_url = getVerifyURL(sigObject.getSignationType()); // settings_.getValueFromKey(TYPE + // + "." + + // Signature.VALUE_MODE_VERIFY + // + + // ".url"); + String verify_request = getVerifyRequestTemplateFileName(sigObject.getSignationType()); // settings_.getValueFromKey(TYPE + // + + // "." + // + + // Signature.VALUE_MODE_VERIFY + // + + // ".request"); + String trust_profile = getVerifyTrustProfileID(sigObject.getSignationType()); + + //String verify_req_str = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request)); + String verify_req_str = this.settings_.readInternalResourceAsString(verify_request); + + String verify_template_str = null; + if (sigObject.isMOASigned()) + { + verify_template_str = getVerifyTemplate(normalizedText, sigObject); + } + else + { + BKUConnector bku_conn = new BKUConnector(); + verify_template_str = bku_conn.getVerifyTemplate(normalizedText, sigObject); + } + verify_req_str = verify_req_str.replaceFirst("XMLContentReplace", verify_template_str); + verify_req_str = verify_req_str.replaceFirst("TrustProfileIDReplace", trust_profile); + + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_req_str); + // FileHelper.writeToFile(verify_request + "_request.xml", + // verify_req_str); + } + String response_string = ""; + try + { + response_string = MOAConnector.connectMOA(verify_req_str, MOAConnector.SERVICE_VERIFY, verify_url); + } + catch (WebException we) + { + if (logger_.isDebugEnabled()) + { + we.printStackTrace(); + } + SignatureException se = new SignatureException(we.getErrorCode(), we); + throw se; + } + + if (!response_string.equals("")) + { + Pattern erc_p_s = Pattern.compile("<[\\w]*:?ErrorCode>"); + Pattern erc_p_e = Pattern.compile(""); + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + if (logger_.isEnabledFor(Level.ERROR)) + { + //logger_.debug(response_string); + // FileHelper.writeToFile(verify_request + "_response.xml", + // response_string); + logger_.error("Write error response to file:" + verify_request + "_response.xml"); + } + Pattern erm_p_s = Pattern.compile("<[\\w]*:?Info>"); + Pattern erm_p_e = Pattern.compile(""); + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + String error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + String error_mess = null; + if (erm_m_s.find() && erm_m_e.find()) + { + error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + } + throw new SignatureException(new ExternalErrorException(error_code, error_mess)); + } + else + { + if (logger_.isDebugEnabled()) + { + //logger_.debug(verify_request + "_response.xml " + response_string); + } + return parseVerifyXMLResponse(response_string); + } + } + return null; + } + + /** + * This method parses the verify response string and return a + * SignatureResponse object. The SignatureResponse object is filled out by the + * response values from the BKU-response. + * + * @param xmlResponse + * the response values from the MOA-verify request + * @return SignatureResponse object + * @see SignatureResponse + */ + private SignatureResponse parseVerifyXMLResponse(String xmlResponse) + { + if (logger_.isInfoEnabled()) + { + logger_.info("Try parsing the verify response"); + } + Pattern sub_nam_p_s = Pattern.compile(""); + Pattern sub_nam_p_e = Pattern.compile(""); + Pattern iss_nam_p_s = Pattern.compile(""); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile(""); + Pattern ser_num_p_e = Pattern.compile(""); + + // [tknall] start qualified certificate + Pattern cert_qualified_p = Pattern.compile(""); + Matcher cert_qualified_m = cert_qualified_p.matcher(xmlResponse); + // [tknall] stop qualified certificate + + Pattern sig_chk_p_s = Pattern.compile(""); + Pattern sig_chk_p_e = Pattern.compile(""); + Pattern man_chk_p_s = Pattern.compile(""); + Pattern man_chk_p_e = Pattern.compile(""); + Pattern cer_chk_p_s = Pattern.compile(""); + Pattern cer_chk_p_e = Pattern.compile(""); + + Pattern code_p_s = Pattern.compile(""); + Pattern code_p_e = Pattern.compile(""); + + Pattern cert_p_s = Pattern.compile(""); + Pattern cert_p_e = Pattern.compile(""); + + Matcher sub_nam_m_s = sub_nam_p_s.matcher(xmlResponse); + Matcher sub_nam_m_e = sub_nam_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + + Matcher sig_chk_m_s = sig_chk_p_s.matcher(xmlResponse); + Matcher sig_chk_m_e = sig_chk_p_e.matcher(xmlResponse); + Matcher man_chk_m_s = man_chk_p_s.matcher(xmlResponse); + Matcher man_chk_m_e = man_chk_p_e.matcher(xmlResponse); + Matcher cer_chk_m_s = cer_chk_p_s.matcher(xmlResponse); + Matcher cer_chk_m_e = cer_chk_p_e.matcher(xmlResponse); + + Matcher cert_m_s = cert_p_s.matcher(xmlResponse); + Matcher cert_m_e = cert_p_e.matcher(xmlResponse); + + SignatureResponse sig_res = new SignatureResponse(); + + // [tknall] start qualified certificate + sig_res.setQualifiedCertificate(cert_qualified_m.find()); + // [tknall] stop qualified certificate + + // public authority + Pattern publicAuthority_p = Pattern.compile(""); + Matcher publicAuthority_m = publicAuthority_p.matcher(xmlResponse); + sig_res.setPublicAuthority(false); + sig_res.setPublicAuthorityCode(null); + if (publicAuthority_m.find()) { + sig_res.setPublicAuthority(true); + } else { + Matcher publicAuthority_m_s = Pattern.compile("").matcher(xmlResponse); + Matcher publicAuthority_m_e = Pattern.compile("").matcher(xmlResponse); + if (publicAuthority_m_s.find() && publicAuthority_m_e.find()) { + sig_res.setPublicAuthority(true); + String codePart = xmlResponse.substring(publicAuthority_m_s.end(), publicAuthority_m_e.start()); + Matcher code_m_s = code_p_s.matcher(codePart); + Matcher code_m_e = code_p_e.matcher(codePart); + if (code_m_s.find() && code_m_e.find()) { + String code = codePart.substring(code_m_s.end(), code_m_e.start()); + sig_res.setPublicAuthorityCode(code); + } + } + } + + if (sub_nam_m_s.find() && sub_nam_m_e.find()) + { + String sub_nam = xmlResponse.substring(sub_nam_m_s.end(), sub_nam_m_e.start()); + sig_res.setX509SubjectName(sub_nam); + } + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + String iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sig_res.setX509IssuerName(iss_nam); + } + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + String ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sig_res.setX509SerialNumber(ser_num); + } + if (sig_chk_m_s.find() && sig_chk_m_e.find()) + { + String sig_chk = xmlResponse.substring(sig_chk_m_s.end(), sig_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(sig_chk); + Matcher code_m_e = code_p_e.matcher(sig_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = sig_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureCheckCode(code); + } + } + if (man_chk_m_s.find() && man_chk_m_e.find()) + { + String man_chk = xmlResponse.substring(man_chk_m_s.end(), man_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(man_chk); + Matcher code_m_e = code_p_e.matcher(man_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = man_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureManifestCheckCode(code); + } + } + if (cer_chk_m_s.find() && cer_chk_m_e.find()) + { + String cer_chk = xmlResponse.substring(cer_chk_m_s.end(), cer_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(cer_chk); + Matcher code_m_e = code_p_e.matcher(cer_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = cer_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setCertificateCheckCode(code); + } + } + if (cert_m_s.find() && cert_m_e.find()) + { + String cert_string = xmlResponse.substring(cert_m_s.end(), cert_m_e.start()); + + X509Cert resp_cert = X509Cert.initByString(cert_string); + sig_res.setCertificate(resp_cert); + } + + return sig_res; + } + + protected String getConnectorValueFromProfile(String profile, String key) + { + String value = settings_.getValueFromKey("sig_obj." + profile + "." + key); + if (value == null) + { + value = settings_.getValueFromKey(key); + } + return value; + } + + public String getSignURL(String profile) + { + final String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".url"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSignRequestTemplateFileName(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".request"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSignKeyIdentifier(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_SIGN + ".KeyIdentifier"; + return getConnectorValueFromProfile(profile, key); + } + + public String getVerifyURL(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".url"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyRequestTemplateFileName(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".request"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyTemplateFileName(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".template"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getSigPropFileName(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".template.SP"; + return getConnectorValueFromProfile(profile, key); + } + + protected String getVerifyTrustProfileID(String profile) + { + String key = TYPE + "." + ConnectorConfigurationKeys.VALUE_MODE_VERIFY + ".TrustProfileID"; + return getConnectorValueFromProfile(profile, key); + } + + /** + * This method connects the moa server getting the requestString, the given + * serviseMode and the endpointUrl. The requestString is the envelope of the + * SOAP Message send and recieve by the AXIS module. The Response SOAP message + * of the MOA server is parsed by AXIS and the message envelope is send back + * to the calling method. + * + * @param requestString + * the request string (XML) to send. + * @param serviceMode + * the mode which connect to MOA + * @param endpointURL + * the URL which the MOA server is running + * @return the response string (XML) of the MOA server + * @throws WebException + */ + public static String connectMOA(String requestString, String serviceMode, + String endpointURL) throws WebException + { + try + { + if (logger_.isInfoEnabled()) + { + logger_.info(serviceMode); + logger_.info(endpointURL); + } + // Parser/DOMBuilder instanzieren + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + + // XML Datei in einen DOM-Baum umwandeln + ByteArrayInputStream bais = new ByteArrayInputStream(requestString.getBytes("UTF-8")); + Document xmlRequest = builder.parse(bais); + + // Call oeffnen + Call call = null; + + // Neues BodyElement anlegen und mit dem DOM-Baum fuellen + SOAPBodyElement body = new SOAPBodyElement(xmlRequest.getDocumentElement()); + SOAPBodyElement[] params = new SOAPBodyElement[] { body }; + + // AXIS-Server instanzieren + Service service = ServiceFactory.newInstance().createService(new QName(serviceMode)); + call = service.createCall(); + call.setTargetEndpointAddress(endpointURL); + + // Call ausloesen und die Antworten speichern + if (logger_.isInfoEnabled()) + { + logger_.info("Calling MOA:" + endpointURL); + } + Vector responses = (Vector) call.invoke(params); + + // Erstes Body Element auslesen + SOAPBodyElement response = (SOAPBodyElement) responses.get(0); + + // Aus der Response den DOM-Baum lesen + Document root_response = response.getAsDocument(); + if (logger_.isInfoEnabled()) + { + logger_.info("Return from MOA:" + serviceMode); + } + + // XML-Formatierung konfiguieren + OutputFormat format = new OutputFormat((Document) root_response); + format.setLineSeparator("\n"); + format.setIndenting(false); + format.setPreserveSpace(true); + format.setOmitXMLDeclaration(false); + format.setEncoding("UTF-8"); + + // Ausgabe der Webservice-Antwort auf die Konsole + // XMLSerializer conSerializer = new XMLSerializer(System.out, format); + // conSerializer.serialize(root_response); + + // Ausgabe der Webservice-Antwort in Datei + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + XMLSerializer response_serializer = new XMLSerializer(baos, format); + response_serializer.serialize(root_response); + return baos.toString("UTF-8"); + } + catch (Exception e) + { + throw new WebException(e); + } + // serialize signature only + + // if + // (root_response.getDocumentElement().getLocalName().equals("CreateXMLSignatureResponse")) + // { + // Element signature = (Element) + // root_response.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", + // "Signature").item(0); + // String signatureFile = getProperty(mode + "Request").substring(0, + // getProperty(mode + + // "Request").lastIndexOf('.')) + ".Signature.xml"; + // fileSerializer = new XMLSerializer(new FileOutputStream(signatureFile), + // format); + // fileSerializer.serialize(signature); + // } + + } +} \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/TemplateReplaces.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/TemplateReplaces.java new file mode 100644 index 0000000..7caf422 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/TemplateReplaces.java @@ -0,0 +1,172 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors; + +/** + * This class contains String constants that are frequently used in various + * connector templates to fill in the data into the templates. + * + * @author wprinz + */ +public final class TemplateReplaces +{ + /** + * The placeholder text in the template to be replaced by the keybox + * identifier. + */ + public static final String KEYBOX_IDENTIFIER_REPLACE = "KeyboxIdentifierReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the mime type. + */ + public static final String MIME_TYPE_REPLACE = "MimeTypeReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the XML content of + * another template. + */ + public static final String XML_CONTENT_REPLACE = "XMLContentReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the cert alg. + */ + public static final String CERT_ALG_REPLACE = "CertAlgReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the digest value of + * the signed data. + */ + public static final String DIGEST_VALUE_SIGNED_DATA_REPLACE = "DigestValueSignedDataReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the signature value. + */ + public static final String SIGNATURE_VALUE_REPLACE = "SignatureValueReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the X.509 + * certificate. + */ + public static final String X509_CERTIFICATE_REPLACE = "X509CertificateReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the signing time. + */ + public static final String SIGNING_TIME_REPLACE = "SigningTimeReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the certificate + * digest. + */ + public static final String DIGEST_VALUE_CERTIFICATE_REPLACE = "DigestValueX509CertificateReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the issuer name. + */ + public static final String X509_ISSUER_NAME_REPLACE = "X509IssuerNameReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the serial number. + */ + public static final String X509_SERIAL_NUMBER_REPLACE = "X509SerialNumberReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the signed + * properties digest. + */ + public static final String DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE = "DigestValueSignedPropertiesReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the SigDataRef. + */ + public static final String SIG_DATA_REF_REPLACE = "SigDataRefReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the EtsiDataRef. + */ + public static final String ETSI_DATA_REF_REPLACE = "EtsiDataRefReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the SigDataObjURI. + */ + public static final String SIG_DATA_OBJ_URI_REPLACE = "SigDataObjURIReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the EtsiDataObjURI. + */ + public static final String ETSI_DATA_OBJ_URI_REPLACE = "EtsiDataObjURIReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the SigId. + */ + public static final String SIG_ID_REPLACE = "SigIdReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the key identifier. + */ + public static final String KEY_IDENTIFIER_REPLACE = "KeyIdentifierReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the LocRefContent + * URL. + */ + public static final String LOC_REF_CONTENT_REPLACE = "LocRefContentReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the trust profile ID. + */ + public static final String TRUST_PROFILE_ID_REPLACE = "TrustProfileIDReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the return hash input data element. + */ + public static final String RETURN_HASH_INPUT_DATA_REPLACE = "ReturnHashInputDataReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the dateTime element. + */ + public static final String DATE_TIME_REPLACE = "DateTimeReplace"; // $NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the Base64 content. + */ + public static final String BASE64_CONTENT_REPLACE = "Base64ContentReplace"; //$NON-NLS-1$ + +//dferbas + /** + * The placeholder text in the template to be replaced by the digest method for data. + */ + public static final String DATA_DIGEST_REPLACE = "DataDigestReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the digest method for properties. + */ + public static final String PROPERTIES_DIGEST_REPLACE = "PropertiesDigestReplace"; //$NON-NLS-1$ + + /** + * The placeholder text in the template to be replaced by the digest method for cert. + */ + public static final String CERT_DIGEST_REPLACE = "CertDigestReplace"; //$NON-NLS-1$ + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java new file mode 100644 index 0000000..64306ab --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUHelper.java @@ -0,0 +1,695 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Properties; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmMapper; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.commons.Constants; +import at.gv.egiz.pdfas.api.internal.LocalBKUParams; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.exceptions.external.ExternalErrorException; +import at.gv.egiz.pdfas.impl.input.helper.DataSourceHelper; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Contains static helper methods used by the BKU Connectors. + * + * @author wprinz + */ +public final class BKUHelper +{ + + private static final Pattern ALLOWED_SL_RESPONSE_PATTERN = Pattern.compile("^.*<[\\w]*:?(CreateXMLSignatureResponse|VerifyXMLSignatureResponse)[^>]*>(.*).*$", Pattern.DOTALL); + + /** + * The log. + */ + private static Log log = LogFactory.getLog(BKUHelper.class); + + /** + * Encodes the given SignatureData to a valid Base64Content. + * + *

+ * The data is Base64 encoded. If the mime-type suggests that the data is + * binary, it is Base64 encoded for a second time. + *

+ * + * @param data + * The data to be converted to a valid Base64 content. + * @return Returns the Base64 content. + */ + public static String prepareBase64Content(SignatureData data) + { + // PERF: base64 encoding needs byte array + byte [] d = DataSourceHelper.convertDataSourceToByteArray(data.getDataSource()); + + String base64 = CodingHelper.encodeBase64(d); + if (data.getMimeType().equals("application/pdf")) //$NON-NLS-1$ + { + log.debug("The data is application/pdf - so the binary data is Base64 encoded."); //$NON-NLS-1$ + base64 = CodingHelper.encodeUTF8AsBase64(base64); + } + return base64; + + } + + /** + * Prepares the enveloping data. + *

+ * This is useful for building the hash. + *

+ * + * @param data + * The data to be prepared. + * @return Returns the prepared data. + */ + public static byte[] prepareEnvelopingData(SignatureData data) + { + // PERF: prepareEnvelopingData needs byte array + byte[] enc = DataSourceHelper.convertDataSourceToByteArray(data.getDataSource()); + + if (data.getMimeType().equals("application/pdf")) //$NON-NLS-1$ + { + log.debug("The data is application/pdf - so the binary data is Base64 encoded."); //$NON-NLS-1$ + String base64 = CodingHelper.encodeBase64(enc); + try + { + enc = base64.getBytes("US-ASCII"); //$NON-NLS-1$ + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + throw new RuntimeException("Very Strange: US-ASCII encoding not supported???", e); //$NON-NLS-1$ + } + } + return enc; + } + + /** + * Checks the response xml for an error description and if found throws an + * appropriate exception. + * + * @param response_string + * The response xml. + * @throws ConnectorException + * f.e. + */ + public static void checkResponseForError(String response_string) throws ConnectorException + { + if (StringUtils.isEmpty(response_string)) { + throw new ConnectorException(ErrorCode.UNABLE_TO_RECEIVE_SUITABLE_RESPONSE, "No suitable response received."); + } + log.debug("Checking response for error: " + response_string); + Pattern erc_p_s = Pattern.compile("<[\\w]*:?ErrorCode>"); //$NON-NLS-1$ + Pattern erc_p_e = Pattern.compile(""); //$NON-NLS-1$ + Matcher erc_m_s = erc_p_s.matcher(response_string); + Matcher erc_m_e = erc_p_e.matcher(response_string); + + if (erc_m_s.find() && erc_m_e.find()) + { + log.error("Found error in response: " + response_string); //$NON-NLS-1$ + + Pattern erm_p_s = Pattern.compile("<[\\w]*:?Info>"); //$NON-NLS-1$ + Pattern erm_p_e = Pattern.compile(""); //$NON-NLS-1$ + Matcher erm_m_s = erm_p_s.matcher(response_string); + Matcher erm_m_e = erm_p_e.matcher(response_string); + String error_code = response_string.substring(erc_m_s.end(), erc_m_e.start()); + String error_mess = null; + if (erm_m_s.find() && erm_m_e.find()) + { + error_mess = response_string.substring(erm_m_s.end(), erm_m_e.start()); + } + throw new ExternalErrorException(error_code, error_mess); + } + log.debug("No error found. Assuring that CreateXMLSignatureResponse or VerifyXMLSignatureResponse elements are available."); + + // assure that a CreateXMLSignatureResponse or a VerifyXMLSignatureResponse is available + Matcher slMatcher = ALLOWED_SL_RESPONSE_PATTERN.matcher(response_string); + if (!slMatcher.matches()) { + throw new ConnectorException(ErrorCode.UNABLE_TO_RECEIVE_SUITABLE_RESPONSE, "No suitable response received: " + response_string); + } + + } + + /** + * This method parses the BKU-Response string. + * + *

+ * It separates the SignatureValue, X509IssuerName, SigningTime, + * X509SerialNumber, X509Certificate, CertDigest, DigestValue and the + * signation id-s. If the X509Certificate is extracted it would be stored in + * the certificates directory. + *

+ * + * @param xmlResponse + * The response string. + * @return Returns the parsed signature object holding the data. + * + * @throws ConnectorException + * ErrorCode (303, 304) + * @see SignatureObject + * @see CodingHelper + * @see X509Cert + */ + public static SignSignatureObject parseCreateXMLResponse(String xmlResponse, + IdFormatter id_formatter, ConnectorEnvironment environment) throws ConnectorException + { + if (log.isDebugEnabled()) { + log.debug("xmlResponse = " + xmlResponse); + } + Pattern sig_val_p_s = Pattern.compile("<[\\w]*:?SignatureValue>"); //$NON-NLS-1$ + Pattern sig_val_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName>"); //$NON-NLS-1$ + Pattern iss_nam_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern sig_tim_p_s = Pattern.compile("<[\\w]*:?SigningTime>"); //$NON-NLS-1$ + Pattern sig_tim_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern ser_num_p_s = Pattern.compile("<[\\w]*:?X509SerialNumber>"); //$NON-NLS-1$ + Pattern ser_num_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern sig_cer_p_s = Pattern.compile("<[\\w]*:?X509Certificate>"); //$NON-NLS-1$ + Pattern sig_cer_p_e = Pattern.compile(""); //$NON-NLS-1$ + + // Pattern sig_cer_d_p_s = Pattern.compile("<[\\w]*:?CertDigest>"); + // //$NON-NLS-1$ + // Pattern sig_cer_d_p_e = Pattern.compile(""); + // //$NON-NLS-1$ + // Pattern dig_val_p_s = Pattern.compile("<[\\w]*:?DigestValue>"); + // //$NON-NLS-1$ + // Pattern dig_val_p_e = Pattern.compile(""); + // //$NON-NLS-1$ + + Matcher sig_val_m_s = sig_val_p_s.matcher(xmlResponse); + Matcher sig_val_m_e = sig_val_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher sig_tim_m_s = sig_tim_p_s.matcher(xmlResponse); + Matcher sig_tim_m_e = sig_tim_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + Matcher sig_cer_m_s = sig_cer_p_s.matcher(xmlResponse); + Matcher sig_cer_m_e = sig_cer_p_e.matcher(xmlResponse); + + // Matcher sig_cer_d_m_s = sig_cer_d_p_s.matcher(xmlResponse); + // Matcher sig_cer_d_m_e = sig_cer_d_p_e.matcher(xmlResponse); + // Matcher dig_val_m_s = dig_val_p_s.matcher(xmlResponse); + // Matcher dig_val_m_e = dig_val_p_e.matcher(xmlResponse); + + // SignatureValue + String sig_val = null; + if (sig_val_m_s.find() && sig_val_m_e.find()) + { + sig_val = removeAllWhitespace(xmlResponse.substring(sig_val_m_s.end(), sig_val_m_e.start())); + } + log.debug("sig_val = " + sig_val); //$NON-NLS-1$ + + // X509IssuerName + String iss_nam = null; + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + } + log.debug("iss_nam = " + iss_nam); //$NON-NLS-1$ + + // X509SerialNumber + String ser_num = null; + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + ser_num = removeAllWhitespace(xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start())); + } + log.debug("ser_num = " + ser_num); //$NON-NLS-1$ + + // SigningTime + String sig_tim = null; + if (sig_tim_m_s.find() && sig_tim_m_e.find()) + { + sig_tim = xmlResponse.substring(sig_tim_m_s.end(), sig_tim_m_e.start()); + } + log.debug("sig_tim = " + sig_tim); //$NON-NLS-1$ + + // CertDigest + // if (sig_cer_d_m_s.find() && sig_cer_d_m_e.find()) + // { + // String cert_digest = xmlResponse.substring(sig_cer_d_m_s.end(), + // sig_cer_d_m_e.start()); + // if (dig_val_m_s.find() && dig_val_m_e.find()) + // { + // sig_dig = cert_digest.substring(dig_val_m_s.end(), dig_val_m_e.start()); + // //sigObj.setX509CertificateDigest(sig_dig); + // } + // } + + // X509Certificate + X509Certificate cert = null; + if (sig_cer_m_s.find() && sig_cer_m_e.find()) + { + String sig_cer = removeAllWhitespace(xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start())); + + try + { + byte[] der = CodingHelper.decodeBase64(sig_cer); + ByteArrayInputStream bais = new ByteArrayInputStream(der); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$ + cert = (X509Certificate) cf.generateCertificate(bais); + bais.close(); + } + catch (UnsupportedEncodingException e) + { + log.error(e); + throw new ConnectorException(300, e); + } + catch (CertificateException e) + { + log.error(e); + throw new ConnectorException(300, e); + } + catch (IOException e) + { + log.error(e); + throw new ConnectorException(300, e); + } + } + log.debug("X509Certificate = " + cert); //$NON-NLS-1$ + + if (log.isDebugEnabled()) + { + + String cert_iss = cert.getIssuerDN().getName(); + log.debug("certificate's issuer = " + cert_iss); //$NON-NLS-1$ + log.debug("response's issuer = " + iss_nam); //$NON-NLS-1$ + log.debug("issuer matches = " + cert_iss.equals(iss_nam)); //$NON-NLS-1$ + log.debug("ser number matches = " + cert.getSerialNumber().toString().equals(ser_num)); //$NON-NLS-1$ + } + + // extract Subject Name from X509Certificate + // if (sig_cer_m_s.find() && sig_cer_m_e.find()) + // { + // sig_cer = xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start()); + // sig_cer = sig_cer.replaceAll("\\s", ""); + // //sigObj.setX509Certificate(sig_cer); + // X509Cert cert = X509Cert.initByString(sig_cer); + // if (cert.isX509Cert()) + // { + // //sigObj.setX509Certificate(cert.getCertString()); + // String serial_num = cert.getSerialNumber(); + // String subject_name = cert.getSubjectName(); + // if (!ser_num.equals(serial_num)) + // { + // ConnectorException se = new ConnectorException(303, "Serialnumber of + // certificate and tag X509SerialNumber differs!"); + // throw se; + // } + // //sigObj.setSignationName(subject_name); + // } + // } + + // extract Signature Id's + String[] ids = new String[5]; + ids[0] = extractId(xmlResponse, "signature-"); //$NON-NLS-1$ + ids[1] = extractId(xmlResponse, "signed-data-reference-"); //$NON-NLS-1$ + ids[2] = extractId(xmlResponse, "signed-data-object-"); //$NON-NLS-1$ + ids[3] = extractId(xmlResponse, "etsi-data-reference-"); //$NON-NLS-1$ + ids[4] = extractId(xmlResponse, "etsi-data-object-"); //$NON-NLS-1$ + + String algs = AlgorithmSuiteUtil.extractAlgorithmSuiteString(xmlResponse); + + SignSignatureObject so = new SignSignatureObject(); + so.date = sig_tim; + so.issuer = iss_nam; + so.signatureValue = sig_val; + so.x509Certificate = cert; + + AlgorithmSuiteObject suite = new AlgorithmSuiteObject(algs, false); + so.sigAlgorithm = AlgorithmMapper.getUri(suite.getSignatureMethod()); + + String defaultCertAlg = environment.getDefaultAlgForCert(cert); + + if (AlgorithmSuiteUtil.isDefaultCertAlg(algs, defaultCertAlg)) { + // do not embed default alg + algs = null; + } + + String final_ids = id_formatter.formatIds(ids, algs); + so.id = final_ids; + + return so; + } + + /** + * Removes all whitespaces ("\\s") from the String. + * + * @param str + * The String. + * @return The String with all whitespaces removed. + */ + public static String removeAllWhitespace(String str) + { + return str.replaceAll("\\s", ""); //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * This emthod extracts id-values from a text. The id is given by the name. + * + * @param text + * the id-value that should extract from + * @param name + * the id-key + * @return the value of the given key in the text + */ + private static String extractId(String text, String name) + { + String id = null; + // fatal bug; fixed by tknall (start) + int startOfName = text.indexOf(name); + if (startOfName == -1) { + log.debug("No id for name \"" + name + "\" extracted. Probably detached signature. Returning empty id: \"\""); //$NON-NLS-1$ + return ""; + } + // stop + + int start_idx = startOfName + name.length(); + int end_idx = text.indexOf("\"", start_idx); //$NON-NLS-1$ + + final int quot_end_idx = end_idx; + final int squot_end_idx = text.indexOf("'", start_idx); //$NON-NLS-1$ + end_idx = Math.min(quot_end_idx, squot_end_idx); + id = text.substring(start_idx, end_idx); + if (log.isDebugEnabled()) + { + log.debug("extract id:" + name + id); //$NON-NLS-1$ + } + return id; + } + + /** + * This method parses the verify response string and return a + * SignatureResponse object. The SignatureResponse object is filled out by the + * response values from the BKU-response. + * + * @param xmlResponse + * the response values from the BKU-verify request + * @return SignatureResponse object + * @see SignatureResponse + */ + public static SignatureResponse parseVerifyXMLResponse(String xmlResponse) + { + log.debug("parseVerifyXMLResponse:"); //$NON-NLS-1$ + + Pattern sub_nam_p_s = Pattern.compile(""); //$NON-NLS-1$ + Pattern sub_nam_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern iss_nam_p_s = Pattern.compile(""); //$NON-NLS-1$ + Pattern iss_nam_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern ser_num_p_s = Pattern.compile(""); //$NON-NLS-1$ + Pattern ser_num_p_e = Pattern.compile(""); //$NON-NLS-1$ + + Pattern sig_chk_p_s = Pattern.compile("<[\\w]*:?SignatureCheck>"); //$NON-NLS-1$ + Pattern sig_chk_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern man_chk_p_s = Pattern.compile("<[\\w]*:?SignatureManifestCheck>"); //$NON-NLS-1$ + Pattern man_chk_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern cer_chk_p_s = Pattern.compile("<[\\w]*:?CertificateCheck>"); //$NON-NLS-1$ + Pattern cer_chk_p_e = Pattern.compile(""); //$NON-NLS-1$ + + // [tknall] start qualified certificate + Pattern cert_qualified_p = Pattern.compile("<[\\w]*:?QualifiedCertificate/>"); //$NON-NLS-1$ + Matcher cert_qualified_m = cert_qualified_p.matcher(xmlResponse); + // [tknall] stop qualified certificate + + Pattern code_p_s = Pattern.compile("<[\\w]*:?Code>"); //$NON-NLS-1$ + Pattern code_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern info_p_s = Pattern.compile("<[\\w]*:?Info>"); //$NON-NLS-1$ + Pattern info_p_e = Pattern.compile(""); //$NON-NLS-1$ + + Pattern cert_p_s = Pattern.compile(""); //$NON-NLS-1$ + Pattern cert_p_e = Pattern.compile(""); //$NON-NLS-1$ + + Matcher sub_nam_m_s = sub_nam_p_s.matcher(xmlResponse); + Matcher sub_nam_m_e = sub_nam_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + + Matcher sig_chk_m_s = sig_chk_p_s.matcher(xmlResponse); + Matcher sig_chk_m_e = sig_chk_p_e.matcher(xmlResponse); + Matcher man_chk_m_s = man_chk_p_s.matcher(xmlResponse); + Matcher man_chk_m_e = man_chk_p_e.matcher(xmlResponse); + Matcher cer_chk_m_s = cer_chk_p_s.matcher(xmlResponse); + Matcher cer_chk_m_e = cer_chk_p_e.matcher(xmlResponse); + + Matcher cert_m_s = cert_p_s.matcher(xmlResponse); + Matcher cert_m_e = cert_p_e.matcher(xmlResponse); + + Pattern hash_data_p_s = Pattern.compile(""); //$NON-NLS-1$ + Pattern hash_data_p_e = Pattern.compile(""); //$NON-NLS-1$ + Matcher hash_data_m_s = hash_data_p_s.matcher(xmlResponse); + Matcher hash_data_m_e = hash_data_p_e.matcher(xmlResponse); + + + SignatureResponse sig_res = new SignatureResponse(); + + // public authority (tknall) + Pattern publicAuthority_p = Pattern.compile(""); + Matcher publicAuthority_m = publicAuthority_p.matcher(xmlResponse); + sig_res.setPublicAuthority(false); + sig_res.setPublicAuthorityCode(null); + if (publicAuthority_m.find()) { + sig_res.setPublicAuthority(true); + } else { + Matcher publicAuthority_m_s = Pattern.compile("").matcher(xmlResponse); + Matcher publicAuthority_m_e = Pattern.compile("").matcher(xmlResponse); + if (publicAuthority_m_s.find() && publicAuthority_m_e.find()) { + sig_res.setPublicAuthority(true); + String codePart = xmlResponse.substring(publicAuthority_m_s.end(), publicAuthority_m_e.start()); + Matcher code_m_s = code_p_s.matcher(codePart); + Matcher code_m_e = code_p_e.matcher(codePart); + if (code_m_s.find() && code_m_e.find()) { + String code = codePart.substring(code_m_s.end(), code_m_e.start()); + sig_res.setPublicAuthorityCode(code); + } + } + } + + // [tknall] start qualified certificate + sig_res.setQualifiedCertificate(cert_qualified_m.find()); + // [tknall] stop qualified certificate + + if (hash_data_m_s.find() && hash_data_m_e.find()) + { + String hashInputData = xmlResponse.substring(hash_data_m_s.end(), hash_data_m_e.start()); + + Pattern b64_p_s = Pattern.compile(""); //$NON-NLS-1$ + Pattern b64_p_e = Pattern.compile(""); //$NON-NLS-1$ + Matcher b64_m_s = b64_p_s.matcher(hashInputData); + Matcher b64_m_e = b64_p_e.matcher(hashInputData); + + boolean hashInputDataFound = b64_m_s.find() && b64_m_e.find(); + + String b64 = hashInputDataFound ? hashInputData.substring(b64_m_s.end(), b64_m_e.start()) : ""; + + sig_res.setHashInputData(b64); + } + + if (sub_nam_m_s.find() && sub_nam_m_e.find()) + { + String sub_nam = xmlResponse.substring(sub_nam_m_s.end(), sub_nam_m_e.start()); + sig_res.setX509SubjectName(sub_nam); + } + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + String iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + sig_res.setX509IssuerName(iss_nam); + } + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + String ser_num = xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start()); + sig_res.setX509SerialNumber(ser_num); + } + if (sig_chk_m_s.find() && sig_chk_m_e.find()) + { + String sig_chk = xmlResponse.substring(sig_chk_m_s.end(), sig_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(sig_chk); + Matcher code_m_e = code_p_e.matcher(sig_chk); + Matcher info_m_s = info_p_s.matcher(sig_chk); + Matcher info_m_e = info_p_e.matcher(sig_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = sig_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = sig_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setSignatureCheckInfo(info); + } + } + if (man_chk_m_s.find() && man_chk_m_e.find()) + { + String man_chk = xmlResponse.substring(man_chk_m_s.end(), man_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(man_chk); + Matcher code_m_e = code_p_e.matcher(man_chk); + Matcher info_m_s = info_p_s.matcher(man_chk); + Matcher info_m_e = info_p_e.matcher(man_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = man_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setSignatureManifestCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = man_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setSignatureManifestCheckInfo(info); + } + } + if (cer_chk_m_s.find() && cer_chk_m_e.find()) + { + String cer_chk = xmlResponse.substring(cer_chk_m_s.end(), cer_chk_m_e.start()); + Matcher code_m_s = code_p_s.matcher(cer_chk); + Matcher code_m_e = code_p_e.matcher(cer_chk); + Matcher info_m_s = info_p_s.matcher(cer_chk); + Matcher info_m_e = info_p_e.matcher(cer_chk); + if (code_m_s.find() && code_m_e.find()) + { + String code = cer_chk.substring(code_m_s.end(), code_m_e.start()); + sig_res.setCertificateCheckCode(code); + } + if (info_m_s.find() && info_m_e.find()) + { + String info = cer_chk.substring(info_m_s.end(), info_m_e.start()); + sig_res.setCertificateCheckInfo(info); + } + } + if (cert_m_s.find() && cert_m_e.find()) + { + String cert_string = xmlResponse.substring(cert_m_s.end(), cert_m_e.start()); + + X509Cert resp_cert = X509Cert.initByString(cert_string); + sig_res.setCertificate(resp_cert); + } + + log.debug("parseVerifyXMLResponse finished."); //$NON-NLS-1$ + return sig_res; + } + + public static String formDateTimeElement(Date verificationTime) + { + return formDateTimeElement(verificationTime, null); + } + + public static String formDateTimeElement(Date verificationTime, String namespace) + { + String nsPrefix = StringUtils.isBlank(namespace) ? "" : (namespace + ":"); + + String dateTimeElement = ""; + if (verificationTime != null) + { + log.debug("VerificationTime = " + verificationTime); + + DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("UTC")); + String dateTime = df.format(verificationTime) + "Z"; + log.debug("DateTime (VerificationTime in UTC) = " + dateTime); + + dateTimeElement = "<" + nsPrefix + "DateTime>" + dateTime + ""; + }; + return dateTimeElement; + } + + public static String getBKUIdentifier(Properties parsedResponseProperties) { + + // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.browser + String bkuServerHeader = parsedResponseProperties.getProperty(BKUPostConnection.BKU_SERVER_HEADER_KEY); + + // http://www.buergerkarte.at/konzept/securitylayer/spezifikation/aktuell/bindings/bindings.html#http.kodierung.response.dataurl + String bkuUserAgentHeader = parsedResponseProperties.getProperty(BKUPostConnection.BKU_USER_AGENT_HEADER_KEY); + + String bkuSignatureLayout = parsedResponseProperties.getProperty(BKUPostConnection.BKU_SIGNATURE_LAYOUT_HEADER_KEY); + + return getBKUIdentifier(bkuServerHeader, bkuUserAgentHeader, bkuSignatureLayout); + } + + public static String getBKUIdentifier(String bkuServerHeader, String bkuUserAgentHeader, String bkuSignatureLayout) { + + log.debug("BKU response header \"user-agent\": " + bkuUserAgentHeader); + log.debug("BKU response header \"server\": " + bkuServerHeader); + log.trace("BKU response header \"" + Constants.BKU_HEADER_SIGNATURE_LAYOUT + "\": " + bkuSignatureLayout); + + String result = null; + + if (bkuServerHeader != null) { + result = bkuServerHeader; + } else if (bkuUserAgentHeader != null) { + result = bkuUserAgentHeader; + } else { + log.warn("Unable to find any BKU identifier (neither header value \"user-agent\" nor \"server\".)"); + } + + if (bkuSignatureLayout != null && result != null) { + log.debug("BKU response header \"" + Constants.BKU_HEADER_SIGNATURE_LAYOUT + "\" found."); + String signatureLayoutData = " " + Constants.BKU_HEADER_SIGNATURE_LAYOUT + "/" + bkuSignatureLayout; + if (!result.endsWith(signatureLayoutData)) { + log.debug("Appending signature layout value \"" + bkuSignatureLayout + "\" to bku identifier."); + result += signatureLayoutData; + } else { + log.debug("Signature layout already encoded in server/user-agent header."); + } + } + + if (result != null) { + log.debug("Returning BKU identifier \"" + result + "\""); + } else { + log.debug("Returning null BKU identifier."); + } + + return result; + } + + public static String getBKUIdentifier(LocalBKUParams bkuParams) { + return getBKUIdentifier(bkuParams.getServer(), bkuParams.getUserAgent(), bkuParams.getSignatureLayout()); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUPostConnection.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUPostConnection.java new file mode 100644 index 0000000..04b817f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/BKUPostConnection.java @@ -0,0 +1,179 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.multipart.FilePart; +import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; +import org.apache.commons.httpclient.methods.multipart.Part; +import org.apache.commons.httpclient.methods.multipart.PartSource; +import org.apache.commons.httpclient.methods.multipart.StringPart; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.api.commons.Constants; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; + +/** + * Helper class with methods that use the Apache Https Client to send HTTP + * requests. + * + * @author wprinz + */ +public final class BKUPostConnection +{ + /** + * The response Properties key that identifies the response string. + */ + public static final String RESPONSE_STRING_KEY = "response_string"; //$NON-NLS-1$ + + /** + * The response Properties key that identifies the BKU Server header. + */ + public static final String BKU_SERVER_HEADER_KEY = "BKU-Server-Header"; //$NON-NLS-1$ + + /** + * The response property that declares the signature layout being applied. + */ + public static final String BKU_SIGNATURE_LAYOUT_HEADER_KEY = "BKU-Signature-Layout"; //$NON-NLS-1$ + + /** + * The response Properties key that identifies the BKU User-Agent header. + */ + public static final String BKU_USER_AGENT_HEADER_KEY = "BKU-User-Agent-Header"; //$NON-NLS-1$ + + /** + * The log. + */ + private static Log log = LogFactory.getLog(BKUPostConnection.class); + + /** + * Sends a multipart/form-data HTTP Post request to the given URL. + * + * @param url The url the request is directed to. + * @param request The request XML, which will be the UTF-8 text/xml first part of the message. + * @param data The binary second part of the message. + * @return Returns the response properties which, among others, contain the response String. + * @throws HttpException + * @throws IOException + */ + public static Properties doPostRequestMultipart(String url, String request, + final SignatureData data) throws HttpException, IOException + { + log.debug("doPostRequestMultipart:"); //$NON-NLS-1$ + + StringPart xmlpart = new StringPart("XMLRequest", request, "UTF-8"); //$NON-NLS-1$//$NON-NLS-2$ + + // TODO this is a BUG in BKU that doesn't allow the Content-Type header + xmlpart.setContentType(null); + xmlpart.setTransferEncoding(null); + // BKU 2.7.4 can't handle the Content-Type Header for the XML + // xmlpart.setContentType("text/xml"); + // xmlpart.setTransferEncoding(null); + + final String filename = data.getMimeType().equals("application/pdf") ? "myfile.pdf" : "myfile.txt"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + PartSource ps = new PartSource() { + public InputStream createInputStream() throws IOException + { + return data.getDataSource().createInputStream(); + } + + public String getFileName() + { + return filename; + } + + public long getLength() + { + return data.getDataSource().getLength(); + } + }; + //ByteArrayPartSource baps = new ByteArrayPartSource(filename, data.getData()); + FilePart filepart = new FilePart("fileupload", ps); //$NON-NLS-1$ + filepart.setContentType(data.getMimeType()); + + // not really needed since external referenced data has to be taken "as-is" (binary stream) for + // digest calculation, so neither content type nor charset is relevant + filepart.setCharSet(data.getCharacterEncoding()); + + Part[] parts = { xmlpart, filepart }; + + HttpMethodParams method_params = new HttpMethodParams(); + method_params.setContentCharset("UTF-8"); //$NON-NLS-1$ + + PostMethod post_method = new PostMethod(url); + post_method.setParams(method_params); + + MultipartRequestEntity mprqe = new MultipartRequestEntity(parts, post_method.getParams()); + post_method.setRequestEntity(mprqe); + + HttpClient http_client = new HttpClient(); + + int method_response = http_client.executeMethod(post_method); + log.debug("method_response = " + method_response); //$NON-NLS-1$ + + Properties response_properties = new Properties(); + + if (log.isDebugEnabled()) + { + Header[] response_headers = post_method.getResponseHeaders(); + for (int i = 0; i < response_headers.length; i++) + { + log.debug(" response_header[" + i + "]: name = " + response_headers[i].getName() + ", value = " + response_headers[i].getValue()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + } + Header server_header = post_method.getResponseHeader("Server"); //$NON-NLS-1$ + if (server_header != null) { + response_properties.setProperty(BKU_SERVER_HEADER_KEY, server_header.getValue()); + } else { + log.warn("BKU response header \"Server\" is empty."); + } + + Header signatureLayoutHeader = post_method.getResponseHeader(Constants.BKU_HEADER_SIGNATURE_LAYOUT); //$NON-NLS-1$ + if (signatureLayoutHeader != null) { + response_properties.setProperty(BKU_SIGNATURE_LAYOUT_HEADER_KEY, signatureLayoutHeader.getValue()); + } + + String responseCharSet = post_method.getResponseCharSet(); + if (!"UTF8".equalsIgnoreCase(responseCharSet) && !"UTF-8".equalsIgnoreCase(responseCharSet)) { + log.warn("BKU response charset is not UTF-8!"); //$NON-NLS-1$ + } + String response_string = post_method.getResponseBodyAsString(); + + response_properties.setProperty(RESPONSE_STRING_KEY, response_string); + + log.debug("doPostRequestMultipart finished."); //$NON-NLS-1$ + + return response_properties; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java new file mode 100644 index 0000000..a8de41e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/DetachedBKUConnector.java @@ -0,0 +1,823 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import java.security.cert.X509Certificate; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.DetachedLocRefMOAConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.MOASoapWithAttachmentConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.LocRefDetachedMOCCAConnector; +import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandlerFactory; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Connects to the BKU using the detached multipart/formdata requests. + * + *

+ * This feature is available since BKU version 2.7.4. + *

+ * + * @author wprinz + */ +public class DetachedBKUConnector implements Connector, LocalConnector +{ +//23.11.2010 changed by exthex - added reconstructXMLDsig method and moved xmldsig creation to chooseAndCreateXMLDsig method + + /** + * The log. + */ + private static Log log = LogFactory.getLog(DetachedBKUConnector.class); + + /** + * The connector parameters. + */ + protected ConnectorParameters params = null; + + /** + * The environemnt configuration of this connector containing templates and + * other configurable elements. + */ + protected Environment environment = null; + + /** + * Constructor that builds the configuration environment for this connector + * according to the given profile. + * + *

+ * If confuguration parameters are not defined on that profile, the default + * parameters defined in the configuration are used. + *

+ * + * @param connectorParameters + * The connectot parameters. + * @throws ConnectorException + * f.e. + */ + public DetachedBKUConnector(ConnectorParameters connectorParameters, String loc_ref_content) throws ConnectorException + { + this.params = connectorParameters; + this.environment = new Environment(this.params.getProfileId(), loc_ref_content); + } + + /** + * Prepares the sign request xml to be sent using the sign request template. + * + * @param data + * The SignatureData. + * @return Returns the sign request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareSignRequest(SignatureData data) throws ConnectorException + { + log.debug("prepareSignRequestDetached:"); //$NON-NLS-1$ + + String sign_request_template = this.environment.getSignRequestTemplate(); + + String sign_keybox_identifier = this.environment.getSignKeyboxIdentifier(); + String mime_type = data.getMimeType(); + String loc_ref_content = this.environment.getLocRefContent(); + + if (log.isDebugEnabled()) + { + log.debug("sign keybox identifier = " + sign_keybox_identifier); //$NON-NLS-1$ + log.debug("mime type = " + mime_type); //$NON-NLS-1$ + log.debug("loc_ref_content = " + loc_ref_content); //$NON-NLS-1$ + } + + String sign_request_xml = sign_request_template.replaceFirst(TemplateReplaces.KEYBOX_IDENTIFIER_REPLACE, sign_keybox_identifier); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, mime_type); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, loc_ref_content); + + log.debug("sign_request_xml = " + sign_request_xml); + log.debug("prepareSignRequestDetached finished."); //$NON-NLS-1$ + return sign_request_xml; + } + + /** + * Analyzes the sign response xml and extracts the signature data. + * + * @param response_properties + * The response properties containing the response String and + * transport related information. + * @return Returns the extracted data encapsulated in a SignatureObject. + * @throws ConnectorException + * f.e. + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeSignResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + String bkuIdentifier = BKUHelper.getBKUIdentifier(response_properties); + log.debug("BKU identifier: " + (bkuIdentifier != null ? ("\"" + bkuIdentifier + "\"") : "n/a")); + + SignatureLayoutHandler sigLayout; + try { + sigLayout = SignatureLayoutHandlerFactory.getSignatureLayoutHandlerInstance(bkuIdentifier); + } catch (SettingsException e) { + throw new ConnectorException(e.getErrorCode(), e.getMessage()); + } + + BKUHelper.checkResponseForError(response_string); + + SignSignatureObject so = sigLayout.parseCreateXMLSignatureResponse(response_string, this.environment); + + so.response_properties = response_properties; + + log.debug("analyzeSignResponse finished."); //$NON-NLS-1$ + return so; + } + + public static String[] parseSigIds(String sig_ids) + { + if (sig_ids == null || sig_ids.length() == 0) + { + return null; + } + + // int index = sig_ids.indexOf(PdfAS.IDS); + // if (index < 0) + // { + // return null; + // } + // sig_ids = sig_ids.substring(index + PdfAS.IDS.length()); + // + // if (sig_ids == null || sig_ids.length() == 0) + // { + // return null; + // } + + String[] ids_str = sig_ids.split("@"); + + String etsi_string = null; + if (ids_str.length == 3) + { + etsi_string = ids_str[0]; + String[] rest_ids = new String[] { ids_str[1], ids_str[2] }; + ids_str = rest_ids; + } + + String base = ids_str[0]; + String[] ids = ids_str[1].split("-"); + String[] real_ids = new String[6]; // the last one contains the etsi string + real_ids[0] = base + "-" + ids[0]; + real_ids[1] = "0-" + base + "-" + ids[1]; + real_ids[2] = "0-" + base + "-" + ids[2]; + real_ids[3] = "0-" + base + "-" + ids[3]; + real_ids[4] = "0-" + base + "-" + ids[4]; + real_ids[5] = etsi_string; + + if (log.isDebugEnabled()) + { + for (int id_idx = 0; id_idx < real_ids.length; id_idx++) + { + log.debug("real_ids[" + id_idx + "] = " + real_ids[id_idx]); + } + } + + return real_ids; + } + + /** + * Sends the request and data to the given URL. + * + *

+ * This method mainly handles communication exceptions. The actual send work + * is done by doPostRequestMultipart. + *

+ * + * @see BKUPostConnection#doPostRequestMultipart(String, String, + * SignatureData) + * + * @param url + * The URL to send the request to. + * @param request_string + * The request XML. + * @param data + * The data. + * @return Returns the response properties containing among others the + * response XML. + * @throws ConnectorException + * f.e. + */ + protected Properties sendRequest(String url, String request_string, + SignatureData data) throws ConnectorException + { + try + { + Properties response_properties = BKUPostConnection.doPostRequestMultipart(url, request_string, data); + return response_properties; + } + catch (Exception e) + { + ConnectorException se = new ConnectorException(320, e); + throw se; + } + } + + /** + * Performs a sign. + * + * @param data + * The data to be signed. + * @return Returns the signature object containing the signature data. + * @throws ConnectorException + * f.e. + */ + public SignSignatureObject doSign(SignatureData data) throws ConnectorException + { + log.debug("doSign:"); //$NON-NLS-1$ + + String sign_request_xml = prepareSignRequest(data); + log.debug("sign_request_xml = " + sign_request_xml); //$NON-NLS-1$ + + String url = this.environment.getSignURL(); + Properties response_properties = sendRequest(url, sign_request_xml, data); + + SignSignatureObject sso = analyzeSignResponse(response_properties); + + sso.response_properties = response_properties; + + log.debug("doSign finished."); //$NON-NLS-1$ + return sso; + } + + /** + * Performs a verification. + * + * @param data + * The data to be verified. + * @param so + * The signature object with the signature information. + * @return Returns the SignatureResponse with the result of the verification. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException + { + log.debug("doVerify:"); //$NON-NLS-1$ + + String verify_request_xml = prepareVerifyRequest(data, so, dsig); + log.debug("verify_request_xml = " + verify_request_xml); //$NON-NLS-1$ + + // TODO debug - remove + // try + // { + // FileOutputStream fos = new + // FileOutputStream("C:\\wprinz\\Filer\\egiz2\\verify_request.utf8.xml"); + // //$NON-NLS-1$ + // fos.write(verify_request_xml.getBytes("UTF-8")); //$NON-NLS-1$ + // fos.close(); + // } + // catch (Exception e) + // { + // log.error(e); + // } + + String url = this.environment.getVerifyURL(); + Properties response_properties = sendRequest(url, verify_request_xml, data); + + SignatureResponse signature_response = analyzeVerifyResponse(response_properties); + + log.debug("doVerify finished."); //$NON-NLS-1$ + return signature_response; + } + + /** + * Prepares the verify request xml to be sent using the verify request + * template. + * + * @param data + * The SignatureData. + * @param so + * The signature information object. + * @return Returns the verify request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException + { + String verify_request_template = this.environment.getVerifyRequestTemplate(); + + String xml_content = null; + + if (dsigData != null && dsigData.getXmlDsig() != null) + { + xml_content = dsigData.getXmlDsig(); + } + else + { + xml_content = chooseAndCreateXMLDsig(data, so); + } + + + + String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, this.environment.getLocRefContent()); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.DATE_TIME_REPLACE, BKUHelper.formDateTimeElement(this.params.getVerificationTime(), "sl")); + + return verify_request_xml; + } + + private String chooseAndCreateXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException { + // MOA + if (SigKZIDHelper.isMOASigned(so)) + { + log.debug("The signature is MOA signed -> getting XML content from DetachedLocRefMOA connector."); + DetachedLocRefMOAConnector moa_conn = new DetachedLocRefMOAConnector(this.environment.getProfile(), "loc ref not needed here"); + return moa_conn.prepareXMLContent(data, so); + + // MOCCA + } else if (SigKZIDHelper.isMOCCASigned(so)) { + log.debug("MOCCA signature detected."); + String algorithmId = SigKZIDHelper.parseAlgorithmId(so.id); + log.debug("Algorithm = " + algorithmId); + LocRefDetachedMOCCAConnector mocca_connector = new LocRefDetachedMOCCAConnector(this.params, "not needed here", algorithmId); + return mocca_connector.prepareXMLContent(data, so); + + // ATRUST + } else if (SigKZIDHelper.isATrustSigned(so)) { + log.debug("ATrust signature detected"); + MOASoapWithAttachmentConnector moaConn = new MOASoapWithAttachmentConnector(this.params); + moaConn.reInitVerifyTemplate(MOASoapWithAttachmentConnector.ATRUST_VERIFY_TEMPLATE_KEY); + return moaConn.prepareXMLContent(data, so); + } + // TD + else if (SigKZIDHelper.isBKUSigned(so)) { + log.debug("TD signature signature detected."); + return prepareXMLContent(data, so); + } + // unknown + else { + throw new ConnectorException(ErrorCode.UNSUPPORTED_SIGNATURE, "Unsupported signature (" + so.id + ", " +so.kz + "). Please get a new version of PDF-AS. Your version is: " + PdfAS.PDFAS_VERSION); + } + } + + /** + * Prepares the XML content the holds the actual signature data. + * + *

+ * This strongly rebuilds the XML content as retuned from a sign request. + *

+ * + * @param data + * The data. + * @param so + * The signature object containing the signature information. + * @return Returns the XML content. + * @throws ConnectorException + * f.e. + */ + public String prepareXMLContent(SignatureData data, SignSignatureObject so) throws ConnectorException + { + log.debug("prepareXMLContent:"); //$NON-NLS-1$ + try + { + + String ids_string = so.getSigID(); + String[] ids = SignatureObject.parseSigIds(ids_string); + + X509Certificate cert = so.getX509Certificate(); + + // dferbas + AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); + String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); + + // data digest replace + { +// byte[] data_value = data.getData(); +// byte[] data_value_hash = CodingHelper.buildDigest(data_value); + byte[] data_value_hash = CodingHelper.buildDigest(data.getDataSource(), algSuite.getDataDigestMethod()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_DATA_REPLACE, object_data_hash); + } + + // SIG id replaces + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_DATA_REF_REPLACE, ids[1]); + verify_xml = verify_xml.replaceAll(TemplateReplaces.ETSI_DATA_REF_REPLACE, ids[3]); + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_DATA_OBJ_URI_REPLACE, ids[2]); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNATURE_VALUE_REPLACE, so.getSignatureValue()); + + // X.509 Certificate replace + byte[] der = cert.getEncoded(); + byte[] cert_hash = CodingHelper.buildDigest(der, algSuite.getCertDigestMethod()); + String certDigest = CodingHelper.encodeBase64(cert_hash); + String x509_cert_string = CodingHelper.encodeBase64(der); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_CERTIFICATE_REPLACE, x509_cert_string); + + // Qualified Properties replaces + verify_xml = verify_xml.replaceAll(TemplateReplaces.ETSI_DATA_OBJ_URI_REPLACE, ids[4]); + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_ID_REPLACE, ids[0]); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); + // SigDataRefReplace already done above + verify_xml = verify_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, data.getMimeType()); + + // Signed Properties hash + { + final String ETSI_SIGNED_PROPERTIES_START_TAG = "= 0; + final int hash_end = verify_xml.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = verify_xml.substring(hash_start, hash_end); + log.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed); //$NON-NLS-1$ + + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); //$NON-NLS-1$ + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE, sig_prop_hash); + } + + log.debug("prepareXMLContent finished."); //$NON-NLS-1$ + return verify_xml; + } + catch (Exception e) + { + log.debug(e); + throw new ConnectorException(310, e); + } + } + + /** + * Analyzes the verify response string. + * + * @param response_properties + * The response properties containing the response XML. + * @return Returns the SignatureResponse containing the verification result. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeVerifyResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignatureResponse signature_response = BKUHelper.parseVerifyXMLResponse(response_string); + + log.debug("analyzeVerifyResponse finished."); //$NON-NLS-1$ + return signature_response; + } + + /** + * Holds environment configuration information like templates. + * + * @author wprinz + */ + public static class Environment extends ConnectorEnvironment + { + /** + * The configuration key of the sign keybox identifier. + */ + protected static final String SIGN_KEYBOX_IDENTIFIER_KEY = "bku.sign.KeyboxIdentifier"; //$NON-NLS-1$ + + /** + * The configuration key of the sign request template. + */ + protected static final String SIGN_REQUEST_TEMPLATE_KEY = "bku.sign.request.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the sign URL. + */ + protected static final String SIGN_URL_KEY = "bku.sign.url"; //$NON-NLS-1$ + + /** + * BKU template file prefix + */ + protected static final String TEMPLATE_FILE_PREFIX = "/templates/bku."; + + /** + * signing file template sufix + */ + protected static final String SIGN_TEMPLATE_FILE_SUFIX = ".sign.xml"; + + /** + * verifing template file sufix + */ + protected static final String VERIFY_REQUEST_TEMPLATE_FILE_SUFIX = ".verify.request.xml"; + + /** + * verifing file template key sufix + */ + protected static final String VERIFY_TEMPLATE_SUFIX = ".verify.template.xml"; + + /** + * The configuration key of the verify request template. + */ + protected static final String VERIFY_REQUEST_TEMPLATE_KEY = "bku.verify.request.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "bku.verify.template.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the verify URL. + */ + protected static final String VERIFY_URL_KEY = "bku.verify.url"; //$NON-NLS-1$ + + /** + * The configuration key for the ECDSA cert alg property. + */ + protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; //$NON-NLS-1$ + + /** + * The configuration key for the RSA cert alg property. + */ + protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; //$NON-NLS-1$ + + protected String profile = null; + + protected String loc_ref_content = null; + + protected String sign_keybox_identifier = null; + + protected String sign_request_template = null; + + protected String sign_url = null; + + protected String verify_request_template = null; + + protected String verify_template = null; + + protected String verify_url = null; + + protected String cert_alg_ecdsa = null; + + protected String cert_alg_rsa = null; + + /** + * Initializes the environment with a given profile. + * + * @param profile + * The configuration profile. + * @throws ConnectorException + * f.e. + */ + public Environment(String profile, String loc_ref_content) throws ConnectorException + { + this.profile = profile; + + this.loc_ref_content = loc_ref_content; + + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(300, e); + } + + this.sign_keybox_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEYBOX_IDENTIFIER_KEY); + + String sign_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.bku.algorithm.id") + SIGN_TEMPLATE_FILE_SUFIX; + + // try to load template from file + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + + // when first load failed (the template file does'nt exist), load it from default template file + if(this.sign_request_template == null) + { + sign_request_filename = getConnectorValueFromProfile(settings, profile, SIGN_REQUEST_TEMPLATE_KEY); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + } + + if (this.sign_request_template == null) + { + throw new ConnectorException(300, "Can not read the create xml request template"); //$NON-NLS-1$ + } + + this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); + + // verify + + String verify_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.bku.algorithm.id") + VERIFY_REQUEST_TEMPLATE_FILE_SUFIX; + + // try to load template file for verifing + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + + if(this.verify_request_template == null) + { + verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + } + + if (this.verify_request_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); //$NON-NLS-1$ + } + + // load template key file + String verify_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.bku.algorithm.id") + VERIFY_TEMPLATE_SUFIX; + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + + if(this.verify_template == null) + { + verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + } + + if (this.verify_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); //$NON-NLS-1$ + } + + this.verify_url = getConnectorValueFromProfile(settings, profile, VERIFY_URL_KEY); + + this.cert_alg_ecdsa = settings.getValueFromKey(ECDSA_CERT_ALG_KEY); + + this.cert_alg_rsa = settings.getValueFromKey(RSA_CERT_ALG_KEY); + + } + + public String getProfile() + { + return this.profile; + } + + /** + * Returns the LocRef content. + * + * @return Returns the LocRef content. + */ + public String getLocRefContent() + { + return this.loc_ref_content; + } + + /** + * Returns the sign keybox identifier. + * + * @return Returns the sign keybox identifier. + */ + public String getSignKeyboxIdentifier() + { + return this.sign_keybox_identifier; + } + + /** + * Returns the sign request template. + * + * @return Returns the sign request template. + */ + public String getSignRequestTemplate() + { + return this.sign_request_template; + } + + /** + * Returns the sign URL. + * + * @return Returns the sign URL. + */ + public String getSignURL() + { + return this.sign_url; + } + + /** + * Returns the verify request template. + * + * @return Returns the verify request template. + */ + public String getVerifyRequestTemplate() + { + return this.verify_request_template; + } + + /** + * Returns the verify template. + * + * @return Returns the verify template. + */ + public String getVerifyTemplate() + { + return this.verify_template; + } + + /** + * Returns the verify URL. + * + * @return Returns the verify URL. + */ + public String getVerifyURL() + { + return this.verify_url; + } + + /** + * Returns the ecdsa cert alg property. + * + * @return Returns the ecdsa cert alg property. + */ + public String getCertAlgEcdsa() + { + return this.cert_alg_ecdsa; + } + + /** + * Returns the rsa cert alg property. + * + * @return Returns the rsa cert alg property. + */ + public String getCertAlgRsa() + { + return this.cert_alg_rsa; + } + + /** + * Reads the configuration entry given by the key, first from the given + * profile, if not found from the defaults. + * + * @param settings + * The settings. + * @param profile + * The profile. + * @param key + * The configuration key. + * @return Returns the configuration entry. + */ + public static String getConnectorValueFromProfile(SettingsReader settings, + String profile, String key) + { + String value = settings.getValueFromKey("sig_obj." + profile + "." + key); //$NON-NLS-1$//$NON-NLS-2$ + if (value == null) + { + value = settings.getValueFromKey(key); + } + return value; + } + } + + + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) + throws ConnectorException { + String xmldsig = chooseAndCreateXMLDsig(data, so); + return new XMLDsigData(xmldsig, true); + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java new file mode 100644 index 0000000..170cc45 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/EnvelopedBase64BKUConnector.java @@ -0,0 +1,666 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import java.io.UnsupportedEncodingException; +import java.security.cert.X509Certificate; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.EnvelopingBase64MOAConnector; +import at.knowcenter.wag.egov.egiz.sig.sigid.HotfixIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * @author wprinz + * + */ +public class EnvelopedBase64BKUConnector implements Connector, LocalConnector +{ + //23.11.2010 changed by exthex - added reconstructXMLDsig method and moved xmldsig creation to chooseAndCreateXMLDsig method + + /** + * The log. + */ + private static Log log = LogFactory.getLog(EnvelopedBase64BKUConnector.class); + + /** + * The environemnt configuration of this connector containing templates and + * other configurable elements. + */ + protected Environment environment = null; + + /** + * Constructor that builds the configuration environment for this connector + * according to the given profile. + * + *

+ * If confuguration parameters are not defined on that profile, the default + * parameters defined in the configuration are used. + *

+ * + *

+ * This is the new "hotfix" base64 connector. + *

+ * + * @param profile + * The profile from which the Environment should be assembled. + * @throws ConnectorException + * f.e. + */ + public EnvelopedBase64BKUConnector(String profile) throws ConnectorException + { + this.environment = new Environment(profile); + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doSign(at.knowcenter.wag.egov.egiz.sig.SignatureData) + */ + public SignSignatureObject doSign(SignatureData data) throws ConnectorException + { + log.debug("doSign:"); //$NON-NLS-1$ + + String sign_request_xml = prepareSignRequest(data); +// DebugHelper.debugStringToFile(sign_request_xml, "BKU_EnvB64_sign_request.xml"); //$NON-NLS-1$ + + String url = this.environment.getSignURL(); + Properties response_properties = sendRequest(url, sign_request_xml); + +// DebugHelper.debugStringToFile(response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY), "BKU_EnvB64_sign_response.xml"); //$NON-NLS-1$ + SignSignatureObject sso = analyzeSignResponse(response_properties); + + sso.response_properties = response_properties; + + log.debug("doSign finished."); //$NON-NLS-1$ + return sso; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doVerify(at.knowcenter.wag.egov.egiz.sig.SignatureData, + * at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject) + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException + { + log.debug("doVerify:"); //$NON-NLS-1$ + + String verify_request_xml = prepareVerifyRequest(data, so, dsig); +// DebugHelper.debugStringToFile(verify_request_xml, "BKU_EnvB64_verify_request.xml"); //$NON-NLS-1$ + + String url = this.environment.getVerifyURL(); + Properties response_properties = sendRequest(url, verify_request_xml); + +// DebugHelper.debugStringToFile(response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY), "BKU_EnvB64_verify_response.xml"); //$NON-NLS-1$ + SignatureResponse signature_response = analyzeVerifyResponse(response_properties); + + log.debug("doVerify finished."); //$NON-NLS-1$ + return signature_response; + } + +// /** +// * This emthod extracts id-values from a text. The id is given by the name. +// * +// * @param text +// * the id-value that should extract from +// * @param name +// * the id-key +// * @return the value of the given key in the text +// */ +// private String extractId(String text, String name) +// { +// String id = null; +// int start_idx = text.indexOf(name) + name.length(); +// int end_idx = text.indexOf("\"", start_idx); +// +// // TODO hotfix! +// final int quot_end_idx = end_idx; +// final int squot_end_idx = text.indexOf("'", start_idx); +// end_idx = Math.min(quot_end_idx, squot_end_idx); +// // TODO hotfix end! +// +// id = text.substring(start_idx, end_idx); +// if (log.isDebugEnabled()) +// { +// log.debug("extract id:" + name + id); +// } +// return id; +// } + + /** + * Prepares the XML content the holds the actual signature data. + * + *

+ * This strongly rebuilds the XML content as retuned from a sign request. + *

+ * + * @param data + * The data. + * @param so + * The signature object containing the signature information. + * @return Returns the XML content. + * @throws ConnectorException + * f.e. + */ + public String prepareXMLContent(SignatureData data, SignSignatureObject so) throws ConnectorException + { + log.debug("prepareXMLContent:"); //$NON-NLS-1$ + try + { + String ids_string = so.getSigID(); + String[] ids = SignatureObject.parseSigIds(ids_string); + + X509Certificate cert = so.getX509Certificate(); + + // dferbas + AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); + String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); + + // data digest replace + byte[] data_value = BKUHelper.prepareEnvelopingData(data); + { + byte[] data_value_hash = CodingHelper.buildDigest(data_value, algSuite.getDataDigestMethod()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_DATA_REPLACE, object_data_hash); + } + + // SIG id replaces + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_DATA_REF_REPLACE, ids[1]); + verify_xml = verify_xml.replaceAll(TemplateReplaces.ETSI_DATA_REF_REPLACE, ids[3]); + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_DATA_OBJ_URI_REPLACE, ids[2]); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNATURE_VALUE_REPLACE, so.getSignatureValue()); + + // X.509 Certificate replace + byte[] der = cert.getEncoded(); + byte[] cert_hash = CodingHelper.buildDigest(der, algSuite.getCertDigestMethod()); + String certDigest = CodingHelper.encodeBase64(cert_hash); + String x509_cert_string = CodingHelper.encodeBase64(der); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_CERTIFICATE_REPLACE, x509_cert_string); + + // Base64 content replace + String base64 = CodingHelper.encodeBase64(data_value); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.BASE64_CONTENT_REPLACE, base64); + + // Qualified Properties replaces + verify_xml = verify_xml.replaceAll(TemplateReplaces.ETSI_DATA_OBJ_URI_REPLACE, ids[4]); + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_ID_REPLACE, ids[0]); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); + // SigDataRefReplace already done above + + // Signed Properties hash + { + String sig_prop_hash = computeSignedPropertiesReplace(verify_xml, algSuite); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE, sig_prop_hash); + } + + log.debug("prepareXMLContent finished."); //$NON-NLS-1$ + return verify_xml; + } + catch (Exception e) + { + log.debug(e); + throw new ConnectorException(310, e); + } + } + + protected String computeSignedPropertiesReplace(String verify_xml, AlgorithmSuiteObject algSuite) + { + try + { + final String ETSI_SIGNED_PROPERTIES_START_TAG = "= 0; + final int hash_end = verify_xml.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = verify_xml.substring(hash_start, hash_end); + log.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed); //$NON-NLS-1$ + + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); //$NON-NLS-1$ + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + return sig_prop_hash; + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException("Very Strange: UTF-8 character encoding not supported.", e); + } + } + + /** + * Prepares the sign request xml to be sent using the sign request template. + * + * @param data + * The SignatureData. + * @return Returns the sign request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareSignRequest(SignatureData data) throws ConnectorException + { + log.debug("prepareSignRequest:"); //$NON-NLS-1$ + + String sign_request_template = this.environment.getSignRequestTemplate(); + + String sign_keybox_identifier = this.environment.getSignKeyboxIdentifier(); + String base64 = BKUHelper.prepareBase64Content(data); + + String sign_request_xml = sign_request_template.replaceFirst(TemplateReplaces.KEYBOX_IDENTIFIER_REPLACE, sign_keybox_identifier); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.BASE64_CONTENT_REPLACE, base64); + + log.debug("prepareSignRequest finished."); //$NON-NLS-1$ + return sign_request_xml; + } + + /** + * Prepares the verify request xml to be sent using the verify request + * template. + * + * @param data + * The SignatureData. + * @param so + * The signature information object. + * @return Returns the verify request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException + { + String verify_request_template = this.environment.getVerifyRequestTemplate(); + + String xml_content = null; + if (dsigData != null && dsigData.getXmlDsig() != null) + { + xml_content = dsigData.getXmlDsig(); + } + else + { + xml_content = chooseAndCreateXMLDsig(data, so); + } + + String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + +// log.debug("\r\n\r\n" + verify_request_xml + "\r\n\r\n"); + + return verify_request_xml; + } + + private String chooseAndCreateXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException { + if (SigKZIDHelper.isMOASigned(so)) + { + log.debug("The signature is MOA signed -> getting XML content from Base64MOA connector."); + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(this.environment.getProfile()); + EnvelopingBase64MOAConnector moa_conn = new EnvelopingBase64MOAConnector(cp); + return moa_conn.prepareXMLContent(data, so); + } + else + { + return prepareXMLContent(data, so); + } + } + +/** + * Sends the request to the given URL. + * + * @param url + * The URL. + * @param request_string + * The request string. + * @return Returns the response string. + * @throws ConnectorException + * F.e. + */ + protected Properties sendRequest(String url, String request_string) throws ConnectorException + { + try + { + Properties response_properties = at.knowcenter.wag.egov.egiz.sig.connectors.BKUPostConnection.doPostRequest(url, request_string); + return response_properties; + } + catch (Exception e) + { + throw new ConnectorException(320, e); + } + } + + /** + * Analyzes the sign response xml and extracts the signature data. + * + * @param response_properties + * The response properties containing the response String and + * transport related information. + * @return Returns the extracted data encapsulated in a SignatureObject. + * @throws ConnectorException + * f.e. + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeSignResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + String bkuIdentifier = BKUHelper.getBKUIdentifier(response_properties); + log.debug("BKU identifier: \"" + bkuIdentifier + "\""); + + SignSignatureObject so = BKUHelper.parseCreateXMLResponse(response_string, new HotfixIdFormatter(), this.environment); + + log.debug("analyzeSignResponse finished."); //$NON-NLS-1$ + return so; + } + + /** + * Analyzes the verify response string. + * + * @param response_properties + * The response properties containing the response XML. + * @return Returns the SignatureResponse containing the verification result. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeVerifyResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignatureResponse signature_response = BKUHelper.parseVerifyXMLResponse(response_string); + + log.debug("analyzeVerifyResponse finished."); //$NON-NLS-1$ + return signature_response; + } + + /** + * Holds environment configuration information like templates. + * + * @author wprinz + */ + public static class Environment extends ConnectorEnvironment + { + /** + * The configuration key of the sign keybox identifier. + */ + protected static final String SIGN_KEYBOX_IDENTIFIER_KEY = "bku.sign.KeyboxIdentifier"; //$NON-NLS-1$ + + /** + * The configuration key of the sign request template. + */ + protected static final String SIGN_REQUEST_TEMPLATE_KEY = "bku.sign.request.base64"; //$NON-NLS-1$ + + /** + * The configuration key of the sign URL. + */ + protected static final String SIGN_URL_KEY = "bku.sign.url"; //$NON-NLS-1$ + + /** + * The configuration key of the verify request template. + */ + protected static final String VERIFY_REQUEST_TEMPLATE_KEY = "bku.verify.request.base64"; //$NON-NLS-1$ + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "bku.verify.template.base64"; //$NON-NLS-1$ + + /** + * The configuration key of the verify URL. + */ + protected static final String VERIFY_URL_KEY = "bku.verify.url"; //$NON-NLS-1$ + + /** + * The configuration key for the ECDSA cert alg property. + */ + protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; //$NON-NLS-1$ + + /** + * The configuration key for the RSA cert alg property. + */ + protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; //$NON-NLS-1$ + + protected String profile = null; + + protected String sign_keybox_identifier = null; + + protected String sign_request_template = null; + + protected String sign_url = null; + + protected String verify_request_template = null; + + protected String verify_template = null; + + protected String verify_url = null; + + protected String cert_alg_ecdsa = null; + + protected String cert_alg_rsa = null; + + /** + * Initializes the environment with a given profile. + * + * @param profile + * The configuration profile. + * @throws ConnectorException + * f.e. + */ + public Environment(String profile) throws ConnectorException + { + this.profile = profile; + + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(300, e); + } + + this.sign_keybox_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEYBOX_IDENTIFIER_KEY); + + String sign_request_filename = getConnectorValueFromProfile(settings, profile, SIGN_REQUEST_TEMPLATE_KEY); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + if (this.sign_request_template == null) + { + throw new ConnectorException(300, "Can not read the create xml request template"); //$NON-NLS-1$ + } + + this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); + + String verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + log.debug("Verify request template filename = " + verify_request_filename); + + if (this.verify_request_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); //$NON-NLS-1$ + } + + log.debug("Verify request template = " + this.verify_request_template); + + String verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + if (this.verify_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); //$NON-NLS-1$ + } + + this.verify_url = getConnectorValueFromProfile(settings, profile, VERIFY_URL_KEY); + + this.cert_alg_ecdsa = settings.getValueFromKey(ECDSA_CERT_ALG_KEY); + + this.cert_alg_rsa = settings.getValueFromKey(RSA_CERT_ALG_KEY); + + } + + public String getProfile() + { + return this.profile; + } + + /** + * Returns the sign keybox identifier. + * + * @return Returns the sign keybox identifier. + */ + public String getSignKeyboxIdentifier() + { + return this.sign_keybox_identifier; + } + + /** + * Returns the sign request template. + * + * @return Returns the sign request template. + */ + public String getSignRequestTemplate() + { + return this.sign_request_template; + } + + /** + * Returns the sign URL. + * + * @return Returns the sign URL. + */ + public String getSignURL() + { + return this.sign_url; + } + + /** + * Returns the verify request template. + * + * @return Returns the verify request template. + */ + public String getVerifyRequestTemplate() + { + return this.verify_request_template; + } + + /** + * Returns the verify template. + * + * @return Returns the verify template. + */ + public String getVerifyTemplate() + { + return this.verify_template; + } + + /** + * Returns the verify URL. + * + * @return Returns the verify URL. + */ + public String getVerifyURL() + { + return this.verify_url; + } + + /** + * Returns the ecdsa cert alg property. + * + * @return Returns the ecdsa cert alg property. + */ + public String getCertAlgEcdsa() + { + return this.cert_alg_ecdsa; + } + + /** + * Returns the rsa cert alg property. + * + * @return Returns the rsa cert alg property. + */ + public String getCertAlgRsa() + { + return this.cert_alg_rsa; + } + + /** + * Reads the configuration entry given by the key, first from the given + * profile, if not found from the defaults. + * + * @param settings + * The settings. + * @param profile + * The profile. + * @param key + * The configuration key. + * @return Returns the configuration entry. + */ + public static String getConnectorValueFromProfile(SettingsReader settings, + String profile, String key) + { + String value = settings.getValueFromKey("sig_obj." + profile + "." + key); //$NON-NLS-1$//$NON-NLS-2$ + if (value == null) + { + value = settings.getValueFromKey(key); + } + return value; + } + } + + + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) + throws ConnectorException { + String xmldsig = chooseAndCreateXMLDsig(data, so); + return new XMLDsigData(xmldsig, false); + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/LocRefDetachedBKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/LocRefDetachedBKUConnector.java new file mode 100644 index 0000000..c5e1513 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/LocRefDetachedBKUConnector.java @@ -0,0 +1,46 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; + +/** + * @author wprinz + * + */ +public class LocRefDetachedBKUConnector extends DetachedBKUConnector +{ + + /** + * @param connectorParameters + * @param loc_ref_content + * @throws ConnectorException + */ + public LocRefDetachedBKUConnector(ConnectorParameters connectorParameters, String loc_ref_content) throws ConnectorException + { + super(connectorParameters, loc_ref_content); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/MultipartDetachedBKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/MultipartDetachedBKUConnector.java new file mode 100644 index 0000000..cfaa55d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/MultipartDetachedBKUConnector.java @@ -0,0 +1,42 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; + +/** + * @author wprinz + * + */ +public class MultipartDetachedBKUConnector extends DetachedBKUConnector +{ + protected static final String MULTIPART_LOC_REF_CONTENT = "formdata:fileupload"; //$NON-NLS-1$ + + public MultipartDetachedBKUConnector(ConnectorParameters connectorParameters) throws ConnectorException + { + super(connectorParameters, MULTIPART_LOC_REF_CONTENT); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/OldEnvelopingBase64BKUConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/OldEnvelopingBase64BKUConnector.java new file mode 100644 index 0000000..58bdec6 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/OldEnvelopingBase64BKUConnector.java @@ -0,0 +1,135 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import java.io.UnsupportedEncodingException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; + +/** + * + *

+ * This is the old base64 connector. The difference is in the way the sign + * response is parsed and the verify content_xml. + *

+ * + * @author wprinz + * + */ +public class OldEnvelopingBase64BKUConnector extends EnvelopedBase64BKUConnector +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(OldEnvelopingBase64BKUConnector.class); + + // TODO implement signing - with old pre 2.7.2 BKUs... not really necessary + // though because this connector is only used for verification + + public OldEnvelopingBase64BKUConnector(String profile) throws ConnectorException + { + super(profile); + + this.environment = new OverriddenEnvironment(profile); + } + + + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.bku.EnvelopedBase64BKUConnector#computeSignedPropertiesReplace(java.lang.String) + */ + protected String computeSignedPropertiesReplace(String verify_xml, AlgorithmSuiteObject algSuite) + { + try + { + final String ETSI_QUALIFYING_PROPERTIES_START_TAG = "= 0; + final int hash_end = verify_xml.indexOf(ETSI_QUALIFYING_PROPERTIES_END_TAG, hash_start) + ETSI_QUALIFYING_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_QUALIFYING_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = verify_xml.substring(hash_start, hash_end); + log.debug("etsi:QualifyingProperties string to be hashed: " + string_to_be_hashed); //$NON-NLS-1$ + + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); //$NON-NLS-1$ + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + return sig_prop_hash; + } + catch (UnsupportedEncodingException e) + { + throw new RuntimeException("Very Strange: UTF-8 character encoding not supported.", e); + } + } + + + + public static class OverriddenEnvironment extends EnvelopedBase64BKUConnector.Environment + { + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "bku.verify.template.base64old"; //$NON-NLS-1$ + + public OverriddenEnvironment(String profile) throws ConnectorException + { + super(profile); + + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, e); + } + + String verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + if (this.verify_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); //$NON-NLS-1$ + } + + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObject.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObject.java new file mode 100644 index 0000000..72f181e --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObject.java @@ -0,0 +1,272 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.bku; + +import java.io.Serializable; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import at.gv.egiz.pdfas.api.timestamp.TimeStamper; +import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.AdditionalSignatureInformation; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.AlgorithmSignatureInformation; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.ConnectorSignatureInformation; +import at.knowcenter.wag.egov.egiz.sig.signatureobject.MandatorySignatureInformation; + +/** + * @author wprinz + * + */ +public class SignSignatureObject implements Serializable, MandatorySignatureInformation, ConnectorSignatureInformation, AlgorithmSignatureInformation, AdditionalSignatureInformation +{ + /** + * SVUID. + */ + private static final long serialVersionUID = -2689261480444802213L; + + public String date = null; + public String issuer = null; + public String signatureValue = null; + + public String id = null; + public String kz = null; + + public String sigAlgorithm; + + public String sigTimeStamp; + + /** + * This is used to transport the response properties to the Detached signator. + */ + public Properties response_properties = null; + + /** + * The X509Certificate. + * + *

+ * This also provides the serial number and name. + *

+ */ + public X509Certificate x509Certificate = null; + + // dferbas + public Map subjectDNMap = new HashMap(); + public Map issuerDNMap = new HashMap(); + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.MandatorySignatureInformation#getDate() + */ + public String getDate() + { + return this.date; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.MandatorySignatureInformation#getIssuer() + */ + public String getIssuer() + { + return this.issuer; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.MandatorySignatureInformation#getSerialNumber() + */ + public String getSerialNumber() + { + return this.x509Certificate.getSerialNumber().toString(); + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.MandatorySignatureInformation#getSignatureValue() + */ + public String getSignatureValue() + { + return this.signatureValue; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.ConnectorSignatureInformation#getSigID() + */ + public String getSigID() + { + return this.id; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.AlgorithmSignatureInformation#getSigKZ() + */ + public String getSigKZ() + { + return this.kz; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.AdditionalSignatureInformation#getName() + */ + public String getName() + { + return this.x509Certificate.getSubjectDN().toString(); + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.signatureobject.AdditionalSignatureInformation#getX509Certificate() + */ + public X509Certificate getX509Certificate() + { + return this.x509Certificate; + } + + public String getSigAlgorithm() { + return this.sigAlgorithm; + } + + public String retrieveStringValue(String sigKey) + { + // mandatory + if (sigKey.equals(SignatureTypes.SIG_DATE)) + { + return getDate(); + } + if (sigKey.equals(SignatureTypes.SIG_VALUE)) + { + return getSignatureValue(); + } + if (sigKey.equals(SignatureTypes.SIG_ISSUER)) + { + return getIssuer(); + } + if (sigKey.equals(SignatureTypes.SIG_NUMBER)) + { + return getSerialNumber(); + } + + // connector + if (sigKey.equals(SignatureTypes.SIG_ID)) + { + return getSigID(); + } + + // algorithm + if (sigKey.equals(SignatureTypes.SIG_KZ)) + { + return getSigKZ(); + } + + // additional + if (sigKey.equals(SignatureTypes.SIG_NAME)) + { + return getName(); + } + + if (sigKey.equals(SignatureTypes.SIG_SUBJECT)) + { + return getName(); + } + + if (sigKey.equals(SignatureTypes.SIG_ALG)) { + return getSigAlgorithm(); + } + + throw new RuntimeException("The key '" + sigKey + "' is not a recognized SignatorObject member."); //$NON-NLS-1$ //$NON-NLS-2$ + } + + // dferbas + + + /** + * Get a timestamp if available as b64 string + * @see TimeStamper + * @return + */ + public String getSigTimeStamp() { + return this.sigTimeStamp; + } + + public Map getSubjectDNMap() { + if (this.subjectDNMap.size() == 0 && this.getX509Certificate() != null) { + //rpiazzi workaround + //the problem with atrust encoding special characters (Sonderzeichen) wrong + //led to this workaround. As special characters are of the form e.g. "&#xxx;" + //Example: for "Georg Müller" atrust returns "Georg Müller" + //By calling this.getX509Certificate().getSubjectDN().getName() you get "Georg Mü\;ller", + //After that the down called method fillDNMap replaces the "\" with a "+" + //Because of this the workaround in at.gv.egiz.pdfas.impl.signator.binary.BinarySignator_1_0_0.fillReplacesWithValues() + //which replaces the wrong codes of atrust with the special chars does not work + //------------------------------------------------------------------------------ + //The workaround here is to call this.getX509Certificate().getSubjectDN.toString() + //instead of this.getX509Certificate().getSubjectDN.getName() + if (this.getX509Certificate().getSubjectDN().toString().contains(";") || + this.getX509Certificate().getSubjectDN().toString().contains("#") || + this.getX509Certificate().getSubjectDN().toString().contains("&")) { + fillDNMap(this.getX509Certificate().getSubjectDN().toString(), this.subjectDNMap); + } + else { + fillDNMap(this.getX509Certificate().getSubjectDN().getName(), this.subjectDNMap); + } + //end workaround + } + return this.subjectDNMap; + } + + public String certSubjectDNPart(String key) { + return (String)this.getSubjectDNMap().get(key); + } + + public Map getIssuerDNMap() { + if (this.issuerDNMap.size() == 0 && this.getX509Certificate() != null) { + fillDNMap(this.getX509Certificate().getIssuerDN().getName(), this.issuerDNMap); + } + return this.issuerDNMap; + } + + public String certIssuerDNPart(String key) { + return (String)this.getIssuerDNMap().get(key); + } + + private void fillDNMap(String dn, Map dnMap) { + + // split at "," but not at "\," + String[] arr = dn.split("\\s*(? , + entry[1] = entry[1].replaceAll("\\\\+", "+"); // \+ -> + + entry[1] = entry[1].replaceAll("\\\\\"", "\""); // \" -> " + entry[1] = entry[1].replaceAll("\\\\\\\\", "\\"); // \\ -> \ + entry[1] = entry[1].replaceAll("\\\\<,", "<"); // \< -> < + entry[1] = entry[1].replaceAll("\\\\>", ">"); // \> -> > + entry[1] = entry[1].replaceAll("\\\\;", ";"); // \; -> ; + entry[1] = entry[1].replaceAll("\\\\#", "#"); // \# -> # + + dnMap.put(entry[0], entry[1]); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObjectHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObjectHelper.java new file mode 100644 index 0000000..4eb6e39 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/bku/SignSignatureObjectHelper.java @@ -0,0 +1,76 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.bku; +// +//import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +//import at.knowcenter.wag.egov.egiz.sig.SignatureTypes; +// +///** +// * @author wprinz +// * +// */ +//public abstract class SignSignatureObjectHelper +//{ +// public static String retrieveStringValueFromSignatureObject (SignSignatureObject so, String key) +// { +// // mandatory +// if (key.equals(SignatureTypes.SIG_DATE)) +// { +// return so.getDate(); +// } +// if (key.equals(SignatureTypes.SIG_VALUE)) +// { +// return so.getSignatureValue(); +// } +// if (key.equals(SignatureTypes.SIG_ISSUER)) +// { +// return so.getIssuer(); +// } +// if (key.equals(SignatureTypes.SIG_NUMBER)) +// { +// return so.getSerialNumber(); +// } +// +// // connector +// if (key.equals(SignatureTypes.SIG_ID)) +// { +// return so.getSigID(); +// } +// +// // algorithm +// if (key.equals(SignatureTypes.SIG_KZ)) +// { +// return so.getSigKZ(); +// } +// +// // additional +// if (key.equals(SignatureTypes.SIG_NAME)) +// { +// return so.getName(); +// } +// +// throw new RuntimeException("The key '" + key + "' is not a recognized SignatorObject member."); //$NON-NLS-1$ //$NON-NLS-2$ +// } +// +//} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java new file mode 100644 index 0000000..ea90841 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/DetachedLocRefMOAConnector.java @@ -0,0 +1,661 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.security.cert.X509Certificate; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmMapper; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.DetachedBKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedLocRefMOAIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; + +/** + * Connects to MOA providing the Data detached as LocRef on a local resource. + * + * @author wprinz + */ +public class DetachedLocRefMOAConnector implements Connector +{ + //23.11.2010 changed by exthex - added reconstructXMLDsig method and moved xmldsig creation to chooseAndCreateXMLDsig method + /** + * The SIG_ID prefix. + */ + // public static final String SIG_ID_PREFIX = "etsi-bku-detached@"; //$NON-NLS-1$ + /** + * The log. + */ + private static Log log = LogFactory.getLog(DetachedLocRefMOAConnector.class); + + /** + * The environemnt configuration of this connector containing templates and + * other configurable elements. + */ + protected Environment environment = null; + + /** + * Constructor that builds the configuration environment for this connector + * according to the given profile. + * + *

+ * If confuguration parameters are not defined on that profile, the default + * parameters defined in the configuration are used. + *

+ * + * @param profile + * The profile from which the Environment should be assembled. + * @throws SettingsException + * f.e. + * @throws SignatureException + * f.e. + */ + public DetachedLocRefMOAConnector(String profile, String signature_data_url) throws ConnectorException + { + this.environment = new Environment(profile, signature_data_url); + } + + protected String prepareSignRequest(SignatureData data) throws ConnectorException + { + log.debug("prepareSignRequestDetached:"); //$NON-NLS-1$ + + String sign_request_template = this.environment.getSignRequestTemplate(); + + String sign_key_identifier = this.environment.getSignKeyIdentifier(); + String loc_ref_content = this.environment.getSignatureDataUrl(); + String mime_type = data.getMimeType(); + if (log.isDebugEnabled()) + { + log.debug("sign keybox identifier = " + sign_key_identifier); //$NON-NLS-1$ + log.debug("LocRefContent = " + loc_ref_content); //$NON-NLS-1$ + log.debug("mime type = " + mime_type); //$NON-NLS-1$ + } + + String sign_request_xml = sign_request_template.replaceFirst(TemplateReplaces.KEY_IDENTIFIER_REPLACE, sign_key_identifier); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, loc_ref_content); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, mime_type); + + log.debug("prepareSignRequestDetached finished."); //$NON-NLS-1$ + return sign_request_xml; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector#analyzeSignResponse(java.util.Properties) + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeSignResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignSignatureObject so = MOAHelper.parseCreateXMLResponse(response_string, new DetachedLocRefMOAIdFormatter(), this.environment); + + log.debug("analyzeSignResponse finished."); //$NON-NLS-1$ + return so; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doSign(at.knowcenter.wag.egov.egiz.sig.SignatureData) + */ + public SignSignatureObject doSign(SignatureData data) throws ConnectorException + { + log.debug("doSign:"); //$NON-NLS-1$ + + String sign_request_xml = prepareSignRequest(data); +// DebugHelper.debugStringToFile(sign_request_xml, "MOA_DetLocRef_sign_request.xml"); //$NON-NLS-1$ + + String url = this.environment.getSignURL(); + Properties response_properties = sendRequest(url, MOASoapConnection.SERVICE_SIGN, sign_request_xml); + +// DebugHelper.debugStringToFile(response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY), "MOA_DetLocRef_sign_response.xml"); //$NON-NLS-1$ + SignSignatureObject sso = analyzeSignResponse(response_properties); + + sso.response_properties = response_properties; + + log.debug("doSign finished."); //$NON-NLS-1$ + return sso; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doVerify(at.knowcenter.wag.egov.egiz.sig.SignatureData, + * at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject) + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException + { + log.debug("doVerify:"); //$NON-NLS-1$ + + String verify_request_xml = prepareVerifyRequest(data, so, dsig); + log.debug("verify_request_xml = " + verify_request_xml); //$NON-NLS-1$ + + String url = this.environment.getVerifyURL(); + Properties response_properties = sendRequest(url, MOASoapConnection.SERVICE_VERIFY, verify_request_xml); + + SignatureResponse signature_response = analyzeVerifyResponse(response_properties); + + log.debug("doVerify finished."); //$NON-NLS-1$ + return signature_response; + } + + /** + * Prepares the verify request xml to be sent using the verify request + * template. + * + * @param data + * The SignatureData. + * @param so + * The signature information object. + * @return Returns the verify request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException + { + String verify_request_template = this.environment.getVerifyRequestTemplate(); + + String xml_content = null; + if (dsigData != null && dsigData.getXmlDsig() != null) + { + xml_content = dsigData.getXmlDsig(); + } + else + { + xml_content = chooseAndCreateXMLDsig(data, so); + } + + String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.TRUST_PROFILE_ID_REPLACE, this.environment.getVerifyTrustProfileId()); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, this.environment.getSignatureDataUrl()); + + log.debug("\r\n\r\n" + verify_request_xml + "\r\n\r\n"); + + return verify_request_xml; + } + + /** + * Analyzes the verify response string. + * + * @param response_properties + * The response properties containing the response XML. + * @return Returns the SignatureResponse containing the verification result. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeVerifyResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignatureResponse signature_response = BKUHelper.parseVerifyXMLResponse(response_string); + + log.debug("analyzeVerifyResponse finished."); //$NON-NLS-1$ + return signature_response; + } + + public String prepareXMLContent(SignatureData data, SignSignatureObject so) throws ConnectorException + { + log.debug("prepareXMLContent:"); //$NON-NLS-1$ + try + { + + X509Certificate cert = so.getX509Certificate(); + + // dferbas + AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); + String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); + + // data digest replace + { +// byte[] data_value = data.getData(); +// byte[] data_value_hash = CodingHelper.buildDigest(data_value); + byte[] data_value_hash = CodingHelper.buildDigest(data.getDataSource(), algSuite.getDataDigestMethod()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_DATA_REPLACE, object_data_hash); + } + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNATURE_VALUE_REPLACE, so.getSignatureValue()); + + // X.509 Certificate replace + byte[] der = cert.getEncoded(); + byte[] cert_hash = CodingHelper.buildDigest(der, algSuite.getCertDigestMethod()); + String certDigest = CodingHelper.encodeBase64(cert_hash); + String x509_cert_string = CodingHelper.encodeBase64(der); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_CERTIFICATE_REPLACE, x509_cert_string); + + // Qualified Properties replaces + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); + // SigDataRefReplace already done above + verify_xml = verify_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, data.getMimeType()); + + // Signed Properties hash + { + final String ETSI_SIGNED_PROPERTIES_START_TAG = "= 0; + final int hash_end = verify_xml.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = verify_xml.substring(hash_start, hash_end); + log.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed); //$NON-NLS-1$ + + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); //$NON-NLS-1$ + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE, sig_prop_hash); + } + + log.debug("prepareXMLContent finished."); //$NON-NLS-1$ + return verify_xml; + } + catch (Exception e) + { + log.debug(e); + throw new ConnectorException(310, e); + } + } + + protected Properties sendRequest(String url, String mode, String request_string) throws ConnectorException + { + try + { + Properties response_properties = MOASoapConnection.connectMOA(request_string, MOASoapConnection.SERVICE_SIGN, url); + return response_properties; + } + catch (Exception e) + { + throw new ConnectorException(330, e); + } + } + + /** + * Holds environment configuration information like templates. + * + * @author wprinz + */ + public static class Environment extends ConnectorEnvironment + { + /** + * The configuration key of the sign keybox identifier. + */ + protected static final String SIGN_KEY_IDENTIFIER_KEY = "moa.sign.KeyIdentifier"; //$NON-NLS-1$ + + /** + * The configuration key of the sign request template. + */ + protected static final String SIGN_REQUEST_TEMPLATE_KEY = "moa.sign.request.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the sign URL. + */ + protected static final String SIGN_URL_KEY = "moa.sign.url"; //$NON-NLS-1$ + + /** + * MOA template file prefix + */ + protected static final String TEMPLATE_FILE_PREFIX = "/templates/moa."; + + /** + * signing file template sufix + */ + protected static final String SIGN_TEMPLATE_FILE_SUFIX = ".sign.xml"; + + /** + * verifing template file sufix + */ + protected static final String VERIFY_REQUEST_TEMPLATE_FILE_SUFIX = ".verify.request.xml"; + + /** + * verifing file template key sufix + */ + protected static final String VERIFY_TEMPLATE_SUFIX = ".verify.template.xml"; + + /** + * The configuration key of the verify request template. + */ + protected static final String VERIFY_REQUEST_TEMPLATE_KEY = "moa.verify.request.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "moa.verify.template.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the verify URL. + */ + protected static final String VERIFY_URL_KEY = "moa.verify.url"; //$NON-NLS-1$ + + /** + * The configuration key of the trust profile id. + */ + protected static final String VERIFY_TRUST_PROFILE_ID = "moa.verify.TrustProfileID"; //$NON-NLS-1$ + + /** + * The configuration key for the ECDSA cert alg property. + */ + protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; //$NON-NLS-1$ + + /** + * The configuration key for the RSA cert alg property. + */ + protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; //$NON-NLS-1$ + + protected String profile = null; + + protected String signature_data_url = null; + + protected String sign_key_identifier = null; + + protected String sign_request_template = null; + + protected String sign_url = null; + + protected String verify_request_template = null; + + protected String verify_template = null; + + protected String verify_url = null; + + protected String verify_trust_profile_id = null; + + protected String cert_alg_ecdsa = null; + + protected String cert_alg_rsa = null; + + /** + * Initializes the environment with a given profile. + * + * @param profile + * The configuration profile. + * @throws SettingsException + * f.e. + * @throws ConnectorException + * f.e. + */ + public Environment(String profile, String signature_data_url) throws ConnectorException + { + this.profile = profile; + + this.signature_data_url = signature_data_url; + + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(300, e); + } + + this.sign_key_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEY_IDENTIFIER_KEY); + + String sign_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moa.algorithm.id") + SIGN_TEMPLATE_FILE_SUFIX; + + // try to load template from file + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + + if (this.sign_request_template == null) + { + sign_request_filename = getConnectorValueFromProfile(settings, profile, SIGN_REQUEST_TEMPLATE_KEY); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + } + + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + if (this.sign_request_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the create xml request template"); //$NON-NLS-1$ + } + + this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); + + String verify_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moa.algorithm.id") + VERIFY_REQUEST_TEMPLATE_FILE_SUFIX; + + // try to load template file for verifing + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + + if (this.verify_request_template == null) + { + verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + } + + if (this.verify_request_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); //$NON-NLS-1$ + } + + // load template key file + String verify_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moa.algorithm.id") + VERIFY_TEMPLATE_SUFIX; + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + + if (this.verify_template == null) + { + verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + } + + if (this.verify_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); //$NON-NLS-1$ + } + + this.verify_url = getConnectorValueFromProfile(settings, profile, VERIFY_URL_KEY); + + this.verify_trust_profile_id = settings.getValueFromKey(VERIFY_TRUST_PROFILE_ID); + + this.cert_alg_ecdsa = settings.getValueFromKey(ECDSA_CERT_ALG_KEY); + + this.cert_alg_rsa = settings.getValueFromKey(RSA_CERT_ALG_KEY); + + } + + public String getProfile() + { + return this.profile; + } + + /** + * Returns the URL where to load the detached data from. + * + * @return Returns the URL where to load the detached data from. + */ + public String getSignatureDataUrl() + { + return this.signature_data_url; + } + + /** + * Returns the sign key identifier. + * + * @return Returns the sign key identifier. + */ + public String getSignKeyIdentifier() + { + return this.sign_key_identifier; + } + + /** + * Returns the sign request template. + * + * @return Returns the sign request template. + */ + public String getSignRequestTemplate() + { + return this.sign_request_template; + } + + /** + * Returns the sign URL. + * + * @return Returns the sign URL. + */ + public String getSignURL() + { + return this.sign_url; + } + + /** + * Returns the verify request template. + * + * @return Returns the verify request template. + */ + public String getVerifyRequestTemplate() + { + return this.verify_request_template; + } + + /** + * Returns the verify template. + * + * @return Returns the verify template. + */ + public String getVerifyTemplate() + { + return this.verify_template; + } + + /** + * Returns the verify URL. + * + * @return Returns the verify URL. + */ + public String getVerifyURL() + { + return this.verify_url; + } + + /** + * Returns the verify trust profile id. + * + * @return Returns the verify trust profile id. + */ + public String getVerifyTrustProfileId() + { + return this.verify_trust_profile_id; + } + + /** + * Returns the ecdsa cert alg property. + * + * @return Returns the ecdsa cert alg property. + */ + public String getCertAlgEcdsa() + { + return this.cert_alg_ecdsa; + } + + /** + * Returns the rsa cert alg property. + * + * @return Returns the rsa cert alg property. + */ + public String getCertAlgRsa() + { + return this.cert_alg_rsa; + } + + /** + * Reads the configuration entry given by the key, first from the given + * profile, if not found from the defaults. + * + * @param settings + * The settings. + * @param profile + * The profile. + * @param key + * The configuration key. + * @return Returns the configuration entry. + */ + public static String getConnectorValueFromProfile(SettingsReader settings, String profile, String key) + { + String value = settings.getValueFromKey("sig_obj." + profile + "." + key); //$NON-NLS-1$//$NON-NLS-2$ + if (value == null) + { + value = settings.getValueFromKey(key); + } + return value; + } + + } + + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) + throws ConnectorException { + String xmldsig = chooseAndCreateXMLDsig(data, so); + return new XMLDsigData(xmldsig, true); + } + + private String chooseAndCreateXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException { + if (!SigKZIDHelper.isMOASigned(so)) + { + ConnectorParameters cp = new ConnectorParameters(); + cp.setProfileId(this.environment.getProfile()); + DetachedBKUConnector bku_connector = new DetachedBKUConnector(cp, "not needed here"); + return bku_connector.prepareXMLContent(data, so); + } + else + { + return prepareXMLContent(data, so); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java new file mode 100644 index 0000000..6f2d171 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/EnvelopingBase64MOAConnector.java @@ -0,0 +1,638 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.security.cert.X509Certificate; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.EnvelopedBase64BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.OldEnvelopingBase64BKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.sigid.OldMOAIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; + +/** + * @author wprinz + * + */ +public class EnvelopingBase64MOAConnector implements Connector +{ + //23.11.2010 changed by exthex - added reconstructXMLDsig method and moved xmldsig creation to chooseAndCreateXMLDsig method + /** + * The log. + */ + private static Log log = LogFactory.getLog(EnvelopingBase64MOAConnector.class); + + /** + * The environemnt configuration of this connector containing templates and + * other configurable elements. + */ + protected Environment environment = null; + + protected ConnectorParameters params = null; + + /** + * Constructor that builds the configuration environment for this connector + * according to the given profile. + * + *

+ * If confuguration parameters are not defined on that profile, the default + * parameters defined in the configuration are used. + *

+ * + * @param profile + * The profile from which the Environment should be assembled. + * @throws ConnectorException + * f.e. + */ + public EnvelopingBase64MOAConnector(ConnectorParameters connectorParameters) throws ConnectorException + { + this.params = connectorParameters; + this.environment = new Environment(connectorParameters.getProfileId(), connectorParameters.getSignatureKeyIdentifier()); + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doSign(at.knowcenter.wag.egov.egiz.sig.SignatureData) + */ + public SignSignatureObject doSign(SignatureData data) throws ConnectorException + { + log.debug("doSign:"); //$NON-NLS-1$ + + String sign_request_xml = prepareSignRequest(data); + log.debug("sign_request_xml = " + sign_request_xml); //$NON-NLS-1$ + + String url = this.environment.getSignURL(); + Properties response_properties = sendRequest(url, MOASoapConnection.SERVICE_SIGN, sign_request_xml); + + log.debug("response_string = " + response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY));; //$NON-NLS-1$ + SignSignatureObject sso = analyzeSignResponse(response_properties); + + sso.response_properties = response_properties; + + log.debug("doSign finished."); //$NON-NLS-1$ + return sso; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doVerify(at.knowcenter.wag.egov.egiz.sig.SignatureData, + * at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject) + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException + { + log.debug("doVerify:"); //$NON-NLS-1$ + + String verify_request_xml = prepareVerifyRequest(data, so, dsig); + log.debug("verify_request_xml = " + verify_request_xml); //$NON-NLS-1$ + + String url = this.environment.getVerifyURL(); + Properties response_properties = sendRequest(url, MOASoapConnection.SERVICE_VERIFY, verify_request_xml); + + SignatureResponse signature_response = analyzeVerifyResponse(response_properties); + + log.debug("doVerify finished."); //$NON-NLS-1$ + return signature_response; + } + + protected Properties sendRequest(String url, String mode, + String request_string) throws ConnectorException + { + try + { + Properties response_properties = MOASoapConnection.connectMOA(request_string, MOASoapConnection.SERVICE_SIGN, url); + return response_properties; + } + catch (Exception e) + { + throw new ConnectorException(330, e); + } + } + + /** + * Prepares the sign request xml to be sent using the sign request template. + * + * @param data + * The SignatureData. + * @return Returns the sign request xml to be sent. + * @throws ConnectorException + * f.e. + */ + protected String prepareSignRequest(SignatureData data) throws ConnectorException + { + log.debug("prepareSignRequest:"); //$NON-NLS-1$ + + String sign_request_template = this.environment.getSignRequestTemplate(); + + String sign_key_identifier = this.environment.getSignKeyIdentifier(); + String base64 = BKUHelper.prepareBase64Content(data); + + String sign_request_xml = sign_request_template.replaceFirst(TemplateReplaces.KEY_IDENTIFIER_REPLACE, sign_key_identifier); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.BASE64_CONTENT_REPLACE, base64); + + log.debug("prepareSignRequest finished."); //$NON-NLS-1$ + return sign_request_xml; + } + + /** + * Prepares the verify request xml to be sent using the verify request + * template. + * + * @param data + * The SignatureData. + * @param so + * The signature information object. + * @return Returns the verify request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException + { + String verify_request_template = this.environment.getVerifyRequestTemplate(); + + String xml_content = null; + if (dsigData != null && dsigData.getXmlDsig() != null) + { + xml_content = dsigData.getXmlDsig(); + } + else + { + xml_content = chooseAndCreateXMLDsig(data, so); + } + + String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.TRUST_PROFILE_ID_REPLACE, this.environment.getVerifyTrustProfileId()); + + String returnHashInputDataElement = ""; + if (this.params.isReturnHashInputData()) + { + returnHashInputDataElement = MOASoapWithAttachmentConnector.RETURN_HASH_INPUT_DATA; + } + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.RETURN_HASH_INPUT_DATA_REPLACE, returnHashInputDataElement); + + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.DATE_TIME_REPLACE, BKUHelper.formDateTimeElement(this.params.getVerificationTime())); + + + log.debug("\r\n\r\n" + verify_request_xml + "\r\n\r\n"); + + return verify_request_xml; + } + + /** + * Analyzes the sign response xml and extracts the signature data. + * + * @param response_properties + * The response properties containing the response String and + * transport related information. + * @return Returns the extracted data encapsulated in a SignatureObject. + * @throws ConnectorException + * f.e. + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeSignResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignSignatureObject so = MOAHelper.parseCreateXMLResponse(response_string, new OldMOAIdFormatter(), this.environment); + + log.debug("analyzeSignResponse finished."); //$NON-NLS-1$ + return so; + } + + /** + * Analyzes the verify response string. + * + * @param response_properties + * The response properties containing the response XML. + * @return Returns the SignatureResponse containing the verification result. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeVerifyResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignatureResponse signature_response = BKUHelper.parseVerifyXMLResponse(response_string); + + log.debug("analyzeVerifyResponse finished."); //$NON-NLS-1$ + return signature_response; + } + + /** + * Prepares the XML content the holds the actual signature data. + * + *

+ * This strongly rebuilds the XML content as retuned from a sign request. + *

+ * + * @param data + * The data. + * @param so + * The signature object containing the signature information. + * @return Returns the XML content. + * @throws ConnectorException + * f.e. + */ + public String prepareXMLContent(SignatureData data, SignSignatureObject so) throws ConnectorException + { + log.debug("prepareXMLContent:"); //$NON-NLS-1$ + try + { + X509Certificate cert = so.getX509Certificate(); + + // dferbas + AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); + String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); + + // data digest replace + byte[] data_value = BKUHelper.prepareEnvelopingData(data); + { + byte[] data_value_hash = CodingHelper.buildDigest(data_value, algSuite.getDataDigestMethod()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_DATA_REPLACE, object_data_hash); + } + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNATURE_VALUE_REPLACE, so.getSignatureValue()); + + // X.509 Certificate replace + byte[] der = cert.getEncoded(); + byte[] cert_hash = CodingHelper.buildDigest(der, algSuite.getCertDigestMethod()); + String certDigest = CodingHelper.encodeBase64(cert_hash); + String x509_cert_string = CodingHelper.encodeBase64(der); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_CERTIFICATE_REPLACE, x509_cert_string); + + // Qualified Properties replaces + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); + // SigDataRefReplace already done above + + // Signed Properties hash + { + final String ETSI_SIGNED_PROPERTIES_START_TAG = "= 0; + final int hash_end = verify_xml.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = verify_xml.substring(hash_start, hash_end); + log.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed); //$NON-NLS-1$ + + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); //$NON-NLS-1$ + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE, sig_prop_hash); + } + + // Base64 content replace -> do this at last for performance + String base64 = CodingHelper.encodeBase64(data_value); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.BASE64_CONTENT_REPLACE, base64); + + log.debug("prepareXMLContent finished."); //$NON-NLS-1$ + return verify_xml; + } + catch (Exception e) + { + log.debug(e); + throw new ConnectorException(310, e); + } + } + + /** + * Holds environment configuration information like templates. + * + * @author wprinz + */ + public static class Environment extends ConnectorEnvironment + { + /** + * The configuration key of the sign keybox identifier. + */ + protected static final String SIGN_KEY_IDENTIFIER_KEY = "moa.sign.KeyIdentifier"; //$NON-NLS-1$ + + /** + * The configuration key of the sign request template. + */ + protected static final String SIGN_REQUEST_TEMPLATE_KEY = "moa.sign.request.base64"; //$NON-NLS-1$ + + /** + * The configuration key of the sign URL. + */ + protected static final String SIGN_URL_KEY = "moa.sign.url"; //$NON-NLS-1$ + + /** + * The configuration key of the verify request template. + */ + protected static final String VERIFY_REQUEST_TEMPLATE_KEY = "moa.verify.request.base64"; //$NON-NLS-1$ + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "moa.verify.template.base64"; //$NON-NLS-1$ + + /** + * The configuration key of the verify URL. + */ + protected static final String VERIFY_URL_KEY = "moa.verify.url"; //$NON-NLS-1$ + + /** + * The configuration key of the trust profile id. + */ + protected static final String VERIFY_TRUST_PROFILE_ID = "moa.verify.TrustProfileID"; //$NON-NLS-1$ + + /** + * The configuration key for the ECDSA cert alg property. + */ + protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; //$NON-NLS-1$ + + /** + * The configuration key for the RSA cert alg property. + */ + protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; //$NON-NLS-1$ + + protected String profile = null; + + protected String sign_key_identifier = null; + + protected String sign_request_template = null; + + protected String sign_url = null; + + protected String verify_request_template = null; + + protected String verify_template = null; + + protected String verify_url = null; + + protected String verify_trust_profile_id = null; + + protected String cert_alg_ecdsa = null; + + protected String cert_alg_rsa = null; + + /** + * Initializes the environment with a given profile. + * + * @param profile + * The configuration profile. + * @throws ConnectorException + * f.e. + */ + public Environment(String profile, String signKeyIdentifier) throws ConnectorException + { + this.profile = profile; + + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(300, e); + } + + if (signKeyIdentifier != null) + { + this.sign_key_identifier = signKeyIdentifier; + } + else + { + this.sign_key_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEY_IDENTIFIER_KEY); + } + + String sign_request_filename = getConnectorValueFromProfile(settings, profile, SIGN_REQUEST_TEMPLATE_KEY); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + if (this.sign_request_template == null) + { + throw new ConnectorException(300, "Can not read the create xml request template"); //$NON-NLS-1$ + } + + this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); + + String verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + if (this.verify_request_template == null) + { + throw new ConnectorException(300, "Can not read the verify xml request template"); //$NON-NLS-1$ + } + + String verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + if (this.verify_template == null) + { + throw new ConnectorException(300, "Can not read the verify template"); //$NON-NLS-1$ + } + + this.verify_url = getConnectorValueFromProfile(settings, profile, VERIFY_URL_KEY); + + this.verify_trust_profile_id = settings.getValueFromKey(VERIFY_TRUST_PROFILE_ID); + + this.cert_alg_ecdsa = settings.getValueFromKey(ECDSA_CERT_ALG_KEY); + + this.cert_alg_rsa = settings.getValueFromKey(RSA_CERT_ALG_KEY); + + } + + public String getProfile() + { + return this.profile; + } + + /** + * Returns the sign key identifier. + * + * @return Returns the sign key identifier. + */ + public String getSignKeyIdentifier() + { + return this.sign_key_identifier; + } + + /** + * Returns the sign request template. + * + * @return Returns the sign request template. + */ + public String getSignRequestTemplate() + { + return this.sign_request_template; + } + + /** + * Returns the sign URL. + * + * @return Returns the sign URL. + */ + public String getSignURL() + { + return this.sign_url; + } + + /** + * Returns the verify request template. + * + * @return Returns the verify request template. + */ + public String getVerifyRequestTemplate() + { + return this.verify_request_template; + } + + /** + * Returns the verify template. + * + * @return Returns the verify template. + */ + public String getVerifyTemplate() + { + return this.verify_template; + } + + /** + * Returns the verify URL. + * + * @return Returns the verify URL. + */ + public String getVerifyURL() + { + return this.verify_url; + } + + /** + * Returns the verify trust profile id. + * + * @return Returns the verify trust profile id. + */ + public String getVerifyTrustProfileId() + { + return this.verify_trust_profile_id; + } + + /** + * Returns the ecdsa cert alg property. + * + * @return Returns the ecdsa cert alg property. + */ + public String getCertAlgEcdsa() + { + return this.cert_alg_ecdsa; + } + + /** + * Returns the rsa cert alg property. + * + * @return Returns the rsa cert alg property. + */ + public String getCertAlgRsa() + { + return this.cert_alg_rsa; + } + + /** + * Reads the configuration entry given by the key, first from the given + * profile, if not found from the defaults. + * + * @param settings + * The settings. + * @param profile + * The profile. + * @param key + * The configuration key. + * @return Returns the configuration entry. + */ + public static String getConnectorValueFromProfile(SettingsReader settings, + String profile, String key) + { + String value = settings.getValueFromKey("sig_obj." + profile + "." + key); //$NON-NLS-1$//$NON-NLS-2$ + if (value == null) + { + value = settings.getValueFromKey(key); + } + return value; + } + + } + + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) + throws ConnectorException { + String xmldsig = chooseAndCreateXMLDsig(data, so); + return new XMLDsigData(xmldsig, false); + } + + private String chooseAndCreateXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException { + if (!SigKZIDHelper.isMOASigned(so)) + { + if (SigKZIDHelper.isOldBKU(so)) + { + OldEnvelopingBase64BKUConnector bku_connector = new OldEnvelopingBase64BKUConnector(this.environment.getProfile()); + return bku_connector.prepareXMLContent(data, so); + } + else + { + EnvelopedBase64BKUConnector bku_connector = new EnvelopedBase64BKUConnector(this.environment.getProfile()); + return bku_connector.prepareXMLContent(data, so); + } + } + else + { + return prepareXMLContent(data, so); + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/FilePartMR.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/FilePartMR.java new file mode 100644 index 0000000..b52b39b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/FilePartMR.java @@ -0,0 +1,152 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.commons.httpclient.methods.multipart.PartSource; +import org.apache.commons.httpclient.util.EncodingUtil; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +public class FilePartMR extends + org.apache.commons.httpclient.methods.multipart.FilePart { + + /** Log object for this class. */ + private static final Log LOG = LogFactory.getLog(FilePartMR.class); + + /** Content dispostion characters */ + protected static final String CONTENT_ID = "Content-Id: "; + + /** Content dispostion as a byte array */ + protected static final byte[] CONTENT_ID_BYTES = + EncodingUtil.getAsciiBytes(CONTENT_ID); + + private String contentID = ""; + + public FilePartMR(String arg0, PartSource arg1) { + super(arg0, arg1); + // TODO Auto-generated constructor stub + } + + public FilePartMR(String arg0, File arg1) throws FileNotFoundException { + super(arg0, arg1); + // TODO Auto-generated constructor stub + } + + public FilePartMR(String arg0, String arg1, File arg2) + throws FileNotFoundException { + super(arg0, arg1, arg2); + // TODO Auto-generated constructor stub + } + + public FilePartMR(String arg0, PartSource arg1, String arg2, String arg3) { + super(arg0, arg1, arg2, arg3); + // TODO Auto-generated constructor stub + } + + public FilePartMR(String arg0, File arg1, String arg2, String arg3) + throws FileNotFoundException { + super(arg0, arg1, arg2, arg3); + // TODO Auto-generated constructor stub + } + + public FilePartMR(String arg0, String arg1, File arg2, String arg3, + String arg4) throws FileNotFoundException { + super(arg0, arg1, arg2, arg3, arg4); + // TODO Auto-generated constructor stub + } + + + public void setContentID(String contentid) { + this.contentID = contentid; + } + + public String getContentID() { + return this.contentID; + } + + /** + * Write the content id header to the specified output stream + * + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + protected void sendContentIDHeader(OutputStream out) throws IOException { + LOG.trace("enter sendContendID instead of ContentDisposition(OutputStream out)"); + out.write(CONTENT_ID_BYTES); + out.write(EncodingUtil.getAsciiBytes(getContentID())); + } + + /** + * Write all the data to the output stream. + * If you override this method make sure to override + * #length() as well + * + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + public void send(OutputStream out) throws IOException { + LOG.trace("enter send(OutputStream out)"); + sendStart(out); + + sendContentIDHeader(out); + sendContentTypeHeader(out); + sendTransferEncodingHeader(out); + sendEndOfHeader(out); + sendData(out); + sendEnd(out); + } + + + /** + * Return the full length of all the data. + * If you override this method make sure to override + * #send(OutputStream) as well + * + * @return long The length. + * @throws IOException If an IO problem occurs + */ + public long length() throws IOException { + LOG.trace("enter length()"); + if (lengthOfData() < 0) { + return -1; + } + ByteArrayOutputStream overhead = new ByteArrayOutputStream(); + sendStart(overhead); + + sendContentIDHeader(overhead); + sendContentTypeHeader(overhead); + sendTransferEncodingHeader(overhead); + sendEndOfHeader(overhead); + sendEnd(overhead); + return overhead.size() + lengthOfData(); + } + + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOAHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOAHelper.java new file mode 100644 index 0000000..8cb9a92 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOAHelper.java @@ -0,0 +1,228 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmMapper; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * @author wprinz + * + */ +public class MOAHelper +{ + /** + * The log. + */ + private static Log log = LogFactory.getLog(MOAHelper.class); + + /** + * This method parses the MOA-Response string. + * + *

+ * It separates the SignatureValue, X509IssuerName, SigningTime, + * X509SerialNumber, X509Certificate, CertDigest and DigestValues. If the + * X509Certificate is extracted it would be stored in the certificates + * directory. + *

+ * + * @param xmlResponse + * the response string from the MOA sign-request + * @throws ConnectorException + * ErrorCode (303, 304) + * @see SignatureObject + * @see CodingHelper + * @see X509Cert + */ + public static SignSignatureObject parseCreateXMLResponse(String xmlResponse, IdFormatter id_formatter, ConnectorEnvironment environment) throws ConnectorException + { + Pattern sig_val_p_s = Pattern.compile("<[\\w]*:?SignatureValue>"); //$NON-NLS-1$ + Pattern sig_val_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName>"); //$NON-NLS-1$ + Pattern iss_nam_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern sig_tim_p_s = Pattern.compile("<[\\w]*:?SigningTime>"); //$NON-NLS-1$ + Pattern sig_tim_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern ser_num_p_s = Pattern.compile("<[\\w]*:?X509SerialNumber>"); //$NON-NLS-1$ + Pattern ser_num_p_e = Pattern.compile(""); //$NON-NLS-1$ + Pattern sig_cer_p_s = Pattern.compile("<[\\w]*:?X509Certificate>"); //$NON-NLS-1$ + Pattern sig_cer_p_e = Pattern.compile(""); //$NON-NLS-1$ + + // Pattern sig_cer_d_p_s = Pattern.compile("<[\\w]*:?CertDigest>"); + // //$NON-NLS-1$ + // Pattern sig_cer_d_p_e = Pattern.compile(""); + // //$NON-NLS-1$ + // Pattern dig_val_p_s = Pattern.compile("<[\\w]*:?DigestValue>"); + // //$NON-NLS-1$ + // Pattern dig_val_p_e = Pattern.compile(""); + // //$NON-NLS-1$ + + Matcher sig_val_m_s = sig_val_p_s.matcher(xmlResponse); + Matcher sig_val_m_e = sig_val_p_e.matcher(xmlResponse); + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher sig_tim_m_s = sig_tim_p_s.matcher(xmlResponse); + Matcher sig_tim_m_e = sig_tim_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + Matcher sig_cer_m_s = sig_cer_p_s.matcher(xmlResponse); + Matcher sig_cer_m_e = sig_cer_p_e.matcher(xmlResponse); + + // Matcher sig_cer_d_m_s = sig_cer_d_p_s.matcher(xmlResponse); + // Matcher sig_cer_d_m_e = sig_cer_d_p_e.matcher(xmlResponse); + // Matcher dig_val_m_s = dig_val_p_s.matcher(xmlResponse); + // Matcher dig_val_m_e = dig_val_p_e.matcher(xmlResponse); + + // SignatureValue + String sig_val = null; + if (sig_val_m_s.find() && sig_val_m_e.find()) + { + sig_val = BKUHelper.removeAllWhitespace(xmlResponse.substring(sig_val_m_s.end(), sig_val_m_e.start())); + } + log.debug("sig_val = " + sig_val); //$NON-NLS-1$ + + // X509IssuerName + String iss_nam = null; + if (iss_nam_m_s.find() && iss_nam_m_e.find()) + { + iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + } + log.debug("iss_nam = " + iss_nam); //$NON-NLS-1$ + + // X509SerialNumber + String ser_num = null; + if (ser_num_m_s.find() && ser_num_m_e.find()) + { + ser_num = BKUHelper.removeAllWhitespace(xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start())); + } + log.debug("ser_num = " + ser_num); //$NON-NLS-1$ + + // SigningTime + String sig_tim = null; + if (sig_tim_m_s.find() && sig_tim_m_e.find()) + { + sig_tim = xmlResponse.substring(sig_tim_m_s.end(), sig_tim_m_e.start()); + } + log.debug("sig_tim = " + sig_tim); //$NON-NLS-1$ + + // CertDigest + // if (sig_cer_d_m_s.find() && sig_cer_d_m_e.find()) + // { + // String cert_digest = xmlResponse.substring(sig_cer_d_m_s.end(), + // sig_cer_d_m_e.start()); + // if (dig_val_m_s.find() && dig_val_m_e.find()) + // { + // sig_dig = cert_digest.substring(dig_val_m_s.end(), dig_val_m_e.start()); + // //sigObj.setX509CertificateDigest(sig_dig); + // } + // } + + // X509Certificate + X509Certificate cert = null; + if (sig_cer_m_s.find() && sig_cer_m_e.find()) + { + String sig_cer = BKUHelper.removeAllWhitespace(xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start())); + + try + { + byte[] der = CodingHelper.decodeBase64(sig_cer); + ByteArrayInputStream bais = new ByteArrayInputStream(der); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$ + cert = (X509Certificate) cf.generateCertificate(bais); + bais.close(); + } + catch (UnsupportedEncodingException e) + { + log.error(e); + throw new ConnectorException(300, e); + } + catch (CertificateException e) + { + log.error(e); + throw new ConnectorException(300, e); + } + catch (IOException e) + { + log.error(e); + throw new ConnectorException(300, e); + } + } + log.debug("X509Certificate = " + cert); //$NON-NLS-1$ + + if (log.isDebugEnabled()) + { + + String cert_iss = cert.getIssuerDN().getName(); + log.debug("certificate's issuer = " + cert_iss); //$NON-NLS-1$ + log.debug("response's issuer = " + iss_nam); //$NON-NLS-1$ + log.debug("issuer matches = " + cert_iss.equals(iss_nam)); //$NON-NLS-1$ + log.debug("ser number matches = " + cert.getSerialNumber().toString().equals(ser_num)); //$NON-NLS-1$ + } + + SignSignatureObject so = new SignSignatureObject(); + so.date = sig_tim; + so.issuer = iss_nam; + so.signatureValue = sig_val; + so.x509Certificate = cert; + + String algs = AlgorithmSuiteUtil.extractAlgorithmSuiteString(xmlResponse); + + AlgorithmSuiteObject suite = new AlgorithmSuiteObject(algs, false); + so.sigAlgorithm = AlgorithmMapper.getUri(suite.getSignatureMethod()); + + String defaultCertAlg = environment.getDefaultAlgForCert(cert); + + if (AlgorithmSuiteUtil.isDefaultCertAlg(algs, defaultCertAlg)) { + // do not embed default alg + algs = null; + } + + + + so.id = id_formatter.formatIds(null, algs); + + return so; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapConnection.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapConnection.java new file mode 100644 index 0000000..7aa3d7b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapConnection.java @@ -0,0 +1,277 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import java.util.Vector; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.rpc.Call; +import javax.xml.rpc.Service; +import javax.xml.rpc.ServiceFactory; + +import org.apache.axis.message.SOAPBodyElement; +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.methods.PostMethod; +import org.apache.commons.httpclient.methods.multipart.FilePart; +import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; +import org.apache.commons.httpclient.methods.multipart.Part; +import org.apache.commons.httpclient.methods.multipart.PartSource; +import org.apache.commons.httpclient.methods.multipart.StringPart; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.xml.serialize.OutputFormat; +import org.apache.xml.serialize.XMLSerializer; +import org.w3c.dom.Document; + +import at.knowcenter.wag.egov.egiz.exceptions.WebException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; + +/** + * @author wprinz + * + */ +public final class MOASoapConnection +{ + /** + * MOA siganture verification mode + */ + public static final String SERVICE_VERIFY = "SignatureVerification"; //$NON-NLS-1$ + + /** + * MOA siganture creation mode + */ + public static final String SERVICE_SIGN = "SignatureCreation"; //$NON-NLS-1$ + + /** + * The log. + */ + private static Log log = LogFactory.getLog(MOASoapConnection.class); + + /** + * This method connects the moa server getting the requestString, the given + * serviseMode and the endpointUrl. The requestString is the envelope of the + * SOAP Message send and recieve by the AXIS module. The Response SOAP message + * of the MOA server is parsed by AXIS and the message envelope is send back + * to the calling method. + * + * @param requestString + * the request string (XML) to send. + * @param serviceMode + * the mode which connect to MOA + * @param endpointURL + * the URL which the MOA server is running + * @return the response string (XML) of the MOA server + * @throws WebException + */ + public static Properties connectMOA(String requestString, String serviceMode, + String endpointURL) throws WebException + { + try + { + if (log.isDebugEnabled()) + { + log.debug(serviceMode); + log.debug(endpointURL); + } + // Parser/DOMBuilder instanzieren + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + + // XML Datei in einen DOM-Baum umwandeln + ByteArrayInputStream bais = new ByteArrayInputStream(requestString.getBytes("UTF-8")); //$NON-NLS-1$ + Document xmlRequest = builder.parse(bais); + + // Call öffnen + Call call = null; + + // Neues BodyElement anlegen und mit dem DOM-Baum füllen + SOAPBodyElement body = new SOAPBodyElement(xmlRequest.getDocumentElement()); + SOAPBodyElement[] params = new SOAPBodyElement[] { body }; + + // AXIS-Server instanzieren + Service service = ServiceFactory.newInstance().createService(new QName(serviceMode)); + call = service.createCall(); + call.setTargetEndpointAddress(endpointURL); + + // Call auslösen und die Antworten speichern + log.debug("Calling MOA: " + endpointURL); //$NON-NLS-1$ + Vector responses = (Vector) call.invoke(params); + + // Erstes Body Element auslesen + SOAPBodyElement response = (SOAPBodyElement) responses.get(0); + + // Aus der Response den DOM-Baum lesen + Document root_response = response.getAsDocument(); + log.debug("Return from MOA: " + serviceMode); //$NON-NLS-1$ + + // XML-Formatierung konfiguieren + OutputFormat format = new OutputFormat((Document) root_response); + format.setLineSeparator("\n"); //$NON-NLS-1$ + format.setIndenting(false); + format.setPreserveSpace(true); + format.setOmitXMLDeclaration(false); + format.setEncoding("UTF-8"); //$NON-NLS-1$ + + // Ausgabe der Webservice-Antwort auf die Konsole + // XMLSerializer conSerializer = new XMLSerializer(System.out, format); + // conSerializer.serialize(root_response); + + // Ausgabe der Webservice-Antwort in Datei + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + XMLSerializer response_serializer = new XMLSerializer(baos, format); + response_serializer.serialize(root_response); + String response_string = baos.toString("UTF-8"); //$NON-NLS-1$ + + Properties response_properties = new Properties(); + response_properties.setProperty(BKUPostConnection.RESPONSE_STRING_KEY, response_string); + + return response_properties; + } + catch (Exception e) + { + throw new WebException(e); + } + // serialize signature only + + // if + // (root_response.getDocumentElement().getLocalName().equals("CreateXMLSignatureResponse")) + // { + // Element signature = (Element) + // root_response.getElementsByTagNameNS("http://www.w3.org/2000/09/xmldsig#", + // "Signature").item(0); + // String signatureFile = getProperty(mode + "Request").substring(0, + // getProperty(mode + + // "Request").lastIndexOf('.')) + ".Signature.xml"; + // fileSerializer = new XMLSerializer(new FileOutputStream(signatureFile), + // format); + // fileSerializer.serialize(signature); + // } + + } + + public static Properties doPostRequestMultipart(String url, String serviceMode, String request, + final SignatureData data) throws HttpException, IOException + { + log.debug("doPostRequestMultipart:"); //$NON-NLS-1$ + + // Wrap XMLRequest into SOAP-Body + request = "" + + request.substring(request.indexOf("?>")+2)+ // do not forget to eliminate any additional XML-header + ""; + + StringPartMR xmlpart = new StringPartMR("test", request, "UTF-8"); //$NON-NLS-1$//$NON-NLS-2$ + xmlpart.setContentType("text/xml"); + xmlpart.setContentID(""); + + // add file to be signed + final String filename = data.getMimeType().equals("application/pdf") ? "myfile.pdf" : "myfile.txt"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + PartSource ps = new PartSource() { + public InputStream createInputStream() throws IOException + { + return data.getDataSource().createInputStream(); + } + + public String getFileName() + { + return filename; + } + + public long getLength() + { + return data.getDataSource().getLength(); + } + }; + //ByteArrayPartSource baps = new ByteArrayPartSource(filename, data.getData()); + FilePartMR filepart = new FilePartMR("fileupload", ps); //$NON-NLS-1$ + filepart.setContentType(data.getMimeType()); + filepart.setContentID(""); + + // not really needed since external referenced data has to be taken "as-is" (binary stream) for + // digest calculation, so neither content type nor charset is relevant + filepart.setCharSet(data.getCharacterEncoding()); + + Part[] parts = { xmlpart, filepart }; + + HttpMethodParams method_params = new HttpMethodParams(); + method_params.setContentCharset("UTF-8"); //$NON-NLS-1$ + + PostMethod post_method = new PostMethod(url); + post_method.setParams(method_params); + + + post_method.addRequestHeader("SOAPAction",serviceMode); + +// MultipartRequestEntity mprqe = new MultipartRequestEntity(parts, post_method.getParams()); + MultipartRelatedEntity mprqe = new MultipartRelatedEntity(parts, post_method.getParams()); + mprqe.setContentType("text/xml"); + mprqe.setStartID(""); + + post_method.setRequestEntity(mprqe); + // post_method.setRequestHeader("Content-Type", "multipart/related; type=\"text/xml\"; boundary=\""+"\""); + HttpClient http_client = new HttpClient(); + + int method_response = http_client.executeMethod(post_method); + log.debug("method_response = " + method_response); //$NON-NLS-1$ + + Properties response_properties = new Properties(); + + if (log.isDebugEnabled()) + { + Header[] response_headers = post_method.getResponseHeaders(); + for (int i = 0; i < response_headers.length; i++) + { + log.debug(" response_header[" + i + "]: name = " + response_headers[i].getName() + ", value = " + response_headers[i].getValue()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + } + Header server_header = post_method.getResponseHeader("Server"); //$NON-NLS-1$ + + response_properties.setProperty(BKUPostConnection.RESPONSE_STRING_KEY, server_header.getValue()); + + String charset = post_method.getResponseCharSet(); + log.debug("MOA response charset is \"" + charset + "\""); + if (!"UTF-8".equalsIgnoreCase(charset) && !"UTF8".equalsIgnoreCase(charset)) //$NON-NLS-1$ + { + log.warn("MOA response charset is not UTF-8!"); //$NON-NLS-1$ + } + String response_string = post_method.getResponseBodyAsString(); + + response_properties.setProperty(BKUPostConnection.RESPONSE_STRING_KEY, response_string); + + log.debug("doPostRequestMultipart finished."); //$NON-NLS-1$ + return response_properties; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java new file mode 100644 index 0000000..db0a04f --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MOASoapWithAttachmentConnector.java @@ -0,0 +1,745 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.security.cert.X509Certificate; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.PdfAS; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.DetachedBKUConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.LocRefDetachedMOCCAConnector; +import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedLocRefMOAIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Connects to MOA providing the Data detached as LocRef on a local resource. + * + * @author wprinz + */ +public class MOASoapWithAttachmentConnector implements Connector +{ + //23.11.2010 changed by exthex - added reconstructXMLDsig method and moved xmldsig creation to chooseAndCreateXMLDsig method + public static final String ATRUST_VERIFY_TEMPLATE_KEY = "atrust.verify.template.detached"; + +/** + * The SIG_ID prefix. + */ + // public static final String SIG_ID_PREFIX = "etsi-bku-detached@"; //$NON-NLS-1$ + /** + * The log. + */ + private static Log log = LogFactory.getLog(MOASoapWithAttachmentConnector.class); + + protected static final String MULTIPART_LOC_REF_CONTENT = "formdata:fileupload"; //$NON-NLS-1$ + + protected static final String RETURN_HASH_INPUT_DATA = ""; //$NON-NLS-1$ + + /** + * The connector parameters. + */ + protected ConnectorParameters params = null; + + /** + * The environemnt configuration of this connector containing templates and + * other configurable elements. + */ + protected Environment environment = null; + + + /** + * Constructor that builds the configuration environment for this connector + * according to the given profile. + * + *

+ * If confuguration parameters are not defined on that profile, the default + * parameters defined in the configuration are used. + *

+ * + * @param connectorParameters + * The parameters for this connector. + * @throws ConnectorException + * f.e. + */ + public MOASoapWithAttachmentConnector(ConnectorParameters connectorParameters) throws ConnectorException + { + this.params = connectorParameters; + this.environment = new Environment(this.params.getProfileId(), this.params.getSignatureKeyIdentifier(), MULTIPART_LOC_REF_CONTENT); + } + + protected String prepareSignRequest(SignatureData data) throws ConnectorException + { + log.debug("prepareSignRequestDetached:"); //$NON-NLS-1$ + + String sign_request_template = this.environment.getSignRequestTemplate(); + + String sign_key_identifier = this.environment.getSignKeyIdentifier(); + String loc_ref_content = this.environment.getSignatureDataUrl(); + String mime_type = data.getMimeType(); + if (log.isDebugEnabled()) + { + log.debug("sign keybox identifier = " + sign_key_identifier); //$NON-NLS-1$ + log.debug("LocRefContent = " + loc_ref_content); //$NON-NLS-1$ + log.debug("mime type = " + mime_type); //$NON-NLS-1$ + } + + String sign_request_xml = sign_request_template.replaceFirst(TemplateReplaces.KEY_IDENTIFIER_REPLACE, sign_key_identifier); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, loc_ref_content); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, mime_type); + + log.debug("prepareSignRequestDetached finished."); //$NON-NLS-1$ + return sign_request_xml; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector#analyzeSignResponse(java.util.Properties) + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeSignResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignSignatureObject so = MOAHelper.parseCreateXMLResponse(response_string, new DetachedLocRefMOAIdFormatter(), this.environment); + + log.debug("analyzeSignResponse finished."); //$NON-NLS-1$ + return so; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doSign(at.knowcenter.wag.egov.egiz.sig.SignatureData) + */ + public SignSignatureObject doSign(SignatureData data) throws ConnectorException + { + log.debug("doSign:"); //$NON-NLS-1$ + + String sign_request_xml = prepareSignRequest(data); +// DebugHelper.debugStringToFile(sign_request_xml, "MOA_DetLocRef_sign_request.xml"); //$NON-NLS-1$ + + String url = this.environment.getSignURL(); + Properties response_properties = sendRequest(url, MOASoapConnection.SERVICE_SIGN, sign_request_xml, data); + +// DebugHelper.debugStringToFile(response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY), "MOA_DetLocRef_sign_response.xml"); //$NON-NLS-1$ + SignSignatureObject sso = analyzeSignResponse(response_properties); + + sso.response_properties = response_properties; + + log.debug("doSign finished."); //$NON-NLS-1$ + return sso; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.connectors.Connector#doVerify(at.knowcenter.wag.egov.egiz.sig.SignatureData, + * at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject) + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException + { + log.debug("doVerify:"); //$NON-NLS-1$ + + String verify_request_xml = prepareVerifyRequest(data, so, dsig); + log.debug("verify_request_xml = " + verify_request_xml); //$NON-NLS-1$ + + String url = this.environment.getVerifyURL(); + Properties response_properties = sendRequest(url, MOASoapConnection.SERVICE_VERIFY, verify_request_xml, data); + + SignatureResponse signature_response = analyzeVerifyResponse(response_properties); + + log.debug("doVerify finished."); //$NON-NLS-1$ + return signature_response; + } + + /** + * Prepares the verify request xml to be sent using the verify request + * template. + * + * @param data + * The SignatureData. + * @param so + * The signature information object. + * @return Returns the verify request xml to be sent. + * @throws ConnectorException + * f.e. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException + { + String verify_request_template = this.environment.getVerifyRequestTemplate(); + + String xml_content = null; + if (dsigData != null && dsigData.getXmlDsig() != null) + { + xml_content = dsigData.getXmlDsig(); + } + else + { + xml_content = chooseAndCreateXMLDsig(data, so); + } + + String verify_request_xml = verify_request_template.replaceFirst(TemplateReplaces.XML_CONTENT_REPLACE, xml_content); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.TRUST_PROFILE_ID_REPLACE, this.environment.getVerifyTrustProfileId()); + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, this.environment.getSignatureDataUrl()); + + String returnHashInputDataElement = ""; + if (this.params.isReturnHashInputData()) + { + returnHashInputDataElement = RETURN_HASH_INPUT_DATA; + } + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.RETURN_HASH_INPUT_DATA_REPLACE, returnHashInputDataElement); + + verify_request_xml = verify_request_xml.replaceFirst(TemplateReplaces.DATE_TIME_REPLACE, BKUHelper.formDateTimeElement(this.params.getVerificationTime())); + + + log.debug("\r\n\r\n" + verify_request_xml + "\r\n\r\n"); + + return verify_request_xml; + } + + private String chooseAndCreateXMLDsig(SignatureData data, SignSignatureObject so) throws ConnectorException { + + // MOA + if (SigKZIDHelper.isMOASigned(so)) { + log.debug("MOA signature detected."); + return prepareXMLContent(data, so); + + // MOCCA + } else if (SigKZIDHelper.isMOCCASigned(so)) { + log.debug("MOCCA signature detected."); + String algorithmId = SigKZIDHelper.parseAlgorithmId(so.id); + log.debug("Algorithm = " + algorithmId); + LocRefDetachedMOCCAConnector mocca_connector = new LocRefDetachedMOCCAConnector(this.params, "not needed here", algorithmId); + return mocca_connector.prepareXMLContent(data, so); + + // ATrust + } else if (SigKZIDHelper.isATrustSigned(so)) { + log.debug("A-Trust signature detected."); + this.environment.reInitVerifyTemplate(ATRUST_VERIFY_TEMPLATE_KEY); + return prepareXMLContent(data, so); + + // TD bku + } else if (SigKZIDHelper.isBKUSigned(so)) { + log.debug("TD bku signature detected."); + DetachedBKUConnector bku_connector = new DetachedBKUConnector(this.params, "not needed here"); + return bku_connector.prepareXMLContent(data, so); + } else { + throw new ConnectorException(ErrorCode.UNSUPPORTED_SIGNATURE, "Unsupported signature (" + so.id + ", " +so.kz + "). Please get a new version of PDF-AS. Your version is: " + PdfAS.PDFAS_VERSION); + + } + } + + /** + * Analyzes the verify response string. + * + * @param response_properties + * The response properties containing the response XML. + * @return Returns the SignatureResponse containing the verification result. + * @throws ConnectorException + * f.e. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException + { + log.debug("analyzeVerifyResponse:"); //$NON-NLS-1$ + + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + BKUHelper.checkResponseForError(response_string); + + SignatureResponse signature_response = BKUHelper.parseVerifyXMLResponse(response_string); + + log.debug("analyzeVerifyResponse finished."); //$NON-NLS-1$ + return signature_response; + } + + public String prepareXMLContent(SignatureData data, SignSignatureObject so) throws ConnectorException + { + log.debug("prepareXMLContent:"); //$NON-NLS-1$ + try + { + + String verify_xml = null; + X509Certificate cert = so.getX509Certificate(); + + // dferbas + AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); + verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); + + + // data digest replace + { +// byte[] data_value = data.getData(); +// byte[] data_value_hash = CodingHelper.buildDigest(data_value); + byte[] data_value_hash = CodingHelper.buildDigest(data.getDataSource(), algSuite.getDataDigestMethod()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_DATA_REPLACE, object_data_hash); + } + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNATURE_VALUE_REPLACE, so.getSignatureValue()); + + // X.509 Certificate replace + byte[] der = cert.getEncoded(); + byte[] cert_hash = CodingHelper.buildDigest(der, algSuite.getCertDigestMethod()); + String certDigest = CodingHelper.encodeBase64(cert_hash); + String x509_cert_string = CodingHelper.encodeBase64(der); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_CERTIFICATE_REPLACE, x509_cert_string); + + // Qualified Properties replaces + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); + // SigDataRefReplace already done above + verify_xml = verify_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, data.getMimeType()); + + // Signed Properties hash + { + final String ETSI_SIGNED_PROPERTIES_START_TAG = "= 0; + final int hash_end = verify_xml.indexOf(ETSI_SIGNED_PROPERTIES_END_TAG, hash_start) + ETSI_SIGNED_PROPERTIES_END_TAG.length(); + assert hash_end - ETSI_SIGNED_PROPERTIES_END_TAG.length() >= 0; + assert hash_end > hash_start; + + final String string_to_be_hashed = verify_xml.substring(hash_start, hash_end); + log.debug("etsi:SignedProperties string to be hashed: " + string_to_be_hashed); //$NON-NLS-1$ + + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); //$NON-NLS-1$ + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE, sig_prop_hash); + } + + log.debug("prepareXMLContent finished."); //$NON-NLS-1$ + return verify_xml; + } + catch (Exception e) + { + log.debug(e); + throw new ConnectorException(310, e); + } + } + + + protected Properties sendRequest(String url, String mode, String request_string, SignatureData data) throws ConnectorException + { + try + { + // for performance measurement +// long startTime = 0; +// if (log.isInfoEnabled()) { +// startTime = System.currentTimeMillis(); +// } + +// Properties response_properties = MOASoapConnection.connectMOA(request_string, MOASoapConnection.SERVICE_SIGN, url); + log.debug("Connecting to " + url); + Properties response_properties = MOASoapConnection.doPostRequestMultipart(url,mode, request_string, data ); + + // for performance measurement +// if (log.isInfoEnabled()) { +// long endTime = System.currentTimeMillis(); +// String toReport = "MOA-PROCESSING;-;-;" + (endTime - startTime) + ";"; +// log.info(toReport); +// } + + return response_properties; + } + catch (Exception e) + { + throw new ConnectorException(330, e); + } + } + + public void reInitVerifyTemplate(String templatePropKey) throws ConnectorException { + this.environment.reInitVerifyTemplate(templatePropKey); + } + + /** + * Holds environment configuration information like templates. + * + * @author wprinz + */ + public static class Environment extends ConnectorEnvironment + { + /** + * The configuration key of the sign keybox identifier. + */ + protected static final String SIGN_KEY_IDENTIFIER_KEY = "moa.sign.KeyIdentifier"; //$NON-NLS-1$ + + /** + * The configuration key of the sign request template. + */ + protected static final String SIGN_REQUEST_TEMPLATE_KEY = "moa.sign.request.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the sign URL. + */ + protected static final String SIGN_URL_KEY = "moa.sign.url"; //$NON-NLS-1$ + + /** + * MOA template file prefix + */ + protected static final String TEMPLATE_FILE_PREFIX = "/templates/moa."; + + /** + * signing file template sufix + */ + protected static final String SIGN_TEMPLATE_FILE_SUFIX = ".sign.xml"; + + /** + * verifing template file sufix + */ + protected static final String VERIFY_REQUEST_TEMPLATE_FILE_SUFIX = ".verify.request.xml"; + + /** + * verifing file template key sufix + */ + protected static final String VERIFY_TEMPLATE_SUFIX = ".verify.template.xml"; + + /** + * The configuration key of the verify request template. + */ + protected static final String VERIFY_REQUEST_TEMPLATE_KEY = "moa.verify.request.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "moa.verify.template.detached"; //$NON-NLS-1$ + + /** + * The configuration key of the verify URL. + */ + protected static final String VERIFY_URL_KEY = "moa.verify.url"; //$NON-NLS-1$ + + /** + * The configuration key of the trust profile id. + */ + protected static final String VERIFY_TRUST_PROFILE_ID = "moa.verify.TrustProfileID"; //$NON-NLS-1$ + + /** + * The configuration key for the ECDSA cert alg property. + */ + protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; //$NON-NLS-1$ + + /** + * The configuration key for the RSA cert alg property. + */ + protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; //$NON-NLS-1$ + + protected String profile = null; + + protected String signature_data_url = null; + + protected String sign_key_identifier = null; + + protected String sign_request_template = null; + + protected String sign_url = null; + + protected String verify_request_template = null; + + protected String verify_template = null; + + protected String verify_url = null; + + protected String verify_trust_profile_id = null; + + protected String cert_alg_ecdsa = null; + + protected String cert_alg_rsa = null; + + + public void reInitVerifyTemplate(String templatePropKey) throws ConnectorException { + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(300, e); + } + + String verify_request_filename = getConnectorValueFromProfile(settings, this.profile, templatePropKey); + this.verify_template = settings.readInternalResourceAsString(verify_request_filename); + + } + /** + * Initializes the environment with a given profile. + * + * @param profile + * The configuration profile. + * @throws SettingsException + * f.e. + * @throws ConnectorException + * f.e. + */ + public Environment(String profile, String signKeyIdentifier, String signature_data_url) throws ConnectorException + { + this.profile = profile; + + this.signature_data_url = signature_data_url; + + SettingsReader settings = null; + try + { + settings = SettingsReader.getInstance(); + } + catch (SettingsException e) + { + throw new ConnectorException(300, e); + } + + if (signKeyIdentifier != null) + { + this.sign_key_identifier = signKeyIdentifier; + } + else + { + this.sign_key_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEY_IDENTIFIER_KEY); + } + + String sign_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moa.algorithm.id") + SIGN_TEMPLATE_FILE_SUFIX; + + // try to load template from file + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + + if (this.sign_request_template == null) + { + sign_request_filename = getConnectorValueFromProfile(settings, profile, SIGN_REQUEST_TEMPLATE_KEY); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + } + + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + if (this.sign_request_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the create xml request template"); //$NON-NLS-1$ + } + + this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); + + String verify_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moa.algorithm.id") + VERIFY_REQUEST_TEMPLATE_FILE_SUFIX; + + // try to load template file for verifing + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + + if (this.verify_request_template == null) + { + verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); + //this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + this.verify_request_template = settings.readInternalResourceAsString(verify_request_filename); + } + + if (this.verify_request_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); //$NON-NLS-1$ + } + + // load template key file + String verify_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moa.algorithm.id") + VERIFY_TEMPLATE_SUFIX; + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + + if (this.verify_template == null) + { + verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + } + + if (this.verify_template == null) + { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); //$NON-NLS-1$ + } + + this.verify_url = getConnectorValueFromProfile(settings, profile, VERIFY_URL_KEY); + + this.verify_trust_profile_id = settings.getValueFromKey(VERIFY_TRUST_PROFILE_ID); + + this.cert_alg_ecdsa = settings.getValueFromKey(ECDSA_CERT_ALG_KEY); + + this.cert_alg_rsa = settings.getValueFromKey(RSA_CERT_ALG_KEY); + + } + + public String getProfile() + { + return this.profile; + } + + /** + * Returns the URL where to load the detached data from. + * + * @return Returns the URL where to load the detached data from. + */ + public String getSignatureDataUrl() + { + return this.signature_data_url; + } + + /** + * Returns the sign key identifier. + * + * @return Returns the sign key identifier. + */ + public String getSignKeyIdentifier() + { + return this.sign_key_identifier; + } + + /** + * Returns the sign request template. + * + * @return Returns the sign request template. + */ + public String getSignRequestTemplate() + { + return this.sign_request_template; + } + + /** + * Returns the sign URL. + * + * @return Returns the sign URL. + */ + public String getSignURL() + { + return this.sign_url; + } + + /** + * Returns the verify request template. + * + * @return Returns the verify request template. + */ + public String getVerifyRequestTemplate() + { + return this.verify_request_template; + } + + /** + * Returns the verify template. + * + * @return Returns the verify template. + */ + public String getVerifyTemplate() + { + return this.verify_template; + } + + /** + * Returns the verify URL. + * + * @return Returns the verify URL. + */ + public String getVerifyURL() + { + return this.verify_url; + } + + /** + * Returns the verify trust profile id. + * + * @return Returns the verify trust profile id. + */ + public String getVerifyTrustProfileId() + { + return this.verify_trust_profile_id; + } + + /** + * Returns the ecdsa cert alg property. + * + * @return Returns the ecdsa cert alg property. + */ + public String getCertAlgEcdsa() + { + return this.cert_alg_ecdsa; + } + + /** + * Returns the rsa cert alg property. + * + * @return Returns the rsa cert alg property. + */ + public String getCertAlgRsa() + { + return this.cert_alg_rsa; + } + + /** + * Reads the configuration entry given by the key, first from the given + * profile, if not found from the defaults. + * + * @param settings + * The settings. + * @param profile + * The profile. + * @param key + * The configuration key. + * @return Returns the configuration entry. + */ + public static String getConnectorValueFromProfile(SettingsReader settings, String profile, String key) + { + String value = settings.getValueFromKey("sig_obj." + profile + "." + key); //$NON-NLS-1$//$NON-NLS-2$ + if (value == null) + { + value = settings.getValueFromKey(key); + } + return value; + } + + } + + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) + throws ConnectorException { + String xmldsig = chooseAndCreateXMLDsig(data, so); + return new XMLDsigData(xmldsig, true); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MultipartRelatedEntity.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MultipartRelatedEntity.java new file mode 100644 index 0000000..dd9f8b8 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/MultipartRelatedEntity.java @@ -0,0 +1,79 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; +import org.apache.commons.httpclient.methods.multipart.Part; +import org.apache.commons.httpclient.params.HttpMethodParams; +import org.apache.commons.httpclient.util.EncodingUtil; + +public class MultipartRelatedEntity extends MultipartRequestEntity { + + /** The Content-Type for multipart/related. */ + private static final String MULTIPART_RELATED_CONTENT_TYPE = "multipart/related"; + + + private String startID; + + private String contentType; + + public MultipartRelatedEntity(Part[] parts, HttpMethodParams params) { + super(parts, params); + // TODO Auto-generated constructor stub + } + + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + + public String getStartID() { + return startID; + } + + + public void setStartID(String startID) { + this.startID = startID; + } + + + /* (non-Javadoc) + * @see org.apache.commons.httpclient.methods.RequestEntity#getContentType() + */ + public String getContentType() { + StringBuffer buffer = new StringBuffer(MULTIPART_RELATED_CONTENT_TYPE); + buffer.append("; type=\""); + buffer.append(EncodingUtil.getAsciiString(this.contentType.getBytes())); + buffer.append("\"; start=\""); + buffer.append(EncodingUtil.getAsciiString(getStartID().getBytes())); + buffer.append("\"; boundary=\""); + buffer.append(EncodingUtil.getAsciiString(getMultipartBoundary())); + buffer.append("\""); + return buffer.toString(); + } + + + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/StringPartMR.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/StringPartMR.java new file mode 100644 index 0000000..2efcbcc --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/moa/StringPartMR.java @@ -0,0 +1,189 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.moa; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.commons.httpclient.methods.multipart.StringPart; +import org.apache.commons.httpclient.util.EncodingUtil; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +public class StringPartMR extends StringPart { + + /** Log object for this class. */ + private static final Log LOG = LogFactory.getLog(StringPartMR.class); + + + /** Content dispostion characters */ + protected static final String CONTENT_ID = "Content-Id: "; + + /** Content dispostion as a byte array */ + protected static final byte[] CONTENT_ID_BYTES = + EncodingUtil.getAsciiBytes(CONTENT_ID); + + private String contentID = ""; + + public StringPartMR(String name, String value, String charset) { + super(name, value, charset); + // TODO Auto-generated constructor stub + } + + public StringPartMR(String name, String value) { + super(name, value); + // TODO Auto-generated constructor stub + } + + /** + * Write the content disposition header to the specified output stream + * + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + protected void sendDispositionHeader(OutputStream out) throws IOException { + LOG.trace("enter sendContendID instead of ContentDisposition(OutputStream out)"); + // Do nothing ! + } + + /** + * Write the content id header to the specified output stream + * + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + protected void sendContentIDHeader(OutputStream out) throws IOException { + LOG.trace("enter sendContendID instead of ContentDisposition(OutputStream out)"); + out.write(CONTENT_ID_BYTES); + out.write(EncodingUtil.getAsciiBytes(getContentID())); + } + + + /** + * Write the content type header to the specified output stream + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + protected void sendContentTypeHeader(OutputStream out) throws IOException { + LOG.trace("enter sendContentTypeHeader(OutputStream out)"); + String contentType = getContentType(); + if (contentType != null) { + out.write(CRLF_BYTES); + out.write(CONTENT_TYPE_BYTES); + out.write(EncodingUtil.getAsciiBytes(contentType)); + String charSet = getCharSet(); + if (charSet != null) { + out.write(CHARSET_BYTES); + out.write(EncodingUtil.getAsciiBytes(charSet)); + } + } + } + + /** + * Write the content transfer encoding header to the specified + * output stream + * + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + protected void sendTransferEncodingHeader(OutputStream out) throws IOException { + LOG.trace("enter sendTransferEncodingHeader(OutputStream out)"); + String transferEncoding = getTransferEncoding(); + if (transferEncoding != null) { + out.write(CRLF_BYTES); + out.write(CONTENT_TRANSFER_ENCODING_BYTES); + out.write(EncodingUtil.getAsciiBytes(transferEncoding)); + } + } + + public void setContentID(String contentid) { + this.contentID = contentid; + } + + public String getContentID() { + return this.contentID; + } + + /** + * Write the end of the header to the output stream + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + protected void sendEndOfHeader(OutputStream out) throws IOException { + LOG.trace("enter sendEndOfHeader(OutputStream out)"); + out.write(CRLF_BYTES); + out.write(CRLF_BYTES); + } + + + /** + * Write all the data to the output stream. + * If you override this method make sure to override + * #length() as well + * + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + public void send(OutputStream out) throws IOException { + LOG.trace("enter send(OutputStream out)"); + sendStart(out); + + sendContentIDHeader(out); + sendContentTypeHeader(out); + sendTransferEncodingHeader(out); + sendEndOfHeader(out); + sendData(out); + sendEnd(out); + } + + + /** + * Return the full length of all the data. + * If you override this method make sure to override + * #send(OutputStream) as well + * + * @return long The length. + * @throws IOException If an IO problem occurs + */ + public long length() throws IOException { + LOG.trace("enter length()"); + if (lengthOfData() < 0) { + return -1; + } + ByteArrayOutputStream overhead = new ByteArrayOutputStream(); + sendStart(overhead); + + sendContentIDHeader(overhead); + sendContentTypeHeader(overhead); + sendTransferEncodingHeader(overhead); + sendEndOfHeader(overhead); + sendEnd(overhead); + return overhead.size() + lengthOfData(); + } + + + + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java new file mode 100644 index 0000000..12fc709 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/LocRefDetachedMOCCAConnector.java @@ -0,0 +1,623 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.mocca; + +import java.security.cert.X509Certificate; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.gv.egiz.pdfas.api.xmldsig.XMLDsigData; +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.gv.egiz.pdfas.framework.ConnectorParameters; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.sig.SignatureData; +import at.knowcenter.wag.egov.egiz.sig.SignatureResponse; +import at.knowcenter.wag.egov.egiz.sig.connectors.Connector; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.LocalConnector; +import at.knowcenter.wag.egov.egiz.sig.connectors.TemplateReplaces; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUPostConnection; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandlerFactory; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Connector for MOCCA. + * @author tknall + */ +public class LocRefDetachedMOCCAConnector implements Connector, LocalConnector { + //23.11.2010 changed by exthex - added reconstructXMLDsig method and moved xmldsig creation to chooseAndCreateXMLDsig method + + private static Log log = LogFactory.getLog(LocRefDetachedMOCCAConnector.class); + + /** + * The connector parameters. + */ + protected ConnectorParameters params = null; + + /** + * The environment of this connector containing templates. + */ + protected Environment environment = null; + + /** + * Constructor that builds the configuration environment for this connector according to the + * given profile. + * @param connectorParameters The connectot parameters. + * @throws ConnectorException Thrown in case of error. + */ + public LocRefDetachedMOCCAConnector(ConnectorParameters connectorParameters, String loc_ref_content) throws ConnectorException { + this(connectorParameters, loc_ref_content, null); + } + + /** + * Constructor that builds the configuration environment for this connector according to the + * given profile. + * @param connectorParameters The connectot parameters. + * @param algorithmId The algorithm idenifier. + * @throws ConnectorException Thrown in case of error. + */ + public LocRefDetachedMOCCAConnector(ConnectorParameters connectorParameters, String loc_ref_content, String algorithmId) throws ConnectorException { + this.params = connectorParameters; + this.environment = new Environment(this.params.getProfileId(), loc_ref_content, algorithmId); + } + + /** + * Sends the request to the given URL. This method handles communication exceptions. + * The actual send work is done by doPostRequestMultipart. + * @see BKUPostConnection#doPostRequestMultipart(String, String, SignatureData) + * @param url The URL to send the request to. + * @param request_string The request XML. + * @param data The data. + * @return Returns the response properties containing among others the response XML. + * @throws ConnectorException Thrown in case of an error. + */ + protected Properties sendRequest(String url, String request_string, SignatureData data) throws ConnectorException { + try { + Properties response_properties = BKUPostConnection.doPostRequestMultipart(url, request_string, data); + return response_properties; + } catch (Exception e) { + ConnectorException se = new ConnectorException(320, e); + throw se; + } + } + + /** + * Starts a signature process. + * @param data The data to be signed. + * @return Returns the signature object containing the signed data. + * @throws ConnectorException Thrown in case of an error. + */ + public SignSignatureObject doSign(SignatureData data) throws ConnectorException { + log.debug("doSign:"); + + String sign_request_xml = prepareSignRequest(data); + log.debug("sign_request_xml = " + sign_request_xml); + + String url = this.environment.getSignURL(); + Properties response_properties = sendRequest(url, sign_request_xml, data); + + SignSignatureObject sso = analyzeSignResponse(response_properties); + + sso.response_properties = response_properties; + + log.debug("doSign finished."); + return sso; + } + + /** + * Verification is not supported by MOCCA. Therefore this method always throws a + * {@link ConnectorException} with error code {@link ErrorCode#SIGNATURE_VERIFICATION_NOT_SUPPORTED}. + */ + public SignatureResponse doVerify(SignatureData data, SignSignatureObject so, XMLDsigData dsig) throws ConnectorException { + throw new ConnectorException(ErrorCode.SIGNATURE_VERIFICATION_NOT_SUPPORTED, "Signature Verification is not supported by MOCCA."); + } + + /** + * This method analyzes a signature response of the signature device. + * @param response_properties The response elements of the signature device. + * @return The parsed signed signature object. + * @throws ConnectorException Thrown in case of an error. + */ + public SignSignatureObject analyzeSignResponse(Properties response_properties) throws ConnectorException { + log.debug("analyzeSignResponse:"); + String response_string = response_properties.getProperty(BKUPostConnection.RESPONSE_STRING_KEY); + + String bkuIdentifier = BKUHelper.getBKUIdentifier(response_properties); + log.debug("BKU identifier: \"" + bkuIdentifier + "\""); + SignatureLayoutHandler sigLayout; + try { + sigLayout = SignatureLayoutHandlerFactory.getSignatureLayoutHandlerInstance(bkuIdentifier); + } catch (SettingsException e) { + throw new ConnectorException(e.getErrorCode(), e.getMessage()); + } + + BKUHelper.checkResponseForError(response_string); + +// SignSignatureObject so = MOCCAHelper.parseCreateXMLResponse(response_string, new DetachedMOCIdFormatter()); + SignSignatureObject so = sigLayout.parseCreateXMLSignatureResponse(response_string, this.environment); + so.response_properties = response_properties; + log.debug("analyzeSignResponse finished."); + return so; + } + + /** + * Verification is not supported by MOCCA. Therefore this method always throws a + * {@link ConnectorException} with error code {@link ErrorCode#SIGNATURE_VERIFICATION_NOT_SUPPORTED}. + */ + public SignatureResponse analyzeVerifyResponse(Properties response_properties) throws ConnectorException { + throw new ConnectorException(ErrorCode.SIGNATURE_VERIFICATION_NOT_SUPPORTED, "Signature Verification is not supported by MOCCA."); + } + + /** + * Prepares the signature request xml to be sent using the sign request template. + * @param data The signature data. + * @return Returns the sign request xml to be sent. + * @throws ConnectorException Thrown in case of an error. + */ + public String prepareSignRequest(SignatureData data) throws ConnectorException { + log.debug("prepareSignRequestDetached:"); + + String sign_request_template = this.environment.getSignRequestTemplate(); + + String sign_keybox_identifier = this.environment.getSignKeyboxIdentifier(); + String mime_type = data.getMimeType(); + String loc_ref_content = this.environment.getLocRefContent(); + + if (log.isDebugEnabled()) { + log.debug("sign keybox identifier = " + sign_keybox_identifier); + log.debug("mime type = " + mime_type); + log.debug("loc_ref_content = " + loc_ref_content); + } + + String sign_request_xml = sign_request_template.replaceFirst(TemplateReplaces.KEYBOX_IDENTIFIER_REPLACE, sign_keybox_identifier); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, mime_type); + sign_request_xml = sign_request_xml.replaceFirst(TemplateReplaces.LOC_REF_CONTENT_REPLACE, loc_ref_content); + + log.debug("sign_request_xml = " + sign_request_xml); + log.debug("prepareSignRequestDetached finished."); + return sign_request_xml; + } + + /** + * Verification is not supported by MOCCA. Therefore this method always throws a + * {@link ConnectorException} with error code {@link ErrorCode#SIGNATURE_VERIFICATION_NOT_SUPPORTED}. + */ + public String prepareVerifyRequest(SignatureData data, SignSignatureObject so, XMLDsigData dsigData) throws ConnectorException { + throw new ConnectorException(ErrorCode.SIGNATURE_VERIFICATION_NOT_SUPPORTED, "Signature Verification is not supported by MOCCA."); + } + + /** + * Prepares the xml content of a signature creation request including the link to the signature data. + * @param data The signature data. + * @param so The signature object containing the signature information. + * @return Returns the xml content. + * @throws ConnectorException Thrown in case of an error. + */ + public String prepareXMLContent(SignatureData data, SignSignatureObject so) throws ConnectorException { + log.debug("prepareXMLContent:"); + try { + + String ids_string = so.getSigID(); + String sigId = this.parseSigId(ids_string); + + X509Certificate cert = so.getX509Certificate(); + + + // dferbas + AlgorithmSuiteObject algSuite = new AlgorithmSuiteObject(); + String verify_xml = AlgorithmSuiteUtil.evaluateReplaceAlgs(algSuite, this.environment, so); + + // data digest replace + byte[] data_value_hash = CodingHelper.buildDigest(data.getDataSource(), algSuite.getDataDigestMethod()); + String object_data_hash = CodingHelper.encodeBase64(data_value_hash); + + // template replacements + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_DATA_REPLACE, object_data_hash); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNATURE_VALUE_REPLACE, so.getSignatureValue()); + + // X.509 Certificate replace + byte[] der = cert.getEncoded(); + byte[] cert_hash = CodingHelper.buildDigest(der, algSuite.getCertDigestMethod()); + String certDigest = CodingHelper.encodeBase64(cert_hash); + String x509_cert_string = CodingHelper.encodeBase64(der); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_CERTIFICATE_REPLACE, x509_cert_string); + + // Qualified Properties replaces + verify_xml = verify_xml.replaceAll(TemplateReplaces.SIG_ID_REPLACE, sigId); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.SIGNING_TIME_REPLACE, so.getDate()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_CERTIFICATE_REPLACE, certDigest); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_ISSUER_NAME_REPLACE, so.getIssuer()); + verify_xml = verify_xml.replaceFirst(TemplateReplaces.X509_SERIAL_NUMBER_REPLACE, so.getSerialNumber()); + // SigDataRefReplace already done above + verify_xml = verify_xml.replaceFirst(TemplateReplaces.MIME_TYPE_REPLACE, data.getMimeType()); + + // Signed Properties hash + Pattern spPattern = Pattern.compile("(<(\\w+:)?SignedProperties.*>.*)"); + Matcher matcher = spPattern.matcher(verify_xml); + if (matcher.find()) { + log.debug("SignedProperties found."); + String string_to_be_hashed = matcher.group(1); + log.debug("SignedProperties string to be hashed: " + string_to_be_hashed); + final byte[] bytes_to_be_hashed = string_to_be_hashed.getBytes("UTF-8"); + byte[] sig_prop_code = CodingHelper.buildDigest(bytes_to_be_hashed, algSuite.getPropertiesDigestMethod()); + String sig_prop_hash = CodingHelper.encodeBase64(sig_prop_code); + + verify_xml = verify_xml.replaceFirst(TemplateReplaces.DIGEST_VALUE_SIGNED_PROPERTIES_REPLACE, sig_prop_hash); + } + + log.debug("prepareXMLContent finished."); + return verify_xml; + } catch (Exception e) { + log.debug(e); + throw new ConnectorException(310, e); + } + } + + /** + * Holds environment configuration information like templates. + * @author wprinz + */ + public static class Environment extends ConnectorEnvironment { + + /** + * The configuration key of the sign keybox identifier. + */ + protected static final String SIGN_KEYBOX_IDENTIFIER_KEY = "moc.sign.KeyboxIdentifier"; + + /** + * The configuration key of the sign request template. + */ + protected static final String SIGN_REQUEST_TEMPLATE_KEY = "moc.sign.request.detached"; + + /** + * The configuration key of the sign URL. + */ + protected static final String SIGN_URL_KEY = "moc.sign.url"; + + /** + * BKU template file prefix + */ + protected static final String TEMPLATE_FILE_PREFIX = "/templates/moc."; + + /** + * signing file template suffix + */ + protected static final String SIGN_TEMPLATE_FILE_SUFFIX = ".sign.request.xml"; + + /** + * verifing template file suffix + */ + /* signature verification is not supported by mocca + protected static final String VERIFY_REQUEST_TEMPLATE_FILE_SUFIX = ".verify.request.xml"; + */ + + /** + * verifing file template key suffix + */ + protected static final String VERIFY_TEMPLATE_SUFFIX = ".verify.template.xml"; + + /** + * The configuration key of the verify request template. + */ + /* signature verification is not supported by mocca + protected static final String VERIFY_REQUEST_TEMPLATE_KEY = "moc.verify.request.detached"; + */ + + /** + * The configuration key of the verify template. + */ + protected static final String VERIFY_TEMPLATE_KEY = "moc.verify.template.detached"; + + /** + * The configuration key of the verify URL. + */ + /* signature verification is not supported by mocca + protected static final String xxxVERIFY_URL_KEY = "moc.verify.url"; + */ + + /** + * The configuration key for the ECDSA cert alg property. + */ + protected static final String ECDSA_CERT_ALG_KEY = "cert.alg.ecdsa"; + + /** + * The configuration key for the RSA cert alg property. + */ + protected static final String RSA_CERT_ALG_KEY = "cert.alg.rsa"; + + protected String profile = null; + + protected String loc_ref_content = null; + + protected String sign_keybox_identifier = null; + + protected String sign_request_template = null; + + protected String sign_url = null; + + /* signature verification is not supported by mocca + protected String verify_request_template = null; + */ + + protected String verify_template = null; + + /* signature verification is not supported by mocca + protected String verify_url = null; + */ + + protected String cert_alg_ecdsa = null; + + protected String cert_alg_rsa = null; + + protected String algorithmId = null; + + /** + * Initializes the environment with a given profile. + * @param profile The configuration profile. + * @param algorithmId The algorithm identifer. + * @throws ConnectorException Thrown in case of an error. + */ + public Environment(String profile, String loc_ref_content, String algorithmId) throws ConnectorException { + this.profile = profile; + + this.loc_ref_content = loc_ref_content; + + SettingsReader settings = null; + try { + settings = SettingsReader.getInstance(); + } catch (SettingsException e) { + throw new ConnectorException(300, e); + } + + this.sign_keybox_identifier = getConnectorValueFromProfile(settings, profile, SIGN_KEYBOX_IDENTIFIER_KEY); + + if (algorithmId == null) { + this.algorithmId = settings.getValueFromKey("default.moc.algorithm.id"); + } else { + this.algorithmId = algorithmId; + } + + // SIGN REQUEST + + // try specific file + String sign_request_filename = TEMPLATE_FILE_PREFIX + this.algorithmId + SIGN_TEMPLATE_FILE_SUFFIX; + log.debug("Trying to load specific sign request file " + sign_request_filename); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + + // try default request file + if (this.sign_request_template == null) { + sign_request_filename = getConnectorValueFromProfile(settings, profile, SIGN_REQUEST_TEMPLATE_KEY); + log.debug("Specific file not found. Trying default sign request file " + sign_request_filename); + //this.sign_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(sign_request_filename)); + this.sign_request_template = settings.readInternalResourceAsString(sign_request_filename); + } + + // request file is needed !!! + if (this.sign_request_template == null) { + throw new ConnectorException(300, "Can not read the create xml request template"); + } + + this.sign_url = getConnectorValueFromProfile(settings, profile, SIGN_URL_KEY); + + + // VERIFY REQUEST + /* signature verification is not supported by mocca + + // try specific file + String verify_request_filename = TEMPLATE_FILE_PREFIX + settings.getValueFromKey("default.moc.algorithm.id") + VERIFY_REQUEST_TEMPLATE_FILE_SUFIX; + log.debug("Trying to load specific verify request file " + verify_request_filename); + this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + + // try default request file + if (this.verify_request_template == null) { + verify_request_filename = getConnectorValueFromProfile(settings, profile, VERIFY_REQUEST_TEMPLATE_KEY); + log.debug("Specific file not found. Trying default verify request file " + verify_request_filename); + this.verify_request_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_request_filename)); + } + + // request file is needed !!! + if (this.verify_request_template == null) { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify xml request template"); + } + + */ + + // load template file + // try specific file + String verify_filename = TEMPLATE_FILE_PREFIX + this.algorithmId + VERIFY_TEMPLATE_SUFFIX; + log.debug("Trying to load specific signature template file " + verify_filename); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + + // try default signature template file + if (this.verify_template == null) { + verify_filename = getConnectorValueFromProfile(settings, profile, VERIFY_TEMPLATE_KEY); + log.debug("Specific signature template file not found. Trying default signature template file " + verify_filename); + //this.verify_template = FileHelper.readFromFile(SettingsReader.relocateFile(verify_filename)); + this.verify_template = settings.readInternalResourceAsString(verify_filename); + } + + // signature template is needed !!! + if (this.verify_template == null) { + throw new ConnectorException(ErrorCode.SETTING_NOT_FOUND, "Can not read the verify template"); + } + + /* signature verification is not supported by mocca + this.verify_url = getConnectorValueFromProfile(settings, profile, VERIFY_URL_KEY); + */ + + this.cert_alg_ecdsa = settings.getValueFromKey(ECDSA_CERT_ALG_KEY); + + this.cert_alg_rsa = settings.getValueFromKey(RSA_CERT_ALG_KEY); + + } + + /** + * Returns the profile name. + * @return The profile name. + */ + public String getProfile() { + return this.profile; + } + + /** + * Returns the LocRef content. + * + * @return Returns the LocRef content. + */ + public String getLocRefContent() { + return this.loc_ref_content; + } + + /** + * Returns the sign keybox identifier. + * + * @return Returns the sign keybox identifier. + */ + public String getSignKeyboxIdentifier() { + return this.sign_keybox_identifier; + } + + /** + * Returns the sign request template. + * + * @return Returns the sign request template. + */ + public String getSignRequestTemplate() { + return this.sign_request_template; + } + + /** + * Returns the sign URL. + * + * @return Returns the sign URL. + */ + public String getSignURL() { + return this.sign_url; + } + + /** + * Returns the verify request template. + * + * @return Returns the verify request template. + */ + /* signature verification is not supported by mocca + public String getVerifyRequestTemplate() { + return this.verify_request_template; + } + */ + + /** + * Returns the verify template. + * + * @return Returns the verify template. + */ + public String getVerifyTemplate() { + return this.verify_template; + } + + /** + * Returns the verify URL. + * + * @return Returns the verify URL. + */ + /* signature verification is not supported by mocca + public String getVerifyURL() { + return this.verify_url; + } + */ + + /** + * Returns the ecdsa cert alg property. + * + * @return Returns the ecdsa cert alg property. + */ + public String getCertAlgEcdsa() { + return this.cert_alg_ecdsa; + } + + /** + * Returns the rsa cert alg property. + * + * @return Returns the rsa cert alg property. + */ + public String getCertAlgRsa() { + return this.cert_alg_rsa; + } + + /** + * Reads the configuration entry given by the key, first from the given + * profile, if not found from the defaults. + * + * @param settings + * The settings. + * @param profile + * The profile. + * @param key + * The configuration key. + * @return Returns the configuration entry. + */ + public static String getConnectorValueFromProfile(SettingsReader settings, String profile, String key) { + String value = settings.getValueFromKey("sig_obj." + profile + "." + key); //$NON-NLS-2$ + if (value == null) { + value = settings.getValueFromKey(key); + } + return value; + } + } + + /** + * Parses the common part for all id attributes from a given signature parameter string. + * @param sigIdString The given signature parameter string. + * @return The common part of all id attributes. + */ + protected String parseSigId(String sigIdString) { + String[] parts = sigIdString.split("@"); + String result = null; + if (parts != null && parts.length > 1) { + result = parts[1].trim(); + } + return result; + } + + public XMLDsigData reconstructXMLDsig(SignatureData data, SignSignatureObject so) + throws ConnectorException { + String xmldsig = prepareXMLContent(data, so); + return new XMLDsigData(xmldsig, true); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/MOCCAHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/MOCCAHelper.java new file mode 100644 index 0000000..6b90fa1 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors/mocca/MOCCAHelper.java @@ -0,0 +1,223 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.connectors.mocca; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmMapper; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteObject; +import at.gv.egiz.pdfas.algorithmSuite.AlgorithmSuiteUtil; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.MOASoapWithAttachmentConnector.Environment; +import at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; + +/** + * Provides useful methods for the usage of the open source cce mocca. + * + * @author tknall + */ +public final class MOCCAHelper { + + /** + * Prevents this plain util class from being instantiated. + */ + private MOCCAHelper() { + } + + /** + * The logging implementation. + */ + private final static Log log = LogFactory.getLog(MOCCAHelper.class); + + /** + * This method parses the signature creation response of the signature + * device mocca. + * + * @param xmlResponse The response string. + * @return Returns the parsed signature object holding the data. + * @see SignatureObject + * @see CodingHelper + * @see X509Cert + */ + public final static SignSignatureObject parseCreateXMLResponse(String xmlResponse, IdFormatter id_formatter, ConnectorEnvironment environment) throws ConnectorException { + + if (log.isDebugEnabled()) { + log.debug("xmlResponse = " + xmlResponse); + } + + Pattern iss_nam_p_s = Pattern.compile("<[\\w]*:?X509IssuerName[^>]*>"); + Pattern iss_nam_p_e = Pattern.compile(""); + Pattern sig_tim_p_s = Pattern.compile("<[\\w]*:?SigningTime>"); + Pattern sig_tim_p_e = Pattern.compile(""); + Pattern ser_num_p_s = Pattern.compile("<[\\w]*:?X509SerialNumber[^>]*>"); + Pattern ser_num_p_e = Pattern.compile(""); + Pattern sig_cer_p_s = Pattern.compile("<[\\w]*:?X509Certificate>"); + Pattern sig_cer_p_e = Pattern.compile(""); + + Matcher iss_nam_m_s = iss_nam_p_s.matcher(xmlResponse); + Matcher iss_nam_m_e = iss_nam_p_e.matcher(xmlResponse); + Matcher sig_tim_m_s = sig_tim_p_s.matcher(xmlResponse); + Matcher sig_tim_m_e = sig_tim_p_e.matcher(xmlResponse); + Matcher ser_num_m_s = ser_num_p_s.matcher(xmlResponse); + Matcher ser_num_m_e = ser_num_p_e.matcher(xmlResponse); + Matcher sig_cer_m_s = sig_cer_p_s.matcher(xmlResponse); + Matcher sig_cer_m_e = sig_cer_p_e.matcher(xmlResponse); + + // SignatureValue + String sig_val = null; + Pattern signatureValuePattern = Pattern.compile("<(\\w+:)?SignatureValue( Id=\"[\\w-]+\")?>\\s*(.*)\\s*", Pattern.DOTALL); + Matcher signatureValueMatcher = signatureValuePattern.matcher(xmlResponse); + if (signatureValueMatcher.find()) { + sig_val = signatureValueMatcher.group(3); + if (sig_val != null) { + sig_val = sig_val.replaceAll("\\s", ""); + } + } + log.debug("sig_val = " + sig_val); + + // X509IssuerName + String iss_nam = null; + if (iss_nam_m_s.find() && iss_nam_m_e.find()) { + iss_nam = xmlResponse.substring(iss_nam_m_s.end(), iss_nam_m_e.start()); + } + log.debug("iss_nam = " + iss_nam); + + // X509SerialNumber + String ser_num = null; + if (ser_num_m_s.find() && ser_num_m_e.find()) { + ser_num = BKUHelper.removeAllWhitespace(xmlResponse.substring(ser_num_m_s.end(), ser_num_m_e.start())); + } + log.debug("ser_num = " + ser_num); + + // SigningTime + String sig_tim = null; + if (sig_tim_m_s.find() && sig_tim_m_e.find()) { + sig_tim = xmlResponse.substring(sig_tim_m_s.end(), sig_tim_m_e.start()); + } + log.debug("sig_tim = " + sig_tim); + + // X509Certificate + X509Certificate cert = null; + if (sig_cer_m_s.find() && sig_cer_m_e.find()) { + String sig_cer = BKUHelper.removeAllWhitespace(xmlResponse.substring(sig_cer_m_s.end(), sig_cer_m_e.start())); + + try { + byte[] der = CodingHelper.decodeBase64(sig_cer); + ByteArrayInputStream bais = new ByteArrayInputStream(der); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + cert = (X509Certificate) cf.generateCertificate(bais); + bais.close(); + } catch (UnsupportedEncodingException e) { + throw new ConnectorException(300, e); + } catch (CertificateException e) { + throw new ConnectorException(300, e); + } catch (IOException e) { + throw new ConnectorException(300, e); + } + } + log.debug("X509Certificate = " + cert); + + if (log.isDebugEnabled()) { + + String cert_iss = cert.getIssuerDN().getName(); + log.debug("certificate's issuer = " + cert_iss); + log.debug("response's issuer = " + iss_nam); + log.debug("issuer matches = " + cert_iss.equals(iss_nam)); + log.debug("ser number matches = " + cert.getSerialNumber().toString().equals(ser_num)); + } + + SignSignatureObject so = new SignSignatureObject(); + + // extract Signature Id's + String[] ids = extractIds(xmlResponse); + // dferbas + String algs = AlgorithmSuiteUtil.extractAlgorithmSuiteString(xmlResponse); + + AlgorithmSuiteObject suite = new AlgorithmSuiteObject(algs, false); + so.sigAlgorithm = AlgorithmMapper.getUri(suite.getSignatureMethod()); + + String defaultCertAlg = environment.getDefaultAlgForCert(cert); + + if (AlgorithmSuiteUtil.isDefaultCertAlg(algs, defaultCertAlg)) { + // do not embed default alg + algs = null; + } + + String final_ids = id_formatter.formatIds(ids, algs); + + + so.date = sig_tim; + so.issuer = iss_nam; + so.signatureValue = sig_val; + so.x509Certificate = cert; + + so.id = final_ids; + + return so; + } + + /** + * Extraction of the id attributes from the xml response. + * + * @param xmlResponse The xml response. + * @return The parsed id attributes. + */ + public final static String[] extractIds(String xmlResponse) { + return new String[] { extractId(xmlResponse) }; + } + + /** + * There is only one special common part of all id attributes of this + * connector that has to be stored. This method returns that single part. + * + * @param xmlResponse The xml response. + * @return The parsed common part of all id attributes. + */ + private final static String extractId(String xmlResponse) { + final Pattern ID_PATTERN = Pattern.compile("Id\\s*=\\s*\"\\s*Signature-([\\p{XDigit}]+)-\\d+\\s*\""); + Matcher matcher = ID_PATTERN.matcher(xmlResponse); + if (matcher.find() && matcher.groupCount() > 0) { + return matcher.group(1); + } + return null; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedIdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedIdFormatter.java new file mode 100644 index 0000000..359e49b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedIdFormatter.java @@ -0,0 +1,101 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.sigid; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * @author wprinz + * + */ +public class DetachedIdFormatter implements IdFormatter +{ + /** + * The SIG_ID prefix. + * Default value: etsi-bka-1.0 + */ + public static String SIG_ID_PREFIX = "etsi-bka-1.0"; //$NON-NLS-1$ + + /** + * Key value in property file + */ + public static final String SIG_ID_PROPERTY_KEY = "default.bku.algorithm.id"; + + /** + * The log. + */ + private static Log log = LogFactory.getLog(DetachedIdFormatter.class); + + /** + * @see at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter#formatIds(java.lang.String[]) + */ + public String formatIds(String[] ids, String algorithmParams) + { + // read id from property file and use it + try { + SIG_ID_PREFIX = SettingsReader.getInstance().getValueFromKey(SIG_ID_PROPERTY_KEY); + } catch (SettingsException e) { + log.error(e.getMessage(), e); + } + + // ids algorithm: + String join = ""; //$NON-NLS-1$ + String base = null; + for (int arr_idx = 0; arr_idx < ids.length; arr_idx++) + { + String id = ids[arr_idx]; + if (log.isDebugEnabled()) + { + log.debug("Set BKU id:" + id); //$NON-NLS-1$ + } + int id_idx = id.lastIndexOf("-"); //$NON-NLS-1$ + if (arr_idx == 0) + { + base = id.substring(0, id_idx); + } + String cur_id = id.substring(id_idx + 1); + if (cur_id.equalsIgnoreCase("")) //$NON-NLS-1$ + { + cur_id = "0"; //$NON-NLS-1$ + } + + join += "-" + cur_id; //$NON-NLS-1$ + } + String idstr = base + "@" + join.substring(1); //$NON-NLS-1$ + + // dferbas + StringBuffer final_ids = new StringBuffer(SIG_ID_PREFIX); + //String final_ids = SIG_ID_PREFIX + "@" + idstr; + if (algorithmParams != null && algorithmParams.length() > 0) { + final_ids.append(":").append(algorithmParams); + } + final_ids.append("@").append(idstr); + return final_ids.toString(); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedLocRefMOAIdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedLocRefMOAIdFormatter.java new file mode 100644 index 0000000..a83540b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedLocRefMOAIdFormatter.java @@ -0,0 +1,80 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.sigid; + +import org.apache.commons.lang.BooleanUtils; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * @author wprinz + * + */ +public class DetachedLocRefMOAIdFormatter implements IdFormatter +{ + /** + * The SIG_ID prefix. + * Default value: etsi-bka-moa-1.0 + */ + public static String SIG_ID_PREFIX = "etsi-bka-moa-1.0"; //$NON-NLS-1$ + + private static final Logger logger_ = ConfigLogger.getLogger(DetachedLocRefMOAIdFormatter.class); + + /** + * Key value in property file + */ + public static final String SIG_ID_PROPERTY_KEY = "default.moa.algorithm.id"; + + /** + * @see at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter#formatIds(java.lang.String[]) + */ + public String formatIds(String[] ids, String algorithmParams) + { + // read id from property file and use it + + try + { + // dferbas +// if (!BooleanUtils.toBoolean(SettingsReader.getInstance().getValueFromKey("moa.id.field.visible"))) { +// return null; +// } + + + SIG_ID_PREFIX = SettingsReader.getInstance().getValueFromKey(SIG_ID_PROPERTY_KEY); + } catch (SettingsException e) + { + logger_.error(e.getMessage(), e); + } + + // dferbas + if (algorithmParams != null && algorithmParams.length() > 0) { + return SIG_ID_PREFIX + ":" + algorithmParams; + } else { + return SIG_ID_PREFIX; + } + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedMOCIdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedMOCIdFormatter.java new file mode 100644 index 0000000..1ba7916 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/DetachedMOCIdFormatter.java @@ -0,0 +1,78 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.sigid; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * @author tknall + * + */ +public class DetachedMOCIdFormatter implements IdFormatter { + + /** + * Key value in property file + */ + private static final String SIG_ID_PROPERTY_KEY = "default.moc.algorithm.id"; + + /** + * The log. + */ + private static Log log = LogFactory.getLog(DetachedIdFormatter.class); + + private String algorithmId; + + public DetachedMOCIdFormatter(String algorithmId) { + this.algorithmId = algorithmId; + } + + /** + * @see at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter#formatIds(java.lang.String[]) + */ + public String formatIds(String[] ids, String algorithmParams) { + // read id from property file and use it + String prefix = null; + try { + prefix = SettingsReader.getInstance().getValueFromKey(SIG_ID_PROPERTY_KEY); + } catch (SettingsException e) { + log.error(e.getMessage(), e); + } + prefix = StringUtils.defaultIfEmpty(this.algorithmId, prefix); + + // dferbas + StringBuffer formattedIds = new StringBuffer(prefix); + if (algorithmParams != null && algorithmParams.length() > 0) { + formattedIds.append(":").append(algorithmParams); + } + formattedIds.append("@").append(ids[0]); + return formattedIds.toString(); + + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/HotfixIdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/HotfixIdFormatter.java new file mode 100644 index 0000000..ea6637a --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/HotfixIdFormatter.java @@ -0,0 +1,74 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.sigid; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @author wprinz + * + */ +public class HotfixIdFormatter implements IdFormatter +{ + /** + * The SIG_ID prefix. + */ + public static final String SIG_ID_PREFIX = "etsi-bka-1.0"; //$NON-NLS-1$ + + /** + * The log. + */ + private static Log log = LogFactory.getLog(HotfixIdFormatter.class); + + /** + * @see at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter#formatIds(java.lang.String[]) + */ + public String formatIds(String[] ids, String algorithmParams) + { + // ids algorithm: + String join = ""; //$NON-NLS-1$ + String base = null; + for (int arr_idx = 0; arr_idx < ids.length; arr_idx++) + { + String id = ids[arr_idx]; + if (log.isDebugEnabled()) + { + log.debug("Set BKU id:" + id); //$NON-NLS-1$ + } + int id_idx = id.lastIndexOf("-"); //$NON-NLS-1$ + if (arr_idx == 0) + { + base = id.substring(0, id_idx); + } + String cur_id = id.substring(id_idx + 1); + join += "-" + cur_id; //$NON-NLS-1$ + } + + String idstr = base + "@" + join.substring(1); //$NON-NLS-1$ + String final_ids = SIG_ID_PREFIX + "@" + idstr; + + return final_ids; + } +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/IdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/IdFormatter.java new file mode 100644 index 0000000..9747055 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/IdFormatter.java @@ -0,0 +1,34 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.sigid; + +/** + * @author wprinz + * + */ +public interface IdFormatter +{ + public String formatIds (String [] ids, String algorithmParams); + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/OldMOAIdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/OldMOAIdFormatter.java new file mode 100644 index 0000000..ff0c9f3 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/OldMOAIdFormatter.java @@ -0,0 +1,42 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.sigid; + +/** + * @author wprinz + * + */ +public class OldMOAIdFormatter implements IdFormatter +{ + + /** + * @see at.knowcenter.wag.egov.egiz.sig.sigid.IdFormatter#formatIds(java.lang.String[]) + */ + public String formatIds(String[] ids, String algorithmParams) + { + return null;//"etsi-bka-moa-1.0"; + } + +} + diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/SimpleIdFormatter.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/SimpleIdFormatter.java new file mode 100644 index 0000000..8e79dc4 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigid/SimpleIdFormatter.java @@ -0,0 +1,48 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.sigid; + +/** + * {@link IdFormatter} implementation that uses specified algorithmid but not additional parameters.
+ * usage A-Trust bku + * @author dferbas + * + */ +public class SimpleIdFormatter implements IdFormatter { + private String algorithmId; + + public SimpleIdFormatter(String algorithmId) { + this.algorithmId = algorithmId; + } + + public String formatIds(String[] ids, String algorithmParams) { + // dferbas + if (algorithmParams != null && algorithmParams.length() > 0) { + return this.algorithmId + ":" + algorithmParams; + } else { + return this.algorithmId; + } + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java new file mode 100644 index 0000000..094880d --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/sigkz/SigKZIDHelper.java @@ -0,0 +1,262 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.sigkz; + +import java.util.Iterator; +import java.util.Vector; +import java.util.regex.Pattern; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.framework.SignatorFactory; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedLocRefMOAIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.sigid.HotfixIdFormatter; + +/** + * @author wprinz + * + */ +public final class SigKZIDHelper +{ + + /** + * The Logger. + */ + protected static Log logger = LogFactory.getLog(SigKZIDHelper.class); + + public static boolean isTextual(PdfASID sig_kz) + { + if (sig_kz == null) + { + // Old signature -> must be textual. + + return true; + } + + // new signauture -> sig_kz decides + return sig_kz.getType().equals(SignatorFactory.TYPE_TEXTUAL); + } + + public static boolean isBinary(PdfASID sig_kz) + { + return ! isTextual(sig_kz); + } + + + public static boolean isMOASigned(PdfASID sig_kz, String sig_id) + { + if (sig_kz == null || sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) + { + // old signature - if sig_id is null this means MOA + + return sig_id == null; + } + + if(sig_id == null) + return true; + + // new signature - sig_id decides + String [] ids = sig_id.split("@"); + // dferbas + String prefix = (ids[0].split(":"))[0]; + + + if (prefix.equals(DetachedLocRefMOAIdFormatter.SIG_ID_PREFIX)) + { + return true; + } + return false; + } + + public static boolean isMOASigned(SignSignatureObject so) + { + String sig_kz = so.kz; + String sig_id = so.id; + PdfASID kz = null; + if (sig_kz != null) + { + try + { + kz = new PdfASID(sig_kz); + } + catch (InvalidIDException e) + { + logger.error(e.getMessage(), e); + } + } + + return isMOASigned(kz, sig_id); + } + + /** + * @author tknall + */ + public static boolean isMOCCASigned(SignSignatureObject so) { + String sig_id = so.id; + if (StringUtils.isEmpty(sig_id)) { + return false; + } + String[] ids = sig_id.split("@"); + if (ArrayUtils.isEmpty(ids)) { + return false; + } + String algorithmId = parseAlgorithmId(sig_id); + if (algorithmId == null) { + return false; + } else { + return algorithmId.startsWith("etsi-moc-1.0") || algorithmId.startsWith("etsi-moc-1.1"); + } + } + + /** + * @author tknall + */ + public static String parseAlgorithmId(String algorithmParameter) { + if (StringUtils.isEmpty(algorithmParameter)) { + return null; + } + // dferbas + String[] ids = algorithmParameter.split("@")[0].split(":"); + if (ArrayUtils.isEmpty(ids)) { + return null; + } + return ids[0]; + } + + public static boolean isOldBKU(PdfASID sig_kz, String sig_id) throws ConnectorException + { + if (sig_kz == null) + { + return true; + } + + if (sig_kz.getVersion().equals(SignatorFactory.VERSION_1_0_0)) + { + if (sig_id == null) + { + throw new ConnectorException(310, "The SIG_ID is null - so this isn't a BKU at all."); + } + + String[] sig_id_parts = sig_id.split("@"); + if (sig_id_parts.length == 2) + { + return true; + } + // dferbas + if (sig_id_parts[0].startsWith(HotfixIdFormatter.SIG_ID_PREFIX)) + { + + return false; + } + + throw new ConnectorException(310, "The SIG_KZ version is 1.0.0, but SIG_ID is neither MOA nor Old base64 nor Hotfix base64 ???'"); + } + + return false; + } + + public static boolean isOldBKU(SignSignatureObject so) throws ConnectorException + { + String sig_kz = so.kz; + String sig_id = so.id; + PdfASID kz = null; + if (sig_kz != null) + { + try + { + kz = new PdfASID(sig_kz); + } + catch (InvalidIDException e) + { + logger.error(e.getMessage(), e); + } + } + + return isOldBKU(kz, sig_id); + } + + public static String getAlgorithmId(String bkuIdentifier) throws SettingsException, SettingNotFoundException, ConnectorException { + SettingsReader sr = SettingsReader.getInstance(); + + String base = "signaturelayout.pattern"; + Vector v = sr.getSettingKeys(base); + + Iterator it = v.iterator(); + while (it.hasNext()) { + String subKey = (String) it.next(); + String key = base + "." + subKey; + String value = sr.getSetting(key); + Pattern p = Pattern.compile(value); + if (p.matcher(bkuIdentifier).matches()) { + String algKey = "signaturelayout.algorithm.id." + subKey; + String algValue = sr.getSetting(algKey); + return algValue; + } + } + + if ("true".equalsIgnoreCase(sr.getSetting("signaturelayout.strict", "false"))) { + logger.debug("Enforcing bku support check."); + throw new ConnectorException(ErrorCode.BKU_NOT_SUPPORTED, "Unsupported BKU: " + bkuIdentifier); + } else { + logger.debug("bku support check disabled."); + return null; + } + + } + + public static boolean isATrustSigned(SignSignatureObject so) { + String sig_id = so.id; + if (sig_id == null && StringUtils.isEmpty(sig_id)) { + return false; + } + return sig_id.startsWith("etsi-bka-atrust-1.0"); + } + + /** + * Checks if signed with a known BKU method/param + * @param so + * @return + */ + public static boolean isBKUSigned(SignSignatureObject so) throws ConnectorException { + if (isOldBKU(so)) return true; + + if (so.id.startsWith("etsi-bka-1.0")) { + return true; + } + + return false; + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandler.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandler.java new file mode 100644 index 0000000..b58b2e4 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandler.java @@ -0,0 +1,45 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.signaturelayout; + +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; + +/** + * Considers different signature layout characteristics among different versions of citizen card + * environments. + * @author tknall + */ +public interface SignatureLayoutHandler { + + /** + * This method parses the CreateXMLSignatureResponse given from a certain signature device. + * + * @param xmlResponse The response string. + * @return Returns the parsed signature object. + */ + public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse, ConnectorEnvironment env) throws ConnectorException; + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandlerFactory.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandlerFactory.java new file mode 100644 index 0000000..07a7792 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/SignatureLayoutHandlerFactory.java @@ -0,0 +1,147 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.signaturelayout; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; +import java.util.regex.Pattern; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingNotFoundException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; + +/** + * Returns instances of signature layout handlers based on given bku + * identifiers. + * + * @author tknall + */ +public class SignatureLayoutHandlerFactory { + + /** + * Prefix of configuration keys defining bku identifiers for a signature layout. + */ + private final static String SIGNATURE_LAYOUT_CONFIG_KEY_PATTERN = "signaturelayout.pattern"; + + /** + * Prefix of configuration keys defining implementations of signature layout handlers. + * @see SignatureLayoutHandler + */ + private final static String SIGNATURE_LAYOUT_CONFIG_KEY_IMPL = "signaturelayout.implementation"; + + /** + * A map holding instantiated signature layout implementations (for performance reasons). + */ + private final static Map instances = Collections.synchronizedMap(new HashMap()); + + /** + * The log. + */ + private static Log log = LogFactory.getLog(SignatureLayoutHandlerFactory.class); + + /** + * Returns an instance of a signature layout handler based on the given bku identifier. + * @param bkuIdentifier The bku identifier (e.g. citizen-card-environment/1.2 MOCCA/1.1.1). + * @return An implementation of a signature layout handler. + * @throws ConnectorException Thrown in case of an error finding a match within the configuration with the given bku identifier. + * @throws SettingsException Thrown in case of an error within the configuration. + */ + public static SignatureLayoutHandler getSignatureLayoutHandlerInstance(String bkuIdentifier) throws ConnectorException, SettingsException { + if (bkuIdentifier == null) { + throw new SettingsException(ErrorCode.MISSING_HEADER_SERVER_USER_AGENT, "Unable to determine type of citizen card environment. Response header \"Server\" resp. \"user-agent\" is missing. Refer to security layer specification 1.2.2, section 3.3.2."); + } + SignatureLayoutHandler signatureLayoutHandler = (SignatureLayoutHandler) instances.get(bkuIdentifier); + + if (signatureLayoutHandler == null) { + SettingsReader sr = SettingsReader.getInstance(); + + Vector v = sr.getSettingKeys(SIGNATURE_LAYOUT_CONFIG_KEY_PATTERN); + String implValue = null; + + Iterator it = v.iterator(); + try { + while (it.hasNext()) { + String subKey = (String) it.next(); + String key = SIGNATURE_LAYOUT_CONFIG_KEY_PATTERN + "." + subKey; + String value = sr.getSetting(key); + Pattern p = Pattern.compile(value); + if (p.matcher(bkuIdentifier).matches()) { + String implKey = SIGNATURE_LAYOUT_CONFIG_KEY_IMPL + "." + subKey; + implValue = sr.getSetting(implKey); + } + } + } catch (SettingNotFoundException e) { + throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, e.getMessage()); + } + + if (implValue == null) { + throw new ConnectorException(ErrorCode.BKU_NOT_SUPPORTED, "Unsupported BKU: " + bkuIdentifier); + } + + log.debug("Trying to instantiate SignatureLayoutHandler \"" + implValue + "\"."); + + try { + Class clazz = Class.forName(implValue); + Object obj = clazz.newInstance(); + if (!(obj instanceof SignatureLayoutHandler)) { + throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, "Invalid signature layout implementation (\"" + implValue + "\") configured for bku identifier \"" + bkuIdentifier + "\"."); + } + signatureLayoutHandler = (SignatureLayoutHandler) obj; + } catch (InstantiationException e) { + throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, "Error instantiating signature layout implementation (\"" + implValue + "\") configured for bku identifier \"" + bkuIdentifier + "\"."); + } catch (IllegalAccessException e) { + throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, "Illegal access instantiating signature layout implementation (\"" + implValue + "\") configured for bku identifier \"" + bkuIdentifier + "\"."); + } catch (ClassNotFoundException e) { + throw new SettingsException(ErrorCode.INVALID_SIGNATURE_LAYOUT_IMPL_CONFIGURED, "Unable to find signature layout implementation (\"" + implValue + "\") configured for bku identifier \"" + bkuIdentifier + "\"."); + } + + log.debug("SignatureLayoutHandler successfully instantiated."); + instances.put(bkuIdentifier, signatureLayoutHandler); + } else { + log.trace("SignatureLayoutHandler has already been instantiated. Returning old instance."); + } + + return signatureLayoutHandler; + + } + + /** + * Verifies that the bku is supported trying to match the given bku identifier. + * @param bkuIdentifier The bku identifier (e.g. citizen-card-environment/1.2 MOCCA/1.1.1). + * @throws ConnectorException Thrown in case of an error (e.g. bku not supported). + * @throws SettingsException Thrown in case of an error within the configuration. + */ + public static void verifyBKUSupport(String bkuIdentifier) throws ConnectorException, SettingsException { + getSignatureLayoutHandlerInstance(bkuIdentifier); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/atrust/ATrustSignatureLayoutHandler.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/atrust/ATrustSignatureLayoutHandler.java new file mode 100644 index 0000000..b7cf72b --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/atrust/ATrustSignatureLayoutHandler.java @@ -0,0 +1,47 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.signaturelayout.atrust; + +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.connectors.moa.MOAHelper; +import at.knowcenter.wag.egov.egiz.sig.sigid.SimpleIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler; + +/** + * Layout handler for atrust bku + * + * @author dferbas + */ +public class ATrustSignatureLayoutHandler implements SignatureLayoutHandler { + + public static final String ETSI_BKA_ATRUST_1_0 = "etsi-bka-atrust-1.0"; + + public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse, + ConnectorEnvironment env) throws ConnectorException { + return MOAHelper.parseCreateXMLResponse(xmlResponse, new SimpleIdFormatter(ETSI_BKA_ATRUST_1_0), env); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MOCCASignatureLayout10Handler.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MOCCASignatureLayout10Handler.java new file mode 100644 index 0000000..600b503 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/MOCCASignatureLayout10Handler.java @@ -0,0 +1,48 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.signaturelayout.mocca; + +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.MOCCAHelper; +import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedMOCIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler; + +/** + * Implementation of a signature layout handler for the first release of mocca. + * @author tknall + */ +public class MOCCASignatureLayout10Handler implements SignatureLayoutHandler { + + private final static String ALGORITHM_ID = "etsi-moc-1.1"; + + /** + * Parses the given xmlResponse with respect to the specific signature layout of mocca. + */ + public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse, ConnectorEnvironment env) throws ConnectorException { + return MOCCAHelper.parseCreateXMLResponse(xmlResponse, new DetachedMOCIdFormatter(ALGORITHM_ID), env); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/OldMOCCASignatureLayoutHandler.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/OldMOCCASignatureLayoutHandler.java new file mode 100644 index 0000000..988a930 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/mocca/OldMOCCASignatureLayoutHandler.java @@ -0,0 +1,48 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.signaturelayout.mocca; + +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.connectors.mocca.MOCCAHelper; +import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedMOCIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler; + +/** + * Implementation of a signature layout handler for the beta version of mocca. + * @author tknall + */ +public class OldMOCCASignatureLayoutHandler implements SignatureLayoutHandler { + + private final static String ALGORITHM_ID = "etsi-moc-1.0"; + + /** + * Parses the given xmlResponse with respect to the specific signature layout of mocca. + */ + public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse, ConnectorEnvironment env) throws ConnectorException { + return MOCCAHelper.parseCreateXMLResponse(xmlResponse, new DetachedMOCIdFormatter(ALGORITHM_ID), env); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/td/TrustDeskSignatureLayoutHandler.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/td/TrustDeskSignatureLayoutHandler.java new file mode 100644 index 0000000..a13ce52 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signaturelayout/td/TrustDeskSignatureLayoutHandler.java @@ -0,0 +1,46 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.signaturelayout.td; + +import at.knowcenter.wag.egov.egiz.exceptions.ConnectorException; +import at.knowcenter.wag.egov.egiz.sig.connectors.ConnectorEnvironment; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.BKUHelper; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; +import at.knowcenter.wag.egov.egiz.sig.sigid.DetachedIdFormatter; +import at.knowcenter.wag.egov.egiz.sig.signaturelayout.SignatureLayoutHandler; + +/** + * Implementation of a signature layout handler for trustDesk basic. + * @author tknall + */ +public class TrustDeskSignatureLayoutHandler implements SignatureLayoutHandler { + + /** + * Parses the given xmlResponse with respect to the specific signature layout of trustDesk basic. + */ + public SignSignatureObject parseCreateXMLSignatureResponse(String xmlResponse, ConnectorEnvironment env) throws ConnectorException { + return BKUHelper.parseCreateXMLResponse(xmlResponse, new DetachedIdFormatter(), env); + } + +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AdditionalSignatureInformation.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AdditionalSignatureInformation.java new file mode 100644 index 0000000..7c86e62 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AdditionalSignatureInformation.java @@ -0,0 +1,41 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.signatureobject; + +import java.security.cert.X509Certificate; + +/** + * @author wprinz + * + */ +public interface AdditionalSignatureInformation +{ + + public String getName(); + + public X509Certificate getX509Certificate(); + + // dferbas: baik + public String getSigAlgorithm(); +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AlgorithmSignatureInformation.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AlgorithmSignatureInformation.java new file mode 100644 index 0000000..7d81758 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/AlgorithmSignatureInformation.java @@ -0,0 +1,33 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.signatureobject; + +/** + * @author wprinz + * + */ +public interface AlgorithmSignatureInformation +{ +public String getSigKZ(); +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/ConnectorSignatureInformation.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/ConnectorSignatureInformation.java new file mode 100644 index 0000000..6b5ef18 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/ConnectorSignatureInformation.java @@ -0,0 +1,34 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.signatureobject; + +/** + * + * @author wprinz + * + */ +public interface ConnectorSignatureInformation +{ + public String getSigID(); +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/MandatorySignatureInformation.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/MandatorySignatureInformation.java new file mode 100644 index 0000000..2da1b02 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/MandatorySignatureInformation.java @@ -0,0 +1,40 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.signatureobject; + +/** + * Encapsulates all information required to define a signature. + * + * @author wprinz + */ +public interface MandatorySignatureInformation +{ + public String getDate(); + + public String getSignatureValue(); + + public String getIssuer(); + + public String getSerialNumber(); +} diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/SignatureObjectHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/SignatureObjectHelper.java new file mode 100644 index 0000000..6a8afc0 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/signatureobject/SignatureObjectHelper.java @@ -0,0 +1,81 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted 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.knowcenter.wag.egov.egiz.sig.signatureobject; + +import at.gv.egiz.pdfas.exceptions.ErrorCode; +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.sig.SignatureObject; +import at.knowcenter.wag.egov.egiz.sig.X509Cert; +import at.knowcenter.wag.egov.egiz.sig.connectors.bku.SignSignatureObject; + +/** + * Contains helper methods for dealing with signature objects. + * + * @author wprinz + * + */ +public final class SignatureObjectHelper +{ + + public static SignatureObject convertSignSignatureObjectToSignatureObject (SignSignatureObject sso, String signature_type) throws SignatureTypesException, SignatureException + { + SignatureObject so = new SignatureObject(); + so.setSigType(signature_type); + so.initByType(); + so.setSignationDate(sso.getDate()); + so.setSignationIssuer(sso.getIssuer()); + so.setSignationSerialNumber(sso.getSerialNumber()); + so.setSignationValue(sso.getSignatureValue()); + so.setSignationIDs(sso.getSigID()); + so.setKZ(new PdfASID(sso.getSigKZ())); + so.setSignationName(sso.getName()); + + so.setSigAlg(sso.getSigAlgorithm()); + + so.setX509Certificate(sso.getX509Certificate()); + + return so; + } + + public static SignSignatureObject convertSignatureObjectToSignSignatureObject (SignatureObject so) throws SignatureException + { + SignSignatureObject sso = new SignSignatureObject(); + sso.date = so.getSignationDate(); + sso.signatureValue = so.getSignationValue(); + sso.issuer = so.getSignationIssuer(); + X509Cert cert = so.getX509Cert(); + if (cert == null) + { + throw new SignatureException(ErrorCode.CERTIFICATE_NOT_FOUND, "so.getX509Cert returned null. No cert found."); + } + sso.x509Certificate = cert.getX509Certificate(); + sso.id = so.getSignationIds(); + sso.kz = so.getKZ() == null ? null : so.getKZ().toString(); + sso.sigAlgorithm = so.getSigAlg(); + + return sso; + } +} -- cgit v1.2.3