[Libreoffice-commits] core.git: Branch 'feature/cib_contract891c' - 16 commits - comphelper/source configure.ac download.lst external/icu external/nss forms/source framework/source include/tools include/vcl include/xmlsecurity package/source sal/osl sc/source sfx2/source shell/source tools/source vcl/Library_vcl.mk vcl/qa vcl/source xmlsecurity/Library_xmlsecurity.mk xmlsecurity/qa xmlsecurity/source xmlsecurity/uiconfig xmlsecurity/workben

Miklos Vajna (via logerrit) logerrit at kemper.freedesktop.org
Tue Sep 29 06:55:22 UTC 2020


 comphelper/source/misc/docpasswordhelper.cxx                               |   74 +++
 configure.ac                                                               |    7 
 download.lst                                                               |    4 
 external/icu/ExternalProject_icu.mk                                        |    5 
 external/icu/UnpackedTarball_icu.mk                                        |    1 
 external/icu/b7d08bc04a4296982fcef8b6b8a354a9e4e7afca.patch.2              |   37 +
 external/nss/ExternalProject_nss.mk                                        |    6 
 external/nss/UnpackedTarball_nss.mk                                        |   31 -
 external/nss/nsinstall.py                                                  |    7 
 external/nss/nss-3.13.5-zlib-werror.patch                                  |    7 
 external/nss/nss-win32-make.patch.1                                        |    2 
 external/nss/nss.windows.patch                                             |    4 
 forms/source/xforms/submission.cxx                                         |    4 
 forms/source/xforms/submission/submission.hxx                              |    6 
 framework/source/services/autorecovery.cxx                                 |   32 +
 include/tools/stream.hxx                                                   |    1 
 include/vcl/filter/PDFiumLibrary.hxx                                       |   93 ++++
 include/vcl/filter/pdfdocument.hxx                                         |    2 
 include/xmlsecurity/pdfio/pdfdocument.hxx                                  |    2 
 package/source/xstor/owriteablestream.cxx                                  |    8 
 package/source/xstor/owriteablestream.hxx                                  |    3 
 package/source/xstor/xstorage.cxx                                          |    2 
 sal/osl/w32/process.cxx                                                    |    6 
 sc/source/core/data/table3.cxx                                             |    4 
 sfx2/source/appl/appopen.cxx                                               |   16 
 sfx2/source/dialog/filedlghelper.cxx                                       |   18 
 sfx2/source/view/view.src                                                  |    4 
 shell/source/win32/SysShExec.cxx                                           |    6 
 tools/source/stream/stream.cxx                                             |   21 
 vcl/Library_vcl.mk                                                         |    1 
 vcl/qa/cppunit/pdfexport/pdfexport.cxx                                     |   11 
 vcl/source/filter/ipdf/pdfdocument.cxx                                     |   13 
 vcl/source/filter/ipdf/pdfread.cxx                                         |   20 
 vcl/source/pdf/PDFiumLibrary.cxx                                           |   93 ++++
 xmlsecurity/Library_xmlsecurity.mk                                         |    5 
 xmlsecurity/qa/unit/pdfsigning/data/partial-in-between.pdf                 |binary
 xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx                              |   21 
 xmlsecurity/qa/unit/signing/data/hide-and-replace-shadow-file-signed-2.pdf |binary
 xmlsecurity/qa/unit/signing/signing.cxx                                    |   19 
 xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx                     |   26 -
 xmlsecurity/source/helper/pdfsignaturehelper.cxx                           |    3 
 xmlsecurity/source/pdfio/pdfdocument.cxx                                   |  212 ++++++++--
 xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui                         |    4 
 xmlsecurity/workben/pdfverify.cxx                                          |   11 
 44 files changed, 733 insertions(+), 119 deletions(-)

New commits:
commit e551fa59b5c224d52f551a600c515650b61fff20
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Fri Sep 4 17:17:48 2020 +0200
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Tue Sep 29 08:21:27 2020 +0200

    xmlsecurity: pdf incremental updates that are non-commenting are invalid
    
    I.e. it's OK to add incremental updates for annotation/commenting
    purposes and that doesn't invalite existing signatures. Everything else
    does.
    
    (cherry picked from commit 61834cd574568613f0b0a2ee099a60fa5a8d9804)
    
    Conflicts:
            include/vcl/filter/PDFiumLibrary.hxx
            vcl/source/pdf/PDFiumLibrary.cxx
    
    Conflicts:
            xmlsecurity/qa/unit/signing/signing.cxx
    
    Change-Id: I4607c242b3c6f6b01517b02407e9e7a095e2e069

diff --git a/include/tools/stream.hxx b/include/tools/stream.hxx
index 0bc3766807fa..608f7f0adde0 100644
--- a/include/tools/stream.hxx
+++ b/include/tools/stream.hxx
@@ -257,6 +257,7 @@ public:
     SvStream&       WriteOString(const OString& rStr)
                         { return WriteCharPtr(rStr.getStr()); }
     SvStream&       WriteStream( SvStream& rStream );
+    sal_uInt64      WriteStream( SvStream& rStream, sal_uInt64 nSize );
 
     SvStream&       WriteBool( bool b )
                         { return WriteUChar(static_cast<unsigned char>(b)); }
diff --git a/include/vcl/filter/PDFiumLibrary.hxx b/include/vcl/filter/PDFiumLibrary.hxx
index b9bceabb8acf..ffc70874c19b 100644
--- a/include/vcl/filter/PDFiumLibrary.hxx
+++ b/include/vcl/filter/PDFiumLibrary.hxx
@@ -17,11 +17,16 @@
 #include <memory>
 #include <rtl/instance.hxx>
 #include <vcl/dllapi.h>
+#include <vcl/checksum.hxx>
+
+#include <fpdf_doc.h>
 
 namespace vcl
 {
 namespace pdf
 {
+class PDFiumDocument;
+
 class VCL_DLLPUBLIC PDFium final
 {
 private:
@@ -33,6 +38,49 @@ public:
     ~PDFium();
 };
 
+class VCL_DLLPUBLIC PDFiumPage final
+{
+private:
+    FPDF_PAGE mpPage;
+
+private:
+    PDFiumPage(const PDFiumPage&) = delete;
+    PDFiumPage& operator=(const PDFiumPage&) = delete;
+
+public:
+    PDFiumPage(FPDF_PAGE pPage)
+        : mpPage(pPage)
+    {
+    }
+
+    ~PDFiumPage()
+    {
+        if (mpPage)
+            FPDF_ClosePage(mpPage);
+    }
+
+    /// Get bitmap checksum of the page, without annotations/commenting.
+    BitmapChecksum getChecksum();
+};
+
+class VCL_DLLPUBLIC PDFiumDocument final
+{
+private:
+    FPDF_DOCUMENT mpPdfDocument;
+
+private:
+    PDFiumDocument(const PDFiumDocument&) = delete;
+    PDFiumDocument& operator=(const PDFiumDocument&) = delete;
+
+public:
+    PDFiumDocument(FPDF_DOCUMENT pPdfDocument);
+    ~PDFiumDocument();
+
+    int getPageCount();
+
+    std::unique_ptr<PDFiumPage> openPage(int nIndex);
+};
+
 struct PDFiumLibrary : public rtl::StaticWithInit<std::shared_ptr<PDFium>, PDFiumLibrary>
 {
     std::shared_ptr<PDFium> operator()() { return std::make_shared<PDFium>(); }
diff --git a/tools/source/stream/stream.cxx b/tools/source/stream/stream.cxx
index 488348719892..b83729e35fbf 100644
--- a/tools/source/stream/stream.cxx
+++ b/tools/source/stream/stream.cxx
@@ -1176,6 +1176,27 @@ SvStream& SvStream::WriteStream( SvStream& rStream )
     return *this;
 }
 
+sal_uInt64 SvStream::WriteStream( SvStream& rStream, sal_uInt64 nSize )
+{
+    const sal_uInt32 cBufLen = 0x8000;
+    std::unique_ptr<char[]> pBuf( new char[ cBufLen ] );
+    sal_uInt32 nCurBufLen = cBufLen;
+    sal_uInt32 nCount;
+    sal_uInt64 nWriteSize = nSize;
+
+    do {
+        if ( nSize >= nCurBufLen )
+            nWriteSize -= nCurBufLen;
+        else
+            nCurBufLen = nWriteSize;
+        nCount = rStream.ReadBytes( pBuf.get(), nCurBufLen );
+        WriteBytes( pBuf.get(), nCount );
+    }
+    while( nWriteSize && nCount == nCurBufLen );
+
+    return nSize - nWriteSize;
+}
+
 OUString SvStream::ReadUniOrByteString( rtl_TextEncoding eSrcCharSet )
 {
     // read UTF-16 string directly from stream ?
diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx
index 5f487b15f48b..02c86622dfaf 100644
--- a/vcl/source/pdf/PDFiumLibrary.cxx
+++ b/vcl/source/pdf/PDFiumLibrary.cxx
@@ -15,6 +15,9 @@
 #include <vcl/filter/PDFiumLibrary.hxx>
 #include <fpdf_doc.h>
 
+#include <vcl/bitmap.hxx>
+#include <vcl/bitmapaccess.hxx>
+
 namespace vcl
 {
 namespace pdf
@@ -31,6 +34,57 @@ PDFium::PDFium()
 
 PDFium::~PDFium() { FPDF_DestroyLibrary(); }
 
+PDFiumDocument::PDFiumDocument(FPDF_DOCUMENT pPdfDocument)
+    : mpPdfDocument(pPdfDocument)
+{
+}
+
+PDFiumDocument::~PDFiumDocument()
+{
+    if (mpPdfDocument)
+        FPDF_CloseDocument(mpPdfDocument);
+}
+
+std::unique_ptr<PDFiumPage> PDFiumDocument::openPage(int nIndex)
+{
+    std::unique_ptr<PDFiumPage> pPDFiumPage;
+    FPDF_PAGE pPage = FPDF_LoadPage(mpPdfDocument, nIndex);
+    if (pPage)
+    {
+        pPDFiumPage = std::make_unique<PDFiumPage>(pPage);
+    }
+    return pPDFiumPage;
+}
+
+int PDFiumDocument::getPageCount() { return FPDF_GetPageCount(mpPdfDocument); }
+
+BitmapChecksum PDFiumPage::getChecksum()
+{
+    size_t nPageWidth = FPDF_GetPageWidth(mpPage);
+    size_t nPageHeight = FPDF_GetPageHeight(mpPage);
+    FPDF_BITMAP pPdfBitmap = FPDFBitmap_Create(nPageWidth, nPageHeight, /*alpha=*/1);
+    if (!pPdfBitmap)
+    {
+        return 0;
+    }
+
+    // Intentionally not using FPDF_ANNOT here, annotations/commenting is OK to not affect the
+    // checksum, signature verification wants this.
+    FPDF_RenderPageBitmap(pPdfBitmap, mpPage, /*start_x=*/0, /*start_y=*/0, nPageWidth, nPageHeight,
+                          /*rotate=*/0, /*flags=*/0);
+    Bitmap aBitmap(Size(nPageWidth, nPageHeight), 24);
+    {
+        Bitmap::ScopedWriteAccess pWriteAccess(aBitmap);
+        const auto pPdfBuffer = static_cast<const sal_uInt8*>(FPDFBitmap_GetBuffer(pPdfBitmap));
+        const int nStride = FPDFBitmap_GetStride(pPdfBitmap);
+        for (size_t nRow = 0; nRow < nPageHeight; ++nRow)
+        {
+            const sal_uInt8* pPdfLine = pPdfBuffer + (nStride * nRow);
+            pWriteAccess->CopyScanline(nRow, pPdfLine, ScanlineFormat::N32BitTcBgra, nStride);
+        }
+    }
+    return aBitmap.GetChecksum();
+}
 }
 } // end vcl::pdf
 
diff --git a/xmlsecurity/Library_xmlsecurity.mk b/xmlsecurity/Library_xmlsecurity.mk
index 77d3bd81dc3b..85950d1dcd4b 100644
--- a/xmlsecurity/Library_xmlsecurity.mk
+++ b/xmlsecurity/Library_xmlsecurity.mk
@@ -20,7 +20,10 @@ $(eval $(call gb_Library_add_defs,xmlsecurity,\
     -DXMLSECURITY_DLLIMPLEMENTATION \
 ))
 
-$(eval $(call gb_Library_use_externals,xmlsecurity,boost_headers))
+$(eval $(call gb_Library_use_externals,xmlsecurity,\
+	boost_headers \
+	$(if $(filter PDFIUM,$(BUILD_TYPE)),pdfium) \
+))
 
 $(eval $(call gb_Library_set_precompiled_header,xmlsecurity,$(SRCDIR)/xmlsecurity/inc/pch/precompiled_xmlsecurity))
 
diff --git a/xmlsecurity/qa/unit/signing/data/hide-and-replace-shadow-file-signed-2.pdf b/xmlsecurity/qa/unit/signing/data/hide-and-replace-shadow-file-signed-2.pdf
new file mode 100644
index 000000000000..f2b1a71096b2
Binary files /dev/null and b/xmlsecurity/qa/unit/signing/data/hide-and-replace-shadow-file-signed-2.pdf differ
diff --git a/xmlsecurity/qa/unit/signing/signing.cxx b/xmlsecurity/qa/unit/signing/signing.cxx
index 2b6e60e7c0bd..29e35738c62b 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -88,6 +88,8 @@ public:
     void testPDFGood();
     /// Test a typical PDF where the signature is bad.
     void testPDFBad();
+    /// Test a maliciously manipulated signed pdf
+    void testPDFHideAndReplace();
     /// Test a typical PDF which is not signed.
     void testPDFNo();
 #endif
@@ -113,6 +115,7 @@ public:
 #if HAVE_FEATURE_PDFIMPORT
     CPPUNIT_TEST(testPDFGood);
     CPPUNIT_TEST(testPDFBad);
+    CPPUNIT_TEST(testPDFHideAndReplace);
     CPPUNIT_TEST(testPDFNo);
 #endif
     CPPUNIT_TEST(test96097Calc);
@@ -458,6 +461,22 @@ void SigningTest::testPDFBad()
     CPPUNIT_ASSERT_EQUAL(static_cast<int>(SignatureState::BROKEN), static_cast<int>(pObjectShell->GetDocumentSignatureState()));
 }
 
+void SigningTest::testPDFHideAndReplace()
+{
+    createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY)
+              + "hide-and-replace-shadow-file-signed-2.pdf");
+    SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
+    CPPUNIT_ASSERT(pBaseModel);
+    SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell();
+    CPPUNIT_ASSERT(pObjectShell);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 2 (BROKEN)
+    // - Actual  : 6 (NOTVALIDATED_PARTIAL_OK)
+    // i.e. a non-commenting update after a signature was not marked as invalid.
+    CPPUNIT_ASSERT_EQUAL(static_cast<int>(SignatureState::BROKEN),
+                         static_cast<int>(pObjectShell->GetDocumentSignatureState()));
+}
+
 void SigningTest::testPDFNo()
 {
     createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "no.pdf");
diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx
index 5cec868a012b..edcb72d9a9ad 100644
--- a/xmlsecurity/source/pdfio/pdfdocument.cxx
+++ b/xmlsecurity/source/pdfio/pdfdocument.cxx
@@ -21,11 +21,15 @@
 #include <filter/msfilter/mscodec.hxx>
 #include <rtl/character.hxx>
 #include <rtl/strbuf.hxx>
+#include <config_features.h>
+
+#include <vcl/filter/PDFiumLibrary.hxx>
 #include <rtl/string.hxx>
 #include <sal/log.hxx>
 #include <sal/types.h>
 #include <sax/tools/converter.hxx>
 #include <tools/zcodec.hxx>
+#include <tools/stream.hxx>
 #include <unotools/calendarwrapper.hxx>
 #include <unotools/datetime.hxx>
 #include <vcl/pdfwriter.hxx>
@@ -49,6 +53,8 @@
 #include <comphelper/windowserrorstring.hxx>
 #endif
 
+#include <vcl/bitmap.hxx>
+
 using namespace com::sun::star;
 
 namespace
@@ -392,6 +398,66 @@ bool VerifyNonDetachedSignature(SvStream& rStream, std::vector<std::pair<size_t,
     return false;
 }
 #endif
+
+/// Collects the checksum of each page of one version of the PDF.
+void AnalyizeSignatureStream(SvMemoryStream& rStream, std::vector<BitmapChecksum>& rPageChecksums)
+{
+#if HAVE_FEATURE_PDFIUM
+    auto pPdfium = vcl::pdf::PDFiumLibrary::get();
+    vcl::pdf::PDFiumDocument aPdfDocument(
+        FPDF_LoadMemDocument(rStream.GetData(), rStream.GetSize(), /*password=*/nullptr));
+
+    int nPageCount = aPdfDocument.getPageCount();
+    for (int nPage = 0; nPage < nPageCount; ++nPage)
+    {
+        std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage(aPdfDocument.openPage(nPage));
+        if (!pPdfPage)
+        {
+            return;
+        }
+
+        BitmapChecksum nPageChecksum = pPdfPage->getChecksum();
+        rPageChecksums.push_back(nPageChecksum);
+    }
+#else
+    (void)rStream;
+#endif
+}
+
+/**
+ * Checks if incremental updates after singing performed valid modifications only.
+ * Annotations/commenting is OK, other changes are not.
+ */
+bool IsValidSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignature)
+{
+    size_t nSignatureEOF = 0;
+    if (!GetEOFOfSignature(pSignature, nSignatureEOF))
+    {
+        return false;
+    }
+
+    SvMemoryStream aSignatureStream;
+    sal_uInt64 nPos = rStream.Tell();
+    rStream.Seek(0);
+    aSignatureStream.WriteStream(rStream, nSignatureEOF);
+    rStream.Seek(nPos);
+    aSignatureStream.Seek(0);
+    std::vector<BitmapChecksum> aSignedPages;
+    AnalyizeSignatureStream(aSignatureStream, aSignedPages);
+
+    SvMemoryStream aFullStream;
+    nPos = rStream.Tell();
+    rStream.Seek(0);
+    aFullStream.WriteStream(rStream);
+    rStream.Seek(nPos);
+    aFullStream.Seek(0);
+    std::vector<BitmapChecksum> aAllPages;
+    AnalyizeSignatureStream(aFullStream, aAllPages);
+
+    // Fail if any page looks different after signing and at the end. Annotations/commenting doesn't
+    // count, though.
+    return aSignedPages == aAllPages;
+}
 }
 
 bool ValidateSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignature,
@@ -499,6 +565,12 @@ bool ValidateSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignat
     }
     rInformation.bPartialDocumentSignature = !IsCompleteSignature(rStream, rDocument, pSignature);
 
+    if (!IsValidSignature(rStream, pSignature))
+    {
+        SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: invalid incremental update detected");
+        return false;
+    }
+
     // At this point there is no obviously missing info to validate the
     // signature.
     std::vector<unsigned char> aSignature = vcl::filter::PDFDocument::DecodeHexString(pContents);
diff --git a/xmlsecurity/workben/pdfverify.cxx b/xmlsecurity/workben/pdfverify.cxx
index ea48350246a6..d0b5405b015b 100644
--- a/xmlsecurity/workben/pdfverify.cxx
+++ b/xmlsecurity/workben/pdfverify.cxx
@@ -20,6 +20,7 @@
 #include <vcl/pngwrite.hxx>
 #include <vcl/svapp.hxx>
 #include <vcl/graphicfilter.hxx>
+#include <comphelper/scopeguard.hxx>
 
 #include <xmlsecurity/pdfio/pdfdocument.hxx>
 
@@ -72,11 +73,11 @@ int pdfVerify(int nArgc, char** pArgv)
     uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(xMultiComponentFactory, uno::UNO_QUERY);
     comphelper::setProcessServiceFactory(xMultiServiceFactory);
 
+    InitVCL();
+    comphelper::ScopeGuard g([] { DeInitVCL(); });
     if (nArgc > 3 && OString(pArgv[3]) == "-p")
     {
-        InitVCL();
         generatePreview(pArgv[1], pArgv[2]);
-        DeInitVCL();
         return 0;
     }
 
commit 9c1ae5c8b9ffacaafc2c2c9c85dd0e8b5a3f9706
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Fri Jul 24 11:29:27 2020 +0200
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Tue Sep 29 08:14:38 2020 +0200

    xmlsecurity: detect unsigned incremental update between signatures
    
    (cherry picked from commit 7468d5df5ec79783eae84b62bdc5ecf12f0ca255)
    
    Conflicts:
            vcl/source/filter/ipdf/pdfdocument.cxx
            xmlsecurity/source/pdfio/pdfdocument.cxx
    
    Change-Id: I269ed858852ee7d1275adf340c8cc1565fc30693
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/99480
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>

diff --git a/include/vcl/filter/pdfdocument.hxx b/include/vcl/filter/pdfdocument.hxx
index 9297ef4a9e5e..6c247fefcd72 100644
--- a/include/vcl/filter/pdfdocument.hxx
+++ b/include/vcl/filter/pdfdocument.hxx
@@ -379,6 +379,8 @@ public:
     std::vector<PDFObjectElement*> GetSignatureWidgets();
     /// Remove the nth signature from read document in the edit buffer.
     bool RemoveSignature(size_t nPosition);
+    /// Get byte offsets of the end of incremental updates.
+    const std::vector<size_t>& GetEOFs() const;
     //@}
 };
 
diff --git a/include/xmlsecurity/pdfio/pdfdocument.hxx b/include/xmlsecurity/pdfio/pdfdocument.hxx
index 6f3b0f263add..2d652397aad2 100644
--- a/include/xmlsecurity/pdfio/pdfdocument.hxx
+++ b/include/xmlsecurity/pdfio/pdfdocument.hxx
@@ -29,7 +29,7 @@ namespace pdfio
  * @param bLast If this is the last signature in the file, so it covers the whole file physically.
  * @return If we can determinate a result.
  */
-XMLSECURITY_DLLPUBLIC bool ValidateSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignature, SignatureInformation& rInformation, bool bLast);
+XMLSECURITY_DLLPUBLIC bool ValidateSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignature, SignatureInformation& rInformation, vcl::filter::PDFDocument& rDocument);
 
 } // namespace pdfio
 } // namespace xmlsecurity
diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx
index 2c4c9288a32c..b01ad824a2c5 100644
--- a/vcl/source/filter/ipdf/pdfdocument.cxx
+++ b/vcl/source/filter/ipdf/pdfdocument.cxx
@@ -160,6 +160,8 @@ bool PDFDocument::RemoveSignature(size_t nPosition)
     return m_aEditBuffer.good();
 }
 
+const std::vector<size_t>& PDFDocument::GetEOFs() const { return m_aEOFs; }
+
 sal_uInt32 PDFDocument::GetNextSignature()
 {
     sal_uInt32 nRet = 0;
@@ -1969,7 +1971,16 @@ bool PDFCommentElement::Read(SvStream& rStream)
             m_aComment = aBuf.makeStringAndClear();
 
             if (m_aComment.startsWith("%%EOF"))
-                m_rDoc.PushBackEOF(rStream.Tell());
+            {
+                sal_uInt64 nPos = rStream.Tell();
+                if (ch == '\r')
+                {
+                    // If the comment ends with a \r\n, count the \n as well to match Adobe Acrobat
+                    // behavior.
+                    nPos += 1;
+                }
+                m_rDoc.PushBackEOF(nPos);
+            }
 
             SAL_INFO("vcl.filter", "PDFCommentElement::Read: m_aComment is '" << m_aComment << "'");
             return true;
diff --git a/xmlsecurity/qa/unit/pdfsigning/data/partial-in-between.pdf b/xmlsecurity/qa/unit/pdfsigning/data/partial-in-between.pdf
new file mode 100644
index 000000000000..211a111cb394
Binary files /dev/null and b/xmlsecurity/qa/unit/pdfsigning/data/partial-in-between.pdf differ
diff --git a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
index 55289fc05176..f0c45d0d7b63 100644
--- a/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
+++ b/xmlsecurity/qa/unit/pdfsigning/pdfsigning.cxx
@@ -66,6 +66,7 @@ public:
     void testPDFPAdESGood();
     /// Test a valid signature that does not cover the whole file.
     void testPartial();
+    void testPartialInBetween();
     /// Test writing a PAdES signature.
     void testSigningCertificateAttribute();
     /// Test that we accept files which are supposed to be good.
@@ -87,6 +88,7 @@ public:
     CPPUNIT_TEST(testPDF14LOWin);
     CPPUNIT_TEST(testPDFPAdESGood);
     CPPUNIT_TEST(testPartial);
+    CPPUNIT_TEST(testPartialInBetween);
     CPPUNIT_TEST(testSigningCertificateAttribute);
     CPPUNIT_TEST(testGood);
     CPPUNIT_TEST(testTokenize);
@@ -132,8 +134,8 @@ std::vector<SignatureInformation> PDFSigningTest::verify(const OUString& rURL, s
     for (size_t i = 0; i < aSignatures.size(); ++i)
     {
         SignatureInformation aInfo(i);
-        bool bLast = i == aSignatures.size() - 1;
-        CPPUNIT_ASSERT(xmlsecurity::pdfio::ValidateSignature(aStream, aSignatures[i], aInfo, bLast));
+        CPPUNIT_ASSERT(
+            xmlsecurity::pdfio::ValidateSignature(aStream, aSignatures[i], aInfo, aVerifyDocument));
         aRet.push_back(aInfo);
 
         if (!rExpectedSubFilter.isEmpty())
@@ -235,7 +237,8 @@ void PDFSigningTest::testPDFRemove()
         std::vector<vcl::filter::PDFObjectElement*> aSignatures = aDocument.GetSignatureWidgets();
         CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aSignatures.size());
         SignatureInformation aInfo(0);
-        CPPUNIT_ASSERT(xmlsecurity::pdfio::ValidateSignature(aStream, aSignatures[0], aInfo, /*bLast=*/true));
+        CPPUNIT_ASSERT(
+            xmlsecurity::pdfio::ValidateSignature(aStream, aSignatures[0], aInfo, aDocument));
     }
 
     // Remove the signature and write out the result as remove.pdf.
@@ -452,6 +455,18 @@ void PDFSigningTest::testUnknownSubFilter()
     CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), rInformations.size());
 }
 
+void PDFSigningTest::testPartialInBetween()
+{
+    std::vector<SignatureInformation> aInfos
+        = verify(m_directories.getURLFromSrc(DATA_DIRECTORY) + "partial-in-between.pdf", 2,
+                 /*rExpectedSubFilter=*/OString());
+    CPPUNIT_ASSERT(!aInfos.empty());
+    SignatureInformation& rInformation = aInfos[0];
+    // Without the accompanying fix in place, this test would have failed, as unsigned incremental
+    // update between two signatures were not detected.
+    CPPUNIT_ASSERT(rInformation.bPartialDocumentSignature);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(PDFSigningTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/xmlsecurity/source/helper/pdfsignaturehelper.cxx b/xmlsecurity/source/helper/pdfsignaturehelper.cxx
index 9bb6e59d0380..884974f4d17a 100644
--- a/xmlsecurity/source/helper/pdfsignaturehelper.cxx
+++ b/xmlsecurity/source/helper/pdfsignaturehelper.cxx
@@ -52,8 +52,7 @@ bool PDFSignatureHelper::ReadAndVerifySignature(const uno::Reference<io::XInputS
     {
         SignatureInformation aInfo(i);
 
-        bool bLast = i == aSignatures.size() - 1;
-        if (!xmlsecurity::pdfio::ValidateSignature(*pStream, aSignatures[i], aInfo, bLast))
+        if (!xmlsecurity::pdfio::ValidateSignature(*pStream, aSignatures[i], aInfo, aDocument))
             SAL_WARN("xmlsecurity.helper", "failed to determine digest match");
 
         m_aSignatureInfos.push_back(aInfo);
diff --git a/xmlsecurity/source/pdfio/pdfdocument.cxx b/xmlsecurity/source/pdfio/pdfdocument.cxx
index 5420196df7d8..5cec868a012b 100644
--- a/xmlsecurity/source/pdfio/pdfdocument.cxx
+++ b/xmlsecurity/source/pdfio/pdfdocument.cxx
@@ -51,6 +51,118 @@
 
 using namespace com::sun::star;
 
+namespace
+{
+/// Turns an array of floats into offset + length pairs.
+bool GetByteRangesFromPDF(vcl::filter::PDFArrayElement& rArray,
+                          std::vector<std::pair<size_t, size_t>>& rByteRanges)
+{
+    size_t nByteRangeOffset = 0;
+    const std::vector<vcl::filter::PDFElement*>& rByteRangeElements = rArray.GetElements();
+    for (size_t i = 0; i < rByteRangeElements.size(); ++i)
+    {
+        auto pNumber = dynamic_cast<vcl::filter::PDFNumberElement*>(rByteRangeElements[i]);
+        if (!pNumber)
+        {
+            SAL_WARN("xmlsecurity.pdfio",
+                     "ValidateSignature: signature offset and length has to be a number");
+            return false;
+        }
+
+        if (i % 2 == 0)
+        {
+            nByteRangeOffset = pNumber->GetValue();
+            continue;
+        }
+        size_t nByteRangeLength = pNumber->GetValue();
+        rByteRanges.emplace_back(nByteRangeOffset, nByteRangeLength);
+    }
+
+    return true;
+}
+
+/// Determines the last position that is covered by a signature.
+bool GetEOFOfSignature(vcl::filter::PDFObjectElement* pSignature, size_t& rEOF)
+{
+    vcl::filter::PDFObjectElement* pValue = pSignature->LookupObject("V");
+    if (!pValue)
+    {
+        return false;
+    }
+
+    auto pByteRange = dynamic_cast<vcl::filter::PDFArrayElement*>(pValue->Lookup("ByteRange"));
+    if (!pByteRange || pByteRange->GetElements().size() < 2)
+    {
+        return false;
+    }
+
+    std::vector<std::pair<size_t, size_t>> aByteRanges;
+    if (!GetByteRangesFromPDF(*pByteRange, aByteRanges))
+    {
+        return false;
+    }
+
+    rEOF = aByteRanges[1].first + aByteRanges[1].second;
+    return true;
+}
+
+/// Checks if there are unsigned incremental updates between the signatures or after the last one.
+bool IsCompleteSignature(SvStream& rStream, vcl::filter::PDFDocument& rDocument,
+                         vcl::filter::PDFObjectElement* pSignature)
+{
+    std::set<size_t> aSignedEOFs;
+    for (const auto& i : rDocument.GetSignatureWidgets())
+    {
+        size_t nEOF = 0;
+        if (!GetEOFOfSignature(i, nEOF))
+        {
+            return false;
+        }
+
+        aSignedEOFs.insert(nEOF);
+    }
+
+    size_t nSignatureEOF = 0;
+    if (!GetEOFOfSignature(pSignature, nSignatureEOF))
+    {
+        return false;
+    }
+
+    const std::vector<size_t>& rAllEOFs = rDocument.GetEOFs();
+    bool bFoundOwn = false;
+    for (const auto& rEOF : rAllEOFs)
+    {
+        if (rEOF == nSignatureEOF)
+        {
+            bFoundOwn = true;
+            continue;
+        }
+
+        if (!bFoundOwn)
+        {
+            continue;
+        }
+
+        if (aSignedEOFs.find(rEOF) == aSignedEOFs.end())
+        {
+            // Unsigned incremental update found.
+            return false;
+        }
+    }
+
+    // Make sure we find the incremental update of the signature itself.
+    if (!bFoundOwn)
+    {
+        return false;
+    }
+
+    // No additional content after the last incremental update.
+    rStream.Seek(STREAM_SEEK_TO_END);
+    size_t nFileEnd = rStream.Tell();
+    return std::find(rAllEOFs.begin(), rAllEOFs.end(), nFileEnd) != rAllEOFs.end();
+}
+}
+
 namespace xmlsecurity
 {
 namespace pdfio
@@ -282,7 +394,8 @@ bool VerifyNonDetachedSignature(SvStream& rStream, std::vector<std::pair<size_t,
 #endif
 }
 
-bool ValidateSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignature, SignatureInformation& rInformation, bool bLast)
+bool ValidateSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignature,
+                       SignatureInformation& rInformation, vcl::filter::PDFDocument& rDocument)
 {
     vcl::filter::PDFObjectElement* pValue = pSignature->LookupObject("V");
     if (!pValue)
@@ -361,24 +474,9 @@ bool ValidateSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignat
 
     // Build a list of offset-length pairs, representing the signed bytes.
     std::vector<std::pair<size_t, size_t>> aByteRanges;
-    size_t nByteRangeOffset = 0;
-    const std::vector<vcl::filter::PDFElement*>& rByteRangeElements = pByteRange->GetElements();
-    for (size_t i = 0; i < rByteRangeElements.size(); ++i)
+    if (!GetByteRangesFromPDF(*pByteRange, aByteRanges))
     {
-        auto pNumber = dynamic_cast<vcl::filter::PDFNumberElement*>(rByteRangeElements[i]);
-        if (!pNumber)
-        {
-            SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: signature offset and length has to be a number");
-            return false;
-        }
-
-        if (i % 2 == 0)
-        {
-            nByteRangeOffset = pNumber->GetValue();
-            continue;
-        }
-        size_t nByteRangeLength = pNumber->GetValue();
-        aByteRanges.push_back(std::make_pair(nByteRangeOffset, nByteRangeLength));
+        return false;
     }
 
     // Detect if the byte ranges don't cover everything, but the signature itself.
@@ -399,11 +497,7 @@ bool ValidateSignature(SvStream& rStream, vcl::filter::PDFObjectElement* pSignat
         SAL_WARN("xmlsecurity.pdfio", "ValidateSignature: second range start is not the end of the signature");
         return false;
     }
-    rStream.Seek(STREAM_SEEK_TO_END);
-    size_t nFileEnd = rStream.Tell();
-    if (bLast && (aByteRanges[1].first + aByteRanges[1].second) != nFileEnd)
-        // Second range end is not the end of the file.
-        rInformation.bPartialDocumentSignature = true;
+    rInformation.bPartialDocumentSignature = !IsCompleteSignature(rStream, rDocument, pSignature);
 
     // At this point there is no obviously missing info to validate the
     // signature.
diff --git a/xmlsecurity/workben/pdfverify.cxx b/xmlsecurity/workben/pdfverify.cxx
index 7b64e42c2a49..ea48350246a6 100644
--- a/xmlsecurity/workben/pdfverify.cxx
+++ b/xmlsecurity/workben/pdfverify.cxx
@@ -149,8 +149,8 @@ int pdfVerify(int nArgc, char** pArgv)
             for (size_t i = 0; i < aSignatures.size(); ++i)
             {
                 SignatureInformation aInfo(i);
-                bool bLast = i == aSignatures.size() - 1;
-                if (!xmlsecurity::pdfio::ValidateSignature(aStream, aSignatures[i], aInfo, bLast))
+                if (!xmlsecurity::pdfio::ValidateSignature(aStream, aSignatures[i], aInfo,
+                                                           aDocument))
                 {
                     SAL_WARN("xmlsecurity.pdfio", "failed to determine digest match");
                     return 1;
@@ -158,6 +158,8 @@ int pdfVerify(int nArgc, char** pArgv)
 
                 bool bSuccess = aInfo.nStatus == xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
                 std::cerr << "signature #" << i << ": digest match? " << bSuccess << std::endl;
+                std::cerr << "signature #" << i << ": partial? " << aInfo.bPartialDocumentSignature
+                          << std::endl;
             }
         }
 
commit 8a30925dc0292a8c603305e3bc9cbab79e26eb99
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Sun May 31 11:50:20 2020 +0200
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 13:51:57 2020 +0200

    pdfium: only init pdfium library once and destroy on LO exit
    
    With more and more usage of PDFium, it is hard to keep track of
    the life-time of the PDFium library, so it can happen that a
    FPDF_DestroyLibrary happens when we still have another instance
    where PDFium is still use. The result of this is a crash. To
    prevent this, just initialize the library once and delete, when
    on LO exit.
    
    This can be improved in the future to only keep the library
    active when in actual use.
    
    [ Leaving out the vector graphic search bits, the motivation is to just
    have this in libreoffice-7-0, so that recent pdf sig verify improvements
    can be backported. ]
    
    (cherry picked from commit 067a8a954c8e1d8d6465a4ab5fb61e93f16c26c2)
    
    Conflicts:
            vcl/source/graphic/VectorGraphicSearch.cxx
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/102317
    Tested-by: Miklos Vajna <vmiklos at collabora.com>
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    (cherry picked from commit b7de766b4dc5b4810277069bcf53a9f3737e87da)
    
    Conflicts:
            svx/source/svdraw/svdpdf.cxx
            svx/source/svdraw/svdpdf.hxx
            vcl/Library_vcl.mk
            vcl/qa/cppunit/pdfexport/pdfexport.cxx
            vcl/source/filter/ipdf/pdfread.cxx
    (cherry picked from commit 12025e528ef50af9e3176a19465f860723e30871)
    
    Change-Id: I5c7e5de7f8b97d10efb394c67c7a61b976c8d57c

diff --git a/include/vcl/filter/PDFiumLibrary.hxx b/include/vcl/filter/PDFiumLibrary.hxx
new file mode 100644
index 000000000000..b9bceabb8acf
--- /dev/null
+++ b/include/vcl/filter/PDFiumLibrary.hxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#pragma once
+
+#include <config_features.h>
+
+#if HAVE_FEATURE_PDFIUM
+
+#include <memory>
+#include <rtl/instance.hxx>
+#include <vcl/dllapi.h>
+
+namespace vcl
+{
+namespace pdf
+{
+class VCL_DLLPUBLIC PDFium final
+{
+private:
+    PDFium(const PDFium&) = delete;
+    PDFium& operator=(const PDFium&) = delete;
+
+public:
+    PDFium();
+    ~PDFium();
+};
+
+struct PDFiumLibrary : public rtl::StaticWithInit<std::shared_ptr<PDFium>, PDFiumLibrary>
+{
+    std::shared_ptr<PDFium> operator()() { return std::make_shared<PDFium>(); }
+};
+}
+} // namespace vcl::pdf
+
+#endif // HAVE_FEATURE_PDFIUM
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index a0113a2e85d4..af4b5f897e64 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -304,6 +304,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
     vcl/source/gdi/wall \
     vcl/source/gdi/scrptrun \
     vcl/source/gdi/CommonSalLayout \
+    vcl/source/pdf/PDFiumLibrary \
     vcl/source/bitmap/bitmapfilter \
     vcl/source/bitmap/bitmapscalesuper \
     vcl/source/bitmap/BitmapScaleConvolution \
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index 1a88b97e5364..ce5b28ffe705 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -28,6 +28,8 @@
 #include <fpdfview.h>
 #endif
 
+#include <vcl/filter/PDFiumLibrary.hxx>
+
 using namespace ::com::sun::star;
 
 namespace
@@ -43,6 +45,7 @@ class PdfExportTest : public test::BootstrapFixture, public unotest::MacrosTest
 #if HAVE_FEATURE_PDFIUM
     FPDF_PAGE mpPdfPage = nullptr;
     FPDF_DOCUMENT mpPdfDocument = nullptr;
+    std::shared_ptr<vcl::pdf::PDFium> mpPDFium;
 #endif
 
 public:
@@ -97,12 +100,7 @@ void PdfExportTest::setUp()
     mxDesktop.set(frame::Desktop::create(mxComponentContext));
 
 #if HAVE_FEATURE_PDFIUM
-    FPDF_LIBRARY_CONFIG config;
-    config.version = 2;
-    config.m_pUserFontPaths = nullptr;
-    config.m_pIsolate = nullptr;
-    config.m_v8EmbedderSlot = 0;
-    FPDF_InitLibraryWithConfig(&config);
+    mpPDFium = vcl::pdf::PDFiumLibrary::get();
 #endif
 }
 
@@ -111,7 +109,6 @@ void PdfExportTest::tearDown()
 #if HAVE_FEATURE_PDFIUM
     FPDF_ClosePage(mpPdfPage);
     FPDF_CloseDocument(mpPdfDocument);
-    FPDF_DestroyLibrary();
 #endif
 
     if (mxComponent.is())
diff --git a/vcl/source/filter/ipdf/pdfread.cxx b/vcl/source/filter/ipdf/pdfread.cxx
index f1a7e2b52a17..85a31fe27ebd 100644
--- a/vcl/source/filter/ipdf/pdfread.cxx
+++ b/vcl/source/filter/ipdf/pdfread.cxx
@@ -19,6 +19,8 @@
 
 #include <vcl/bitmapaccess.hxx>
 
+#include <vcl/filter/PDFiumLibrary.hxx>
+
 using namespace com::sun::star;
 
 namespace
@@ -58,12 +60,7 @@ double pointToPixel(double fPoint)
 /// Does PDF to bitmap conversion using pdfium.
 bool generatePreview(SvStream& rStream, Graphic& rGraphic)
 {
-    FPDF_LIBRARY_CONFIG aConfig;
-    aConfig.version = 2;
-    aConfig.m_pUserFontPaths = nullptr;
-    aConfig.m_pIsolate = nullptr;
-    aConfig.m_v8EmbedderSlot = 0;
-    FPDF_InitLibraryWithConfig(&aConfig);
+    auto pPdfium = vcl::pdf::PDFiumLibrary::get();
 
     // Read input into a buffer.
     SvMemoryStream aInBuffer;
@@ -108,7 +105,6 @@ bool generatePreview(SvStream& rStream, Graphic& rGraphic)
     FPDFBitmap_Destroy(pPdfBitmap);
     FPDF_ClosePage(pPdfPage);
     FPDF_CloseDocument(pPdfDocument);
-    FPDF_DestroyLibrary();
 
     return true;
 }
@@ -145,13 +141,8 @@ bool getCompatibleStream(SvStream& rInStream, SvStream& rOutStream)
         rOutStream.WriteStream(rInStream);
     else
     {
-        // Downconvert to PDF-1.4.
-        FPDF_LIBRARY_CONFIG aConfig;
-        aConfig.version = 2;
-        aConfig.m_pUserFontPaths = nullptr;
-        aConfig.m_pIsolate = nullptr;
-        aConfig.m_v8EmbedderSlot = 0;
-        FPDF_InitLibraryWithConfig(&aConfig);
+        // Downconvert to PDF-1.5.
+        auto pPdfium = vcl::pdf::PDFiumLibrary::get();
 
         // Read input into a buffer.
         SvMemoryStream aInBuffer;
@@ -168,7 +159,6 @@ bool getCompatibleStream(SvStream& rInStream, SvStream& rOutStream)
             return false;
 
         FPDF_CloseDocument(pPdfDocument);
-        FPDF_DestroyLibrary();
 
         aWriter.m_aStream.Seek(STREAM_SEEK_TO_BEGIN);
         rOutStream.WriteStream(aWriter.m_aStream);
diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx
new file mode 100644
index 000000000000..5f487b15f48b
--- /dev/null
+++ b/vcl/source/pdf/PDFiumLibrary.cxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <config_features.h>
+
+#if HAVE_FEATURE_PDFIUM
+
+#include <vcl/filter/PDFiumLibrary.hxx>
+#include <fpdf_doc.h>
+
+namespace vcl
+{
+namespace pdf
+{
+PDFium::PDFium()
+{
+    FPDF_LIBRARY_CONFIG aConfig;
+    aConfig.version = 2;
+    aConfig.m_pUserFontPaths = nullptr;
+    aConfig.m_pIsolate = nullptr;
+    aConfig.m_v8EmbedderSlot = 0;
+    FPDF_InitLibraryWithConfig(&aConfig);
+}
+
+PDFium::~PDFium() { FPDF_DestroyLibrary(); }
+
+}
+} // end vcl::pdf
+
+#endif // HAVE_FEATURE_PDFIUM
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 74021662f1e055d6cfde4bfb2bd9592a3cb7919e
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Wed Sep 2 12:37:18 2020 +0200
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 13:40:50 2020 +0200

    xmlsecurity: avoid saying OK when the signature is partial
    
    That's reserved for valid signatures (digest match, certificate
    validates and the signature covers the whole document).
    
    Also avoid "invalid" in the dialog when the digest matches and the
    signature is just incomplete.
    
    This now uses wording which is closer to Acrobat and also uses the same
    wording on the infobar and in the dialog.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101926
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    Tested-by: Jenkins
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/102188
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    (cherry picked from commit 46efad443472679b93b282c8e08b807d7e8f1a78)
    
    Conflicts:
            xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
    
    Change-Id: I26e4781d555b65cf29aa8df2232e286917235dc1

diff --git a/sfx2/source/view/view.src b/sfx2/source/view/view.src
index 94f8a5ecbd1f..f42bedaefb68 100644
--- a/sfx2/source/view/view.src
+++ b/sfx2/source/view/view.src
@@ -144,12 +144,12 @@ String STR_SIGNATURE_INVALID
 
 String STR_SIGNATURE_NOTVALIDATED
 {
-    Text[ en-US ] = "The signature is OK, but the certificate could not be validated.";
+    Text[ en-US ] = "At least one signature has problems: the certificate could not be validated.";
 };
 
 String STR_SIGNATURE_PARTIAL_OK
 {
-    Text[ en-US ] = "The signature is OK, but the document is only partially signed.";
+    Text[ en-US ] = "At least one signature has problems: the document is only partially signed.";
 };
 
 String STR_SIGNATURE_OK
diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
index 3ca748019cf7..2eeaef132adb 100644
--- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
+++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
@@ -518,6 +518,7 @@ void DigitalSignaturesDialog::ImplFillSignaturesBox()
     size_t nInfos = maSignatureManager.maCurrentSignatureInformations.size();
     size_t nValidSigs = 0, nValidCerts = 0;
     bool bAllNewSignatures = true;
+    bool bSomePartial = false;
 
     if( nInfos )
     {
@@ -595,7 +596,7 @@ void DigitalSignaturesDialog::ImplFillSignaturesBox()
             {
                 if (maSignatureManager.mxStore.is())
                 {
-                    // XML based.
+                    // ZIP based.
                     bSigValid = DocumentSignatureHelper::checkIfAllFilesAreSigned(
                           aElementsToBeVerified, rInfo, mode);
                 }
@@ -607,6 +608,10 @@ void DigitalSignaturesDialog::ImplFillSignaturesBox()
 
                 if( bSigValid )
                     nValidSigs++;
+                else
+                {
+                    bSomePartial = true;
+                }
             }
 
             Image aImage;
@@ -660,8 +665,8 @@ void DigitalSignaturesDialog::ImplFillSignaturesBox()
 
     bool bShowInvalidState = nInfos && !bAllSigsValid;
 
-    m_pSigsInvalidImg->Show( bShowInvalidState );
-    m_pSigsInvalidFI->Show( bShowInvalidState );
+    m_pSigsInvalidImg->Show( bShowInvalidState && !bSomePartial);
+    m_pSigsInvalidFI->Show( bShowInvalidState && !bSomePartial);
 
     bool bShowNotValidatedState = nInfos && bAllSigsValid && !bAllCertsValid;
 
@@ -670,8 +675,8 @@ void DigitalSignaturesDialog::ImplFillSignaturesBox()
 
     //bAllNewSignatures is always true if we are not in document mode
     bool bShowOldSignature = nInfos && bAllSigsValid && bAllCertsValid && !bAllNewSignatures;
-    m_pSigsOldSignatureImg->Show(bShowOldSignature);
-    m_pSigsOldSignatureFI->Show(bShowOldSignature);
+    m_pSigsOldSignatureImg->Show(bShowOldSignature || bSomePartial);
+    m_pSigsOldSignatureFI->Show(bShowOldSignature || bSomePartial);
 
     SignatureHighlightHdl( nullptr );
 }
diff --git a/xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui b/xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui
index 487bebdf8764..330a0f27bff0 100644
--- a/xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui
+++ b/xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui
@@ -297,7 +297,7 @@
                     <property name="can_focus">False</property>
                     <property name="no_show_all">True</property>
                     <property name="hexpand">True</property>
-                    <property name="label" translatable="yes">Not all parts of the document are signed</property>
+                    <property name="label" translatable="yes">At least one signature has problems: the document is only partially signed.</property>
                     <property name="xalign">0</property>
                   </object>
                   <packing>
@@ -310,7 +310,7 @@
                     <property name="can_focus">False</property>
                     <property name="no_show_all">True</property>
                     <property name="hexpand">True</property>
-                    <property name="label" translatable="yes">Certificate could not be validated</property>
+                    <property name="label" translatable="yes">At least one signature has problems: the certificate could not be validated.</property>
                     <property name="xalign">0</property>
                   </object>
                   <packing>
commit a0066c4dba0f00ce62b84ab540a6ff1a3dbafffd
Author:     Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Mon Aug 31 13:34:17 2020 +0200
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 13:29:54 2020 +0200

    xmlsecurity: fix infobar vs signature dialog inconsistency
    
    The infobar mentioned if a signature is partial, but the dialog just has
    a bool UI for signatures. Then present "good, but partial" as "bad".
    
    (cherry picked from commit 3ba1144cb96c710e665ffb3ada26fb6a48a03472)
    
    Change-Id: I698190aa77702000b11d635bd038d9c9a91614ac
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101844
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    (cherry picked from commit 8696c20cbf5c816ded9fee469616cb693b4572b0)
    
    Conflicts:
            xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx

diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
index 5a49151608d3..3ca748019cf7 100644
--- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
+++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
@@ -593,8 +593,17 @@ void DigitalSignaturesDialog::ImplFillSignaturesBox()
 
             if ( bSigValid )
             {
-                 bSigValid = DocumentSignatureHelper::checkIfAllFilesAreSigned(
-                      aElementsToBeVerified, rInfo, mode);
+                if (maSignatureManager.mxStore.is())
+                {
+                    // XML based.
+                    bSigValid = DocumentSignatureHelper::checkIfAllFilesAreSigned(
+                          aElementsToBeVerified, rInfo, mode);
+                }
+                else
+                {
+                    // Assume PDF.
+                    bSigValid = !rInfo.bPartialDocumentSignature;
+                }
 
                 if( bSigValid )
                     nValidSigs++;
commit 292d952e2af7f4abd0184fa623fab3efa0221f80
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Tue Apr 16 22:08:42 2019 +0200
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 12:50:17 2020 +0200

    tdf#124776: don't use SearchPathW to get full path of executable
    
    ... use GetModuleFileNameW() for that.
    
    We call SetDllDirectoryW and SetSearchPathMode to improve security of
    the process, and exclude some paths (including current directory) from
    search when using API that looks for binaries whose names are not fully
    qualified.
    
    So the sequence is this:
    1. Program is started using relative executable path like
       "instdir\program\soffice";
    2. sal_detail_initialize is called, which calls the two mentioned
       hardening functions;
    3. sal_detail_initialize calls osl_setCommandArgs, which in turn calls
       osl_createCommandArgs_Impl;
    4. The latter uses SearchPathW with empty path and first program arg
       "instdir\program\soffice" to find fully qualified program path.
    
    That now naturally fails, because current path is not searched.
    
    But to find the process name, we need no search: we can simply use
    GetModuleFileNameW() with NULL passed as module handle. Let's use that.
    
    Note that we can't use _wpgmptr/_get_wpgmptr, because we don't use wide
    entry point like wmain.
    
    LHM-Stuff
    ---------
    Dieser Patch löst das Problem wenn Symbols eingeschaltet ist, danach
    konnte LO nicht mit scalc.exe, swriter.exe, .. gestartet werden den es
    ist damit abgestürzt. (Dumpfile war im LO-Verzeichnis)
    
    Reviewed-on: https://gerrit.libreoffice.org/70844
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>
    Tested-by: Mike Kaganski <mike.kaganski at collabora.com>
    (cherry picked from commit c650217cc543080928a26de4bfc07ebb0be5c6ca)
    
    Change-Id: I7a0013a0505f7bdd38164b09b045bfade9686664
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89689
    Tested-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>

diff --git a/sal/osl/w32/process.cxx b/sal/osl/w32/process.cxx
index 6d86ae58bad8..94792e4cc09e 100644
--- a/sal/osl/w32/process.cxx
+++ b/sal/osl/w32/process.cxx
@@ -350,10 +350,8 @@ static rtl_uString ** osl_createCommandArgs_Impl (int argc, char **)
         {
             /* Ensure absolute path */
             ::osl::LongPathBuffer< sal_Unicode > aBuffer( MAX_LONG_PATH );
-            DWORD dwResult = 0;
-
-            dwResult = SearchPath (
-                nullptr, reinterpret_cast<LPCWSTR>(ppArgs[0]->buffer), L".exe", aBuffer.getBufSizeInSymbols(), ::osl::mingw_reinterpret_cast<LPWSTR>(aBuffer), nullptr);
+            DWORD dwResult
+                = GetModuleFileNameW(nullptr, o3tl::toW(aBuffer), aBuffer.getBufSizeInSymbols());
             if ((0 < dwResult) && (dwResult < aBuffer.getBufSizeInSymbols()))
             {
                 /* Replace argv[0] with its absolute path */
commit a2e4526a85d154cd235297e28fc447e8af90c651
Author:     Thorsten Behrens <Thorsten.Behrens at CIB.de>
AuthorDate: Thu Sep 10 00:18:08 2020 +0200
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 12:47:57 2020 +0200

    Check range before accessing Calc sort userlist
    
    Change-Id: I74df0bc6db978e06e8014ac1bc0d76a66c7f4fe8

diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 9f63f8f2ff10..de6f6f01d1c4 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -1533,9 +1533,9 @@ short ScTable::CompareCell(
                 bool bNaturalSort = aSortParam.bNaturalSort;    // natural sort
                 bool bCaseSens    = aSortParam.bCaseSens;       // case sensitivity
 
-                if (bUserDef)
+                ScUserList* pList = ScGlobal::GetUserList();
+                if (bUserDef && pList && pList->size() > aSortParam.nUserIndex)
                 {
-                    ScUserList* pList = ScGlobal::GetUserList();
                     const ScUserListData& rData = (*pList)[aSortParam.nUserIndex];
 
                     if ( bNaturalSort )
commit fb29fc38274559d33a549403d729d365c82a6b78
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Aug 7 18:57:00 2020 +0200
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 12:32:20 2020 +0200

    nss: upgrade to release 3.55.0
    
    Fixes CVE-2020-6829, CVE-2020-12400 CVE-2020-12401 CVE-2020-12403.
    (also CVE-2020-12402 CVE-2020-12399 in older releases since 3.47)
    
    * external/nss/nss.nspr-parallel-win-debug_build.patch:
      remove, merged upstream
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100345
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.stahl at cib.de>
    (cherry picked from commit 495a5944a3d442cfe748a3bb0dcef76f6a961d30)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100420
    Reviewed-by: Xisco Fauli <xiscofauli at libreoffice.org>
    (cherry picked from commit 227d30a3a17f2fffb1a166cdc3e2a796bb335214)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100590
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    (cherry picked from commit 94cecbfdf3cf01fe3d5658c7edf78696da2a249f)
    
    Change-Id: I8b48e25ce68a2327cde1420abdaea8f9e51a7888

diff --git a/download.lst b/download.lst
index dea9f67a0727..1f6503badec7 100644
--- a/download.lst
+++ b/download.lst
@@ -164,8 +164,8 @@ export MYTHES_SHA256SUM := 1e81f395d8c851c3e4e75b568e20fa2fa549354e75ab397f9de4b
 export MYTHES_TARBALL := a8c2c5b8f09e7ede322d5c602ff6a4b6-mythes-1.2.4.tar.gz
 export NEON_SHA256SUM := 00c626c0dc18d094ab374dbd9a354915bfe4776433289386ed489c2ec0845cdd
 export NEON_TARBALL := 231adebe5c2f78fded3e3df6e958878e-neon-0.30.1.tar.gz
-export NSS_SHA256SUM := 861a4510b7c21516f49a4cfa5b871aa796e4e1ef2dfe949091970e56f9d60cdf
-export NSS_TARBALL := nss-3.53-with-nspr-4.25.tar.gz
+export NSS_SHA256SUM := ec6032d78663c6ef90b4b83eb552dedf721d2bce208cec3bf527b8f637db7e45
+export NSS_TARBALL := nss-3.55-with-nspr-4.27.tar.gz
 export ODFGEN_SHA256SUM := 2c7b21892f84a4c67546f84611eccdad6259875c971e98ddb027da66ea0ac9c2
 export ODFGEN_VERSION_MICRO := 6
 export ODFGEN_TARBALL := libodfgen-0.1.$(ODFGEN_VERSION_MICRO).tar.bz2
diff --git a/external/nss/UnpackedTarball_nss.mk b/external/nss/UnpackedTarball_nss.mk
index b77939f20f31..e77f92341d91 100644
--- a/external/nss/UnpackedTarball_nss.mk
+++ b/external/nss/UnpackedTarball_nss.mk
@@ -21,7 +21,6 @@ $(eval $(call gb_UnpackedTarball_add_patches,nss,\
     external/nss/clang-cl.patch.0 \
     external/nss/nss.vs2015.patch \
     external/nss/nss.vs2015.pdb.patch \
-    external/nss/nss.nspr-parallel-win-debug_build.patch \
     $(if $(filter iOS,$(OS)), \
         external/nss/nss-ios.patch) \
     $(if $(filter MSC-INTEL,$(COM)-$(CPUNAME)), \
diff --git a/external/nss/nss.nspr-parallel-win-debug_build.patch b/external/nss/nss.nspr-parallel-win-debug_build.patch
deleted file mode 100644
index 86b55e1ccf7f..000000000000
--- a/external/nss/nss.nspr-parallel-win-debug_build.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-Änderung:        4866:23940b78e965
-Nutzer:          Jan-Marek Glogowski <glogow at fbihome.de>
-Datum:           Fri May 01 22:50:55 2020 +0000
-Dateien:         pr/tests/Makefile.in
-Beschreibung:
-Bug 290526 Write separate PDBs for test OBJs r=glandium
-
-Quite often when running a parallel NSS build, I get the following
-compiler error message, resulting in a build failure, despite
-compiling with the -FS flag:
-
-.../nss/nspr/pr/tests/zerolen.c: fatal error C1041:
-Programmdatenbank "...\nss\nspr\out\pr\tests\vc140.pdb" kann nicht
-ge<94>ffnet werden; verwenden Sie /FS, wenn mehrere CL.EXE in
-dieselbe .PDB-Datei schreiben.
-
-The failing source file is always one of the last test object
-files. But the actual problem is not the compiler accessing the
-PDB file, but the linker already linking the first test
-executables accessing the shared PDB; at least that's my guess.
-
-So instead of using a shared PDB for all test object files, this
-uses -Fd$(@:.$(OBJ_SUFFIX)=.pdb) to write a separate PDB for every
-test's object file. The linker works fine with the shared OBJ PDB.
-
-Differential Revision: https://phabricator.services.mozilla.com/D68693
-
-
-diff -r 219d131499d5 -r 23940b78e965 nss/nspr/pr/tests/Makefile.in
---- a/nss/nspr/pr/tests/Makefile.in	Mon Feb 10 20:58:42 2020 +0000
-+++ b/nss/nspr/pr/tests/Makefile.in	Fri May 01 22:50:55 2020 +0000
-@@ -211,6 +211,7 @@
- else
-   EXTRA_LIBS += ws2_32.lib
-   LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO
-+  CFLAGS += -Fd$(@:.$(OBJ_SUFFIX)=.pdb)
-   ifdef PROFILE
-     LDOPTS += -PROFILE -MAP
-   endif # profile
-
commit 9b820555e28f73098bfcb0587d812e7ae6b5f760
Author:     Jan-Marek Glogowski <glogow at fbihome.de>
AuthorDate: Wed Jun 26 18:09:19 2019 +0200
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 12:32:09 2020 +0200

    NSS: enable parallel build
    
    Since NSS 3.53, the Makefile based build should be fixed (upstream
    bug 290526). The only missing patch is a minimal NSPR fix for the
    "NSPR, configure + make, parallel, Windows, MS VS, debug" build.
    That patch isn't incuded in the NSPR 4.25 release (but it's already
    in the mercurial repo for NSPR 4.26).
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/95218
    Tested-by: Jenkins
    Reviewed-by: Jan-Marek Glogowski <glogow at fbihome.de>
    (cherry picked from commit b56e8d6def26a0430853835e997f1be841840a61)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100419
    Reviewed-by: Michael Stahl <michael.stahl at cib.de>
    (cherry picked from commit c1bce55faebd9ad8751d7b6b9a7f77dff7b3d507)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100589
    (cherry picked from commit 3e4dbb1708d4b3b7619602b63602b884a7bb2caa)
    
    Change-Id: I8eaa3792a12bdff734e56ac3f552991478957e23

diff --git a/download.lst b/download.lst
index f46a38121016..dea9f67a0727 100644
--- a/download.lst
+++ b/download.lst
@@ -164,8 +164,8 @@ export MYTHES_SHA256SUM := 1e81f395d8c851c3e4e75b568e20fa2fa549354e75ab397f9de4b
 export MYTHES_TARBALL := a8c2c5b8f09e7ede322d5c602ff6a4b6-mythes-1.2.4.tar.gz
 export NEON_SHA256SUM := 00c626c0dc18d094ab374dbd9a354915bfe4776433289386ed489c2ec0845cdd
 export NEON_TARBALL := 231adebe5c2f78fded3e3df6e958878e-neon-0.30.1.tar.gz
-export NSS_SHA256SUM := 07d4276168f59bb3038c7826dabb5fbfbab8336ddf65e4e6e43bce89ada78c64
-export NSS_TARBALL := nss-3.47.1-with-nspr-4.23.tar.gz
+export NSS_SHA256SUM := 861a4510b7c21516f49a4cfa5b871aa796e4e1ef2dfe949091970e56f9d60cdf
+export NSS_TARBALL := nss-3.53-with-nspr-4.25.tar.gz
 export ODFGEN_SHA256SUM := 2c7b21892f84a4c67546f84611eccdad6259875c971e98ddb027da66ea0ac9c2
 export ODFGEN_VERSION_MICRO := 6
 export ODFGEN_TARBALL := libodfgen-0.1.$(ODFGEN_VERSION_MICRO).tar.bz2
diff --git a/external/nss/ExternalProject_nss.mk b/external/nss/ExternalProject_nss.mk
index f555975ee7fa..01b6b4e07794 100644
--- a/external/nss/ExternalProject_nss.mk
+++ b/external/nss/ExternalProject_nss.mk
@@ -29,11 +29,11 @@ ifeq ($(OS),WNT)
 $(call gb_ExternalProject_get_state_target,nss,build): $(call gb_ExternalProject_get_state_target,nss,configure) $(call gb_ExternalExecutable_get_dependencies,python)
 	$(call gb_ExternalProject_run,build,\
 		$(if $(MSVC_USE_DEBUG_RUNTIME),USE_DEBUG_RTL=1,BUILD_OPT=1) \
-		MOZ_MSVCVERSION=9 OS_TARGET=WIN95 \
+		OS_TARGET=WIN95 \
 		$(if $(filter X86_64,$(CPUNAME)),USE_64=1) \
 		LIB="$(ILIB)" \
 		XCFLAGS="-arch:SSE $(SOLARINC)" \
-		$(MAKE) -j1 nss_build_all RC="rc.exe $(SOLARINC)" \
+		$(MAKE) nss_build_all RC="rc.exe $(SOLARINC)" \
 			NSINSTALL='$(call gb_ExternalExecutable_get_command,python) $(SRCDIR)/external/nss/nsinstall.py' \
 	,nss)
 
@@ -53,7 +53,7 @@ $(call gb_ExternalProject_get_state_target,nss,build): $(call gb_ExternalProject
 			$(if $(filter IOS-ARM,$(OS)-$(CPUNAME)),CPU_ARCH=arm) \
 			NSINSTALL="$(call gb_ExternalExecutable_get_command,python) $(SRCDIR)/external/nss/nsinstall.py") \
 		NSDISTMODE=copy \
-		$(MAKE) -j1 AR="$(AR)" \
+		$(MAKE) AR="$(AR)" \
 			RANLIB="$(RANLIB)" \
 			NMEDIT="$(NM)edit" \
 			CCC="$(CXX)" \
diff --git a/external/nss/UnpackedTarball_nss.mk b/external/nss/UnpackedTarball_nss.mk
index 463451ecd924..b77939f20f31 100644
--- a/external/nss/UnpackedTarball_nss.mk
+++ b/external/nss/UnpackedTarball_nss.mk
@@ -12,32 +12,32 @@ $(eval $(call gb_UnpackedTarball_UnpackedTarball,nss))
 $(eval $(call gb_UnpackedTarball_set_tarball,nss,$(NSS_TARBALL)))
 
 $(eval $(call gb_UnpackedTarball_add_patches,nss,\
-	external/nss/nss.patch \
-	external/nss/nss.aix.patch \
-	external/nss/nss-3.13.5-zlib-werror.patch \
-	external/nss/nss_macosx.patch \
-	external/nss/nss-win32-make.patch.1 \
-	$(if $(filter WNT,$(OS)),external/nss/nss.windows.patch \
-        external/nss/nss.nowerror.patch \
-		external/nss/nss.vs2015.patch) \
+    external/nss/nss.patch \
+    external/nss/nss.aix.patch \
+    external/nss/nss-3.13.5-zlib-werror.patch \
+    external/nss/nss_macosx.patch \
+    external/nss/nss-win32-make.patch.1 \
     external/nss/ubsan.patch.0 \
     external/nss/clang-cl.patch.0 \
-    $(if $(filter IOS,$(OS)), \
+    external/nss/nss.vs2015.patch \
+    external/nss/nss.vs2015.pdb.patch \
+    external/nss/nss.nspr-parallel-win-debug_build.patch \
+    $(if $(filter iOS,$(OS)), \
         external/nss/nss-ios.patch) \
-	$(if $(filter MSC-INTEL,$(COM)-$(CPUNAME)), \
-		external/nss/nss.cygwin64.in32bit.patch) \
-	$(if $(filter WNT,$(OS)), \
-		external/nss/nss.vs2015.pdb.patch) \
+    $(if $(filter MSC-INTEL,$(COM)-$(CPUNAME)), \
+        external/nss/nss.cygwin64.in32bit.patch) \
     $(if $(findstring 120_70,$(VCVER)_$(WINDOWS_SDK_VERSION)), \
         external/nss/nss-winXP-sdk.patch.1) \
-	$(if $(filter WNT,$(OS)), \
-    	external/nss/nss.utf8bom.patch.1) \
+    $(if $(filter WNT,$(OS)), \
+        external/nss/nss.windows.patch \
+        external/nss/nss.nowerror.patch \
+        external/nss/nss.utf8bom.patch.1) \
 ))
 
 ifeq ($(COM_IS_CLANG),TRUE)
 ifneq ($(filter -fsanitize=%,$(CC)),)
 $(eval $(call gb_UnpackedTarball_add_patches,nss,\
-	external/nss/asan.patch.1 \
+    external/nss/asan.patch.1 \
 ))
 endif
 endif
diff --git a/external/nss/nsinstall.py b/external/nss/nsinstall.py
index 31b3de3450c5..80e9c1679373 100644
--- a/external/nss/nsinstall.py
+++ b/external/nss/nsinstall.py
@@ -155,7 +155,12 @@ def nsinstall(argv):
   target = args.pop()
   # ensure target directory
   if not os.path.isdir(target):
-    os.makedirs(target)
+    try:
+      os.makedirs(target)
+    except FileExistsError:
+      if not os.path.isdir(target):
+        sys.stderr.write('nsinstall: ' + target + ' is not a directoy!\n')
+        return 1
 
   copy_all_entries(args, target)
   return 0
diff --git a/external/nss/nss-3.13.5-zlib-werror.patch b/external/nss/nss-3.13.5-zlib-werror.patch
index 6cda50023f1b..0cdbf7808f81 100644
--- a/external/nss/nss-3.13.5-zlib-werror.patch
+++ b/external/nss/nss-3.13.5-zlib-werror.patch
@@ -1,9 +1,10 @@
 --- a/a/nss/lib/zlib/gzguts.h	2010-08-22 03:07:03.000000000 +0200
 +++ b/b/nss/lib/zlib/gzguts.h	2012-07-17 08:52:14.821552788 +0200
-@@ -26,6 +26,9 @@
- #  include <limits.h>
+@@ -26,6 +26,10 @@
+ #  define write _write
+ #  define close _close
  #endif
- #include <fcntl.h>
++
 +#ifndef _WIN32
 +#include <unistd.h>
 +#endif
diff --git a/external/nss/nss-win32-make.patch.1 b/external/nss/nss-win32-make.patch.1
index bc5a759275e2..7ba3df451ee6 100644
--- a/external/nss/nss-win32-make.patch.1
+++ b/external/nss/nss-win32-make.patch.1
@@ -1,7 +1,7 @@
 --- nss/nss/coreconf/rules.mk.orig2	2014-06-03 15:30:01.667200000 +0200
 +++ nss/nss/coreconf/rules.mk	2014-06-03 15:30:14.537200000 +0200
 @@ -259,7 +259,7 @@
- 	@$(MAKE_OBJDIR)
+ $(LIBRARY): $(OBJS) | $$(@D)/d
  	rm -f $@
  ifeq (,$(filter-out _WIN%,$(NS_USE_GCC)_$(OS_TARGET)))
 -	$(AR) $(subst /,\\,$(OBJS))
diff --git a/external/nss/nss.nspr-parallel-win-debug_build.patch b/external/nss/nss.nspr-parallel-win-debug_build.patch
new file mode 100644
index 000000000000..86b55e1ccf7f
--- /dev/null
+++ b/external/nss/nss.nspr-parallel-win-debug_build.patch
@@ -0,0 +1,40 @@
+Änderung:        4866:23940b78e965
+Nutzer:          Jan-Marek Glogowski <glogow at fbihome.de>
+Datum:           Fri May 01 22:50:55 2020 +0000
+Dateien:         pr/tests/Makefile.in
+Beschreibung:
+Bug 290526 Write separate PDBs for test OBJs r=glandium
+
+Quite often when running a parallel NSS build, I get the following
+compiler error message, resulting in a build failure, despite
+compiling with the -FS flag:
+
+.../nss/nspr/pr/tests/zerolen.c: fatal error C1041:
+Programmdatenbank "...\nss\nspr\out\pr\tests\vc140.pdb" kann nicht
+ge<94>ffnet werden; verwenden Sie /FS, wenn mehrere CL.EXE in
+dieselbe .PDB-Datei schreiben.
+
+The failing source file is always one of the last test object
+files. But the actual problem is not the compiler accessing the
+PDB file, but the linker already linking the first test
+executables accessing the shared PDB; at least that's my guess.
+
+So instead of using a shared PDB for all test object files, this
+uses -Fd$(@:.$(OBJ_SUFFIX)=.pdb) to write a separate PDB for every
+test's object file. The linker works fine with the shared OBJ PDB.
+
+Differential Revision: https://phabricator.services.mozilla.com/D68693
+
+
+diff -r 219d131499d5 -r 23940b78e965 nss/nspr/pr/tests/Makefile.in
+--- a/nss/nspr/pr/tests/Makefile.in	Mon Feb 10 20:58:42 2020 +0000
++++ b/nss/nspr/pr/tests/Makefile.in	Fri May 01 22:50:55 2020 +0000
+@@ -211,6 +211,7 @@
+ else
+   EXTRA_LIBS += ws2_32.lib
+   LDOPTS = -NOLOGO -DEBUG -DEBUGTYPE:CV -INCREMENTAL:NO
++  CFLAGS += -Fd$(@:.$(OBJ_SUFFIX)=.pdb)
+   ifdef PROFILE
+     LDOPTS += -PROFILE -MAP
+   endif # profile
+
diff --git a/external/nss/nss.windows.patch b/external/nss/nss.windows.patch
index 9dbeaa946520..901846e7bc1f 100644
--- a/external/nss/nss.windows.patch
+++ b/external/nss/nss.windows.patch
@@ -18,8 +18,8 @@
 -core_abspath = '$(if $(findstring :,$(1)),$(1),$(if $(filter /%,$(1)),$(1),$(PWD)/$(1)))'
 +core_abspath = '$(if $(findstring :,$(1)),$(1),$(if $(filter /%,$(shell cygpath -m $(1))),$(1),$(shell cygpath -m $(PWD)/$(1))))'
  
- $(OBJDIR)/$(PROG_PREFIX)%$(OBJ_SUFFIX): %.c
- 	@$(MAKE_OBJDIR)
+ $(OBJDIR)/$(PROG_PREFIX)%$(OBJ_SUFFIX): %.c | $$(@D)/d
+ ifdef USE_NT_C_SYNTAX
 --- a/a/nspr/pr/include/md/_win95.h
 +++ b/b/nspr/pr/include/md/_win95.h
 @@ -312,7 +312,7 @@
commit b2e75e593e4f6833f1fa19d6d2215a843ac1ef0f
Author:     Stephan Bergmann <sbergman at redhat.com>
AuthorDate: Wed Jan 15 17:16:02 2020 +0100
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 12:30:10 2020 +0200

    Remove a fragment from a file URL early on
    
    ...as ShellExecuteExW would ignore it anyway
    
    Change-Id: I969db094bb7d2ea230ac8c36eb23d71a90fbe466
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86868
    Tested-by: Jenkins
    Reviewed-by: Stephan Bergmann <sbergman at redhat.com>
    (cherry picked from commit 14b36a16b225bf7c988f118d499a7287c47cd83e)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86877
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>
    (cherry picked from commit 51da0d22ff42b20ab38130b7874651ef136ecceb)

diff --git a/shell/source/win32/SysShExec.cxx b/shell/source/win32/SysShExec.cxx
index 6648d3f8d8a8..f18022897e7f 100644
--- a/shell/source/win32/SysShExec.cxx
+++ b/shell/source/win32/SysShExec.cxx
@@ -281,6 +281,7 @@ void SAL_CALL CSysShExec::execute( const OUString& aCommand, const OUString& aPa
             static_cast< XSystemShellExecute* >( this ),
             3 );
 
+    OUString preprocessed_command(aCommand);
     if ((nFlags & URIS_ONLY) != 0)
     {
         css::uno::Reference< css::uri::XUriReference > uri(
@@ -294,8 +295,10 @@ void SAL_CALL CSysShExec::execute( const OUString& aCommand, const OUString& aPa
                 static_cast< cppu::OWeakObject * >(this), 0);
         }
         if (uri->getScheme().equalsIgnoreAsciiCase("file")) {
+            // ShellExecuteExW appears to ignore the fragment of a file URL anyway, so remove it:
+            uri->clearFragment();
+            preprocessed_command = uri->getUriReference();
             OUString pathname;
-            uri->clearFragment(); // getSystemPathFromFileURL fails for URLs with fragment
             auto const e1
                 = osl::FileBase::getSystemPathFromFileURL(uri->getUriReference(), pathname);
             if (e1 != osl::FileBase::E_None) {
@@ -399,7 +402,6 @@ void SAL_CALL CSysShExec::execute( const OUString& aCommand, const OUString& aPa
         and names no existing file (remember the jump mark
         sign '#' is a valid file name character we remove
         the jump mark, else ShellExecuteEx fails */
-    OUString preprocessed_command(aCommand);
     if (is_system_path(preprocessed_command))
     {
         if (has_jump_mark(preprocessed_command) && !is_existing_file(preprocessed_command))
commit 352c08e75555791922e365314220f7b55f18e8c5
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Mar 24 10:48:04 2020 +0100
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 12:29:56 2020 +0200

    icu: add patch to fix CVE-2020-10531
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/90971
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.stahl at cib.de>
    (cherry picked from commit 002d1152dc418f7d624409e76cd9d4ac0b42c7f8)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/90975
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    (cherry picked from commit 63b573faf984875cda7a879e696ea75fae81df57)
    
    Change-Id: I0aca4af1bd79f28bf1c920a4d05e80948106aaac
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/90998
    Tested-by: Michael Stahl <michael.stahl at cib.de>
    Reviewed-by: Michael Stahl <michael.stahl at cib.de>

diff --git a/external/icu/ExternalProject_icu.mk b/external/icu/ExternalProject_icu.mk
index 205817938539..838bef127e0e 100644
--- a/external/icu/ExternalProject_icu.mk
+++ b/external/icu/ExternalProject_icu.mk
@@ -13,7 +13,10 @@ $(eval $(call gb_ExternalProject_register_targets,icu,\
 	build \
 ))
 
-icu_CPPFLAGS:="-DHAVE_GCC_ATOMICS=$(if $(filter TRUE,$(GCC_HAVE_BUILTIN_ATOMIC)),1,0)"
+# -I to find o3tl headers
+icu_CPPFLAGS:=" \
+	-DHAVE_GCC_ATOMICS=$(if $(filter TRUE,$(GCC_HAVE_BUILTIN_ATOMIC)),1,0) \
+	-I$(SRCDIR)/include"
 
 ifeq ($(OS),WNT)
 
diff --git a/external/icu/UnpackedTarball_icu.mk b/external/icu/UnpackedTarball_icu.mk
index 304d71399561..4aebd830051b 100644
--- a/external/icu/UnpackedTarball_icu.mk
+++ b/external/icu/UnpackedTarball_icu.mk
@@ -29,6 +29,7 @@ $(eval $(call gb_UnpackedTarball_add_patches,icu,\
 	external/icu/icu4c-changeset-39671.patch.1 \
 	external/icu/icu4c-changeset-40324.patch.1 \
 	external/icu/icu4c-59-icu13329-xlocale.patch.1 \
+	external/icu/b7d08bc04a4296982fcef8b6b8a354a9e4e7afca.patch.2 \
 ))
 
 $(eval $(call gb_UnpackedTarball_add_file,icu,source/data/brkitr/khmerdict.dict,external/icu/khmerdict.dict))
diff --git a/external/icu/b7d08bc04a4296982fcef8b6b8a354a9e4e7afca.patch.2 b/external/icu/b7d08bc04a4296982fcef8b6b8a354a9e4e7afca.patch.2
new file mode 100644
index 000000000000..d3b34db670c5
--- /dev/null
+++ b/external/icu/b7d08bc04a4296982fcef8b6b8a354a9e4e7afca.patch.2
@@ -0,0 +1,37 @@
+From b7d08bc04a4296982fcef8b6b8a354a9e4e7afca Mon Sep 17 00:00:00 2001
+From: Frank Tang <ftang at chromium.org>
+Date: Sat, 1 Feb 2020 02:39:04 +0000
+Subject: [PATCH] ICU-20958 Prevent SEGV_MAPERR in append
+
+See #971
+---
+ icu4c/source/common/unistr.cpp          |  6 ++-
+ icu4c/source/test/intltest/ustrtest.cpp | 62 +++++++++++++++++++++++++
+ icu4c/source/test/intltest/ustrtest.h   |  1 +
+ 3 files changed, 68 insertions(+), 1 deletion(-)
+
+diff --git a/icu4c/source/common/unistr.cpp b/icu4c/source/common/unistr.cpp
+index 901bb3358ba..077b4d6ef20 100644
+--- a/icu4c/source/common/unistr.cpp
++++ b/icu4c/source/common/unistr.cpp
+@@ -31,6 +31,7 @@
+ #include "ustr_imp.h"
+ #include "umutex.h"
+ #include "uassert.h"
++#include <o3tl/safeint.hxx>
+ 
+ #if 0
+ 
+@@ -1563,7 +1563,11 @@ UnicodeString::doAppend(const UChar *srcChars, int32_t srcStart, int32_t srcLeng
+   }
+ 
+   int32_t oldLength = length();
+-  int32_t newLength = oldLength + srcLength;
++  int32_t newLength;
++  if (o3tl::checked_add(oldLength, srcLength, newLength)) {
++    setToBogus();
++    return *this;
++  }
+   // optimize append() onto a large-enough, owned string
+   if((newLength <= getCapacity() && isBufferWritable()) ||
+       cloneArrayIfNeeded(newLength, getGrowCapacity(newLength))) {
commit 5bda4b0243d66350e29384cc5d816f4939dd5f12
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Fri Jan 3 22:40:07 2020 +0300
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 11:21:47 2020 +0200

    tdf#93389: keep encryption information for autorecovered MS formats
    
    The autorecovery data is stored in ODF, regardless of the original
    document format. When restoring, type detection generates ODF data,
    which is stored in the media descriptor attached to document, even
    after real filter was restored (see AutoRecovery::implts_openDocs).
    If real filter is not ODF, then at the save time, it doesn't find
    necessary information in encryption data, and makes not encrypted
    package.
    
    This patch adds both MS binary data, and OOXML data, to existing
    ODF data for recovered password-protected documents (regardless of
    their real filter).
    
    TODO: only add required information to encryption data: pass real
    filter name to DocPasswordHelper::requestAndVerifyDocPassword from
    AutoRecovery::implts_openDocs.
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86201
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>
    Tested-by: Mike Kaganski <mike.kaganski at collabora.com>
    (cherry picked from commit dd198398b6e5c84ab1255a90ef96e6445b66a64f)
    
    Conflicts:
            comphelper/source/misc/docpasswordhelper.cxx
    
    (cherry picked from commit 6017cdff264afc3b98beeba1330d6df28102fe7a)
    
    Change-Id: I4717f067ad3c40167312b99eefef5584a467bfed

diff --git a/comphelper/source/misc/docpasswordhelper.cxx b/comphelper/source/misc/docpasswordhelper.cxx
index f3baa93091c0..c4f380691f46 100644
--- a/comphelper/source/misc/docpasswordhelper.cxx
+++ b/comphelper/source/misc/docpasswordhelper.cxx
@@ -20,6 +20,8 @@
 #include <algorithm>
 
 #include <comphelper/docpasswordhelper.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/storagehelper.hxx>
 #include <comphelper/sequence.hxx>
 #include <com/sun/star/beans/PropertyValue.hpp>
 #include <com/sun/star/task/XInteractionHandler.hpp>
@@ -360,6 +362,25 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence(
     OUString aPassword;
     DocPasswordVerifierResult eResult = DocPasswordVerifierResult::WrongPassword;
 
+    sal_Int32 nMediaEncDataCount = rMediaEncData.getLength();
+
+    // tdf#93389: if the document is being restored from autorecovery, we need to add encryption
+    // data also for real document type.
+    // TODO: get real filter name here (from CheckPasswd_Impl), to only add necessary data
+    bool bForSalvage = false;
+    if (nMediaEncDataCount)
+    {
+        for (auto& val : rMediaEncData)
+        {
+            if (val.Name == "ForSalvage")
+            {
+                --nMediaEncDataCount; // don't consider this element below
+                val.Value >>= bForSalvage;
+                break;
+            }
+        }
+    }
+
     // first, try provided default passwords
     if( pbIsDefaultPassword )
         *pbIsDefaultPassword = false;
@@ -384,7 +405,7 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence(
     // try media encryption data (skip, if result is OK or ABORT)
     if( eResult == DocPasswordVerifierResult::WrongPassword )
     {
-        if( rMediaEncData.getLength() > 0 )
+        if (nMediaEncDataCount)
         {
             eResult = rVerifier.verifyEncryptionData( rMediaEncData );
             if( eResult == DocPasswordVerifierResult::OK )
@@ -443,6 +464,26 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence(
             aEncData = comphelper::concatSequences(
                 aEncData, OStorageHelper::CreatePackageEncryptionData(aPassword));
         }
+
+        if (bForSalvage)
+        {
+            // TODO: add individual methods for different target filter, and only call what's needed
+
+            // 1. Prepare binary MS formats encryption data
+            auto aUniqueID = GenerateRandomByteSequence(16);
+            auto aEnc97Key = GenerateStd97Key(aPassword.getStr(), aUniqueID);
+            // 2. Add MS binary and OOXML encryption data to result
+            uno::Sequence< beans::NamedValue > aContainer(3);
+            aContainer[0].Name = "STD97EncryptionKey";
+            aContainer[0].Value <<= aEnc97Key;
+            aContainer[1].Name = "STD97UniqueID";
+            aContainer[1].Value <<= aUniqueID;
+            aContainer[2].Name = "OOXPassword";
+            aContainer[2].Value <<= aPassword;
+
+            aEncData = comphelper::concatSequences(
+                aEncData, aContainer);
+        }
     }
 
     return (eResult == DocPasswordVerifierResult::OK) ? aEncData : uno::Sequence< beans::NamedValue >();
diff --git a/package/source/xstor/owriteablestream.cxx b/package/source/xstor/owriteablestream.cxx
index 9c4c6f3cc680..a5cb9d0383a0 100644
--- a/package/source/xstor/owriteablestream.cxx
+++ b/package/source/xstor/owriteablestream.cxx
@@ -79,9 +79,11 @@ struct WSInternalData_Impl
 namespace package
 {
 
-bool PackageEncryptionDatasEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 )
+bool PackageEncryptionDataLessOrEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 )
 {
-    bool bResult = !aHash1.empty() && aHash1.size() == aHash2.size();
+    // tdf#93389: aHash2 may contain more than in aHash1, if it contains also data for other package
+    // formats (as in case of autorecovery)
+    bool bResult = !aHash1.empty() && aHash1.size() <= aHash2.size();
     for ( ::comphelper::SequenceAsHashMap::const_iterator aIter = aHash1.begin();
           bResult && aIter != aHash1.end();
           ++aIter )
@@ -1164,7 +1166,7 @@ uno::Reference< io::XStream > OWriteStream_Impl::GetStream( sal_Int32 nStreamMod
 
     if ( m_bHasCachedEncryptionData )
     {
-        if ( !::package::PackageEncryptionDatasEqual( m_aEncryptionData, aEncryptionData ) )
+        if ( !::package::PackageEncryptionDataLessOrEqual( m_aEncryptionData, aEncryptionData ) )
             throw packages::WrongPasswordException();
 
         // the correct key must be set already
diff --git a/package/source/xstor/owriteablestream.hxx b/package/source/xstor/owriteablestream.hxx
index dde8375155bd..0ef32efe2adf 100644
--- a/package/source/xstor/owriteablestream.hxx
+++ b/package/source/xstor/owriteablestream.hxx
@@ -62,7 +62,8 @@ struct MutexHolder
 };
 
 namespace package {
-    bool PackageEncryptionDatasEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 );
+    // all data in aHash1 is contained in aHash2
+    bool PackageEncryptionDataLessOrEqual( const ::comphelper::SequenceAsHashMap& aHash1, const ::comphelper::SequenceAsHashMap& aHash2 );
 }
 
 struct WSInternalData_Impl;
diff --git a/package/source/xstor/xstorage.cxx b/package/source/xstor/xstorage.cxx
index db5ddcd8ba5a..ab528b157d14 100644
--- a/package/source/xstor/xstorage.cxx
+++ b/package/source/xstor/xstorage.cxx
@@ -858,7 +858,7 @@ void OStorage_Impl::CopyStorageElement( SotElement_Impl* pElement,
                 SAL_INFO("package.xstor", "No Encryption: " << rNoEncryptionException.Message);
             }
 
-            if (bHasCommonEncryptionData && ::package::PackageEncryptionDatasEqual(pElement->m_xStream->GetCachedEncryptionData(), aCommonEncryptionData))
+            if (bHasCommonEncryptionData && ::package::PackageEncryptionDataLessOrEqual(pElement->m_xStream->GetCachedEncryptionData(), aCommonEncryptionData))
             {
                 // If the stream can be opened with the common storage password
                 // it must be stored with the common storage password as well
diff --git a/sfx2/source/appl/appopen.cxx b/sfx2/source/appl/appopen.cxx
index ca6901737e27..ae4534ee1e49 100644
--- a/sfx2/source/appl/appopen.cxx
+++ b/sfx2/source/appl/appopen.cxx
@@ -48,6 +48,7 @@
 #include <comphelper/processfactory.hxx>
 #include <comphelper/storagehelper.hxx>
 #include <comphelper/string.hxx>
+#include <comphelper/sequence.hxx>
 #include <comphelper/synchronousdispatch.hxx>
 
 #include <vcl/wrkwin.hxx>
@@ -237,6 +238,21 @@ sal_uInt32 CheckPasswd_Impl
                             if ( pEncryptionDataItem )
                                 pEncryptionDataItem->GetValue() >>= aEncryptionData;
 
+                            // tdf#93389: if recoverying a document, encryption data should contain
+                            // entries for the real filter, not only for recovery ODF, to keep it
+                            // encrypted. Pass this in encryption data.
+                            // TODO: pass here the real filter (from AutoRecovery::implts_openDocs)
+                            // to marshal this to requestAndVerifyDocPassword
+                            if (pSet->GetItemState(SID_DOC_SALVAGE, false) == SfxItemState::SET)
+                            {
+                                uno::Sequence< beans::NamedValue > aContainer(1);
+                                aContainer[0].Name = "ForSalvage";
+                                aContainer[0].Value <<= true;
+
+                                aEncryptionData = comphelper::concatSequences(
+                                    aEncryptionData, aContainer);
+                            }
+
                             SfxDocPasswordVerifier aVerifier( xStorage );
                             aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
                                 aVerifier, aEncryptionData, aPassword, xInteractionHandler, pFile->GetOrigURL(), comphelper::DocPasswordRequestType::Standard );
commit f6feb7a6bc7ecbbe1b1cdb527bd52d7516086c32
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Fri Nov 29 13:07:57 2019 +0300
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 11:21:47 2020 +0200

    tdf#118639: store ODF encryption data for autorecovery
    
    When saving autorecovery information, ODF is used. If the original
    document is password-protected, its autorecovery is also generated
    password-protected (since ef87ff6680f79362a431db6e7ef2f40cfc576219).
    But when the stored encryption data for non-ODF document does not
    contain "PackageSHA256UTF8EncryptionKey" value, following
    ZipPackage::GetEncryptionKey fails, so the whole save fails.
    
    So just generate and append ODF encryption keys where we still have
    user password.
    
    Reviewed-on: https://gerrit.libreoffice.org/84052
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>
    (cherry picked from commit 63634738dd03cc74806ce6843c16ff5e51a371a0)
    Reviewed-on: https://gerrit.libreoffice.org/84133
    Reviewed-by: Xisco Faulí <xiscofauli at libreoffice.org>
    (cherry picked from commit e569dc9824e95617d921bb8f115d243aea0125b9)
    Reviewed-on: https://gerrit.libreoffice.org/84232
    Reviewed-by: Adolfo Jayme Barrientos <fitojb at ubuntu.com>
    
    Change-Id: I776e28de784489521e4941d1075690f90c056014
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94355
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Andras Timar <andras.timar at collabora.com>

diff --git a/comphelper/source/misc/docpasswordhelper.cxx b/comphelper/source/misc/docpasswordhelper.cxx
index 042421ac29d0..f3baa93091c0 100644
--- a/comphelper/source/misc/docpasswordhelper.cxx
+++ b/comphelper/source/misc/docpasswordhelper.cxx
@@ -20,6 +20,7 @@
 #include <algorithm>
 
 #include <comphelper/docpasswordhelper.hxx>
+#include <comphelper/sequence.hxx>
 #include <com/sun/star/beans/PropertyValue.hpp>
 #include <com/sun/star/task/XInteractionHandler.hpp>
 
@@ -356,6 +357,7 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence(
         bool* pbIsDefaultPassword )
 {
     css::uno::Sequence< css::beans::NamedValue > aEncData;
+    OUString aPassword;
     DocPasswordVerifierResult eResult = DocPasswordVerifierResult::WrongPassword;
 
     // first, try provided default passwords
@@ -369,8 +371,12 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence(
             if( !aIt->isEmpty() )
             {
                 eResult = rVerifier.verifyPassword( *aIt, aEncData );
-                if( pbIsDefaultPassword )
-                    *pbIsDefaultPassword = eResult == DocPasswordVerifierResult::OK;
+                if (eResult == DocPasswordVerifierResult::OK)
+                {
+                    aPassword = *aIt;
+                    if (pbIsDefaultPassword)
+                        *pbIsDefaultPassword = true;
+                }
             }
         }
     }
@@ -390,7 +396,11 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence(
     if( eResult == DocPasswordVerifierResult::WrongPassword )
     {
         if( !rMediaPassword.isEmpty() )
+        {
             eResult = rVerifier.verifyPassword( rMediaPassword, aEncData );
+            if (eResult == DocPasswordVerifierResult::OK)
+                aPassword = rMediaPassword;
+        }
     }
 
     // request a password (skip, if result is OK or ABORT)
@@ -406,6 +416,8 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence(
             {
                 if( !pRequest->getPassword().isEmpty() )
                     eResult = rVerifier.verifyPassword( pRequest->getPassword(), aEncData );
+                if (eResult == DocPasswordVerifierResult::OK)
+                    aPassword = pRequest->getPassword();
             }
             else
             {
@@ -418,6 +430,21 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence(
     {
     }
 
+    if (eResult == DocPasswordVerifierResult::OK && !aPassword.isEmpty())
+    {
+        if (std::find_if(std::cbegin(aEncData), std::cend(aEncData),
+                         [](const css::beans::NamedValue& val) {
+                             return val.Name == PACKAGE_ENCRYPTIONDATA_SHA256UTF8;
+                         })
+            == std::cend(aEncData))
+        {
+            // tdf#118639: We need ODF encryption data for autorecovery, where password
+            // will already be unavailable, so generate and append it here
+            aEncData = comphelper::concatSequences(
+                aEncData, OStorageHelper::CreatePackageEncryptionData(aPassword));
+        }
+    }
+
     return (eResult == DocPasswordVerifierResult::OK) ? aEncData : uno::Sequence< beans::NamedValue >();
 }
 
diff --git a/sfx2/source/dialog/filedlghelper.cxx b/sfx2/source/dialog/filedlghelper.cxx
index 2026be6ad82e..96552e94f72f 100644
--- a/sfx2/source/dialog/filedlghelper.cxx
+++ b/sfx2/source/dialog/filedlghelper.cxx
@@ -2644,6 +2644,8 @@ ErrCode RequestPassword(const std::shared_ptr<const SfxFilter>& pCurrentFilter,
     {
         if ( pPasswordRequest->getPassword().getLength() )
         {
+            css::uno::Sequence< css::beans::NamedValue > aEncryptionData;
+
             // TODO/LATER: The filters should show the password dialog themself in future
             if ( bMSType )
             {
@@ -2652,7 +2654,7 @@ ErrCode RequestPassword(const std::shared_ptr<const SfxFilter>& pCurrentFilter,
                 {
                     ::comphelper::SequenceAsHashMap aHashData;
                     aHashData[ OUString( "OOXPassword"  ) ] <<= pPasswordRequest->getPassword();
-                    pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aHashData.getAsConstNamedValueList() ) ) );
+                    aEncryptionData = aHashData.getAsConstNamedValueList();
                 }
                 else
                 {
@@ -2665,7 +2667,7 @@ ErrCode RequestPassword(const std::shared_ptr<const SfxFilter>& pCurrentFilter,
                         aHashData[ OUString( "STD97EncryptionKey"  ) ] <<= aEncryptionKey;
                         aHashData[ OUString( "STD97UniqueID"  ) ] <<= aUniqueID;
 
-                        pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aHashData.getAsConstNamedValueList() ) ) );
+                        aEncryptionData = aHashData.getAsConstNamedValueList();
                     }
                     else
                     {
@@ -2673,10 +2675,14 @@ ErrCode RequestPassword(const std::shared_ptr<const SfxFilter>& pCurrentFilter,
                     }
                 }
             }
-            else
-            {
-                pSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( ::comphelper::OStorageHelper::CreatePackageEncryptionData( pPasswordRequest->getPassword() ) ) ) );
-            }
+
+            // tdf#118639: We need ODF encryption data for autorecovery where password will already
+            // be unavailable, even for non-ODF documents, so append it here unconditionally
+            pSet->Put(SfxUnoAnyItem(
+                SID_ENCRYPTIONDATA,
+                uno::makeAny(comphelper::concatSequences(
+                    aEncryptionData, comphelper::OStorageHelper::CreatePackageEncryptionData(
+                                         pPasswordRequest->getPassword())))));
         }
 
         if ( pPasswordRequest->getRecommendReadOnly() )
commit 3d82848922dec9d5f4de13fa95567ff3354c0343
Author:     Vasily Melenchuk <vasily.melenchuk at cib.de>
AuthorDate: Mon Feb 17 10:52:11 2020 +0300
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 11:21:47 2020 +0200

    tdf#129096: Document Recovery: Use TypeDetection on load
    
    Loading of recovered document happend before via XFilter::filter
    is not updating media descriptor of document. But this is
    important for password protected documents to store entered password
    and used encryption type.
    
    To avoid this problem let's use TypeDetection which during its work
    will ask user for password and store all the info in modified media
    descriptor before actual recovery attempt.
    
    Change-Id: Ide2ebf0955e0937cdc7c9d7165593b71f904649b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88844
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
    Tested-by: Jenkins
    (cherry picked from commit 8461127750e1fe92a615409505256132e54fb8e8)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89789
    Reviewed-by: Vasily Melenchuk <vasily.melenchuk at cib.de>
    (cherry picked from commit b05c87f00433987b10542866696f0b4aaad015cc)
    (cherry picked from commit ba8b744086443b197e88397aa09a67fb263eb9d9)

diff --git a/framework/source/services/autorecovery.cxx b/framework/source/services/autorecovery.cxx
index 48cb5bad7861..982cf93685cc 100644
--- a/framework/source/services/autorecovery.cxx
+++ b/framework/source/services/autorecovery.cxx
@@ -55,6 +55,7 @@
 #include <com/sun/star/beans/PropertyAttribute.hpp>
 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
 #include <com/sun/star/document/XDocumentRecovery.hpp>
+#include <com/sun/star/document/XExtendedFilterDetection.hpp>
 #include <com/sun/star/util/XCloseable.hpp>
 #include <com/sun/star/awt/XWindow2.hpp>
 #include <com/sun/star/task/XStatusIndicatorFactory.hpp>
@@ -3406,6 +3407,37 @@ void AutoRecovery::implts_openOneDoc(const OUString&               sURL       ,
         }
         else
         {
+            OUString sFilterName;
+            lDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] >>= sFilterName;
+            if (!sFilterName.isEmpty()
+                && (   sFilterName == "Calc MS Excel 2007 XML"
+                    || sFilterName == "Impress MS PowerPoint 2007 XML"
+                    || sFilterName == "MS Word 2007 XML"))
+                // TODO: Propbably need to check other affected formats + templates?
+            {
+                // tdf#129096: in case of recovery of password protected OOXML document it is done not
+                // the same way as ordinal loading. Inside XDocumentRecovery::recoverFromFile
+                // there is a call to XFilter::filter which has constant media descriptor and thus
+                // all encryption data used in document is lost. To avoid this try to walkaround
+                // with explicit call to FormatDetector. It will try to load document, prompt for password
+                // and store this info in media descriptor we will use for recoverFromFile call.
+                Reference< css::document::XExtendedFilterDetection > xDetection(
+                    m_xContext->getServiceManager()->createInstanceWithContext(
+                        "com.sun.star.comp.oox.FormatDetector", m_xContext),
+                    UNO_QUERY_THROW);
+                lDescriptor[utl::MediaDescriptor::PROP_URL()] <<= sURL;
+                Sequence< css::beans::PropertyValue > aDescriptorSeq = lDescriptor.getAsConstPropertyValueList();
+                OUString sType = xDetection->detect(aDescriptorSeq);
+
+                OUString sNewFilterName;
+                lDescriptor[utl::MediaDescriptor::PROP_FILTERNAME()] >>= sNewFilterName;
+                if (!sType.isEmpty() && sNewFilterName == sFilterName)
+                {
+                    // Filter detection was okay, update media descriptor with one received from FilterDetect
+                    lDescriptor = aDescriptorSeq;
+                }
+            }
+
             // let it recover itself
             Reference< XDocumentRecovery > xDocRecover( xModel, UNO_QUERY_THROW );
             xDocRecover->recoverFromFile(
commit 11927b70f0394c2f255fc78663fe87a1f68c966b
Author:     Caolán McNamara <caolanm at redhat.com>
AuthorDate: Mon May 11 20:46:43 2020 +0100
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 11:21:46 2020 +0200

    limit forms to http[s]
    
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94015
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.stahl at cib.de>
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    (cherry picked from commit a5458d1f219c8a67d2c4c90fdbdf8ffba40d769d)
    
    Change-Id: I3ed0bc626f693ec03f610dc7361f93cad914c9d8

diff --git a/forms/source/xforms/submission.cxx b/forms/source/xforms/submission.cxx
index a0cd6e9fcdba..2fd49f35ef69 100644
--- a/forms/source/xforms/submission.cxx
+++ b/forms/source/xforms/submission.cxx
@@ -254,7 +254,11 @@ bool Submission::doSubmit( const Reference< XInteractionHandler >& xHandler )
         return false;
     }
 
+    if (!xSubmission->IsWebProtocol())
+        return false;
+
     xSubmission->setEncoding(getEncoding());
+
     CSubmission::SubmissionResult aResult = xSubmission->submit( xHandler );
 
     if (aResult == CSubmission::SUCCESS)
diff --git a/forms/source/xforms/submission/submission.hxx b/forms/source/xforms/submission/submission.hxx
index facbc64d5be7..a8b887615df3 100644
--- a/forms/source/xforms/submission/submission.hxx
+++ b/forms/source/xforms/submission/submission.hxx
@@ -129,6 +129,12 @@ public:
         , m_xContext(::comphelper::getProcessComponentContext())
     {}
 
+    bool IsWebProtocol() const
+    {
+        INetProtocol eProtocol = m_aURLObj.GetProtocol();
+        return eProtocol == INetProtocol::Http || eProtocol == INetProtocol::Https;
+    }
+
     virtual ~CSubmission() {}
 
     void setEncoding(const OUString& aEncoding)
commit b41693a64c9b5ff926398014639e7b018ddff76f
Author:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
AuthorDate: Mon Sep 28 11:21:23 2020 +0200
Commit:     Samuel Mehrbrodt <Samuel.Mehrbrodt at cib.de>
CommitDate: Mon Sep 28 11:21:23 2020 +0200

    Add switch to disable opencl
    
    Manually ported from 63972e79bbb9ea9654e755381641052632b0402c
    
    Change-Id: I81c8a13b81aaafea36ea92d01f0d50d90f1ea73c

diff --git a/configure.ac b/configure.ac
index cdbb9401c78d..83fe089baf59 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1516,6 +1516,11 @@ libo_FUZZ_ARG_ENABLE(formula-logger,
     )
 )
 
+AC_ARG_ENABLE(opencl,
+    AS_HELP_STRING([--disable-opencl],
+        [Disable OpenCL support.]),
+,enable_opencl=yes)
+
 dnl ===================================================================
 dnl Optional Packages (--with/without-)
 dnl ===================================================================
@@ -10253,7 +10258,7 @@ dnl =================================================
 dnl Check whether to build with OpenCL support.
 dnl =================================================
 
-if test $_os != iOS -a $_os != Android; then
+if test $_os != iOS -a $_os != Android -a "$ENABLE_FUZZERS" != "TRUE" -a "$enable_opencl" = "yes"; then
     # OPENCL in BUILD_TYPE and HAVE_FEATURE_OPENCL tell that OpenCL is potentially available on the
     # platform (optional at run-time, used through clew).
     BUILD_TYPE="$BUILD_TYPE OPENCL"


More information about the Libreoffice-commits mailing list