summaryrefslogtreecommitdiff
path: root/package
diff options
context:
space:
mode:
authorMichael Stahl <michael.stahl@allotropia.de>2023-12-13 21:53:55 +0100
committerMichael Stahl <michael.stahl@allotropia.de>2023-12-14 15:38:13 +0100
commit91f35f22f0447769c08ca89e27a39b40df18fffa (patch)
treeb3e0f8344ae6277332bf1b0933b39591e62dc89e /package
parentf618e9b8c1d4748a9ff9ee97405af8e43c6ae294 (diff)
tdf#105844 package: remove root document from manifest ...
... for ODF wholesome encryption. 4.3 <manifest:file-entry> For directories, the manifest file should contain a <manifest:file-entry> element only if a directory contains a document or a sub document. Because the "encrypted-package" is not a document but a package, we should probably omit the file-entry for the root document. ZipPackage::writeTempFile() always generates the root document becuase it's needed for GPG properties, and ManifestExport filters it out. A bit tricky to implement, because there isn't a clean distinction between the package and the root document/storage in the package module, in particular there's no other place than the root storage to store the MediaType property. Change-Id: Id7e72a64e2faa074dce80cd5fefb2fa189e2e3ee Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160717 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
Diffstat (limited to 'package')
-rw-r--r--package/source/manifest/ManifestExport.cxx33
-rw-r--r--package/source/zipapi/ZipFile.cxx3
-rw-r--r--package/source/zippackage/ZipPackage.cxx23
3 files changed, 50 insertions, 9 deletions
diff --git a/package/source/manifest/ManifestExport.cxx b/package/source/manifest/ManifestExport.cxx
index 950e47f49741..cf60614ccd58 100644
--- a/package/source/manifest/ManifestExport.cxx
+++ b/package/source/manifest/ManifestExport.cxx
@@ -81,6 +81,7 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
// find the mediatype of the document if any
OUString aDocMediaType;
OUString aDocVersion;
+ bool isWholesomeEncryption(false);
const uno::Sequence<beans::PropertyValue>* pRootFolderPropSeq = nullptr;
for (const uno::Sequence < beans::PropertyValue >& rSequence : rManList)
{
@@ -109,12 +110,27 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
if ( aPath == "/" )
{
+ assert(aDocMediaType.isEmpty());
+ // unfortunately no aMediaType in some cases where non-documents
+ // are stored as StorageFormats::PACKAGE instead of sensible
+ // StorageFormats::ZIP, such as SvxXMLXTableExportComponent and
+ // SwXMLTextBlocks, which results in an empty "mimetype" etc but
+ // can't be easily fixed; try to exclude these cases by checking
+ // for aVersion, but of course then forgetting to set both version
+ // and type on an actual document can't be found :(
+ assert(!aMediaType.isEmpty() || aVersion.isEmpty());
aDocMediaType = aMediaType;
aDocVersion = aVersion;
pRootFolderPropSeq = &rSequence;
- break;
+ }
+
+ if (aPath == "encrypted-package")
+ {
+ isWholesomeEncryption = true;
+ assert(aDocMediaType.isEmpty() || aDocMediaType == aMediaType);
}
}
+ assert(pRootFolderPropSeq);
bool bProvideDTD = false;
bool bAcceptNonemptyVersion = false;
@@ -293,7 +309,12 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
// now write individual file entries
for (const uno::Sequence<beans::PropertyValue>& rSequence : rManList)
{
+ if (&rSequence == pRootFolderPropSeq && isWholesomeEncryption)
+ {
+ continue; // no root document, but embedded package => omit
+ }
rtl::Reference<::comphelper::AttributeList> pAttrList = new ::comphelper::AttributeList;
+ OUString fullPath;
OUString aString;
const uno::Any *pVector = nullptr, *pSalt = nullptr, *pIterationCount = nullptr, *pDigest = nullptr, *pDigestAlg = nullptr, *pEncryptAlg = nullptr, *pStartKeyAlg = nullptr, *pDerivedKeySize = nullptr;
for (const beans::PropertyValue& rValue : rSequence)
@@ -312,8 +333,8 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
}
else if (rValue.Name == sFullPathProperty )
{
- rValue.Value >>= aString;
- pAttrList->AddAttribute ( ATTRIBUTE_FULL_PATH, aString );
+ rValue.Value >>= fullPath;
+ pAttrList->AddAttribute(ATTRIBUTE_FULL_PATH, fullPath);
}
else if (rValue.Name == sSizeProperty )
{
@@ -338,6 +359,11 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
else if (rValue.Name == sDerivedKeySizeProperty )
pDerivedKeySize = &rValue.Value;
}
+ assert(!fullPath.isEmpty());
+ if (isWholesomeEncryption)
+ { // there may be signatures in META-INF too
+ assert(fullPath == "encrypted-package" || fullPath.startsWith("META-INF/"));
+ }
xHandler->ignorableWhitespace ( sWhiteSpace );
xHandler->startElement( ELEMENT_FILE_ENTRY , pAttrList);
@@ -390,6 +416,7 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
}
else if (nEncAlgID == xml::crypto::CipherID::AES_GCM_W3C)
{
+ assert(bStoreStartKeyGeneration || pKeyInfoProperty);
SAL_WARN_IF(nDerivedKeySize != 32, "package.manifest", "Unexpected key size is provided!");
if (nDerivedKeySize != 32)
{
diff --git a/package/source/zipapi/ZipFile.cxx b/package/source/zipapi/ZipFile.cxx
index 664cfa7f1e17..bdcd8610be60 100644
--- a/package/source/zipapi/ZipFile.cxx
+++ b/package/source/zipapi/ZipFile.cxx
@@ -647,7 +647,8 @@ uno::Reference< XInputStream > ZipFile::createStreamForZipEntry(
#ifndef EMSCRIPTEN
static const sal_Int32 nThreadingThreshold = 10000;
- if( xSrcStream->available() > nThreadingThreshold )
+ // "encrypted-package" is the only data stream, no point in threading it
+ if (rEntry.sPath != "encrypted-package" && nThreadingThreshold < xSrcStream->available())
xBufStream = new XBufferedThreadedStream(xSrcStream, xSrcStream->getSize());
else
#endif
diff --git a/package/source/zippackage/ZipPackage.cxx b/package/source/zippackage/ZipPackage.cxx
index 1bae902c177a..f95731f368d1 100644
--- a/package/source/zippackage/ZipPackage.cxx
+++ b/package/source/zippackage/ZipPackage.cxx
@@ -417,25 +417,36 @@ void ZipPackage::parseManifest()
}
}
- if ( !bManifestParsed )
+ if (!bManifestParsed || m_xRootFolder->GetMediaType().isEmpty())
{
// the manifest.xml could not be successfully parsed, this is an inconsistent package
if ( aPackageMediatype.startsWith("application/vnd.") )
{
// accept only types that look similar to own mediatypes
m_xRootFolder->SetMediaType( aPackageMediatype );
- m_bMediaTypeFallbackUsed = true;
+ // if there is an encrypted inner package, there is no root
+ // document, because instead there is a package, and it is not
+ // an error
+ if (!m_xRootFolder->hasByName("encrypted-package"))
+ {
+ m_bMediaTypeFallbackUsed = true;
+ }
}
}
else if ( !m_bForceRecovery )
{
- // the mimetype stream should contain the information from manifest.xml
- if ( m_xRootFolder->GetMediaType() != aPackageMediatype )
+ // the mimetype stream should contain the same information as manifest.xml
+ OUString const mediaTypeXML(m_xRootFolder->hasByName("encrypted-package")
+ ? m_xRootFolder->doGetByName("encrypted-package").xPackageEntry->GetMediaType()
+ : m_xRootFolder->GetMediaType());
+ if (mediaTypeXML != aPackageMediatype)
+ {
throw ZipIOException(
THROW_WHERE
"mimetype conflicts with manifest.xml, \""
- + m_xRootFolder->GetMediaType() + "\" vs. \""
+ + mediaTypeXML + "\" vs. \""
+ aPackageMediatype + "\"" );
+ }
}
m_xRootFolder->removeByName( sMimetype );
@@ -1269,6 +1280,8 @@ uno::Reference< io::XInputStream > ZipPackage::writeTempFile()
static constexpr OUStringLiteral sFullPath(u"FullPath");
const bool bIsGpgEncrypt = m_aGpgProps.hasElements();
+ // note: this is always created here (needed for GPG), possibly
+ // filtered out later in ManifestExport
if ( m_nFormat == embed::StorageFormats::PACKAGE )
{
uno::Sequence < PropertyValue > aPropSeq(