电子签章: 数字签名过后的PDF,导入根证书后,用阅读器查看还是签名未知

ditf
  • 6

题目描述

想弄一个电子签章的东西,目的是对pdf文档签名,然后验签。采用itext7来实现,pdf浏览软件用的福昕阅读器。

题目来源及自己的思路

业务场景是每个用户都有自己的证书文件,然后希望用户查看自己或其他人签名的pdf的时候,能证明签名是有效的,并且只通过1个根证书来完成。

参考了下网上的资料。以下证书的生成都是采用的keytool工具。

  1. 创建一个自签名的证书(类似CA?)。
  2. 生成一个人员的证书。
  3. 生成该人员证书对应的证书请求文件。
  4. 然后通过步骤1生成的根证书并对其签名,得到一个证书文件(发布者就变了)。
  5. 通过itext来对pdf文件进行签名。
  6. 导出第一步的证书(根证书),添加到pdf阅读器受信任的证书列表中,然后查看pdf。

相关代码

粘贴代码文本(请勿用截图)

  1. keytool生成证书。
  2. itext对pdf签名:

    修改自itext的demo

    public class C4_07_ClientServerSigning {
    public static final String DEST = "/Users/xxx/Downloads/";
    public static final String SRC = "/Users/xxx/Downloads/ApplicationForm.pdf";
    public static final String CERT = "/Users/xxx/Documents/csr/pdf/aaa.cer";
    public static final String KEYSTORE = "/Users/xxx/Documents/csr/pdf/aaa.keystore";
    public static final char[] PASSWORD = "123456".toCharArray();
    public static final String[] RESULT_FILES = new String[] {
            "hello_server.pdf"
 };
    public static void main(String[] args) throws GeneralSecurityException, IOException {
        File file = new File(DEST);
        file.mkdirs();
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        Certificate[] chain = new Certificate[1];
        chain[0] = factory.generateCertificate(new FileInputStream(CERT));
        new C4_07_ClientServerSigning2().sign(SRC, DEST + RESULT_FILES[0], chain, PdfSigner.CryptoStandard.CMS,
                "Test", "Ghent");
    }
    public void sign(String src, String dest, Certificate[] chain, PdfSigner.CryptoStandard subfilter,
                     String reason, String location) throws GeneralSecurityException, IOException {
        PdfReader reader = new PdfReader(src);
        PdfSigner signer = new PdfSigner(reader, new FileOutputStream(dest), new StampingProperties());
        // Create the signature appearance
 Rectangle rect = new Rectangle(36, 648, 200, 100);
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance
 .setReason(reason)
                .setLocation(location)
                .setPageRect(rect)
                .setPageNumber(1);
        signer.setFieldName("sig");
        IExternalDigest digest = new BouncyCastleDigest();
        BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, provider.getName());
        // Sign the document using the detached mode, CMS or CAdES equivalent.
 signer.signDetached(digest, pks, chain, null, null, null,
                0, subfilter);
    }
}

你期待的结果是什么?实际看到的错误信息又是什么?

希望pdf阅读器能表明该签名是有效的,现在是签名有效性未知;如果把证书加到信任列表,当然是可以,但是场景不允许。

我感觉我思路有问题,关于证书的想法错了,并且还未了解CRL和OCSP。

有什么想法都可以指教,谢谢各位

回复
阅读 1.1k
2 个回答

问题在构造的证书数组长度只为 1,并且就导入了导出的二级证书,应该把根证书也导入进来,顺序的话是根证书在后头,这样就可以了。

itext 还有另一个方法,就是通过 KeyStore 对象的 getCertificateChain 方法获取证书链,不过这样就需要把签名(正常的请看就是 CA 认证)后的证书(上面第 4 步生成的)导入到密钥库中才行。

如果需要验证数字签名是否有效,可以看下spire.pdf的验证方法

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏