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 2020/07/20 17:09:28 UTC

svn commit: r1880082 - in /pdfbox/branches/issue45/examples/src: main/java/org/apache/pdfbox/examples/signature/ test/java/org/apache/pdfbox/examples/pdmodel/

Author: tilman
Date: Mon Jul 20 17:09:27 2020
New Revision: 1880082

URL: http://svn.apache.org/viewvc?rev=1880082&view=rev
Log:
PDFBOX-3017: verify certificate chain of timeStamp certificate in test + DRY refactoring

Modified:
    pdfbox/branches/issue45/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java
    pdfbox/branches/issue45/examples/src/main/java/org/apache/pdfbox/examples/signature/SigUtils.java
    pdfbox/branches/issue45/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java

Modified: pdfbox/branches/issue45/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java?rev=1880082&r1=1880081&r2=1880082&view=diff
==============================================================================
--- pdfbox/branches/issue45/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java (original)
+++ pdfbox/branches/issue45/examples/src/main/java/org/apache/pdfbox/examples/signature/ShowSignature.java Mon Jul 20 17:09:27 2020
@@ -34,9 +34,7 @@ import java.security.cert.X509Certificat
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Date;
 import java.util.HashSet;
-import java.util.Set;
 import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDictionary;
@@ -233,7 +231,7 @@ public final class ShowSignature
                                 {
                                     @SuppressWarnings("unchecked")
                                     Store<X509CertificateHolder> store = new JcaCertStore(certs);
-                                    verifyCertificateChain(store, cert, sig.getSignDate().getTime());
+                                    SigUtils.verifyCertificateChain(store, cert, sig.getSignDate().getTime());
                                 }
                             }
                         }
@@ -378,7 +376,7 @@ public final class ShowSignature
         X509Certificate certFromTimeStamp = (X509Certificate) certs.iterator().next();
         SigUtils.checkTimeStampCertificateUsage(certFromTimeStamp);
         SigUtils.validateTimestampToken(timeStampToken);
-                verifyCertificateChain(timeStampToken.getCertificates(),
+                SigUtils.verifyCertificateChain(timeStampToken.getCertificates(),
                 certFromTimeStamp,
                 timeStampToken.getTimeStampInfo().getGenTime());
     }
@@ -448,7 +446,7 @@ public final class ShowSignature
             HashSet<X509CertificateHolder> certificateHolderSet = new HashSet<X509CertificateHolder>();
             certificateHolderSet.addAll(certificatesStore.getMatches(null));
             certificateHolderSet.addAll(timeStampToken.getCertificates().getMatches(null));
-            verifyCertificateChain(new CollectionStore<X509CertificateHolder>(certificateHolderSet),
+            SigUtils.verifyCertificateChain(new CollectionStore<X509CertificateHolder>(certificateHolderSet),
                     certFromTimeStamp,
                     timeStampToken.getTimeStampInfo().getGenTime());
             SigUtils.checkTimeStampCertificateUsage(certFromTimeStamp);
@@ -532,7 +530,7 @@ public final class ShowSignature
 
             if (sig.getSignDate() != null)
             {
-                verifyCertificateChain(certificatesStore, certFromSignedData, sig.getSignDate().getTime());
+                SigUtils.verifyCertificateChain(certificatesStore, certFromSignedData, sig.getSignDate().getTime());
             }
             else
             {
@@ -541,32 +539,6 @@ public final class ShowSignature
         }
     }
 
-    private void verifyCertificateChain(Store<X509CertificateHolder> certificatesStore,
-            X509Certificate certFromSignedData, Date signDate)
-            throws CertificateVerificationException, CertificateException
-    {
-        // Verify certificate chain (new since 11/2018)
-        // Please post bad PDF files that succeed and
-        // good PDF files that fail in
-        // https://issues.apache.org/jira/browse/PDFBOX-3017
-        Collection<X509CertificateHolder> certificateHolders = certificatesStore.getMatches(null);
-        Set<X509Certificate> additionalCerts = new HashSet<X509Certificate>();
-        JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter();
-        for (X509CertificateHolder certHolder : certificateHolders)
-        {
-            X509Certificate certificate = certificateConverter.getCertificate(certHolder);
-            if (!certificate.equals(certFromSignedData))
-            {
-                additionalCerts.add(certificate);
-            }
-        }
-        CertificateVerifier.verifyCertificate(certFromSignedData, additionalCerts, true, signDate);
-        //TODO check whether the root certificate is in our trusted list.
-        // For the EU, get a list here:
-        // https://ec.europa.eu/digital-single-market/en/eu-trusted-lists-trust-service-providers
-        // ( getRootCertificates() is not helpful because these are SSL certificates)
-    }
-
     /**
      * Analyzes the DSS-Dictionary (Document Security Store) of the document. Which is used for
      * signature validation. The DSS is defined in PAdES Part 4 - Long Term Validation.

Modified: pdfbox/branches/issue45/examples/src/main/java/org/apache/pdfbox/examples/signature/SigUtils.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/examples/src/main/java/org/apache/pdfbox/examples/signature/SigUtils.java?rev=1880082&r1=1880081&r2=1880082&view=diff
==============================================================================
--- pdfbox/branches/issue45/examples/src/main/java/org/apache/pdfbox/examples/signature/SigUtils.java (original)
+++ pdfbox/branches/issue45/examples/src/main/java/org/apache/pdfbox/examples/signature/SigUtils.java Mon Jul 20 17:09:27 2020
@@ -21,7 +21,10 @@ import java.security.cert.CertificateExc
 import java.security.cert.CertificateParsingException;
 import java.security.cert.X509Certificate;
 import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
 import org.apache.commons.logging.Log;
@@ -30,6 +33,8 @@ import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.examples.signature.cert.CertificateVerificationException;
+import org.apache.pdfbox.examples.signature.cert.CertificateVerifier;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.encryption.SecurityProvider;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
@@ -39,6 +44,7 @@ import org.bouncycastle.asn1.cms.Attribu
 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.asn1.x509.KeyPurposeId;
 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;
@@ -48,6 +54,7 @@ import org.bouncycastle.operator.Operato
 import org.bouncycastle.tsp.TSPException;
 import org.bouncycastle.tsp.TimeStampToken;
 import org.bouncycastle.util.Selector;
+import org.bouncycastle.util.Store;
 
 /**
  * Utility class for the signature / timestamp examples.
@@ -286,4 +293,43 @@ public class SigUtils
                 new JcaSimpleSignerInfoVerifierBuilder().setProvider(SecurityProvider.getProvider()).build(certificateHolder);
         timeStampToken.validate(siv);
     }
+
+
+    /**
+     * Verify the certificate chain up to the root, including OCSP or CRL. However this does not
+     * test whether the root certificate is in a trusted list.<br><br>
+     * Please post bad PDF files that succeed and good PDF files that fail in
+     * <a href="https://issues.apache.org/jira/browse/PDFBOX-3017">PDFBOX-3017</a>.
+     *
+     * @param certificatesStore
+     * @param certFromSignedData
+     * @param signDate
+     * @throws CertificateVerificationException
+     * @throws CertificateException
+     */
+    public static void verifyCertificateChain(Store<X509CertificateHolder> certificatesStore,
+            X509Certificate certFromSignedData, Date signDate)
+            throws CertificateVerificationException, CertificateException
+    {
+        // Verify certificate chain (new since 10/2018)
+        // Please post bad PDF files that succeed and
+        // good PDF files that fail in
+        // https://issues.apache.org/jira/browse/PDFBOX-3017
+        Collection<X509CertificateHolder> certificateHolders = certificatesStore.getMatches(null);
+        Set<X509Certificate> additionalCerts = new HashSet<X509Certificate>();
+        JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter();
+        for (X509CertificateHolder certHolder : certificateHolders)
+        {
+            X509Certificate certificate = certificateConverter.getCertificate(certHolder);
+            if (!certificate.equals(certFromSignedData))
+            {
+                additionalCerts.add(certificate);
+            }
+        }
+        CertificateVerifier.verifyCertificate(certFromSignedData, additionalCerts, true, signDate);
+        //TODO check whether the root certificate is in our trusted list.
+        // For the EU, get a list here:
+        // https://ec.europa.eu/digital-single-market/en/eu-trusted-lists-trust-service-providers
+        // ( getRootCertificates() is not helpful because these are SSL certificates)
+    }
 }

Modified: pdfbox/branches/issue45/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java?rev=1880082&r1=1880081&r2=1880082&view=diff
==============================================================================
--- pdfbox/branches/issue45/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java (original)
+++ pdfbox/branches/issue45/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java Mon Jul 20 17:09:27 2020
@@ -30,9 +30,11 @@ import java.security.KeyStoreException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
+import java.security.Security;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
 import java.text.MessageFormat;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -51,10 +53,12 @@ import org.apache.pdfbox.examples.signat
 import org.apache.pdfbox.examples.signature.CreateSignature;
 import org.apache.pdfbox.examples.signature.CreateVisibleSignature;
 import org.apache.pdfbox.examples.signature.SigUtils;
+import org.apache.pdfbox.examples.signature.cert.CertificateVerificationException;
 import org.apache.pdfbox.io.IOUtils;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.PDPageContentStream;
+import org.apache.pdfbox.pdmodel.encryption.SecurityProvider;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.ExternalSigningSupport;
 import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
 import org.apache.pdfbox.pdmodel.interactive.form.PDField;
@@ -62,6 +66,7 @@ import org.apache.pdfbox.rendering.PDFRe
 import org.apache.pdfbox.util.Hex;
 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.CMSProcessableByteArray;
 import org.bouncycastle.cms.CMSSignedData;
@@ -72,6 +77,7 @@ import org.bouncycastle.operator.Operato
 import org.bouncycastle.tsp.TSPException;
 import org.bouncycastle.tsp.TSPValidationException;
 import org.bouncycastle.tsp.TimeStampToken;
+import org.bouncycastle.tsp.TimeStampTokenInfo;
 import org.bouncycastle.util.Selector;
 import org.bouncycastle.util.Store;
 import org.junit.Assert;
@@ -111,6 +117,8 @@ public class TestCreateSignature
     @BeforeClass
     public static void init() throws Exception
     {
+        Security.addProvider(SecurityProvider.getProvider());
+
         new File("target/test-output").mkdirs();
 
         KeyStore keystore = KeyStore.getInstance("PKCS12");
@@ -131,7 +139,7 @@ public class TestCreateSignature
     @Test
     public void testDetachedSHA256()
             throws IOException, CMSException, OperatorCreationException, GeneralSecurityException,
-                   TSPException
+                   TSPException, CertificateVerificationException
     {
         // load the keystore
         KeyStore keystore = KeyStore.getInstance("PKCS12");
@@ -177,7 +185,7 @@ public class TestCreateSignature
     @Test
     public void testDetachedSHA256WithTSA()
             throws IOException, CMSException, OperatorCreationException, GeneralSecurityException,
-                   TSPException
+                   TSPException, CertificateVerificationException
     {
         // mock TSA response content
         InputStream input = new FileInputStream(inDir + "tsa_response.asn1");
@@ -242,7 +250,7 @@ public class TestCreateSignature
     @Test
     public void testCreateVisibleSignature()
             throws IOException, CMSException, OperatorCreationException, GeneralSecurityException,
-                   TSPException
+                   TSPException, CertificateVerificationException
     {
         // load the keystore
         KeyStore keystore = KeyStore.getInstance("PKCS12");
@@ -281,7 +289,7 @@ public class TestCreateSignature
     public void testPDFBox3978() throws IOException, NoSuchAlgorithmException, KeyStoreException, 
                                         CertificateException, UnrecoverableKeyException, 
                                         CMSException, OperatorCreationException, GeneralSecurityException,
-                                        TSPException
+                                        TSPException, CertificateVerificationException
     {
         String filename        = outDir + "EmptySignatureForm.pdf";
         String filenameSigned1 = outDir + "EmptySignatureForm-signed1.pdf";
@@ -336,7 +344,7 @@ public class TestCreateSignature
     // This check fails with a file created with the code before PDFBOX-3011 was solved.
     private void checkSignature(File origFile, File signedFile, boolean checkTimeStamp)
             throws IOException, CMSException, OperatorCreationException, GeneralSecurityException,
-            TSPException
+            TSPException, CertificateVerificationException
     {
         PDDocument document = PDDocument.load(origFile);
         // get string representation of pages COSObject
@@ -396,11 +404,23 @@ public class TestCreateSignature
                 Assert.assertNotNull(timeStampToken);
                 SigUtils.validateTimestampToken(timeStampToken);
 
+                TimeStampTokenInfo timeStampInfo = timeStampToken.getTimeStampInfo();
+
                 // compare the hash of the signed content with the hash in the timestamp
-                byte[] tsMessageImprintDigest = timeStampToken.getTimeStampInfo().getMessageImprintDigest();
-                String hashAlgorithm = timeStampToken.getTimeStampInfo().getMessageImprintAlgOID().getId();
+                byte[] tsMessageImprintDigest = timeStampInfo.getMessageImprintDigest();
+                String hashAlgorithm = timeStampInfo.getMessageImprintAlgOID().getId();
                 byte[] sigMessageImprintDigest = MessageDigest.getInstance(hashAlgorithm).digest(signerInformation.getSignature());
                 Assert.assertArrayEquals("timestamp signature verification failed", sigMessageImprintDigest, tsMessageImprintDigest);
+
+                Store<X509CertificateHolder> tsCertStore = timeStampToken.getCertificates();
+
+                // get the certificate from the timeStampToken
+                Collection<X509CertificateHolder> tsCertStoreMatches = tsCertStore.getMatches(null);
+                X509CertificateHolder certHolderFromTimeStamp = tsCertStoreMatches.iterator().next();
+                X509Certificate certFromTimeStamp = new JcaX509CertificateConverter().getCertificate(certHolderFromTimeStamp);
+
+                SigUtils.checkTimeStampCertificateUsage(certFromTimeStamp);
+                SigUtils.verifyCertificateChain(tsCertStore, certFromTimeStamp, timeStampInfo.getGenTime());
             }
             else
             {