NakovDocumentSigner: A System for Digitally Signing Documents in Web Applications
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
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.
Page 4 of 5