Download
FAQ History |
API
Search Feedback |
XML Digital Signature API Examples
The following sections describe two examples that show how to use the XML Digital Signature API:
To run the sample applications using the supplied Ant
build.xml
files, issue the following commands after you installed Java WSDP:For Solaris/Linux:
For Windows 2000/XP:
validate Example
You can find the code shown in this section in the
Validate.java
file in the<
JWSDP_HOME
>/xmldsig/samples/validate
directory. The file on which it operates,envelopedSignature.xml
, is in the same directory.If you are behind a firewall and use an HTTP proxy server, you will need to modify the
build.properties
file before you can run this example.To run the example, execute the following command from the
<
JWSDP_HOME
>/xmldsig/samples/validate
directory:The sample program will validate the signature in the file
envelopedSignature.xml
in the current working directory. To validate a different signature, run the following command:where
"signature.xml"
is the pathname of the file.Validating an XML Signature
This example shows you how to validate an XML Signature using the JSR 105 API. The example uses DOM (the Document Object Model) to parse an XML document containing a Signature element and a JSR 105 DOM implementation to validate the signature.
Instantiating the Document that Contains the Signature
First we use a JAXP
DocumentBuilderFactory
to parse the XML document containing the Signature. An application obtains the default implementation forDocumentBuilderFactory
by calling the following line of code:We must also make the factory namespace-aware:
Next, we use the factory to get an instance of a
DocumentBuilder
, which is used to parse the document:DocumentBuilder builder = dbf.newDocumentBuilder(); Document doc = builder.parse(new FileInputStream(argv[0]));Specifying the Signature Element to be Validated
We need to specify the
Signature
element that we want to validate, since there could be more than one in the document. We use the DOM methodDocument.getElementsByTagNameNS
, passing it the XML Signature namespace URI and the tag name of theSignature
element, as shown:NodeList nl = doc.getElementsByTagNameNS (XMLSignature.XMLNS, "Signature"); if (nl.getLength() == 0) { throw new Exception("Cannot find Signature element"); }This returns a list of all
Signature
elements in the document. In this example, there is only oneSignature
element.Creating a Validation Context
We create an
XMLValidateContext
instance containing input parameters for validating the signature. Since we are using DOM, we instantiate aDOMValidateContext
instance (a subclass ofXMLValidateContext
), and pass it two parameters, aKeyValueKeySelector
object and a reference to theSignature
element to be validated (which is the first entry of theNodeList
we generated earlier):The
KeyValueKeySelector
is explained in greater detail in Using KeySelectors.Unmarshaling the XML Signature
We extract the contents of the
Signature
element into anXMLSignature
object. This process is called unmarshalling. TheSignature
element is unmarshalled using anXMLSignatureFactory
object. An application can obtain a DOM implementation ofXMLSignatureFactory
by calling the following line of code:We then invoke the
unmarshalXMLSignature
method of the factory to unmarshal anXMLSignature
object, and pass it the validation context we created earlier:Validating the XML Signature
Now we are ready to validate the signature. We do this by invoking the
validate
method on theXMLSignature
object, and pass it the validation context as follows:The
validate
method returns "true" if the signature validates successfully according to thecore validation rules
in theW3C XML Signature Recommendation
, and false otherwise.What If the XML Signature Fails to Validate?
If the
XMLSignature.validate
method returns false, we can try to narrow down the cause of the failure. There are two phases in core XML Signature validation:Each phase must be successful for the signature to be valid. To check if the signature failed to cryptographically validate, we can check the status, as follows:
boolean sv = signature.getSignatureValue().validate(valContext); System.out.println("signature validation status: " + sv);We can also iterate over the references and check the validation status of each one, as follows:
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); }Using KeySelectors
KeySelectors
are used to find and select keys that are needed to validate an XMLSignature. Earlier, when we created aDOMValidateContext
object, we passed aKeySelector
object as the first argument:Alternatively, we could have passed a
PublicKey
as the first argument if we already knew what key is needed to validate the signature. However, we often don't know.The
KeyValueKeySelector
is a concrete implementation of the abstractKeySelector
class. TheKeyValueKeySelector
implementation tries to find an appropriate validation key using the data contained inKeyValue
elements of theKeyInfo
element of anXMLSignature
. It does not determine if the key is trusted. This is a very simpleKeySelector
implementation, designed for illustration rather than real-world usage. A more practical example of aKeySelector
is one that searches aKeyStore
for trusted keys that matchX509Data
information (for example,X509SubjectName
,X509IssuerSerial
,X509SKI
, orX509Certificate
elements) contained in aKeyInfo
.The implementation of the
KeyValueKeySelector
is as follows: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!"); } static boolean algEquals(String algURI, String algName) { if (algName.equalsIgnoreCase("DSA") && algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) { return true; } else if (algName.equalsIgnoreCase("RSA") && algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)) { return true; } else { return false; } } }genenveloped Example
The code discussed in this section is in the
GenEnveloped.java
file in the<
JWSDP_HOME
>/xmldsig/samples/genenveloped
directory. The file on which it operates,envelope.xml
, is in the same directory. It generates the fileenvelopedSignature.xml.
To compile and run this sample, execute the following command from the
<
JWSDP_HOME
>/xmldsig/samples/genenveloped
directory:The sample program will generate an enveloped signature of the document in the file
envelope.xml
and store it in the fileenvelopedSignature.xml
in the current working directory.Generating an XML Signature
This example shows you how to generate an XML Signature using the XML Digital Signature API. More specifically, the example generates an enveloped XML Signature of an XML document. An enveloped signature is a signature that is contained inside the content that it is signing. The example uses DOM (the Document Object Model) to parse the XML document to be signed and a JSR 105 DOM implementation to generate the resulting signature.
A basic knowledge of XML Signatures and their different components is helpful for understanding this section. See
http://www.w3.org/TR/xmldsig-core/
for more information.Instantiating the Document to be Signed
First, we use a JAXP
DocumentBuilderFactory
to parse the XML document that we want to sign. An application obtains the default implementation forDocumentBuilderFactory
by calling the following line of code:We must also make the factory namespace-aware:
Next, we use the factory to get an instance of a
DocumentBuilder
, which is used to parse the document:DocumentBuilder builder = dbf.newDocumentBuilder(); Document doc = builder.parse(new FileInputStream(argv[0]));Creating a Public Key Pair
We generate a public key pair. Later in the example, we will use the private key to generate the signature. We create the key pair with a
KeyPairGenerator
. In this example, we will create a DSAKeyPair
with a length of 512 bytes :KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA"); kpg.initialize(512); KeyPair kp = kpg.generateKeyPair();In practice, the private key is usually previously generated and stored in a
KeyStore
file with an associated public key certificate.Creating a Signing Context
We create an XML Digital Signature
XMLSignContext
containing input parameters for generating the signature. Since we are using DOM, we instantiate aDOMSignContext
(a subclass ofXMLSignContext
), and pass it two parameters, the private key that will be used to sign the document and the root of the document to be signed:Assembling the XML Signature
We assemble the different parts of the
Signature
element into anXMLSignature
object. These objects are all created and assembled using anXMLSignatureFactory
object. An application obtains a DOM implementation ofXMLSignatureFactory
by calling the following line of code:We then invoke various factory methods to create the different parts of the
XMLSignature
object as shown below. We create aReference
object, passing to it the following:Next, we create the
SignedInfo
object, which is the object that is actually signed, as shown below. When creating theSignedInfo
, we pass as parameters:Next, we create the optional
KeyInfo
object, which contains information that enables the recipient to find the key needed to validate the signature. In this example, we add aKeyValue
object containing the public key. To createKeyInfo
and its various subtypes, we use aKeyInfoFactory
object, which can be obtained by invoking thegetKeyInfoFactory
method of theXMLSignatureFactory
, as follows:We then use the
KeyInfoFactory
to create theKeyValue
object and add it to aKeyInfo
object:KeyValue kv = kif.newKeyValue(kp.getPublic()); KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));Finally, we create the
XMLSignature
object, passing as parameters theSignedInfo
andKeyInfo
objects that we created earlier:Notice that we haven't actually generated the signature yet; we'll do that in the next step.
Generating the XML Signature
Now we are ready to generate the signature, which we do by invoking the
sign
method on theXMLSignature
object, and pass it the signing context as follows:The resulting document now contains a signature, which has been inserted as the last child element of the root element.
Printing or Displaying the Resulting Document
You can use the following code to print the resulting signed document to a file or standard output:
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));
Download
FAQ History |
API
Search Feedback |
All of the material in The Java(TM) Web Services Tutorial is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.