NakovDocumentSigner is an example of putting the pieces of the puzzle together. NakovDocumentSigner is a freeware, open-source framework for digitally signing documents in Java-based Web applications developed at Sofia University “St. Kliment Ohridski” by Prof. Svetlin Nakov and his team. The framework consists of the following components:
- A signed Java applet that is used to digitally sign files before uploading them to the server.
- A reference Web application that receives the signed files, along with their digital signatures, and verifies whether the calculated signature corresponds to the received file and certificate.
- A simple subsystem for certificate and certification chain verification, implemented as a part of the reference Web application.
The Signed Java Applet
The signed Java applet requires that Java Plug-In version 1.4 or later is installed on the client machine. This is necessary because the applet uses the Java Cryptography Architecture, which is unavailable in earlier versions of the Java Plug-In. The applet does not work with the standard virtual machine distributed with some versions of Internet Explorer. The applet is signed so that it can gain access to the user’s local file system and works properly only if allowed to be executed with full rights.
The applet firmly follows the steps described in the previous part of this paper about signing documents and it represents, all in all, a button that is to be embedded in the HTML form for uploading files. It takes as parameters the field name wherefrom the file to be signed is taken and the names of the fields in which the calculated signature, the digital certificate, and the full certification chain should be written.
Obtaining Digital Certificates for Test Purposes
The client is supposed to have a digital certificate and a corresponding private key saved in a PFX file and the password to access this file should be the same as the one for the private key in it. Such PFX files can usually be obtained by purchasing a certificate from a certification authority.
For test purposes, some trial certificates can be used, such as the ones that are issued to potential customers by some well-known certification authorities, such as Thawte, VeriSign, and GlobalSign. By submitting a valid e-mail address, users can, absolutely free, get a certificate for digitally signing e-mails by Thawte. This can be done in just a few minutes at the address: http://www.thawte.com/html/COMMUNITY/personal/index.html. VeriSign issues trial certificates valid within 60 days upon submission of a valid e-mail address at http://www.verisign.com/client/enrollment/index.html. GlobalSign also offers trial certificates upon a valid e-mail address submission at http://secure.globalsign.net/ but theirs have a 30 day expiration period. All three of these certification authorities issue their certificates through the Internet and, as a result, users get them directly installed in their Web browsers. To use such certificates with NakovDocumentSigner, users have to export them from their Web browsers along with their associated private keys in a .PFX or a .P12 files.
DigitalSignerApplet—The Source Code
DigitalSignerApplet is available for free download as part of the NakovDocumentSigner framework from its official Web site http://www.nakov.com/documents-signing/. It is available in two forms: as source code and as a compiled and digitally signed .JAR file.
How DigitalSignerApplet Works
The applet extracts the selected file name from the HTML form where the applet is hosted, signs the file with the private key supplied by the user, and stores the calculated signature and user’s certificate into the HTML form. This is done in several steps:
Step 1. Obtaining the Name of the File for Signing
A Few Words about the JSObject Class
The most important methods of the JSObject class are:
- getWindow()—a static method that returns an object that corresponds to the browser’s window where the Java applet is running. It is used as a starting point for further accessing the browser’s window and HTML document displayed in it.
Step 2. Reading the File for Signing
Next, the contents of the selected file for uploading file are read. If the file is freely readable, that means that the applet has enough security privileges to do its job.
Step 3. Choosing the Certificate Keystore File (.PFX File)
Next, the user is shown the dialog for choosing a PFX file and entering a password to access it. Later, this password is used twice—once to access the keystore and once to access the user’s private key in it.
Step 4. Extracting the Private Key and Certification Chain from the .PFX File
After the PFX file is selected, it is read and the private key and corresponding certification chain are extracted. The chain always begins with the user’s certificate but it is possible to consist of it only (that is, to not contain any other certificates). If the extraction of the private key and the certification chain from the PFX file is successful, the certification chain is appropriately encoded in text form to be transferred through a text field in the HTML form. Standard PkiPath encoding is used, that represents a series of ASN.1 DER-encoded certificates. The resultant certification chain is additionally encoded with Base64 to be rendered in text form.
Step 5. Signing the File
Afterwards, the signing itself takes place with the private key read from the PFX file. The digital signature thereupon obtained is encoded in text form with Base64 encoding. In the end, the text value of the certification chain extracted from the PFX file and the digital signature are written in certain fields in the HMTL form.
The fields’ names in the HTML form accessed during the signing process are taken from parameters passed to the applet. The HTML document containing the signing applet is expected to have exactly one HMTL form.
If an error occurs at any of the described steps, the user is shown an appropriate error message. Errors can be produced in lots of situations—when the file to be signed is unable to be read, when the PFX file cannot be read, when the PFX file is invalid, when the private key is missing, when the certificate is missing, when the certificate format is invalid because of an error during the signing itself, because of inability to access the file system or some field of the form, as well as in a number of other unusual situations.
The Certification Chain Starts with the User’s Certificate
Some readers can assume that the applet writes only the certification chain in the HTML form, without the certificate itself, but this is not exactly so. By specification, a certification chain always begins with the certificate it belongs to; in particular, it might even consist if it alone. Because of this, the writing of the certification chain in the HTML form means the certificate is also written as a part of the chain.
The PFX File Selection Dialog
The PFX file selection and password dialog allow users to select among PFX and P12 files only. The last-used PFX file is saved with its full path in a configuration file in the user’s home directory, so that it can be used in the next showing of the dialog.
About the Cryptographic Algorithms and APIs Used
The implementation of all used cryptographic algorithms is given by the default cryptographic services provider SunJSSE, which is also part of the JDK 1.4.
To sign files, the digital signature algorithm SHA1withRSA is used. This means that for the calculation of the document’s hash value, the SHA1 algorithm is used and for encrypting this value and obtaining or the digital signature, the RSA algorithm is used. The SHA1withRSA algorithm is accessible in the Java Cryptography Architecture (JCA) through the java.security.Signature class. The length of the RSA keys depends on the user-selected PFX file and is usually 512 or 1024 bits. Depending on the RSA key, a digital signature with the same length is produced—usually 512 or 1024 bits (64 or 128 bytes, respectively). After encoding with Base64, the signature is written in 88 or 172 text characters, respectively.
The certification chain length depends on the number of certificates that construct it and on the contents of these certificates. Usually, after Base64 encoding, the chain has a length of 200-300 to 8000-10000 text characters.
To perform access to the protected keystore (the user selected PFX file), the java.security.KeyStore class is used. The applet expects the keystore to be in PKCS#12 format and to contain only one alias, in which the user’s private key and certificate’s certification chain are stored. In particular, the certification chain might consist of one certificate only—the user’s certificate. The keystore access password is expected to coincide with the access password for the private key.
Generating a Self-Signed Certificate
For the applet to function properly, it is necessary that it be signed. For the purpose of its signing, a certificate issued by a certification authority (PFX file) can be used, as well as a self-signed certificate. We can use the generate-certificate.bat script to generate a self-signed certificate:
del DigitalSignerApplet.jks keytool -genkey -alias signFiles -keystore DigitalSignerApplet.jks -keypass !secret -dname "CN=Your Company" -storepass !secretpause
As a result, we obtain a file named DigitalSignerApplet.jks, which is a keystore that contains the generated certificate and the corresponding private key, saved under the name "signFiles" and accessible with the password "!secret". The output file format is not PFX, but JKS (Java Key Store), which is used by default by the keytool utility.
Compiling the DigitalSignerApplet
We could use the build-script.bat script to compile the applet source code, create a JAR archive, and sign it:
del *.class javac -classpath .;"%JAVA_HOME%jrelibjaws.jar" *.java del *.jar jar -cvf DigitalSignerApplet.jar *.class jarsigner -keystore DigitalSignerApplet.jks -storepass !secret -keypass !secret DigitalSignerApplet.jar signFiles pause
This sequence of commands deletes all compiled .class files, compiles all .java files that constitute the applet, packs the resulting .class files in a JAR archive, and signs the archive with the self-signed certificate (located in the keystore DigitalSignerApplet.jks), generated in the previous step. For the source file compilation, JDK 1.4 or later is required. It is expected that the JAVA_HOME environment variable has a value corresponding to the full path to the directory where JDK is installed, and also that in the current path, the bin directory of the JDK installation is present.
Testing the DigitalSignerApplet
Now, we could test the signed applet with a sample HTML document containing an appropriate HTML form and the applet itself. We have created a test form called TestSignApplet.html.
It is important to note that we are not using the obsolete <applet> tag because it has no means of telling the browser that the applet only works with JDK 1.4 or later. If we use the <applet> tag, our applet would execute on any JDK, but would not always function properly.
Running the DigitalSignerApplet
Upon opening the sample HTML document shown above, it is first checked whether there is a Java Plug-In 1.4 or later installed on the machine. If the respective version of Java Plug-In is not found, the user is redirected to the site where it could be downloaded. If the machine has Java Plug-In 1.4 installed and the user’s browser is correctly configured to use it for Java applets execution, upon loading the test HTML document, a dialog is shown that asks whether to allow the applet embedded in the loaded HTML page to execute with fill permissions. If the user consents, the applet starts normally.
The purpose of the test HTML page is to demonstrate signing files on the client machine. The example consists of a HTML form containing three fields, the signing applet, and a button that activates the signing procedure that is actually located inside the applet. The three fields are used to select a file to be sent, to write the certification chain, and to write the resulting signature, respectively. When the button is pressed, the user is presented the ability to select a PFX file and password. Afterwards, the applet signs the file with the private key from the selected PFX file. As a result of the signing, the calculated signature and the certification chain are written in the respective fields of the HTML form. Here’s how the form and PFX file selection dialog look:
After a successful signing of the selected file, the HTML form looks like the following:
The certification chain and signature fields are filled in by the applet with values encoded in a text form in Base64 format.
The Server Side of the Framework
As a part of the document signing framework NakovDocumentSigner a reference Java-based Web application is developed to fully demonstrate its capabilities. The application allows users to sign and send files and, after that, checks the digital signature and certificate of the sender.
The server-side functionality implements three functions:
- Verification of the received digital signature
- Direct verification of the received certificate
- Verification of the received certification chain in case one is present
Digital Signature Verification
Digital signature verification asserts that the received signature corresponds to the received file and certificate. Direct certificate verification determines whether the certificate can be trusted without verifying its certification chain. Verification of the certification chain, when one is available, aims to confirm the sender’s identity.
The verification of the received signature is done in the most trivial way by using the java.security.Signature class.
Direct Certificate Verification
For direct certificate verification, the reference Web application supports a set of trusted certificates and checks whether the user’s certificate is signed by one of them. Trusted certificates are stored as .CER files in a special application directory, the name of which is specified by a constant.
Certification Chain Verification
For certification chain verification of the user’s certificate, the reference application uses a set of Root certificates of trusted root certification authorities. From these certificates, a set of trust anchors that is necessary for the certification chain verification is built. Trusted Root certificates are stored as .CER files in a special application directory, the name of which is specified by a constant.
The Server-Side Architecture
The reference Web application is based on the J2EE (Java 2 Enterprise Edition) platform and the popular Web application development framework called Struts. The application consists of one Struts-based HTML form, a Struts action class to process the form, a Struts action form class to store the data from the form, a class for digital signatures and certificates, a page for processing the sent signed file, and several configuration files. The application strictly follows the programming model of the Struts framework—Model-View-Controller (MVC).
The Server Side of the NakovDocumentSigner Framework
The reference Web application’s full source code is available for free download at the NakovDocumentSigner site: http://www.nakov.com/documents-signing/.
The Struts-based File Signing and Uploading Form
The starting form of the application consists of three fields: for the filename, for the certificatem and for the signature, respectively, and also contains the signing applet and a submit button:
On the screenshot above, the signing applet looks like a button with caption “Sign selected file.” This form is produced by a JSP page, SignedFileUploadForm.jsp, that is based on the “struts-html” tag library and uses the Struts tag to send <html:file> files.
How It Works
During the data transmission from the form to the server, “multipart/form-data” encoding is used that permits the sending of files and other large data.
The signing applet is embedded within the <object> and <embed> tags. Actually, the <object> tag is recognized by Internet Explorer only and <embed> tag is recognized by all other browsers and, to make the application work properly on all machines, it is necessary that the two tags are combined.
Upon loading this page, if Java Plug-In 1.4 or later is present on the machine, a warning shows up and informs that the applet is signed and wants to proceed with full rights. In case the required Java Plug-In version is not present, the user’s browser is redirected to the site from where it can be downloaded. For the normal user, this site is http://java.sun.com/products/plugin/index.html, but some browsers are capable of directly installing plug-ins (available as signed .cab files) so the Java Plug-In location for them is http://java.sun.com/products/plugin/autodl/jinstall-1_4-windows-i586.cab#Version=1,4,0,0. Note that the minimal version number of the required plug-in is encoded in the URL.
When the user permits the loaded applet to execute with full rights, it starts and can be used for signing files. On the following screenshot, the warning message produced by the Java Plug-In is shown:
Generally, it is very unsafe to trust such signed applets, but testing the signing applet it is required. In real-world situations, the applet should be signed by a valid trusted certificate purchased from some widely accepted certification authority. If the certificate used to sign the applet is valid, the exclamation marks in the warning dialog will be absent.
The Struts Action Form Class
Behind the Struts form for sending the signed file, there is a respective Struts action form SignedFileUploadActionForm.java class that is intended to store the data from the Web form.
This class is nothing more than a simple Java bean where some properties strictly corresponding to the fields from the form are defined. When the user fills in the form fields and submits it, the Struts framework automatically creates an object from this class and transfers the data received from the form into the object’s properties.
The Struts Action Class
The received data, written in the action form object, is handled by the /SignedFileUpload event that corresponds to the Struts action class SignedFileUploadAction.java.
This event puts the resulting action form object, together with the data received by the client’s browser, in the user’s session under the "signedFileUploadActionForm" key and afterwards redirects the Web application to the page that analyzes the received signed file.
The Signed File Analysis Page
The ShowSignedFileUploadResults.jsp page analyses the received file, its signature, the user’s certificate, and certification chain.
The signed file analysis page takes from the session the data sent by the user, verifies the digital signature, certificate, and certification chain, and displays information about them. These actions are done in several steps.
Step 1. Checking for Action Form Object in the Session
First, a check is made whether the action form object, containing the user-sent data, is saved in the session. If there is no such object, that would mean data has not been received and the user is informed to visit to the file signing and sending page (SignedFileUploadForm.jsp). If an action form object is present, the file name and its length are taken from it and displayed.
Step 2. Decoding the Received Certification Chain
Afterwards, the certification chain sent by the user is decoded. We already know it has been encoded in text form to be transferred through a HTML form field. We first obtain its original binary form by Base64 decoding. Then, the original X.509 certificates sequence is restored from the binary form, having in mind that encoding has been done in PkiPath format. From the decoded certification chain, the user’s certificate used in the signing is extracted. This certificate is the first one in the chain.
Step 3. Verifying the Received Signature
The received digital signature is decoded to restore its original binary form and it is verified for validity. From the client’s certificate, his public key is obtained and is used to verify whether the received signature corresponds to the received document (uploaded file). The signature in text form, as it is received, together with the result from its verification are displayed to the user.
Step 4. Verifying the Certificate Directly
The next step after confirmation that the signature received is valid is to verify the received certificate. First, the certificate information is displayed—who its owner is and what its purpose of use is. Then, the certificate is checked for validity. The check is done directly, without using the certification chain. This can be particularly useful when the certification chain is missing. Direct verification uses a set of trusted certificates, which are read from a special directory, the name of which is taken from a constant in the page. This directory must be a subdirectory of the Web application and must contain only certificate files (.CER files). If the user’s certificate is ascertained to be directly signed by one of these certificates, it is considered valid. The user is displayed the result from the direct verification.
Step 5. Verifying the Certification Chain
Then, the received certification chain verification follows. Before the verification itself starts, the chain is displayed as a sequence of certificates, each on a separate row. For each certificate, its consecutive number in the chain and information about its owner are displayed. Verification starts with loading the certificates that are to be used as trust anchors. These trusted Root certificates are available as .CER files in a special directory of the Web application that is set by a constant. The verification uses the standard classes of the Java Certification Path API to assert whether the given chain is valid.
If the chain consists of one certificate only (i.e. there is no chain), it is considered invalid because it is not possible for only one certificate to be a valid chain. If the chain consists of more than one certificate, the last one is removed and the PKIX algorithm is executed for its verification. The result from the verification is displayed and, if the chain is ascertained invalid, the user is displayed the reason for that and the consecutive number of the certificate in the chain that produced the error.
More about the Signed File Analysis Page
To read all the files in a given directory, the getResourcePaths() and getResourceAsStream() methods from the ServletContext class are used.
If some exception is raised during some of the steps of processing the received signed file, the user is displayed an error message accompanied by the full form of the raised exception. Different problem situations are possible; for example, a missing file, a missing certification chain, a missing signature, invalid certification chain or signature encoding, missing directory with trusted certificates, invalid certificate format, and so forth.
The results from all the described verifications that are done upon receiving a signed file that looks like this:
The Utility Class for Handling Signatures and Certificates
The main functionality for the signature, certificate, and certification chain verification is located in the DigitalSignatureUtils.java class.
How It Works
The class begins with methods for loading a certificate from the stream and from the file that read the trusted certificate files used for the certificates and certification chains verification. These files are expected to be in standard .CER format (ASN.1 DER-encoded). After them follows a method for loading the certification chain, presented in PkiPath format and text encoded with Base64 encoding. The class also offers functionality for digital signatures verification, using the SHA1withRSA algorithm—the same used by the signing applet. There are also methods for direct certificate verification and certification chain verification.
The direct certificate verification method expects as parameters the certificate and a set of trusted certificates, among which the issuer of the checked certificate should be found. Verification is successful if the method executes without raising an exception.
The certification chain verification method is a little more complicated. It takes as input a certification chain and a set of trusted Root certificates. Before starting the verification, thr first thing checked is whether the chain consists of two or more certificates. A chain of only one user certificate cannot be valid because it has to end with the Root certificate of some top-level certification authority, whereas it begins with the user certificate.
Verification starts with building a set of trust anchors (TrustAnchor objects) from the given trusted Root certificates. Afterwards, an object that contains the list of parameters is created for the verification algorithm. These parameters indicate that the algorithm should not use certificate revocation lists (CRLs). Using CRL lists is not applied because it is hard to implement them and requires additional efforts to extract these lists from the servers of the certification authorities that issue and distribute them.
After building the trust anchors and initializing the verification algorithm parameters, there is one more important step before the verification itself—to remove the last certificate from the chain. The PKIX algorithm used for verification has one peculiarity. It expects to be passed a certification chain that does not end with a certification authority Root certificate, but with the certificate that immediately precedes it. If the last certificate in the chain is not removed prior to the verification, it is possible that valid certification chains will be considered invalid.
After the preparation for verification, the validate() method of the CertPathValidator class is called to perform the verification. If the chain is invalid, an exception is raised in which the consecutive number of the certificate is written in the chain that caused the problem.
Just as in the applet for working with the digital signatures, certificates, and certification chains, the classes from the Java Cryptography Architecture are used and the implementation of all the cryptographic algorithms is provided by the default cryptographic services provider SunJSSE, which is a part of the JDK 1.4.
For working with Base64-encoded data in the Web application, the same Base64Utils.java class is used, as in the file signing applet.
The Web Application Deployment Descriptor
In compliance with the J2EE platform standards for the functioning of the reference Web application, the configuration file web.xml (also called the Web application deployment descriptor) is also needed.
This file contains the application’s configuration that *.do URL pattern to struts action servlet and sets the default application JSP page to /SignedFileUploadForm.jsp.
Struts Framework Configuration File
This file configures the Struts forms and Struts actions that the application uses. It also configures the forwarding actions for each form.
The Ant Build Script
The result from this script execution is the DocumentSigningDemoWebApp.war file that contains the compiled application in a form ready for execution that is in compliance with the Web application specifications of the J2EE platform.
Deploying and Running the Reference Web Application
To deploy and run the reference DocumentSigningDemoWebApp.war Web application, it is necessary that it is deployed on some J2EE server or some Java Web application server (Servlet container).
The deployment on Tomcat 4.x can be done just by copying the DocumentSigningDemoWebApp.war file into the “webapps” subdirectory of the Tomcat installation. The Tomcat server should be restarted after the initial deployment and after deployment of any changed version of the WAR archive.
Running the reference Web application can be performed by entering its URL in a Web browser. Under a standard deployment of the DocumentSigningDemoWebApp.war application on Tomcat 4.x server, this URL is: http://localhost:8080/DocumentSigningDemoWebApp/.
We performed various tests of the framework to ensure that is it compatible with different operating systems, Web browsers, and Java virtual machines. Our tests showed that NakovDocumentSigner is platform-independent and browser-independent. It runs on several operating systems and Web browsers with an installed Java Plug-In.
On the client side, we have successfully run tests in the environments of the following browsers: Internet Explorer 5.0 and 6.0, Mozilla 1.2.1 and 1.3 (for Windows and Linux), Netscape 6.1, having installed Java Plug-In 1.4.1 and 1.4.2, working on operating systems Windows 98, Windows 2000, Windows XP, and Red Hat Linux 9.0 (with the GNOME 2.0 graphical desktop).
The NakovDocumentSigner framework is a working example that illustrates one particular approach for using digital signatures by Java-based Web applications. It deals with the problems that arises in signing documents on the client machine and verifying them on the server. It demonstrates how the standard functionality available in the Java platform can be exploited to sign files in Web, verify digital signatures, certificates, and certification chains. The framework is freeware and can be used in its original or modified form for any purposes, including as a part of commercial products.
The need for informational security in Web applications is constantly rising and this inevitably leads to development and improvement of the technologies connected with it. It is very likely that future versions of the most widespread Web browsers will have built-in features for signing documents and HTML forms using the certificates installed in them, but until such features occur and become standard, NakovDocumentSigner will most probably remain one of the few complete freeware solutions in this direction.
The complete source code of the NakovDocumentSigner framework, along with instructions how to compile and use it, is available at its home site: http://www.nakov.com/documents-signing/.
In the most recent days, to increase security, some certification authorities provide their customers with smart cards instead of PFX certificate keystores. Smart cards are more secure because they cannot be duplicated and thus the private key stored in them cannot be stolen without the knowledge of their owner. It is a great idea to add support for signing documents on the Web with smart cards in DigitalSigninerApplet with the some version of NakovDocumentSigner. Due to a lack of standards for accessing smart cards’ functionality, it is very hard to make a vendor-independent solution. We hope that one day smart cards will be strongly supported in the most popular operating systems and Web browsers and there will a standard API for accessing them from standalone and Web applications.
Contributors to the project are always welcome, especially for the smart cards functionality development.
- GlobalSign Certification Practice Statement, Chapter 21, Definitions
- Introduction to Public-Key Cryptography
- How PGP Works
- Java Glossary—Certificates
- Digital Signatures: How They Work
- Java Cryptography Architecture (JCA)—API Specification & Reference
- Trail: Security in Java 2 SDK 1.2—The Java Tutorial
- Java Certification Path API Programmer’s Guide
- Java Security Evolution and Concepts, Part 5—Java CertPath API
- Java 2 Platform, Standard Edition, v 1.4.2—API Specification
- How to Sign Applets Using RSA-Signed Certificates
- NakovDocumentSigner—Digital Document Signing Framework for Java-based Web Applications
- Struts Framework
- Apache Ant
- Apache Tomcat
About the Author
Svetlin Nakov is part-time computer science lecturer in Sofia University, Bulgaria. He has over 5 years of professional software engineering and training experience and currently works as IT consultant in a leading Bulgarian software company. His areas of expertise include Java and related technologies, .NET Framework, network security, data structures and algorithms, and programming code quality. More information on his research background, skills and work experience is available from his home site