itext 的数字签名验证不起作用
Digital Signature Verification with itext not working
我正在使用 itext 库来验证数字签名的 pdf,以下示例可在 https://developers.itextpdf.com/examples/security/digital-signatures-white-paper/digital-signatures-chapter-5 网站上找到。验证数字签名文档时出现以下错误。谁能帮忙解决一下。
Exception in thread "main" ExceptionConverter: java.security.NoSuchAlgorithmException: SHA256with1.2.840.10045.4.3.2 Signature not available
at java.security.Signature.getInstance(Signature.java:229)
at com.itextpdf.text.pdf.security.PdfPKCS7.initSignature(PdfPKCS7.java:697)
at com.itextpdf.text.pdf.security.PdfPKCS7.<init>(PdfPKCS7.java:459)
at com.itextpdf.text.pdf.AcroFields.verifySignature(AcroFields.java:2420)
at com.itextpdf.text.pdf.AcroFields.verifySignature(AcroFields.java:2373)
at nic.test.C5_01_SignatureIntegrity.verifySignature(C5_01_SignatureIntegrity.java:24)
at test.ExtractSignInfor.inspectSignature(ExtractSignInfor.java:95)
at test.ExtractSignInfor.inspectSignatures(ExtractSignInfor.java:135)
at test.ExtractSignInfor.main(ExtractSignInfor.java:63)
如果您搜索 iText 阻塞的 OID,您会看到这是 "ecdsa-with-sha256":
http://www.oid-info.com/get/1.2.840.10045.4.3.2
这在 iText 5 中不受支持。但我们确实在 iText 7 中添加了对此的支持。尝试 运行 使用最新的 iText 7 构建此代码示例:
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
PdfReader reader = new PdfReader(INPUT);
PdfDocument pdfDocument = new PdfDocument(reader);
PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDocument, false);
for ( String name : acroForm.getFormFields().keySet() ) {
PdfFormField formField = acroForm.getField(name);
if (formField != null && formField instanceof PdfSignatureFormField) {
SignatureUtil signatureUtil = new SignatureUtil(pdfDocument);
PdfPKCS7 pkcs7 = signatureUtil.verifySignature(name);
pkcs7.verify();
[...]
正如 Michaël Demey 在他的回答中所解释的那样,iText 5.x 目前不支持所讨论的算法 OID。
不过,幸运的是,iText 5.x 在签名验证期间主要依赖底层的 BouncyCastle 库来提供安全算法支持,而它自己做的很少,所缺少的只是 iText 正确找到 "encryption algorithm" OID 的 ECDSA(在引号中,因为它不是真正的加密,因为没有并行解密)。
您可以在 iText 5.x 中添加对该 OID 的验证支持(已在当前 SNAPSHOT 中针对 5.5.13 进行测试),如下所示:
java.lang.reflect.Field algorithmNamesField = com.itextpdf.text.pdf.security.EncryptionAlgorithms.class.getDeclaredField("algorithmNames");
algorithmNamesField.setAccessible(true);
@SuppressWarnings("unchecked")
HashMap<String, String> algorithmNames = (HashMap<String, String>) algorithmNamesField.get(null);
algorithmNames.put("1.2.840.10045.4.3.2", "ECDSA");
执行此添加后,iText 验证
PdfReader reader = new PdfReader(resource);
AcroFields acroFields = reader.getAcroFields();
List<String> names = acroFields.getSignatureNames();
for (String name : names) {
System.out.println("Signature name: " + name);
System.out.println("Signature covers whole document: " + acroFields.signatureCoversWholeDocument(name));
System.out.println("Document revision: " + acroFields.getRevision(name) + " of " + acroFields.getTotalRevisions());
PdfPKCS7 pk = acroFields.verifySignature(name);
System.out.println("Subject: " + CertificateInfo.getSubjectFields(pk.getSigningCertificate()));
System.out.println("Document verifies: " + pk.verify());
}
演出
Signature name: Signature1
Signature covers whole document: true
Document revision: 1 of 1
Subject: {ST=[Rajasthan], C=[India], CN=[Devi Singh Pilwal], O=[Personal]}
Document verifies: true
(VerifySignature.java方法中的测试代码testVerifyTestDsp
)
小心...
上面的代码使用了反射,因为有问题的 Map
不是 public。根据您的环境,可能不允许这样的解决方案。在那种情况下,您必须相应地修补 iText。此外,由于访问的 Map
不是 public,该解决方案在未来的版本中可能会失败。 (这不太可能,因为 iText 5 处于维护模式,但人们永远不会知道。)
这只会增加对这个非常 OID 的支持。很可能可以类似地添加对许多其他 OID 的支持,但不一定对所有 OID。
此外,我只在验证用例中对此进行了测试。 ECDSA 签名可能需要完全不同的更改。
我正在使用 itext 库来验证数字签名的 pdf,以下示例可在 https://developers.itextpdf.com/examples/security/digital-signatures-white-paper/digital-signatures-chapter-5 网站上找到。验证数字签名文档时出现以下错误。谁能帮忙解决一下。
Exception in thread "main" ExceptionConverter: java.security.NoSuchAlgorithmException: SHA256with1.2.840.10045.4.3.2 Signature not available
at java.security.Signature.getInstance(Signature.java:229)
at com.itextpdf.text.pdf.security.PdfPKCS7.initSignature(PdfPKCS7.java:697)
at com.itextpdf.text.pdf.security.PdfPKCS7.<init>(PdfPKCS7.java:459)
at com.itextpdf.text.pdf.AcroFields.verifySignature(AcroFields.java:2420)
at com.itextpdf.text.pdf.AcroFields.verifySignature(AcroFields.java:2373)
at nic.test.C5_01_SignatureIntegrity.verifySignature(C5_01_SignatureIntegrity.java:24)
at test.ExtractSignInfor.inspectSignature(ExtractSignInfor.java:95)
at test.ExtractSignInfor.inspectSignatures(ExtractSignInfor.java:135)
at test.ExtractSignInfor.main(ExtractSignInfor.java:63)
如果您搜索 iText 阻塞的 OID,您会看到这是 "ecdsa-with-sha256":
http://www.oid-info.com/get/1.2.840.10045.4.3.2
这在 iText 5 中不受支持。但我们确实在 iText 7 中添加了对此的支持。尝试 运行 使用最新的 iText 7 构建此代码示例:
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
PdfReader reader = new PdfReader(INPUT);
PdfDocument pdfDocument = new PdfDocument(reader);
PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDocument, false);
for ( String name : acroForm.getFormFields().keySet() ) {
PdfFormField formField = acroForm.getField(name);
if (formField != null && formField instanceof PdfSignatureFormField) {
SignatureUtil signatureUtil = new SignatureUtil(pdfDocument);
PdfPKCS7 pkcs7 = signatureUtil.verifySignature(name);
pkcs7.verify();
[...]
正如 Michaël Demey 在他的回答中所解释的那样,iText 5.x 目前不支持所讨论的算法 OID。
不过,幸运的是,iText 5.x 在签名验证期间主要依赖底层的 BouncyCastle 库来提供安全算法支持,而它自己做的很少,所缺少的只是 iText 正确找到 "encryption algorithm" OID 的 ECDSA(在引号中,因为它不是真正的加密,因为没有并行解密)。
您可以在 iText 5.x 中添加对该 OID 的验证支持(已在当前 SNAPSHOT 中针对 5.5.13 进行测试),如下所示:
java.lang.reflect.Field algorithmNamesField = com.itextpdf.text.pdf.security.EncryptionAlgorithms.class.getDeclaredField("algorithmNames");
algorithmNamesField.setAccessible(true);
@SuppressWarnings("unchecked")
HashMap<String, String> algorithmNames = (HashMap<String, String>) algorithmNamesField.get(null);
algorithmNames.put("1.2.840.10045.4.3.2", "ECDSA");
执行此添加后,iText 验证
PdfReader reader = new PdfReader(resource);
AcroFields acroFields = reader.getAcroFields();
List<String> names = acroFields.getSignatureNames();
for (String name : names) {
System.out.println("Signature name: " + name);
System.out.println("Signature covers whole document: " + acroFields.signatureCoversWholeDocument(name));
System.out.println("Document revision: " + acroFields.getRevision(name) + " of " + acroFields.getTotalRevisions());
PdfPKCS7 pk = acroFields.verifySignature(name);
System.out.println("Subject: " + CertificateInfo.getSubjectFields(pk.getSigningCertificate()));
System.out.println("Document verifies: " + pk.verify());
}
演出
Signature name: Signature1 Signature covers whole document: true Document revision: 1 of 1 Subject: {ST=[Rajasthan], C=[India], CN=[Devi Singh Pilwal], O=[Personal]} Document verifies: true
(VerifySignature.java方法中的测试代码testVerifyTestDsp
)
小心...
上面的代码使用了反射,因为有问题的
Map
不是 public。根据您的环境,可能不允许这样的解决方案。在那种情况下,您必须相应地修补 iText。此外,由于访问的Map
不是 public,该解决方案在未来的版本中可能会失败。 (这不太可能,因为 iText 5 处于维护模式,但人们永远不会知道。)这只会增加对这个非常 OID 的支持。很可能可以类似地添加对许多其他 OID 的支持,但不一定对所有 OID。
此外,我只在验证用例中对此进行了测试。 ECDSA 签名可能需要完全不同的更改。