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/04/22 19:48:07 UTC

svn commit: r1876850 - /pdfbox/branches/issue45/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java

Author: tilman
Date: Wed Apr 22 19:48:07 2020
New Revision: 1876850

URL: http://svn.apache.org/viewvc?rev=1876850&view=rev
Log:
PDFBOX-3017: add methods to verify timestamp signature

Modified:
    pdfbox/branches/issue45/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java

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=1876850&r1=1876849&r2=1876850&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 Wed Apr 22 19:48:07 2020
@@ -50,19 +50,27 @@ 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.PDSignature;
 import org.apache.pdfbox.pdmodel.interactive.form.PDField;
 import org.apache.pdfbox.rendering.PDFRenderer;
 import org.apache.pdfbox.util.Hex;
 import org.apache.wink.client.MockHttpServer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.cms.Attribute;
+import org.bouncycastle.asn1.cms.AttributeTable;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
 import org.bouncycastle.cert.X509CertificateHolder;
 import org.bouncycastle.cms.CMSException;
 import org.bouncycastle.cms.CMSProcessableByteArray;
 import org.bouncycastle.cms.CMSSignedData;
 import org.bouncycastle.cms.SignerInformation;
+import org.bouncycastle.cms.SignerInformationVerifier;
 import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
 import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.tsp.TSPException;
 import org.bouncycastle.tsp.TSPValidationException;
+import org.bouncycastle.tsp.TimeStampToken;
 import org.bouncycastle.util.Selector;
 import org.bouncycastle.util.Store;
 import org.junit.Assert;
@@ -115,10 +123,12 @@ public class TestCreateSignature
      * @throws GeneralSecurityException
      * @throws CMSException
      * @throws OperatorCreationException
+     * @throws TSPException
      */
     @Test
     public void testDetachedSHA256()
-            throws IOException, CMSException, OperatorCreationException, GeneralSecurityException
+            throws IOException, CMSException, OperatorCreationException, GeneralSecurityException,
+                   TSPException
     {
         // load the keystore
         KeyStore keystore = KeyStore.getInstance("PKCS12");
@@ -196,10 +206,12 @@ public class TestCreateSignature
      * @throws CMSException
      * @throws OperatorCreationException
      * @throws GeneralSecurityException
+     * @throws TSPException
      */
     @Test
     public void testCreateVisibleSignature()
-            throws IOException, CMSException, OperatorCreationException, GeneralSecurityException
+            throws IOException, CMSException, OperatorCreationException, GeneralSecurityException,
+                   TSPException
     {
         // load the keystore
         KeyStore keystore = KeyStore.getInstance("PKCS12");
@@ -231,12 +243,14 @@ public class TestCreateSignature
      * @throws UnrecoverableKeyException
      * @throws CMSException
      * @throws OperatorCreationException
-     * @throws GeneralSecurityException 
+     * @throws GeneralSecurityException
+     * @throws TSPException
      */
     @Test
     public void testPDFBox3978() throws IOException, NoSuchAlgorithmException, KeyStoreException, 
                                         CertificateException, UnrecoverableKeyException, 
-                                        CMSException, OperatorCreationException, GeneralSecurityException
+                                        CMSException, OperatorCreationException, GeneralSecurityException,
+                                        TSPException
     {
         String filename        = outDir + "EmptySignatureForm.pdf";
         String filenameSigned1 = outDir + "EmptySignatureForm-signed1.pdf";
@@ -290,7 +304,8 @@ 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)
-            throws IOException, CMSException, OperatorCreationException, GeneralSecurityException
+            throws IOException, CMSException, OperatorCreationException, GeneralSecurityException,
+            TSPException
     {
         PDDocument document = PDDocument.load(origFile);
         // get string representation of pages COSObject
@@ -343,10 +358,47 @@ public class TestCreateSignature
             {
                 Assert.fail("Signature verification failed");
             }
+
+            TimeStampToken timeStampToken = extractTimeStampTokenFromSignerInformation(signerInformation);
+            if (timeStampToken != null)
+            {
+                validateTimestampToken(timeStampToken);
+            }
         }
         document.close();
     }
 
+    private void validateTimestampToken(TimeStampToken timeStampToken)
+            throws TSPException, CertificateException, OperatorCreationException, IOException
+    {
+        // https://stackoverflow.com/questions/42114742/
+        @SuppressWarnings("unchecked") // TimeStampToken.getSID() is untyped
+        Collection<X509CertificateHolder> tstMatches =
+                timeStampToken.getCertificates().getMatches((Selector<X509CertificateHolder>) timeStampToken.getSID());
+        X509CertificateHolder holder = tstMatches.iterator().next();
+        SignerInformationVerifier siv = new JcaSimpleSignerInfoVerifierBuilder().setProvider(SecurityProvider.getProvider()).build(holder);
+        timeStampToken.validate(siv);
+    }
+
+    private TimeStampToken extractTimeStampTokenFromSignerInformation(SignerInformation signerInformation)
+            throws CMSException, IOException, TSPException
+    {
+        if (signerInformation.getUnsignedAttributes() == null)
+        {
+            return null;
+        }
+        AttributeTable unsignedAttributes = signerInformation.getUnsignedAttributes();
+        // https://stackoverflow.com/questions/1647759/how-to-validate-if-a-signed-jar-contains-a-timestamp
+        Attribute attribute = unsignedAttributes.get(PKCSObjectIdentifiers.id_aa_signatureTimeStampToken);
+        if (attribute == null)
+        {
+            return null;
+        }
+        ASN1Object obj = (ASN1Object) attribute.getAttrValues().getObjectAt(0);
+        CMSSignedData signedTSTData = new CMSSignedData(obj.getEncoded());
+        return new TimeStampToken(signedTSTData);
+    }
+
     private String calculateDigestString(InputStream inputStream) throws NoSuchAlgorithmException, IOException
     {
         MessageDigest md = MessageDigest.getInstance("SHA-256");