如何检测签名的 pdf 是否对 iText 有效?
How to detect a signed pdf is valid with iText?
对于一个项目,我需要检查数字签名是否有效。
我已经开发了一段代码来做到这一点。
我测试了一些 pdf(正确与否),代码似乎有效。
但是也有验证不通的情况。
在 Adobe Reader 中,我收到带有 "beautiful" 红叉的消息 "Document has been altered or corrupted since it was signed."...
不幸的是,我不知道如何测试这个最重要的案例。
因为据我了解,签名是正确的,但更改的是文档,而不是签名。
我想我们可以使用文件的哈希值,但我不知道如何正确提取这些信息。
如何用 Itext 检查?
为了参考,我测试了以下方法:
- pdfpkcs7.verify(): return 真
- acroFields.signatureCoversWholeDocument(签名): return 真
- pdfReader.isRebuilt() : return 假
Adobe 在 this document 中记录了他们在签名中接受的算法选择。特别是他们在其中声明了所有适用的 PDF 版本
DSA only supports SHA1 and adbe.pkcs7.detached
另一方面,OP 的文档使用 DSA 和 SHA256。效果是
- Adobe Reader 无法肯定地验证哈希值但是
- iText(不局限于那些算法组合)可以。
其实signature本身的signing algorithm信息本身就是有问题的,它仅仅使用了OID 1.2.840.10040.4.1,这只说明使用了DSA,而不是使用的digest算法。严格来说应该使用不同的 OID:
- 对于带 DSA 的 SHA1:1.2.840.10040.4.3
- 对于带 DSA 的 SHA256:2.16.840.1.101.3.4.3.2
(甚至还有一些替代方案,其中大部分已被弃用。)
仅发现 1.2.840.10040.4.1(仅 DSA)验证者必须猜测/推断摘要,并假设 SHA1(就像 Adobe Reader 所做的那样)并非完全不合理。
iText 最有可能猜测使用的是 SHA256,因为这种摘要算法也用于计算签名属性中的文档摘要 messageDigest
。
iText : 使用 iText 避免 PDF 数字签名漏洞。 links
In February 2019, a team of security researchers from the Ruhr-University Bochum in Germany published details of vulnerabilities in the digital signing system of many PDF viewers and online PDF digital signing services. After investigating these vulnerabilities, we found that recent updates to iText introduced in version 7.1.5 mean we are not vulnerable to the described attacks.
However, it was determined that the current names of the methods for checking and verifying signatures could be improved to better reflect their functionality. Therefore we have decided to deprecate the SignatureUtil#verifySignature and PdfPKCS7#verify methods, and replace them with SignatureUtil#readSignatureData and PdfPKCS7#verifySignatureIntegrityAndAuthenticity which have been introduced in iText 7.1.6.
下面的代码示例展示了如何对每个 iText 版本使用签名完整性和真实性检查。
iText 7.1.6:
PdfDocument pdfDocument = new PdfDocument(new PdfReader(input));
// Checks that signature is genuine and the document was not modified.
boolean genuineAndWasNotModified = false;
String signatureFieldName = "Signature1";
SignatureUtil signatureUtil = new SignatureUtil(pdfDocument);
try {
PdfPKCS7 signature1 = signatureUtil.readSignatureData(signatureFieldName);
if (signature1 != null) {
genuineAndWasNotModified = signature1.verifySignatureIntegrityAndAuthenticity();
}
} catch (Exception ignored) {
// ignoring exceptions,
// we are only interested in signatures that are passing the check successfully
}
pdfDocument.close();
The second and third types of attack, Incremental Saving Attack (ISA) and Signature Wrapping (SWA), are based on attempts to insert into the PDF file some malicious data to override signed data.
In order to validate every signature, it is necessary to check if it covers the entire file, otherwise iText cannot be sure that signature in question indeed signs the data that constitutes the current PdfDocument and all its contents. Even though the signature is authentic and signed data integrity is intact, iText will always check that signed data is not only a part of the PDF content but is also a valid PDF file.
iText implements this check in the SignatureUtil.signatureCoversWholeDocument(String fieldName) method. For both ISA and SWA attacks, this method will return false, because some unsigned data was inserted into the file:
We actually addressed this specific issue back in November 2018 (before we were aware of the reported vulnerabilities) with a rewrite of the signatureCoversWholeDocument() method. Providing you use iText 7.1.5 (or newer) the following code should correctly validate the PDF:
PdfDocument pdfDocument = new PdfDocument(new PdfReader(input));
String signatureFieldName = "Signature1";
SignatureUtil signatureUtil = new SignatureUtil(pdfDocument);
Boolean completeDocumentIsSigned = signatureUtil.signatureCoversWholeDocument(signatureFieldName)}
if (!completeDocumentIsSigned)
{
// handle PDF file which contains NOT signed data
}
pdfDocument.close();
注意:未覆盖整个文档的签名不能被视为验证 PDF 文件,因为签名未覆盖的内容可能在创建签名后已被修改。
对于一个项目,我需要检查数字签名是否有效。 我已经开发了一段代码来做到这一点。 我测试了一些 pdf(正确与否),代码似乎有效。 但是也有验证不通的情况。
在 Adobe Reader 中,我收到带有 "beautiful" 红叉的消息 "Document has been altered or corrupted since it was signed."... 不幸的是,我不知道如何测试这个最重要的案例。
因为据我了解,签名是正确的,但更改的是文档,而不是签名。
我想我们可以使用文件的哈希值,但我不知道如何正确提取这些信息。
如何用 Itext 检查?
为了参考,我测试了以下方法:
- pdfpkcs7.verify(): return 真
- acroFields.signatureCoversWholeDocument(签名): return 真
- pdfReader.isRebuilt() : return 假
Adobe 在 this document 中记录了他们在签名中接受的算法选择。特别是他们在其中声明了所有适用的 PDF 版本
DSA only supports SHA1 and adbe.pkcs7.detached
另一方面,OP 的文档使用 DSA 和 SHA256。效果是
- Adobe Reader 无法肯定地验证哈希值但是
- iText(不局限于那些算法组合)可以。
其实signature本身的signing algorithm信息本身就是有问题的,它仅仅使用了OID 1.2.840.10040.4.1,这只说明使用了DSA,而不是使用的digest算法。严格来说应该使用不同的 OID:
- 对于带 DSA 的 SHA1:1.2.840.10040.4.3
- 对于带 DSA 的 SHA256:2.16.840.1.101.3.4.3.2
(甚至还有一些替代方案,其中大部分已被弃用。)
仅发现 1.2.840.10040.4.1(仅 DSA)验证者必须猜测/推断摘要,并假设 SHA1(就像 Adobe Reader 所做的那样)并非完全不合理。
iText 最有可能猜测使用的是 SHA256,因为这种摘要算法也用于计算签名属性中的文档摘要 messageDigest
。
iText : 使用 iText 避免 PDF 数字签名漏洞。 links
In February 2019, a team of security researchers from the Ruhr-University Bochum in Germany published details of vulnerabilities in the digital signing system of many PDF viewers and online PDF digital signing services. After investigating these vulnerabilities, we found that recent updates to iText introduced in version 7.1.5 mean we are not vulnerable to the described attacks.
However, it was determined that the current names of the methods for checking and verifying signatures could be improved to better reflect their functionality. Therefore we have decided to deprecate the SignatureUtil#verifySignature and PdfPKCS7#verify methods, and replace them with SignatureUtil#readSignatureData and PdfPKCS7#verifySignatureIntegrityAndAuthenticity which have been introduced in iText 7.1.6.
下面的代码示例展示了如何对每个 iText 版本使用签名完整性和真实性检查。 iText 7.1.6:
PdfDocument pdfDocument = new PdfDocument(new PdfReader(input));
// Checks that signature is genuine and the document was not modified.
boolean genuineAndWasNotModified = false;
String signatureFieldName = "Signature1";
SignatureUtil signatureUtil = new SignatureUtil(pdfDocument);
try {
PdfPKCS7 signature1 = signatureUtil.readSignatureData(signatureFieldName);
if (signature1 != null) {
genuineAndWasNotModified = signature1.verifySignatureIntegrityAndAuthenticity();
}
} catch (Exception ignored) {
// ignoring exceptions,
// we are only interested in signatures that are passing the check successfully
}
pdfDocument.close();
The second and third types of attack, Incremental Saving Attack (ISA) and Signature Wrapping (SWA), are based on attempts to insert into the PDF file some malicious data to override signed data.
In order to validate every signature, it is necessary to check if it covers the entire file, otherwise iText cannot be sure that signature in question indeed signs the data that constitutes the current PdfDocument and all its contents. Even though the signature is authentic and signed data integrity is intact, iText will always check that signed data is not only a part of the PDF content but is also a valid PDF file.
iText implements this check in the SignatureUtil.signatureCoversWholeDocument(String fieldName) method. For both ISA and SWA attacks, this method will return false, because some unsigned data was inserted into the file:
We actually addressed this specific issue back in November 2018 (before we were aware of the reported vulnerabilities) with a rewrite of the signatureCoversWholeDocument() method. Providing you use iText 7.1.5 (or newer) the following code should correctly validate the PDF:
PdfDocument pdfDocument = new PdfDocument(new PdfReader(input));
String signatureFieldName = "Signature1";
SignatureUtil signatureUtil = new SignatureUtil(pdfDocument);
Boolean completeDocumentIsSigned = signatureUtil.signatureCoversWholeDocument(signatureFieldName)}
if (!completeDocumentIsSigned)
{
// handle PDF file which contains NOT signed data
}
pdfDocument.close();
注意:未覆盖整个文档的签名不能被视为验证 PDF 文件,因为签名未覆盖的内容可能在创建签名后已被修改。