org.faceless.pdf2
Class FormSignature

java.lang.Object
  extended byorg.faceless.pdf2.PDFObject
      extended byorg.faceless.pdf2.PDFMap
          extended byorg.faceless.pdf2.FormElement
              extended byorg.faceless.pdf2.FormSignature
All Implemented Interfaces:
Cloneable

public final class FormSignature
extends FormElement

This class represents a public key "Digital Signature" which can be used to sign a PDF document. Signatures from existing documents can be verified and new signatures can be added.

Signatures may be applied and verified using either the full version of Adobe Acrobat™ or Adobe Approval, but not the free Acrobat Reader. Acrobat comes with a "digital signature handler" called the Self-Sign handler, which allows a limited form of verification, and additional handlers are available as plugins for Acrobat. Several are supplied on the Acrobat CD.

Since version 2.0, the framework is in place to allow custom signature handlers to be written. This means that with the right SignatureHandler, the library can be used to create or verify any type of digital signature. The library is distributed with three handlers out-of-the-box, which are returned by the HANDLER_VERISIGN, HANDLER_SELFSIGN and HANDLER_ACROBATSIX factories. All of these handlers use the standard KeyStore class supplied with J2SE1.3, and do not necessarily need any third party libraries to work.

An important point to remember is that the signatures on an existing document are not preserved if that document is loaded then saved. This is because the document structure is irreversably changed by this process, which renders the signature invalid. Another key point is that in the current version of this library only a single STATE_PENDING signature can be applied to a PDF - ie. when saving a document, only a single signature may be applied.

So how do you use this class? The following examples show how to sign and verify documents using the supplied signature handlers.

Verifying existing signatures

To verify a document has been signed and not altered since signing, and to be sure of the signatory, three steps are required. These three steps apply to any type of digital signature, not just PKI (Pulbic Key Infrastuction) signatures, but for these examples we'll focus on the PKI signatures only.

  1. You must verify that content of the document matches the signature
  2. You must verify that the signature covers the whole document
  3. You must verify that the key used to sign the document belongs to who it says it does
First, verifying that the signature matches the document content is done using the verify() method. This can be done like so:

    PDF pdf = new PDF(new PDFReader(new FileInputStream(args[0])));
    Map elements = pdf.getForm().getElements();

    for (Iterator i=elements.entrySet().iterator(); i.hasNext();) {
        Map.Entry entry = (Map.Entry)i.next();
        if (entry.getValue() instanceof FormSignature) {
            FormSignature sig = (FormSignature)entry.getValue();
            if (sig.verify()) {
                System.out.println("Signature from "+sig.getName()+" matches document checksum");
            }
        }
    }
 

Second, you must verify that the signature covers the latest revision of the document - otherwise the document could have been altered after signing (see the PDFReader class documentation for more information about revisions). To verify the signature covers the latest revision, you need to compare the value of PDF.getNumberOfRevisions() with the value of getNumberOfRevisionsCovered(). Something like this should do it:

    int pdfrevision = pdf.getNumberOfRevisions();
    int sigrevision = signature.getNumberOfRevisionsCovered();
    if (pdfrevision==sigrevision) System.out.println("Whole document is covered");
 

At this point you know the signature covers the whole document, and that the document hasn't been changed since signing. However, this is only half the story. Although the signature matches the content, in order to be 100% sure the document is unaltered you need to check the document really was signed by the name on the signature. With public-key signatures like those implemented by the PKCS7SignatureHandler signature handler, this is done by verifying the X.509 certificates used to sign the document.

A full discussion of PKI could fill a book in itself, but generally speaking a key is signed by a "chain" of certificates, with the certificate at the end of the chain considered to be "trusted". This prevents anyone from creating a certificate with a name of their choosing.

Each Java distribution comes with a list of trusted top-level certificates, which are used to verify signed JAR files. In the case of VeriSign signatures, one of these top-level certificates is usually at the end of every certificate chain. In the next example we show how to verify the signature certificates against that list, stored as a KeyStore. However, the principle is the same for any type of PKI signature - provided you can get the trusted certificates loaded as a KeyStore, you can verify the signature as follows:

    KeyStore trusted = FormSignature.loadDefaultKeyStore();

    PDF pdf = new PDF(new PDFReader(new FileInputStream(args[0])));
    Map elements = pdf.getForm().getElements();

    for (Iterator i=elements.entrySet().iterator(); i.hasNext();) {
        Map.Entry entry = (Map.Entry)i.next();
        if (entry.getValue() instanceof FormSignature) {
            FormSignature sig = (FormSignature)entry.getValue();

            if (sig.getHandler() instanceof PKCS7SignatureHandler) {
                PKCS7SignatureHandler handler = (PKCS7SignatureHandler)sig.getHandler();
                Calender when = sig.getSignDate();
                X509Certificate[] certs = handler.getCertificate();
                if (FormSignature.verifyCertificates(certs,trusted,null,when)==null) {
                    System.out.println("Certificates for "+sig.getName()+" verified");
                }
            } else {
                System.out.println("Not a PKCS#7 public-key signature!");
            }
        }
    }
 

As any cryptographer will tell you, there is much more to key management than we've described here. It's hard not to sound paranoid when discussing cryptography, because you must always remember when verifying certificates that you are trusting every entity in the certificate chain. Their certificate is the only guarantee you've got that the certificates they've signed belong to the entities those certificates represent. The certificate chain for the supplied signature handlers can be accessed via the PKCS7SignatureHandler.getCertificates() method, and the isValidCertificate method used to perform some basic validation if you want to check the certificates yourself.

Signing documents

A single signature can be applied to a PDF document by adding the signature to the PDF documents Form. Although the PDF library supports reading documents with multiple revisions, it doesn't support writing them, which is why only a single signature can be used. Here's an example.

   PDF pdf = new PDF();
   // Create pdf document here

   KeyStore keystore = loadMyKeyStore();  // Somehow load a keystore
 
   FormSignature sig = new FormSignature(keystore, "mykey",
                                         "secret".toCharArray(),
                                         FormSignature.HANDLER_VERISIGN);
   pdf.getForm().addElement("Test Signature", sig);
 

This slightly oversimplified example demonstrates two things. One, that the private key and its associated certificates used to sign a document must be loaded from a KeyStore, and two, that you must specify the signature handler that will be used to verify the document in Acrobat.

Although in theory all PKI signature handlers should be interoperable (Adobe recommend this in their specification, and this library can verify all signatures that meet those requirements), Acrobat up to 5.0 doesn't allow a signature created with the Self-Sign handler to be verified by the VeriSign handler, and vice-versa. This means before applying a digital signature you need to know which handlers are available to your audience.

Here are the handlers we know about with the level of support we offer. Bear in mind that if you want to sign a document using an unsupported handler, there is (in theory) nothing stopping you from writing your own extension of SignatureHandler to deal with them.

Adobe Acrobat 6.0Can read/write signatures. See HANDLER_ACROBATSIX
Adobe "Self Sign" handlerCan read/write signatures. See HANDLER_SELFSIGN
VeriSign Document SignerCan read/write signatures. See HANDLER_VERISIGN
nCipher TimeSealSupported using the DSE200Handler class
Entrust PPKEF architectureUnsupported, as it uses a non-standard (and as best as we can tell, undocumented) ASN.1 object, rather than a standard PKCS#7 container.
CIC "Sign-It" handlerUnsupported, as it uses handwritten signature entered with a graphics tables. See http://www.cic.com/products/signit
Silanis "ApproveIt" handlerUnsupported, as it uses handwritten signature entered with a graphics tablet. See http://www.silanis.com
Topaz Systems "SigPlus" handlerUnsupported, as it uses handwritten signatures entered through a graphics tablet. See http://www.topazsystems.com

Finally to get you started, here is a complete example showing how to create a PDF signed with the Adobe "self-sign" signature handler. Rather than type all this out we suggest you take a look at the "Sign.java" example supplied with the package, which does all this and more.

  1. Create a self-signed key using the "keytool" program supplied with the JDK. The following command will create a 1024-bit RSA key plus certificate in the file "mykeystore". You'll be prompted for a password.

        keytool -genkey -alias mykey -keyalg RSA -sigalg MD5withRSA \
                -keystore mykeystore -dname 'C=UK, O=BigFaceless, CN=BFO'
     
  2. The following code can be used to create a blank PDF which is digitally signed with this key.

     import java.security.KeyStore;
     import java.io.*;
     import org.faceless.pdf.*;
    
     public static void TestSign
     {
         static final String KEYFILE = "mykeystore";  // Name of keystore file
         static final String KEYALIAS = "mykey";      // Alias for private key
         static final char[] PASSWORD = "secret".toCharArray(); // Password
         static final String OUTFILE = "signed.pdf";  // File to write to.
    
         public static void main(String[] args) throws Exception
         {
             // Load the keystore
             //
             KeyStore keystore = KeyStore.getInstance("JKS");
             keystore.load(new FileInputStream(KEYFILE), PASSWORD);
    
             // Create the PDF (with 1 blank page to keep Acrobat happy).
             //
             PDF pdf = new PDF();
             PDFPage page = pdf.newPage(PDF.PAGESIZE_A4);
    
             // Create the digital signature object
             //
             FormSignature sig = new FormSignature(keystore, KEYALIAS, PASSWORD,
                                                   FormSignature.HANDLER_SELFSIGN);
             pdf.getForm().addElement("Test Signature", sig);
    
             // Write it out
             pdf.render(new FileOutputStream(OUTFILE));
         }
     }
     
  3. Run the program. This creates a file "signed.pdf", whose integrity can be verified in Adobe Acrobat 4.0 or greater.

       java TestSign
     

More information on digital signatures is available in the userguide.

Since:
1.1.13

Field Summary
static SignatureHandlerFactory HANDLER_ACROBATSIX
           A type of handler representing the new, general purpose PKI signature plugin supplied with Acrobat 6.0 and later.
static SignatureHandlerFactory HANDLER_SELFSIGN
           A type of handler representing the Adobe "self-sign" signature handler supplied with Acrobat 4.x and 5.x.
static SignatureHandlerFactory HANDLER_VERISIGN
           A type of handler representing the VeriSign "Document Signer" digital signature handler available for Acrobat 4.x and 5.x.
static int STATE_BLANK
          This value is returned from the getState() method if the signature field has not been completed yet.
static int STATE_PENDING
          This value is returned from the getState() method if the signature is "new" - it has been added to the document and is waiting for the document to be completed before it is applied.
static int STATE_SIGNED
          This value is returned from the getState() method if the signature is "old" - the PDF document that was read in was already signed with this signature.
 
Constructor Summary
FormSignature()
          Create a new blank digital signature field.
FormSignature(KeyStore keystore, String alias, char[] password, SignatureHandlerFactory factory)
          Create a new pending digital signature to sign a PDF document.
 
Method Summary
 WidgetAnnotation addAnnotation(PDFPage page, float x1, float y1, float x2, float y2)
          Add an annotation for this Signature to the specified page at the specified location.
 String getFilter()
          Return the name of the digital signature handler used to sign the document.
static String getIssuerField(X509Certificate cert, String field)
           Return the specified X.500 field from the specified X.509 certificates Issuer.
 String getLocation()
          Return the location where this document was signed if if that information is available, or null otherwise.
 String getName()
          Get the name of the person or entity that signed this PDF if that information is available, or null otherwise.
 int getNumberOfRevisionsCovered()
          Return the number of document revisions covered by this signature.
 String getReason()
          Return the reason this signature was applied to the PDF if that information is available, or null otherwise.
 SignatureHandler getSignatureHandler()
          Return the SignatureHandler that is used with this Signature, or null if the signature has not been signed yet (ie. the state is still STATE_BLANK)
 Calendar getSignDate()
          Return the time the signature was applied to the document.
 int getState()
          Returns the current state of the signature.
static String getSubjectField(X509Certificate cert, String field)
           Return the specified X.500 field from the specified X.509 certificates Subject.
 String getValue()
          As signatures do not have a "value" as such, this method always returns null.
static boolean isValidCertificate(X509Certificate cert, CRL crl, Date signdate)
          Return true if the specified X.509 Certificate is valid for the specified date, has not been revoked and has no unknown critical extensions.
static KeyStore loadAKFKeyStore(InputStream in)
           Load an X.509 certificate from an "Adobe Key File" keystore, the type exported from the Adobe Self-Sign signature handler in Acrobat 4.0.
static KeyStore loadDefaultKeyStore()
          Return the default Java keystore to validate keys against.
static KeyStore loadFDFKeyStore(InputStream in)
           Load an X.509 certificate from an "Adobe Self-Sign Key" keystore, the type exported from the Adobe Self-Sign signature handler in Acrobat 5.0.
static KeyStore loadPKCS7KeyStore(InputStream in)
           Load a list of one or more X.509 certificates from a PKCS#7 file.
static void registerHandlerForVerification(SignatureHandlerFactory factory)
           This method must be called to register a new SignatureHandlerFactory that can be used when verifying signatures, although it's not necessary for handlers that are only used for signing.
 void setLocation(String location)
          Set the location where the signer is signing the PDF document - e.g.
 void setName(String name)
          Set the name of the person or entity who is applying this signature.
 void setReason(String reason)
          Set the reason why the the document is being signed - e.g.
 void sign(KeyStore keystore, String alias, char[] password, SignatureHandlerFactory factory)
          Sign a STATE_BLANK digital signature.
 boolean verify()
           Verify a signature by ensuring that the PDF document hasn't been altered since it was signed.
static X509Certificate verifyCertificates(X509Certificate[] certs, KeyStore keystore, CRL crl, Calendar signdate)
          Verify a list of X.509 certificates against a list of trusted certificates.
 
Methods inherited from class org.faceless.pdf2.FormElement
equals, flatten, getAction, getAnnotation, getAnnotations, getDescription, getForm, isReadOnly, isRequired, isSubmitted, setAction, setDescription, setReadOnly, setRequired, setSubmitted, toString
 
Methods inherited from class java.lang.Object
getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

HANDLER_SELFSIGN

public static final SignatureHandlerFactory HANDLER_SELFSIGN

A type of handler representing the Adobe "self-sign" signature handler supplied with Acrobat 4.x and 5.x. Keys must use the RSA algorithm and may be any length (we've tested 512, 1024 and 2048-bit keys). Certificates must use the MD5/RSA signature algorithm. Obviously the certificate associated with the key must be self-signed, and Acrobat also insists that the country code, if specified, must be exactly 2 letters long.

Self-sign signatures are limited in that only certificates in the viewing users "Personal Address Book" are considered to be trusted - a Certifying Authority is not used. Certificates may be added to the address book if they're not already there, and provided they are confirmed (by manually checking the serial number with the issuer), this handler does most of what is required of a PKI system.

Documents signed with this handler can be verifed in Acrobat 4, 5 and 6 out of the box.

Since:
2.0 (prior to 2.0 this constant existed, but was an integer)

HANDLER_VERISIGN

public static final SignatureHandlerFactory HANDLER_VERISIGN

A type of handler representing the VeriSign "Document Signer" digital signature handler available for Acrobat 4.x and 5.x. Keys must use the RSA algorithm and may be any length, but must be signed by a VeriSign CA key or they will be considered invalid by the VeriSign plugin. Having said that, VeriSign also distribute an "Administrator Tool" which allows you to set your own list of trusted certificates, although we haven't tested this functionality.

The plugin itself is distributed on the Acrobat CD or available from the VeriSign website as a free download. Details on how to use and install the plugin are also available from this site.

The VeriSign test certificate we worked with was MD5/RSA, and we expect that all keys that work with this plugin must use this algorithm.

Documents signed with this handler can be verifed in Acrobat 4, 5 with the VeriSign plugin, and Acrobat 6 out of the box.

Since:
2.0 (prior to 2.0 this constant existed, but was an integer)

HANDLER_ACROBATSIX

public static final SignatureHandlerFactory HANDLER_ACROBATSIX

A type of handler representing the new, general purpose PKI signature plugin supplied with Acrobat 6.0 and later. This handler (which has the Filter name "Adobe.PPKMS") is also known as the "Windows Certificate Security" handler. This handler verifies certificates against the standard Windows Keystore, which is, as best as we can tell, the default behaviour when verifying documents signed with the Acrobat 5.0 "VeriSign" and "Self-Sign" in Acrobat 6.0 anyway. We've no idea what it does on other platforms.

Documents signed with this handler can only be verifed in Acrobat 6. This handler provides no additional functionality over the VeriSign or SelfSign handlers, so for signing documents you may as well use one of those.

Since:
2.0

STATE_SIGNED

public static final int STATE_SIGNED
This value is returned from the getState() method if the signature is "old" - the PDF document that was read in was already signed with this signature. The signature may be validated, but will not be exported again if the document is resaved.

See Also:
STATE_PENDING, STATE_BLANK, getState(), Constant Field Values

STATE_PENDING

public static final int STATE_PENDING
This value is returned from the getState() method if the signature is "new" - it has been added to the document and is waiting for the document to be completed before it is applied. Only one "pending" signature may currently be applied to each document.

See Also:
STATE_SIGNED, STATE_BLANK, getState(), Constant Field Values

STATE_BLANK

public static final int STATE_BLANK
This value is returned from the getState() method if the signature field has not been completed yet. A document may contain more than one blank signature fields.

See Also:
STATE_SIGNED, STATE_PENDING, Constant Field Values
Constructor Detail

FormSignature

public FormSignature()
Create a new blank digital signature field. The field may have a signature applied to it at a later date, either by this library or by Acrobat

Since:
2.0

FormSignature

public FormSignature(KeyStore keystore,
                     String alias,
                     char[] password,
                     SignatureHandlerFactory factory)
              throws GeneralSecurityException,
                     IllegalArgumentException
Create a new pending digital signature to sign a PDF document. The private key and the certificates used to sign the PDF are contained in the specified keystore. This constructor is identical to calling:
   FormSignature sig = new FormSignature();
   sig.sign(keystore, alias, password, factory);
 

Parameters:
keystore - the KeyStore containing the private key and a list of certificates to sign the document with
alias - the alias or "friendly-name" which the private key is stored under in the keystore
password - the password to unlock the private key
factory - the digital signature handler that will be used to verify the signature. Probably one of HANDLER_SELFSIGN or HANDLER_VERISIGN
Throws:
GeneralSecurityException - if the keystore, private key, password or certificates are invalid in any way
IllegalArgumentException - if the arguments are technically correct but will result in an invalid signature for any reason.
Since:
2.0 (prior to 2.0 the last parameter was an integer)
Method Detail

registerHandlerForVerification

public static void registerHandlerForVerification(SignatureHandlerFactory factory)

This method must be called to register a new SignatureHandlerFactory that can be used when verifying signatures, although it's not necessary for handlers that are only used for signing.

When a signature is verified, the appropriate handler is chosen from the list of registered handlers by matching the "Filter" and "SubFilter" fields in the handler to those in the signature. By default, the HANDLER_VERISIGN, HANDLER_SELFSIGN and HANDLER_ACROBATSIX factories are the only three that are registered.

Since:
2.0

addAnnotation

public WidgetAnnotation addAnnotation(PDFPage page,
                                      float x1,
                                      float y1,
                                      float x2,
                                      float y2)
Add an annotation for this Signature to the specified page at the specified location. Unlike other form elements, it is not necessary for a signature to have an annotation - those that don't are called "invisible" signatures in Acrobat. The annotation will take on the appearance defined by the SignatureHandler.getLayerAppearance() method.

Parameters:
page - the page to place the annotation on
x1 - the left-most X co-ordinate of the annotation
y1 - the top-most Y co-ordinate of the annotation
x2 - the right-most X co-ordinate of the annotation
y2 - the bottom-most Y co-ordinate of the annotation
Returns:
a new WidgetAnnotation at the specified location
Since:
2.0

sign

public void sign(KeyStore keystore,
                 String alias,
                 char[] password,
                 SignatureHandlerFactory factory)
          throws GeneralSecurityException,
                 IllegalArgumentException
Sign a STATE_BLANK digital signature. The private key and the certificates used to sign the PDF are contained in the specified keystore.

Parameters:
keystore - the KeyStore containing the private key and a list of certificates to sign the document with
alias - the alias or "friendly-name" which the private key is stored under in the keystore
password - the password to unlock the private key
factory - the digital signature handler that will be used to verify the signature. Probably one of HANDLER_SELFSIGN or HANDLER_VERISIGN
Throws:
GeneralSecurityException - if the keystore, private key, password or certificates are invalid in any way
IllegalArgumentException - if the arguments are technically correct but will result in an invalid signature for any reason.
Since:
2.0

getState

public int getState()
Returns the current state of the signature. The state is either STATE_SIGNED for existing signatures, STATE_PENDING for new signatures that have been added, or STATE_BLANK for empty signature fields


setName

public void setName(String name)
Set the name of the person or entity who is applying this signature. Setting this field is recommended but not necessary - for PKCS#7 signatures, it defaults to the Common Name (CN) of the signing certificate.

Parameters:
name - the name of the entity signing the PDF, or null to clear the current name
Throws:
IllegalStateException - if this signature is STATE_BLANK

getName

public String getName()
Get the name of the person or entity that signed this PDF if that information is available, or null otherwise.

Throws:
IllegalStateException - if this signature is STATE_BLANK

setReason

public void setReason(String reason)
Set the reason why the the document is being signed - e.g. "Approved for distribution". This field is optional.

Parameters:
reason - the reason the entity is signing the document, or null to clear the current reason
Throws:
IllegalStateException - if this signature is STATE_BLANK

getReason

public String getReason()
Return the reason this signature was applied to the PDF if that information is available, or null otherwise.

Throws:
IllegalStateException - if this signature is STATE_BLANK

setLocation

public void setLocation(String location)
Set the location where the signer is signing the PDF document - e.g. "Head Office". This field is optional.

Parameters:
location - the location where the entity is signing the document, or null to clear the current location
Throws:
IllegalStateException - if this signature is STATE_BLANK

getLocation

public String getLocation()
Return the location where this document was signed if if that information is available, or null otherwise.

Throws:
IllegalStateException - if this signature is STATE_BLANK

getSignDate

public Calendar getSignDate()
Return the time the signature was applied to the document.

Returns:
the time the document was signed.
Throws:
IllegalStateException - if this signature isn't STATE_SIGNED

getFilter

public String getFilter()
Return the name of the digital signature handler used to sign the document. This is the value of the "Filter" field from the signature handler being used. Values could well be one of "Adobe.PPKLite", "VeriSign.PPKVS", "Entrust.PPKEF", "CICI.SignIt", "Gemtools.GemSign" or "Silanis.ApproveIt". This method is identical to calling getSignatureHandler().getFilter()

Throws:
IllegalStateException - if this signature is STATE_BLANK
Since:
2.0 (was renamed from "getType" in 1.2.x release)

getSignatureHandler

public SignatureHandler getSignatureHandler()
Return the SignatureHandler that is used with this Signature, or null if the signature has not been signed yet (ie. the state is still STATE_BLANK)

Since:
2.0

verify

public boolean verify()
               throws GeneralSecurityException

Verify a signature by ensuring that the PDF document hasn't been altered since it was signed. Only signatures with a state of STATE_SIGNED may be verified.

Note that this only ensures the document matches the checksum included in the signature object. To completely confirm the document is unaltered the signature object must be confirmed to belong to who it says it does. For the supplied handlers, this is done by checking the X.509 certificates returned by PKCS7SignatureHandler.getCertificates(), either manually or by calling the verifyCertificates method.

Returns:
true if the document is unaltered, false if the document has been altered since signing
Throws:
IllegalStateException - if the signature you're verifying isn't STATE_SIGNED
GeneralSecurityException - if the specified signing algorithm is unknown, or the certificate or key are invalid

getNumberOfRevisionsCovered

public int getNumberOfRevisionsCovered()
Return the number of document revisions covered by this signature. A PDF document can be revised a number of times - for example, filling out a form in Acrobat and saving the document creates a new revision. Every revision of the document must be covered by a signature in order to be sure of the documents contents. See the PDFReader class for more information on document revisions, and the class documentation for this class for examples of how to validate a signature using this method.

Returns:
the number of revisions covered by this signature, or zero if the signature doesn't cover any (in which case it should be discounted)
Throws:
IllegalArgumentException - if the signature is not signed yet (ie. does not have a state of STATE_SIGNED)
Since:
1.2.1

verifyCertificates

public static X509Certificate verifyCertificates(X509Certificate[] certs,
                                                 KeyStore keystore,
                                                 CRL crl,
                                                 Calendar signdate)
                                          throws GeneralSecurityException
Verify a list of X.509 certificates against a list of trusted certificates.

The X.509 certificate(s) used to sign the document are verified and compared against the certificates in the keystore, which are assumed to be trusted. An optional Certificate Revocation List may be specified with a list of compromised certificates.

The method returns the first certificate specified in the PDF that cannot be verified. If every certificate in the chain is verified and the final certificate is signed by a certificate in the specified keystore, the entire chain is considered valid and this method returns null.

The specified keystore may be the result of loadDefaultKeyStore(), or a user specified keystore. The CRL may be (and usually is) null.

Note that self-signed certificates (as created by the Adobe Self-Sign handler) will generally fail, as they cannot be verified against a trusted root certificate. The only exception to this is if you're verifying against a keystore returned from loadAKFKeyStore(java.io.InputStream) or loadFDFKeyStore(java.io.InputStream), containing a certificate that was exported from Acrobat.

Also note that unless you personally trust every entity (represented by a certificate) in the chain to issue certificates responsibly, verifying the chain integrity is worthless.

Parameters:
certs - the X509Certificate list to verify. Usually this is the return result from PKCS7SignatureHandler.getCertificates()
keystore - the KeyStore containing one or more trusted certificates to verify the certificate chain against.
crl - the Certificate Revocation List to check the certificates against. May be null.
signdate - the date the documents was signed. Usually the output of getSignDate()
Returns:
the first certificate in the chain that couldn't be verified, or null if all were verified against a certificate from the keystore.
Throws:
GeneralSecurityException - if the KeyStore or any of the certificates are invalid.
Since:
2.0
See Also:
PKCS7SignatureHandler.getCertificates(), loadAKFKeyStore(java.io.InputStream), loadFDFKeyStore(java.io.InputStream), loadPKCS7KeyStore(java.io.InputStream), loadDefaultKeyStore()

isValidCertificate

public static boolean isValidCertificate(X509Certificate cert,
                                         CRL crl,
                                         Date signdate)
Return true if the specified X.509 Certificate is valid for the specified date, has not been revoked and has no unknown critical extensions.

Parameters:
cert - the X.509 certificate to verify
crl - the Certificate Revokation List to search - may be null
signdate - the date the certificate was used for signing

loadDefaultKeyStore

public static KeyStore loadDefaultKeyStore()
                                    throws GeneralSecurityException
Return the default Java keystore to validate keys against. This is the same keystore used to verify signed JAR files, and is distributed with most versions of Java. It includes the public certificates for several certifying authorities - in our version (Sun JDK1.3.1), VeriSign and Thawte.

Throws:
GeneralSecurityException - if the default keystore cannot be loaded - an unlikely situation

loadAKFKeyStore

public static KeyStore loadAKFKeyStore(InputStream in)
                                throws IOException,
                                       GeneralSecurityException

Load an X.509 certificate from an "Adobe Key File" keystore, the type exported from the Adobe Self-Sign signature handler in Acrobat 4.0. The file (which typically has a .akf suffix) contains a self-signed X.509 certificate, which can be used to verify (but not sign) documents created with the Adobe Self-Sign signature handler.

The returned KeyStore has a single X.509 certificate, and can be passed to the verifyCertificates method to fully validate a document signed with the "self-sign" signature handler, acting as the Java equivalent of the "Personal Address Book" in Acrobat 4 terminology.

Acrobat 5.0 keystores are saved in a different format - the filename is usually "CertExchangeName.fdf", where Name is the name of the user. These keystores can be loaded via the loadFDFKeyStore(java.io.InputStream) method.

Please note the InputStream is not closed by this method.

Throws:
IOException - if the keystore cannot be parsed or loaded properly
GeneralSecurityException - if the keystore's contents are cryptographically wrong
See Also:
HANDLER_SELFSIGN, verifyCertificates(java.security.cert.X509Certificate[], java.security.KeyStore, java.security.cert.CRL, java.util.Calendar), loadFDFKeyStore(java.io.InputStream)

loadFDFKeyStore

public static KeyStore loadFDFKeyStore(InputStream in)
                                throws IOException,
                                       GeneralSecurityException

Load an X.509 certificate from an "Adobe Self-Sign Key" keystore, the type exported from the Adobe Self-Sign signature handler in Acrobat 5.0. The file (which is exported with a .fdf suffix) contains a self-signed X.509 certificate, which can be used to verify (but not sign) documents created with the Adobe Self-Sign signature handler.

The returned KeyStore has a single X.509 certificate, and can be passed to the verifyCertificates method to fully validate a document signed with the "self-sign" signature handler, acting as the Java equivalent of the "Trusted Certificates" in Acrobat 5 terminology.

Acrobat 4.0 keystores are saved in a different format - the filename has a suffix of ".akf". These keystores can be loaded via the loadAKFKeyStore(java.io.InputStream) method. Acrobat 5.0 can also save keys in a PKCS#7 format, which can be loaded using the loadPKCS7KeyStore(java.io.InputStream) method.

Please note the InputStream is not closed by this method.

Throws:
IOException - if the keystore cannot be parsed or loaded properly
GeneralSecurityException - if the keystore's contents are cryptographically wrong
Since:
1.2.1
See Also:
HANDLER_SELFSIGN, verifyCertificates(java.security.cert.X509Certificate[], java.security.KeyStore, java.security.cert.CRL, java.util.Calendar), loadAKFKeyStore(java.io.InputStream)

loadPKCS7KeyStore

public static KeyStore loadPKCS7KeyStore(InputStream in)
                                  throws IOException,
                                         GeneralSecurityException

Load a list of one or more X.509 certificates from a PKCS#7 file.

The returned KeyStore contains X.509 certificates and can be passed to the verifyCertificates method to verify (but not sign) the certificates used to sign a PDF document.

Note that we provide this method for convenience only. If you're working heavily with PKCS format files, we recommend obtaining a JCE implementation that supports them fully. One that we have tested with some success is provided by The Legion of the Bouncy Castle.

Please note the InputStream is not closed by this method.

Throws:
IOException - if the keystore cannot be parsed or loaded properly
GeneralSecurityException - if the keystore's contents are cryptographically wrong
See Also:
HANDLER_VERISIGN, verifyCertificates(java.security.cert.X509Certificate[], java.security.KeyStore, java.security.cert.CRL, java.util.Calendar)

getIssuerField

public static String getIssuerField(X509Certificate cert,
                                    String field)
                             throws CertificateException

Return the specified X.500 field from the specified X.509 certificates Issuer.

Each X.509 certificate has two entities - a subject and an issuer. These are represented in java by the Principal class, but unfortunately that class doesn't allow for extraction of the various elements from the entity - elements like Common Name, Country, Organization etc.

The getIssuerField(java.security.cert.X509Certificate, java.lang.String) and getSubjectField(java.security.cert.X509Certificate, java.lang.String) methods aren't specific to digital signatures or PKCS#7, but are useful "utility" methods that fill that gap in functionality.

Parameters:
cert - the X.509 certificate to extract the Issuer from
field - the field to return. Can be one of "C" (country), "CN" (common name), "O" (organization"), "OU" (organization unit), "L" (locale), "ST" (state or province) or "Email" (email address - although technically not part of X.500 this is sometimes included)
Returns:
the requested field, or null if the field is not part of the X.500 name.
Throws:
CertificateException

getSubjectField

public static String getSubjectField(X509Certificate cert,
                                     String field)
                              throws CertificateException

Return the specified X.500 field from the specified X.509 certificates Subject. See the getIssuerField(java.security.cert.X509Certificate, java.lang.String) method for more information.

Parameters:
cert - the X.509 certificate to extract the Issuer from
field - the field to return. Can be one of "C" (country), "CN" (common name), "O" (organization"), "OU" (organization unit), "L" (locale), "ST" (state or province) or "Email" (email address - although technically not part of X.500 this is sometimes included)
Returns:
the requested field, or null if the field is not part of the X.500 name.
Throws:
CertificateException

getValue

public String getValue()
As signatures do not have a "value" as such, this method always returns null.

Specified by:
getValue in class FormElement


Copyright © 2001-2004 Big Faceless Organization