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();
}
}