电子签章: 数字签名过后的PDF,导入根证书后,用阅读器查看还是签名未知
题目描述
想弄一个电子签章的东西,目的是对pdf文档签名,然后验签。采用itext7来实现,pdf浏览软件用的福昕阅读器。
题目来源及自己的思路
业务场景是每个用户都有自己的证书文件,然后希望用户查看自己或其他人签名的pdf的时候,能证明签名是有效的,并且只通过1个根证书来完成。
参考了下网上的资料。以下证书的生成都是采用的keytool工具。
- 创建一个自签名的证书(类似CA?)。
- 生成一个人员的证书。
- 生成该人员证书对应的证书请求文件。
- 然后通过步骤1生成的根证书并对其签名,得到一个证书文件(发布者就变了)。
- 通过itext来对pdf文件进行签名。
- 导出第一步的证书(根证书),添加到pdf阅读器受信任的证书列表中,然后查看pdf。
相关代码
粘贴代码文本(请勿用截图)
- keytool生成证书。
略 - 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。
有什么想法都可以指教,谢谢各位
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
问题在构造的证书数组长度只为 1,并且就导入了导出的二级证书,应该把根证书也导入进来,顺序的话是根证书在后头,这样就可以了。
itext 还有另一个方法,就是通过 KeyStore 对象的 getCertificateChain 方法获取证书链,不过这样就需要把签名(正常的请看就是 CA 认证)后的证书(上面第 4 步生成的)导入到密钥库中才行。
如果需要验证数字签名是否有效,可以看下spire.pdf的验证方法,