[XML Security Suite]

How to use the XML-Signature library

Note: JSR 105 XML Digital Signature APIs are under development. Our implementation is going to follow the JSR 105, and the current API introduced in this document is going to be obsolete.

Index:
Signing
Verifying
Frequently Asked Questions

Signing

The following three steps are required to sign.

  1. Preparing a Signature DOM
  2. Creating a SignatureContext instance and setting parameters
  3. Signing with sign() method of SignatureContext

1.a. Preparing a Signature DOM with TemplateGenerator

Sample code using TemplateGenerator:

Document doc = new DocumentImpl();
TemplateGenerator siggen
    = new TemplateGenerator(doc, XSignature.SHA1,
                            Canonicalizer.W3C2,
                            SignatureMethod.DSA);
siggen.addReference(siggen.createReference("http://www.ibm.com/"));
siggen.addReference(siggen.createReference("http://www.alphaworks.ibm.com/"));
Element sigElement = siggen.getSignatureElement();
// You must append sigElement into the document before signing
// if the signature is an enveloped signature.
doc_or_an_element_in_doc.appendChild(sigElement);
  1. Creates a TemplateGenerator instance and sets parameters
    ParameterHow to set to TemplateGeneratorDescription
    factory 1st parameter of TemplateGenerator() / setDocument() a factory instance to be used to create nodes
    default digest algorithm URI 2nd parameter of TemplateGenerator() / setDefaultDigestMethod() default algorithm URI for DigestMethod elements in the signature. If you don't specify an algorithm URI to a Reference instance, this default algorithm URI is used.
    canonicalization algorithm URI 3rd parameter of TemplateGenerator() / setCanonicalizer() an algorithm URI for canonicalization of the SignedInfo element.
    signature algorithm URI 4th parameter of TemplateGenerator() / setSignatureMethod() an algorithm URI for signing the SignedInfo element.

    You have to set all parameters with a constructor or setter methods.

  2. Registers Reference instances

    To set transformations to a Reference instance, use addTransform(String algorithm), addXPathTransform(String expression), or addTransform(Element transform).

  3. Generates a DOM tree

    Call getSignatureElement(). The owner of generated element is the Document instance registered to siggen, but the element is not a child of any elements or documents.

    Element sigElement = siggen.getSignatureElement();
    // You must append sigElement into the document before signing
    // if the signature is an enveloped signature.
    doc_or_an_element_in_doc.appendChild(sigElement);
    

1.b. Preparing a Signature DOM with a template document

A template document is a complete signature document except the following points:

You can sign to a DOM tree representing a template document.

// An example for Xerces
DOMParser parser = new DOMParser();
parser.parse("URI of a template document");
DOcument doc = parser.getDocument();
Element sigElement = (A Signature element in doc);

2. Creating a SignatureContext instance and setting parameters

Create a SignatureContext instance.

SignatureContext sigContext = new SignatureContext();

Set parameters.

setEntityResolver(EntityResolver);
Specified EntityResolver instance is used to fetch detached resources. If nothing is specified, standard URLConnection class is used to fetch.
setIDResolver(IDResolver);
Specified IDResolver instance is used to get an Element instance related to an ID name that is in the URI attribute value of a Reference element. You have to provide an IDResolver if a URI attribute value contains "#ID-name".
setResourceShower(ResourceShower);
ResourceShower.showSignedResource() is called before a digest value of each resource is calculated. With ResourceShower, applications can inform a user what is going to be signed.
setAlgorithmFactory(AlgorithmFactory);
...
setNullURIHandler(NullURIHandler);
...

3. Signing with sign() method of SignatureContext

If the Signature DOM has no KeyInfo element, call KeyInfo.insertTo().

Then, prepare a key used to sign and call SignatureContext.sign(Element, Key). The key is a private key if the signature uses a public/private key algorithm such as DSS, RSA.

X509Certificate cert = (Prepare a certificate);
KeyInfo keyInfo = new KeyInfo();
keyInfo.setKeyValue(cert.getPublicKey());
KeyInfo.X509Data x5data = new X509Data();
x5data.setCertificate(cert);
x5data.setParameters(cert, true, true, true);
keyInfo.setX509Data(new KeyInfo.X509Data[] { x5data });
keyInfo.insertTo(sigElement);
Key key = (Prepare a private key or a symmetric key)
sigContext.sign(sigElement, key);

Verifying

Create a SignatureContext instance and set parameters. See 2.

Prepare a key that is a public key or a symmetric key, and call SigantureContext.verify(Element, Key)

Preparing a key

If you'd like to get a key from the KeyInfo element in the signature, create a KeyInfo instance and get a key from the instance.
Element keyInfoElement = KeyInfo.searchForKeyInfo(signature);
if (keyInfoElement != null) {
    KeyInfo keyInfo = new KeyInfo(keyInfoElement);
    // If you want to use a key in the KeyValue element:
    key = keyInfo.getKeyValue();
    // You can also get keys from X509 certificates.
    // See xss4j/samples/dsig/VerifyGUI.java.
}

Verifying

SignatureContext sigContext = new SignatureContext();
// Sets parameters to sigContext
Validity validity = sigContext.verify(sigElement, key);

You get a Validity instance with which you can know result of verification. See the API reference of Validity.


Frequently Asked Questions

How to specify prefixes of elements in generated template?

The version of Apr 2002 introduced new methods to specify prefix, TemplateGenerator.setPrefix(String) and KeyInfo.insertTo(Element, String).

Does whitespace modification break signatures?
Does prefix rewriting break signatures?

They depend on canonicalization algorithm. XML Security Suite has three canonicalization algorithms:

All of them are sensitive to whitespace outside tags. For example, modification from

<SignedInfo><CanonicalizationMethod .../>
to
<SignedInfo>
  <CanonicalizationMethod .../>
breaks the signature. Modifications of whitespace in tags does not break.

Canonical XML (20010315) and Exclusive XML Canonicalization are sesitive to namespace prefixes though Canonical XML (20000119) are not.

Canonical XML (20010315) is sensitive to namespace context. If you had a signature

<Signature xmlns="...">
  :
</Signature>
and wrapped it with an element of another namespace,
<SOAP-ENV:Header xmlns:SOAP-ENV="http://www.w3.org/2001/06/soap-envelope">
<Signature xmlns="...">
  :
</Signature>
</SOAP-ENV:Header>
the signature would break. Namespace declarations outside the signature affects the result of Canonical XML (20010315). You have to strip the wrapping element before verification. With Canonical XML (20000119) and Exclusive XML Canonicalization, namespace declarations outside signatures does not affect.
 
How to sign/verify other parts of a MIME multipart message?
How to sign/verify a URI of which protocol is not supported by Java2 Runtime?

Implement an org.xml.sax.EntityResolver and set its instance to a SignatureContext instance.

XPath transform does not work as my expectation.

Many people expects an XPath transform with <XPath>/root/child</XPath> selects child elements under the root element. Actually, the transoform outputs all input nodes if the input nodes contain a node matching to /root/child, or outputs nothing if the input nodes contain no nodes matching to /root/child.

The input type of XPath transform is a node-set. Let's see an example below.

Signature-A:
  <Reference URI="URI-A">
   <Transforms>
    <Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
     <XPath>/root/child</XPath>
    </Transform>
     :
     :
URI-A:
  <?xml version="1.0"?>
  <root>
   <child>text</child>
  </root>

The input of the XPath transform of Signature-A is a node-set converted from the document pointed by URI-A. The node-set contains five nodes:

An XML-Signature processor do the following process for each node:

  1. Sets the node as the context node
  2. Evaluates the XPath expression
  3. Converts the result of the above step to boolean
  4. If the resultant boolean is true, the node remains in the output node-set; Otherwise, the node does not included in the output node-set.

In the case that the XPath expression is /root/child, this expression ignores the initial context node and always select the child element node. So the result of XPath evaluation is a node-set consisted of one node. Non-empty node-set is converted to the boolean value true. All nodes in the input node-set pass through this XPath transform.

You have to check whether the initial context node in an XPath expression matches to your demand or not. If you want to keep an element and its descendants, specify an XPath expression like "count( /root/child/descendant-or-self::node() | /root/child/descendant-or-self::*/@* | /root/child/descendant-or-self::*/namespace::*) = count(. | /root/child/descendant-or-self::node() | /root/child/descendant-or-self::*/@* | /root/child/descendant-or-self::*/namespace::*)." This expression is evaluated as true if the inital context node is child element or its descendant node.

See 6.6.3 XPath Filtering in "XML-Signature Syntax and Processing."

How to specify namespace-qualified elements in an XPath expression?

Accoding to XML Signature specification, namespace context of an XPath expression in an XPath transform is equals to the text node in which the XPath expression is written. That is to say, an XPath expression in an XPath transform can refer namespace prefixes available at its <XPath> tag.

There are two ways to specify non-declared prefxes.


TAMURA Kent
$Id: dsig-howto.html,v 1.11 2002/04/22 04:33:04 kent Exp $