summaryrefslogtreecommitdiffstats
path: root/package
diff options
context:
space:
mode:
Diffstat (limited to 'package')
-rw-r--r--package/source/manifest/ManifestDefines.hxx9
-rw-r--r--package/source/manifest/ManifestImport.cxx25
-rw-r--r--package/source/manifest/ManifestImport.hxx1
-rw-r--r--package/source/zipapi/ZipFile.cxx45
-rw-r--r--package/source/zippackage/ZipPackage.cxx17
-rw-r--r--package/source/zippackage/ZipPackageStream.cxx10
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;