org.faceless.pdf2
Class SignatureHandler

java.lang.Object
  extended by org.faceless.pdf2.SignatureHandler
Direct Known Subclasses:
DSE200Handler, PKCS7SignatureHandler

public abstract class SignatureHandler
extends Object

This class is the baseline handler for all digital signatures - it could theoretically be used for any type of signature, using biometrics, public/private key and so on. Two main implementations are provided with this package, those returned by AcrobatSignatureHandlerFactory and thoe returned by the DSE200HandlerFactory. Typically an object of this type will be a PKCS7SignatureHandler.

For 99% of users, it is enough to look at the examples in the FormSignature API documentation, which details how to sign and verify documents using the standard handlers. For those wanting to write their own signature handlers however, read on.

The SignatureHandler class has several methods which need to be implemented by concrete implementations of this class. They are at a minimum getFilter(), the verify() method (if the handler is to be used to verify signatures), and/or the prepareToSign() and sign() methods if the handler is to be used to sign signatures. In addition, when signing if the signature is to have a visible appearance on the page, something useful should be returned from getLayerNames() and getLayerAppearance().

The idea behind the handler is that when signing, first any annotations associated with the signature are created and filled using the values returned from the getLayerAppearance() method. Then the prepareToSign() method is called, which should set all the values in the "V" dictionary and generally do everything required to set up the signature in preparation for signing. Finally the sign() method is called, it's return value is stored in the "Contents" field.

The SignatureHandler works in a similar way to the EncryptionHandler class. There are a number of get...Value and put...Value methods which can be used to get/set values in the "V" dictionary of the Signature dictionary. See the discussion in the EncryptionHandler class documentation for details on how these methods work. As an example, the SelfSign handler includes the following lines in it's prepareToSign() method:

   putNameValue("Filter", "Adobe.PPKLite");
   putNameValue("SubFilter", "adbe.x509.rsa_sha1");
   putNumericValue("R", 65539);
   putStringValue("Cert", certificatebytearray);
 

As a slightly more complicated example, to add /MyArray [ 100 << /Type /MyHandler >> ] to the "V" dictionary, just do:

   putArrayValue("MyArray");
   putNumericValue("MyArray.0", 100);
   putDictionaryValue("MyArray.1");
   putNameValue("MyArray.1.Type", "MyHandler");
 

The getFilter() method should return an appropriate value - so again, the SelfSign handler will return the string "Adobe.PPKLite".

For a concrete example of a working, if somewhat brain-dead signature handler, see the DummySignatureHandler.java example, supplied with the download package.

Since:
2.0
See Also:
FormSignature, SignatureHandlerFactory

Constructor Summary
SignatureHandler()
           
 
Method Summary
abstract  String getFilter()
          Return the name of the filter, eg "Adobe.PPKLite".
abstract  PDFCanvas getLayerAppearance(String layername, PDFStyle style)
          Return a PDFCanvas for the specified layer.
abstract  String[] getLayerNames()
          Return the list of appearance layer names used by this Signature Handler to create a visible appearance on the page, in the order they should be drawn.
abstract  MessageDigest getMessageDigest()
          Return a MessageDigest that will be used to calculate the digest of the PDF for signing.
 byte[] getVariable(String name)
          This method returns the contents of the variable specified by name.
 Map getVariables()
           Return the list of "variables" which will be set by the handler after the PDF is rendered.
 boolean isVariableEncrypted(String name)
           When signing an encrypted document, whether to encrypt the specified variable or not.
abstract  byte[] sign()
          Finish the digest calculation on the digest returned from getMessageDigest() and return a signature token the signs it.
abstract  boolean verify(InputStream in)
          Return a boolean indicating whether or not the signature handler can verify the specified InputStream.
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

SignatureHandler

public SignatureHandler()
Method Detail

getVariables

public Map getVariables()
                 throws GeneralSecurityException

Return the list of "variables" which will be set by the handler after the PDF is rendered. Entries in the returned map should have a String as a key and a byte[] as a value. The byte array should be empty (ie all zeros), and should be long enough to hold the token that will eventually be substituted into it from the getVariable(java.lang.String) method.

Remember that the token may be encrypted if it is a string (or contains a string) and an EncryptionHandler is present. For that reason it's recommended to encode enough spaces after any string to cater for expansion due to character escaping. For example, the variable value (Test) may be converted to (r^$\n) after encryption - which requires an extra byte.

For most SignatureHandlers, the only variable is the "Contents" array containing the signature token, which is what this method returns (it may be overridden if more variables are required).

This method and getVariable(java.lang.String) replace the isPDFObjectSignature method which was added in 2.2.4 but has been removed in favour of this considerably more flexible approach.

Returns:
a Map containing the name and size of variables to be substituted into the "V" dictionary.
Throws:
GeneralSecurityException
Since:
2.3
See Also:
AcrobatSignatureHandlerFactory.setContentSize(int)

getVariable

public byte[] getVariable(String name)
                   throws GeneralSecurityException
This method returns the contents of the variable specified by name. It is called after the sign() method. The returned byte array should not be longer than the array returned by getVariables(), and as it will be substituted straight into the PDF should contain any PDF formatting that's required - for example, if returning a string, you need to make sure the "(" and ")" characters are added around the String and that any nested "(" characters are escaped. This method will be called once for each item returned from the getVariables() method, except for "Contents" (which is handled seperately).

Parameters:
name - the name of a variable - guaranteed to be one of the keys returned from getVariables() (although not "Contents")
Returns:
a byte array which will be substituted into the "V" dictionary of the Signature Handler.
Throws:
GeneralSecurityException
Since:
2.3

isVariableEncrypted

public boolean isVariableEncrypted(String name)

When signing an encrypted document, whether to encrypt the specified variable or not. The PDF specification is silent on this, and different handlers have different approaches. For instance, the standard Adobe handlers encrypt every variable except the "Contents" field. The nCipher TimeSeal handler encrypts all variables including Contents. This method should return true if the variable is to be stored encrypted in an encrypted PDF.

The default implementation of this method returns true for every variable except "Contents"

Parameters:
name - the name of a variable - guaranteed to be one of the keys returned from getVariables()
Returns:
true if, when signing an encrypted document, this variable is to be stored encrypted
Since:
2.3.4

getFilter

public abstract String getFilter()
Return the name of the filter, eg "Adobe.PPKLite".


sign

public abstract byte[] sign()
                     throws GeneralSecurityException,
                            IOException
Finish the digest calculation on the digest returned from getMessageDigest() and return a signature token the signs it. This method will be called more than once - the first time with a zero-length stream, to calculate the length of the token, the second time with the actual data to sign. The returned byte array will be stored as the "Contents" value of the Signature dictionary.

Returns:
a byte array representing the signature token
Throws:
GeneralSecurityException - if the signature cannot be applied for some cryptographic reason
IOException - if the InputStream cannot be read
Since:
2.10 (this method existed earlier but took an InputStream as a parameter, and was required to create the digest now returned from getMessageDigest() internally)

getMessageDigest

public abstract MessageDigest getMessageDigest()
Return a MessageDigest that will be used to calculate the digest of the PDF for signing.

Since:
2.10

verify

public abstract boolean verify(InputStream in)
                        throws GeneralSecurityException,
                               IOException
Return a boolean indicating whether or not the signature handler can verify the specified InputStream.

Returns:
true if the signature matches the specified InputStream
Throws:
GeneralSecurityException - if the signature cannot be verified for some cryptographic reason
IOException - if the InputStream cannot be read

getLayerNames

public abstract String[] getLayerNames()
Return the list of appearance layer names used by this Signature Handler to create a visible appearance on the page, in the order they should be drawn. This method is called internally by the FormSignature class when drawing the signature annotations on the page. For more information see the document "Digital Signature Appearances for Public-Key Interoperability", from Adobes website.

As an example, both the Verisign and the SelfSign handlers return the array [ "n0", "n1", "n2", "n3" ].

Returns:
the ordered list of layer names that should to used to create a visible representation of this signature on a page.
See Also:
getLayerAppearance(java.lang.String, org.faceless.pdf2.PDFStyle)

getLayerAppearance

public abstract PDFCanvas getLayerAppearance(String layername,
                                             PDFStyle style)
Return a PDFCanvas for the specified layer. This method is called internally by the FormSignature class when drawing the signature annotations on the page. For more information see the document "Digital Signature Appearances for Public-Key Interoperability", from Adobes website.

Parameters:
layername - the layer to create (from the list returned by getLayerNames())
style - the style in which to draw the text, if any
Returns:
a new PDFCanvas of any size containing the specified layer.
See Also:
getLayerNames()


Copyright © 2001-2004 Big Faceless Organization