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/SignatureObject.java | 2108 ++++++++++++++++++++ 1 file changed, 2108 insertions(+) create mode 100644 pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java (limited to 'pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java') diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java new file mode 100644 index 0000000..8855b86 --- /dev/null +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/SignatureObject.java @@ -0,0 +1,2108 @@ +/** + * Copyright 2006 by Know-Center, Graz, Austria + * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a + * joint initiative of the Federal Chancellery Austria and Graz University of + * Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + * + * $Id: SignatureObject.java,v 1.7 2006/10/31 08:18:56 wprinz Exp $ + */ +package at.knowcenter.wag.egov.egiz.sig; + +import iaik.asn1.structures.Name; +import iaik.asn1.structures.RDN; +import iaik.utils.RFC2253NameParser; +import iaik.utils.RFC2253NameParserException; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; + +import at.knowcenter.wag.egov.egiz.PdfASID; +import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; +import at.knowcenter.wag.egov.egiz.cfg.OverridePropertyHolder; +import at.knowcenter.wag.egov.egiz.cfg.SettingsReader; +import at.knowcenter.wag.egov.egiz.exceptions.InvalidIDException; +import at.knowcenter.wag.egov.egiz.exceptions.NormalizeException; +import at.knowcenter.wag.egov.egiz.exceptions.SettingsException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureException; +import at.knowcenter.wag.egov.egiz.exceptions.SignatureTypesException; +import at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIException; +import at.knowcenter.wag.egov.egiz.ldap.api.LDAPAPIFactory; +import at.knowcenter.wag.egov.egiz.ldap.client.LDAPIssuerNameFilter; +import at.knowcenter.wag.egov.egiz.sig.sigkz.SigKZIDHelper; +import at.knowcenter.wag.egov.egiz.table.Entry; +import at.knowcenter.wag.egov.egiz.table.Style; +import at.knowcenter.wag.egov.egiz.table.Table; +import at.knowcenter.wag.egov.egiz.tools.CodingHelper; +import at.knowcenter.wag.egov.egiz.tools.FileHelper; +import at.knowcenter.wag.egov.egiz.tools.Normalizer; + +/** + * This class represents the abstract signature object. It contains all methods + * reading the definitions from the settings file, analyse them and build the + * abstract signature table.
+ * All values that build or used by the signation creation process, call the + * external services, can read or set separately. All other values are defined + * in the settings file. + * + * @author wlackner + * @author modified by Thomas Knall + */ +public class SignatureObject implements Serializable +{ + +// 03.11.2010 changed by exthex - added default for defaultValueStyle_.hAlign since we had to remove the hardcoded default in Style +// 04.11.2010 changed by exthex - setSigValue no longer removes multiple newlines from value + + /** + * SVUID. + */ + private static final long serialVersionUID = -3535189232362254713L; + + /** + * The system file separator char + */ + private static final String FILE_SEP = System.getProperty("file.separator"); + + /** + * The certificate extension + */ + private static final String CERT_FILE_EXTENSION = ".der"; + + /** + * certificate import dir + */ + private static final String CERT_ADD_DIR = "tobeadded"; + + /** + * The default style definition for images. + */ + private Style defaultImageStyle_ = new Style(); + + /** + * The default style definition for captions. + */ + private Style defaultCaptionStyle_ = new Style(); + + /** + * The default style definition for values. + */ + private Style defaultValueStyle_ = new Style(); + + /** + * Standard key get/set the signature meta informations + */ + public static final String SIG_META = "SIG_META"; + + /** + * Standard key get/set the certification value + */ + public static final String SIG_CER = "SIG_CER"; + + /** + * Standard key get/set the certification digest value + */ + public static final String SIG_CER_DIG = "SIG_CER_DIG"; + + private X509Cert x509Cert_ = null; + + private String timeStamp = null; + + // public static final String SIG_RES = "SIG_RES"; + // dummy value for debugging only + private String sigResponse_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger.getLogger(SignatureObject.class); + + /** + * The normalizer reference + */ + private Normalizer normalizer_ = null; + + /** + * The settings reader reference + */ + private SettingsReader settings_ = null; + + // /** + // * The reference to the settings property tree + // */ + // private PropertyTree pTree_ = null; + /** + * The current signature type used reading and analysing the property tree + */ + private String sigType_ = null; + + /** + * Reference from signature key to there corresponding value + */ + private Hashtable sigEntries_ = new Hashtable(8); + + /** + * The abstract table representation + */ + private Table sigTable_ = null; + + // private HashMap sigIndexMap_ = new HashMap(); + + /** + * Path value storing and fetching the certificates + */ + private String certPath_ = null; + + /** + * the signature definition object + */ + private SignatureTypeDefinition signatureDefinition_ = null; + + /** + * The raw xml response from the connector that was used to set the values in + * this SignatureObject. + * + *

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

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

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

+ * + * @param raw_response_string + * The new raw signature response string. + */ + public void setRawSignatureResponse(String raw_response_string) + { + this.raw_signature_response = raw_response_string; + } + + + + /** + * get timestamp if available + * @return + */ + public String getTimeStamp() { + return this.timeStamp; + } + + /** + * set timestamp + * @param timeStamp + */ + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + +/** + * The toString method, used for tests or debugging. + */ + public String toString() + { + String strg = ""; + Iterator it = sigEntries_.values().iterator(); + while (it.hasNext()) + { + SignatureEntry sig_entry = (SignatureEntry) it.next(); + String key = sig_entry.getKey(); + String caption = sig_entry.getCaption(); + String value = sig_entry.getValue(); + strg += key + "=" + caption + ":" + value + "\n"; + } + strg += "Signation Type:" + getSignationType() + "\n"; + return strg; + } + + public Map getSigEntries() { + return sigEntries_; + } + +} \ No newline at end of file -- cgit v1.2.3