XAdES includes several time-stamp token containers, namely the IndividualDataObjectsTimeStamp and AllDataObjectsTimeStamp properties. Time-stamps are applied over the digest of an input that is property-dependant. For instance, for the AllDataObjectsTimeStamp the input is the concatenation of the octet-streams resulting from processing each XML-DSIG Reference, in order of appearance.
In the beginning of my project I was (you’ll understand soon why I was) using the Java XML Signatures API (with the reference implementation), since it wouldn’t add any external dependencies to the library. Thus, when implementing the time-stamp properties over data object references, my first thought was: “the Reference interface should supply the referenced data after all the transforms are applied!”. And it does, through the getDigestInputStream method, which returns an InputStream representing the content to be digested as part of the Reference generation/validation process.
Everything looked good until that method actually returned null. The scenario was something like this (the operation order is what’s relevant):
XMLSignatureFactory xmlSigFact = XMLSignatureFactory.getInstance();
Reference ref = xmlSigFact.newReference("#root", …);
InputStream data = ref.getDigestInputStream(); // null
XMLSignature signature = xmlSigFact.newXMLSignature(…);
And then I read the documentation again: “returns an input stream containing the pre-digested input, or
null if reference caching is not enabled or this reference has not been generated or validated”. Since the API is implementation-independent, one doesn’t have direct control of Reference generation. In this case, I’m using the Reference before creating the signature, so it isn’t generated yet. Actually, since the Reference in the example above is a same-document reference and the default Java XML-DSIG implementation is DOM-based, what is really needed is for the Reference to be marshaled, because the getHere method is used during dereferencing. This is done internally during the signature generation, hence being out of our control. The problem is that the properties that need the data are signed properties, meaning they have to be created before the signature to also be signed!
I needed to try all the options so I came with another hypothesis: explicitly dereference the Reference:
This was a last resort, doomed right after I thought of it; naturally, it also failed because the Reference isn’t marshaled. Bottom line is I couldn’t find a way to do this!
I ended up switching to Apache XML Security, which makes the needed data available. The drawback is that I’m not using the standard API and I add an external dependency. On the other hand, I get better API to handle the dereferenced data and some useful services, such as direct canonicalization of DOM (sub)trees. If anyone has a solution, please tell me about it!
The final project on my Master’s degree consists of implementing a Java library for XML Advanced Electronic Signatures (XAdES) services, which I named XAdES4j. XAdES defines XML formats for advanced electronic signatures that remain valid over long periods (even if repudiation is attempted), are compliant with the European Directive on electronic signatures (1999/93/EC) and incorporate additional qualifying information. XAdES builds on XML Digital Signatures (XML-DSIG) which specifies XML syntax and processing rules for creating, representing and verifying basic digital signatures over a set of resources (XML or not).
There are multiple implementations of XML-DSIG, namely the one bundled with the Java platform and the one in Apache XML Security. However, XAdES is not supported in the platform and solid/complete/public implementations are hard to find. My goal is to build on an existing XML-DSIG implementation and provide a library for producing and verifying XAdES signatures. The project is already at a late stage and I’m aiming at publishing it on an online project hosting system soon enough.
During the analysis of the specifications and the existing libraries I wrote the documents below. While the project isn’t published I’ll keep posting some aspects I run into during the implementation. Actually, the previous post was already one of those.
EDIT: XAdES4j is now online at Google Code!