|
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.xmlfiles, 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.javafile in the<JWSDP_HOME>/xmldsig/samples/validatedirectory. 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.propertiesfile before you can run this example.To run the example, execute the following command from the
<JWSDP_HOME>/xmldsig/samples/validatedirectory:The sample program will validate the signature in the file
envelopedSignature.xmlin 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
DocumentBuilderFactoryto parse the XML document containing the Signature. An application obtains the default implementation forDocumentBuilderFactoryby 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
Signatureelement 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 theSignatureelement, 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
Signatureelements in the document. In this example, there is only oneSignatureelement.Creating a Validation Context
We create an
XMLValidateContextinstance containing input parameters for validating the signature. Since we are using DOM, we instantiate aDOMValidateContextinstance (a subclass ofXMLValidateContext), and pass it two parameters, aKeyValueKeySelectorobject and a reference to theSignatureelement to be validated (which is the first entry of theNodeListwe generated earlier):The
KeyValueKeySelectoris explained in greater detail in Using KeySelectors.Unmarshaling the XML Signature
We extract the contents of the
Signatureelement into anXMLSignatureobject. This process is called unmarshalling. TheSignatureelement is unmarshalled using anXMLSignatureFactoryobject. An application can obtain a DOM implementation ofXMLSignatureFactoryby calling the following line of code:We then invoke the
unmarshalXMLSignaturemethod of the factory to unmarshal anXMLSignatureobject, 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
validatemethod on theXMLSignatureobject, and pass it the validation context as follows:The
validatemethod returns "true" if the signature validates successfully according to thecore validation rulesin theW3C XML Signature Recommendation, and false otherwise.What If the XML Signature Fails to Validate?
If the
XMLSignature.validatemethod 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
KeySelectorsare used to find and select keys that are needed to validate an XMLSignature. Earlier, when we created aDOMValidateContextobject, we passed aKeySelectorobject as the first argument:Alternatively, we could have passed a
PublicKeyas the first argument if we already knew what key is needed to validate the signature. However, we often don't know.The
KeyValueKeySelectoris a concrete implementation of the abstractKeySelectorclass. TheKeyValueKeySelectorimplementation tries to find an appropriate validation key using the data contained inKeyValueelements of theKeyInfoelement of anXMLSignature. It does not determine if the key is trusted. This is a very simpleKeySelectorimplementation, designed for illustration rather than real-world usage. A more practical example of aKeySelectoris one that searches aKeyStorefor trusted keys that matchX509Datainformation (for example,X509SubjectName,X509IssuerSerial,X509SKI, orX509Certificateelements) contained in aKeyInfo.The implementation of the
KeyValueKeySelectoris 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.javafile in the<JWSDP_HOME>/xmldsig/samples/genenvelopeddirectory. 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/genenvelopeddirectory:The sample program will generate an enveloped signature of the document in the file
envelope.xmland store it in the fileenvelopedSignature.xmlin 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
DocumentBuilderFactoryto parse the XML document that we want to sign. An application obtains the default implementation forDocumentBuilderFactoryby 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 DSAKeyPairwith 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
KeyStorefile with an associated public key certificate.Creating a Signing Context
We create an XML Digital Signature
XMLSignContextcontaining 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
Signatureelement into anXMLSignatureobject. These objects are all created and assembled using anXMLSignatureFactoryobject. An application obtains a DOM implementation ofXMLSignatureFactoryby calling the following line of code:We then invoke various factory methods to create the different parts of the
XMLSignatureobject as shown below. We create aReferenceobject, passing to it the following:Next, we create the
SignedInfoobject, which is the object that is actually signed, as shown below. When creating theSignedInfo, we pass as parameters:Next, we create the optional
KeyInfoobject, which contains information that enables the recipient to find the key needed to validate the signature. In this example, we add aKeyValueobject containing the public key. To createKeyInfoand its various subtypes, we use aKeyInfoFactoryobject, which can be obtained by invoking thegetKeyInfoFactorymethod of theXMLSignatureFactory, as follows:We then use the
KeyInfoFactoryto create theKeyValueobject and add it to aKeyInfoobject:KeyValue kv = kif.newKeyValue(kp.getPublic()); KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));Finally, we create the
XMLSignatureobject, passing as parameters theSignedInfoandKeyInfoobjects 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
signmethod on theXMLSignatureobject, 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.