Java XML Digital Signature API Specification

This document describes the Java XML Digital Signature API Specification (JSR 105). The purpose of this JSR is to define a standard Java API for generating and validating XML signatures.

When this specification is final, there will be a Reference Implementation which will demonstrate the capabilities of this API and will provide an operational definition of this specification. A Technology Compatibility Kit (TCK) will also be available that will verify whether an implementation of the specification is compliant. These are required as per the Java Community Process 2.1.

The JSR 105 API is intended to target the following two types of users:

  • Java programmers who want to use the JSR 105 API to generate and validate XML signatures.

  • Java programmers who want to create a concrete implementation of the JSR 105 API and register it as a cryptographic service of a JCA provider (see The Provider Class).

Acknowledgements

The JSR 105 Expert Group:

  • Nicolas Catania, Hewlett-Packard

  • Donald E. Eastlake 3rd, Motorola

  • Christian Geuer-Pollmann, Apache Software Foundation

  • Hans Granqvist, VeriSign

  • Kazuyuki Harada, Fujitsu

  • Anthony Ho, DSTC

  • Merlin Hughes, Baltimore Technologies

  • Joyce Leung, IBM

  • Gregor Karlinger, IAIK

  • Serge Mister, Entrust Technologies

  • Takuya Mori, NEC Corporation

  • Sean Mullan, Sun Microsystems (co-specification lead)

  • Anthony Nadalin, IBM (co-specification lead)

  • Erwin van der Koogh, Apache Software Foundation

  • Chris Yeung, XML Asia

Also, special thanks to: Valerie Peng, Vincent Ryan, Sharon Liu, Chok Poh, K. Venugopal Rao., Paul Rank, Alexey Gavrilov, Bill Situ, Eric Jendrock, Andrew Fan, Manveen Kaur, Tom Amiro, Michael Mi, Dmitri Silaev, Roman Makarchuk, Vanitha Venkatraman, Arkadiy Sutchilin, and Scott Fordin from Sun Microsystems, Vishal Mahajan from Apache, and Martin Centner from IAIK.

Requirements

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

  1. W3C Recommendation, XML-Signature Syntax and Processing.

    • The API MUST allow a programmer to generate and validate XML Signatures such that all of the SHOULD and MUST requirements specified by the W3C recommendation can be satisfied.

    • The API MUST allow an implementation of the API to be created such that all of the SHOULD and MUST requirements specified by the W3C recommendation can be satisfied.

  2. An implementation SHOULD support the W3C Recommendation, XML-Signature XPath Filter Transform 2.0.

  3. An implementation SHOULD support the W3C Recommendation, Exclusive XML Canonicalization Version 1.0.

  4. DOM-independent API. The API MUST NOT have dependencies on a specific XML representation, such as DOM. It MUST be possible to create implementations of the API for different XML processing and mechanism representations, such as DOM, JDOM or dom4j.

  5. Extensible, provider-based API. It MUST be possible for a third-party to create and plug in an implementation responsible for managing and creating cryptographic and transform algorithms, dereferencing URIs, and marshalling objects to/from XML.

  6. Support for a default XML mechanism type: DOM. An implementation MUST minimally support the default mechanism type: DOM. This ensures that all implementations of JSR 105 are guaranteed a minimal level of functionality. Implementations MAY support other mechanism types.

  7. Interoperability for the default XML mechanism type: DOM. The API SHOULD ensure that applications using a DOM implementation are portable and interoperable.

  8. J2SE requirements. Implementations of this technology MAY support J2SE 1.2 or later but MUST at a minimum support version 1.4 or later of J2SE.

API Dependencies

Non-Goals

  1. Support for non-DOM implementations. While the API SHOULD allow non-DOM implementations to be created, it is beyond the scope of the first version to ensure interoperability between implementations other than DOM. Additional standard service provider types MAY be added in the future and necessary API enhancements MAY be considered for a maintenance revision of JSR 105.

  2. Support for a higher-level API. We expect that programmers MAY design high-level APIs which will be built on the JSR 105 API to hide low-level details, address common use-cases or apply profiling constraints. However, it is beyond the scope of the first version to support these requirements. A high-level API MAY be considered for a maintenance release of JSR 105.

  3. Support for user-pluggable algorithms (other than transform and canonicalization algorithms which is supported by the javax.xml.crypto.dsig.TransformService class): Allowing developers to plug in their own implementations of XML Signature algorithms without requiring them to create a complete JSR 105 implementation seems like a worthy goal but SHALL NOT be REQUIRED for this release of JSR 105. A solution we are investigating for a subsequent release of Java SE is to enhance the underlying JCA/JCE to add better support for registering, parsing and processing XML security algorithms, parameters, and key information.

Package Overview

The JSR 105 API consists of 6 packages:

The javax.xml.crypto package contains common classes that are used to perform XML cryptographic operations, such as generating an XML signature or encrypting XML data. Two notable classes in this package are the KeySelector class, the purpose of which is to allow developers to supply implementations which locate and optionally validate keys using the information contained in a KeyInfo object, and the URIDereferencer class which allows developers to create and specify their own URI dereferencing implementations.

The javax.xml.crypto.dsig package includes interfaces that represent the core elements defined in the W3C XML digital signature specification. Of primary significance is the XMLSignature class, which allows you to sign and validate an XML digital signature. Most of the XML signature structures or elements are represented by a corresponding interface (except for the KeyInfo structures, which are included in their own package, and discussed in the next paragraph). These interfaces include: SignedInfo, CanonicalizationMethod, SignatureMethod, Reference, Transform, DigestMethod, XMLObject, Manifest, SignatureProperty, and SignatureProperties. The XMLSignatureFactory class is an abstract factory that is used to create objects that implement these interfaces.

The javax.xml.crypto.dsig.keyinfo package contains interfaces that represent most of the KeyInfo structures defined in the W3C XML digital signature recommendation, including KeyInfo, KeyName, KeyValue, X509Data, X509IssuerSerial, RetrievalMethod, and PGPData. The KeyInfoFactory class is an abstract factory that is used to create objects that implement these interfaces.

The javax.xml.crypto.dsig.spec package contains interfaces and classes representing input parameters for the digest, signature, transform, or canonicalization algorithms used in the processing of XML signatures.

Finally, the javax.xml.crypto.dom and javax.xml.crypto.dsig.dom packages contains DOM-specific classes for the javax.xml.crypto and javax.xml.crypto.dsig packages, respectively. Only developers and users who are creating or using a DOM-based XMLSignatureFactory or KeyInfoFactory implementation should need to make direct use of these packages.

Service Providers

A JSR 105 cryptographic service is a concrete implementation of the abstract XMLSignatureFactory and KeyInfoFactory classes and is responsible for creating objects and algorithms that parse, generate and validate XML Signatures and KeyInfo structures. A concrete implementation of XMLSignatureFactory MUST provide support for each of the REQUIRED algorithms as specified by the W3C recommendation for XML Signatures. It MAY support other algorithms as defined by the W3C recommendation or other specifications.

JSR 105 leverages the JCA provider model (see The Provider Class) for registering and loading XMLSignatureFactory and KeyInfoFactory implementations.

Each concrete XMLSignatureFactory or KeyInfoFactory implementation supports a specific XML mechanism type that identifies the XML processing mechanism that an implementation uses internally to parse and generate XML signature and KeyInfo structures. This JSR supports one standard type: DOM. Support for new standard types (such as JDOM) MAY be added in the future.

A JSR 105 implementation SHOULD use underlying JCA engine classes, such as java.security.Signature and java.security.MessageDigest to perform cryptographic operations.

In addition to the XMLSignatureFactory and KeyInfoFactory classes, JSR 105 supports a service provider interface for transform and canonicalization algorithms. The TransformService class allows you to develop and plug in an implementation of a specific transform or canonicalization algorithm for a particular XML mechanism type. The TransformService class uses the standard JCA provider model for registering and loading implementations. Each JSR 105 implementation SHOULD use the TransformService class to find a provider that supports transform and canonicalization algorithms in XML Signatures that it is generating or validating.

DOM Mechanism Requirements

The following requirements MUST be abided by when implementing a DOM-based XMLSignatureFactory, KeyInfoFactory or TransformService in order to minimize interoperability problems:

  1. The unmarshalXMLSignature method of XMLSignatureFactory MUST support DOMValidateContext types. If the type is DOMValidateContext, it SHOULD contain an Element of type Signature. Additionally, the unmarshalXMLSignature method MAY populate the Id/Element mappings of the passed-in DOMValidateContext.

  2. The sign method of XMLSignatures produced by XMLSignatureFactory MUST support DOMSignContext types and the validate method MUST support DOMValidateContext types. This requirement also applies to the validate method of SignatureValue and the validate method of Reference.

  3. The implementation MUST support DOMStructures as the mechanism for the application to specify extensible content (any elements or mixed content).

  4. If the dereference method of user-specified URIDereferencers returns NodeSetData objects, the iterator method MUST return an iteration over objects of type org.w3c.dom.Node.

  5. URIReference objects passed to the dereference method of user-specified URIDereferencers MUST be of type DOMURIReference and XMLCryptoContext objects MUST implement DOMCryptoContext.

  6. The previous 2 requirements also apply to URIDereferencers returned by the getURIDereferencer method of XMLSignatureFactory and KeyInfoFactory.

  7. The unmarshalKeyInfo method of KeyInfoFactory MUST support DOMStructure types. If the type is DOMStructure, it SHOULD contain an Element of type KeyInfo.

  8. The transform method of Transform MUST support DOMCryptoContext context parameter types.

  9. The newtransform and newCanonicalizationMethod methods of XMLSignatureFactory MUST support DOMStructure parameter types.

  10. The init, and marshalParams methods of TransformService MUST support DOMStructure and DOMCryptoContext types.

  11. The unmarshalXMLSignature method of XMLSignatureFactory MUST support DOMStructure types. If the type is DOMStructure, it SHOULD contain an Element of type Signature.

  12. The marshal method of KeyInfo MUST support DOMStructure and DOMCryptoContext parameter types.

Note that a DOM implementation MAY internally use other XML parsing APIs other than DOM as long as it doesn't affect interoperability. For example, a DOM implementation of XMLSignatureFactory might use a SAX parser internally to canonicalize data.

Open API Issues

The following is a list of open API issues.

  1. ID attribute registration of external XML document references is not supported. Consider the following reference:

    Dereferencing the external document results in an octet stream which is subsequently converted to a NodeSet by the JSR 105 implementation. But the API does not provide a mechanism for registering ID attributes of external documents and therefore the XPath Transform implementation may be unable to identify the "foo" ID.

<Reference URI="document.xml">
  <Transforms>
    <Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
      <XPath>id("foo")</XPath>
    </Transform>
  </Transforms>
</Reference> 

Programming Examples

Examples 1-3 below demonstrate how to generate different types of simple XML Digital Signature using the JSR 105 API. Example 1 describes how to generate a detached signature using the DSA signature algorithm. Example 2 describes how to generate an enveloped signature. Example 3 describes how to generate an enveloping signature. Example 4 describes how to validate an XML Signature.

Example 11-1 1. Generating a detached XML Digital Signature

import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.security.*;
import java.util.Collections;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;

/**
 * This is a simple example of generating a Detached XML
 * Signature using the JSR 105 API. The resulting signature will look
 * like (key and signature values will be different):
 *
 * <pre><code>
 * <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
 *   <SignedInfo>
 *     <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
 *     <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha256"/>
 *     <Reference URI="http://www.w3.org/TR/xml-stylesheet">
 *       <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
 *       <DigestValue>60NvZvtdTB+7UnlLp/H24p7h4bs=</DigestValue>
 *     </Reference>
 *   </SignedInfo>
 *   <SignatureValue>
 *     DpEylhQoiUKBoKWmYfajXO7LZxiDYgVtUtCNyTgwZgoChzorA2nhkQ==
 *   </SignatureValue>
 *   <KeyInfo>
 *     <KeyValue>
 *       <DSAKeyValue>
 *         <P>
 *           rFto8uPQM6y34FLPmDh40BLJ1rVrC8VeRquuhPZ6jYNFkQuwxnu/wCvIAMhukPBL
 *           FET8bJf/b2ef+oqxZajEb+88zlZoyG8g/wMfDBHTxz+CnowLahnCCTYBp5kt7G8q
 *           UobJuvjylwj1st7V9Lsu03iXMXtbiriUjFa5gURasN8=
 *         </P>
 *         <Q>
 *           kEjAFpCe4lcUOdwphpzf+tBaUds=
 *         </Q>
 *         <G>
 *           oe14R2OtyKx+s+60O5BRNMOYpIg2TU/f15N3bsDErKOWtKXeNK9FS7dWStreDxo2
 *           SSgOonqAd4FuJ/4uva7GgNL4ULIqY7E+mW5iwJ7n/WTELh98mEocsLXkNh24HcH4
 *           BZfSCTruuzmCyjdV1KSqX/Eux04HfCWYmdxN3SQ/qqw=
 *         </G>
 *         <Y>
 *           pA5NnZvcd574WRXuOA7ZfC/7Lqt4cB0MRLWtHubtJoVOao9ib5ry4rTk0r6ddnOv
 *           AIGKktutzK3ymvKleS3DOrwZQgJ+/BDWDW8kO9R66o6rdjiSobBi/0c2V1+dkqOg
 *           jFmKz395mvCOZGhC7fqAVhHat2EjGPMfgSZyABa7+1k=
 *         </Y>
 *       </DSAKeyValue>
 *     </KeyValue>
 *   </KeyInfo>
 * </Signature>
 * </code></pre>
 */
public class GenDetached {

    //
    // Synopsis: java GenDetached [output]
    //
    // where output is the name of the file that will contain the detached
    // signature. If not specified, standard output is used.
    //
    public static void main(String[] args) throws Exception {

        // First, create a DOM XMLSignatureFactory that will be used to
        // generate the XMLSignature and marshal it to DOM.
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

        // Create a Reference to an external URI that will be digested
        // using the SHA256 digest algorithm
        Reference ref = fac.newReference("http://www.w3.org/TR/xml-stylesheet",
            fac.newDigestMethod(DigestMethod.SHA256, null));

        // Create the SignedInfo
        SignedInfo si = fac.newSignedInfo(
            fac.newCanonicalizationMethod
                (CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
                 (C14NMethodParameterSpec) null),
            fac.newSignatureMethod("http://www.w3.org/2000/09/xmldsig#dsa-sha256", null),
            Collections.singletonList(ref));

        // Create a DSA KeyPair
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(2048);
        KeyPair kp = kpg.generateKeyPair();

        // Create a KeyValue containing the DSA PublicKey that was generated
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        KeyValue kv = kif.newKeyValue(kp.getPublic());

        // Create a KeyInfo and add the KeyValue to it
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

        // Create the XMLSignature (but don't sign it yet)
        XMLSignature signature = fac.newXMLSignature(si, ki);

        // Create the Document that will hold the resulting XMLSignature
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true); // must be set
        Document doc = dbf.newDocumentBuilder().newDocument();

        // Create a DOMSignContext and set the signing Key to the DSA
        // PrivateKey and specify where the XMLSignature should be inserted
        // in the target document (in this case, the document root)
        DOMSignContext signContext = new DOMSignContext(kp.getPrivate(), doc);

        // Marshal, generate (and sign) the detached XMLSignature. The DOM
        // Document will contain the XML Signature if this method returns
        // successfully.
        signature.sign(signContext);

        // output the resulting document
        OutputStream os;
        if (args.length > 0) {
           os = new FileOutputStream(args[0]);
        } else {
           os = System.out;
        }

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
    }
}

Example 11-2 2. Generating an enveloped XML Digital Signature

import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.security.*;
import java.util.Collections;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;

/**
 * This is a simple example of generating an Enveloped XML
 * Signature using the JSR 105 API. The resulting signature will look
 * like (key and signature values will be different):
 *
 * <pre><code>
 *<Envelope xmlns="urn:envelope">
 * <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
 *   <SignedInfo>
 *     <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
 *     <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha256"/>
 *     <Reference URI="">
 *       <Transforms>
 *         <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
 *       </Transforms>
 *       <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
 *       <DigestValue>K8M/lPbKnuMDsO0Uzuj75lQtzQI=<DigestValue>
 *     </Reference>
 *   </SignedInfo>
 *   <SignatureValue>
 *     DpEylhQoiUKBoKWmYfajXO7LZxiDYgVtUtCNyTgwZgoChzorA2nhkQ==
 *   </SignatureValue>
 *   <KeyInfo>
 *     <KeyValue>
 *       <DSAKeyValue>
 *         <P>
 *           rFto8uPQM6y34FLPmDh40BLJ1rVrC8VeRquuhPZ6jYNFkQuwxnu/wCvIAMhukPBL
 *           FET8bJf/b2ef+oqxZajEb+88zlZoyG8g/wMfDBHTxz+CnowLahnCCTYBp5kt7G8q
 *           UobJuvjylwj1st7V9Lsu03iXMXtbiriUjFa5gURasN8=
 *         </P>
 *         <Q>
 *           kEjAFpCe4lcUOdwphpzf+tBaUds=
 *         </Q>
 *         <G>
 *           oe14R2OtyKx+s+60O5BRNMOYpIg2TU/f15N3bsDErKOWtKXeNK9FS7dWStreDxo2
 *           SSgOonqAd4FuJ/4uva7GgNL4ULIqY7E+mW5iwJ7n/WTELh98mEocsLXkNh24HcH4
 *           BZfSCTruuzmCyjdV1KSqX/Eux04HfCWYmdxN3SQ/qqw=
 *         </G>
 *         <Y>
 *           pA5NnZvcd574WRXuOA7ZfC/7Lqt4cB0MRLWtHubtJoVOao9ib5ry4rTk0r6ddnOv
 *           AIGKktutzK3ymvKleS3DOrwZQgJ+/BDWDW8kO9R66o6rdjiSobBi/0c2V1+dkqOg
 *           jFmKz395mvCOZGhC7fqAVhHat2EjGPMfgSZyABa7+1k=
 *         </Y>
 *       </DSAKeyValue>
 *     </KeyValue>
 *   </KeyInfo>
 * </Signature>
 *</Envelope>
 * </code></pre>
 */
public class GenEnveloped {

    //
    // Synopsis: java GenEnveloped [document] [output]
    //
    //    where "document" is the name of a file containing the XML document
    //    to be signed, and "output" is the name of the file to store the
    //    signed document. The 2nd argument is optional - if not specified,
    //    standard output will be used.
    //
    public static void main(String[] args) throws Exception {

        // Create a DOM XMLSignatureFactory that will be used to generate the
        // enveloped signature
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

        // Create a Reference to the enveloped document (in this case we are
        // signing the whole document, so a URI of "" signifies that) and
        // also specify the SHA256 digest algorithm and the ENVELOPED Transform.
        Reference ref = fac.newReference
            ("", fac.newDigestMethod(DigestMethod.SHA256, null),
             Collections.singletonList
              (fac.newTransform
                (Transform.ENVELOPED, (TransformParameterSpec) null)),
             null, null);

        // Create the SignedInfo
        SignedInfo si = fac.newSignedInfo
            (fac.newCanonicalizationMethod
             (CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
              (C14NMethodParameterSpec) null),
             fac.newSignatureMethod("http://www.w3.org/2000/09/xmldsig#dsa-sha256", null),
             Collections.singletonList(ref));

        // Create a DSA KeyPair
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(2048);
        KeyPair kp = kpg.generateKeyPair();

        // Create a KeyValue containing the DSA PublicKey that was generated
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        KeyValue kv = kif.newKeyValue(kp.getPublic());

        // Create a KeyInfo and add the KeyValue to it
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

        // Instantiate the document to be signed
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc =
            dbf.newDocumentBuilder().parse(new FileInputStream(args[0]));

        // Create a DOMSignContext and specify the DSA PrivateKey and
        // location of the resulting XMLSignature's parent element
        DOMSignContext dsc = new DOMSignContext
            (kp.getPrivate(), doc.getDocumentElement());

        // Create the XMLSignature (but don't sign it yet)
        XMLSignature signature = fac.newXMLSignature(si, ki);

        // Marshal, generate (and sign) the enveloped signature
        signature.sign(dsc);

        // output the resulting document
        OutputStream os;
        if (args.length > 1) {
           os = new FileOutputStream(args[1]);
        } else {
           os = System.out;
        }

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
    }
}

Example 11-3 3. Generating an enveloping XML Digital Signature

import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.security.*;
import java.util.Arrays;
import java.util.Collections;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 * This is a simple example of generating an Enveloping XML
 * Signature using the JSR 105 API. The signature in this case references a
 * local URI that points to an Object element.
 * The resulting signature will look like (certificate and
 * signature values will be different):
 *
 * <pre><code>
 * <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
 *   <SignedInfo>
 *     <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
 *     <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha256"/>
 *     <Reference URI="#object">
 *       <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
 *       <DigestValue>7/XTsHaBSOnJ/jXD5v0zL6VKYsk=</DigestValue>
 *     </Reference>
 *   </SignedInfo>
 *   <SignatureValue>
 *     RpMRbtMHLa0siSS+BwUpLIEmTfh/0fsld2JYQWZzCzfa5kBTz25+XA==
 *   </SignatureValue>
 *   <KeyInfo>
 *     <KeyValue>
 *       <DSAKeyValue>
 *         <P>
 *           /KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxeEu0Imbz
 *           RMqzVDZkVG9xD7nN1kuFw==
 *         </P>
 *         <Q>
 *           li7dzDacuo67Jg7mtqEm2TRuOMU=
 *         </Q>
 *         <G>
 *           Z4Rxsnqc9E7pGknFFH2xqaryRPBaQ01khpMdLRQnG541Awtx/XPaF5Bpsy4pNWMOH
 *           CBiNU0NogpsQW5QvnlMpA==
 *         </G>
 *         <Y>
 *           wbEUaCgHZXqK4qLvbdYrAc6+Do0XVcsziCJqxzn4cJJRxwc3E1xnEXHscVgr1Cql9
 *           i5fanOKQbFXzmb+bChqig==
 *         </Y>
 *       </DSAKeyValue>
 *     </KeyValue>
 *   </KeyInfo>
 *   <Object Id="object">some text</Object>
 * </Signature>
 *
 * </code></pre>
 */
public class GenEnveloping {

    //
    // Synopis: java GenEnveloping [output]
    //
    //   where "output" is the name of a file that will contain the
    //   generated signature. If not specified, standard ouput will be used.
    //
    public static void main(String[] args) throws Exception {

        // First, create the DOM XMLSignatureFactory that will be used to
        // generate the XMLSignature
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

        // Next, create a Reference to a same-document URI that is an Object
        // element and specify the SHA256 digest algorithm
        Reference ref = fac.newReference("#object",
            fac.newDigestMethod(DigestMethod.SHA256, null));

        // Next, create the referenced Object
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc = dbf.newDocumentBuilder().newDocument();
        Node text = doc.createTextNode("some text");
        XMLStructure content = new DOMStructure(text);
        XMLObject obj = fac.newXMLObject
            (Collections.singletonList(content), "object", null, null);

        // Create the SignedInfo
        SignedInfo si = fac.newSignedInfo(
            fac.newCanonicalizationMethod
                (CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
                 (C14NMethodParameterSpec) null),
            fac.newSignatureMethod("http://www.w3.org/2000/09/xmldsig#dsa-sha256", null),
            Collections.singletonList(ref));

        // Create a DSA KeyPair
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(2048);
        KeyPair kp = kpg.generateKeyPair();

        // Create a KeyValue containing the DSA PublicKey that was generated
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        KeyValue kv = kif.newKeyValue(kp.getPublic());

        // Create a KeyInfo and add the KeyValue to it
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

        // Create the XMLSignature (but don't sign it yet)
        XMLSignature signature = fac.newXMLSignature(si, ki,
            Collections.singletonList(obj), null, null);

        // Create a DOMSignContext and specify the DSA PrivateKey for signing
        // and the document location of the XMLSignature
        DOMSignContext dsc = new DOMSignContext(kp.getPrivate(), doc);

        // Lastly, generate the enveloping signature using the PrivateKey
        signature.sign(dsc);

        // output the resulting document
        OutputStream os;
        if (args.length > 0) {
           os = new FileOutputStream(args[0]);
        } else {
           os = System.out;
        }

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
    }
}

Example 11-4 4. Validating an XML Digital Signature

import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.*;
import java.io.FileInputStream;
import java.security.*;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

/**
 * This is a simple example of validating an XML
 * Signature using the JSR 105 API. It assumes the key needed to
 * validate the signature is contained in a KeyValue KeyInfo.
 */
public class Validate {

    //
    // Synopsis: java Validate [document]
    //
    //    where "document" is the name of a file containing the XML document
    //    to be validated.
    //
    public static void main(String[] args) throws Exception {

        // Instantiate the document to be validated
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc =
            dbf.newDocumentBuilder().parse(new FileInputStream(args[0]));

        // Find Signature element
        NodeList nl =
            doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
        if (nl.getLength() == 0) {
            throw new Exception("Cannot find Signature element");
        }

        // Create a DOM XMLSignatureFactory that will be used to unmarshal the
        // document containing the XMLSignature
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

        // Create a DOMValidateContext and specify a KeyValue KeySelector
        // and document context
        DOMValidateContext valContext = new DOMValidateContext
            (new KeyValueKeySelector(), nl.item(0));

        // unmarshal the XMLSignature
        XMLSignature signature = fac.unmarshalXMLSignature(valContext);

        // Validate the XMLSignature (generated above)
        boolean coreValidity = signature.validate(valContext);

        // Check core validation status
        if (coreValidity == false) {
            System.err.println("Signature failed core validation");
            boolean sv = signature.getSignatureValue().validate(valContext);
            System.out.println("signature validation status: " + sv);
            // check the validation status of each Reference
            Iterator i = signature.getSignedInfo().getReferences().iterator();
            for (int j=0; i.hasNext(); j++) {
                boolean refValid =
                    ((Reference) i.next()).validate(valContext);
                System.out.println("ref["+j+"] validity status: " + refValid);
            }
        } else {
            System.out.println("Signature passed core validation");
        }
    }

    /**
     * KeySelector which retrieves the public key out of the
     * KeyValue element and returns it.
     * NOTE: If the key algorithm doesn't match signature algorithm,
     * then the public key will be ignored.
     */
    private static class KeyValueKeySelector extends KeySelector {
        public KeySelectorResult select(KeyInfo keyInfo,
                                        KeySelector.Purpose purpose,
                                        AlgorithmMethod method,
                                        XMLCryptoContext context)
            throws KeySelectorException {
            if (keyInfo == null) {
                throw new KeySelectorException("Null KeyInfo object!");
            }
            SignatureMethod sm = (SignatureMethod) method;
            List list = keyInfo.getContent();

            for (int i = 0; i < list.size(); i++) {
                XMLStructure xmlStructure = (XMLStructure) list.get(i);
                if (xmlStructure instanceof KeyValue) {
                    PublicKey pk = null;
                    try {
                        pk = ((KeyValue)xmlStructure).getPublicKey();
                    } catch (KeyException ke) {
                        throw new KeySelectorException(ke);
                    }
                    // make sure algorithm is compatible with method
                    if (algEquals(sm.getAlgorithm(), pk.getAlgorithm())) {
                        return new SimpleKeySelectorResult(pk);
                    }
                }
            }
            throw new KeySelectorException("No KeyValue element found!");
        }

        //@@@FIXME: this should also work for key types other than DSA/RSA
        static boolean algEquals(String algURI, String algName) {
            if (algName.equalsIgnoreCase("DSA") &&
                algURI.equalsIgnoreCase("http://www.w3.org/2000/09/xmldsig#dsa-sha256")) {
                return true;
            } else if (algName.equalsIgnoreCase("RSA") &&
                       algURI.equalsIgnoreCase("http://www.w3.org/2000/09/xmldsig#dsa-sha256")) {
                return true;
            } else {
                return false;
            }
        }
    }

    private static class SimpleKeySelectorResult implements KeySelectorResult {
        private PublicKey pk;
        SimpleKeySelectorResult(PublicKey pk) {
            this.pk = pk;
        }

        public Key getKey() { return pk; }
    }
}