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
{