/**
*
* All values that build or used by the signation creation process, call the
* external services, can read or set separately. All other values are defined
* in the settings file.
*
* @author wlackner
* @author modified by Thomas
* Knall
*/
public class SignatureObject implements Serializable {
// 03.11.2010 changed by exthex - added default for
// defaultValueStyle_.hAlign since we had to remove the hardcoded default in
// Style
// 04.11.2010 changed by exthex - setSigValue no longer removes multiple
// newlines from value
/**
* SVUID.
*/
private static final long serialVersionUID = -3535189232362254713L;
/**
* The system file separator char
*/
private static final String FILE_SEP = System.getProperty("file.separator");
/**
* The certificate extension
*/
private static final String CERT_FILE_EXTENSION = ".der";
/**
* certificate import dir
*/
private static final String CERT_ADD_DIR = "tobeadded";
/**
* The default style definition for images.
*/
private Style defaultImageStyle_ = new Style();
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())); try { name = parser.parse(); } catch (RFC2253NameParserException e) { logger_.error(e.getMessage(), e); } return name; } }; /** * The empty constructor. It initilize the normlizer, load the settings and * set the default styles. * * @throws SignatureException * ErrorCode:101, 400 */ public SignatureObject() throws SignatureException { initNormalizer(); loadSettings(); setDefaultStyles(); } /** * This method initialize the normalizer * * @throws SignatureException * ErrorCode:400 */ private void initNormalizer() throws SignatureException { try { normalizer_ = new Normalizer(); } catch (NormalizeException e) { SignatureException se = new SignatureException(400, "Normalizer can not be initialized", e); throw se; } } /** * This method load the signature definitions * * @throws SignatureException * ErrorCode:101 */ private void loadSettings() throws SignatureException { if (settings_ == null) { try { settings_ = SettingsReader.getInstance(); } catch (SettingsException e) { String log_message = "Can not load pdf signature settings. Cause:\n" + e.getMessage(); logger_.error(log_message); throw new SignatureException(101, log_message, e); } } // pTree_ = settings_.getPTree(); certPath_ = SettingsReader.CERT_PATH; } /** * This method set the default styles for images, captions and values. */ private void setDefaultStyles() { defaultImageStyle_.setPadding(3); defaultImageStyle_.setHAlign(Style.CENTER); defaultImageStyle_.setVAlign(Style.MIDDLE); defaultCaptionStyle_.setHAlign(Style.CENTER); defaultCaptionStyle_.setVAlign(Style.MIDDLE); defaultValueStyle_.setHAlign(Style.LEFT); defaultValueStyle_.setVAlign(Style.MIDDLE); } /** * Dummy getter Method for debugging only * * @return response string */ public String getSigResponse() { return sigResponse_; } /** * Dummy setter Method for debugging only * * @param sigRespone * store the response string */ public void setSigResponse(String sigRespone) { sigResponse_ = sigRespone; } /** * This method set the signature type. * * @param sigType * the signature type to be set * @throws SignatureTypesException */ public void setSigType(String sigType) throws SignatureTypesException { SignatureTypes sig_types = SignatureTypes.getInstance(); signatureDefinition_ = sig_types.getSignatureTypeDefinition(sigType_); sigType_ = sigType; } /** * Returns the default signation type * * @return the key for the default signature definition, if the key is not * found it returns null */ private String getDefaultSigType() { return settings_.getSetting(SignatureTypes.DEFAULT_TYPE, null); } /** * This method checks if a given signature key is realy a defined signature * key. * * @param sigKey * the key to check * @return true if the key is correct, false if the given key is not defined */ public boolean isSigKey(String sigKey) { return signatureDefinition_.contains(sigKey); } /** * This method adds an sig value to the entry cache. If a key is not in the * cache a new signature entry is created. Therefore the method return true.SIG_VALUE
all whitespaces are
* removed! 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.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).2.5.4.5=#1306323030383034, CN=ForeignerCA,C=BE
2.5.4.5=#1306323030383034,CN=Foreigner CA,C=BE
2.5.4.5=#1306323030383034, CN=ForeignerCA,C=BE
serialNumber=863532247989,CN=Foreigner CA,C=BE
#1306323030383034
).
*
* @param nameFromText
* The extracted RFC2253 name from the text (e.g.
* 2.5.4.5=#1306323030383034, CN=ForeignerCA,C=BE
).
* @param nameFromCertificate
* The RFC2253 name from the certificate (e.g.
* serialNumber=863532247989,CN=Foreigner CA,C=BE
)
* @return The RFC2253 name that was used for signature (e.g.
* 2.5.4.5=#1306323030383034,CN=Foreigner CA,C=BE
).
*/
public static String prepareRFC2253Name(String nameFromText,
String nameFromCertificate) {
// do not invoke the workaround for performance reasons when both the
// extracted name and the
// name from certificate are equal
if (StringUtils.equals(nameFromText, nameFromCertificate)) {
return nameFromText;
}
logger_.debug("Checking RFC2253 name.");
// if we do not have a name from certificate just return the name from
// text
if (nameFromCertificate == null) {
logger_.debug("No certificate RFC2253 name provided. Applying less sophisticated workaround (does not cover all cases) without certificate usage.");
return prepareRFC2253Name(nameFromText);
}
// no name from text extraction available, just return name from
// certificate
if (nameFromText == null) {
logger_.debug("No extracted/reconstructed name available. Just returning the name from certificate: \""
+ nameFromCertificate + "\".");
return nameFromCertificate;
}
// helper class
final class RDNValuePair {
private String rdn;
private String value;
public RDNValuePair(String rdn, String value) {
this.rdn = rdn;
this.value = value;
}
public String getRdn() {
return this.rdn;
}
public String getValue() {
return this.value;
}
public String toString() {
return rdn + "=" + value;
}
}
// retrieve RDNs from text based name
List rdnList = new ArrayList();
StringTokenizer tokenizer = new StringTokenizer(nameFromText, ",",
false);
while (tokenizer.hasMoreTokens()) {
String rdnExpression = tokenizer.nextToken().trim();
try {
new RFC2253NameParser(rdnExpression).parse();
// token is RDN=value pair
// split RDN from value
String[] split = rdnExpression.split("=", 2);
rdnList.add(new RDNValuePair(split[0].trim(), split[1].trim()));
} catch (RFC2253NameParserException e) {
// no RDN in token
}
}
// get values from certificate name
Name nCert;
try {
nCert = new RFC2253NameParser(nameFromCertificate).parse();
} catch (RFC2253NameParserException e) {
// should never happen
logger_.warn("Unable to parse RFC2253 name \""
+ nameFromCertificate
+ "\". Applying less sophisticated workaround (does not cover all cases) without certificate usage.");
return prepareRFC2253Name(nameFromText);
}
RDN[] values = nCert.getRDNs();
// check if results are mergeable
if (values.length != rdnList.size()) {
// unable to merge names; returning nameFromCertificate (since this
// should be normal
// behavior)
logger_.warn("Number of parsed text based RDNs from \""
+ nameFromText
+ "\" does not fit the number of RDN values from certificate name \""
+ nameFromCertificate
+ "\". Returning name from certificate.");
return nameFromCertificate;
}
// merge textual based RDNs with values from certificate
StringBuffer result = new StringBuffer();
for (int i = 0; i < values.length; i++) {
if (i > 0) {
result.append(",");
}
// take rdn from textual representation
RDNValuePair rdnVP = (RDNValuePair) rdnList.get(i);
// Note: Do not take RDN from extraction but from certificate
// (Bug-Fix for EMAIL/EMAILADDRESS problem in ZID documents)
// take value from certificate but make sure that we do not have a
// BER encoding
if (rdnVP.getValue().startsWith("#")) {
// take rdn from textual representation
result.append(rdnVP.getRdn()).append("=");
// BER encoding -> take value from text representation
result.append(rdnVP.getValue());
} else {
// no BER encoding -> take value from certificate
// also take RDN from certificate if possible
String certValue = values[values.length - 1 - i].getAVA()
.getValueAsString();
String rdn = resolveRDN(nameFromCertificate, certValue,
rdnVP.getRdn());
result.append(rdn + "=").append(certValue);
}
}
String merged = result.toString();
if (logger_.isDebugEnabled()) {
if (merged.equals(nameFromText)) {
logger_.debug("Taking name from text: \"" + nameFromText + "\"");
} else if (merged.equals(nameFromCertificate)) {
logger_.debug("Taking name from certificate: \"" + nameFromText
+ "\"");
} else {
logger_.debug("Name has been fixed.");
logger_.debug("Name from text : \"" + nameFromText
+ "\"");
logger_.debug("Name from certificate : \""
+ nameFromCertificate + "\"");
logger_.debug("Fixed name : \"" + merged + "\"");
}
}
return merged;
}
/**
* This method tries to resolve the RDN corresponding to a given value from
* the certificate String. As values might occur multiple times for
* different RDNs, an unambiguous resolving cannot be assured. In case of
* ambiguity, the RDN extracted from text is returned by default.
*
* This method is a bug fix for a problem that caused the verification of
* ZID documents to fail as the RDN from the extracted text ("EMAILADDRESS")
* was different to the RDN in the certificate ("EMAIL")
*
* @param certString
* The String obtained from the certificate
* @param value
* The RDN's value
* @param extractedRDN
* The RDN extracted from the given text
* @return The resolved RDN from the certificate, or the RDN from text
* extraction
*/
private static String resolveRDN(String certString, String value,
String extractedRDN) {
if (!certString.contains(value)) {
// given value cannot be found in certificate string
return extractedRDN;
}
if (certString.indexOf(value) != certString.lastIndexOf(value)) {
// given value is ambiguous - cannot resolve RDN from certificate
// string
return extractedRDN;
}
String[] parts = certString.split(",|;");
String val = value.trim();
for (int i = 0; i < parts.length; i++) {
String part = parts[i].trim();
if (part.endsWith(val)) {
// found entry - extract RDN
String[] components = part.split("=");
if (components.length != 2) {
// unexpected format - return default
return extractedRDN;
}
String rdn = components[0].trim();
return rdn;
}
}
// default
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. .der
extension to get the certificate binary.txt
extension to get the meta information of
* the certificate@
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:
* .der
extension to get the certificate binary.txt
extension to get the meta information of
* the certificate@
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:
* .der
extension to get the certificate binary.txt
extension to get the meta information of
* the certificate@
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_; } }