From a2baea7faff31d26459dab3668a39eae85e4991b Mon Sep 17 00:00:00 2001
From: Daniel Baumann <daniel.baumann@progress-linux.org>
Date: Mon, 15 Apr 2024 11:27:30 +0200
Subject: Adding upstream version 4:24.2.1.

Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
---
 package/source/manifest/ManifestDefines.hxx    |  9 ++++--
 package/source/manifest/ManifestImport.cxx     | 25 ++++++++++++--
 package/source/manifest/ManifestImport.hxx     |  1 +
 package/source/zipapi/ZipFile.cxx              | 45 ++++++++++++++++++++++++--
 package/source/zippackage/ZipPackage.cxx       | 17 ++++++++++
 package/source/zippackage/ZipPackageStream.cxx | 10 ++++--
 6 files changed, 97 insertions(+), 10 deletions(-)

(limited to 'package')

diff --git a/package/source/manifest/ManifestDefines.hxx b/package/source/manifest/ManifestDefines.hxx
index dbe7b985b8..c2f5e2778a 100644
--- a/package/source/manifest/ManifestDefines.hxx
+++ b/package/source/manifest/ManifestDefines.hxx
@@ -70,9 +70,12 @@ inline constexpr OUString ELEMENT_KEY_DERIVATION = u"manifest:key-derivation"_us
 inline constexpr OUString ATTRIBUTE_KEY_DERIVATION_NAME  = u"manifest:key-derivation-name"_ustr;
 inline constexpr OUString ATTRIBUTE_SALT  = u"manifest:salt"_ustr;
 inline constexpr OUString ATTRIBUTE_ITERATION_COUNT = u"manifest:iteration-count"_ustr;
-inline constexpr OUString ATTRIBUTE_ARGON2_T_LO= u"loext:argon2-iterations"_ustr;
-inline constexpr OUString ATTRIBUTE_ARGON2_M_LO= u"loext:argon2-memory"_ustr;
-inline constexpr OUString ATTRIBUTE_ARGON2_P_LO= u"loext:argon2-lanes"_ustr;
+inline constexpr OUString ATTRIBUTE_ARGON2_T = u"manifest:argon2-iterations"_ustr;
+inline constexpr OUString ATTRIBUTE_ARGON2_M = u"manifest:argon2-memory"_ustr;
+inline constexpr OUString ATTRIBUTE_ARGON2_P = u"manifest:argon2-lanes"_ustr;
+inline constexpr OUString ATTRIBUTE_ARGON2_T_LO = u"loext:argon2-iterations"_ustr;
+inline constexpr OUString ATTRIBUTE_ARGON2_M_LO = u"loext:argon2-memory"_ustr;
+inline constexpr OUString ATTRIBUTE_ARGON2_P_LO = u"loext:argon2-lanes"_ustr;
 
 /// OFFICE-3708: wrong URL cited in ODF 1.2 and used since OOo 3.4 beta
 inline constexpr OUString SHA256_URL_ODF12 = u"http://www.w3.org/2000/09/xmldsig#sha256"_ustr;
diff --git a/package/source/manifest/ManifestImport.cxx b/package/source/manifest/ManifestImport.cxx
index f6f4ce36f4..77f795efdc 100644
--- a/package/source/manifest/ManifestImport.cxx
+++ b/package/source/manifest/ManifestImport.cxx
@@ -242,11 +242,17 @@ void ManifestImport::doKeyDerivation(StringHashMap &rConvertedAttribs)
         {
             aSequence[PKG_MNFST_KDF].Value <<= xml::crypto::KDFID::Argon2id;
 
-            aString = rConvertedAttribs[ATTRIBUTE_ARGON2_T_LO];
+            aString = rConvertedAttribs.find(ATTRIBUTE_ARGON2_T) != rConvertedAttribs.end()
+                ? rConvertedAttribs[ATTRIBUTE_ARGON2_T]
+                : rConvertedAttribs[ATTRIBUTE_ARGON2_T_LO];
             sal_Int32 const t(aString.toInt32());
-            aString = rConvertedAttribs[ATTRIBUTE_ARGON2_M_LO];
+            aString = rConvertedAttribs.find(ATTRIBUTE_ARGON2_M) != rConvertedAttribs.end()
+                ? rConvertedAttribs[ATTRIBUTE_ARGON2_M]
+                : rConvertedAttribs[ATTRIBUTE_ARGON2_M_LO];
             sal_Int32 const m(aString.toInt32());
-            aString = rConvertedAttribs[ATTRIBUTE_ARGON2_P_LO];
+            aString = rConvertedAttribs.find(ATTRIBUTE_ARGON2_P) != rConvertedAttribs.end()
+                ? rConvertedAttribs[ATTRIBUTE_ARGON2_P]
+                : rConvertedAttribs[ATTRIBUTE_ARGON2_P_LO];
             sal_Int32 const p(aString.toInt32());
             if (0 < t && 0 < m && 0 < p)
             {
@@ -321,6 +327,7 @@ void SAL_CALL ManifestImport::startElement( const OUString& aName, const uno::Re
 
     switch (nLevel) {
     case 1: {
+        m_PackageVersion = aConvertedAttribs[ATTRIBUTE_VERSION];
         if (aConvertedName != ELEMENT_MANIFEST) //manifest:manifest
             aStack.back().m_bValid = false;
         break;
@@ -445,6 +452,18 @@ void SAL_CALL ManifestImport::endElement( const OUString& aName )
         return;
 
     if ( aConvertedName == ELEMENT_FILE_ENTRY && aStack.back().m_bValid ) {
+        // required for wholesome encryption: if there is no document and hence
+        // no file-entry with a version attribute, send the package's version
+        // with the first file-entry.
+        // (note: the only case when a valid ODF document has no "/" entry with
+        // a version is when it is ODF 1.0/1.1 and then it doesn't have the
+        // package version either)
+        if (rManVector.empty() && !m_PackageVersion.isEmpty()
+            && !aSequence[PKG_MNFST_VERSION].Value.hasValue())
+        {
+            aSequence[PKG_MNFST_VERSION].Name = u"Version"_ustr;
+            aSequence[PKG_MNFST_VERSION].Value <<= m_PackageVersion;
+        }
         // the first entry gets KeyInfo element if any, for PGP encryption
         if (!bIgnoreEncryptData && !aKeys.empty() && rManVector.empty())
         {
diff --git a/package/source/manifest/ManifestImport.hxx b/package/source/manifest/ManifestImport.hxx
index fd86e02e4f..883f1de623 100644
--- a/package/source/manifest/ManifestImport.hxx
+++ b/package/source/manifest/ManifestImport.hxx
@@ -61,6 +61,7 @@ class ManifestImport final : public cppu::WeakImplHelper < css::xml::sax::XDocum
     bool bPgpEncryption;
     sal_Int32 nDerivedKeySize;
     ::std::vector < css::uno::Sequence < css::beans::PropertyValue > > & rManVector;
+    OUString m_PackageVersion; // on root element
 
 
     OUString PushNameAndNamespaces( const OUString& aName,
diff --git a/package/source/zipapi/ZipFile.cxx b/package/source/zipapi/ZipFile.cxx
index 474b73ff53..3d382bd3a3 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -38,6 +38,7 @@
 #include <rtl/digest.h>
 #include <sal/log.hxx>
 #include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
 #include <osl/diagnose.h>
 
 #include <algorithm>
@@ -1073,7 +1074,7 @@ sal_Int32 ZipFile::readCEN()
             if ( nTestSig != CENSIG )
                 throw ZipException("Invalid CEN header (bad signature)" );
 
-            aMemGrabber.skipBytes ( 2 );
+            sal_uInt16 versionMadeBy = aMemGrabber.ReadUInt16();
             aEntry.nVersion = aMemGrabber.ReadInt16();
             aEntry.nFlag = aMemGrabber.ReadInt16();
 
@@ -1093,7 +1094,8 @@ sal_Int32 ZipFile::readCEN()
             aEntry.nPathLen = aMemGrabber.ReadInt16();
             aEntry.nExtraLen = aMemGrabber.ReadInt16();
             nCommentLen = aMemGrabber.ReadInt16();
-            aMemGrabber.skipBytes ( 8 );
+            aMemGrabber.skipBytes ( 4 );
+            sal_uInt32 externalFileAttributes = aMemGrabber.ReadUInt32();
             sal_uInt64 nOffset = aMemGrabber.ReadUInt32();
 
             if ( aEntry.nPathLen < 0 )
@@ -1132,6 +1134,15 @@ sal_Int32 ZipFile::readCEN()
                 throw ZipException("Integer-overflow");
 
             aMemGrabber.skipBytes(nCommentLen);
+
+            // Is this a FAT-compatible empty entry?
+            if (aEntry.nSize == 0 && (versionMadeBy & 0xff00) == 0)
+            {
+                constexpr sal_uInt32 FILE_ATTRIBUTE_DIRECTORY = 16;
+                if (externalFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+                    continue; // This is a directory entry, not a stream - skip it
+            }
+
             aEntries[aEntry.sPath] = aEntry;
         }
 
@@ -1253,6 +1264,7 @@ void ZipFile::recover()
                                                               RTL_TEXTENCODING_UTF8 );
                                     aEntry.nPathLen = static_cast< sal_Int16 >(aFileName.getLength());
                                 }
+                                aEntry.sPath = aEntry.sPath.replace('\\', '/');
 
                                 // read 64bit header
                                 if (aEntry.nExtraLen > 0)
@@ -1294,7 +1306,36 @@ void ZipFile::recover()
                                         aEntry.nSize = 0;
                                     }
 
+                                    // Do not add this entry, if it is empty and is a directory of
+                                    // an already existing entry
+                                    if (aEntry.nSize == 0 && aEntry.nCompressedSize == 0
+                                        && std::find_if(
+                                               aEntries.begin(), aEntries.end(),
+                                               [path = OUString(aEntry.sPath + "/")](const auto& r)
+                                               { return r.first.startsWith(path); })
+                                               != aEntries.end())
+                                    {
+                                        nPos += 4;
+                                        continue;
+                                    }
+
                                     aEntries.emplace( aEntry.sPath, aEntry );
+
+                                    // Drop any "directory" entry corresponding to this one's path;
+                                    // since we don't use central directory, we don't see external
+                                    // file attributes, so sanitize here
+                                    sal_Int32 i = 0;
+                                    for (OUString subdir = aEntry.sPath.getToken(0, '/', i); i >= 0;
+                                         subdir += OUString::Concat("/")
+                                                   + o3tl::getToken(aEntry.sPath, 0, '/', i))
+                                    {
+                                        if (auto it = aEntries.find(subdir); it != aEntries.end())
+                                        {
+                                            // if not empty, let it fail later in ZipPackage::getZipFileContents
+                                            if (it->second.nSize == 0 && it->second.nCompressedSize == 0)
+                                                aEntries.erase(it);
+                                        }
+                                    }
                                 }
                             }
                         }
diff --git a/package/source/zippackage/ZipPackage.cxx b/package/source/zippackage/ZipPackage.cxx
index 02f7cf71e8..0f3fa6ff7d 100644
--- a/package/source/zippackage/ZipPackage.cxx
+++ b/package/source/zippackage/ZipPackage.cxx
@@ -171,6 +171,7 @@ void ZipPackage::parseManifest()
         return;
 
     bool bManifestParsed = false;
+    ::std::optional<OUString> oFirstVersion;
     static constexpr OUString sMeta (u"META-INF"_ustr);
     if ( m_xRootFolder->hasByName( sMeta ) )
     {
@@ -216,7 +217,13 @@ void ZipPackage::parseManifest()
                             if ( rValue.Name == sPropFullPath )
                                 rValue.Value >>= sPath;
                             else if ( rValue.Name == sPropVersion )
+                            {
                                 rValue.Value >>= sVersion;
+                                if (!oFirstVersion)
+                                {
+                                    oFirstVersion.emplace(sVersion);
+                                }
+                            }
                             else if ( rValue.Name == sPropMediaType )
                                 rValue.Value >>= sMediaType;
                             else if ( rValue.Name == sPropSalt )
@@ -457,6 +464,11 @@ void ZipPackage::parseManifest()
             {
                 // accept only types that look similar to own mediatypes
                 m_xRootFolder->SetMediaType( aPackageMediatype );
+                // also set version explicitly
+                if (oFirstVersion && m_xRootFolder->GetVersion().isEmpty())
+                {
+                    m_xRootFolder->SetVersion(*oFirstVersion);
+                }
                 // if there is an encrypted inner package, there is no root
                 // document, because instead there is a package, and it is not
                 // an error
@@ -1716,6 +1728,11 @@ uno::Sequence< sal_Int8 > ZipPackage::GetEncryptionKey()
         for ( const auto& rKey : std::as_const(m_aStorageEncryptionKeys) )
             if ( rKey.Name == aNameToFind )
                 rKey.Value >>= aResult;
+
+        if (!aResult.hasElements() && m_aStorageEncryptionKeys.hasElements())
+        {   // tdf#159519 sanity check
+            throw uno::RuntimeException(THROW_WHERE "Expected key is missing!");
+        }
     }
     else
         aResult = m_aEncryptionKey;
diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx
index d3068a6665..a5d4a0f7ce 100644
--- a/package/source/zippackage/ZipPackageStream.cxx
+++ b/package/source/zippackage/ZipPackageStream.cxx
@@ -592,8 +592,14 @@ bool ZipPackageStream::saveChild(
                 uno::Sequence<sal_Int8> aSalt(16);
                 // note: for GCM it's particularly important that IV is unique
                 uno::Sequence<sal_Int8> aVector(GetIVSize());
-                rtl_random_getBytes ( rRandomPool, aSalt.getArray(), 16 );
-                rtl_random_getBytes ( rRandomPool, aVector.getArray(), aVector.getLength() );
+                if (rtl_random_getBytes(rRandomPool, aSalt.getArray(), 16) != rtl_Random_E_None)
+                {
+                    throw uno::RuntimeException("rtl_random_getBytes failed");
+                }
+                if (rtl_random_getBytes(rRandomPool, aVector.getArray(), aVector.getLength()) != rtl_Random_E_None)
+                {
+                    throw uno::RuntimeException("rtl_random_getBytes failed");
+                }
                 if ( !m_bHaveOwnKey )
                 {
                     m_aEncryptionKey = rEncryptionKey;
-- 
cgit v1.2.3