前提是公司要弄一个电子签章的系统,目的是对 pdf 文档签名,然后验签。用户用阅读器查看 pdf 时,也要显示证书的有效性,验证时从场景来看,也不能简单把每个人的证书都加到信任列表中,希望能有个根证书一样的东西来验证。
我以前对证书加解密这块不是很懂,https 也是用的 Let's Encrypt 。后面补了相关知识,大致上是 CA 机构用自己的私钥加密我的公钥得到证书,然后客户信任并拥有这个 CA 的公钥,这样客户使用公钥解密加密后的证书,并从证书中得到我的公钥。不知道我理解的对不对?
然后回到 pdf,我想就是私钥签名,公钥验签。
然后查询了相关资料后,我使用 keytool 来生成证书,用 itext7 来对 pdf 文档签名,以下是步骤:
下面是签名的方法,修改的 itext7 的 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 时,阅读器(测试时用的福昕阅读器),还是显示的 “签名有效性未知,签名者身份未知,因为它和父证书都不包含在信任列表中”。
现在就没有头绪了,我觉得是我想错了,请各位有空帮忙看看,谢谢
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.