XML Digital Signatures
Posted by mmaltiar on December 15, 2007
Introduction:
XML digital signatures are a way to digitally sign an XML document so that the recipient is able to authenticate the Integrity of document. There has been enough literature in place dealing with the theoretical aspect of explaining digital signature and how are they useful in verifying the integrity of the document, this article will focus upon implementing the same using the Java XML digital signature API provided by SUN.
Brief Description of Java Digital Signature API:
Sun Microsystems provides a standard set of Java technology APIs to sign and verify XML and binary documents. The Java Community Process (JCP) program defined these APIs as JSR 105. Sun ships these APIs with the Java Web Services Developer Pack (JWSDP), Project GlassFish, and the Java Platform, Standard Edition (Java SE), version 6.
Brief Understanding of Digital Signature Protocol:
- In order to create a digital signature, the sender first generates a small unique thumb-print of the document, called a hash or digest. Even a very minor change to the original document will cause the hash value to change.
- The hash of the document is signed or encrypted with the sender’s private key acts as a digital signature for that document and can be transmitted openly along with the document to the recipient.
- The recipient will be able to verify or decrypt the signature by taking a hash of the message and verifying it with the signature by decrypting it with senders public key that accompanied the message.
- The signature is authentic. When the receiver verifies the message with the sender’s public key, the receiver knows that the sender signed it.
- The signature cannot be forged. Only the sender knows his or her private key.
- The signature is not reusable. The signature is a function of the document and cannot be transferred to any other document.
- The signed document is unalterable. If there is any alteration to the document, the signature verification will fail at the receiver’s end because the hash value will be recomputed and will differ from the original hash value.
- The signature cannot be repudiated. The sender cannot deny previous committed actions, and the receiver does not need the sender’s help to verify the sender’s signature.
We can divide the whole process of this sample implementation roughly in two parts (A) XML Signature creation and (B) XML Signature Validation. Depending upon the needs of the implementation these two parts can be plugged together. For example there can be a web-service implementation where a client can send sensitive XML data after digitally signing it and the server can then validate it based upon the digital signature it received from the client.
(A) XML Signature creation:
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 for DocumentBuilderFactory by calling the following line of code:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
We must also make the factory namespace-aware:
dbf.setNamespaceAware(true);
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 DSA KeyPair 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 Key-Store 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 a DOMSignContext (a subclass of XMLSignContext), 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:
DOMSignContext dsc = new DOMSignContext (kp.getPrivate(), doc.getDocumentElement());
Assembling the XML Signature:
We assemble the different parts of the Signature element into an XMLSignature object. These objects are all created and assembled using an XMLSignatureFactory object. An application obtains a DOM implementation of XMLSignatureFactory by calling the following line of code:
XMLSignatureFactory fac = XMLSignatureFactory.getInstance();
We then invoke various factory methods to create the different parts of the XMLSignature object as shown below. We create a Reference object, passing to it the following:
- The URI of the object to be signed (We specify a URI of “”, which implies the root of the document.)
- The DigestMethod (we use SHA1)
- A single Transform, the enveloped Transform, which is required for enveloped signatures so that the signature itself is removed before calculating the signature value.
Reference ref = fac.newReference(“”, fac.newDigestMethod(DigestMethod.SHA1,null),Collections.singletonList(fac.newTransform(Transform.ENVELOPED,
(TransformParameterSpec) null)), null, null);
Next, we create the SignedInfo object, which is the object that is actually signed, as shown below.
When creating the SignedInfo, we pass as parameters:
- The CanonicalizationMethod (we use inclusive and preserve comments)
- The Signature Method (we use DSA)
- A list of References (in this case, only one)
The SignedInfo code is as follows:
SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod
(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
(C14NMethodParameterSpec) null),
fac.newSignatureMethod(SignatureMethod.DSA_SHA1, null),
Collections.singletonList(ref));
Next, we create the optional KeyInfo object, which contains information that enables the recipient to find the key needed to validate the signature. Here, we add a KeyValue object containing the public key. To create KeyInfo and its various subtypes, we use a KeyInfoFactory object, which can be obtained by invoking the getKeyInfoFactory method of the XMLSignature Factory, as follows:
KeyInfoFactory kif = fac.getKeyInfoFactory();
We then use the KeyInfoFactory to create the KeyValue object and add it to a KeyInfo object:
KeyValue kv = kif.newKeyValue(kp.getPublic());
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));
Finally, we create the XMLSignature object, passing as parameters the SignedInfo and KeyInfo objects that we created earlier:
XMLSignature signature = fac.newXMLSignature(si, ki);
Now we are ready to generate the signature, which we do by invoking the sign method on the XMLSignature object, and pass it the signing context as follows:
signature.sign(dsc);
The resulting document now contains a signature, which has been inserted as the last child element of the root element.
(B) XML Signature Validation:
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 for DocumentBuilderFactory by calling the following line of code:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
We must also make the factory namespace-aware:
dbf.setNamespaceAware(true);
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 method Document.getElementsByTagNameNS, passing it the XML Signature namespace URI and the tag name of the Signature element, as shown:
NodeList nl = doc.getElementsByTagNameNS
(XMLSignature.XMLNS, “Signature”);
if (nl.getLength() == 0) {
throw new Exception(“Cannot find Signature element”);
}
Creating a Validation Context:
We create an XMLValidateContext instance containing input parameters for validating the signature. Since we are using DOM, we instantiate a DOMValidateContext instance (a subclass of XMLValidateContext), and pass it two parameters, a KeyValueKeySelector object and a reference to the Signature element to be validated (which is the first entry of the NodeList we generated earlier):
DOMValidateContext valContext = new DOMValidateContext (new KeyValueKeySelector(),nl.item(0));
Unmarshaling the XML Signature:
We extract the contents of the Signature element into an XMLSignature object. This process is called unmarshalling. The Signature element is unmarshalled using an XMLSignatureFactory object. An application can obtain a DOM implementation of XMLSignatureFactory by calling the following line of code:
XMLSignatureFactory factory = XMLSignatureFactory.getInstance(“DOM”);
We then invoke the unmarshalXMLSignature method of the factory to unmarshal an XMLSignature object, and pass it the validation context we created earlier:
XMLSignature signature = factory.unmarshalXMLSignature(valContext);
Validating the XML Signature:
Now we are ready to validate the signature. We do this by invoking the validate method on the XMLSignature object, and pass it the validation context as follows:
boolean coreValidity = signature.validate(valContext);
The validate method returns “true” if the signature validates successfully according to the core validation rules in the W3C XML Signature Recommendation, and false otherwise.
Using KeySelectors:
KeySelectors are used to find and select keys that are needed to validate an XMLSignature. Earlier, when we created a DOMValidateContext object, we passed a KeySelector object as the first argument:
DOMValidateContext valContext = new DOMValidateContext(newKeyValueKeySelector(),nl.item(0));
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 abstract KeySelector class. The KeyValueKeySelector implementation tries to find an appropriate validation key using the data contained in KeyValue elements of the KeyInfo element of an XMLSignature.
Conclusion :
XML technology has become an integral part of web-based business applications, it is critical that applications meet the security requirements of data integrity, non-repudiation, and endpoint authentication. The Java XML digital signature implementation provides the infrastructure to meet these security requirements.
Mr WordPress said
Hi, this is a comment.
To delete a comment, just log in, and view the posts’ comments, there you will have the option to edit or delete them.