在PdfBox中使用自签名数字标识签名的pdf为空

时间:2016-10-20 13:26:53

标签: pdfbox

我正在尝试使用pdfbox签署现有的pdf文档。我的类实现了SignatureInterface接口,使用bouncycastle作为提供者和存储在.jks文件中的自签名证书。但在输出中我得到一个空白页面。我的代码出了什么问题?

public class CreateSignature implements SignatureInterface {

private PrivateKey privateKey;
private Certificate[] cert;

private CreateSignature(KeyStore keyStore, String certPassword) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException {
    privateKey = (PrivateKey) keyStore.getKey("1", certPassword.toCharArray()); // "1" - alias default name
    cert = keyStore.getCertificateChain("1");
}

@Override
public byte[] sign(InputStream inputStream) throws IOException {

    byte[] c = IOUtils.toByteArray(inputStream);

    List<Certificate> certList = new ArrayList<>();
    certList.add(cert[0]);

    try {
        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(privateKey);

        gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).build(sha1Signer, new X509CertificateHolder(certificate)));
        gen.addCertificates(certs);

        CMSTypedData  msg = new CMSProcessableByteArray(c);
        CMSSignedData signedData = gen.generate(msg,false);

        return signedData.getEncoded();

    } catch (CertificateEncodingException | OperatorCreationException | CMSException e) {
        throw new RuntimeException(e);
    }

}

public static byte[] signPdfDocument(PDDocument document) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException {
    String keystorePassword = AppVars.getPdfCertificationKeystorePass();
    String adobeDigitalIDPassword = AppVars.getPdfCertificationAdobePass();
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(CreateSignature.class.getResourceAsStream("/pdf/certificate/SelfSignedCert.jks"), keystorePassword.toCharArray());

    CreateSignature singing = new CreateSignature(ks, adobeDigitalIDPassword);

    return singing.doSign(document);
}

private byte[] doSign(PDDocument document) throws IOException {
    PDSignature signature = new PDSignature();
    signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
    signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
    signature.setName("name");
    signature.setLocation("location");
    signature.setReason("reason");

    signature.setSignDate(Calendar.getInstance());

    document.addSignature(signature, this);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    document.saveIncremental(out);

    document.close();
    return out.toByteArray();
}

}

1 个答案:

答案 0 :(得分:0)

正如评论中所讨论的那样 - 原因是文档在加载后在应用程序本身中构建,而不是从PDF文件(或流)加载。增量签名不会识别这些更改,因此结果是加载时的PDF加上未显示的签名,可能因为文档甚至没有页面。放弃它的原因是签名的PDF比未签名的PDF要小得多。

解决方案是

  • 创建PDF,创建内容
  • 保存
  • 关闭它
  • 重新加载PDF并签名。