Java API for XML Signature

At the time of writing this chapter (March 2003), there exists no JCP-approved Java API for XML Signature. A Java Specification Request, JSR-105 titled XML Digital Signature APIs, was accepted by JCP members as early as March 2001, but the specification work is still incomplete. This JSR is currently under community review, meaning it is being reviewed by JCP member organizations. One hopes that by the time this book comes to market, the final specification will be ready and available for download.[3]

[3] In June 2003, as this book goes to press, JSR 105 specification has become available for public review. Please visit the book's companion Web site, http://www.j2ee-security.net for more information.

Notwithstanding the lack of a standard Java API, there exist many library implementations, open source as well as proprietary, to create and verify XML Signature. Each implementation has defined its own API. We look at a couple of these implementations. But before we do that, let us analyze, at a high level, what input and output values should be expected by an operation that creates or verifies XML Signature. This would help us understand any API supporting XML Signature.

The process of signing, or creating a Signature element, in most general case, needs the following input values:

  • One or more Reference URI values identifying the data items to be signed.

  • Specific transformations to be applied on each data item.

  • A digest algorithm for each data item.

  • An algorithm to be used for canonicalizing SignedInfo element.

  • A digital signature algorithm to be applied on SignedInfo element.

  • The signing key and signer's identity information. This may be in the form of a private key and the corresponding X.509 certificate, but other formats are also possible.

  • A flag to indicate whether the generated Signature element should include the key information.

  • A flag per to-be-signed data item to indicate whether the generated Signature element should include the signed data item.

  • A location to place the generated Signature element. This could either be a location within an existing XML document or a new document of its own.

To make matters worse, some of these parameters themselves may take parameters. A number of these parameters could have default values to simplify the API. Still, the list is quite daunting. Also, even in cases where default values make sense, there has to be a way to override the defaults. And of course, it would be helpful for this API to have the same architecture as other cryptographic services, allowing implementation and algorithm independence. Recall that a cryptographic service class like java.security.Signature allows multiple providers and multiple algorithms for a given provider.

In contrast, the verification process requires a much smaller set of parameters:

  • The Singature element to be verified.

  • Verification keys, if not specified through the Signature element.

Let us now look at a couple of implementations and what mechanisms they support for XML Signature operations. For this purpose I have selected two libraries: VeriSign's TSIK (Trust Services Integration Kit) and Infomosaic's SecureXML. TSIK includes a pure Java implementation of XML Signature. SecureXML contains a Windows-based implementation with Java API. As we see, each has strengths and weaknesses. Our objective here is to gain insight into the structure and high-level features of these APIs, not to learn everything they offer.

VeriSign's TSIK

VeriSign's TSIK includes Java implementation of XML Signature and a number of other XML-based security specifications. Most notable among these are: XML Encryption, SAML (Security Assertion Markup language) and XKMS (XML Key management Specification). A useful thing about TSIK is that it is free for non-commercial use. For commercial use, you must contact VeriSign.

Download the current version of TSIK from http://www.xmltrustcenter.org. For TSIK 1.7, the version used for examples in this book, the download is a zip file named tsik-1.7.zip. Unzip this file using your favorite file compression/decompression utility or "jar xf tsik-1.7.zip" command. This should create subdirectory tsik-1.7 and place all the binaries, documentation and sample programs in the directory tree rooted at tsik-1.7.

No further setup is needed with J2SE SDK v1.4.x for using XML Signature. As we see later, a third-party JCE provider is required for XML Encryption. This is so because RSA public-key encryption is not supported by the default JCE provider in J2SE v1.4.

To explore TSIK, look into various subdirectories of the TSIK home directory, especially lib, docs and samples. You will find tsik.jar in the lib directory. This is all you need to run the examples in this chapter.

TSIK-based XML Signature examples are available under jsbookch7ex1 subdirectory of the JSTK installation directory. One of the example programs, CreateSignature.java, signs the two elements of XML data file of Listing 7-1. This source file is shown in Listing 7-6a, 7-6b and 7-6c.

Listing 7-6a. Initialization steps for creating XML Signature with TSIK
// File: src/jsbook/ch7/ex1/CreateSignature.java
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.w3c.dom.Document;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;

import com.verisign.xmlsig.Signer;
import com.verisign.xpath.XPath;

public class CreateSignature {
  public static void main(String[] args) throws Exception {
    String datafile = "book.xml";
    String sigfile = "sig.xml";
    XPath tobeSigned1 = new XPath("id('book_info')");
    XPath tobeSigned2 = new XPath("id('book_title')");
    XPath sigloc = new XPath("id('book_title')");
    System.out.println("Signing two elements of file "" +
        datafile + """);

    String keystore = "my.keystore";
    String storepass = "changeit";
    String kstype = "JCEKS";
    String alias = "mykey";
    System.out.println("Using private key in keystore "" +
        keystore + "" ...");

The class CreateSignature uses two classes from TSIK: com.verisign.xmlsig.Signer and com.verisign.xpath.XPath. The former encapsulates the signing process and the latter is a Java representation of an XPath expression.

The input parameters are hard-coded values assigned to the following variables:

  • datafile: the name of the XML file containing to-be-signed elements.

  • sigfile: the name of the file where output should be written.

  • tobeSigned1, tobeSigned2: XPath expressions to access to-be-signed elements.

  • sigloc: Location in the document, expressed as an XPath expression, where the generated Signature element should be inserted.

Besides these variables, there are input values to access a private key and the corresponding X.509 certificate from JCEKS format keystore file my.keystore. Recall our discussion of keystore and keystore formats from Chapter 3, Cryptography with Java. You can create a Java keystore with keytool utility.

Subsequent source lines read the private key and the corresponding X.509 certificate from the keystore and the XML file using the XmlUtility class that we discussed earlier in the chapter.

Listing 7-6b. Reading the private-key, certificate and input XML
FileInputStream fis = new FileInputStream(keystore);
java.security.KeyStore ks =
    java.security.KeyStore.getInstance(kstype);
ks.load(fis, storepass.toCharArray());
PrivateKey key = (PrivateKey)
    ks.getKey(alias, storepass.toCharArray());
X509Certificate cert = (X509Certificate)ks.getCertificate(alias);

Document doc = XmlUtility.readXML(datafile);

The rest of the source lines create a Signer instance, passing the XML document, private key and the certificate as arguments. The elements to be signed are added with the addReference() method. Finally, the method sign() creates the Signature element, inserting this element before the element identified by sigloc in a copy of the input document, and returns the resulting document. The original document is left untouched. To insert the Signature element in the original document, use the method signInPlace() instead of sign(). Also, if you want the Signature element to be placed after sigloc, change the second argument of the method sign() to false.

Listing 7-6c. Create the Signature element
							Signer signer = new Signer(doc, key, cert);
							signer.addReference(tobeSigned1);
							signer.addReference(tobeSigned2);
							Document signedDoc = signer.sign(sigloc, true);

    XmlUtility.writeXML(signedDoc, new FileOutputStream(sigfile));

    System.out.println();
    System.out.println("Signature Creation SUCCESSFUL!!");
    System.out.println("Signature written to file: " + sigfile);
  }
}

To compile and run this program, change your working directory to ch7ex1, make sure that tsik.jar and current directory "." are in CLASSPATH and issue the commands:

C:ch7ex1>javac CreateSignature.java
C:ch7ex1>java CreateSignature
Signing two elements of file "book.xml"
Using private key in keystore "my.keystore" ...

Signature Creation SUCCESSFUL!!
Signature written to file: sig.xml

That is it! You now have the signed document, along with the signature, in the output file sig.xml. If you look inside this file, you find that it is similar to the one shown in Listing 7-3.

Whether the generated signature is enveloping (includes signed elements), enveloped (surrounded by signed element) or detached (separate from signed elements) depends on the location specified as an argument to the sign() method. No argument implies an enveloping signature. A location outside all the signed elements implies a detached signature and a location inside a signed element implies an enveloped signature. As an exercise, you may want to modify the CreateSignature class to create each of the above-mentioned types of the Signature element.

You may have noticed that the CreateSignature class used fewer input values than we had listed earlier. Specifically, we didn't supply transformation and digest algorithms for signed elements, canonicalization and signature algorithm for the SignedInfo element, the flag to include KeyInfo and the flag to exclude signed elements from Signature element. TSIK took default values for these parameters. Can you guess these defaults by examining sig.xml or Listing 7-3?

The default values work fine most of the time and allow a simple and easy-to-use API. It is possible to change some of the default values, but in general, TSIK doesn't provide a lot of flexibility in controlling the behavior of the signing process. For example:

  • You can change the default of using normal canonicalization to exclusive canonicalization by calling the useExclusiveCanonicalizer() method on the Signer object, but cannot control this setting for independent data items and the SignedInfo individually. Also, there is no way to perform canonicalization without comments.

  • Transformations other than the default ones cannot be specified.

  • You may have noticed that the method addReference() takes an XPath object as an argument. This provides a powerful mechanism to select nodes internal to a document. However, it is not possible to specify http://... or file://... style URLs to sign any arbitrary Web page or file.

  • There is no support to plug-in your own algorithms for transformation, canonicalization, digest, and so on.

These limitations are specific to TSIK 1.7. Future releases may address some of these issues.

Let us turn our attention to the signature verification process. Class VerifySignature under the same directory as CreateSignature illustrates this process. You can find the source code of this class in Listing 7-7.

Listing 7-7. Verifying an XML Signature
// File: src/jsbook/ch7/ex1/CreateSignature.java
import org.w3c.dom.Document;
import com.verisign.xmlsig.Verifier;
import com.verisign.xpath.XPath;

public class VerifySignature {
  public static void main(String[] args) throws Exception {
    String sigfile = "sig.xml";
    System.out.println("Verifying signature in file "" +
        sigfile + """);

    Document doc = XmlUtility.readXML(sigfile);

    String ns[] = {"ds", "http://www.w3.org/2000/09/xmldsig#"};
							XPath signatureLocation = new XPath("//ds:Signature", ns);
							Verifier verifier = new Verifier(doc, signatureLocation);
							boolean isVerified = verifier.verify();

    System.out.println();
    System.out.println("Signature Verification " +
        (isVerified ? "SUCCESSFUL!!":"FAILED!!"));
  }
}

The code to verify the XML Signature is much simpler than the code for signing. The Verifier object is constructed with the document having the Signature element as constructor argument and an XPath object to locate the Signature element within the document. Method verify() performs the signature verification and returns true on success, false otherwise. The verification keys are assumed to be available in the Signature itself and need not be supplied separately.

The environment setup, compilation and execution steps for VerifySignature.java are similar to those we carried out for CreateSiganture.java:

C:ch7ex1>javac VerifySignature.java
C:ch7ex1>java VerifySignature
Verifying signature in file "sig.xml"

Signature Verification SUCCESSFUL!!

Now that you have the programs to create and verify XML signature, it would be interesting to modify the signed elements within the sig.xml file, and rerun the verification program. Is the verification process able to flag changes in the signed content by failing to verify? What about cosmetic changes permitted by canonicalization rules? Carry out these experiments and see whether you get the expected result.

For more information on TSIK APIs and additional example programs, refer to its Javadoc documentation and the sample programs bundled with TSIK distribution.

Infomosaic's SecureXML

Infomosaic Corporation, a San Jose-based startup developing digital signature technology products, has a MS Windows-based desktop software product, SecureSign, to digitally sign documents and a library, known as SecureXML, for developers to incorporate this technology in their software. Though the library itself is developed in C/C++ and is designed to work on MS Windows platforms only, it exposes APIs in a number of languages, including Java. An interesting aspect of this library is that it takes a template file, specifying the structure of the Signature element minus the DigestValue, SignatureValue and a few other elements, as input. This approach makes specification of a wide variety of input parameters relatively painless for certain kinds of applications. Tight integration with MS Windows also allows it to access the certificates stored in the Windows certificate store, the same one that is accessed by MS Outlook, MS IE and other Windows applications, with significant ease.

You can download SecureXML with a 30 day evaluation license from Infomosaic's Web site at http://www.infomosaic.net. Alternatively, you could use the license key given in Appendix E for 90-day evaluation. Going through the installation wizard and selecting the default installation directory will install SecureXML under the directory c:Program FilesInfomosaicSecureXML. The license file SecureXMLLicense.xml, which contains the expiry date and list of enabled features, is an XML Signature compliant digitally signed document and is used to enforce the expiry date and the enabled features. This is an innovative use of the digital signature where this technology itself is used to make sure that the license and expiry details cannot be tampered with. To activate SecureXML, simply copy the license file to the SecureXML installation directory.

Subdirectory srcjsbookch7ex2 of JSTK installation directory has programs CreateSignature.java and VerifySignature.java that use SecureXML APIs to create and verify XML Signature. Let us look at these source files in Listing 7-8.

Listing 7-8. XML Signature creation with Infomosaic's SecureXML
// File: srcjsbookch7ex2CreateSignature.java
import infomosaic.securexml.Signature;

public class CreateSignature{
  public static void main(String[] unused){
  String outfile = "sig.xml";
  Signature sig = new Signature();
  sig.selectActiveCertificate();
  String fileData = sig.readAll("book.tmpl");
							String outFileData = sig.signXMLStr(fileData, "Sig");
							sig.saveXMLStr(outFileData, outfile);

  System.out.println("Signed XMl document saved in file: " + outfile);
  }
}

As you can see, the Signature class takes minimal input—the name of the template file and the ID attribute of the Signature element in the template file. The signing keys and the corresponding certificate is retrieved from the MS Windows certificate store through the selectActiveCertificate() method. This method prompts the user to select a certificate, showing a list of all the available certificates associated with private keys. Although the idea of letting a library function interact with a user doesn't sound appealing, it does simplify the program and gives more control to the user for desktop-based applications. For uses other than in a desktop application, the SecureXML API supports other non-interactive ways of accessing the private key and the certificate.

Here is what the template file for signing the two elements of the XML file of Listing 7-1, looks like.

<?xml version="1.0"?>

<bk:book id="j2ee_sec" xmlns:bk="http://www.pankaj-k.net/schemas/book">
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="Sig">
  <SignedInfo>
  <Reference URI="#book_info">
  </Reference>
  <Reference URI="#book_title">
  </Reference>
  </SignedInfo>
  </Signature>
... same as in Listing 7-1. skipped. ...
</bk:book>

This mechanism of specifying the input values is quite convenient, especially if you want to sign multiple documents and specify different transforms and/or digest methods for each of the signed documents. It is kind of WYSWYG (What You See is What You Get)!

To compile the program, make sure that the full pathnames of securexml.jar and jacob.jar, two jar files included in the SecureXML download, are in the CLASSPATH and jacob.dll, another component of the SecureXMl download, is in PATH. All these jar and dll files can be found in the main SecureXML installation directory.

C:ch7ex2>set SXDIR=C:Program FilesInfomosaicSecureXML
C:ch7ex2>set CLASSPATH=.;%SXDIR%securexml.jar;%SXDIR%jacob.jar
C:ch7ex2>set PATH=%SXDIR%jacob.dll;%PATH%
						

Compiling and running the CreateSignature.java is quite straightforward.

C:ch7ex2>javac CreateSignature.java
C:ch7ex2>java CreateSignature
Signed XMl document saved in file: sig.xml

The verification program is on expected lines, as shown in Listing 7-9.

Listing 7-9. XML Signature verification with SecureXML
// File: srcjsbookch7ex2VerifySignature.java
import infomosaic.securexml.Signature;

public class VerifySignature{
  public static void main(String[] unused){
    Signature sig = new Signature();
							int result =  sig.verify("sig.xml");

    System.out.println("Signature verification " +
        (result == 0 ? "FAILED!!" : "SUCCESSFUL!!"));
  }
}

You can compile and run this program in exactly the same way as the earlier SecureXML program for creating the Signature element..

C:ch7ex2>javac VerifySignature.java
C:ch7ex2>java VerifySignature
Signature verification SUCCESSFUL!!

You are encouraged to try different combinations of input values in the template file.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.57.43