2014-03-03 110 views
1

我想使用pdfbox將多個簽名添加到我的pdf中,我嘗試使用兩個簽名,而第二個簽名總是變爲無效。請諮詢, 可以將PDF數字簽名數次? Adobe生命週期論壇說是。使用pdfbox的數字簽名

import java.io.File; 
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.security.KeyStore; 
import java.security.KeyStoreException; 
import java.security.NoSuchAlgorithmException; 
import java.security.PrivateKey; 
import java.security.UnrecoverableKeyException; 
import java.security.cert.CertStore; 
import java.security.cert.Certificate; 
import java.security.cert.CertificateException; 
import java.security.cert.CollectionCertStoreParameters; 
import java.security.cert.X509Certificate; 
import java.util.Arrays; 
import java.util.Calendar; 
import java.util.Enumeration; 
import java.util.List; 

import org.apache.pdfbox.exceptions.COSVisitorException; 
import org.apache.pdfbox.exceptions.SignatureException; 
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.cms.CMSException; 
import org.bouncycastle.cms.CMSProcessable; 
import org.bouncycastle.cms.CMSSignedData; 
import org.bouncycastle.cms.CMSSignedDataGenerator; 
import org.bouncycastle.cms.CMSSignedGenerator; 
import org.bouncycastle.jce.provider.BouncyCastleProvider; 

public class SigningTest implements SignatureInterface { 

    private static BouncyCastleProvider provider = new BouncyCastleProvider(); 

    private PrivateKey privKey; 

    private Certificate[] cert; 

    public SigningTest(KeyStore keystore, char[] pin) { 
     try { 
      Enumeration<String> aliases = keystore.aliases(); 
      String alias = null; 
      if (aliases.hasMoreElements()) 
       alias = aliases.nextElement(); 
      else 
       throw new RuntimeException("Could not find Key"); 
      privKey = (PrivateKey) keystore.getKey(alias, pin); 
      cert = keystore.getCertificateChain(alias); 
     } catch (KeyStoreException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (UnrecoverableKeyException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (NoSuchAlgorithmException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

    public byte[] sign(InputStream content) throws SignatureException, 
      IOException { 
     CMSProcessableInputStream input = new CMSProcessableInputStream(content); 
     CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); 
     // CertificateChain 
     List<Certificate> certList = Arrays.asList(cert); 

     CertStore certStore = null; 
     try { 
      certStore = CertStore.getInstance("Collection", 
        new CollectionCertStoreParameters(certList), provider); 
      gen.addSigner(privKey, (X509Certificate) certList.get(0), 
        CMSSignedGenerator.DIGEST_SHA256); 
      gen.addCertificatesAndCRLs(certStore); 
      CMSSignedData signedData = gen.generate(input, false, provider); 
      return signedData.getEncoded(); 
     } catch (Exception e) { 
      // should be handled 
      e.printStackTrace(); 
     } 
     throw new RuntimeException("Problem while preparing signature"); 
    } 

    public static void main(String[] args) throws KeyStoreException, 
      NoSuchAlgorithmException, CertificateException, 
      FileNotFoundException, IOException, COSVisitorException, 
      SignatureException, Exception { 
     File document = new File("resources/OCD.pdf"); 
     PDDocument pdDocument = PDDocument.load(document); 

     addSignature(pdDocument, "resources/j4l_test.p12", "test"); 
     addSignature(pdDocument, "resources/my.p12", "123456"); 

     File outputDocument = new File("resources/signed" + document.getName()); 
     FileInputStream fis = new FileInputStream(document); 
     FileOutputStream fos = new FileOutputStream(outputDocument); 
     byte[] buffer = new byte[8 * 1024]; 
     int c; 
     while ((c = fis.read(buffer)) != -1) 
     { 
      fos.write(buffer, 0, c); 
     } 
     fis.close(); 
     fis = new FileInputStream(outputDocument); 

     pdDocument.saveIncremental(fis, fos); 
     //pdDocument.close(); 

    } 




    static void addSignature(PDDocument pdDocument, String filePath,String pwd) throws Exception{ 
     File ksFile = new File(filePath); 
     KeyStore keystore = KeyStore.getInstance("PKCS12", provider); 
     char[] pin = pwd.toCharArray(); 
     keystore.load(new FileInputStream(ksFile), pin); 
     SigningTest signing = new SigningTest(keystore, pin.clone()); 
     //signing.signPDF(document); 

     // create signature dictionary 
     PDSignature signature = new PDSignature(); 
     signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); // default filter 
     // subfilter for basic and PAdES Part 2 signatures 
     signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED); 
     signature.setName("signer name"); 
     signature.setLocation("signer location"); 
     signature.setReason("reason for signature"); 

     // the signing date, needed for valid signature 
     signature.setSignDate(Calendar.getInstance()); 
//  SignatureOptions signatureOptions= new SignatureOptions(); 
//  signatureOptions.setVisualSignature(); 
     // register signature dictionary and sign interface 
     pdDocument.addSignature(signature, signing); 

    } 
} 

class CMSProcessableInputStream implements CMSProcessable { 

    InputStream in; 

    public CMSProcessableInputStream(InputStream is) { 
     in = is; 
    } 

    public Object getContent() { 
     return null; 
    } 

    public void write(OutputStream out) throws IOException, CMSException { 
     // read the content only one time 
     byte[] buffer = new byte[8 * 1024]; 
     int read; 
     while ((read = in.read(buffer)) != -1) { 
      out.write(buffer, 0, read); 
     } 
     in.close(); 
    } 
} 

回答

1

可以是一個PDF進行數字簽名幾次

是的,是可以的,但在連續的增量更新的情況發生,而不是在相同的版本。

你做

PDDocument pdDocument = PDDocument.load(document); 
addSignature(pdDocument, "resources/j4l_test.p12", "test"); 
addSignature(pdDocument, "resources/my.p12", "123456"); 
... 
pdDocument.saveIncremental(fis, fos); 

但你必須做

PDDocument pdDocument = PDDocument.load(document); 
addSignature(pdDocument, "resources/j4l_test.p12", "test"); 
... 
pdDocument.saveIncremental(fis, fos); // fos an intermediary file 

... 

pdDocument = PDDocument.load(intermediaryFile); 
addSignature(pdDocument, "resources/my.p12", "123456"); 
... 
pdDocument.saveIncremental(fis, fos); // fos the final file 

一些背景會this answer被發現,其中的鏈接。