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/10 15:58:07 UTC

svn commit: r1707879 - in /pdfbox/trunk/examples/src: main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java

Author: tilman
Date: Sat Oct 10 13:58:07 2015
New Revision: 1707879

URL: http://svn.apache.org/viewvc?rev=1707879&view=rev
Log:
PDFBOX-3011: improve test, access signature contents

Modified:
    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/CreateVisibleSignature.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java?rev=1707879&r1=1707878&r2=1707879&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 Sat Oct 10 13:58:07 2015
@@ -25,7 +25,6 @@ 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.CertificateException;
 import java.util.Calendar;
 import java.util.Enumeration;
@@ -159,7 +158,6 @@ public class CreateVisibleSignature exte
     public static void main(String[] args) throws KeyStoreException, CertificateException,
             IOException, NoSuchAlgorithmException, UnrecoverableKeyException
     {
-
         if (args.length != 4)
         {
             usage();

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=1707879&r1=1707878&r2=1707879&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 Sat Oct 10 13:58:07 2015
@@ -26,13 +26,28 @@ import java.net.URL;
 import java.security.GeneralSecurityException;
 import java.security.KeyStore;
 import java.security.MessageDigest;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSString;
 
 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.pdfbox.pdmodel.PDDocument;
 import org.apache.wink.client.MockHttpServer;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.SignerInformation;
+import org.bouncycastle.operator.OperatorCreationException;
 import org.bouncycastle.tsp.TSPValidationException;
+import org.bouncycastle.util.Store;
 
 /**
  * Test for CreateSignature
@@ -44,20 +59,27 @@ public class TestCreateSignature extends
     private final String keystorePath = inDir + "keystore.p12";
     private final String jpegPath = inDir + "stamp.jpg";
     private final String password = "123456";
+    private Certificate certificate;
 
     @Override
     protected void setUp() throws Exception
     {
         super.setUp();
         new File("target/test-output").mkdirs();
+        
+        KeyStore keystore = KeyStore.getInstance("PKCS12");
+        keystore.load(new FileInputStream(keystorePath), password.toCharArray());
+        certificate = keystore.getCertificateChain(keystore.aliases().nextElement())[0];
     }
 
     /**
      * Signs a PDF using the "adbe.pkcs7.detached" SubFilter with the SHA-256 digest.
+     *
      * @throws IOException
      * @throws GeneralSecurityException
      */
-    public void testDetachedSHA256() throws IOException, GeneralSecurityException
+    public void testDetachedSHA256()
+            throws IOException, CMSException, OperatorCreationException, GeneralSecurityException
     {
         // load the keystore
         KeyStore keystore = KeyStore.getInstance("PKCS12");
@@ -67,22 +89,23 @@ public class TestCreateSignature extends
         CreateSignature signing = new CreateSignature(keystore, password.toCharArray());
         signing.signDetached(new File(inDir + "sign_me.pdf"), new File(outDir + "signed.pdf"));
 
-        // TODO verify the signed PDF file
+        checkSignature(new File(outDir + "signed.pdf"));
     }
 
     /**
-     * Signs a PDF using the "adbe.pkcs7.detached" SubFilter with the SHA-256 digest and
-     * a signed timestamp from a Time Stamping Authority (TSA) server.
+     * Signs a PDF using the "adbe.pkcs7.detached" SubFilter with the SHA-256 digest and a signed
+     * timestamp from a Time Stamping Authority (TSA) server.
      *
-     * This is not a complete test because we don't have the ability to return a valid
-     * response, so we return a cached response which is well-formed, but does not match
-     * the timestamp or nonce in the request. This allows us to test the basic TSA mechanism
-     * and test the nonce, which is a good start.
+     * This is not a complete test because we don't have the ability to return a valid response, so
+     * we return a cached response which is well-formed, but does not match the timestamp or nonce
+     * in the request. This allows us to test the basic TSA mechanism and test the nonce, which is a
+     * good start.
      *
      * @throws IOException
      * @throws GeneralSecurityException
      */
-    public void testDetachedSHA256WithTSA() throws IOException, GeneralSecurityException
+    public void testDetachedSHA256WithTSA()
+            throws IOException, CMSException, OperatorCreationException, GeneralSecurityException
     {
         // mock TSA response content
         InputStream input = new FileInputStream(inDir + "tsa_response.asn1");
@@ -121,6 +144,7 @@ public class TestCreateSignature extends
         }
 
         // TODO verify the signed PDF file
+        // TODO create a file signed with TSA
     }
     
     /**
@@ -129,7 +153,8 @@ public class TestCreateSignature extends
      * @throws IOException
      * @throws GeneralSecurityException
      */
-    public void testCreateVisibleSignature() throws IOException, GeneralSecurityException
+    public void testCreateVisibleSignature()
+            throws IOException, CMSException, OperatorCreationException, GeneralSecurityException
     {
         // load the keystore
         KeyStore keystore = KeyStore.getInstance("PKCS12");
@@ -139,10 +164,64 @@ public class TestCreateSignature extends
         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"));
+        signing.setVisibleSignatureProperties(inPath, 0, 0, -50, fis, 1);
+        signing.setSignatureProperties("name", "location", "Security", 0, 1, true);
+        File destFile = new File(outDir + "signed_visible.pdf");
+        signing.signPDF(new File(inPath), destFile);
 
-        // TODO verify the signed PDF file
+        checkSignature(destFile);
+    }
+
+    //TODO expand this into a full verify (if possible)
+    // This check fails with a file created with the code before PDFBOX-3011 was solved.
+    private void checkSignature(File file)
+            throws IOException, CMSException, OperatorCreationException, GeneralSecurityException
+    {
+        PDDocument document = PDDocument.load(file);
+        COSDictionary trailer = document.getDocument().getTrailer();
+        COSDictionary root = (COSDictionary) trailer.getDictionaryObject(COSName.ROOT);
+        COSDictionary acroForm = (COSDictionary) root.getDictionaryObject(COSName.ACRO_FORM);
+        COSArray fields = (COSArray) acroForm.getDictionaryObject(COSName.FIELDS);
+        COSDictionary sig = null;
+        for (int i = 0; i < fields.size(); i++)
+        {
+            COSDictionary field = (COSDictionary) fields.getObject(i);
+            if (COSName.SIG.equals(field.getCOSName(COSName.FT)))
+            {
+                sig = (COSDictionary) field.getDictionaryObject(COSName.V);
+
+                COSString contents = (COSString) sig.getDictionaryObject(COSName.CONTENTS);
+                // inspiration:
+                // http://stackoverflow.com/a/26702631/535646
+                CMSSignedData signedData = new CMSSignedData(contents.getBytes());
+                Store certificatesStore = signedData.getCertificates();
+                Collection<SignerInformation> signers = signedData.getSignerInfos().getSigners();
+                SignerInformation signerInformation = signers.iterator().next();
+
+                Collection matches = certificatesStore.getMatches(signerInformation.getSID());
+                X509CertificateHolder certificateHolder = (X509CertificateHolder) matches.iterator().next();
+                X509Certificate certFromSignedData = new JcaX509CertificateConverter().getCertificate(certificateHolder);
+                
+                assertEquals(certificate, certFromSignedData);
+
+                // code below doesn't work - maybe because the signature can indeed not be verified?
+                
+//                if (signerInformation.verify(new JcaSimpleSignerInfoVerifierBuilder().build(certFromSignedData)))
+//                {
+//                    System.out.println("Signature verified");
+//                }
+//                else
+//                {
+//                    System.out.println("Signature verification failed");
+//                }
+
+                break;
+            }
+        }
+        if (sig == null)
+        {
+            fail("no signature found");
+        }
+        document.close();
     }
 }