![[XML Security Suite]](xmlsec.gif)
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.
The following three steps are required to sign.
TemplateGenerator
SignatureContext instance and setting parameters
sign() method of SignatureContext
TemplateGeneratorSample 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);
TemplateGenerator instance and sets parameters
| Parameter | How to set to TemplateGenerator | Description |
|---|---|---|
| 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.
Reference instances
Reference for a detached signature
Reference ref = siggen.createReference("URI");
siggen.addReference(ref);
Reference for a enveloping signature
You have to create an Object element.
You can use the wrapWithObject() method
to create an Object element.
Suppose that you have an element to be signed and it is assigned
to a variable resElement.
If resElement's owner is not the Document
instance registered to siggen,
the wrapWithObject() creates a copy of resElement.
Otherwise, the resElement itself is going to be embedded in the signature.
An ID name of an Object element is required.
The ID name is id in the following code fragment.
You have to specify an IDResolver instance
to a SignatureContext instance.
The IDResolver instance have to know
id points resElement.
Element objectElement = siggen.wrapWithObject(resElement, id); Reference ref = siggen.createReference(objectElement); siggen.addReference(ref);
Reference for an enveloped signature
If you can point a target resource with an ID name,
call createReference() with single String parameter,
which is "#"+"ID-name".
You have to specify an IDResolver to SignatureContext.
Reference ref = siggen.createReference("#ID name");
siggen.addReference(ref);
If a target resource has no ID and you want to modify the document
with transformations, the parameter for createReference()
must be "" and you must set transformations
to the Reference.
Reference ref = siggen.createReference("");
ref.addTransform(...);
siggen.addReference(ref);
To set transformations to a Reference instance,
use addTransform(String algorithm),
addXPathTransform(String expression),
or addTransform(Element transform).
addTransform(String algorithm) for algorithms with no parameters such as
Base64,
enveloped-signature,
Canonical XML (old), and
Canonical XML (new).
Reference ref = siggen.createReference("");
ref.addTransform(Transform.ENVELOPED); // enveloped-signature
siggen.addReference(ref);
addXPathTransform(String expression) for XPath transformation.
String des = "/aaa/ccc/ddd/descendant-or-self::";
Reference ref = siggen.createReference("");
ref.addXPathTransform("count(. | "+des+"node() | "+des+"*/@* | "
+des+"*/namespace::*) = "+"count("+des+"node() | "+des
+"*/@* | "+des+"*/namespace::*)");
siggen.addReference(ref);
addTransform(Elment transform)
if you make a Transform element by yourself.
Reference ref = siggen.createReference("");
Element trans = doc.createElementNS(XSignature.XMLDSIG_NAMESPACE,
"Transform"); // *1
trans.setAttribute("Algorithm", "http://.....");
trans.appendChild(...);
ref.addTransform(trans);
siggen.addReference(ref);
*1: With TemplateGenerator,
an ancestor element of the Transform has a default namespace
declaration for XML Signature namespace by default.
So you don't have to set namespace declaration
attribute if the qualified name has no prefix.
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);
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);
SignatureContext instance and setting parametersCreate a SignatureContext instance.
SignatureContext sigContext = new SignatureContext();
Set parameters.
setEntityResolver(EntityResolver);
EntityResolver instance is used to fetch detached resources.
If nothing is specified,
standard URLConnection class is used to fetch.
setIDResolver(IDResolver);
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);
sign() method of SignatureContextIf 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);
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)
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.
}
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.
The version of Apr 2002 introduced new methods to specify prefix,
TemplateGenerator.setPrefix(String) and
KeyInfo.insertTo(Element, String).
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 .../>
<SignedInfo> <CanonicalizationMethod .../>
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>
<SOAP-ENV:Header xmlns:SOAP-ENV="http://www.w3.org/2001/06/soap-envelope"> <Signature xmlns="..."> : </Signature> </SOAP-ENV:Header>
Implement an org.xml.sax.EntityResolver and set its instance to
a SignatureContext instance.
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:
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."
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.
<XPath xmlns:order="URI"> ..... /order:bookOrder/ .... </XPath>
The prefix declarated here need not match to original prefix in the target document.
namespace-uri() and local-name().
<XPath> ..... /*[namespace-uri()="URI"
and local-name()="bookOrder"]/ .... </XPath>