From b5b09ae47752e2ea376c6dd0d0836ebd497523ab Mon Sep 17 00:00:00 2001 From: Andreas Fitzek Date: Thu, 27 Feb 2014 16:57:31 +0100 Subject: preperations for 3.5.1, plus old uncommited changes from 3.4 --- pdf-as-cli/pom.xml | 2 +- pdf-as-lib/pom.xml | 2 +- .../java/at/knowcenter/wag/egov/egiz/PdfAS.java | 2 +- .../wag/egov/egiz/sig/SignatureObject.java | 3901 ++++++++++---------- .../at/knowcenter/wag/egov/egiz/sig/X509Cert.java | 899 +++-- .../knowcenter/wag/egov/egiz/tools/FileHelper.java | 17 +- pdf-as-release/pom.xml | 2 +- pdf-as-web/pom.xml | 3 +- pom.xml | 6 +- 9 files changed, 2401 insertions(+), 2433 deletions(-) diff --git a/pdf-as-cli/pom.xml b/pdf-as-cli/pom.xml index 2c5777d..82a08e4 100644 --- a/pdf-as-cli/pom.xml +++ b/pdf-as-cli/pom.xml @@ -6,7 +6,7 @@ eu.europa.ec.joinup.egovlabs.pdf-as pdf-as - 3.4 + 3.5.1 pom diff --git a/pdf-as-lib/pom.xml b/pdf-as-lib/pom.xml index 786e0c2..406ad7e 100644 --- a/pdf-as-lib/pom.xml +++ b/pdf-as-lib/pom.xml @@ -8,7 +8,7 @@ eu.europa.ec.joinup.egovlabs.pdf-as pdf-as - 3.4 + 3.5.1 jar diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java index a09a238..e501641 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/PdfAS.java @@ -115,7 +115,7 @@ public abstract class PdfAS * The current version of the pdf-as library. This version string is logged on every invocation * of the api or the web application. */ - public static final String PDFAS_VERSION = "3.3"; + public static final String PDFAS_VERSION = "3.5.1"; /** * The key of the strict mode setting. 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 index b5a05ed..04e9036 100644 --- 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 @@ -77,139 +77,147 @@ import at.knowcenter.wag.egov.egiz.tools.Normalizer; * 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 + * @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 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(); + + public static Object adding_mutex = new Object(); + + /** + * 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())); + RFC2253NameParser parser = new RFC2253NameParser( + normalizeIssuer(name.getName())); try { name = parser.parse(); } catch (RFC2253NameParserException e) { @@ -219,591 +227,588 @@ public class SignatureObject implements Serializable } }; - /** - * 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("#")) { + /** + * 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(); + } - // take rdn from textual representation - result.append(rdnVP.getRdn()).append("="); - // BER encoding -> take value from text representation - result.append(rdnVP.getValue()); + /** + * 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 { - // 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); + 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 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") - * + 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 + * The String obtained from the certificate * @param value - * The RDN's 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 + * 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) { + private static String resolveRDN(String certString, String value, + String extractedRDN) { if (!certString.contains(value)) { @@ -813,7 +818,8 @@ public class SignatureObject implements Serializable if (certString.indexOf(value) != certString.lastIndexOf(value)) { - // given value is ambiguous - cannot resolve RDN from certificate string + // given value is ambiguous - cannot resolve RDN from certificate + // string return extractedRDN; } @@ -840,1268 +846,1223 @@ public class SignatureObject implements Serializable return extractedRDN; } - /** - * @return Returns the SignationIssuer. - */ - public String getSignationIssuer() - { - String issuer = getSigValue(SignatureTypes.SIG_ISSUER); - X509Cert cert = loadCertificate(getSigValue(SignatureTypes.SIG_NUMBER), issuer); - 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; - } - 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) - { - // 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) - { - 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_.debug("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; - } + /** + * @return Returns the SignationIssuer. + */ + public String getSignationIssuer() { + String issuer = getSigValue(SignatureTypes.SIG_ISSUER); + X509Cert cert = loadCertificate(getSigValue(SignatureTypes.SIG_NUMBER), + issuer); + 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; + } + issuer = getSigValue(SignatureTypes.SIG_ISSUER); + return issuer; + } -/** - * 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_; - } + /** + * @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) { + // 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) { + 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() { + synchronized (adding_mutex) { + 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; + File cert_file_name_file = new File( + cert_file_name); + + 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) { + synchronized (adding_mutex) { + 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) { + synchronized (adding_mutex) { + 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) { + synchronized (adding_mutex) { + // 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_.debug("store certificate:" + cert_file_name); + } + boolean store_cert_file = FileHelper.writeToFile( + cert_file_name, x509Certificate); + store_complete = store_cert_file;// && store_cert_meta; + } else { + logger_.warn("Certstore dir \"" + cert_store_dir + + "\" is not a directory. Skipping storage."); + } + } + return store_complete; + } + + /** + * @return Returns the AbstractTable. + * @see at.knowcenter.wag.egov.egiz.table.Table + */ + public Table getAbstractTable() { + if (sigTable_ == null) { + sigTable_ = createSigTable(SignatureTypes.MAIN_TABLE); + } + return sigTable_; + } + + /** + * This method read the style definitions from the settings file. + * + * @param styleKey + * the key to read the style definitions + * @return the defined style informations + * @see at.knowcenter.wag.egov.egiz.table.Style + */ + private Style readStyle(String styleKey) { + ArrayList styles = settings_.getKeys(styleKey); + Style style = new Style(); + for (int style_idx = 0; style_idx < styles.size(); style_idx++) { + String style_id = (String) styles.get(style_idx); + String style_val = settings_.getSetting(styleKey + "." + style_id, + null); + style.setStyle(style_id, style_val); + } + return style; + } + + /** + * This method creates an abstract signature table object. It takes all keys + * and values set by the signature object to create the corresponding + * abstract table object. The table definition is read from the settings + * file. + * + * @param tableKey + * is the name of the table definition in the settings file + * @return a new abstract signature table + * @see at.knowcenter.wag.egov.egiz.table.Style + * @see at.knowcenter.wag.egov.egiz.table.Table + * @see at.knowcenter.wag.egov.egiz.table.Entry + */ + private Table createSigTable(String tableKey) { + String table_key_prefix = SignatureTypes.SIG_OBJ + getSignationType() + + "." + SignatureTypes.TABLE; + String table_key = table_key_prefix + tableKey; + // String caption_prefix = SignatureTypes.SIG_OBJ + getSignationType() + + // ".key."; + // String value_prefix = SignatureTypes.SIG_OBJ + getSignationType() + + // ".value."; + // ArrayList table_def_keys = settings_.getKeys(table_key); + Vector table_def_keys = settings_.getSettingKeys(table_key); + if (table_def_keys == null) { + return null; + } + Table sig_table = new Table(tableKey); + boolean found_style = false; + for (int table_key_idx = table_def_keys.size() - 1; table_key_idx >= 0; table_key_idx--) { + String table_def = (String) table_def_keys.get(table_key_idx); + int dot_idx = (table_def.indexOf(".") > 0 ? table_def.indexOf(".") + : table_def.length()); + table_def = table_def.substring(0, dot_idx); + String table_def_keys_prefix = table_key + "." + table_def; + String table_def_string = settings_.getSetting( + table_def_keys_prefix, null); + if (table_def.matches("\\D*")) { + // if the table key is not a number (row number index) + if (SignatureTypes.COLS_WITH.equals(table_def)) { + String[] cols_s = table_def_string.split(" "); + float[] cols_f = new float[cols_s.length]; + for (int i = 0; i < cols_s.length; i++) { + cols_f[i] = Float.parseFloat(cols_s[i]); + } + sig_table.setColsRelativeWith(cols_f); + } + if (SignatureTypes.STYLE.equals(table_def) && !found_style) { + Style style = readStyle(table_def_keys_prefix); + sig_table.setStyle(style); + found_style = true; + } + continue; + } + if (table_def_string != null) { + // analyse the row definition + String[] elems = table_def_string.split("\\|"); + ArrayList row = new ArrayList(); + for (int elem_idx = 0; elem_idx < elems.length; elem_idx++) { + String elem = elems[elem_idx]; + String[] key_type = elem.split("-"); + if (key_type.length < 2) { + return null; + } + String key = key_type[0]; + String type = key_type[1]; + if (SignatureTypes.TYPE_TABLE.equals(key)) { + // add a table entry + Table table = createSigTable(type); + if (table != null) { + Entry entry = new Entry(Entry.TYPE_TABLE, table, + key); + row.add(entry); + } + } + if (SignatureTypes.TYPE_IMAGE.equals(type)) { + // add an image entry + String value = getSigValue(key); + if (value != null) { + Entry entry = new Entry(Entry.TYPE_IMAGE, value, + key); + entry.setStyle(defaultImageStyle_); + row.add(entry); + } + } + if (SignatureTypes.TYPE_VALUE.equals(type)) { + // add a single value entry + String value = getSigValue(key); + Entry entry = new Entry(Entry.TYPE_VALUE, value, key); + if (entry != null) { + entry.setColSpan(2); + entry.setStyle(defaultValueStyle_); + row.add(entry); + } + } + if ((SignatureTypes.TYPE_VALUE + SignatureTypes.TYPE_CAPTION) + .equals(type) + || (SignatureTypes.TYPE_CAPTION + SignatureTypes.TYPE_VALUE) + .equals(type)) { + // add a caption value pair + String caption = getSigCaption(key); + String value = getSigValue(key); + if (value != null) { + Entry c_entry = new Entry(Entry.TYPE_CAPTION, + caption, key); + c_entry.setNoWrap(true); // dferbas fix bug #331 + c_entry.setStyle(defaultCaptionStyle_); + + Entry v_entry = new Entry(Entry.TYPE_VALUE, value, + key); + v_entry.setStyle(defaultValueStyle_); + if (c_entry != null && v_entry != null) { + row.add(c_entry); + row.add(v_entry); + } + } + } + } + sig_table.addRow(table_def, row); + } + } + + return sig_table; + } + + /** + * This method inits the signature object by the given type. It loads the + * configured values and captions from the config.properties file. + */ + public void initByType() throws SignatureTypesException { + if (sigType_ == null) { + sigType_ = getDefaultSigType(); + } + SignatureTypes sig_types = SignatureTypes.getInstance(); + signatureDefinition_ = sig_types.getSignatureTypeDefinition(sigType_); + if (signatureDefinition_ == null) { + final String msg = "The SignatureObject's sigType '" + + sigType_ + + "' wasn't found in the configuration file's specified signature profiles. This usually happens if the sig_obj.type.default object has been turned off or is misspelled."; + logger_.error(msg); + throw new SignatureTypesException(msg); + } + Map key_cap_map = signatureDefinition_.getKeyCaptionMap(); + if (key_cap_map != null) { + Iterator key_cap = key_cap_map.entrySet().iterator(); + while (key_cap.hasNext()) { + Map.Entry entry = (Map.Entry) key_cap.next(); + String key = (String) entry.getKey(); + String caption = (String) entry.getValue(); + SignatureEntry sig_entry = null; + if (sigEntries_.containsKey(key)) { + sig_entry = (SignatureEntry) sigEntries_.get(key); + } else { + sig_entry = new SignatureEntry(key); + sigEntries_.put(key, sig_entry); + } + sig_entry.setCaption(caption); + } + } + + Map key_val_map = signatureDefinition_.getKeyValueMap(); + if (key_val_map != null) { + Set key_val_set = key_val_map.entrySet(); + Iterator key_val = key_val_set.iterator(); + while (key_val.hasNext()) { + Map.Entry entry = (Map.Entry) key_val.next(); + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + if (SignatureTypes.SIG_NORM.equals(key)) { + try { + normalizer_.setVersion(value); + } catch (NormalizeException e) { + throw new SignatureTypesException(e); + } + } + // value = new String(CodingHelper.encodeUTF8(value)); + // if (logger_.isDebugEnabled()) + // { + // logger_.debug("key:" + key + " value:" + value); + // } + setSigValue(key, value); + } + } + } + + /** + * This method returns a signature entry object. + * + * @param key + * the corresponding key + * @return the signature entry object of the given key, null if the key does + * not exist + */ + public SignatureEntry getSigEntry(String key) { + return (SignatureEntry) sigEntries_.get(key); + } + + /** + * This method is a helper function to remove all white spaces from a text. + * + * @param text + * the white spaces should remove from + * @return a text without white spaces + */ + private static String removeAllWhiteSpaces(String text) { + return text.replaceAll("\\s", ""); + } + + public SignatureTypeDefinition getSignatureTypeDefinition() { + return this.signatureDefinition_; + } + + /** + * + * @param placeholder + * @return Returns the list of SignatureFieldDefinitions that's values in + * the SignatureObject have been filled out with placeholders. + */ + public List fillValues(final char placeholder, boolean has_SIG_ID, + boolean baikEnabled) { + List variable_fields = new ArrayList(); + + List field_definitions = this.signatureDefinition_ + .getFieldDefinitions(); + Iterator it = field_definitions.iterator(); + while (it.hasNext()) { + SignatureFieldDefinition sfd = (SignatureFieldDefinition) it.next(); + String value_string = null; + if (sfd.placeholder_length > 0) { + if (sfd.field_name.equals(SignatureTypes.SIG_ID) + && has_SIG_ID == false) { + setValueBruteForce(SignatureTypes.SIG_ID, null); + continue; + } + + if (sfd.field_name.equals(SignatureTypes.SIG_ALG) + && !baikEnabled) { + setValueBruteForce(SignatureTypes.SIG_ID, null); + continue; + } + + char[] placeholder_chars = new char[sfd.placeholder_length]; + for (int i = 0; i < placeholder_chars.length; i++) { + placeholder_chars[i] = placeholder; + } + value_string = new String(placeholder_chars); + + variable_fields.add(sfd); + + setSigValue(sfd.field_name, value_string, true); + } + } + + return variable_fields; + } + + /** + * Returns the raw signature response XML string as set by the signing + * Connector. + * + * @return Returns the XML response String. + */ + public String getRawSignatureResponse() { + return this.raw_signature_response; + } + + /** + * Sets the raw signature response XML string. + * + *

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

+ * + * @param raw_response_string + * The new raw signature response string. + */ + public void setRawSignatureResponse(String raw_response_string) { + this.raw_signature_response = raw_response_string; + } + + /** + * get timestamp if available + * + * @return + */ + public String getTimeStamp() { + return this.timeStamp; + } + + /** + * set timestamp + * + * @param timeStamp + */ + public void setTimeStamp(String timeStamp) { + this.timeStamp = timeStamp; + } + + /** + * The toString method, used for tests or debugging. + */ + public String toString() { + String strg = ""; + Iterator it = sigEntries_.values().iterator(); + while (it.hasNext()) { + SignatureEntry sig_entry = (SignatureEntry) it.next(); + String key = sig_entry.getKey(); + String caption = sig_entry.getCaption(); + String value = sig_entry.getValue(); + strg += key + "=" + caption + ":" + value + "\n"; + } + strg += "Signation Type:" + getSignationType() + "\n"; + return strg; + } + + public Map getSigEntries() { + return sigEntries_; + } } \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java index e11a38c..4e849b7 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/sig/X509Cert.java @@ -25,6 +25,7 @@ */ package at.knowcenter.wag.egov.egiz.sig; +import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; @@ -38,461 +39,455 @@ import java.security.cert.X509Certificate; import java.util.List; import org.apache.log4j.Logger; +import org.omg.CORBA.portable.ApplicationException; import at.knowcenter.wag.egov.egiz.cfg.ConfigLogger; import at.knowcenter.wag.egov.egiz.tools.CodingHelper; import at.knowcenter.wag.egov.egiz.tools.FileHelper; -public class X509Cert implements Serializable -{ - - /** - * SVUID. - */ - private static final long serialVersionUID = 6945327015386694557L; - - /** - * The x509 certificate binary string Base64 coded - */ - private String certString_ = null; - - /** - * The name value of the issuer - */ - private String issuerName_ = null; - - /** - * The serial number of the certificate - */ - private String serialNumber_ = null; - - /** - * The digest value of the certificate - */ - private String certDigest_ = null; - - /** - * The name value of the subject - */ - private String subjectName_ = null; - - /** - * The X509Certificate object - */ - private X509Certificate x509Cert_ = null; - - /** - * The logger definition. - */ - private static final Logger logger_ = ConfigLogger.getLogger(X509Cert.class); - - /** - * The empty constructor not acessible from outside --> use the static init - * methods instead - */ - private X509Cert() - { - } - - /** - * Normalize the base64 coded .cer or .der string. Remove the begin and end - * statement and remove all whitespaces in the string. The result string - * (base64) is used by reconstructing the certiface sign by the verification - * process. - * - * @param certString - * the string to normalize - * @return the normalized cert string - */ - private static String normalizeCertString(String certString) - { - certString = certString.replaceAll("-----BEGIN CERTIFICATE-----", ""); - certString = certString.replaceAll("-----END CERTIFICATE-----", ""); - certString = certString.replaceAll("\\s", ""); - return certString; - } - - /** - * This method initialzes a X509Certificate by a string value. It must be - * coded Base64 or as plain binary stream. - * - * @param certString - * the certificate string to analyse - * @return the X509Cert object - * @see CertificateFactory - * @see X509Certificate - */ - public static X509Cert initByString(String certString) - { - if (certString == null) - { - return null; - } - certString = normalizeCertString(certString); - X509Cert x509_cert = new X509Cert(); - x509_cert.setCertString(certString); - try - { - byte[] b64_dec = certString.getBytes("US-ASCII"); - if (CodingHelper.isB64(b64_dec)) - { - b64_dec = CodingHelper.decodeBase64(b64_dec); - } - else - { - b64_dec = CodingHelper.encodeBase64(b64_dec).getBytes("US-ASCII"); - } - ByteArrayInputStream bais = new ByteArrayInputStream(b64_dec); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); - bais.close(); - x509_cert.setX509Cert(cert); - - String serial_num = cert.getSerialNumber().toString(); - String issuer = cert.getIssuerDN().getName(); - // fixed by dti: commas within issuer rdns are escapted by "\,". These escapted commas must not be replaced. -// issuer = issuer.replaceAll(", ", ","); - issuer = issuer.replaceAll("[^\\\\], ", ","); - String subject_name = cert.getSubjectDN().toString(); - x509_cert.setSerialNumber(serial_num); - x509_cert.setIssuerName(issuer); - x509_cert.setSubjectName(subject_name); - if (logger_.isDebugEnabled()) - { - logger_.debug("Serial number from certificate:" + serial_num); - logger_.debug("Issuer name from certificate :" + issuer); - logger_.debug("Subject name from certificate :" + subject_name); - } - } - catch (java.security.cert.CertificateException ce) - { - // nothing to do, cause certString is not X509 conformc - logger_.error(ce.getMessage(), ce); - } - catch (IOException ioe) - { - // nothing to do, cause certString is not X509 conform - logger_.error(ioe.getMessage(), ioe); - } - return x509_cert; - } - - public static X509Cert initByX509Certificate(X509Certificate cert) throws CertificateEncodingException { - X509Cert x509_cert = new X509Cert(); - x509_cert.setX509Cert(cert); - x509_cert.setCertString(CodingHelper.encodeBase64(cert.getEncoded())); - - String serial_num = cert.getSerialNumber().toString(); - String issuer = cert.getIssuerDN().getName(); - // fixed by dti: commas within issuer rdns are escapted by "\,". These escapted commas must not be replaced. -// issuer = issuer.replaceAll(", ", ","); - issuer = issuer.replaceAll("[^\\\\], ", ","); - String subject_name = cert.getSubjectDN().toString(); - x509_cert.setSerialNumber(serial_num); - x509_cert.setIssuerName(issuer); - x509_cert.setSubjectName(subject_name); - if (logger_.isDebugEnabled()) - { - logger_.debug("Serial number from certificate:" + serial_num); - logger_.debug("Issuer name from certificate :" + issuer); - logger_.debug("Subject name from certificate :" + subject_name); - } - return x509_cert; - } - - public static X509Cert initByByteArray(byte[] data) - { - X509Cert x509_cert = new X509Cert(); - try - { - ByteArrayInputStream bais = new ByteArrayInputStream(data); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); - bais.close(); - - x509_cert.setX509Cert(cert); - - String serial_num = cert.getSerialNumber().toString(); - String issuer = cert.getIssuerDN().getName(); - // fixed by dti: commas within issuer rdns are escapted by "\,". These escapted commas must not be replaced. -// issuer = issuer.replaceAll(", ", ","); - issuer = issuer.replaceAll("[^\\\\], ", ","); - String subject_name = cert.getSubjectDN().toString(); - x509_cert.setSerialNumber(serial_num); - x509_cert.setIssuerName(issuer); - x509_cert.setSubjectName(subject_name); - if (logger_.isDebugEnabled()) - { - logger_.debug("Serial number from certificate:" + serial_num); - logger_.debug("Issuer name from certificate :" + issuer); - logger_.debug("Subject name from certificate :" + subject_name); - } - } - catch (java.security.cert.CertificateException ce) - { - // nothing to do, cause certString is not X509 conformc - logger_.error(ce.getMessage(), ce); - - } - catch (IOException ioe) - { - // nothing to do, cause certString is not X509 conform - logger_.error(ioe.getMessage(), ioe); - } - - return x509_cert; - } - - /** - * This method initialzes a X509Certificate by a file path value. The file - * must be a plain binary file like .cer format. - * - * @param filePath - * the certificate file to analyse - * @return the X509Cert object - * @see CertificateFactory - * @see X509Certificate - */ - public static X509Cert initByFilePath(String filePath) - { - if (filePath == null) - { - return null; - } - X509Cert x509_cert = new X509Cert(); - try - { - FileInputStream fis = new FileInputStream(filePath); - X509Certificate cert = null; - try - { - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - cert = (X509Certificate) cf.generateCertificate(fis); - } - catch (java.security.cert.CertificateException ce) - { - fis.close(); - String cert_string = FileHelper.readFromFile(filePath); - return initByString(cert_string); - } - fis.close(); - x509_cert.setX509Cert(cert); - String cert_string = FileHelper.readFromFile(filePath); - x509_cert.setCertString(normalizeCertString(cert_string)); - - String serial_num = cert.getSerialNumber().toString(); - String issuer = cert.getIssuerDN().getName(); - // fixed by dti: commas within issuer rdns are escapted by "\,". These escapted commas must not be replaced. -// issuer = issuer.replaceAll(", ", ","); - issuer = issuer.replaceAll("[^\\\\], ", ","); - String subject_name = cert.getSubjectDN().toString(); - x509_cert.setSerialNumber(serial_num); - x509_cert.setIssuerName(issuer); - x509_cert.setSubjectName(subject_name); - if (logger_.isDebugEnabled()) - { - logger_.debug("Serial number from certificate:" + serial_num); - logger_.debug("Issuer name from certificate :" + issuer); - logger_.debug("Subject name from certificate :" + subject_name); - } - } - catch (IOException ioe) - { - String cert_string = FileHelper.readFromFile(filePath); - return initByString(cert_string); - } - return x509_cert; - - } - - /** - * This method initialzes a X509Certificate by a file value. The file must be - * a plain binary file like .cer format. - * - * @param certFile - * the certificate file to analyse - * @return the X509Cert object - * @see CertificateFactory - * @see X509Certificate - */ - public static X509Cert initByFile(File certFile) - { - return initByFilePath(certFile.getAbsolutePath()); - } - - /** - * This method checks if a certificate file is X509 conform. - * - * @return true if a certificate file is X509 conform, false otherwise - */ - public boolean isX509Cert() - { - return x509Cert_ != null; - } - - /** - * @return Returns the certificate digest value. - * @deprecated Should not be used any more. - */ - public String getCertDigest() - { - if (certDigest_ == null) - { - if (certString_ != null) - { - byte[] cert_b64 = CodingHelper.decodeBase64(certString_); - String sigAlgName = this.x509Cert_.getSigAlgName(); - String digestAlg = sigAlgName.split("/")[0]; - if (sigAlgName.toLowerCase().indexOf("with") != -1 ) { - digestAlg = sigAlgName.substring(0,sigAlgName.toLowerCase().indexOf("with")); - } - byte[] cert_hash = CodingHelper.buildDigest(cert_b64, digestAlg); - certDigest_ = new String(CodingHelper.encodeBase64(cert_hash)); - } - } - return certDigest_; - } - - /** - * @return Returns the certificate Base64 binary string. - */ - public String getCertString() - { - return certString_; - } - - /** - * @return Returns the issuer string. - */ - public String getIssuerName() - { - return issuerName_; - } - - /** - * @return Returns the serial number. - */ - public String getSerialNumber() - { - return serialNumber_; - } - - /** - * @return Returns the real X509Certifcate object. - * @see X509Certificate - */ - public X509Certificate getX509Certificate() - { - return x509Cert_; - } - - /** - * @return Returns the subject name. - */ - public String getSubjectName() - { - return subjectName_; - } - - // /** - // * @param certDigest - // * The certDigest to set. - // */ - // private void setCertDigest(String certDigest) - // { - // certDigest_ = certDigest; - // } - - /** - * @param certString - * The certString to set. - */ - private void setCertString(String certString) - { - certString_ = certString; - } - - /** - * @param issuerString - * The issuerString to set. - */ - private void setIssuerName(String issuerString) - { - issuerName_ = issuerString; - } - - /** - * @param serialNumber - * The serialNumber to set. - */ - private void setSerialNumber(String serialNumber) - { - serialNumber_ = serialNumber; - } - - /** - * @param cert - * The x509Cert to set. - */ - private void setX509Cert(X509Certificate cert) - { - x509Cert_ = cert; - } - - /** - * @param subjectName - * The subjectName to set. - */ - private void setSubjectName(String subjectName) - { - subjectName_ = subjectName; - } - - public byte[] getTBSCertificate() throws CertificateEncodingException - { - return x509Cert_.getTBSCertificate(); - } - - public String getSigAlgName() - { - return x509Cert_.getSigAlgName(); - } - - public String getSigAlgOID() - { - return x509Cert_.getSigAlgOID(); - } - - public List getExtendedKeyUsage() - { - List list = null; - try - { - list = x509Cert_.getExtendedKeyUsage(); - } - catch (CertificateParsingException e) - { - logger_.error(e.getMessage(), e); - } - return null; - } - - /** - * @return the public key of the X509Certificate - */ - public PublicKey getPublicKey() - { - return x509Cert_.getPublicKey(); - } - - /** - * This method checks, if a X509Certificate has a public key with the rsa - * algorithm. - * - * @return true if the public key is produced with rsa, false otherwise - */ - public boolean isRSA() - { - return (x509Cert_.getPublicKey().getAlgorithm()).indexOf("RSA") >= 0; - } +public class X509Cert implements Serializable { + + /** + * SVUID. + */ + private static final long serialVersionUID = 6945327015386694557L; + + /** + * The x509 certificate binary string Base64 coded + */ + private String certString_ = null; + + /** + * The name value of the issuer + */ + private String issuerName_ = null; + + /** + * The serial number of the certificate + */ + private String serialNumber_ = null; + + /** + * The digest value of the certificate + */ + private String certDigest_ = null; + + /** + * The name value of the subject + */ + private String subjectName_ = null; + + /** + * The X509Certificate object + */ + private X509Certificate x509Cert_ = null; + + /** + * The logger definition. + */ + private static final Logger logger_ = ConfigLogger + .getLogger(X509Cert.class); + + /** + * The empty constructor not acessible from outside --> use the static init + * methods instead + */ + private X509Cert() { + } + + /** + * Normalize the base64 coded .cer or .der string. Remove the begin and end + * statement and remove all whitespaces in the string. The result string + * (base64) is used by reconstructing the certiface sign by the verification + * process. + * + * @param certString + * the string to normalize + * @return the normalized cert string + */ + private static String normalizeCertString(String certString) { + certString = certString.replaceAll("-----BEGIN CERTIFICATE-----", ""); + certString = certString.replaceAll("-----END CERTIFICATE-----", ""); + certString = certString.replaceAll("\\s", ""); + return certString; + } + + /** + * This method initialzes a X509Certificate by a string value. It must be + * coded Base64 or as plain binary stream. + * + * @param certString + * the certificate string to analyse + * @return the X509Cert object + * @see CertificateFactory + * @see X509Certificate + */ + public static X509Cert initByString(String certString) { + synchronized (SignatureObject.adding_mutex) { + + if (certString == null) { + return null; + } + certString = normalizeCertString(certString); + X509Cert x509_cert = new X509Cert(); + x509_cert.setCertString(certString); + try { + byte[] b64_dec = certString.getBytes("US-ASCII"); + if (CodingHelper.isB64(b64_dec)) { + b64_dec = CodingHelper.decodeBase64(b64_dec); + } else { + b64_dec = CodingHelper.encodeBase64(b64_dec).getBytes( + "US-ASCII"); + } + ByteArrayInputStream bais = new ByteArrayInputStream(b64_dec); + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf + .generateCertificate(bais); + bais.close(); + x509_cert.setX509Cert(cert); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + // fixed by dti: commas within issuer rdns are escapted by "\,". + // These escapted commas must not be replaced. + // issuer = issuer.replaceAll(", ", ","); + issuer = issuer.replaceAll("[^\\\\], ", ","); + String subject_name = cert.getSubjectDN().toString(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) { + logger_.debug("Serial number from certificate:" + + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + + subject_name); + } + } catch (java.security.cert.CertificateException ce) { + // nothing to do, cause certString is not X509 conformc + logger_.error(ce.getMessage(), ce); + } catch (IOException ioe) { + // nothing to do, cause certString is not X509 conform + logger_.error(ioe.getMessage(), ioe); + } + return x509_cert; + + } + } + + public static X509Cert initByX509Certificate(X509Certificate cert) + throws CertificateEncodingException { + synchronized (SignatureObject.adding_mutex) { + X509Cert x509_cert = new X509Cert(); + x509_cert.setX509Cert(cert); + x509_cert + .setCertString(CodingHelper.encodeBase64(cert.getEncoded())); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + // fixed by dti: commas within issuer rdns are escapted by "\,". + // These + // escapted commas must not be replaced. + // issuer = issuer.replaceAll(", ", ","); + issuer = issuer.replaceAll("[^\\\\], ", ","); + String subject_name = cert.getSubjectDN().toString(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) { + logger_.debug("Serial number from certificate:" + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + subject_name); + } + return x509_cert; + } + } + + public static X509Cert initByByteArray(byte[] data) { + synchronized (SignatureObject.adding_mutex) { + X509Cert x509_cert = new X509Cert(); + try { + ByteArrayInputStream bais = new ByteArrayInputStream(data); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) cf + .generateCertificate(bais); + bais.close(); + + x509_cert.setX509Cert(cert); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + // fixed by dti: commas within issuer rdns are escapted by "\,". + // These escapted commas must not be replaced. + // issuer = issuer.replaceAll(", ", ","); + issuer = issuer.replaceAll("[^\\\\], ", ","); + String subject_name = cert.getSubjectDN().toString(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) { + logger_.debug("Serial number from certificate:" + + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + + subject_name); + } + } catch (java.security.cert.CertificateException ce) { + // nothing to do, cause certString is not X509 conformc + logger_.error(ce.getMessage(), ce); + + } catch (IOException ioe) { + // nothing to do, cause certString is not X509 conform + logger_.error(ioe.getMessage(), ioe); + } + + return x509_cert; + } + } + + /** + * This method initialzes a X509Certificate by a file path value. The file + * must be a plain binary file like .cer format. + * + * @param filePath + * the certificate file to analyse + * @return the X509Cert object + * @see CertificateFactory + * @see X509Certificate + */ + public static X509Cert initByFilePath(String filePath) { + synchronized (SignatureObject.adding_mutex) { + if (filePath == null) { + return null; + } + X509Cert x509_cert = new X509Cert(); + try { + FileInputStream fis = new FileInputStream(filePath); + + X509Certificate cert = null; + try { + CertificateFactory cf = CertificateFactory + .getInstance("X.509"); + //logger_.error("Decoding Info reading : [ " + filePath + " ]"); + cert = (X509Certificate) cf.generateCertificate(fis); + } catch (java.security.cert.CertificateException ce) { + File f = new File(filePath); + //logger_.error("Decoding Error: [ " + filePath + " ] " + f.exists() + " ", ce); + fis.close(); + String cert_string = FileHelper.readFromFile(filePath); + //logger_.error(cert_string); + int max_count = 5; + int count = 0; + while(cert_string.equals("") && count < max_count) { + // Invalid File contents reread .... + cert_string = FileHelper.readFromFile(filePath); + count++; + Thread.yield(); + } + if(count == 5) { + logger_.error("Cannot read from file " + filePath); + } + return initByString(cert_string); + } + fis.close(); + x509_cert.setX509Cert(cert); + String cert_string = FileHelper.readFromFile(filePath); + x509_cert.setCertString(normalizeCertString(cert_string)); + + String serial_num = cert.getSerialNumber().toString(); + String issuer = cert.getIssuerDN().getName(); + // fixed by dti: commas within issuer rdns are escapted by "\,". + // These escapted commas must not be replaced. + // issuer = issuer.replaceAll(", ", ","); + issuer = issuer.replaceAll("[^\\\\], ", ","); + String subject_name = cert.getSubjectDN().toString(); + x509_cert.setSerialNumber(serial_num); + x509_cert.setIssuerName(issuer); + x509_cert.setSubjectName(subject_name); + if (logger_.isDebugEnabled()) { + logger_.debug("Serial number from certificate:" + + serial_num); + logger_.debug("Issuer name from certificate :" + issuer); + logger_.debug("Subject name from certificate :" + + subject_name); + } + } catch (IOException ioe) { + String cert_string = FileHelper.readFromFile(filePath); + return initByString(cert_string); + } + return x509_cert; + } + } + + /** + * This method initialzes a X509Certificate by a file value. The file must + * be a plain binary file like .cer format. + * + * @param certFile + * the certificate file to analyse + * @return the X509Cert object + * @see CertificateFactory + * @see X509Certificate + */ + public static X509Cert initByFile(File certFile) { + synchronized (SignatureObject.adding_mutex) { + return initByFilePath(certFile.getAbsolutePath()); + } + } + + /** + * This method checks if a certificate file is X509 conform. + * + * @return true if a certificate file is X509 conform, false otherwise + */ + public boolean isX509Cert() { + return x509Cert_ != null; + } + + /** + * @return Returns the certificate digest value. + * @deprecated Should not be used any more. + */ + public String getCertDigest() { + if (certDigest_ == null) { + if (certString_ != null) { + byte[] cert_b64 = CodingHelper.decodeBase64(certString_); + String sigAlgName = this.x509Cert_.getSigAlgName(); + String digestAlg = sigAlgName.split("/")[0]; + if (sigAlgName.toLowerCase().indexOf("with") != -1) { + digestAlg = sigAlgName.substring(0, sigAlgName + .toLowerCase().indexOf("with")); + } + byte[] cert_hash = CodingHelper + .buildDigest(cert_b64, digestAlg); + certDigest_ = new String(CodingHelper.encodeBase64(cert_hash)); + } + } + return certDigest_; + } + + /** + * @return Returns the certificate Base64 binary string. + */ + public String getCertString() { + return certString_; + } + + /** + * @return Returns the issuer string. + */ + public String getIssuerName() { + return issuerName_; + } + + /** + * @return Returns the serial number. + */ + public String getSerialNumber() { + return serialNumber_; + } + + /** + * @return Returns the real X509Certifcate object. + * @see X509Certificate + */ + public X509Certificate getX509Certificate() { + return x509Cert_; + } + + /** + * @return Returns the subject name. + */ + public String getSubjectName() { + return subjectName_; + } + + // /** + // * @param certDigest + // * The certDigest to set. + // */ + // private void setCertDigest(String certDigest) + // { + // certDigest_ = certDigest; + // } + + /** + * @param certString + * The certString to set. + */ + private void setCertString(String certString) { + certString_ = certString; + } + + /** + * @param issuerString + * The issuerString to set. + */ + private void setIssuerName(String issuerString) { + issuerName_ = issuerString; + } + + /** + * @param serialNumber + * The serialNumber to set. + */ + private void setSerialNumber(String serialNumber) { + serialNumber_ = serialNumber; + } + + /** + * @param cert + * The x509Cert to set. + */ + private void setX509Cert(X509Certificate cert) { + x509Cert_ = cert; + } + + /** + * @param subjectName + * The subjectName to set. + */ + private void setSubjectName(String subjectName) { + subjectName_ = subjectName; + } + + public byte[] getTBSCertificate() throws CertificateEncodingException { + return x509Cert_.getTBSCertificate(); + } + + public String getSigAlgName() { + return x509Cert_.getSigAlgName(); + } + + public String getSigAlgOID() { + return x509Cert_.getSigAlgOID(); + } + + public List getExtendedKeyUsage() { + List list = null; + try { + list = x509Cert_.getExtendedKeyUsage(); + } catch (CertificateParsingException e) { + logger_.error(e.getMessage(), e); + } + return null; + } + + /** + * @return the public key of the X509Certificate + */ + public PublicKey getPublicKey() { + return x509Cert_.getPublicKey(); + } + + /** + * This method checks, if a X509Certificate has a public key with the rsa + * algorithm. + * + * @return true if the public key is produced with rsa, false otherwise + */ + public boolean isRSA() { + return (x509Cert_.getPublicKey().getAlgorithm()).indexOf("RSA") >= 0; + } } \ No newline at end of file diff --git a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/FileHelper.java b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/FileHelper.java index 17b98d7..e7bef08 100644 --- a/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/FileHelper.java +++ b/pdf-as-lib/src/main/java/at/knowcenter/wag/egov/egiz/tools/FileHelper.java @@ -29,11 +29,13 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import org.apache.log4j.Logger; @@ -60,7 +62,10 @@ public class FileHelper { String file_string = null; logger_.trace("Looking for file: " + fileName); try { - BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(fileName), "UTF-8")); + FileInputStream fis = new FileInputStream(fileName); + fis.getFD().sync(); + BufferedReader reader = new BufferedReader(new InputStreamReader(fis, "UTF-8")); + //InputStreamReader reader = new InputStreamReader(new FileInputStream(fileName), "UTF-8"); logger_.trace("Reading file: " + fileName); String line = null; file_string = ""; @@ -112,10 +117,16 @@ public class FileHelper { public static boolean writeToFile(String fileName, String fileString) { BufferedWriter writer; try { - FileWriter fwriter = new FileWriter(fileName); - writer = new BufferedWriter(fwriter); + FileOutputStream out = new FileOutputStream(fileName); + OutputStreamWriter osw = new OutputStreamWriter(out); + writer = new BufferedWriter(osw); writer.write(fileString); + writer.flush(); writer.close(); + writer.flush(); + osw.flush(); + out.flush(); + out.getFD().sync(); } catch (IOException e) { logger_.info("File:" + fileName + " can not be written. Cause:" + e.getMessage()); return false; diff --git a/pdf-as-release/pom.xml b/pdf-as-release/pom.xml index 062adb5..64a8a82 100644 --- a/pdf-as-release/pom.xml +++ b/pdf-as-release/pom.xml @@ -7,7 +7,7 @@ eu.europa.ec.joinup.egovlabs.pdf-as pdf-as - 3.4-SNAPSHOT + 3.5.1 pom diff --git a/pdf-as-web/pom.xml b/pdf-as-web/pom.xml index 024c231..30dd2e7 100644 --- a/pdf-as-web/pom.xml +++ b/pdf-as-web/pom.xml @@ -7,7 +7,7 @@ eu.europa.ec.joinup.egovlabs.pdf-as pdf-as - 3.4 + 3.5.1 war @@ -122,6 +122,7 @@ commons-fileupload commons-fileupload + 1.3.1 diff --git a/pom.xml b/pom.xml index 966af8c..60d53d0 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ eu.europa.ec.joinup.egovlabs.pdf-as pdf-as - 3.4 + 3.5.1 pom @@ -50,7 +50,7 @@ - 7.0.37 + 7.0.52 @@ -327,7 +327,7 @@ commons-fileupload commons-fileupload - 1.1 + 1.3.1 -- cgit v1.2.3