diff options
Diffstat (limited to 'package')
-rw-r--r-- | package/source/manifest/ManifestDefines.hxx | 9 | ||||
-rw-r--r-- | package/source/manifest/ManifestImport.cxx | 25 | ||||
-rw-r--r-- | package/source/manifest/ManifestImport.hxx | 1 | ||||
-rw-r--r-- | package/source/zipapi/ZipFile.cxx | 45 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackage.cxx | 17 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackageStream.cxx | 10 |
6 files changed, 97 insertions, 10 deletions
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; |