xmlsecurity: reject a few dangerous annotation types during pdf sig verify

Change-Id: I950b49a6e7181639daf27348ddfa0f36586baa65
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/105312
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
This commit is contained in:
Miklos Vajna 2020-11-04 21:39:04 +01:00
parent d261356266
commit f231dacde9
3 changed files with 59 additions and 5 deletions

View File

@ -402,6 +402,21 @@ CPPUNIT_TEST_FIXTURE(PDFSigningTest, testBadCertP1)
rInformation.nStatus);
}
CPPUNIT_TEST_FIXTURE(PDFSigningTest, testBadCertP3Stamp)
{
std::vector<SignatureInformation> aInfos
= verify(m_directories.getURLFromSrc(DATA_DIRECTORY) + "bad-cert-p3-stamp.pdf", 1);
CPPUNIT_ASSERT(!aInfos.empty());
SignatureInformation& rInformation = aInfos[0];
// Without the accompanying fix in place, this test would have failed with:
// - Expected: 0 (SecurityOperationStatus_UNKNOWN)
// - Actual : 1 (SecurityOperationStatus_OPERATION_SUCCEEDED)
// i.e. adding a stamp annotation was not considered as a bad modification.
CPPUNIT_ASSERT_EQUAL(xml::crypto::SecurityOperationStatus::SecurityOperationStatus_UNKNOWN,
rInformation.nStatus);
}
/// Test writing a PAdES signature.
CPPUNIT_TEST_FIXTURE(PDFSigningTest, testSigningCertificateAttribute)
{

View File

@ -226,8 +226,30 @@ bool IsCompleteSignature(SvStream& rStream, vcl::filter::PDFDocument& rDocument,
}
#if HAVE_FEATURE_PDFIUM
/**
* Contains checksums of a PDF page, which is rendered without annotations. It also contains
* the geometry of a few dangerous annotation types.
*/
struct PageChecksum
{
BitmapChecksum m_nPageContent;
std::vector<basegfx::B2DRectangle> m_aAnnotations;
bool operator==(const PageChecksum& rChecksum) const;
};
bool PageChecksum::operator==(const PageChecksum& rChecksum) const
{
if (m_nPageContent != rChecksum.m_nPageContent)
{
return false;
}
return m_aAnnotations == rChecksum.m_aAnnotations;
}
/// Collects the checksum of each page of one version of the PDF.
void AnalyizeSignatureStream(SvMemoryStream& rStream, std::vector<BitmapChecksum>& rPageChecksums,
void AnalyizeSignatureStream(SvMemoryStream& rStream, std::vector<PageChecksum>& rPageChecksums,
int nMDPPerm)
{
auto pPdfium = vcl::pdf::PDFiumLibrary::get();
@ -247,8 +269,25 @@ void AnalyizeSignatureStream(SvMemoryStream& rStream, std::vector<BitmapChecksum
return;
}
BitmapChecksum nPageChecksum = pPdfPage->getChecksum(nMDPPerm);
rPageChecksums.push_back(nPageChecksum);
PageChecksum aPageChecksum;
aPageChecksum.m_nPageContent = pPdfPage->getChecksum(nMDPPerm);
for (int i = 0; i < pPdfPage->getAnnotationCount(); ++i)
{
std::unique_ptr<vcl::pdf::PDFiumAnnotation> pPdfAnnotation = pPdfPage->getAnnotation(i);
vcl::pdf::PDFAnnotationSubType eType = pPdfAnnotation->getSubType();
switch (eType)
{
case vcl::pdf::PDFAnnotationSubType::Unknown:
case vcl::pdf::PDFAnnotationSubType::FreeText:
case vcl::pdf::PDFAnnotationSubType::Stamp:
case vcl::pdf::PDFAnnotationSubType::Redact:
aPageChecksum.m_aAnnotations.push_back(pPdfAnnotation->getRectangle());
break;
default:
break;
}
}
rPageChecksums.push_back(aPageChecksum);
}
}
#endif
@ -272,7 +311,7 @@ bool IsValidSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignatu
aSignatureStream.WriteStream(rStream, nSignatureEOF);
rStream.Seek(nPos);
aSignatureStream.Seek(0);
std::vector<BitmapChecksum> aSignedPages;
std::vector<PageChecksum> aSignedPages;
AnalyizeSignatureStream(aSignatureStream, aSignedPages, nMDPPerm);
SvMemoryStream aFullStream;
@ -281,7 +320,7 @@ bool IsValidSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignatu
aFullStream.WriteStream(rStream);
rStream.Seek(nPos);
aFullStream.Seek(0);
std::vector<BitmapChecksum> aAllPages;
std::vector<PageChecksum> aAllPages;
AnalyizeSignatureStream(aFullStream, aAllPages, nMDPPerm);
// Fail if any page looks different after signing and at the end. Annotations/commenting doesn't