java 使用itext的数字签名验证不起作用

wwodge7n  于 2023-02-28  发布在  Java
关注(0)|答案(3)|浏览(258)

我正在使用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)
w41d8nur

w41d8nur1#

如果搜索iText阻塞的OID,您会看到它是“ecdsa-with-sha 256”:
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();
        [...]
k97glaaz

k97glaaz2#

正如Michaël Demey在他的回答中已经解释的那样,iText 5.x目前不支持所讨论的算法OID。
幸运的是,iText 5.x在签名验证过程中主要依赖底层BouncyCastle库来提供安全算法支持,而它本身只做了很少的事情,所缺少的只是iText正确地找到OID的“加密算法”ECDSA的名称(在引号中,因为它不是真正的加密,因为没有并行解密)。
您可以在iText 5.x中添加对该OID的验证支持(在当前5.5.13的SNAPSHOT中测试),如下所示:

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

(TestVerifySignature.javatestVerifyTestDsp中的代码)

小心...

  • 上面的代码使用反射,因为Map不是公共的。根据您的环境,这样的解决方案可能不被允许。在这种情况下,您必须相应地修补iText。此外,由于访问的Map不是公共的,解决方案可能在未来版本中失败。(这不太可能,因为iText 5处于维护模式,但谁也不知道。)
  • 这只增加了对 * 这个OID* 的支持。最有可能的是,可以类似地增加对许多其他OID的支持,但不一定是对所有OID的支持。
  • 此外,我只在一个 * 验证 * 用例中测试过,ECDSA签名可能需要完全不同的更改。
zphenhs4

zphenhs43#

对于仍在使用旧版本 iText 库(如 iText 2.1.7)的用户,可以根据mkl的建议,添加以下代码来验证对ecdsa-with-sha 256算法的支持:

// Get field with algorithms used in verification.
java.lang.reflect.Field algorithmNamesField = com.lowagie.text.pdf.PdfPKCS7.class.getDeclaredField("algorithmNames");
algorithmNamesField.setAccessible(true);

// Add missing algorithm to the map of algorithms.
@SuppressWarnings("unchecked")
HashMap<String, String> algorithmNames = (HashMap<String, String>) algorithmNamesField.get(null);
algorithmNames.put("1.2.840.10045.4.3.2", "ECDSA");

使用上面的最后一行代码,还可以将其他缺少的算法添加到Map中。

相关问题