include/vcl/filter/PDFiumLibrary.hxx                      |    2 
 xmlsecurity/qa/unit/pdfsigning/data/bad-cert-p3-stamp.pdf |binary
 xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx             |   18 ++++
 xmlsecurity/source/pdfio/pdfdocument.cxx                  |   63 ++++++++++++--
 4 files changed, 78 insertions(+), 5 deletions(-)

New commits:
commit 1dc6df7139295ac6e3eb1352d77fcddb0339af0b
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Wed Nov 4 21:39:04 2020 +0100
Commit:     Michael Stahl <michael.st...@cib.de>
CommitDate: Fri Dec 4 09:30:41 2020 +0100

    xmlsecurity: reject a few dangerous annotation types during pdf sig verify
    
    (cherry picked from commit f231dacde9df1c4aa5f4e0970535c4f4093364a7)
    
    Conflicts:
            xmlsecurity/source/helper/pdfsignaturehelper.cxx
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/105926
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    (cherry picked from commit fcab45e0e22f4cf46e71856dba7ae5abd6f99bc5)
    
    Change-Id: I950b49a6e7181639daf27348ddfa0f36586baa65
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/107118
    Tested-by: Michael Stahl <michael.st...@cib.de>
    Reviewed-by: Michael Stahl <michael.st...@cib.de>

diff --git a/include/vcl/filter/PDFiumLibrary.hxx 
b/include/vcl/filter/PDFiumLibrary.hxx
index 783b9a6da8b4..027e4939fab1 100644
--- a/include/vcl/filter/PDFiumLibrary.hxx
+++ b/include/vcl/filter/PDFiumLibrary.hxx
@@ -59,6 +59,8 @@ public:
             FPDF_ClosePage(mpPage);
     }
 
+    FPDF_PAGE getPointer() { return mpPage; }
+
     /// Get bitmap checksum of the page, without annotations/commenting.
     BitmapChecksum getChecksum(int nMDPPerm);
 };
diff --git a/xmlsecurity/qa/unit/pdfsigning/data/bad-cert-p3-stamp.pdf 
b/xmlsecurity/qa/unit/pdfsigning/data/bad-cert-p3-stamp.pdf
new file mode 100644
index 000000000000..b30f5b03867c
Binary files /dev/null and 
b/xmlsecurity/qa/unit/pdfsigning/data/bad-cert-p3-stamp.pdf differ
diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx 
b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
index b5a6d5914833..63990fb36225 100644
--- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
+++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
@@ -76,6 +76,7 @@ public:
     /// Test a valid signature that does not cover the whole file.
     void testPartial();
     void testBadCertP1();
+    void testBadCertP3Stamp();
     void testPartialInBetween();
     /// Test writing a PAdES signature.
     void testSigningCertificateAttribute();
@@ -99,6 +100,7 @@ public:
     CPPUNIT_TEST(testPDFPAdESGood);
     CPPUNIT_TEST(testPartial);
     CPPUNIT_TEST(testBadCertP1);
+    CPPUNIT_TEST(testBadCertP3Stamp);
     CPPUNIT_TEST(testPartialInBetween);
     CPPUNIT_TEST(testSigningCertificateAttribute);
     CPPUNIT_TEST(testGood);
@@ -455,6 +457,22 @@ void PDFSigningTest::testBadCertP1()
                          rInformation.nStatus);
 }
 
+void PDFSigningTest::testBadCertP3Stamp()
+{
+    std::vector<SignatureInformation> aInfos
+        = verify(m_directories.getURLFromSrc(DATA_DIRECTORY) + 
"bad-cert-p3-stamp.pdf", 1,
+                 /*rExpectedSubFilter=*/OString());
+    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.
 void PDFSigningTest::testSigningCertificateAttribute()
 {
diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx 
b/xmlsecurity/source/pdfio/pdfdocument.cxx
index 9d056de0a15c..51eac91495a7 100644
--- a/xmlsecurity/source/pdfio/pdfdocument.cxx
+++ b/xmlsecurity/source/pdfio/pdfdocument.cxx
@@ -24,6 +24,11 @@
 #include <svl/cryptosign.hxx>
 #include <vcl/filter/pdfdocument.hxx>
 #include <vcl/bitmap.hxx>
+#include <basegfx/range/b2drectangle.hxx>
+
+#if HAVE_FEATURE_PDFIUM
+#include <fpdf_annot.h>
+#endif
 
 using namespace com::sun::star;
 
@@ -138,8 +143,29 @@ bool IsCompleteSignature(SvStream& rStream, 
vcl::filter::PDFDocument& rDocument,
     return std::find(rAllEOFs.begin(), rAllEOFs.end(), nFileEnd) != 
rAllEOFs.end();
 }
 
+/**
+ * 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)
 {
 #if HAVE_FEATURE_PDFIUM
@@ -156,8 +182,35 @@ 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 < FPDFPage_GetAnnotCount(pPdfPage->getPointer()); 
++i)
+        {
+            FPDF_ANNOTATION pAnnotation = 
FPDFPage_GetAnnot(pPdfPage->getPointer(), i);
+            int nType = FPDFAnnot_GetSubtype(pAnnotation);
+            switch (nType)
+            {
+                case FPDF_ANNOT_UNKNOWN:
+                case FPDF_ANNOT_FREETEXT:
+                case FPDF_ANNOT_STAMP:
+                case FPDF_ANNOT_REDACT:
+                {
+                    basegfx::B2DRectangle aB2DRectangle;
+                    FS_RECTF aRect;
+                    if (FPDFAnnot_GetRect(pAnnotation, &aRect))
+                    {
+                        aB2DRectangle = basegfx::B2DRectangle(aRect.left, 
aRect.top, aRect.right,
+                                                              aRect.bottom);
+                    }
+                    aPageChecksum.m_aAnnotations.push_back(aB2DRectangle);
+                    break;
+                }
+                default:
+                    break;
+            }
+            FPDFPage_CloseAnnot(pAnnotation);
+        }
+        rPageChecksums.push_back(aPageChecksum);
     }
 #else
     (void)rStream;
@@ -182,7 +235,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;
@@ -191,7 +244,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
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to