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:11 UTC
svn commit: r1876851 -
/pdfbox/trunk/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java
Author: tilman
Date: Wed Apr 22 19:48:10 2020
New Revision: 1876851
URL: http://svn.apache.org/viewvc?rev=1876851&view=rev
Log:
PDFBOX-3017: add methods to verify timestamp signature
Modified:
pdfbox/trunk/examples/src/test/java/org/apache/pdfbox/examples/pdmodel/TestCreateSignature.java
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=1876851&r1=1876850&r2=1876851&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 Wed Apr 22 19:48:10 2020
@@ -51,20 +51,28 @@ 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.annotation.PDAppearanceDictionary;
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;
@@ -118,10 +126,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");
@@ -150,6 +160,7 @@ public class TestCreateSignature
* @throws GeneralSecurityException
* @throws CMSException
* @throws OperatorCreationException
+ * @throws TSPException
*/
@Test
public void testDetachedSHA256WithTSA()
@@ -197,10 +208,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");
@@ -233,12 +246,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 = OUT_DIR + "EmptySignatureForm.pdf";
String filenameSigned1 = OUT_DIR + "EmptySignatureForm-signed1.pdf";
@@ -295,7 +310,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
{
String origPageKey;
try (PDDocument document = Loader.loadPDF(origFile))
@@ -350,10 +366,47 @@ public class TestCreateSignature
{
Assert.fail("Signature verification failed");
}
+
+ TimeStampToken timeStampToken = extractTimeStampTokenFromSignerInformation(signerInformation);
+ if (timeStampToken != null)
+ {
+ validateTimestampToken(timeStampToken);
+ }
}
}
}
+ 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");