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 --- .../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 +++++ 29 files changed, 9586 insertions(+) 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 (limited to 'pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/connectors') 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; + } + +} -- cgit v1.2.3