/* * Copyright (c) 2006 by Know-Center, Graz, Austria * * This software is the confidential and proprietary information of Know-Center, * Graz, Austria. You shall not disclose such Confidential Information and shall * use it only in accordance with the terms of the license agreement you entered * into with Know-Center. * * KNOW-CENTER MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR * NON-INFRINGEMENT. KNOW-CENTER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. * * $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.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.Vector; 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 signaton value to the entry cache. If a key is not in * the cache a new signature entry is createad. Therefor 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) { 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); 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; if (sigEntries_.containsKey(key)) { value = ((SignatureEntry) sigEntries_.get(key)).getValue(); } if (value == null && SignatureTypes.SIG_NORM.equals(key)) { value = normalizer_.getVersion(); } String overrideVal = OverridePropertyHolder.getProperty(key); if (overrideVal != null) { 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); } /** * @return Returns the SignationIssuer. */ public String getSignationIssuer() { String issuer = getSigValue(SignatureTypes.SIG_ISSUER); X509Cert cert = loadCertificate(getSigValue(SignatureTypes.SIG_NUMBER), issuer); if (cert != null) { setSigValue(SignatureTypes.SIG_ISSUER, cert.getIssuerName()); setSigValue(SIG_CER, cert.getCertString()); // setSigValue(SIG_CER_DIG, cert.getCertDigest()); x509Cert_ = cert; } issuer = getSigValue(SignatureTypes.SIG_ISSUER); return issuer; } /** * @param sigIssuer * The SignationIssuer to set. */ public void setSignationIssuer(String sigIssuer) { setSigValue(SignatureTypes.SIG_ISSUER, sigIssuer); } /** * @return Returns the SignationValue. */ public String getSignationValue() { return getSigValue(SignatureTypes.SIG_VALUE); } /** * @param sigValue * The SignationValue to set. */ public void setSignationValue(String sigValue) { setSigValue(SignatureTypes.SIG_VALUE, sigValue); } /** * @return the reference to the signature label */ public String getOfficialSeal() { return getSigValue(SignatureTypes.SIG_LABEL); } /** * @param serialNumber * The serial number of the signature to set */ public void setSignationSerialNumber(String serialNumber) { setSigValue(SignatureTypes.SIG_NUMBER, serialNumber); } /** * @return sigNumber the serial number of the signature */ public String getSignationSerialNumber() { return getSigValue(SignatureTypes.SIG_NUMBER); } // dferbas baik /** * signature algorithm if embedded * @param sigAlg */ public void setSigAlg(String sigAlg) { setSigValue(SignatureTypes.SIG_ALG, sigAlg); } /** * signature algorithm if embedded * @return */ public String getSigAlg() { return getSigValue(SignatureTypes.SIG_ALG); } /** * @param certDigest * set the digest value for the X509Certificate */ public void setX509CertificateDigest(String certDigest) { setSigValue(SIG_CER_DIG, certDigest); } /** * This method load the current certificate getting the current SerialNumber * and the current SignationIssuer.
* It stores back the SignationIssuer, X509Certificate and * X509CertificateDigest */ private void loadCurrentCert() { X509Cert cert = loadCertificate(getSignationSerialNumber(), getSignationIssuer()); if (cert != null) { setSigValue(SignatureTypes.SIG_ISSUER, 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); } } 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; } }