Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
ee.sk.digidoc.factory.SAXDigiDocFactory Maven / Gradle / Ivy
/*
* SAXDigiDocFactory.java
* PROJECT: JDigiDoc
* DESCRIPTION: Digi Doc functions for reading signed documents.
* AUTHOR: Veiko Sinivee, Sunset Software O������
*==================================================
* Copyright (C) AS Sertifitseerimiskeskus
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* GNU Lesser General Public Licence is available at
* http://www.gnu.org/copyleft/lesser.html
*==================================================
*/
package ee.sk.digidoc.factory;
import ee.sk.digidoc.*;
import ee.sk.utils.ConvertUtils;
import ee.sk.utils.ConfigManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Stack;
import java.util.List;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.TreeSet;
import org.apache.commons.compress.archivers.zip.*;
import org.xml.sax.SAXException;
import org.xml.sax.Attributes;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import java.security.cert.X509Certificate;
import org.apache.log4j.Logger;
/**
* SAX implementation of DigiDocFactory
* Provides methods for reading a DigiDoc file
* @author Veiko Sinivee
* @version 1.0
*/
public class SAXDigiDocFactory
extends DefaultHandler
implements DigiDocFactory
{
private Stack m_tags;
private SignedDoc m_doc;
private Signature m_sig;
private String m_strSigValTs, m_strSigAndRefsTs;
private StringBuffer m_sbCollectChars;
private StringBuffer m_sbCollectItem;
private StringBuffer m_sbCollectSignature;
private boolean m_bCollectDigest;
private String m_xmlnsAttr;
/** This mode means collect SAX events into xml data
* and is used to collect all , and
* content. Also servers as level of
* embedded DigiDoc files. Initially it should be 0. If
* we start collecting data then it's 1 and if we find
* another SignedDoc inside a DataFile then it will be incremented
* in order to know which is the correct tag to leave
* the collect mode
*/
private int m_nCollectMode;
private long nMaxBdocFilCached;
/** log4j logger */
private Logger m_logger = null;
/** calculation of digest */
private MessageDigest m_digest, m_altDigest;
/** temp output stream used to cache DataFile content */
private FileOutputStream m_dfCacheOutStream;
private String m_tempDir;
/** name of file being loaded */
private String m_fileName, m_sigComment;
private String m_nsDsPref, m_nsXadesPref, m_nsAsicPref;
private List m_errs;
private XmlElemInfo m_elemRoot, m_elemCurrent;
public static final String FILE_MIMETYPE = "mimetype";
public static final String FILE_MANIFEST = "META-INF/manifest.xml";
public static final String CONTENTS_MIMETYPE = "application/vnd.bdoc";
public static final String CONTENTS_MIMETYPE_1_0 = "application/vnd.bdoc-1.0";
public static final String MIME_SIGNATURE_BDOC = "signature/bdoc";
public static final String FILE_SIGNATURES = "META-INF/signature";
/**
* Creates new SAXDigiDocFactory
* and initializes the variables
*/
public SAXDigiDocFactory() {
m_tags = new Stack();
m_doc = null;
m_sig = null;
m_sbCollectSignature = null;
m_xmlnsAttr = null;
m_nsAsicPref = null;
m_sbCollectItem = null;
m_digest = null;
m_altDigest = null;
m_bCollectDigest = false;
m_dfCacheOutStream = null;
m_tempDir = null;
m_errs = null;
m_elemRoot = null;
m_elemCurrent = null;
m_logger = Logger.getLogger(SAXDigiDocFactory.class);
nMaxBdocFilCached = ConfigManager.instance().
getLongProperty("DIGIDOC_MAX_DATAFILE_CACHED", Long.MAX_VALUE);
}
/**
* Helper method to update sha1 digest with some data
* @param data
*/
private void updateDigest(byte[] data)
{
try {
// if not inited yet then initialize digest
if(m_digest == null)
m_digest = MessageDigest.getInstance("SHA-1");
m_digest.update(data);
} catch(Exception ex) {
m_logger.error("Error calculating digest: " + ex);
//ex.printStackTrace();
}
}
/**
* Helper method to update alternate sha1 digest with some data
* @param data
*/
private void updateAltDigest(byte[] data)
{
try {
// if not inited yet then initialize digest
if(m_altDigest == null)
m_altDigest = MessageDigest.getInstance("SHA-1");
m_altDigest.update(data);
} catch(Exception ex) {
m_logger.error("Error calculating digest: " + ex);
//ex.printStackTrace();
}
}
/**
* Set temp dir used to cache data files.
* @param s directory name
*/
public void setTempDir(String s) {
m_tempDir = s;
}
/**
* Helper method to calculate the digest result and
* reset digest
* @return sha-1 digest value
*/
private byte[] getDigest()
{
byte [] digest = null;
try {
// if not inited yet then initialize digest
digest = m_digest.digest();
m_digest = null; // reset for next calculation
} catch(Exception ex) {
m_logger.error("Error calculating digest: " + ex);
//ex.printStackTrace();
}
return digest;
}
/**
* Helper method to calculate the alternate digest result and
* reset digest
* @return sha-1 digest value
*/
private byte[] getAltDigest()
{
byte [] digest = null;
try {
// if not inited yet then initialize digest
digest = m_altDigest.digest();
m_altDigest = null; // reset for next calculation
} catch(Exception ex) {
m_logger.error("Error calculating digest: " + ex);
//ex.printStackTrace();
}
return digest;
}
/**
* initializes the implementation class
*/
public void init() throws DigiDocException {
}
/**
* Checks filename extension if this is bdoc / asic-e
* @param fname filename
* @return true if this is bdoc / asic-e
*/
public boolean isBdocExtension(String fname)
{
return fname.endsWith(".bdoc") ||
fname.endsWith(".asice") ||
fname.endsWith(".sce");
}
/**
* Checks if this stream could be a bdoc input stream
* @param is input stream, must support mark() and reset() operations!
* @return true if bdoc
*/
private boolean isBdocFile(InputStream is)
throws DigiDocException
{
try {
if(is.markSupported())
is.mark(10);
byte[] tdata = new byte[10];
int n = is.read(tdata);
if(is.markSupported())
is.reset();
if(n >= 2 && tdata[0] == (byte)'P' && tdata[1] == (byte)'K')
return true; // probably a zip file
if(n >= 5 && tdata[0] == (byte)'<' && tdata[1] == (byte)'?' &&
tdata[2] == (byte)'x' && tdata[3] == (byte)'m' &&
tdata[4] == (byte)'l')
return false; // an xml file - probably ddoc format?
} catch(Exception ex) {
m_logger.error("Error determining file type: " + ex);
}
return false;
}
/**
* Checks if this file contains the correct bdoc mimetype
* @param zis ZIP input stream
* @return true if correct bdoc
*/
private boolean checkBdocMimetype(InputStream zis)
throws DigiDocException
{
try {
byte[] data = new byte[100];
int nRead = zis.read(data);
if(nRead >= CONTENTS_MIMETYPE.length()) {
//skip leading whitespace & BOM marks
String s2 = new String(data, 0, nRead), s = null;
for(int i = 0; i < nRead; i++) {
if(s2.charAt(i) == 'a') { // search application/...
s = s2.substring(i);
break;
}
}
if(s == null)
s = new String(data);
if(m_logger.isDebugEnabled())
m_logger.debug("MimeType: \'" + s + "\'" + " len: " + s.length());
if(s.trim().equals(SignedDoc.MIMET_FILE_CONTENT_10)) {
m_doc.setVersion(SignedDoc.BDOC_VERSION_1_0);
m_doc.setFormat(SignedDoc.FORMAT_BDOC);
throw new DigiDocException(DigiDocException.ERR_DIGIDOC_FORMAT,
"Format BDOC supports only version 2.1", null);
} else if(s.trim().equals(SignedDoc.MIMET_FILE_CONTENT_11)) {
m_doc.setVersion(SignedDoc.BDOC_VERSION_1_1);
m_doc.setFormat(SignedDoc.FORMAT_BDOC);
throw new DigiDocException(DigiDocException.ERR_DIGIDOC_FORMAT,
"Format BDOC supports only version 2.1", null);
} else if(s.trim().equals(SignedDoc.MIMET_FILE_CONTENT_20)) {
m_doc.setVersion(SignedDoc.BDOC_VERSION_2_1);
m_doc.setFormat(SignedDoc.FORMAT_BDOC);
m_doc.setProfile(SignedDoc.BDOC_PROFILE_TM);
return true;
} else if(s.trim().startsWith(CONTENTS_MIMETYPE)) {
throw new DigiDocException(DigiDocException.ERR_DIGIDOC_FORMAT,
"Invalid BDOC version!", null);
} else { // no bdoc or wrong version
if(m_logger.isDebugEnabled())
m_logger.debug("Invalid MimeType: \'" + s + "\'" + " len: " + s.length() + " expecting: " + CONTENTS_MIMETYPE.length());
throw new DigiDocException(DigiDocException.ERR_DIGIDOC_BADXML,
"Not a BDOC format file!", null);
}
} else {
if(m_logger.isDebugEnabled())
m_logger.debug("Invalid empty MimeType");
throw new DigiDocException(DigiDocException.ERR_DIGIDOC_BADXML,
"Not a BDOC format file! MimeType file is empty!", null);
}
} catch(DigiDocException ex) {
m_logger.error("Mimetype err: " + ex);
//ex.printStackTrace();
throw ex;
} catch(Exception ex) {
m_logger.error("Error reading mimetype file: " + ex);
}
return false;
}
private void handleError(Exception err)
throws DigiDocException
{
if(m_logger.isDebugEnabled())
m_logger.debug("Handle err: " + err + " list: " + (m_errs != null));
err.printStackTrace();
DigiDocException err1 = null;
if(err instanceof SAXDigiDocException) {
err1 = ((SAXDigiDocException)err).getDigiDocException();
} else if(err instanceof DigiDocException) {
err1 = (DigiDocException)err;
err1.printStackTrace();
if(err1.getNestedException() != null)
err1.getNestedException().printStackTrace();
} else
err1 = new DigiDocException(DigiDocException.ERR_PARSE_XML, "Invalid xml file!", err);
if(m_errs != null)
m_errs.add(err1);
else
throw err1;
}
private void handleSAXError(Exception err)
throws SAXDigiDocException
{
if(m_logger.isDebugEnabled()) {
m_logger.debug("Handle sa err: " + err + " list: " + (m_errs != null));
m_logger.debug("Trace: " + ConvertUtils.getTrace(err));
}
DigiDocException err1 = null;
SAXDigiDocException err2 = null;
if(err instanceof SAXDigiDocException) {
err1 = ((SAXDigiDocException)err).getDigiDocException();
err2 = (SAXDigiDocException)err;
} else if(err instanceof DigiDocException) {
err1 = (DigiDocException)err;
err2 = new SAXDigiDocException(err.getMessage());
err2.setNestedException(err);
} else {
err1 = new DigiDocException(0, err.getMessage(), null);
err2 = new SAXDigiDocException(err.getMessage());
err2.setNestedException(err);
}
if(m_errs != null)
m_errs.add(err1);
else
throw err2;
}
/**
* Reads in a DigiDoc file. One of fname or isSdoc must be given.
* @param fname signed doc filename
* @param isSdoc opened stream with DigiDoc data
* The user must open and close it.
* @param errs list of errors to fill with parsing errors. If given
* then attempt is made to continue parsing on errors and return them in this list.
* If not given (null) then the first error found will be thrown.
* @return signed document object if successfully parsed
*/
private SignedDoc readSignedDocOfType(String fname, InputStream isSdoc, boolean isBdoc, List errs)
throws DigiDocException
{
// Use an instance of ourselves as the SAX event handler
SAXDigiDocFactory handler = this;
m_errs = errs;
DigiDocVerifyFactory.initProvider();
SAXParserFactory factory = SAXParserFactory.newInstance();
if(m_logger.isDebugEnabled())
m_logger.debug("Start reading ddoc/bdoc " + ((fname != null) ? "from file: " + fname : "from stream") + " bdoc: " + isBdoc);
if(fname == null && isSdoc == null) {
throw new DigiDocException(DigiDocException.ERR_READ_FILE, "No input file", null);
}
if(fname != null) {
File inFile = new File(fname);
if(!inFile.canRead() || inFile.length() == 0) {
throw new DigiDocException(DigiDocException.ERR_READ_FILE, "Empty or unreadable input file", null);
}
}
ZipFile zf = null;
ZipArchiveInputStream zis = null;
ZipArchiveEntry ze = null;
InputStream isEntry = null;
File fTmp = null;
try {
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
if(isBdoc) { // bdoc parsing
// must be a bdoc document ?
m_doc = new SignedDoc();
m_doc.setVersion(SignedDoc.BDOC_VERSION_1_0);
m_doc.setFormat(SignedDoc.FORMAT_BDOC);
Enumeration eFiles = null;
if(fname != null) {
zf = new ZipFile(fname, "UTF-8");
eFiles = zf.getEntries();
} else if(isSdoc != null) {
zis = new ZipArchiveInputStream(isSdoc, "UTF-8", true, true);
}
ArrayList lSigFnames = new ArrayList();
ArrayList lDataFnames = new ArrayList();
// read all entries
boolean bHasMimetype = false, bManifest1 = false;
int nFil = 0;
while((zf != null && eFiles.hasMoreElements()) ||
(zis != null && ((ze = zis.getNextZipEntry()) != null)) ) {
nFil++;
// read entry
if(zf != null) { // ZipFile
ze = (ZipArchiveEntry)eFiles.nextElement();
isEntry = zf.getInputStream(ze);
} else { // ZipArchiveInputStream
int n = 0, nTot = 0;
if((ze.getName().equals(FILE_MIMETYPE) ||
ze.getName().equals(FILE_MANIFEST) ||
(ze.getName().startsWith(FILE_SIGNATURES) &&
ze.getName().endsWith(".xml"))) ||
(nMaxBdocFilCached <= 0 || (ze.getSize() < nMaxBdocFilCached && ze.getSize() >= 0))) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] data = new byte[2048];
while((n = zis.read(data)) > 0) {
bos.write(data, 0, n);
nTot += n;
}
if(m_logger.isDebugEnabled())
m_logger.debug("Read: " + nTot + " bytes from zip");
data = bos.toByteArray();
bos = null;
isEntry = new ByteArrayInputStream(data);
} else {
File fCacheDir = new File(ConfigManager.instance().
getStringProperty("DIGIDOC_DF_CACHE_DIR", System.getProperty("java.io.tmpdir")));
fTmp = File.createTempFile("bdoc-data", ".tmp", fCacheDir);
FileOutputStream fos = new FileOutputStream(fTmp);
byte[] data = new byte[2048];
while((n = zis.read(data)) > 0) {
fos.write(data, 0, n);
nTot += n;
}
if(m_logger.isDebugEnabled())
m_logger.debug("Read: " + nTot + " bytes from zip to: " + fTmp.getAbsolutePath());
fos.close();
isEntry = new FileInputStream(fTmp);
}
}
if(m_logger.isDebugEnabled())
m_logger.debug("Entry: " + ze.getName() + " nlen: " + ze.getName().length() + " size: " + ze.getSize() + " dir: " + ze.isDirectory() + " comp-size: " + ze.getCompressedSize());
// mimetype file
if(ze.getName().equals(FILE_MIMETYPE)) {
if(m_logger.isDebugEnabled())
m_logger.debug("Check mimetype!");
checkBdocMimetype(isEntry);
bHasMimetype = true;
m_doc.setComment(ze.getComment());
if(nFil != 1) {
m_logger.error("mimetype file is " + nFil + " file but must be first");
handleError(new DigiDocException(DigiDocException.ERR_DIGIDOC_BADXML,
"mimetype file is not first zip entry", null));
}
} else if(ze.getName().equals(FILE_MANIFEST)) { // manifest.xml file
if(m_logger.isDebugEnabled())
m_logger.debug("Read manifest");
if(!bManifest1 && isEntry != null) {
bManifest1 = true;
BdocManifestParser mfparser = new BdocManifestParser(m_doc);
mfparser.readManifest(isEntry);
} else {
m_logger.error("Found multiple manifest.xml files!");
throw new DigiDocException(DigiDocException.ERR_MULTIPLE_MANIFEST_FILES,
"Found multiple manifest.xml files!", null);
}
} else if(ze.getName().startsWith(FILE_SIGNATURES) &&
ze.getName().endsWith(".xml")) { // some signature
m_fileName = ze.getName();
if(m_logger.isDebugEnabled())
m_logger.debug("Reading bdoc siganture: " + m_fileName);
boolean bExists = false;
for(int j = 0; j < lSigFnames.size(); j++) {
String s1 = (String)lSigFnames.get(j);
if(s1.equals(m_fileName))
bExists = true;
}
if(bExists) {
m_logger.error("Duplicate signature filename: " + m_fileName);
handleError(new DigiDocException(DigiDocException.ERR_DIGIDOC_BADXML,
"Duplicate signature filename: " + m_fileName, null));
} else
lSigFnames.add(m_fileName);
SAXParser saxParser = factory.newSAXParser();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int n = 0;
byte[] data = new byte[2048];
while((n = isEntry.read(data)) > 0)
bos.write(data, 0, n);
data = bos.toByteArray();
bos = null;
if(m_logger.isDebugEnabled())
m_logger.debug("Parsing bdoc: " + m_fileName + " size: " + ((data != null) ? data.length : 0));
saxParser.parse(new SignatureInputStream(new ByteArrayInputStream(data)), this);
if(m_logger.isDebugEnabled())
m_logger.debug("Parsed bdoc: " + m_fileName);
Signature sig1 = m_doc.getLastSignature();
m_sigComment = ze.getComment();
if(sig1 != null) {
sig1.setPath(m_fileName);
sig1.setComment(ze.getComment());
}
} else { // probably a data file
if(m_logger.isDebugEnabled())
m_logger.debug("Read data file: " + ze.getName());
if(!ze.isDirectory()) {
boolean bExists = false;
for(int j = 0; j < lDataFnames.size(); j++) {
String s1 = (String)lDataFnames.get(j);
if(s1.equals(ze.getName()))
bExists = true;
}
if(bExists) {
m_logger.error("Duplicate datafile filename: " + ze.getName());
handleError(new DigiDocException(DigiDocException.ERR_DIGIDOC_BADXML,
"Duplicate datafile filename: " + ze.getName(), null));
} else
lDataFnames.add(ze.getName());
DataFile df = m_doc.findDataFileById(ze.getName());
if(df != null) {
if(ze.getSize() > 0)
df.setSize(ze.getSize());
df.setContentType(DataFile.CONTENT_BINARY);
df.setFileName(ze.getName());
} else {
df = new DataFile(ze.getName(), DataFile.CONTENT_BINARY, ze.getName(), "application/binary", m_doc);
if(m_doc.getDataFiles() == null)
m_doc.setDataFiles(new ArrayList());
m_doc.getDataFiles().add(df);
//m_doc.addDataFile(df); // this does some intiailization work unnecessary here
}
// enable caching if requested
if(isEntry != null)
df.setOrCacheBodyAndCalcHashes(isEntry);
df.setComment(ze.getComment());
df.setLastModDt(new Date(ze.getTime()));
// fix mime type according to DataObjectFormat
Signature sig1 = m_doc.getLastSignature();
if(sig1 != null) {
Reference dRef = sig1.getSignedInfo().getReferenceForDataFile(df);
if(dRef != null) {
DataObjectFormat dof = sig1.getSignedInfo().getDataObjectFormatForReference(dRef);
if(dof != null) {
df.setMimeType(dof.getMimeType());
}
}
}
}
}
if(fTmp != null) {
fTmp.delete();
fTmp = null;
}
} // while zip entries
if(!bHasMimetype) {
m_logger.error("No mimetype file");
handleError(new DigiDocException(DigiDocException.ERR_DIGIDOC_BADXML,
"Not a BDOC format file! No mimetype file!", null));
}
// if no signatures exist then copy mime-type from manifest.xml to DataFile -s
if(m_doc.countSignatures() == 0) {
for(int i = 0; i < m_doc.countDataFiles(); i++) {
DataFile df = m_doc.getDataFile(i);
if(m_doc.getManifest() != null) {
for(int j = 0; j < m_doc.getManifest().getNumFileEntries(); j++) {
ManifestFileEntry mfe = m_doc.getManifest().getFileEntry(j);
if(mfe.getFullPath() != null && mfe.getFullPath().equals(df.getFileName())) {
df.setMimeType(mfe.getMediaType());
} // if fullpath
} // for
} // if
} // for i
}
} else { // ddoc parsing
if(m_logger.isDebugEnabled())
m_logger.debug("Reading ddoc: " + fname + " file: " + m_fileName);
m_fileName = fname;
SAXParser saxParser = factory.newSAXParser();
if(fname != null)
saxParser.parse(new SignatureInputStream(new FileInputStream(fname)), this);
else if(isSdoc != null)
saxParser.parse(isSdoc, this);
}
} catch(org.xml.sax.SAXParseException ex) {
m_logger.error("SAX Error: " + ex);
handleError(ex);
} catch (Exception ex) {
m_logger.error("Error reading3: " + ex);
ex.printStackTrace();
/*if(ex instanceof DigiDocException){
DigiDocException dex = (DigiDocException)ex;
m_logger.error("Dex: " + ex);
if(dex.getNestedException() != null) {
dex.getNestedException().printStackTrace();
m_logger.error("Trace: ");
}
}*/
handleError(ex);
} finally { // cleanup
try {
if(isEntry != null) {
isEntry.close();
isEntry = null;
}
if(zis != null)
zis.close();
if(zf != null)
zf.close();
if(fTmp != null) {
fTmp.delete();
fTmp = null;
}
} catch(Exception ex) {
m_logger.error("Error closing streams and files: " + ex);
}
}
// compare Manifest and DataFiles
boolean bErrList = (errs != null);
if(errs == null)
errs = new ArrayList();
boolean bOk = DigiDocVerifyFactory.verifyManifestEntries(m_doc, errs);
if(m_doc == null) {
m_logger.error("Error reading4: doc == null");
handleError(new DigiDocException(DigiDocException.ERR_DIGIDOC_BADXML,
"This document is not in ddoc or bdoc format", null));
}
if(!bErrList && errs.size() > 0) { // if error list was not used then we have to throw exception. So we will throw the first one since we can only do it once
DigiDocException ex = (DigiDocException)errs.get(0);
throw ex;
}
return m_doc;
}
/**
* Reads in a DigiDoc or BDOC file
* @param fname filename
* @param isBdoc true if bdoc is read
* @return signed document object if successfully parsed
*/
public SignedDoc readSignedDocOfType(String fname, boolean isBdoc)
throws DigiDocException
{
return readSignedDocOfType(fname, null, isBdoc, null);
}
/**
* Reads in a DigiDoc or BDOC from stream. In case of BDOC a Zip stream will be
* constructed to read this input stream. In case of ddoc a normal saxparsing stream
* will be used.
* @param is opened stream with DigiDoc/BDOC data
* The user must open and close it.
* @param isBdoc true if bdoc is read
* @return signed document object if successfully parsed
* @deprecated use readSignedDocFromStreamOfType(InputStream is, boolean isBdoc, List lerr)
*/
public SignedDoc readSignedDocFromStreamOfType(InputStream is, boolean isBdoc)
throws DigiDocException
{
return readSignedDocOfType(null, is, isBdoc, null);
}
/**
* Reads in a DigiDoc or BDOC file
* @param fname filename
* @param isBdoc true if bdoc is read
* @param lerr list of errors to be filled. If not null then no exceptions are thrown
* but returned in this array
* @return signed document object if successfully parsed
*/
public SignedDoc readSignedDocOfType(String fname, boolean isBdoc, List lerr)
throws DigiDocException
{
return readSignedDocOfType(fname, null, isBdoc, lerr);
}
/**
* Reads in a DigiDoc or BDOC from stream. In case of BDOC a Zip stream will be
* constructed to read this input stream. In case of ddoc a normal saxparsing stream
* will be used.
* @param is opened stream with DigiDoc/BDOC data
* The user must open and close it.
* @param isBdoc true if bdoc is read
* @param lerr list of errors to be filled. If not null then no exceptions are thrown
* but returned in this array
* @return signed document object if successfully parsed
*/
public SignedDoc readSignedDocFromStreamOfType(InputStream is, boolean isBdoc, List lerr)
throws DigiDocException
{
return readSignedDocOfType(null, is, isBdoc, lerr);
}
/**
* Reads in a DigiDoc file.This method reads only data in digidoc format. Not BDOC!
* @param digiDocStream opened stream with DigiDoc data
* The user must open and close it.
* @return signed document object if successfully parsed
*/
public SignedDoc readDigiDocFromStream(InputStream digiDocStream)
throws DigiDocException
{
DigiDocVerifyFactory.initProvider();
if(m_logger.isDebugEnabled())
m_logger.debug("Start reading ddoc/bdoc");
try {
if(m_logger.isDebugEnabled())
m_logger.debug("Reading ddoc");
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(digiDocStream, this);
} catch (SAXDigiDocException ex) {
throw ex.getDigiDocException();
} catch (Exception ex) {
DigiDocException.handleException(ex, DigiDocException.ERR_PARSE_XML);
}
if (m_doc == null)
throw new DigiDocException(DigiDocException.ERR_DIGIDOC_FORMAT,
"This document is not in digidoc", null);
return m_doc;
}
/**
* Reads in a DigiDoc file
* @param fileName file name
* @return signed document object if successfully parsed
*/
public SignedDoc readSignedDoc(String fileName)
throws DigiDocException
{
try {
FileInputStream fis = new FileInputStream(fileName);
boolean bdoc = isBdocFile(fis);
fis.close();
SignedDoc sdoc = readSignedDocOfType(fileName, bdoc);
File f = new File(fileName);
m_fileName = fileName;
sdoc.setFile(f.getName());
String s = f.getAbsolutePath();
int n = s.lastIndexOf(File.separator);
if(n > 0) {
s = s.substring(0,n);
sdoc.setPath(s);
}
return sdoc;
} catch (DigiDocException ex) {
throw ex;
} catch(java.io.FileNotFoundException ex) {
throw new DigiDocException(DigiDocException.ERR_READ_FILE,
"File not found: " + fileName, null);
} catch(java.io.IOException ex) {
throw new DigiDocException(DigiDocException.ERR_READ_FILE,
"Error determning file type: " + fileName, null);
}
}
/**
* Reads in a DigiDoc file
* @param digiSigStream opened stream with Signature data
* The user must open and close it.
* @return signed document object if successfully parsed
*/
public Signature readSignature(InputStream digiSigStream)
throws DigiDocException
{
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(digiSigStream, this);
} catch (SAXDigiDocException ex) {
throw ex.getDigiDocException();
} catch (Exception ex) {
DigiDocException.handleException(ex, DigiDocException.ERR_PARSE_XML);
}
if (m_sig == null)
throw new DigiDocException(DigiDocException.ERR_DIGIDOC_FORMAT,
"This document is not in signature format", null);
return m_sig;
}
/**
* Reads in only one
* @param sdoc SignedDoc to add this signature to
* @param sigStream opened stream with Signature data
* The user must open and close it.
* @return signed document object if successfully parsed
*/
public Signature readSignature(SignedDoc sdoc, InputStream sigStream)
throws DigiDocException
{
m_doc = sdoc;
m_nCollectMode = 0;
try {
// prepare validator to receive signature from xml file as root element
if(sdoc != null && sdoc.getFormat() != null) {
XmlElemInfo e = null;
// for BDOC
if(SignedDoc.FORMAT_BDOC.equals(sdoc.getFormat())) {
e = new XmlElemInfo("XAdESSignatures", null, null);
} else if(SignedDoc.FORMAT_DIGIDOC_XML.equals(sdoc.getFormat())) {
e = new XmlElemInfo("SignedDoc", null, null);
}
if(e != null)
m_elemRoot = m_elemCurrent = e;
}
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(sigStream, this);
} catch (SAXDigiDocException ex) {
throw ex.getDigiDocException();
} catch (Exception ex) {
DigiDocException.handleException(ex,
DigiDocException.ERR_PARSE_XML);
}
if (m_doc.getLastSignature() == null)
throw new DigiDocException(DigiDocException.ERR_DIGIDOC_FORMAT,
"This document is not in Signature format", null);
return m_doc.getLastSignature();
}
/**
* Helper method to canonicalize a piece of xml
* @param xml data to be canonicalized
* @return canonicalized xml
*/
private String canonicalizeXml(String xml) {
try {
CanonicalizationFactory canFac = ConfigManager.
instance().getCanonicalizationFactory();
byte[] tmp = canFac.canonicalize(xml.getBytes("UTF-8"),
SignedDoc.CANONICALIZATION_METHOD_20010315);
return new String(tmp, "UTF-8");
} catch(Exception ex) {
m_logger.error("Canonicalizing exception: " + ex);
}
return null;
}
public SignedDoc getSignedDoc() {
return m_doc;
}
public Signature getLastSignature() {
if(m_doc != null)
return m_doc.getLastSignature();
else
return m_sig;
}
/**
* Start Document handler
*/
public void startDocument() throws SAXException {
m_nCollectMode = 0;
m_xmlnsAttr = null;
m_dfCacheOutStream = null;
m_nsDsPref = null;
m_nsXadesPref = null;
m_nsAsicPref = null;
}
private void findCertIDandCertValueTypes(Signature sig)
{
if(m_logger.isDebugEnabled() && sig != null)
m_logger.debug("Sig: " + sig.getId() + " certids: " + sig.countCertIDs());
for(int i = 0; (sig != null) && (i < sig.countCertIDs()); i++) {
CertID cid = sig.getCertID(i);
if(cid != null && cid.getType() == CertID.CERTID_TYPE_UNKNOWN) {
if(m_logger.isDebugEnabled())
m_logger.debug("CertId: " + cid.getId() + " type: " + cid.getType() + " nr: " + cid.getSerial());
CertValue cval = sig.findCertValueWithSerial(cid.getSerial());
if(cval != null) {
String cn = null;
try {
cn = SignedDoc.
getCommonName(cval.getCert().getSubjectDN().getName());
if(m_logger.isDebugEnabled() && cid != null)
m_logger.debug("CertId type: " + cid.getType() + " nr: " + cid.getSerial() + " cval: " + cval.getId() + " CN: " + cn);
if(ConvertUtils.isKnownOCSPCert(cn)) {
if(m_logger.isInfoEnabled())
m_logger.debug("Cert: " + cn + " is OCSP responders cert");
cid.setType(CertID.CERTID_TYPE_RESPONDER);
cval.setType(CertValue.CERTVAL_TYPE_RESPONDER);
}
if(ConvertUtils.isKnownTSACert(cn)) {
if(m_logger.isDebugEnabled())
m_logger.debug("Cert: " + cn + " is TSA cert");
cid.setType(CertID.CERTID_TYPE_TSA);
cval.setType(CertValue.CERTVAL_TYPE_TSA);
if(m_logger.isDebugEnabled())
m_logger.debug("CertId: " + cid.getId() + " type: " + cid.getType() + " nr: " + cid.getSerial());
}
} catch(DigiDocException ex) {
m_logger.error("Error setting type on certid or certval: " + cn);
}
}
}
} // for i < sig.countCertIDs()
if(m_logger.isDebugEnabled())
m_logger.debug("Sig: " + sig.getId() + " certvals: " + sig.countCertValues());
for(int i = 0; (sig != null) && (i < sig.countCertValues()); i++) {
CertValue cval = sig.getCertValue(i);
if(m_logger.isDebugEnabled() && cval != null)
m_logger.debug("CertValue: " + cval.getId() + " type: " + cval.getType());
if(cval.getType() == CertValue.CERTVAL_TYPE_UNKNOWN) {
String cn = null;
try {
cn = SignedDoc.
getCommonName(cval.getCert().getSubjectDN().getName());
if(ConvertUtils.isKnownOCSPCert(cn)) {
if(m_logger.isDebugEnabled())
m_logger.debug("Cert: " + cn + " is OCSP responders cert");
cval.setType(CertValue.CERTVAL_TYPE_RESPONDER);
}
if(ConvertUtils.isKnownTSACert(cn)) {
if(m_logger.isDebugEnabled())
m_logger.debug("Cert: " + cn + " is TSA cert");
cval.setType(CertValue.CERTVAL_TYPE_TSA);
}
} catch(DigiDocException ex) {
m_logger.error("Error setting type on certid or certval: " + cn);
}
}
}
}
private String findXmlElemContents(String str, String tag, String id)
{
String s1 = "<" + tag;
String s2 = "" + tag + ">";
int nIdx1 = 0, nIdx2 = 0, nIdx3 = 0, nIdx4 = 0;
while((nIdx1 = str.indexOf(s1, nIdx1)) > 0) {
nIdx2 = str.indexOf(">", nIdx1);
if(nIdx2 > 0) {
nIdx3 = str.indexOf("Id", nIdx1);
if(nIdx3 > 0 && nIdx3 < nIdx2) {
nIdx3 = str.indexOf("\"", nIdx3);
nIdx4 = str.indexOf("\"", nIdx3+1);
if(nIdx3 > nIdx1 && nIdx3 < nIdx2 && nIdx4 > nIdx1 && nIdx4 < nIdx2) {
String sId = str.substring(nIdx3+1, nIdx4);
if(sId.equals(id)) {
nIdx2 = str.indexOf(s2, nIdx2);
if(nIdx2 > nIdx1) {
nIdx2 += s2.length() + 1;
String sEl = str.substring(nIdx1, nIdx2);
if(m_logger.isDebugEnabled())
m_logger.debug("Elem: " + tag + " id: " + id + "\n---\n" + sEl + "\n---\n");
return sEl;
}
}
}
}
}
}
return null;
}
/**
* End Document handler
*/
public void endDocument()
throws SAXException
{
}
private String findNsPrefForUri(Attributes attrs, String uri)
{
for(int i = 0; i < attrs.getLength(); i++) {
String key = attrs.getQName(i);
String val = attrs.getValue(i);
if(val.equals(uri)) {
int p = key.indexOf(':');
if(p > 0)
return key.substring(p+1);
else
return null;
}
}
return null;
}
private String findAttrValueByName(Attributes attrs, String aName)
{
for(int i = 0; i < attrs.getLength(); i++) {
String key = attrs.getQName(i);
if (key.equalsIgnoreCase(aName)) {
return attrs.getValue(i);
}
}
return null;
}
/**
* Start Element handler
* @param namespaceURI namespace URI
* @param lName local name
* @param qName qualified name
* @param attrs attributes
*/
public void startElement(String namespaceURI, String lName, String qName, Attributes attrs)
throws SAXDigiDocException
{
if(m_logger.isDebugEnabled())
m_logger.debug("Start Element: " + qName + " lname: " + lName + " uri: " + namespaceURI);
String tag = qName;
if(tag.indexOf(':') != -1) {
tag = qName.substring(qName.indexOf(':') + 1);
if(m_nsDsPref == null) {
m_nsDsPref = findNsPrefForUri(attrs, xmlnsDs);
if(m_logger.isDebugEnabled())
m_logger.debug("Element: " + qName + " xmldsig pref: " + ((m_nsDsPref != null) ? m_nsDsPref : "NULL"));
}
if(m_nsXadesPref == null) {
m_nsXadesPref = findNsPrefForUri(attrs, xmlnsEtsi);
if(m_logger.isDebugEnabled())
m_logger.debug("Element: " + qName + " xades pref: " + ((m_nsXadesPref != null) ? m_nsXadesPref : "NULL"));
}
if(m_nsAsicPref == null) {
m_nsAsicPref = findNsPrefForUri(attrs, xmlnsAsic);
if(m_logger.isDebugEnabled())
m_logger.debug("Element: " + qName + " asic pref: " + ((m_nsAsicPref != null) ? m_nsAsicPref : "NULL"));
}
}
// record elements found
XmlElemInfo e = new XmlElemInfo(tag, findAttrValueByName(attrs, "id"),
(tag.equals("XAdESSignatures") || tag.equals("SignedDoc")) ? null : m_elemCurrent);
// and cannot be child of another element, must be root elements
if(m_elemCurrent != null && !tag.equals("XAdESSignatures") && !tag.equals("SignedDoc"))
m_elemCurrent.addChild(e);
m_elemCurrent = e;
if(m_elemRoot == null || tag.equals("XAdESSignatures") || tag.equals("SignedDoc"))
m_elemRoot = e;
DigiDocException exv = DigiDocStructureValidator.validateElementPath(m_elemCurrent);
if(exv != null)
handleSAXError(exv);
m_tags.push(tag);
if(tag.equals("SigningTime") ||
tag.equals("IssuerSerial") ||
tag.equals("X509SerialNumber") ||
tag.equals("X509IssuerName") ||
tag.equals("ClaimedRole") ||
tag.equals("City") ||
tag.equals("StateOrProvince") ||
tag.equals("CountryName") ||
tag.equals("PostalCode") ||
tag.equals("SignatureValue") ||
tag.equals("DigestValue") ||
//qName.equals("EncapsulatedX509Certificate") ||
tag.equals("IssuerSerial") ||
(tag.equals("ResponderID") && !m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC)) ||
(tag.equals("ByName") && m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC) ) ||
(tag.equals("ByKey") && m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC)) ||
tag.equals("X509SerialNumber") ||
tag.equals("ProducedAt") ||
tag.equals("EncapsulatedTimeStamp") ||
tag.equals("Identifier") ||
tag.equals("SPURI") ||
tag.equals("NonceAlgorithm") ||
tag.equals("MimeType") ||
tag.equals("EncapsulatedOCSPValue") ) {
if(m_logger.isDebugEnabled())
m_logger.debug("Start collecting tag: " + tag);
m_sbCollectItem = new StringBuffer();
}
//
if(tag.equals("XAdESSignatures")) {
try {
if (m_logger.isDebugEnabled())
m_logger.debug("BDOC 2.0 - ASIC-E");
m_doc.setFormatAndVersion(SignedDoc.FORMAT_BDOC, SignedDoc.BDOC_VERSION_2_1);
} catch(DigiDocException ex) {
handleSAXError(ex);
}
}
//
// Prepare CertValue object
if(tag.equals("X509Certificate")) {
Signature sig = getLastSignature();
CertValue cval = null;
try {
if (m_logger.isDebugEnabled())
m_logger.debug("Adding signers cert to: " + sig.getId());
cval = sig.getOrCreateCertValueOfType(CertValue.CERTVAL_TYPE_SIGNER);
} catch(DigiDocException ex) {
handleSAXError(ex);
}
m_sbCollectItem = new StringBuffer();
}
//
// Prepare CertValue object and record it's id
if(tag.equals("EncapsulatedX509Certificate")) {
Signature sig = getLastSignature();
String id = null;
for(int i = 0; i < attrs.getLength(); i++) {
String key = attrs.getQName(i);
if (key.equalsIgnoreCase("Id")) {
id = attrs.getValue(i);
}
}
CertValue cval = new CertValue();
if(id != null) {
cval.setId(id);
try {
if(id.indexOf("RESPONDER_CERT") != -1 ||
id.indexOf("RESPONDER-CERT") != -1)
cval.setType(CertValue.CERTVAL_TYPE_RESPONDER);
} catch(DigiDocException ex) {
handleSAXError(ex);
}
}
if(m_logger.isDebugEnabled() && cval != null)
m_logger.debug("Adding cval " + cval.getId() + " type: " + cval.getType() + " to: " + sig.getId());
sig.addCertValue(cval);
m_sbCollectItem = new StringBuffer();
}
// the following elements switch collect mode
// in and out
//
boolean bDfDdoc13Bad = false;
if(tag.equals("DataFile")) {
String ContentType = null, Filename = null, Id = null, MimeType = null, Size = null, DigestType = null, Codepage = null;
byte[] DigestValue = null;
m_digest = null; // init to null
if (m_doc != null &&
m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) &&
m_doc.getVersion().equals(SignedDoc.VERSION_1_3)) {
m_xmlnsAttr = SignedDoc.xmlns_digidoc13;
bDfDdoc13Bad = true; // possible case for ddoc 1.3 invalid namespace problem
} else
m_xmlnsAttr = null;
ArrayList dfAttrs = new ArrayList();
for (int i = 0; i < attrs.getLength(); i++) {
String key = attrs.getQName(i);
if (key.equals("ContentType")) {
ContentType = attrs.getValue(i);
} else if (key.equals("Filename")) {
Filename = attrs.getValue(i);
if(Filename.indexOf('/') != -1 || Filename.indexOf('\\') != -1) {
DigiDocException ex = new DigiDocException(DigiDocException.ERR_DF_NAME, "Failed to parse DataFile name. Invalid file name!", null);
handleSAXError(ex);
}
} else if (key.equals("Id")) {
Id = attrs.getValue(i);
} else if (key.equals("MimeType")) {
MimeType = attrs.getValue(i);
} else if (key.equals("Size")) {
Size = attrs.getValue(i);
} else if (key.equals("DigestType")) {
DigestType = attrs.getValue(i);
} else if (key.equals("Codepage")) {
Codepage = attrs.getValue(i);
} else if (key.equals("DigestValue")) {
DigestValue = Base64Util.decode(attrs.getValue(i));
} else {
try {
if (!key.equals("xmlns")) {
DataFileAttribute attr = new DataFileAttribute(key, attrs.getValue(i));
dfAttrs.add(attr);
} else {
bDfDdoc13Bad = false; // nope, this one has it's own xmlns
}
} catch (DigiDocException ex) {
handleSAXError(ex);
}
} // else
} // for
if(m_nCollectMode == 0) {
try {
DataFile df = new DataFile(Id, ContentType, Filename, MimeType, m_doc);
m_dfCacheOutStream = null; // default is don't use cache file
if (Size != null)
df.setSize(Long.parseLong(Size));
if (DigestValue != null) {
if(m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML))
df.setAltDigest(DigestValue);
else if(ContentType != null && ContentType.equals(DataFile.CONTENT_HASHCODE))
df.setDigestValue(DigestValue);
}
if (Codepage != null)
df.setInitialCodepage(Codepage);
for (int i = 0; i < dfAttrs.size(); i++)
df.addAttribute((DataFileAttribute) dfAttrs.get(i));
// enable caching if requested
if(m_tempDir != null) {
File fCache = new File(m_tempDir + File.separator + df.getFileName());
if(m_logger.isDebugEnabled())
m_logger.debug("Parser temp DF: " + Id + " size: " + df.getSize() +
" cache-file: " + fCache.getAbsolutePath());
m_dfCacheOutStream = new FileOutputStream(fCache);
df.setCacheFile(fCache);
} else if(df.schouldUseTempFile()) {
File fCache = df.createCacheFile();
if(m_logger.isDebugEnabled())
m_logger.debug("Df-temp DF: " + Id + " size: " + df.getSize() +
" cache-file: " + fCache.getAbsolutePath());
df.setCacheFile(fCache);
m_dfCacheOutStream = new FileOutputStream(fCache);
}
m_doc.addDataFile(df);
} catch (IOException ex) {
handleSAXError(ex);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
m_nCollectMode++;
// try to anticipate how much memory we need for collecting this
try {
if(Size != null) {
int nSize = Integer.parseInt(Size);
if(!ContentType.equals(DataFile.CONTENT_HASHCODE)) {
if(ContentType.equals(DataFile.CONTENT_EMBEDDED_BASE64)) {
nSize *= 2;
m_bCollectDigest = true;
if(m_logger.isDebugEnabled())
m_logger.debug("Start collecting digest");
}
if(m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML))
m_bCollectDigest = false;
if(m_logger.isDebugEnabled())
m_logger.debug("Allocating buf: " + nSize + " Element: " + qName + " lname: " + lName + " uri: " + namespaceURI);
if(m_dfCacheOutStream == null) // if we use temp files then we don't cache in memory
m_sbCollectChars = new StringBuffer(nSize);
}
}
} catch(Exception ex) {
m_logger.error("Error: " + ex);
}
}
//
if(tag.equals("SignedInfo")) {
if (m_nCollectMode == 0) {
try {
if (m_doc != null &&
(m_doc.getVersion().equals(SignedDoc.VERSION_1_3) ||
m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC) ||
m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)))
m_xmlnsAttr = null;
else
m_xmlnsAttr = SignedDoc.xmlns_xmldsig;
Signature sig = getLastSignature();
SignedInfo si = new SignedInfo(sig);
if(sig != null) {
sig.setSignedInfo(si);
String Id = attrs.getValue("Id");
if(Id != null)
si.setId(Id);
}
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
m_nCollectMode++;
m_sbCollectChars = new StringBuffer(1024);
}
//
if(tag.equals("SignedProperties")) {
String Id = attrs.getValue("Id");
String Target = attrs.getValue("Target");
if (m_nCollectMode == 0) {
try {
if(m_doc != null &&
(m_doc.getVersion().equals(SignedDoc.VERSION_1_3) ||
m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC)))
m_xmlnsAttr = null;
else
m_xmlnsAttr = SignedDoc.xmlns_xmldsig;
Signature sig = getLastSignature();
SignedProperties sp = new SignedProperties(sig);
sp.setId(Id);
if(Target != null)
sp.setTarget(Target);
sig.setSignedProperties(sp);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
m_nCollectMode++;
m_sbCollectChars = new StringBuffer(2048);
}
//
if(tag.equals("XAdESSignatures") && m_nCollectMode == 0) {
if (m_logger.isDebugEnabled())
m_logger.debug("Start collecting ");
m_sbCollectSignature = new StringBuffer();
}
//
if(tag.equals("Signature") && m_nCollectMode == 0) {
if (m_logger.isDebugEnabled())
m_logger.debug("Start collecting ");
if(m_doc == null) {
DigiDocException ex = new DigiDocException(DigiDocException.ERR_PARSE_XML, "Invalid signature format. Missing signed container root element.", null);
handleSAXError(ex); // now stop parsing
SAXDigiDocException sex1 = new SAXDigiDocException("Invalid signature format. Missing signed container root element.");
throw sex1;
}
String str1 = attrs.getValue("Id");
Signature sig = null;
// in case of ddoc-s try find existing signature but not in case of bdoc-s.
// to support libc++ buggy implementation with non-unique id atributes
if(m_doc != null && !m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC))
sig = m_doc.findSignatureById(str1);
if(m_doc != null && m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC) &&
m_doc.getVersion().equals(SignedDoc.BDOC_VERSION_2_1)) {
m_doc.addSignatureProfile(str1, SignedDoc.BDOC_PROFILE_TM);
if(m_doc.getProfile() == null || !m_doc.getProfile().equals(SignedDoc.BDOC_PROFILE_TM))
m_doc.setProfile(SignedDoc.BDOC_PROFILE_TM);
}
if(sig == null || (sig.getId() != null && !sig.getId().equals(str1))) {
if (m_logger.isDebugEnabled())
m_logger.debug("Create signature: " + str1);
if(m_doc != null) {
sig = new Signature(m_doc);
try {
sig.setId(str1);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
sig.setPath(m_fileName);
sig.setComment(m_sigComment);
String sProfile = m_doc.findSignatureProfile(m_fileName);
if(sProfile == null)
sProfile = m_doc.findSignatureProfile(sig.getId());
if(sProfile != null)
sig.setProfile(sProfile);
/*if(sProfile == null &&
(m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) ||
m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)))
sig.setProfile(SignedDoc.BDOC_PROFILE_TM);*/
m_doc.addSignature(sig);
if (m_logger.isDebugEnabled())
m_logger.debug("Sig1: " + m_fileName + " profile: " + sProfile + " doc: " + ((m_doc != null) ? "OK" : "NULL"));
} else {
m_sig = new Signature(null);
m_sig.setPath(m_fileName);
m_sig.setComment(m_sigComment);
String sProfile = null;
if(m_doc != null && m_fileName != null)
sProfile = m_doc.findSignatureProfile(m_fileName);
if(sProfile != null)
m_sig.setProfile(sProfile);
if (m_logger.isDebugEnabled())
m_logger.debug("Sig2: " + m_fileName + " profile: " + sProfile);
sig = m_sig;
}
for(int j = 0; (m_doc != null) && (j < m_doc.countSignatures()); j++) {
Signature sig2 = m_doc.getSignature(j);
if(sig2 != null && sig != null && m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC) &&
sig2.getId() != null && sig.getId() != null && !sig2.getId().equals(sig.getId()) &&
sig2.getPath() != null && sig.getPath() != null && sig2.getPath().equals(sig.getPath())) {
m_logger.error("Signatures: " + sig.getId() + " and " + sig2.getId() + " are in same file: " + sig.getPath());
DigiDocException ex = new DigiDocException(DigiDocException.ERR_PARSE_XML, "More than one signature in signatures.xml file is unsupported", null);
handleSAXError(ex);
}
}
}
if(m_sbCollectSignature == null)
m_sbCollectSignature = new StringBuffer();
}
//
if(tag.equals("SignatureValue") && m_nCollectMode == 0) {
m_strSigValTs = null;
m_nCollectMode++;
m_sbCollectChars = new StringBuffer(1024);
}
//
if(tag.equals("SignatureTimeStamp") && m_nCollectMode == 0) {
if(m_sig != null) m_sig.setProfile(SignedDoc.BDOC_PROFILE_TS);
m_doc.setProfile(SignedDoc.BDOC_PROFILE_TS);
m_strSigAndRefsTs = null;
m_nCollectMode++;
m_sbCollectChars = new StringBuffer(2048);
}
// collect data
if(m_sbCollectSignature != null) {
m_sbCollectSignature.append("<");
m_sbCollectSignature.append(qName);
for (int i = 0; i < attrs.getLength(); i++) {
m_sbCollectSignature.append(" ");
m_sbCollectSignature.append(attrs.getQName(i));
m_sbCollectSignature.append("=\"");
String s = attrs.getValue(i);
s = s.replaceAll("&", "&");
m_sbCollectSignature.append(s);
m_sbCollectSignature.append("\"");
}
m_sbCollectSignature.append(">");
}
// if we just switched to collect-mode
// collect SAX event data to original XML data
// for we don't collect the begin and
// end tags unless this an embedded
if(m_nCollectMode > 0 || m_sbCollectChars != null) {
StringBuffer sb = new StringBuffer();
String sDfTagBad = null;
sb.append("<");
sb.append(qName);
for (int i = 0; i < attrs.getLength(); i++) {
if(attrs.getQName(i).equals("xmlns")) {
m_xmlnsAttr = null; // allready have it from document
bDfDdoc13Bad = false;
}
sb.append(" ");
sb.append(attrs.getQName(i));
sb.append("=\"");
if(m_logger.isDebugEnabled())
m_logger.debug("Attr: " + attrs.getQName(i) + " =\'" + attrs.getValue(i) + "\'");
if(!m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)) {
sb.append(ConvertUtils.escapeXmlSymbols(attrs.getValue(i)));
} else {
String sv = attrs.getValue(i);
if(attrs.getQName(i).equals("DigestValue") && sv.endsWith(" "))
sv = sv.replaceAll(" ", "\n");
sb.append(sv);
}
sb.append("\"");
}
if(bDfDdoc13Bad)
sDfTagBad = sb.toString() + ">";
if (m_xmlnsAttr != null) {
sb.append(" xmlns=\"" + m_xmlnsAttr + "\"");
m_xmlnsAttr = null;
}
sb.append(">");
//canonicalize & calculate digest over DataFile begin-tag without content
if(tag.equals("DataFile") && m_nCollectMode == 1) {
String strCan = null;
if(!m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)) {
strCan = sb.toString() + " ";
strCan = canonicalizeXml(strCan);
strCan = strCan.substring(0, strCan.length() - 11);
if(m_logger.isDebugEnabled())
m_logger.debug("Canonicalized: \'" + strCan + "\'");
if(sDfTagBad != null) {
strCan = sDfTagBad + " ";
strCan = canonicalizeXml(strCan);
sDfTagBad = strCan.substring(0, strCan.length() - 11);
if(m_logger.isDebugEnabled())
m_logger.debug("Canonicalized alternative: \'" + sDfTagBad + "\'");
}
try {
updateDigest(ConvertUtils.str2data(strCan));
if(sDfTagBad != null)
updateAltDigest(ConvertUtils.str2data(sDfTagBad));
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
} // we don't collect begin and end - tags and we don't collect if we use temp files
else {
if(m_sbCollectChars != null)
m_sbCollectChars.append(sb.toString());
try {
if(m_dfCacheOutStream != null)
m_dfCacheOutStream.write(ConvertUtils.str2data(sb.toString()));
} catch (IOException ex) {
handleSAXError(ex);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
}
// the following stuff is used also on level 1
// because it can be part of SignedInfo or SignedProperties
if(m_nCollectMode == 1) {
//
if(tag.equals("CanonicalizationMethod")) {
String Algorithm = attrs.getValue("Algorithm");
try {
Signature sig = getLastSignature();
SignedInfo si = sig.getSignedInfo();
si.setCanonicalizationMethod(Algorithm);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("SignatureMethod")) {
String Algorithm = attrs.getValue("Algorithm");
try {
Signature sig = getLastSignature();
SignedInfo si = sig.getSignedInfo();
si.setSignatureMethod(Algorithm);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("Reference")) {
String URI = attrs.getValue("URI");
try {
Signature sig = getLastSignature();
SignedInfo si = sig.getSignedInfo();
Reference ref = new Reference(si);
String Id = attrs.getValue("Id");
if(Id != null)
ref.setId(Id);
ref.setUri(ConvertUtils.unescapeXmlSymbols(ConvertUtils.uriDecode(URI)));
String sType = attrs.getValue("Type");
if(sType != null)
ref.setType(sType);
si.addReference(ref);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
/*if(tag.equals("Transform")) {
String Algorithm = attrs.getValue("Algorithm");
if(m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC) ||
m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML)) {
DigiDocException ex = new DigiDocException(DigiDocException.ERR_TRANSFORMS, "Transform elements are currently not supported ", null);
handleSAXError(ex);
}
}*/
//
if(tag.equals("X509SerialNumber") && m_doc != null
&& m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML))
{
String sXmlns = attrs.getValue("xmlns");
if(sXmlns == null || !sXmlns.equals(SignedDoc.xmlns_xmldsig)) {
if(m_logger.isDebugEnabled())
m_logger.debug("X509SerialNumber has none or invalid namespace: " + sXmlns);
DigiDocException ex = new DigiDocException(DigiDocException.ERR_ISSUER_XMLNS, "X509SerialNumber has none or invalid namespace: " + sXmlns, null);
handleSAXError(ex);
}
}
//
if(tag.equals("X509IssuerName") && m_doc != null
&& m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML))
{
String sXmlns = attrs.getValue("xmlns");
if(sXmlns == null || !sXmlns.equals(SignedDoc.xmlns_xmldsig)) {
if(m_logger.isDebugEnabled())
m_logger.debug("X509IssuerName has none or invalid namespace: " + sXmlns);
DigiDocException ex = new DigiDocException(DigiDocException.ERR_ISSUER_XMLNS, "X509IssuerName has none or invalid namespace: " + sXmlns, null);
handleSAXError(ex);
}
}
//
if(tag.equals("SignatureProductionPlace")) {
try {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
SignatureProductionPlace spp =
new SignatureProductionPlace();
sp.setSignatureProductionPlace(spp);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
}
// the following is collected anyway independent of collect mode
//
if(tag.equals("SignatureValue")) {
String Id = attrs.getValue("Id");
try {
Signature sig = getLastSignature();
SignatureValue sv = new SignatureValue(sig, Id);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("OCSPRef")) {
OcspRef orf = new OcspRef();
Signature sig = getLastSignature();
UnsignedProperties usp = sig.getUnsignedProperties();
CompleteRevocationRefs rrefs = usp.getCompleteRevocationRefs();
rrefs.addOcspRef(orf);
}
//
if(tag.equals("DigestMethod")) {
String Algorithm = attrs.getValue("Algorithm");
try {
if(m_tags.search("Reference") != -1) {
Signature sig = getLastSignature();
SignedInfo si = sig.getSignedInfo();
Reference ref = si.getLastReference();
ref.setDigestAlgorithm(Algorithm);
} else if(m_tags.search("SigningCertificate") != -1) {
Signature sig = getLastSignature();
CertID cid = sig.getOrCreateCertIdOfType(CertID.CERTID_TYPE_SIGNER);
cid.setDigestAlgorithm(Algorithm);
} else if(m_tags.search("CompleteCertificateRefs") != -1) {
Signature sig = getLastSignature();
CertID cid = sig.getLastCertId(); // initially set to unknown type !
cid.setDigestAlgorithm(Algorithm);
} else if(m_tags.search("CompleteRevocationRefs") != -1) {
Signature sig = getLastSignature();
UnsignedProperties up = sig.getUnsignedProperties();
CompleteRevocationRefs rrefs = up.getCompleteRevocationRefs();
OcspRef orf = rrefs.getLastOcspRef();
if(orf != null)
orf.setDigestAlgorithm(Algorithm);
} else if(m_tags.search("SigPolicyHash") != -1) {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
SignaturePolicyIdentifier spi = sp.getSignaturePolicyIdentifier();
SignaturePolicyId sppi = spi.getSignaturePolicyId();
sppi.setDigestAlgorithm(Algorithm);
}
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("Cert")) {
String id = attrs.getValue("Id");
try {
Signature sig = getLastSignature();
if(m_tags.search("SigningCertificate") != -1) {
CertID cid = sig.getOrCreateCertIdOfType(CertID.CERTID_TYPE_SIGNER);
if(id != null)
cid.setId(id);
}
if(m_tags.search("CompleteCertificateRefs") != -1) {
//CertID cid = new CertID();
CertID cid = sig.getOrCreateCertIdOfType(CertID.CERTID_TYPE_RESPONDER);
if(id != null)
cid.setId(id);
sig.addCertID(cid);
}
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("AllDataObjectsTimeStamp")) {
String id = attrs.getValue("Id");
try {
Signature sig = getLastSignature();
TimestampInfo ts = new TimestampInfo(id, TimestampInfo.TIMESTAMP_TYPE_ALL_DATA_OBJECTS);
sig.addTimestampInfo(ts);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("IndividualDataObjectsTimeStamp")) {
String id = attrs.getValue("Id");
try {
Signature sig = getLastSignature();
TimestampInfo ts = new TimestampInfo(id, TimestampInfo.TIMESTAMP_TYPE_INDIVIDUAL_DATA_OBJECTS);
sig.addTimestampInfo(ts);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("SignatureTimeStamp")) {
String id = attrs.getValue("Id");
try {
Signature sig = getLastSignature();
TimestampInfo ts = new TimestampInfo(id, TimestampInfo.TIMESTAMP_TYPE_SIGNATURE);
sig.addTimestampInfo(ts);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("SigAndRefsTimeStamp")) {
String id = attrs.getValue("Id");
try {
Signature sig = getLastSignature();
TimestampInfo ts = new TimestampInfo(id, TimestampInfo.TIMESTAMP_TYPE_SIG_AND_REFS);
sig.addTimestampInfo(ts);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("RefsOnlyTimeStamp")) {
String id = attrs.getValue("Id");
try {
Signature sig = getLastSignature();
TimestampInfo ts = new TimestampInfo(id, TimestampInfo.TIMESTAMP_TYPE_REFS_ONLY);
sig.addTimestampInfo(ts);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("ArchiveTimeStamp")) {
String id = attrs.getValue("Id");
try {
Signature sig = getLastSignature();
TimestampInfo ts = new TimestampInfo(id, TimestampInfo.TIMESTAMP_TYPE_ARCHIVE);
sig.addTimestampInfo(ts);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("Include")) {
String uri = attrs.getValue("URI");
try {
Signature sig = getLastSignature();
TimestampInfo ts = sig.getLastTimestampInfo();
IncludeInfo inc = new IncludeInfo(uri);
ts.addIncludeInfo(inc);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("CompleteCertificateRefs")) {
String Target = attrs.getValue("Target");
try {
Signature sig = getLastSignature();
UnsignedProperties up = sig.getUnsignedProperties();
CompleteCertificateRefs crefs =
new CompleteCertificateRefs();
up.setCompleteCertificateRefs(crefs);
crefs.setUnsignedProperties(up);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("CompleteRevocationRefs")) {
try {
Signature sig = getLastSignature();
UnsignedProperties up = sig.getUnsignedProperties();
CompleteRevocationRefs rrefs = new CompleteRevocationRefs();
up.setCompleteRevocationRefs(rrefs);
rrefs.setUnsignedProperties(up);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("OCSPIdentifier")) {
String URI = attrs.getValue("URI");
try {
Signature sig = getLastSignature();
UnsignedProperties up = sig.getUnsignedProperties();
CompleteRevocationRefs rrefs = up.getCompleteRevocationRefs();
OcspRef orf = rrefs.getLastOcspRef();
orf.setUri(URI);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("SignaturePolicyIdentifier")) {
try {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
SignaturePolicyIdentifier spid = sp.getSignaturePolicyIdentifier();
if(spid == null) {
spid = new SignaturePolicyIdentifier(null);
sp.setSignaturePolicyIdentifier(spid);
}
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("SignaturePolicyId")) {
try {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
SignaturePolicyIdentifier spid = sp.getSignaturePolicyIdentifier();
if(spid == null) {
spid = new SignaturePolicyIdentifier(null);
sp.setSignaturePolicyIdentifier(spid);
}
SignaturePolicyId spi = spid.getSignaturePolicyId();
if(spi == null) {
spi = new SignaturePolicyId(null);
spid.setSignaturePolicyId(spi);
}
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
// cannot handle alone because we need mandatory Identifier value
//
if(tag.equals("Identifier")) {
try {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
SignaturePolicyIdentifier spid = sp.getSignaturePolicyIdentifier();
if(spid == null) {
spid = new SignaturePolicyIdentifier(null);
sp.setSignaturePolicyIdentifier(spid);
}
SignaturePolicyId spi = spid.getSignaturePolicyId();
if(spi == null) {
spi = new SignaturePolicyId(null);
spid.setSignaturePolicyId(spi);
}
String sQualifier = attrs.getValue("Qualifier");
Identifier id = new Identifier(sQualifier);
ObjectIdentifier oi = spi.getSigPolicyId();
if(oi == null)
oi = new ObjectIdentifier(id);
else
oi.setIdentifier(id);
spi.setSigPolicyId(oi);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("SigPolicyQualifier")) {
try {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
SignaturePolicyIdentifier spid = sp.getSignaturePolicyIdentifier();
if(spid == null) {
spid = new SignaturePolicyIdentifier(null);
sp.setSignaturePolicyIdentifier(spid);
}
SignaturePolicyId spi = spid.getSignaturePolicyId();
if(spi == null) {
spi = new SignaturePolicyId(null);
spid.setSignaturePolicyId(spi);
}
SigPolicyQualifier spq = new SigPolicyQualifier();
spi.addSigPolicyQualifier(spq);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("DataObjectFormat")) {
Signature sig = getLastSignature();
try {
if(sig != null) {
SignedProperties sp = sig.getSignedProperties();
if(sp != null) {
SignedDataObjectProperties sdps = sp.getSignedDataObjectProperties();
if(sdps == null) {
sdps = new SignedDataObjectProperties();
sp.setSignedDataObjectProperties(sdps);
}
String sObjectReference = attrs.getValue("ObjectReference");
DataObjectFormat dof = new DataObjectFormat(sObjectReference);
sdps.addDataObjectFormat(dof);
}
}
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
// - give error?
if(tag.equals("NonceAlgorithm")) {
}
// the following stuff is ignored in collect mode
// because it can only be the content of a higher element
if(m_nCollectMode == 0) {
//
if(tag.equals("SignedDoc")) {
String format = null, version = null;
for(int i = 0; i < attrs.getLength(); i++) {
String key = attrs.getQName(i);
if(key.equals("format"))
format = attrs.getValue(i);
if(key.equals("version"))
version = attrs.getValue(i);
}
try {
m_doc = new SignedDoc();
m_doc.setFormat(format);
m_doc.setVersion(version);
if(format != null && (format.equals(SignedDoc.FORMAT_SK_XML) || format.equals(SignedDoc.FORMAT_DIGIDOC_XML))) {
m_doc.setProfile(SignedDoc.BDOC_PROFILE_TM); // in ddoc format we used only TM
}
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
/*if(qName.equals("Signature")) {
String Id = attrs.getValue("Id");
try {
Signature sig = new Signature(m_doc);
if(Id != null)
sig.setId(Id);
m_doc.addSignature(sig);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}*/
//
if(tag.equals("KeyInfo")) {
try {
KeyInfo ki = new KeyInfo();
String Id = attrs.getValue("Id");
if(Id != null)
ki.setId(Id);
Signature sig = getLastSignature();
sig.setKeyInfo(ki);
ki.setSignature(sig);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("UnsignedProperties")) {
String Target = attrs.getValue("Target");
try {
Signature sig = getLastSignature();
UnsignedProperties up = new UnsignedProperties(sig);
sig.setUnsignedProperties(up);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("EncapsulatedOCSPValue")) {
String Id = attrs.getValue("Id");
Signature sig = getLastSignature();
UnsignedProperties up = sig.getUnsignedProperties();
Notary not = new Notary();
if(Id != null)
not.setId(Id);
not.setId(Id);
up.addNotary(not);
if(sig.getProfile() == null &&
(m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) ||
m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)))
sig.setProfile(SignedDoc.BDOC_PROFILE_TM);
}
} // if(m_nCollectMode == 0)
}
private static final String xmlnsEtsi = "http://uri.etsi.org/01903/v1.3.2#";
private static final String xmlnsDs = "http://www.w3.org/2000/09/xmldsig#";
private static final String xmlnsAsic = "http://uri.etsi.org/02918/v1.2.1#";
//private static final String xmlnsNonce = "http://www.sk.ee/repository/NonceAlgorithm";
private TreeSet collectNamespaces(String sCanInfo, TreeSet tsOtherAttr)
{
TreeSet ts = new TreeSet();
// find element header
int p1 = -1, p2 = -1;
p1 = sCanInfo.indexOf('>');
if(p1 != -1) {
String sHdr = sCanInfo.substring(0, p1);
if(m_logger.isDebugEnabled())
m_logger.debug("Header: " + sHdr);
String[] toks = sHdr.split(" ");
for(int i = 0; (toks != null) && (i < toks.length); i++) {
String tok = toks[i];
if(tok != null && tok.trim().length() > 0 && tok.charAt(0) != '<') {
if(tok.indexOf("xmlns") != -1)
ts.add(tok);
else
tsOtherAttr.add(tok);
}
}
}
return ts;
}
private void addNamespaceIfMissing(TreeSet ts, String ns, String pref)
{
boolean bF = false;
Iterator iNs = ts.iterator();
while(iNs.hasNext()) {
String s = (String)iNs.next();
if(s != null && s.indexOf(ns) != -1) {
bF = true;
break;
}
}
if(!bF) {
StringBuffer sb = new StringBuffer("xmlns");
if(pref != null) {
sb.append(":");
sb.append(pref);
}
sb.append("=\"");
sb.append(ns);
sb.append("\"");
ts.add(sb.toString());
}
}
private String getPrefOfNs(String ns)
{
if(ns.indexOf(xmlnsDs) != -1) return m_nsDsPref;
if(ns.indexOf(xmlnsEtsi) != -1) return m_nsXadesPref;
if(ns.indexOf(xmlnsAsic) != -1) return m_nsAsicPref;
return null;
}
private byte[] addNamespaces(byte[] bCanInfo, boolean bDsNs, boolean bEtsiNs,
String dsNsPref, String xadesNsPref, boolean bAsicNs, String asicPref)
{
byte[] bInfo = bCanInfo;
try {
String s1 = new String(bCanInfo, "UTF-8");
if(m_logger.isDebugEnabled())
m_logger.debug("Input xml:\n------\n" + s1 + "\n------\n");
TreeSet tsOtherAttr = new TreeSet();
TreeSet tsNs = collectNamespaces(s1, tsOtherAttr);
Iterator iNs = tsNs.iterator();
while(iNs.hasNext()) {
String s = (String)iNs.next();
m_logger.debug("Has ns: " + s);
}
iNs = tsOtherAttr.iterator();
while(iNs.hasNext()) {
String s = (String)iNs.next();
m_logger.debug("Other attr: " + s);
}
if(bDsNs)
addNamespaceIfMissing(tsNs, xmlnsDs, dsNsPref);
if(bEtsiNs)
addNamespaceIfMissing(tsNs, xmlnsEtsi, xadesNsPref);
if(bAsicNs)
addNamespaceIfMissing(tsNs, xmlnsAsic, asicPref);
iNs = tsNs.iterator();
while(iNs.hasNext()) {
String s = (String)iNs.next();
m_logger.debug("Now has ns: " + s);
}
// put back in header
int p1 = s1.indexOf(' ');
int p2 = s1.indexOf('>');
if(p1 > p2) p1 = p2; // if has no atributes
String sRest = s1.substring(p2);
StringBuffer sb = new StringBuffer();
sb.append(s1.substring(0, p1));
iNs = tsNs.iterator();
while(iNs.hasNext()) {
sb.append(" ");
String s = (String)iNs.next();
sb.append(s);
}
iNs = tsOtherAttr.iterator();
while(iNs.hasNext()) {
sb.append(" ");
String s = (String)iNs.next();
sb.append(s);
}
sb.append(sRest);
bInfo = sb.toString().getBytes("UTF-8");
if(m_logger.isDebugEnabled())
m_logger.debug("Modified xml:\n------\n" + sb.toString() + "\n------\n");
} catch(Exception ex) {
m_logger.error("Error adding namespaces: " + ex);
}
return bInfo; // default is to return original content
}
private byte[] addNamespaceOnChildElems(byte[] bCanInfo, String nsPref, String nsUri)
{
byte[] bInfo = bCanInfo;
try {
String s1 = new String(bCanInfo, "UTF-8");
if(m_logger.isDebugEnabled())
m_logger.debug("AddChildNs: " + nsPref + "=" + nsUri + " Input xml:\n------\n" + s1 + "\n------\n");
// find boundarys of root elem
int p1 = s1.indexOf('>')+1;
int p2 = s1.lastIndexOf('<');
String sRest = s1.substring(p2);
StringBuffer sb = new StringBuffer();
sb.append(s1.substring(0, p1));
int p3 = p1, p4 = 0, p5 = 0, p6 = 0;
do {
boolean bCopy = true;
p4 = s1.indexOf('<', p3);
// possible whitespace
if(p4 > p3+1)
sb.append(s1.substring(p3, p4));
p3 = p4;
p4 = s1.indexOf('>', p3) + 1;
if(s1.charAt(p3) == '<' && s1.charAt(p3+1) != '/') {
p5 = s1.indexOf(':', p3);
if(p5 > p3 && p5 < p4) {
String pref = s1.substring(p3+1, p5);
if(pref != null && pref.equals(nsPref)) {
p6 = s1.indexOf(' ', p5);
if(p6 > p4)
p6 = p4 - 1;
sb.append(s1.substring(p3, p6));
sb.append(" xmlns:");
sb.append(nsPref);
sb.append("=\"");
sb.append(nsUri);
sb.append("\"");
bCopy = false;
sb.append(s1.substring(p6, p4));
}
}
}
if(bCopy)
sb.append(s1.substring(p3, p4));
if(p4 > 0 && p4 < p2)
p3 = p4;
} while (p4 > 0 && p4 < p2);
sb.append(sRest);
bInfo = sb.toString().getBytes("UTF-8");
if(m_logger.isDebugEnabled())
m_logger.debug("Modified xml:\n------\n" + sb.toString() + "\n------\n");
} catch(Exception ex) {
m_logger.error("Error adding namespaces: " + ex);
}
return bInfo; // default is to return original content
}
/**
* End Element handler
* @param namespaceURI namespace URI
* @param lName local name
* @param qName qualified name
*/
public void endElement(String namespaceURI, String sName, String qName)
throws SAXException
{
if(m_logger.isDebugEnabled())
m_logger.debug("End Element: " + qName + " collect: " + m_nCollectMode);
// remove last tag from stack
String tag = qName;
String nsPref = null;
if(tag.indexOf(':') != -1) {
tag = qName.substring(qName.indexOf(':') + 1);
nsPref = qName.substring(0, qName.indexOf(':'));
}
if(m_elemCurrent != null)
m_elemCurrent = m_elemCurrent.getParent();
String currTag = (String) m_tags.pop();
// collect SAX event data to original XML data
// for we don't collect the begin and
// end tags unless this an embedded
StringBuffer sb = null;
if (m_nCollectMode > 0
&& (!tag.equals("DataFile") || m_nCollectMode > 1)) {
sb = new StringBuffer();
sb.append("");
sb.append(qName);
sb.append(">");
}
if (m_sbCollectSignature != null) {
m_sbCollectSignature.append("");
m_sbCollectSignature.append(qName);
m_sbCollectSignature.append(">");
}
// if we do cache in mem
if(m_sbCollectChars != null && sb != null)
m_sbCollectChars.append(sb.toString());
//
if(tag.equals("DataFile")) {
m_nCollectMode--;
if (m_nCollectMode == 0) {
// close DataFile cache if necessary
try {
if(m_dfCacheOutStream != null) {
if(sb != null)
m_dfCacheOutStream.write(ConvertUtils.str2data(sb.toString()));
m_dfCacheOutStream.close();
m_dfCacheOutStream = null;
}
} catch (IOException ex) {
handleSAXError(ex);
} catch (DigiDocException ex) {
handleSAXError(ex);
}
DataFile df = m_doc.getLastDataFile();
if(df != null && df.getContentType().equals(DataFile.CONTENT_EMBEDDED_BASE64)) {
try {
if(m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)) {
String sDf = null;
if(m_sbCollectChars != null) {
sDf = m_sbCollectChars.toString();
m_sbCollectChars = null;
} else if(df.getDfCacheFile() != null) {
byte[] data = null;
try {
data = SignedDoc.readFile(df.getDfCacheFile());
sDf = new String(data);
} catch(Exception ex) {
m_logger.error("Error reading cache file: " + df.getDfCacheFile() + " - " + ex);
}
}
if(sDf != null) {
byte[] bDf = Base64Util.decode(sDf);
updateDigest(bDf);
}
df.setDigest(getDigest());
if(m_logger.isDebugEnabled())
m_logger.debug("Digest: " + df.getId() + " - " + Base64Util.encode(df.getDigest()) + " size: " + df.getSize());
} else {
long nSize = df.getSize();
if(m_logger.isDebugEnabled())
m_logger.debug("DF: " + df.getId() + " cache-file: " + df.getDfCacheFile());
if(df.getDfCacheFile() == null) {
byte[] b = Base64Util.decode(m_sbCollectChars.toString());
if(m_logger.isDebugEnabled())
m_logger.debug("DF: " + df.getId() + " orig-size: " + nSize + " new size: " + b.length);
if(b != null && nSize == 0) nSize = b.length;
df.setBodyAsData(ConvertUtils.str2data(m_sbCollectChars.toString(), "UTF-8"), true, nSize);
}
// calc digest over end tag
updateDigest(" ".getBytes());
//df.setDigestType(SignedDoc.SHA1_DIGEST_TYPE);
df.setDigest(getDigest());
//df.setDigestValue(df.getDigest());
if(m_logger.isDebugEnabled())
m_logger.debug("Digest: " + df.getId() + " - " + Base64Util.encode(df.getDigest()) + " size: " + df.getSize());
}
if(m_altDigest != null) {
//calc digest over end tag
updateAltDigest(ConvertUtils.str2data(" "));
//df.setDigestType(SignedDoc.SHA1_DIGEST_TYPE);
df.setAltDigest(getAltDigest());
//df.setDigestValue(df.getDigest());
}
m_sbCollectChars = null; // stop collecting
} catch (DigiDocException ex) {
handleSAXError(ex);
}
// this would throw away whitespace so calculate digest before it
//df.setBody(Base64Util.decode(m_sbCollectChars.toString()));
}
m_bCollectDigest = false;
}
}
//
if(tag.equals("SignedInfo")) {
if(m_nCollectMode > 0) m_nCollectMode--;
// calculate digest over the original
// XML form of SignedInfo block and save it
try {
Signature sig = getLastSignature();
SignedInfo si = sig.getSignedInfo();
String sSigInf = m_sbCollectChars.toString();
if(m_logger.isDebugEnabled())
m_logger.debug("SigInf:\n------\n" + sSigInf + "\n------\n");
//debugWriteFile("SigInfo1.xml", m_sbCollectChars.toString());
byte[] bCanSI = null;
if(m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)) {
bCanSI = sSigInf.getBytes();
} else {
CanonicalizationFactory canFac = ConfigManager.instance().getCanonicalizationFactory();
if(si.getCanonicalizationMethod().equals(SignedDoc.CANONICALIZATION_METHOD_2010_10_EXC))
bCanSI = canFac.canonicalize(ConvertUtils.str2data(sSigInf, "UTF-8"), SignedDoc.CANONICALIZATION_METHOD_2010_10_EXC);
else
bCanSI = canFac.canonicalize(ConvertUtils.str2data(sSigInf, "UTF-8"), SignedDoc.CANONICALIZATION_METHOD_20010315);
}
si.setOrigDigest(SignedDoc.digestOfType(bCanSI,
(m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC) ?
SignedDoc.SHA256_DIGEST_TYPE : SignedDoc.SHA1_DIGEST_TYPE)));
if(m_logger.isDebugEnabled())
m_logger.debug("SigInf:\n------\n" + new String(bCanSI) + "\n------\nHASH: " + Base64Util.encode(si.getOrigDigest()));
if(m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC) /*||
m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) ||
m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)*/) {
boolean bEtsiNs = false, bAsicNs = false;
if(m_nsXadesPref != null && m_nsXadesPref.length() > 0)
bEtsiNs = true;
if(m_nsAsicPref != null && m_nsAsicPref.length() > 0)
bAsicNs = true;
if(si.getCanonicalizationMethod().equals(SignedDoc.CANONICALIZATION_METHOD_2010_10_EXC)) {
bAsicNs = false;
}
bCanSI = addNamespaces(bCanSI, true, bEtsiNs, m_nsDsPref, m_nsXadesPref, bAsicNs, m_nsAsicPref);
si.setOrigXml(bCanSI);
String sDigType = ConfigManager.sigMeth2Type(si.getSignatureMethod());
if(sDigType != null)
si.setOrigDigest(SignedDoc.digestOfType(bCanSI, sDigType));
else
throw new DigiDocException(DigiDocException.ERR_SIGNATURE_METHOD, "Invalid signature method: " + si.getSignatureMethod(), null);
if(m_logger.isDebugEnabled())
m_logger.debug("\nHASH: " + Base64Util.encode(si.getOrigDigest()));
}
m_sbCollectChars = null; // stop collecting
//debugWriteFile("SigInfo2.xml", si.toString());
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("SignedProperties")) {
if(m_nCollectMode > 0) m_nCollectMode--;
// calculate digest over the original
// XML form of SignedInfo block and save it
//debugWriteFile("SigProps-orig.xml", m_sbCollectChars.toString());
try {
Signature sig = getLastSignature();
SignedInfo si = sig.getSignedInfo();
SignedProperties sp = sig.getSignedProperties();
String sigProp = m_sbCollectChars.toString();
//debugWriteFile("SigProp1.xml", sigProp);
byte[] bSigProp = ConvertUtils.str2data(sigProp, "UTF-8");
byte[] bDig0 = SignedDoc.digestOfType(bSigProp, SignedDoc.SHA1_DIGEST_TYPE);
if(m_logger.isDebugEnabled())
m_logger.debug("SigProp0:\n------\n" + sigProp + "\n------" + " len: " +
sigProp.length() + " sha1 HASH0: " + Base64Util.encode(bDig0));
CanonicalizationFactory canFac = ConfigManager.instance().getCanonicalizationFactory();
byte[] bCanProp = null;
if(si.getCanonicalizationMethod().equals(SignedDoc.CANONICALIZATION_METHOD_2010_10_EXC))
bCanProp = canFac.canonicalize(bSigProp, SignedDoc.CANONICALIZATION_METHOD_2010_10_EXC);
else
bCanProp = canFac.canonicalize(bSigProp, SignedDoc.CANONICALIZATION_METHOD_20010315);
if(m_logger.isDebugEnabled())
m_logger.debug("SigProp can:\n------\n" + new String(bCanProp, "UTF-8") + "\n------" + " len: " + bCanProp.length);
if(m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC)) {
boolean bNeedDsNs = false;
String st1 = new String(bCanProp);
if(st1.indexOf("") != -1) {
bNeedDsNs = true;
}
boolean bEtsiNs = false, bAsicNs = false;
if(m_nsXadesPref != null && m_nsXadesPref.length() > 0)
bEtsiNs = true;
if(m_nsAsicPref != null && m_nsAsicPref.length() > 0)
bAsicNs = true;
if(si.getCanonicalizationMethod().equals(SignedDoc.CANONICALIZATION_METHOD_2010_10_EXC)) {
bAsicNs = false;
bNeedDsNs = false;
}
bCanProp = addNamespaces(bCanProp, bNeedDsNs, bEtsiNs, m_nsDsPref, m_nsXadesPref, bAsicNs, m_nsAsicPref);
if(si.getCanonicalizationMethod().equals(SignedDoc.CANONICALIZATION_METHOD_2010_10_EXC))
bCanProp = addNamespaceOnChildElems(bCanProp, m_nsDsPref, xmlnsDs);
Reference spRef = sig.getSignedInfo().getReferenceForSignedProperties(sp);
if(spRef != null) {
String sDigType = ConfigManager.digAlg2Type(spRef.getDigestAlgorithm());
if(sDigType != null)
sp.setOrigDigest(SignedDoc.digestOfType(bCanProp, sDigType));
if(m_logger.isDebugEnabled())
m_logger.debug("\nHASH: " + Base64Util.encode(sp.getOrigDigest()) + " REF-HASH: " + Base64Util.encode(spRef.getDigestValue()));
}
}
m_sbCollectChars = null; // stop collecting
CertID cid = sig.getCertIdOfType(CertID.CERTID_TYPE_SIGNER);
if(cid != null) {
if(cid.getId() != null)
sp.setCertId(cid.getId());
else if(!sig.getSignedDoc().getVersion().equals(SignedDoc.VERSION_1_3) &&
!m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC))
sp.setCertId(sig.getId() + "-CERTINFO");
sp.setCertSerial(cid.getSerial());
sp.setCertDigestAlgorithm(cid.getDigestAlgorithm());
if(cid.getDigestValue() != null)
sp.setCertDigestValue(cid.getDigestValue());
if(m_logger.isDebugEnabled())
m_logger.debug("CID: " + cid.getId() + " ser: " + cid.getSerial() + " alg: " + cid.getDigestAlgorithm());
}
if(m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) ||
m_doc.getFormat().equals(SignedDoc.FORMAT_SK_XML)) {
String sDigType1 = ConfigManager.digAlg2Type(sp.getCertDigestAlgorithm());
if(sDigType1 != null)
sp.setOrigDigest(SignedDoc.digestOfType(bCanProp, sDigType1));
if(m_logger.isDebugEnabled())
m_logger.debug("SigProp2:\n------\n" + new String(bCanProp) + "\n------\n" +
" len: " + bCanProp.length + " digtype: " + sDigType1 + " HASH: " + Base64Util.encode(sp.getOrigDigest()));
}
} catch (DigiDocException ex) {
handleSAXError(ex);
} catch(UnsupportedEncodingException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("SignatureValue")) {
if(m_nCollectMode > 0) m_nCollectMode--;
m_strSigValTs = m_sbCollectChars.toString();
m_sbCollectChars = null; // stop collecting
}
//
if(tag.equals("CompleteRevocationRefs")) {
if(m_nCollectMode > 0) m_nCollectMode--;
if(m_sbCollectChars != null)
m_strSigAndRefsTs = m_strSigValTs + m_sbCollectChars.toString();
m_sbCollectChars = null; // stop collecting
}
//
if(tag.equals("Signature")) {
if (m_nCollectMode == 0) {
if (m_logger.isDebugEnabled())
m_logger.debug("End collecting ");
try {
Signature sig = getLastSignature();
//if (m_logger.isDebugEnabled())
// m_logger.debug("Set sig content:\n---\n" + m_sbCollectSignature.toString() + "\n---\n");
if (m_sbCollectSignature != null && !sig.getSignedDoc().getFormat().equals(SignedDoc.FORMAT_BDOC)) {
sig.setOrigContent(ConvertUtils.str2data(m_sbCollectSignature.toString(), "UTF-8"));
//if (m_logger.isDebugEnabled())
// m_logger.debug("SIG orig content set: " + sig.getId() + " len: " + ((sig.getOrigContent() == null) ? 0 : sig.getOrigContent().length));
//debugWriteFile("SIG-" + sig.getId() + ".txt", m_sbCollectSignature.toString());
m_sbCollectSignature = null; // reset collecting
}
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
}
//
if(tag.equals("XAdESSignatures")) {
if (m_nCollectMode == 0) {
if (m_logger.isDebugEnabled())
m_logger.debug("End collecting ");
try {
Signature sig = getLastSignature();
//if (m_logger.isDebugEnabled())
// m_logger.debug("Set sig content:\n---\n" + m_sbCollectSignature.toString() + "\n---\n");
if (m_sbCollectSignature != null) {
sig.setOrigContent(ConvertUtils.str2data(m_sbCollectSignature.toString(), "UTF-8"));
//if (m_logger.isDebugEnabled())
// m_logger.debug("SIG orig content set: " + sig.getId() + " len: " + ((sig.getOrigContent() == null) ? 0 : sig.getOrigContent().length));
//debugWriteFile("SIG-" + sig.getId() + ".txt", m_sbCollectSignature.toString());
m_sbCollectSignature = null; // reset collecting
}
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
}
//
if(tag.equals("SignatureTimeStamp")) {
if (m_logger.isDebugEnabled())
m_logger.debug("End collecting ");
try {
Signature sig = getLastSignature();
TimestampInfo ts = sig.getTimestampInfoOfType(TimestampInfo.TIMESTAMP_TYPE_SIGNATURE);
if(ts != null && m_strSigValTs != null) {
CanonicalizationFactory canFac = ConfigManager.instance().getCanonicalizationFactory();
byte[] bCanXml = canFac.canonicalize(ConvertUtils.str2data(m_strSigValTs, "UTF-8"),
SignedDoc.CANONICALIZATION_METHOD_20010315);
//TODO: other diges types for timestamps?
byte[] hash = SignedDoc.digest(bCanXml);
if(m_logger.isDebugEnabled())
m_logger.debug("SigValTS \n---\n" + new String(bCanXml) + "\n---\nHASH: " + Base64Util.encode(hash));
//debugWriteFile("SigProp2.xml", new String(bCanProp));
ts.setHash(hash);
}
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("SigAndRefsTimeStamp")) {
if (m_logger.isDebugEnabled())
m_logger.debug("End collecting ");
try {
Signature sig = getLastSignature();
TimestampInfo ts = sig.getTimestampInfoOfType(TimestampInfo.TIMESTAMP_TYPE_SIG_AND_REFS);
if(ts != null && m_strSigAndRefsTs != null) {
String canXml = "" + m_strSigAndRefsTs + " ";
CanonicalizationFactory canFac = ConfigManager.instance().getCanonicalizationFactory();
byte[] bCanXml = canFac.canonicalize(ConvertUtils.str2data(canXml, "UTF-8"),
SignedDoc.CANONICALIZATION_METHOD_20010315);
canXml = new String(bCanXml, "UTF-8");
canXml = canXml.substring(3, canXml.length() - 4);
//TODO: other diges types for timestamps?
byte[] hash = SignedDoc.digest(ConvertUtils.str2data(canXml, "UTF-8"));
if(m_logger.isDebugEnabled())
m_logger.debug("SigAndRefsTimeStamp \n---\n" + canXml + "\n---\n" + Base64Util.encode(hash));
//debugWriteFile("SigProp2.xml", new String(bCanProp));
ts.setHash(hash);
}
} catch (DigiDocException ex) {
handleSAXError(ex);
} catch(Exception ex) {
handleSAXError(ex);
}
}
// the following stuff is used also in
// collect mode level 1 because it can be part
// of SignedInfo or SignedProperties
if (m_nCollectMode == 1) {
//
if(tag.equals("SigningTime")) {
try {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
sp.setSigningTime(ConvertUtils.string2date(m_sbCollectItem.toString(), m_doc));
m_sbCollectItem = null; // stop collecting
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("ClaimedRole")) {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
sp.addClaimedRole(m_sbCollectItem.toString());
m_sbCollectItem = null; // stop collecting
}
//
if(tag.equals("City")) {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
SignatureProductionPlace spp = sp.getSignatureProductionPlace();
spp.setCity(m_sbCollectItem.toString());
m_sbCollectItem = null; // stop collecting
}
//
if(tag.equals("StateOrProvince")) {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
SignatureProductionPlace spp = sp.getSignatureProductionPlace();
spp.setStateOrProvince(m_sbCollectItem.toString());
m_sbCollectItem = null; // stop collecting
}
//
if(tag.equals("CountryName")) {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
SignatureProductionPlace spp = sp.getSignatureProductionPlace();
spp.setCountryName(m_sbCollectItem.toString());
m_sbCollectItem = null; // stop collecting
}
//
if(tag.equals("PostalCode")) {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
SignatureProductionPlace spp = sp.getSignatureProductionPlace();
spp.setPostalCode(m_sbCollectItem.toString());
m_sbCollectItem = null; // stop collecting
}
} // level 1
// the following is collected on any level
//
if(tag.equals("DigestValue")) {
try {
if(m_tags.search("Reference") != -1) {
Signature sig = getLastSignature();
SignedInfo si = sig.getSignedInfo();
Reference ref = si.getLastReference();
ref.setDigestValue(Base64Util.decode(m_sbCollectItem.toString()));
m_sbCollectItem = null; // stop collecting
} else if(m_tags.search("SigningCertificate") != -1) {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
sp.setCertDigestValue(Base64Util.decode(m_sbCollectItem.toString()));
CertID cid = sig.getCertIdOfType(CertID.CERTID_TYPE_SIGNER);
if(cid != null)
cid.setDigestValue(Base64Util.decode(m_sbCollectItem.toString()));
m_sbCollectItem = null; // stop collecting
} else if(m_tags.search("CompleteCertificateRefs") != -1) {
Signature sig = getLastSignature();
UnsignedProperties up = sig.getUnsignedProperties();
CompleteCertificateRefs crefs = up.getCompleteCertificateRefs();
CertID cid = crefs.getLastCertId();
if(cid != null)
cid.setDigestValue(Base64Util.decode(m_sbCollectItem.toString()));
if(m_logger.isDebugEnabled())
m_logger.debug("CertID: " + cid.getId() + " digest: " + m_sbCollectItem.toString());
m_sbCollectItem = null; // stop collecting
} else if(m_tags.search("CompleteRevocationRefs") != -1) {
Signature sig = getLastSignature();
UnsignedProperties up = sig.getUnsignedProperties();
CompleteRevocationRefs rrefs = up.getCompleteRevocationRefs();
//if(rrefs.getDigestValue() == null) // ignore sub and root ca ocsp digests
OcspRef orf = rrefs.getLastOcspRef();
orf.setDigestValue(Base64Util.decode(m_sbCollectItem.toString()));
if(m_logger.isDebugEnabled())
m_logger.debug("Revoc ref: " + m_sbCollectItem.toString());
m_sbCollectItem = null; // stop collecting
} else if(m_tags.search("SigPolicyHash") != -1) {
Signature sig = getLastSignature();
SignedProperties sp = sig.getSignedProperties();
SignaturePolicyIdentifier spi = sp.getSignaturePolicyIdentifier();
SignaturePolicyId sppi = spi.getSignaturePolicyId();
sppi.setDigestValue(Base64Util.decode(m_sbCollectItem.toString()));
if(m_logger.isDebugEnabled())
m_logger.debug("SignaturePolicyId hash: " + m_sbCollectItem.toString());
m_sbCollectItem = null; // stop collecting
}
} catch(DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("IssuerSerial") && m_doc != null
&& !m_doc.getVersion().equals(SignedDoc.VERSION_1_3)
&& !m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC)) {
try {
Signature sig = getLastSignature();
CertID cid = sig.getLastCertId();
if(m_logger.isDebugEnabled())
m_logger.debug("X509SerialNumber 0: " + m_sbCollectItem.toString());
if(cid != null)
cid.setSerial(ConvertUtils.string2bigint(m_sbCollectItem.toString()));
m_sbCollectItem = null; // stop collecting
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("X509SerialNumber") && m_doc != null
&& (m_doc.getVersion().equals(SignedDoc.VERSION_1_3)
|| m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC))) {
try {
Signature sig = getLastSignature();
CertID cid = sig.getLastCertId();
if(m_logger.isDebugEnabled())
m_logger.debug("X509SerialNumber: " + m_sbCollectItem.toString());
if(cid != null)
cid.setSerial(ConvertUtils.string2bigint(m_sbCollectItem.toString()));
if(m_logger.isDebugEnabled())
m_logger.debug("X509SerialNumber: " + cid.getSerial() + " type: " + cid.getType());
m_sbCollectItem = null; // stop collecting
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("X509IssuerName") && m_doc != null
&& (m_doc.getVersion().equals(SignedDoc.VERSION_1_3)
|| m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC))) {
try {
Signature sig = getLastSignature();
CertID cid = sig.getLastCertId();
String s = m_sbCollectItem.toString();
if(cid != null)
cid.setIssuer(s);
if(m_logger.isDebugEnabled() && cid != null)
m_logger.debug("X509IssuerName: " + s + " type: " + cid.getType() + " nr: " + cid.getSerial());
m_sbCollectItem = null; // stop collecting
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("EncapsulatedTimeStamp")) {
Signature sig = getLastSignature();
TimestampInfo ts = sig.getLastTimestampInfo();
try {
//ts.setTimeStampToken(new TimeStampToken(new CMSSignedData(Base64Util.decode(m_sbCollectItem.toString()))));
BouncyCastleTimestampFactory tfac = new BouncyCastleTimestampFactory();
ts.setTimeStampToken(tfac.readTsTok(Base64Util.decode(m_sbCollectItem.toString())));
if(m_logger.isDebugEnabled() && ts != null)
m_logger.debug("TS: " + ts.getId() + " type: " + ts.getType() + " time: " + ts.getTime() + " digest: " + Base64Util.encode(ts.getMessageImprint()));
} catch(Exception ex) {
handleSAXError(new DigiDocException(DigiDocException.ERR_TIMESTAMP_RESP, "Invalid timestamp token", ex));
}
m_sbCollectItem = null; // stop collecting
}
//
if(tag.equals("ResponderID")) {
try {
if(!m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC)) {
Signature sig = getLastSignature();
UnsignedProperties up = sig.getUnsignedProperties();
CompleteRevocationRefs rrefs = up.getCompleteRevocationRefs();
if(m_logger.isDebugEnabled())
m_logger.debug("ResponderID: " + m_sbCollectItem.toString());
OcspRef orf = rrefs.getLastOcspRef();
orf.setResponderId(m_sbCollectItem.toString());
m_sbCollectItem = null; // stop collecting
}
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("ByName")) {
try {
if(m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC)) {
Signature sig = getLastSignature();
UnsignedProperties up = sig.getUnsignedProperties();
CompleteRevocationRefs rrefs = up.getCompleteRevocationRefs();
if(m_logger.isDebugEnabled())
m_logger.debug("ResponderID by-name: " + m_sbCollectItem.toString());
OcspRef orf = rrefs.getLastOcspRef();
orf.setResponderId(m_sbCollectItem.toString());
m_sbCollectItem = null; // stop collecting
}
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("ProducedAt")) {
try {
Signature sig = getLastSignature();
UnsignedProperties up = sig.getUnsignedProperties();
CompleteRevocationRefs rrefs = up.getCompleteRevocationRefs();
OcspRef orf = rrefs.getLastOcspRef();
orf.setProducedAt(ConvertUtils.string2date(m_sbCollectItem.toString(), m_doc));
m_sbCollectItem = null; // stop collecting
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
// the following stuff is ignored in collect mode
// because it can only be the content of a higher element
//if (m_nCollectMode == 0) {
//
if(tag.equals("SignatureValue")) {
try {
Signature sig = getLastSignature();
SignatureValue sv = sig.getSignatureValue();
//debugWriteFile("SigVal.txt", m_sbCollectItem.toString());
if(m_sbCollectItem != null && m_sbCollectItem.length() > 0)
sig.setSignatureValue(Base64Util.decode(m_sbCollectItem.toString().trim()));
//sv.setValue(Base64Util.decode(m_sbCollectItem.toString().trim()));
if(m_logger.isDebugEnabled())
m_logger.debug("SIGVAL mode: " + m_nCollectMode + ":\n--\n" + (m_sbCollectItem != null ? m_sbCollectItem.toString() : "NULL") +
"\n---\n len: " + ((sv.getValue() != null) ? sv.getValue().length : 0));
m_sbCollectItem = null; // stop collecting
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("X509Certificate")) {
try {
Signature sig = getLastSignature();
CertValue cval = sig.getLastCertValue();
cval.setCert(SignedDoc.readCertificate(Base64Util.decode(m_sbCollectItem.toString())));
m_sbCollectItem = null; // stop collecting
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("EncapsulatedX509Certificate")) {
try {
Signature sig = getLastSignature();
CertValue cval = sig.getLastCertValue();
cval.setCert(SignedDoc.readCertificate(Base64Util.decode(m_sbCollectItem.toString())));
m_sbCollectItem = null; // stop collecting
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//
if(tag.equals("EncapsulatedOCSPValue")) {
try {
Signature sig = getLastSignature();
// first we have to find correct certid and certvalue types
findCertIDandCertValueTypes(sig);
UnsignedProperties up = sig.getUnsignedProperties();
Notary not = up.getLastNotary();
//if(m_logger.isDebugEnabled())
// m_logger.debug("Notary: " + not.getId() + " resp: " + m_sbCollectItem.toString());
not.setOcspResponseData(Base64Util.decode(m_sbCollectItem.toString()));
NotaryFactory notFac = ConfigManager.instance().getNotaryFactory();
notFac.parseAndVerifyResponse(sig, not);
// in 1.1 we had bad OCPS digest
if (m_doc != null && m_doc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) && m_doc.getVersion().equals(SignedDoc.VERSION_1_1)) {
CompleteRevocationRefs rrefs = up.getCompleteRevocationRefs();
OcspRef orf = rrefs.getLastOcspRef();
orf.setDigestValue(SignedDoc.digestOfType(not.getOcspResponseData(),
(m_doc.getFormat().equals(SignedDoc.FORMAT_BDOC) ?
SignedDoc.SHA256_DIGEST_TYPE : SignedDoc.SHA1_DIGEST_TYPE)));
}
m_sbCollectItem = null; // stop collecting
} catch (Exception ex) {
handleSAXError(ex);
}
}
// bdoc 2.0
//
if(tag.equals("Identifier")) {
//try {
Signature sig = getLastSignature();
if(sig != null) {
SignedProperties sp = sig.getSignedProperties();
if(sp != null) {
SignaturePolicyIdentifier spid = sp.getSignaturePolicyIdentifier();
if(spid != null) {
SignaturePolicyId spi = spid.getSignaturePolicyId();
ObjectIdentifier oi = spi.getSigPolicyId();
if(oi != null) {
Identifier id = oi.getIdentifier();
id.setUri(m_sbCollectItem.toString().trim());
if(oi.getIdentifier().getUri().equals(DigiDocGenFactory.BDOC_210_OID)) {
try {
m_doc.setVersion(SignedDoc.BDOC_VERSION_2_1);
} catch(Exception ex) {
m_logger.error("Error setting 2.1 ver: " + ex);
}
}
}
}
}
}
m_sbCollectItem = null; // stop collecting
/*} catch (DigiDocException ex) {
handleSAXError(ex);
}*/
}
//
if(tag.equals("SPURI")) {
//try {
Signature sig = getLastSignature();
if(sig != null) {
SignedProperties sp = sig.getSignedProperties();
if(sp != null) {
SignaturePolicyIdentifier spid = sp.getSignaturePolicyIdentifier();
if(spid != null) {
SignaturePolicyId spi = spid.getSignaturePolicyId();
if(spi != null)
spi.addSigPolicyQualifier(new SpUri(m_sbCollectItem.toString().trim()));
}
}
}
m_sbCollectItem = null; // stop collecting
/*} catch (DigiDocException ex) {
handleSAXError(ex);
}*/
}
//
if(tag.equals("MimeType")) {
try {
Signature sig = getLastSignature();
if(sig != null) {
SignedProperties sp = sig.getSignedProperties();
if(sp != null) {
SignedDataObjectProperties sdps = sp.getSignedDataObjectProperties();
DataObjectFormat dof = sdps.getLastDataObjectFormat();
if(dof != null) {
dof.setMimeType(m_sbCollectItem.toString());
Reference ref = sig.getSignedInfo().getReferenceForDataObjectFormat(dof);
if(ref != null) {
for(int d = 0; d < sig.getSignedDoc().countDataFiles(); d++) {
DataFile df = sig.getSignedDoc().getDataFile(d);
if(df.getFileName() != null && df.getFileName().length() > 1 &&
ref.getUri() != null && ref.getUri().length() > 1) {
// normalize uri and filename
String sFileName = df.getFileName();
if(sFileName.charAt(0) == '/')
sFileName = sFileName.substring(1);
String sUri = ref.getUri();
if(sUri.charAt(0) == '/')
sUri = sUri.substring(1);
if(sFileName.equals(sUri)) {
df.setMimeType(m_sbCollectItem.toString());
}
}
}
}
}
}
}
m_sbCollectItem = null; // stop collecting
} catch (DigiDocException ex) {
handleSAXError(ex);
}
}
//} // if(m_nCollectMode == 0)
}
/**
* SAX characters event handler
* @param buf received bytes array
* @param offset offset to the array
* @param len length of data
*/
public void characters(char buf[], int offset, int len)
throws SAXException
{
String s = new String(buf, offset, len);
// just collect the data since it could
// be on many lines and be processed in many events
if (s != null) {
if (m_sbCollectItem != null) {
m_sbCollectItem.append(s);
//if(m_logger.isDebugEnabled())
// m_logger.debug("IN:\n---\n" + s + "\n---\nCollected:\n---\n" + m_sbCollectItem.toString() + "\n---\n");
}
if (m_sbCollectChars != null) {
//m_sbCollectChars.append(s);
if(m_logger.isDebugEnabled() && m_sbCollectChars.indexOf("SignedInfo") != -1)
m_logger.debug("IN: \'" + s + "\' escaped: \'" + ConvertUtils.escapeTextNode(s) + "\'");
m_sbCollectChars.append(ConvertUtils.escapeTextNode(s));
}
if (m_sbCollectSignature != null)
m_sbCollectSignature.append(ConvertUtils.escapeTextNode(s));
if(m_digest != null && m_bCollectDigest)
updateDigest(s.getBytes());
if(m_altDigest != null && m_bCollectDigest)
updateAltDigest(s.getBytes());
try {
if(m_dfCacheOutStream != null)
m_dfCacheOutStream.write(ConvertUtils.str2data(s));
} catch(DigiDocException ex) {
handleSAXError(ex);
} catch(IOException ex) {
handleSAXError(ex);
}
}
}
}