📄 formsignature.java
字号:
// $Id: FormSignature.java,v 1.4 2003/11/03 14:03:51 mike Exp $package org.faceless.pdf;import java.io.*;import java.util.*;import java.security.*;import java.security.cert.*;import java.security.spec.*;/** * <p> * 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 not based around a * Public Key crypto system are not supported. * </p><p> * Signatures may be applied and verified using either the full version of * Adobe Acrobat™ or Adobe Approval, <b>not</b> 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. * </p><p> * The signatures used in PDF documents are X.509 certificates, which are * already handled by the <code>java.security</code> packages supplied with * J2SE 1.2 and later. No additional Java classes are required. * </p><p> * An important point to remember is that the signatures on an existing * document are <b>not preserved</b> 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 {@link #STATE_PENDING} * signature can be applied to a PDF. * </p><p> * So how do you use this class? First we'll cover how to verify signatures * on an existing document. * </p> * * <h3>Verifying existing signatures</h3> * <p> * To verify a document has been signed and not altered since signing, and * to be sure of the signatory, three steps are required: * <ol> * <li>You must verify that content of the document matches the signature</li> * <li>You must verify that the signature covers the whole document</li> * <li>You must verify that the key used to sign the document belongs to who it says it does</li> * </ol> * First, verifying that the signature matches the document content is done * using the {@link #verify} method. This can be done like so: * </p> * <pre> * PDF pdf = new PDF(new PDFReader(new FileInputStream(args[0]))); * <b>Map elements = pdf.getForm().getElements();</b> * * for (Iterator i=elements.keySet().iterator(); i.hasNext();) { * String name = (String)i.next(); * if (elements.get(name) instanceof FormSignature) { * <b>FormSignature sig = (FormSignature)elements.get(name); * if (sig.verify()) {</b> * System.out.println("Signature from "+sig.getName()+" matches"); * } * } * } * </pre> * <p> * 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 * {@link PDFReader} class documentation for more information about revisions. To * verify the signature covers the latest revision, you need to compare the value of * {@link PDF#getNumberOfRevisions} with the value of {@link #getNumberOfRevisionsCovered}. * Something like this should do it: * </p> * <pre> * int pdfrevision = pdf.getNumberOfRevisions(); * int sigrevision = signature.getNumberOfRevisionsCovered(); * if (pdfrevision==sigrevision) System.out.println("Whole document is covered"); * </pre> * <p> * 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 certificates used to sign the * document - otherwise anyone could create a certificate with any name they choose. * 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". * </p><p> * Each Java distribution comes with a list of trusted top-level certificates, * which are used to verify signed JAR files. One of these top-level certificates * is usually at the end of every certificate chain. Here's how to verify the * certificates used against that list, called a "KeyStore". * </p> * <pre> * <b>KeyStore trusted = FormSignature.loadDefaultKeyStore();</b> * * PDF pdf = new PDF(new PDFReader(new FileInputStream(args[0]))); * <b>Map elements = pdf.getForm().getElements();</b> * * for (Iterator i=elements.keySet().iterator(); i.hasNext();) { * String name = (String)i.next(); * if (elements.get(name) instanceof FormSignature) { * <b>FormSignature sig = (FormSignature)elements.get(name); * if (sig.verifyCertificates(trusted,null)==null) {</b> * System.out.println("Certificates for "+sig.getName()+" verified"); * } * } * } * </pre> * <p> * 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 can be accessed * via the {@link #getCertificates} method, and the * <code>isValidCertificate</code> method used to perform some basic validation * if you want to check the certificates yourself. * </p> * * <h3>Signing documents</h3> * <p> * 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. * </p> * <pre> * PDF pdf = new PDF(); * // Create pdf document here * * KeyStore keystore = loadMyKeyStore(); // Somehow load a keystore * * <b>FormSignature sig = new FormSignature(keystore, "mykey", * "secret".toCharArray(), * FormSignature.HANDLER_VERISIGN);</b> * <b>pdf.getForm().addElement("Test Signature", sig);</b> * </pre> * <p> * 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 {@link KeyStore}, and two, that a digital signature must * be verified by a specified digital signature handler. * </p><p> * Although in theory all PKI signature handlers should be interoperable (Adobe recommend * this in their <a href=http://partners.adobe.com/asn/developer/acrosdk/docs/ppk_pdfspec.pdf>specification</a>, * and this library can verify all signatures that meet those requirements), * at least Acrobat 4.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. * </p><p> * Here are the handlers we know about with the level of support we offer. * </p><p> * <table border=1> * <tr><td><b>Adobe "Self Sign" handler</b></td><td>Can read/write signatures. See {@link #HANDLER_SELFSIGN}</td></tr> * <tr><td nowrap><b>VeriSign Document Signer</b></td><td>Can read/write signatures. See {@link #HANDLER_VERISIGN}</td></tr> * <tr><td nowrap><b>Entrust PPKEF architecture</b></td><td>Currently unsupported. We hope to support the Entrust architecture in the not-so-distant future.</td></tr> * <tr><td><b>CIC "Sign-It" handler</b></td><td>Not a public/private key handler, uses custom "written" signatures instead. Unsupported.</td></tr> * </table> * <p> * 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. * </p> * <ol> * <li> * <p> * 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. * </p> * <pre> * keytool -genkey -alias mykey -keyalg RSA -sigalg MD5withRSA \ * -keystore mykeystore -dname 'C=UK, O=BigFaceless, CN=BFO' * </pre> * </li> * <li> * <p> * The following code can be used to create a blank PDF which is digitally * signed with this key. * </p><pre> * 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)); * } * } * </pre> * </li><li> * <p> * Run the program. This creates a file "signed.pdf", whose integrity can be * verified in Adobe Acrobat 4.0 or greater. * </p><pre> * java TestSign * </pre> * </li></ol> * <p> * More information on digital signatures is available in the userguide. * </p> * * @since 1.1.13 * @version $Revision: 1.4 $ */public final class FormSignature extends FormElement{ FormSignature(org.faceless.pdf2.FormSignature b) { super(b); } /** * <p> * A type of handler representing the Adobe "self-sign" signature handler * supplied with every version of Acrobat. 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. * </p><p> * 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. * </p> */ public static final int HANDLER_SELFSIGN = 0; /** * <p> * A type of handler representing the VeriSign "Document Signer" digital signature handler. * Keys must use the RSA algorithm and may be any length, but <i>must</i> * 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. * </p><p> * The plugin itself is distributed on the Acrobat CD or available from the * <a href="http://www.verisign.com/products/acrobat">VeriSign website</a> * as a free download. Details on how to use and install the plugin are also * available from this site. * </p><p> * 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. * </p> */ public static final int HANDLER_VERISIGN = 1; /** * This value is returned from the {@link #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 #STATE_PENDING * @see #getState */ public static final int STATE_SIGNED = 0; /** * This value is returned from the {@link #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 #STATE_SIGNED * @see #getState */ public static final int STATE_PENDING = 1; private org.faceless.pdf2.FormSignature sig; /** * <p> * Create a new digital signature to sign a PDF document. The private key and * the certificates used to sign the PDF are contained in the specified * keystore. * </p> * @param keystore the KeyStore containing the private key and a list of certificates * to sign the document with * @param alias the alias or "friendly-name" which the private key is stored under * in the keystore * @param password the password to unlock the private key * @param handler the digital signature handler that will be used to verify the * signature. Current values are {@link #HANDLER_SELFSIGN}, for the Adobe Self-Sign handler, * and {@link #HANDLER_VERISIGN}, for the VeriSign handler. * @throws GeneralSecurityException if the keystore, private key, password or certificates are invalid in any way * @throws IllegalArgumentException if the arguments are technically correct but will result in an invalid signature for any reason. */ public FormSignature(KeyStore keystore, String alias, char[] password, int handler) throws GeneralSecurityException, IllegalArgumentException { super(new org.faceless.pdf2.FormSignature(keystore, alias, password, handler==HANDLER_VERISIGN ? org.faceless.pdf2.FormSignature.HANDLER_VERISIGN : org.faceless.pdf2.FormSignature.HANDLER_SELFSIGN)); } /** * Returns the current state of the signature. The state is * currently either {@link #STATE_SIGNED} for existing signatures, * or {@link #STATE_PENDING} for new signatures. */ public int getState() { int state = ((org.faceless.pdf2.FormSignature)element).getState(); if (state==org.faceless.pdf2.FormSignature.STATE_SIGNED) { return STATE_SIGNED; } else { return STATE_PENDING; } } /** * Set the name of the person or entity who is applying this signature. * Setting this field is recommended but not necessary - it defaults * to the Common Name (CN) of the signing certificate. * * @param name the name of the entity signing the PDF, * or <code>null</code> to clear the current reason */ public void setName(String name) { ((org.faceless.pdf2.FormSignature)element).setName(name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -