xoxa 0.3.1 API

The Xoxa package is for normalising XML, and signing and verifying it using GPG signatures.

See:
          Description

Packages
uk.me.nxg.xoxa Provides facilities for signing, verifying, and before that normalising, XML
uk.me.nxg.xoxa.esis Writes out a SAX stream in a format based on the sgmls ESIS output.
uk.me.nxg.xoxa.gpg Handles the interaction with the GPG program.
uk.me.nxg.xoxa.util Various utility classes

 

The Xoxa package is for normalising XML, and signing and verifying it using GPG signatures.

The text below describes the need for a normalised form for XML, describes a normalised form which is simple to generate and is reversible, and which can be signed by GPG in a natural way.

For more details, see the paper XXX to be added.

Note: This is still beta code. Some functionality is implemented only in the C version of the code and not the Java version, or vice versa. The interface may yet change.

Normalising and signing XML

Both normalising and signing XML appear to be hard problems, given the size and complexity of the work of the W3C Signature working group, which has produced recommendations on creating signatures for XML, as well as on the necessary problem of canonicalising XML prior to signature. Normalisation (or canonicalisation) is necessary because for every XML document, there is a set of other documents with trivially different syntax, but which mean ‘the same thing’ – that is, they might use single-quotes rather than double-quotes for marking attributes, or have the attributes in a different order, or have ‘unimportant’ whitespace differences between elements, or appear in a different encoding, while still being usefully regarded as the same document.

The key problem with attempting to sign XML is that all cryptographic signature mechanisms are designed to sign a bag of bytes. XML documents are not just bags of bytes, so there's a fundamental dislocation here between what's wanted and what's available.

One solution is not to normalise at all, but instead to regard the on-disk or on-the-wire XML document as the bag of bytes to be signed. This works, but throws away the mutability of XML, which means that if you want to actually do anything with the XML other than simply admire it, and if you want to round-trip the XML into and out of a system which doesn't know about your signature, you're presented with the dilemma of either abandoning the signature, or else worrying about how to reproduce exactly the same bag of bytes when the XML is serialised at some later stage.

It is part of the point of XML that XML documents are not just bags of bytes, and that there is a well-defined distinction between important content and meaninglessly mutable syntax. XML processors and editors freely take advantage of this, and this mutability is reflected in the fact that applications typically do not operate on the bytes of a document or stream, but instead on the abstracted content of a document, as exposed via an API such as SAX, DOM, or an XSL node-set. An XML database is free to store an XML document in any way it likes, as long as it produces an equivalent document when required.

These notions have been formalised in the concept of the XML Information Set, and the much simpler SAX model (the SAX model is defined in terms of Java, but there are exactly analogous APIs in other languages, which can consequently support the same model). Viewed through a SAX lens, an XML document is a rather simple thing, which is consequently very simple to normalise, serialise and thus sign.

A simple-enough normalisation procedure

We here define a simple normalisation mechanism, which straightforwardly turns an XML document into a stream of bytes, in a well-defined, streamable and reversible way. The resulting stream can be signed by GPG in a natural way, and the signature embedded into the XML equally naturally.

The simple normalisation turns the XML:

<doc><p class='foo'>Hello</p>
  <p> there,
chum
</p>
</doc>

into the normalised form:

(doc
Aclass foo
(p
-Hello
)p
(p
- there, chum
)p
)doc

This normalised form can then be signed, and the signature reinserted into the original XML, or else included as the parsed XML is passed downstream.

This Java library provides support for the various steps involved. See guidance on using the library below.

This is a rather aggressive normalisation, meaning that it defines a large class of XML documents which are equivalent in the sense that they produce identical normalisations.

The <?signature ... ?> PI

The XML may include a processing instruction (PI) of the form <?signature ... ?>, which indicates a signature for the normalised form of the output, not including the signature PI. This PI has a ‘data’ payload consisting of a sequence of key-value pairs, where each value is enclosed in double quotes. The only keys defined so far are:

algorithm
This indicates the type of signature. The values currently defined are pgp for PGP/OpenPGP/GPG signatures (cf RFC 4880, plus keys such as sha1 (see eg RFC 3174), sha256 or md5, indicating cryptographic hashing algorithms. The actual values available are at present rather ill-defined, since the list is to some extent dependent on the algorithms available in the library support available at the time the library is defined; this may change in future versions.
content
This indicates the PGP-armoured output of a PGP/GPG signature (that is, starting with -----BEGIN PGP SIGNATURE-----), or else the cryptographic hash indicated by the algorithm attribute.
target

XXX this is not yet implemented in the Java version.

This indicates the element which is to be signed. It may have one of the values / or following::*[1], indicating respectively the whole document or the XML element immediately following the signature PI. In the absence of this attribute, the signature is taken to refer to the whole document.

The permitted attribute values are these literal strings. They are indeed syntactically XPath specifiers, but there is no implication that an arbitrary XPath may be provided here.

Using the library

You may sign and verify XML documents using the GPGSigner and GPGVerifier classes, and perform the normalisation step (for debugging purposes, for example) using the EsisHandler class. However the most usual way of using the library will be using the SigningXMLReader or MessageDigestXMLReader class. These are both implementations of the SAX XMLReader interface, which passes on SAX events and manages a <?signature?> processing instruction.

For example, consider the following XML file.

<doc>
<p att='foo'> Hello  </p>
<?signature algorithm="pgp" content="-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.19 (Darwin)

iEYEABECAAYFAlJVjmkACgkQcZAEv05sGSBJZgCeN3AJzN+Mmp8kcDgcmE14nRAP
8hAAnAl14jR5yAIJoo3edD4LaqtBiJ9+\n=KeDl
-----END PGP SIGNATURE-----
"?>
<p> there

</p></doc>

Then the following will verify the signature in the file, passing the XML content on to the MyHandler SAX handler. The verification is insensitive to changes in the whitespace or attribute quoting within the file.

XMLReader reader = SigningXMLReader.getXMLReader(null);

reader.setContentHandler(new MyHandler());
// if you don't set a content-handler,
// the reader just throws the results away,
// and lets you check the signature.

reader.parse(new org.xml.sax.InputSource(new FileReader(myXmlFile)));

GPGInformation result = SigningXMLReader.getGPGInformation(reader);

assertEquals(GPGInformation.Action.VERIFYING, result.getAction());
assertEquals(GPGInformation.KeyStatus.GOOD, result.getSignatureStatus());
assertEquals("719004BF4E6C1920", result.getSignatureKeyId());
assertEquals(GPGInformation.Validity.ULTIMATE, result.getValidity());
assertEquals(1381338729000L, result.getSignatureDate().getTime());

Author:
Norman Gray, http://nxg.me.uk


Copyright © 2015. All rights reserved.