You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2015/10/09 20:54:39 UTC

svn commit: r1707795 - in /pdfbox/trunk/examples/src: main/java/org/apache/pdfbox/examples/signature/ test/java/org/apache/pdfbox/examples/pdmodel/

Author: tilman
Date: Fri Oct  9 18:54:39 2015
New Revision: 1707795

URL: http://svn.apache.org/viewvc?rev=1707795&view=rev
Log:
PDFBOX-3011: move common code to abstract base class; add test for visible signature

Added:
    pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java   (with props)
Modified:
    pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java
    pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java
    pdfbox/trunk/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java

Modified: pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java?rev=1707795&r1=1707794&r2=1707795&view=diff
==============================================================================
--- pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java (original)
+++ pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java Fri Oct  9 18:54:39 2015
@@ -21,7 +21,6 @@ import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URL;
 import java.security.GeneralSecurityException;
@@ -40,7 +39,6 @@ import java.util.List;
 
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
-import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
 import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1EncodableVector;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
@@ -50,20 +48,10 @@ import org.bouncycastle.asn1.cms.Attribu
 import org.bouncycastle.asn1.cms.AttributeTable;
 import org.bouncycastle.asn1.cms.Attributes;
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cert.jcajce.JcaCertStore;
-import org.bouncycastle.cms.CMSException;
 import org.bouncycastle.cms.CMSSignedData;
-import org.bouncycastle.cms.CMSSignedDataGenerator;
 import org.bouncycastle.cms.SignerInformation;
 import org.bouncycastle.cms.SignerInformationStore;
-import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
 import org.bouncycastle.tsp.TSPException;
-import org.bouncycastle.util.Store;
 
 /**
  * An example for singing a PDF with bouncy castle.
@@ -76,11 +64,8 @@ import org.bouncycastle.util.Store;
  * @author Vakhtang Koroghlishvili
  * @author John Hewson
  */
-public class CreateSignature implements SignatureInterface
+public class CreateSignature extends CreateSignatureBase
 {
-    private final PrivateKey privateKey;
-    private final Certificate certificate;
-    private TSAClient tsaClient;
 
     /**
      * Initialize the signature creator with a keystore and certficate password.
@@ -184,7 +169,8 @@ public class CreateSignature implements
      * @param signedData -Generated CMS signed data
      * @return CMSSignedData - Extended CMS signed data
      */
-    private CMSSignedData signTimeStamps(CMSSignedData signedData)
+    @Override
+    protected CMSSignedData signTimeStamps(CMSSignedData signedData)
             throws IOException, TSPException
     {
         SignerInformationStore signerStore = signedData.getSignerInfos();
@@ -235,57 +221,6 @@ public class CreateSignature implements
         return newSigner;
     }
 
-    /**
-     * SignatureInterface implementation.
-     *
-     * This method will be called from inside of the pdfbox and create the PKCS #7 signature.
-     * The given InputStream contains the bytes that are given by the byte range.
-     *
-     * This method is for internal use only. <-- TODO this method should be private
-     *
-     * Use your favorite cryptographic library to implement PKCS #7 signature creation.
-     */
-    @Override
-    public byte[] sign(InputStream content) throws IOException
-    {
-        try
-        {
-            List<Certificate> certList = new ArrayList<Certificate>();
-            certList.add(certificate);
-            Store certs = new JcaCertStore(certList);
-            CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
-            org.bouncycastle.asn1.x509.Certificate cert =
-                    org.bouncycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(certificate.getEncoded()));
-            ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA256WithRSA").build(privateKey);
-            gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
-                    new JcaDigestCalculatorProviderBuilder().build()).build(sha1Signer, new X509CertificateHolder(cert)));
-            gen.addCertificates(certs);
-            CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
-            CMSSignedData signedData = gen.generate(msg, false);
-            if (tsaClient != null)
-            {
-                signedData = signTimeStamps(signedData);
-            }
-            return signedData.getEncoded();
-        }
-        catch (GeneralSecurityException e)
-        {
-            throw new IOException(e);
-        }
-        catch (CMSException e)
-        {
-            throw new IOException(e);
-        }
-        catch (TSPException e)
-        {
-            throw new IOException(e);
-        }
-        catch (OperatorCreationException e)
-        {
-            throw new IOException(e);
-        }
-    }
-
     public static void main(String[] args) throws IOException, GeneralSecurityException
     {
         if (args.length < 3)

Added: pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java?rev=1707795&view=auto
==============================================================================
--- pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java (added)
+++ pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java Fri Oct  9 18:54:39 2015
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.pdfbox.examples.signature;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaCertStore;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.CMSSignedDataGenerator;
+import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.bouncycastle.tsp.TSPException;
+import org.bouncycastle.util.Store;
+
+public abstract class CreateSignatureBase implements SignatureInterface
+{
+    protected PrivateKey privateKey;
+    protected Certificate certificate;
+    protected TSAClient tsaClient;
+
+    /**
+     * Does nothing. Override this if needed.
+     *
+     * @param signedData Generated CMS signed data
+     * @return CMSSignedData Extended CMS signed data
+     */
+    protected CMSSignedData signTimeStamps(CMSSignedData signedData) throws IOException, TSPException
+    {
+        return signedData;
+    }
+
+    /**
+     * SignatureInterface implementation.
+     *
+     * This method will be called from inside of the pdfbox and create the PKCS #7 signature.
+     * The given InputStream contains the bytes that are given by the byte range.
+     *
+     * This method is for internal use only. <-- TODO this method should be private
+     *
+     * Use your favorite cryptographic library to implement PKCS #7 signature creation.
+     */
+    @Override
+    public byte[] sign(InputStream content) throws IOException
+    {
+        try
+        {
+            List<Certificate> certList = new ArrayList<Certificate>();
+            certList.add(certificate);
+            Store certs = new JcaCertStore(certList);
+            CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+            org.bouncycastle.asn1.x509.Certificate cert = org.bouncycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(certificate.getEncoded()));
+            ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA256WithRSA").build(privateKey);
+            gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).build(sha1Signer, new X509CertificateHolder(cert)));
+            gen.addCertificates(certs);
+            CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
+            CMSSignedData signedData = gen.generate(msg, false);
+            if (tsaClient != null)
+            {
+                signedData = signTimeStamps(signedData);
+            }
+            return signedData.getEncoded();
+        }
+        catch (GeneralSecurityException e)
+        {
+            throw new IOException(e);
+        }
+        catch (CMSException e)
+        {
+            throw new IOException(e);
+        }
+        catch (TSPException e)
+        {
+            throw new IOException(e);
+        }
+        catch (OperatorCreationException e)
+        {
+            throw new IOException(e);
+        }
+    }
+
+}

Propchange: pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java?rev=1707795&r1=1707794&r2=1707795&view=diff
==============================================================================
--- pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java (original)
+++ pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java Fri Oct  9 18:54:39 2015
@@ -20,40 +20,23 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
-import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Enumeration;
-import java.util.List;
 import org.apache.pdfbox.io.IOUtils;
 
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
-import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner;
-import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cert.jcajce.JcaCertStore;
-import org.bouncycastle.cms.CMSException;
-import org.bouncycastle.cms.CMSSignedData;
-import org.bouncycastle.cms.CMSSignedDataGenerator;
-import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
-import org.bouncycastle.util.Store;
 
 /**
  * This is an example for visual signing a pdf with bouncy castle.
@@ -61,12 +44,10 @@ import org.bouncycastle.util.Store;
  * @see CreateSignature
  * @author Vakhtang Koroghlishvili
  */
-public class CreateVisibleSignature implements SignatureInterface
+public class CreateVisibleSignature extends CreateSignatureBase
 {
     private static final BouncyCastleProvider BCPROVIDER = new BouncyCastleProvider();
 
-    private final PrivateKey privKey;
-    private final Certificate[] cert;
     private SignatureOptions options;
 
     /**
@@ -92,34 +73,29 @@ public class CreateVisibleSignature impl
         {
             throw new IOException("Could not find alias");
         }
-        privKey = (PrivateKey) keystore.getKey(alias, pin);
-        cert = keystore.getCertificateChain(alias);
+        privateKey = (PrivateKey) keystore.getKey(alias, pin);
+        certificate = keystore.getCertificateChain(alias)[0];
     }
 
     /**
      * Sign pdf file and create new file that ends with "_signed.pdf".
      *
-     * @param documentFile The source pdf document file.
-     * @param signatureProperties The signature properties.
-     * @return the signed pdf document file.
+     * @param inputFile The source pdf document file.
+     * @param signedFile The file to be signed.
      * @throws IOException
      */
-    public File signPDF(File documentFile, PDVisibleSigProperties signatureProperties) throws IOException
+    public void signPDF(File inputFile, File signedFile) throws IOException
     {
-        if (documentFile == null || !documentFile.exists())
+        if (inputFile == null || !inputFile.exists())
         {
             throw new IOException("Document for signing does not exist");
         }
 
         // creating output document and prepare the IO streams.
-        String name = documentFile.getName();
-        String substring = name.substring(0, name.lastIndexOf('.'));
-
-        File outputDocumentFile = new File(documentFile.getParent(), substring + "_signed.pdf");
-        FileOutputStream fos = new FileOutputStream(outputDocumentFile);
+        FileOutputStream fos = new FileOutputStream(signedFile);
 
         // load document
-        PDDocument doc = PDDocument.load(documentFile);
+        PDDocument doc = PDDocument.load(inputFile);
 
         // create signature dictionary
         PDSignature signature = new PDSignature();
@@ -152,51 +128,25 @@ public class CreateVisibleSignature impl
         // do not close options before saving, because some COSStream objects within options 
         // are transferred to the signed document.
         IOUtils.closeQuietly(options);
-
-        return outputDocumentFile;
     }
 
-    /**
-     * SignatureInterface implementation.
-     *
-     * This method will be called from inside of the pdfbox and create the pkcs7 signature.
-     * The given InputStream contains the bytes that are given by the byte range.
-     *
-     * This method is for internal use only. <-- TODO this method should be private
-     *
-     * Use your favorite cryptographic library to implement pkcs7 signature creation.
-     */
-    @Override
-    public byte[] sign(InputStream content) throws IOException
+    PDVisibleSignDesigner visibleSignDesigner;
+    PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties();
+
+    public void setVisibleSignatureProperties(String filename, int x, int y, int zoomPercent, 
+            FileInputStream image, int page) 
+            throws IOException
     {
-        try
-        {
-            List<Certificate> certList = new ArrayList<Certificate>();
-            certList.add(cert[0]);
-            Store certs = new JcaCertStore(certList);
-            CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
-            org.bouncycastle.asn1.x509.Certificate certificate =
-                    org.bouncycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(cert[0].getEncoded()));
-            ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA256WithRSA").build(privKey);
-            gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
-                    new JcaDigestCalculatorProviderBuilder().build()).build(sha1Signer, new X509CertificateHolder(certificate)));
-            gen.addCertificates(certs);
-            CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
-            CMSSignedData signedData = gen.generate(msg, false);
-            return signedData.getEncoded();
-        }
-        catch (CertificateEncodingException e)
-        {
-            throw new IOException(e);
-        }
-        catch (CMSException e)
-        {
-            throw new IOException(e);
-        }
-        catch (OperatorCreationException e)
-        {
-            throw new IOException(e);
-        }
+        visibleSignDesigner = new PDVisibleSignDesigner(filename, image, page);
+        visibleSignDesigner.xAxis(x).yAxis(y).zoom(zoomPercent).signatureFieldName("signature");
+    }
+    
+    public void setSignatureProperties(String name, String location, String reason, int preferredSize, 
+            int page, boolean visualSignEnabled) throws IOException
+    {
+        signatureProperties.signerName(name).signerLocation(location).signatureReason(reason).
+                preferredSize(preferredSize).page(page).visualSignEnabled(visualSignEnabled).
+                setPdVisibleSignature(visibleSignDesigner).buildSignature();
     }
 
     /**
@@ -222,21 +172,19 @@ public class CreateVisibleSignature impl
             char[] pin = args[1].toCharArray();
             keystore.load(new FileInputStream(ksFile), pin);
 
-            File document = new File(args[2]);
+            File documentFile = new File(args[2]);
 
             CreateVisibleSignature signing = new CreateVisibleSignature(keystore, pin.clone());
 
             FileInputStream image = new FileInputStream(args[3]);
-
-            PDVisibleSignDesigner visibleSig = new PDVisibleSignDesigner(args[2], image, 1);
-            visibleSig.xAxis(0).yAxis(0).zoom(-50).signatureFieldName("signature");
-
-            PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties();
-
-            signatureProperties.signerName("name").signerLocation("location").signatureReason("Security").preferredSize(0)
-                    .page(1).visualSignEnabled(true).setPdVisibleSignature(visibleSig).buildSignature();
-
-            signing.signPDF(document, signatureProperties);
+            
+            String name = documentFile.getName();
+            String substring = name.substring(0, name.lastIndexOf('.'));
+            File signedDocumentFile = new File(documentFile.getParent(), substring + "_signed.pdf");
+
+            signing.setVisibleSignatureProperties (args[2], 0, 0, -50, image, 1);
+            signing.setSignatureProperties ("name", "location", "Security", 0, 1, true);
+            signing.signPDF(documentFile, signedDocumentFile);
         }
     }
 

Modified: pdfbox/trunk/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java?rev=1707795&r1=1707794&r2=1707795&view=diff
==============================================================================
--- pdfbox/trunk/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java (original)
+++ pdfbox/trunk/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java Fri Oct  9 18:54:39 2015
@@ -17,11 +17,6 @@
 package org.apache.pdfbox.examples.pdmodel;
 
 import junit.framework.TestCase;
-import org.apache.pdfbox.examples.signature.CreateSignature;
-import org.apache.pdfbox.examples.signature.TSAClient;
-import org.apache.pdfbox.io.IOUtils;
-import org.apache.wink.client.MockHttpServer;
-import org.bouncycastle.tsp.TSPValidationException;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -32,6 +27,13 @@ import java.security.GeneralSecurityExce
 import java.security.KeyStore;
 import java.security.MessageDigest;
 
+import org.apache.pdfbox.examples.signature.CreateSignature;
+import org.apache.pdfbox.examples.signature.CreateVisibleSignature;
+import org.apache.pdfbox.examples.signature.TSAClient;
+import org.apache.pdfbox.io.IOUtils;
+import org.apache.wink.client.MockHttpServer;
+import org.bouncycastle.tsp.TSPValidationException;
+
 /**
  * Test for CreateSignature
  */
@@ -40,6 +42,7 @@ public class TestCreateSignature extends
     private final String inDir = "src/test/resources/org/apache/pdfbox/examples/signature/";
     private final String outDir = "target/test-output/";
     private final String keystorePath = inDir + "keystore.p12";
+    private final String jpegPath = inDir + "stamp.jpg";
     private final String password = "123456";
 
     @Override
@@ -119,4 +122,27 @@ public class TestCreateSignature extends
 
         // TODO verify the signed PDF file
     }
+    
+    /**
+     * Test creating visual signature.
+     *
+     * @throws IOException
+     * @throws GeneralSecurityException
+     */
+    public void testCreateVisibleSignature() throws IOException, GeneralSecurityException
+    {
+        // load the keystore
+        KeyStore keystore = KeyStore.getInstance("PKCS12");
+        keystore.load(new FileInputStream(keystorePath), password.toCharArray());
+
+        // sign PDF
+        String inPath = inDir + "sign_me.pdf";
+        FileInputStream fis = new FileInputStream(jpegPath);
+        CreateVisibleSignature signing = new CreateVisibleSignature(keystore, password.toCharArray());
+        signing.setVisibleSignatureProperties (inPath, 0, 0, -50, fis, 1);
+        signing.setSignatureProperties ("name", "location", "Security", 0, 1, true);
+        signing.signPDF(new File(inPath), new File(outDir + "signed_visible.pdf"));
+
+        // TODO verify the signed PDF file
+    }
 }