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/09 20:54:39 UTC
svn commit: r1707795 - in /pdfbox/trunk/examples/src:
main/java/org/apache/pdfbox/examples/signature/
test/java/org/apache/pdfbox/examples/pdmodel/
Author: tilman
Date: Fri Oct 9 18:54:39 2015
New Revision: 1707795
URL: http://svn.apache.org/viewvc?rev=1707795&view=rev
Log:
PDFBOX-3011: move common code to abstract base class; add test for visible signature
Added:
pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java (with props)
Modified:
pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java
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/CreateSignature.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java?rev=1707795&r1=1707794&r2=1707795&view=diff
==============================================================================
--- pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java (original)
+++ pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignature.java Fri Oct 9 18:54:39 2015
@@ -21,7 +21,6 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.security.GeneralSecurityException;
@@ -40,7 +39,6 @@ import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
-import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
@@ -50,20 +48,10 @@ import org.bouncycastle.asn1.cms.Attribu
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.cms.Attributes;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cert.jcajce.JcaCertStore;
-import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSSignedData;
-import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
-import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.tsp.TSPException;
-import org.bouncycastle.util.Store;
/**
* An example for singing a PDF with bouncy castle.
@@ -76,11 +64,8 @@ import org.bouncycastle.util.Store;
* @author Vakhtang Koroghlishvili
* @author John Hewson
*/
-public class CreateSignature implements SignatureInterface
+public class CreateSignature extends CreateSignatureBase
{
- private final PrivateKey privateKey;
- private final Certificate certificate;
- private TSAClient tsaClient;
/**
* Initialize the signature creator with a keystore and certficate password.
@@ -184,7 +169,8 @@ public class CreateSignature implements
* @param signedData -Generated CMS signed data
* @return CMSSignedData - Extended CMS signed data
*/
- private CMSSignedData signTimeStamps(CMSSignedData signedData)
+ @Override
+ protected CMSSignedData signTimeStamps(CMSSignedData signedData)
throws IOException, TSPException
{
SignerInformationStore signerStore = signedData.getSignerInfos();
@@ -235,57 +221,6 @@ public class CreateSignature implements
return newSigner;
}
- /**
- * SignatureInterface implementation.
- *
- * This method will be called from inside of the pdfbox and create the PKCS #7 signature.
- * The given InputStream contains the bytes that are given by the byte range.
- *
- * This method is for internal use only. <-- TODO this method should be private
- *
- * Use your favorite cryptographic library to implement PKCS #7 signature creation.
- */
- @Override
- public byte[] sign(InputStream content) throws IOException
- {
- try
- {
- List<Certificate> certList = new ArrayList<Certificate>();
- certList.add(certificate);
- Store certs = new JcaCertStore(certList);
- CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
- org.bouncycastle.asn1.x509.Certificate cert =
- org.bouncycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(certificate.getEncoded()));
- ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA256WithRSA").build(privateKey);
- gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
- new JcaDigestCalculatorProviderBuilder().build()).build(sha1Signer, new X509CertificateHolder(cert)));
- gen.addCertificates(certs);
- CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
- CMSSignedData signedData = gen.generate(msg, false);
- if (tsaClient != null)
- {
- signedData = signTimeStamps(signedData);
- }
- return signedData.getEncoded();
- }
- catch (GeneralSecurityException e)
- {
- throw new IOException(e);
- }
- catch (CMSException e)
- {
- throw new IOException(e);
- }
- catch (TSPException e)
- {
- throw new IOException(e);
- }
- catch (OperatorCreationException e)
- {
- throw new IOException(e);
- }
- }
-
public static void main(String[] args) throws IOException, GeneralSecurityException
{
if (args.length < 3)
Added: pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java?rev=1707795&view=auto
==============================================================================
--- pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java (added)
+++ pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java Fri Oct 9 18:54:39 2015
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.pdfbox.examples.signature;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaCertStore;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.CMSSignedDataGenerator;
+import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
+import org.bouncycastle.tsp.TSPException;
+import org.bouncycastle.util.Store;
+
+public abstract class CreateSignatureBase implements SignatureInterface
+{
+ protected PrivateKey privateKey;
+ protected Certificate certificate;
+ protected TSAClient tsaClient;
+
+ /**
+ * Does nothing. Override this if needed.
+ *
+ * @param signedData Generated CMS signed data
+ * @return CMSSignedData Extended CMS signed data
+ */
+ protected CMSSignedData signTimeStamps(CMSSignedData signedData) throws IOException, TSPException
+ {
+ return signedData;
+ }
+
+ /**
+ * SignatureInterface implementation.
+ *
+ * This method will be called from inside of the pdfbox and create the PKCS #7 signature.
+ * The given InputStream contains the bytes that are given by the byte range.
+ *
+ * This method is for internal use only. <-- TODO this method should be private
+ *
+ * Use your favorite cryptographic library to implement PKCS #7 signature creation.
+ */
+ @Override
+ public byte[] sign(InputStream content) throws IOException
+ {
+ try
+ {
+ List<Certificate> certList = new ArrayList<Certificate>();
+ certList.add(certificate);
+ Store certs = new JcaCertStore(certList);
+ CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+ org.bouncycastle.asn1.x509.Certificate cert = org.bouncycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(certificate.getEncoded()));
+ ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA256WithRSA").build(privateKey);
+ gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).build(sha1Signer, new X509CertificateHolder(cert)));
+ gen.addCertificates(certs);
+ CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
+ CMSSignedData signedData = gen.generate(msg, false);
+ if (tsaClient != null)
+ {
+ signedData = signTimeStamps(signedData);
+ }
+ return signedData.getEncoded();
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new IOException(e);
+ }
+ catch (CMSException e)
+ {
+ throw new IOException(e);
+ }
+ catch (TSPException e)
+ {
+ throw new IOException(e);
+ }
+ catch (OperatorCreationException e)
+ {
+ throw new IOException(e);
+ }
+ }
+
+}
Propchange: pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateSignatureBase.java
------------------------------------------------------------------------------
svn:eol-style = native
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=1707795&r1=1707794&r2=1707795&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 Fri Oct 9 18:54:39 2015
@@ -20,40 +20,23 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.security.KeyStore;
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.CertificateEncodingException;
import java.security.cert.CertificateException;
-import java.util.ArrayList;
import java.util.Calendar;
import java.util.Enumeration;
-import java.util.List;
import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
-import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner;
-import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cert.jcajce.JcaCertStore;
-import org.bouncycastle.cms.CMSException;
-import org.bouncycastle.cms.CMSSignedData;
-import org.bouncycastle.cms.CMSSignedDataGenerator;
-import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
-import org.bouncycastle.util.Store;
/**
* This is an example for visual signing a pdf with bouncy castle.
@@ -61,12 +44,10 @@ import org.bouncycastle.util.Store;
* @see CreateSignature
* @author Vakhtang Koroghlishvili
*/
-public class CreateVisibleSignature implements SignatureInterface
+public class CreateVisibleSignature extends CreateSignatureBase
{
private static final BouncyCastleProvider BCPROVIDER = new BouncyCastleProvider();
- private final PrivateKey privKey;
- private final Certificate[] cert;
private SignatureOptions options;
/**
@@ -92,34 +73,29 @@ public class CreateVisibleSignature impl
{
throw new IOException("Could not find alias");
}
- privKey = (PrivateKey) keystore.getKey(alias, pin);
- cert = keystore.getCertificateChain(alias);
+ privateKey = (PrivateKey) keystore.getKey(alias, pin);
+ certificate = keystore.getCertificateChain(alias)[0];
}
/**
* Sign pdf file and create new file that ends with "_signed.pdf".
*
- * @param documentFile The source pdf document file.
- * @param signatureProperties The signature properties.
- * @return the signed pdf document file.
+ * @param inputFile The source pdf document file.
+ * @param signedFile The file to be signed.
* @throws IOException
*/
- public File signPDF(File documentFile, PDVisibleSigProperties signatureProperties) throws IOException
+ public void signPDF(File inputFile, File signedFile) throws IOException
{
- if (documentFile == null || !documentFile.exists())
+ if (inputFile == null || !inputFile.exists())
{
throw new IOException("Document for signing does not exist");
}
// creating output document and prepare the IO streams.
- String name = documentFile.getName();
- String substring = name.substring(0, name.lastIndexOf('.'));
-
- File outputDocumentFile = new File(documentFile.getParent(), substring + "_signed.pdf");
- FileOutputStream fos = new FileOutputStream(outputDocumentFile);
+ FileOutputStream fos = new FileOutputStream(signedFile);
// load document
- PDDocument doc = PDDocument.load(documentFile);
+ PDDocument doc = PDDocument.load(inputFile);
// create signature dictionary
PDSignature signature = new PDSignature();
@@ -152,51 +128,25 @@ public class CreateVisibleSignature impl
// do not close options before saving, because some COSStream objects within options
// are transferred to the signed document.
IOUtils.closeQuietly(options);
-
- return outputDocumentFile;
}
- /**
- * SignatureInterface implementation.
- *
- * This method will be called from inside of the pdfbox and create the pkcs7 signature.
- * The given InputStream contains the bytes that are given by the byte range.
- *
- * This method is for internal use only. <-- TODO this method should be private
- *
- * Use your favorite cryptographic library to implement pkcs7 signature creation.
- */
- @Override
- public byte[] sign(InputStream content) throws IOException
+ PDVisibleSignDesigner visibleSignDesigner;
+ PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties();
+
+ public void setVisibleSignatureProperties(String filename, int x, int y, int zoomPercent,
+ FileInputStream image, int page)
+ throws IOException
{
- try
- {
- List<Certificate> certList = new ArrayList<Certificate>();
- certList.add(cert[0]);
- Store certs = new JcaCertStore(certList);
- CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
- org.bouncycastle.asn1.x509.Certificate certificate =
- org.bouncycastle.asn1.x509.Certificate.getInstance(ASN1Primitive.fromByteArray(cert[0].getEncoded()));
- ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA256WithRSA").build(privKey);
- gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
- new JcaDigestCalculatorProviderBuilder().build()).build(sha1Signer, new X509CertificateHolder(certificate)));
- gen.addCertificates(certs);
- CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
- CMSSignedData signedData = gen.generate(msg, false);
- return signedData.getEncoded();
- }
- catch (CertificateEncodingException e)
- {
- throw new IOException(e);
- }
- catch (CMSException e)
- {
- throw new IOException(e);
- }
- catch (OperatorCreationException e)
- {
- throw new IOException(e);
- }
+ visibleSignDesigner = new PDVisibleSignDesigner(filename, image, page);
+ visibleSignDesigner.xAxis(x).yAxis(y).zoom(zoomPercent).signatureFieldName("signature");
+ }
+
+ public void setSignatureProperties(String name, String location, String reason, int preferredSize,
+ int page, boolean visualSignEnabled) throws IOException
+ {
+ signatureProperties.signerName(name).signerLocation(location).signatureReason(reason).
+ preferredSize(preferredSize).page(page).visualSignEnabled(visualSignEnabled).
+ setPdVisibleSignature(visibleSignDesigner).buildSignature();
}
/**
@@ -222,21 +172,19 @@ public class CreateVisibleSignature impl
char[] pin = args[1].toCharArray();
keystore.load(new FileInputStream(ksFile), pin);
- File document = new File(args[2]);
+ File documentFile = new File(args[2]);
CreateVisibleSignature signing = new CreateVisibleSignature(keystore, pin.clone());
FileInputStream image = new FileInputStream(args[3]);
-
- PDVisibleSignDesigner visibleSig = new PDVisibleSignDesigner(args[2], image, 1);
- visibleSig.xAxis(0).yAxis(0).zoom(-50).signatureFieldName("signature");
-
- PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties();
-
- signatureProperties.signerName("name").signerLocation("location").signatureReason("Security").preferredSize(0)
- .page(1).visualSignEnabled(true).setPdVisibleSignature(visibleSig).buildSignature();
-
- signing.signPDF(document, signatureProperties);
+
+ String name = documentFile.getName();
+ String substring = name.substring(0, name.lastIndexOf('.'));
+ File signedDocumentFile = new File(documentFile.getParent(), substring + "_signed.pdf");
+
+ signing.setVisibleSignatureProperties (args[2], 0, 0, -50, image, 1);
+ signing.setSignatureProperties ("name", "location", "Security", 0, 1, true);
+ signing.signPDF(documentFile, signedDocumentFile);
}
}
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=1707795&r1=1707794&r2=1707795&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 Fri Oct 9 18:54:39 2015
@@ -17,11 +17,6 @@
package org.apache.pdfbox.examples.pdmodel;
import junit.framework.TestCase;
-import org.apache.pdfbox.examples.signature.CreateSignature;
-import org.apache.pdfbox.examples.signature.TSAClient;
-import org.apache.pdfbox.io.IOUtils;
-import org.apache.wink.client.MockHttpServer;
-import org.bouncycastle.tsp.TSPValidationException;
import java.io.File;
import java.io.FileInputStream;
@@ -32,6 +27,13 @@ import java.security.GeneralSecurityExce
import java.security.KeyStore;
import java.security.MessageDigest;
+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.wink.client.MockHttpServer;
+import org.bouncycastle.tsp.TSPValidationException;
+
/**
* Test for CreateSignature
*/
@@ -40,6 +42,7 @@ public class TestCreateSignature extends
private final String inDir = "src/test/resources/org/apache/pdfbox/examples/signature/";
private final String outDir = "target/test-output/";
private final String keystorePath = inDir + "keystore.p12";
+ private final String jpegPath = inDir + "stamp.jpg";
private final String password = "123456";
@Override
@@ -119,4 +122,27 @@ public class TestCreateSignature extends
// TODO verify the signed PDF file
}
+
+ /**
+ * Test creating visual signature.
+ *
+ * @throws IOException
+ * @throws GeneralSecurityException
+ */
+ public void testCreateVisibleSignature() throws IOException, GeneralSecurityException
+ {
+ // load the keystore
+ KeyStore keystore = KeyStore.getInstance("PKCS12");
+ keystore.load(new FileInputStream(keystorePath), password.toCharArray());
+
+ // sign PDF
+ 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"));
+
+ // TODO verify the signed PDF file
+ }
}