tdf#105844 package,sfx2: wholesome ODF package wrapping encryption
Redo the ODF encryption by storing an ODF package and wrapping it as a stream "encrypted-package" in another ODF package, such that there is only one encrypted stream - this requires only one KDF computation. * This is only enabled in Experimental mode for now. * Avoid storing unencrypted data in the pTempFile of SfxMedium, as it is usually created in the same directory as the target file, which may be on a network share or similar less trusted location. * SfxMedium::SetEncryptionDataToStorage_Impl() should just set an error status if it fails (how can it fail anyway) * when loading a document, SfxDocPasswordVerifier extracts an encrypted inner package (by calling SfxMedium::TryEncryptedInnerPackage()) * SfxMedium::GetStorage() automatically decrypts an encrypted inner storage and sets it as the SfxMedium's xStorage * when storing a document, SfxObjectShell::SaveTo_Impl() creates the wrapped storages * One challenge is to keep the macro/scripting signature working; this can only be put in the inner storage, whereas the document signature should continue to be on the outer storage; also it must use a Zip storage, to see the "META-INF" directory. This needs a new SfxMedium::GetScriptingStorageToSign_Impl() and changes in SfxMedium::SignContents_Impl(). Change-Id: Ibfee36ce3a9cd030f2aa2ce1484b6d001cba2389 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160401 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
This commit is contained in:
@@ -70,7 +70,7 @@ class SFX2_DLLPUBLIC SfxMedium final : public SvRefBase
|
||||
SAL_DLLPRIVATE void CloseOutStream_Impl();
|
||||
SAL_DLLPRIVATE void CloseStreams_Impl(bool bInDestruction = false);
|
||||
|
||||
SAL_DLLPRIVATE void SetEncryptionDataToStorage_Impl();
|
||||
SAL_DLLPRIVATE bool SetEncryptionDataToStorage_Impl();
|
||||
|
||||
public:
|
||||
|
||||
@@ -218,10 +218,14 @@ public:
|
||||
SAL_DLLPRIVATE OUString const & GetBackup_Impl();
|
||||
|
||||
SAL_DLLPRIVATE css::uno::Reference< css::embed::XStorage > const & GetZipStorageToSign_Impl( bool bReadOnly = true );
|
||||
SAL_DLLPRIVATE css::uno::Reference<css::embed::XStorage> GetScriptingStorageToSign_Impl();
|
||||
SAL_DLLPRIVATE void CloseZipStorage_Impl();
|
||||
|
||||
// the storage that will be returned by the medium on GetStorage request
|
||||
SAL_DLLPRIVATE void SetStorage_Impl( const css::uno::Reference< css::embed::XStorage >& xNewStorage );
|
||||
SAL_DLLPRIVATE void SetInnerStorage_Impl(const css::uno::Reference<css::embed::XStorage>& xStorage);
|
||||
SAL_DLLPRIVATE css::uno::Reference<css::embed::XStorage>
|
||||
TryEncryptedInnerPackage(css::uno::Reference<css::embed::XStorage> xStorage);
|
||||
|
||||
SAL_DLLPRIVATE void CloseAndReleaseStreams_Impl();
|
||||
SAL_DLLPRIVATE void AddVersion_Impl( css::util::RevisionTag& rVersion );
|
||||
|
||||
@@ -287,7 +287,9 @@ void ZipPackage::parseManifest()
|
||||
const sal_Int32 nStartKeyAlg = xml::crypto::DigestID::SHA256;
|
||||
pStream->SetImportedStartKeyAlgorithm( nStartKeyAlg );
|
||||
|
||||
if ( !m_bHasEncryptedEntries && pStream->getName() == "content.xml" )
|
||||
if (!m_bHasEncryptedEntries
|
||||
&& (pStream->getName() == "content.xml"
|
||||
|| pStream->getName() == "encrypted-package"))
|
||||
{
|
||||
m_bHasEncryptedEntries = true;
|
||||
m_nChecksumDigestID = nDigestAlg;
|
||||
@@ -336,7 +338,9 @@ void ZipPackage::parseManifest()
|
||||
pStream->SetToBeCompressed ( true );
|
||||
pStream->SetToBeEncrypted ( true );
|
||||
pStream->SetIsEncrypted ( true );
|
||||
if ( !m_bHasEncryptedEntries && pStream->getName() == "content.xml" )
|
||||
if (!m_bHasEncryptedEntries
|
||||
&& (pStream->getName() == "content.xml"
|
||||
|| pStream->getName() == "encrypted-package"))
|
||||
{
|
||||
m_bHasEncryptedEntries = true;
|
||||
m_nStartKeyGenerationID = nStartKeyAlg;
|
||||
|
||||
@@ -115,16 +115,19 @@ namespace {
|
||||
class SfxDocPasswordVerifier : public ::comphelper::IDocPasswordVerifier
|
||||
{
|
||||
public:
|
||||
explicit SfxDocPasswordVerifier( const Reference< embed::XStorage >& rxStorage ) :
|
||||
mxStorage( rxStorage ) {}
|
||||
explicit SfxDocPasswordVerifier(SfxMedium& rMedium)
|
||||
: m_rMedium(rMedium)
|
||||
, mxStorage(rMedium.GetStorage())
|
||||
{
|
||||
}
|
||||
|
||||
virtual ::comphelper::DocPasswordVerifierResult
|
||||
verifyPassword( const OUString& rPassword, uno::Sequence< beans::NamedValue >& o_rEncryptionData ) override;
|
||||
virtual ::comphelper::DocPasswordVerifierResult
|
||||
verifyEncryptionData( const uno::Sequence< beans::NamedValue >& rEncryptionData ) override;
|
||||
|
||||
|
||||
private:
|
||||
SfxMedium & m_rMedium;
|
||||
Reference< embed::XStorage > mxStorage;
|
||||
};
|
||||
|
||||
@@ -147,9 +150,14 @@ private:
|
||||
// and immediately closed
|
||||
::comphelper::OStorageHelper::SetCommonStorageEncryptionData( mxStorage, rEncryptionData );
|
||||
|
||||
mxStorage->openStreamElement(
|
||||
// for new ODF encryption, try to extract the encrypted inner package
|
||||
// (it will become the SfxObjectShell storage)
|
||||
if (!m_rMedium.TryEncryptedInnerPackage(mxStorage))
|
||||
{ // ... old ODF encryption:
|
||||
mxStorage->openStreamElement(
|
||||
"content.xml",
|
||||
embed::ElementModes::READ | embed::ElementModes::NOCREATE );
|
||||
}
|
||||
|
||||
// no exception -> success
|
||||
eResult = ::comphelper::DocPasswordVerifierResult::OK;
|
||||
@@ -247,7 +255,7 @@ ErrCode CheckPasswd_Impl
|
||||
{ "ForSalvage", css::uno::Any(true) } });
|
||||
}
|
||||
|
||||
SfxDocPasswordVerifier aVerifier( xStorage );
|
||||
SfxDocPasswordVerifier aVerifier(*pFile);
|
||||
aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
|
||||
aVerifier, aEncryptionData, aPassword, xInteractionHandler, pFile->GetOrigURL(), comphelper::DocPasswordRequestType::Standard );
|
||||
|
||||
|
||||
+155
-12
@@ -62,9 +62,11 @@
|
||||
#include <com/sun/star/io/XInputStream.hpp>
|
||||
#include <com/sun/star/io/XTruncate.hpp>
|
||||
#include <com/sun/star/io/XSeekable.hpp>
|
||||
#include <com/sun/star/io/TempFile.hpp>
|
||||
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
|
||||
#include <com/sun/star/ucb/InsertCommandArgument.hpp>
|
||||
#include <com/sun/star/ucb/NameClash.hpp>
|
||||
#include <com/sun/star/util/XModifiable.hpp>
|
||||
#include <com/sun/star/beans/NamedValue.hpp>
|
||||
#include <com/sun/star/beans/PropertyValue.hpp>
|
||||
#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
|
||||
@@ -374,6 +376,8 @@ public:
|
||||
bool m_bInCheckIn:1;
|
||||
bool m_bDisableFileSync = false;
|
||||
bool m_bNotifyWhenEditable = false;
|
||||
/// if true, xStorage is an inner package and not directly from xStream
|
||||
bool m_bODFWholesomeEncryption = false;
|
||||
|
||||
OUString m_aName;
|
||||
OUString m_aLogicName;
|
||||
@@ -410,6 +414,9 @@ public:
|
||||
uno::Reference<io::XStream> xStream;
|
||||
uno::Reference<io::XStream> m_xLockingStream;
|
||||
uno::Reference<task::XInteractionHandler> xInteraction;
|
||||
uno::Reference<io::XStream> m_xODFDecryptedInnerPackageStream;
|
||||
uno::Reference<embed::XStorage> m_xODFEncryptedOuterStorage;
|
||||
uno::Reference<embed::XStorage> m_xODFDecryptedInnerZipStorage;
|
||||
|
||||
ErrCodeMsg nLastStorageError;
|
||||
|
||||
@@ -670,6 +677,7 @@ bool SfxMedium::IsSkipImages() const
|
||||
|
||||
SvStream* SfxMedium::GetInStream()
|
||||
{
|
||||
//assert(!pImpl->xStorage); // either SvStream or Storage
|
||||
if ( pImpl->m_pInStream )
|
||||
return pImpl->m_pInStream.get();
|
||||
|
||||
@@ -740,6 +748,7 @@ void SfxMedium::CloseInStream_Impl(bool bInDestruction)
|
||||
|
||||
SvStream* SfxMedium::GetOutStream()
|
||||
{
|
||||
assert(!pImpl->xStorage); // either SvStream or Storage
|
||||
if ( !pImpl->m_pOutStream )
|
||||
{
|
||||
// Create a temp. file if there is none because we always
|
||||
@@ -953,8 +962,11 @@ uno::Reference < embed::XStorage > SfxMedium::GetOutputStorage()
|
||||
|
||||
// if the medium was constructed with a Storage: use this one, not a temp. storage
|
||||
// if a temporary storage already exists: use it
|
||||
if ( pImpl->xStorage.is() && ( pImpl->m_aLogicName.isEmpty() || pImpl->pTempFile ) )
|
||||
if (pImpl->xStorage.is()
|
||||
&& (pImpl->m_bODFWholesomeEncryption || pImpl->m_aLogicName.isEmpty() || pImpl->pTempFile))
|
||||
{
|
||||
return pImpl->xStorage;
|
||||
}
|
||||
|
||||
// if necessary close stream that was used for reading
|
||||
if ( pImpl->m_pInStream && !pImpl->m_pInStream->IsWritable() )
|
||||
@@ -971,15 +983,15 @@ uno::Reference < embed::XStorage > SfxMedium::GetOutputStorage()
|
||||
}
|
||||
|
||||
|
||||
void SfxMedium::SetEncryptionDataToStorage_Impl()
|
||||
bool SfxMedium::SetEncryptionDataToStorage_Impl()
|
||||
{
|
||||
// in case media-descriptor contains password it should be used on opening
|
||||
if ( !pImpl->xStorage.is() || !pImpl->m_pSet )
|
||||
return;
|
||||
return false;
|
||||
|
||||
uno::Sequence< beans::NamedValue > aEncryptionData;
|
||||
if ( !GetEncryptionData_Impl( pImpl->m_pSet.get(), aEncryptionData ) )
|
||||
return;
|
||||
return false;
|
||||
|
||||
// replace the password with encryption data
|
||||
pImpl->m_pSet->ClearItem( SID_PASSWORD );
|
||||
@@ -992,9 +1004,10 @@ void SfxMedium::SetEncryptionDataToStorage_Impl()
|
||||
catch( const uno::Exception& )
|
||||
{
|
||||
SAL_WARN( "sfx.doc", "It must be possible to set a common password for the storage" );
|
||||
// TODO/LATER: set the error code in case of problem
|
||||
// SetError(ERRCODE_IO_GENERAL);
|
||||
SetError(ERRCODE_IO_GENERAL);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
|
||||
@@ -1699,12 +1712,54 @@ SfxMedium::LockFileResult SfxMedium::LockOrigFileOnDemand(bool bLoading, bool bN
|
||||
#endif
|
||||
}
|
||||
|
||||
// this either returns non-null or throws exception
|
||||
uno::Reference<embed::XStorage>
|
||||
SfxMedium::TryEncryptedInnerPackage(uno::Reference<embed::XStorage> const xStorage)
|
||||
{
|
||||
uno::Reference<embed::XStorage> xRet;
|
||||
if (xStorage->hasByName("encrypted-package"))
|
||||
{
|
||||
uno::Reference<io::XStream> const
|
||||
xDecryptedInnerPackage = xStorage->openStreamElement(
|
||||
"encrypted-package",
|
||||
embed::ElementModes::READ | embed::ElementModes::NOCREATE);
|
||||
assert(xDecryptedInnerPackage.is()); // just for testing? not if wrong pwd
|
||||
// need a seekable stream => copy
|
||||
Reference<uno::XComponentContext> const xContext(::comphelper::getProcessComponentContext());
|
||||
uno::Reference<io::XStream> const xDecryptedInnerPackageStream(
|
||||
xContext->getServiceManager()->createInstanceWithContext(
|
||||
"com.sun.star.comp.MemoryStream", xContext),
|
||||
UNO_QUERY_THROW);
|
||||
comphelper::OStorageHelper::CopyInputToOutput(xDecryptedInnerPackage->getInputStream(), xDecryptedInnerPackageStream->getOutputStream());
|
||||
xDecryptedInnerPackageStream->getOutputStream()->closeOutput();
|
||||
#if 0
|
||||
// debug: dump to temp file
|
||||
uno::Reference<io::XTempFile> const xTempFile(io::TempFile::create(xContext), uno::UNO_SET_THROW);
|
||||
xTempFile->setRemoveFile(false);
|
||||
comphelper::OStorageHelper::CopyInputToOutput(xDecryptedInnerPackageStream->getInputStream(), xTempFile->getOutputStream());
|
||||
xTempFile->getOutputStream()->closeOutput();
|
||||
SAL_DE BUG("AAA tempfile " << xTempFile->getResourceName());
|
||||
uno::Reference<io::XSeekable>(xDecryptedInnerPackageStream, uno::UNO_QUERY_THROW)->seek(0);
|
||||
#endif
|
||||
// create storage, if this succeeds assume password is correct
|
||||
xRet = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream(
|
||||
PACKAGE_STORAGE_FORMAT_STRING, xDecryptedInnerPackageStream,
|
||||
embed::ElementModes::READWRITE, xContext, false);
|
||||
assert(xRet.is());
|
||||
pImpl->m_bODFWholesomeEncryption = true;
|
||||
pImpl->m_xODFDecryptedInnerPackageStream = xDecryptedInnerPackageStream;
|
||||
pImpl->m_xODFEncryptedOuterStorage = xStorage;
|
||||
pImpl->xStorage = xRet;
|
||||
}
|
||||
return xRet;
|
||||
}
|
||||
|
||||
uno::Reference < embed::XStorage > SfxMedium::GetStorage( bool bCreateTempFile )
|
||||
{
|
||||
if ( pImpl->xStorage.is() || pImpl->m_bTriedStorage )
|
||||
return pImpl->xStorage;
|
||||
|
||||
assert(!pImpl->m_pOutStream /*&& !pImpl->m_pInStream*/); // either SvStream or Storage
|
||||
uno::Sequence< uno::Any > aArgs( 2 );
|
||||
auto pArgs = aArgs.getArray();
|
||||
|
||||
@@ -1797,10 +1852,26 @@ uno::Reference < embed::XStorage > SfxMedium::GetStorage( bool bCreateTempFile )
|
||||
|
||||
pImpl->m_bTriedStorage = true;
|
||||
|
||||
if (pImpl->xStorage.is())
|
||||
{
|
||||
pImpl->m_bODFWholesomeEncryption = false;
|
||||
if (SetEncryptionDataToStorage_Impl())
|
||||
{
|
||||
try
|
||||
{
|
||||
TryEncryptedInnerPackage(pImpl->xStorage);
|
||||
}
|
||||
catch (Exception const&)
|
||||
{
|
||||
TOOLS_WARN_EXCEPTION("sfx.doc", "exception from TryEncryptedInnerPackage: ");
|
||||
SetError(ERRCODE_IO_GENERAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO/LATER: Get versionlist on demand
|
||||
if ( pImpl->xStorage.is() )
|
||||
{
|
||||
SetEncryptionDataToStorage_Impl();
|
||||
GetVersionList();
|
||||
}
|
||||
|
||||
@@ -1867,6 +1938,8 @@ uno::Reference < embed::XStorage > SfxMedium::GetStorage( bool bCreateTempFile )
|
||||
if ( bResetStorage )
|
||||
{
|
||||
pImpl->xStorage.clear();
|
||||
pImpl->m_xODFDecryptedInnerPackageStream.clear();
|
||||
pImpl->m_xODFEncryptedOuterStorage.clear();
|
||||
if ( pImpl->m_pInStream )
|
||||
pImpl->m_pInStream->Seek( 0 );
|
||||
}
|
||||
@@ -1875,7 +1948,39 @@ uno::Reference < embed::XStorage > SfxMedium::GetStorage( bool bCreateTempFile )
|
||||
return pImpl->xStorage;
|
||||
}
|
||||
|
||||
uno::Reference<embed::XStorage> SfxMedium::GetScriptingStorageToSign_Impl()
|
||||
{
|
||||
// this was set when it was initially loaded
|
||||
if (pImpl->m_bODFWholesomeEncryption)
|
||||
{
|
||||
// (partial) scripting signature can only be in inner storage!
|
||||
// Note: a "PackageFormat" storage like pImpl->xStorage doesn't work
|
||||
// (even if it's not encrypted) because it hides the "META-INF" dir.
|
||||
// This "ZipFormat" storage is used only read-only; a writable one is
|
||||
// created manually in SignContents_Impl().
|
||||
if (!pImpl->m_xODFDecryptedInnerZipStorage.is())
|
||||
{
|
||||
GetStorage(false);
|
||||
// don't care about xStorage here because Zip is readonly
|
||||
SAL_WARN_IF(!pImpl->m_xODFDecryptedInnerPackageStream.is(), "sfx.doc", "no inner package stream?");
|
||||
if (pImpl->m_xODFDecryptedInnerPackageStream.is())
|
||||
{
|
||||
pImpl->m_xODFDecryptedInnerZipStorage =
|
||||
::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
|
||||
ZIP_STORAGE_FORMAT_STRING,
|
||||
pImpl->m_xODFDecryptedInnerPackageStream->getInputStream());
|
||||
}
|
||||
}
|
||||
return pImpl->m_xODFDecryptedInnerZipStorage;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetZipStorageToSign_Impl(true);
|
||||
}
|
||||
}
|
||||
|
||||
// note: currently nobody who calls this with "false" writes into an ODF
|
||||
// storage that is returned here, that is only for OOXML
|
||||
uno::Reference< embed::XStorage > const & SfxMedium::GetZipStorageToSign_Impl( bool bReadOnly )
|
||||
{
|
||||
if ( !GetErrorIgnoreWarning() && !pImpl->m_xZipStorage.is() )
|
||||
@@ -1919,6 +2024,7 @@ void SfxMedium::CloseZipStorage_Impl()
|
||||
|
||||
pImpl->m_xZipStorage.clear();
|
||||
}
|
||||
pImpl->m_xODFDecryptedInnerZipStorage.clear();
|
||||
}
|
||||
|
||||
void SfxMedium::CloseStorage()
|
||||
@@ -1938,6 +2044,9 @@ void SfxMedium::CloseStorage()
|
||||
}
|
||||
|
||||
pImpl->xStorage.clear();
|
||||
pImpl->m_xODFDecryptedInnerPackageStream.clear();
|
||||
// pImpl->m_xODFDecryptedInnerZipStorage.clear();
|
||||
pImpl->m_xODFEncryptedOuterStorage.clear();
|
||||
pImpl->bStorageBasedOnInStream = false;
|
||||
}
|
||||
|
||||
@@ -3632,12 +3741,17 @@ void SfxMedium::SetLoadTargetFrame(SfxFrame* pFrame )
|
||||
pImpl->wLoadTargetFrame = pFrame;
|
||||
}
|
||||
|
||||
|
||||
void SfxMedium::SetStorage_Impl( const uno::Reference < embed::XStorage >& rStor )
|
||||
void SfxMedium::SetStorage_Impl(const uno::Reference<embed::XStorage>& xStorage)
|
||||
{
|
||||
pImpl->xStorage = rStor;
|
||||
pImpl->xStorage = xStorage;
|
||||
pImpl->m_bODFWholesomeEncryption = false;
|
||||
}
|
||||
|
||||
void SfxMedium::SetInnerStorage_Impl(const uno::Reference<embed::XStorage>& xStorage)
|
||||
{
|
||||
pImpl->xStorage = xStorage;
|
||||
pImpl->m_bODFWholesomeEncryption = true;
|
||||
}
|
||||
|
||||
SfxItemSet& SfxMedium::GetItemSet() const
|
||||
{
|
||||
@@ -4173,7 +4287,18 @@ bool SfxMedium::SignContents_Impl(weld::Window* pDialogParent,
|
||||
bool bODF = GetFilter()->IsOwnFormat();
|
||||
try
|
||||
{
|
||||
xWriteableZipStor = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream( ZIP_STORAGE_FORMAT_STRING, pImpl->xStream );
|
||||
if (pImpl->m_bODFWholesomeEncryption && bSignScriptingContent)
|
||||
{
|
||||
assert(pImpl->xStorage); // GetStorage was called above
|
||||
assert(pImpl->m_xODFDecryptedInnerPackageStream);
|
||||
xWriteableZipStor = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream(
|
||||
ZIP_STORAGE_FORMAT_STRING, pImpl->m_xODFDecryptedInnerPackageStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
xWriteableZipStor = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream(
|
||||
ZIP_STORAGE_FORMAT_STRING, pImpl->xStream );
|
||||
}
|
||||
}
|
||||
catch (const io::IOException&)
|
||||
{
|
||||
@@ -4205,7 +4330,11 @@ bool SfxMedium::SignContents_Impl(weld::Window* pDialogParent,
|
||||
embed::ElementModes::READWRITE ),
|
||||
uno::UNO_SET_THROW );
|
||||
|
||||
if ( xSigner->signScriptingContent( GetZipStorageToSign_Impl(), xStream ) )
|
||||
// note: the storage passed here must be independent from the
|
||||
// xWriteableZipStor because a writable storage can't have 2
|
||||
// instances of sub-storage for the same directory open, but with
|
||||
// independent storages it somehow works
|
||||
if (xSigner->signScriptingContent(GetScriptingStorageToSign_Impl(), xStream))
|
||||
{
|
||||
// remove the document signature if any
|
||||
OUString aDocSigName = xSigner->getDocumentContentSignatureDefaultStreamName();
|
||||
@@ -4217,6 +4346,20 @@ bool SfxMedium::SignContents_Impl(weld::Window* pDialogParent,
|
||||
xTransact.set( xWriteableZipStor, uno::UNO_QUERY_THROW );
|
||||
xTransact->commit();
|
||||
|
||||
if (pImpl->m_bODFWholesomeEncryption)
|
||||
{ // manually copy the inner package to the outer one
|
||||
uno::Reference<io::XSeekable>(pImpl->m_xODFDecryptedInnerPackageStream, uno::UNO_QUERY_THROW)->seek(0);
|
||||
uno::Reference<io::XStream> const xEncryptedPackage =
|
||||
pImpl->m_xODFEncryptedOuterStorage->openStreamElement(
|
||||
"encrypted-package",
|
||||
embed::ElementModes::WRITE|embed::ElementModes::TRUNCATE);
|
||||
comphelper::OStorageHelper::CopyInputToOutput(pImpl->m_xODFDecryptedInnerPackageStream->getInputStream(), xEncryptedPackage->getOutputStream());
|
||||
xTransact.set(pImpl->m_xODFEncryptedOuterStorage, uno::UNO_QUERY_THROW);
|
||||
xTransact->commit(); // Commit() below won't do this
|
||||
}
|
||||
|
||||
assert(!pImpl->xStorage.is() // ensure this doesn't overwrite
|
||||
|| !uno::Reference<util::XModifiable>(pImpl->xStorage, uno::UNO_QUERY_THROW)->isModified());
|
||||
// the temporary file has been written, commit it to the original file
|
||||
Commit();
|
||||
bChanges = true;
|
||||
|
||||
@@ -1924,7 +1924,7 @@ bool SfxObjectShell_Impl::hasTrustedScriptingSignature(
|
||||
{
|
||||
task::DocumentMacroConfirmationRequest aRequest;
|
||||
aRequest.DocumentURL = getDocumentLocation();
|
||||
aRequest.DocumentStorage = rDocShell.GetMedium()->GetZipStorageToSign_Impl();
|
||||
aRequest.DocumentStorage = rDocShell.GetMedium()->GetScriptingStorageToSign_Impl();
|
||||
aRequest.DocumentSignatureInformation = aInfo;
|
||||
aRequest.DocumentVersion = aVersion;
|
||||
aRequest.Classification = task::InteractionClassification_QUERY;
|
||||
|
||||
@@ -1840,8 +1840,11 @@ uno::Sequence< security::DocumentSignatureInformation > SfxObjectShell::GetDocum
|
||||
}
|
||||
|
||||
if ( bScriptingContent )
|
||||
aResult = xLocSigner->verifyScriptingContentSignatures( GetMedium()->GetZipStorageToSign_Impl(),
|
||||
uno::Reference< io::XInputStream >() );
|
||||
{
|
||||
aResult = xLocSigner->verifyScriptingContentSignatures(
|
||||
GetMedium()->GetScriptingStorageToSign_Impl(),
|
||||
uno::Reference<io::XInputStream>());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GetMedium()->GetStorage(false).is())
|
||||
@@ -2034,7 +2037,7 @@ bool SfxObjectShell::CheckIsReadonly(bool bSignScriptingContent, weld::Window* p
|
||||
xSigner->setParentWindow(pDialogParent->GetXWindow());
|
||||
|
||||
if (bSignScriptingContent)
|
||||
xSigner->showScriptingContentSignatures(GetMedium()->GetZipStorageToSign_Impl(),
|
||||
xSigner->showScriptingContentSignatures(GetMedium()->GetScriptingStorageToSign_Impl(),
|
||||
uno::Reference<io::XInputStream>());
|
||||
else
|
||||
{
|
||||
|
||||
+161
-13
@@ -1150,6 +1150,9 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
// tdf#41063, tdf#135244: prevent jumping to cursor at any temporary modification
|
||||
auto aViewGuard(LockAllViews());
|
||||
|
||||
uno::Reference<uno::XComponentContext> const xContext(
|
||||
::comphelper::getProcessComponentContext());
|
||||
|
||||
std::shared_ptr<const SfxFilter> pFilter = rMedium.GetFilter();
|
||||
if ( !pFilter )
|
||||
{
|
||||
@@ -1173,6 +1176,12 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
return false;
|
||||
}
|
||||
|
||||
SvtSaveOptions::ODFSaneDefaultVersion nVersion(SvtSaveOptions::ODFSVER_LATEST_EXTENDED);
|
||||
if (bOwnTarget && !utl::ConfigManager::IsFuzzing())
|
||||
{
|
||||
nVersion = GetODFSaneDefaultVersion();
|
||||
}
|
||||
|
||||
bool bNeedsDisconnectionOnFail = false;
|
||||
|
||||
bool bStoreToSameLocation = false;
|
||||
@@ -1193,7 +1202,6 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
if ( bTryToPreserveScriptSignature )
|
||||
{
|
||||
// check that the storage format stays the same
|
||||
SvtSaveOptions::ODFSaneDefaultVersion nVersion = GetODFSaneDefaultVersion();
|
||||
|
||||
OUString aODFVersion;
|
||||
try
|
||||
@@ -1220,6 +1228,33 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
}
|
||||
}
|
||||
|
||||
uno::Reference<io::XStream> xODFDecryptedInnerPackageStream;
|
||||
uno::Reference<embed::XStorage> xODFDecryptedInnerPackage;
|
||||
uno::Sequence<beans::NamedValue> aEncryptionData;
|
||||
if (GetEncryptionData_Impl(&rMedium.GetItemSet(), aEncryptionData))
|
||||
{
|
||||
assert(aEncryptionData.getLength() != 0);
|
||||
if (bOwnTarget && nVersion == SvtSaveOptions::ODFSVER_LATEST_EXTENDED
|
||||
&& officecfg::Office::Common::Misc::ExperimentalMode::get())
|
||||
{
|
||||
// when embedded objects are stored here, it should be called from
|
||||
// this function for the root document and encryption data was cleared
|
||||
assert(GetCreateMode() != SfxObjectCreateMode::EMBEDDED);
|
||||
// clear now to store inner package (+ embedded objects) unencrypted
|
||||
rMedium.GetItemSet().ClearItem(SID_ENCRYPTIONDATA);
|
||||
rMedium.GetItemSet().ClearItem(SID_PASSWORD);
|
||||
xODFDecryptedInnerPackageStream.set(
|
||||
xContext->getServiceManager()->createInstanceWithContext(
|
||||
"com.sun.star.comp.MemoryStream", xContext),
|
||||
UNO_QUERY_THROW);
|
||||
xODFDecryptedInnerPackage = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream(
|
||||
PACKAGE_STORAGE_FORMAT_STRING, xODFDecryptedInnerPackageStream,
|
||||
css::embed::ElementModes::WRITE, xContext, false);
|
||||
assert(xODFDecryptedInnerPackage.is());
|
||||
}
|
||||
}
|
||||
|
||||
bool isStreamAndInputStreamCleared(false);
|
||||
// use UCB for case sensitive/insensitive file name comparison
|
||||
if ( !pMedium->GetName().equalsIgnoreAsciiCase("private:stream")
|
||||
&& !rMedium.GetName().equalsIgnoreAsciiCase("private:stream")
|
||||
@@ -1280,6 +1315,7 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
|| ConnectTmpStorage_Impl( pMedium->GetStorage(), pMedium ) )
|
||||
{
|
||||
pMedium->CloseAndRelease();
|
||||
isStreamAndInputStreamCleared = true;
|
||||
|
||||
// TODO/LATER: for now the medium must be closed since it can already contain streams from old medium
|
||||
// in future those streams should not be copied in case a valid target url is provided,
|
||||
@@ -1287,7 +1323,15 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
// reachable.
|
||||
rMedium.CloseAndRelease();
|
||||
rMedium.SetHasEmbeddedObjects(GetEmbeddedObjectContainer().HasEmbeddedObjects());
|
||||
rMedium.GetOutputStorage();
|
||||
if (xODFDecryptedInnerPackageStream.is())
|
||||
{
|
||||
assert(!rMedium.GetItemSet().GetItem(SID_STREAM));
|
||||
rMedium.SetInnerStorage_Impl(xODFDecryptedInnerPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
rMedium.GetOutputStorage();
|
||||
}
|
||||
rMedium.SetHasEmbeddedObjects(false);
|
||||
}
|
||||
}
|
||||
@@ -1299,6 +1343,7 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
|
||||
pMedium->CloseAndRelease();
|
||||
rMedium.CloseAndRelease();
|
||||
isStreamAndInputStreamCleared = true;
|
||||
rMedium.CreateTempFileNoCopy();
|
||||
rMedium.GetOutStream();
|
||||
}
|
||||
@@ -1310,7 +1355,16 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
|
||||
pMedium->CloseAndRelease();
|
||||
rMedium.CloseAndRelease();
|
||||
rMedium.GetOutputStorage();
|
||||
isStreamAndInputStreamCleared = true;
|
||||
if (xODFDecryptedInnerPackageStream.is())
|
||||
{
|
||||
assert(!rMedium.GetItemSet().GetItem(SID_STREAM));
|
||||
rMedium.SetInnerStorage_Impl(xODFDecryptedInnerPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
rMedium.GetOutputStorage();
|
||||
}
|
||||
}
|
||||
else // means if ( bStorageBasedSource && !bStorageBasedTarget )
|
||||
{
|
||||
@@ -1325,6 +1379,7 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
{
|
||||
pMedium->CloseAndRelease();
|
||||
rMedium.CloseAndRelease();
|
||||
isStreamAndInputStreamCleared = true;
|
||||
rMedium.CreateTempFileNoCopy();
|
||||
rMedium.GetOutStream();
|
||||
}
|
||||
@@ -1339,10 +1394,20 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
// TODO/LATER: let the medium be prepared for alien formats as well
|
||||
|
||||
rMedium.CloseAndRelease();
|
||||
isStreamAndInputStreamCleared = true;
|
||||
if ( bStorageBasedTarget )
|
||||
{
|
||||
rMedium.SetHasEmbeddedObjects(GetEmbeddedObjectContainer().HasEmbeddedObjects());
|
||||
rMedium.GetOutputStorage();
|
||||
if (xODFDecryptedInnerPackageStream.is())
|
||||
{
|
||||
assert(!rMedium.GetItemSet().GetItem(SID_STREAM));
|
||||
// this should set only xStorage, all of the streams remain null
|
||||
rMedium.SetInnerStorage_Impl(xODFDecryptedInnerPackage);
|
||||
}
|
||||
else
|
||||
{
|
||||
rMedium.GetOutputStorage();
|
||||
}
|
||||
rMedium.SetHasEmbeddedObjects(false);
|
||||
}
|
||||
}
|
||||
@@ -1354,6 +1419,9 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
return false;
|
||||
}
|
||||
|
||||
// these have been cleared on all paths that don't take above error return
|
||||
assert(isStreamAndInputStreamCleared); (void) isStreamAndInputStreamCleared;
|
||||
|
||||
rMedium.LockOrigFileOnDemand( false, false );
|
||||
|
||||
if ( bStorageBasedTarget )
|
||||
@@ -1416,19 +1484,26 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
}
|
||||
|
||||
// transfer password from the parameters to the storage
|
||||
uno::Sequence< beans::NamedValue > aEncryptionData;
|
||||
bool bPasswdProvided = false;
|
||||
if ( GetEncryptionData_Impl( &rMedSet, aEncryptionData ) )
|
||||
if (aEncryptionData.getLength() != 0)
|
||||
{
|
||||
bPasswdProvided = true;
|
||||
try {
|
||||
::comphelper::OStorageHelper::SetCommonStorageEncryptionData( xMedStorage, aEncryptionData );
|
||||
if (xODFDecryptedInnerPackageStream.is())
|
||||
{
|
||||
bOk = true;
|
||||
}
|
||||
catch( uno::Exception& )
|
||||
else
|
||||
{
|
||||
SAL_WARN( "sfx.doc", "Setting of common encryption key failed!" );
|
||||
SetError(ERRCODE_IO_GENERAL);
|
||||
// TODO: GetStorage() already did that?
|
||||
try {
|
||||
::comphelper::OStorageHelper::SetCommonStorageEncryptionData( xMedStorage, aEncryptionData );
|
||||
bOk = true;
|
||||
}
|
||||
catch( uno::Exception& )
|
||||
{
|
||||
SAL_WARN( "sfx.doc", "Setting of common encryption key failed!" );
|
||||
SetError(ERRCODE_IO_GENERAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1576,6 +1651,13 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
|
||||
if ( bOk )
|
||||
{
|
||||
uno::Any mediaType;
|
||||
if (xODFDecryptedInnerPackageStream.is())
|
||||
{ // before the signature copy closes it
|
||||
mediaType = uno::Reference<beans::XPropertySet>(xODFDecryptedInnerPackage,
|
||||
uno::UNO_QUERY_THROW)->getPropertyValue("MediaType");
|
||||
}
|
||||
|
||||
// if ODF version of oasis format changes on saving the signature should not be preserved
|
||||
if ( bTryToPreserveScriptSignature && bNoPreserveForOasis )
|
||||
bTryToPreserveScriptSignature = ( SotStorage::GetVersion( rMedium.GetStorage() ) == SOFFICE_FILEFORMAT_60 );
|
||||
@@ -1610,14 +1692,26 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
rMedium.StorageCommit_Impl();
|
||||
rMedium.CloseStorage();
|
||||
|
||||
uno::Reference< embed::XStorage > xReadOrig = pMedium->GetZipStorageToSign_Impl();
|
||||
// signature must use Zip storage, not Package storage
|
||||
uno::Reference<embed::XStorage> const xReadOrig(
|
||||
pMedium->GetScriptingStorageToSign_Impl());
|
||||
uno::Reference<embed::XStorage> xTarget;
|
||||
if (xODFDecryptedInnerPackageStream.is())
|
||||
{
|
||||
xTarget = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream(
|
||||
ZIP_STORAGE_FORMAT_STRING, xODFDecryptedInnerPackageStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
xTarget = rMedium.GetZipStorageToSign_Impl(false);
|
||||
}
|
||||
|
||||
if ( !xReadOrig.is() )
|
||||
throw uno::RuntimeException();
|
||||
uno::Reference< embed::XStorage > xMetaInf = xReadOrig->openStorageElement(
|
||||
"META-INF",
|
||||
embed::ElementModes::READ );
|
||||
|
||||
uno::Reference< embed::XStorage > xTarget = rMedium.GetZipStorageToSign_Impl( false );
|
||||
if ( !xTarget.is() )
|
||||
throw uno::RuntimeException();
|
||||
uno::Reference< embed::XStorage > xTargetMetaInf = xTarget->openStorageElement(
|
||||
@@ -1648,6 +1742,12 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
xTransact.set( xTarget, uno::UNO_QUERY );
|
||||
if ( xTransact.is() )
|
||||
xTransact->commit();
|
||||
if (xODFDecryptedInnerPackageStream.is())
|
||||
{ // recreate, to have it with copied sig
|
||||
xODFDecryptedInnerPackage = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream(
|
||||
PACKAGE_STORAGE_FORMAT_STRING, xODFDecryptedInnerPackageStream,
|
||||
css::embed::ElementModes::WRITE, xContext, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1665,6 +1765,49 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
rMedium.CloseZipStorage_Impl();
|
||||
}
|
||||
|
||||
if (xODFDecryptedInnerPackageStream.is())
|
||||
{
|
||||
rMedium.StorageCommit_Impl();
|
||||
// prevent dispose as inner storage will be needed later
|
||||
assert(!rMedium.WillDisposeStorageOnClose_Impl());
|
||||
rMedium.CloseStorage();
|
||||
// restore encryption for outer package, note: disable for debugging
|
||||
rMedium.GetItemSet().Put(SfxUnoAnyItem(SID_ENCRYPTIONDATA, uno::Any(aEncryptionData)));
|
||||
assert(xODFDecryptedInnerPackageStream.is());
|
||||
// now create the outer storage
|
||||
uno::Reference<embed::XStorage> const xOuterStorage(rMedium.GetOutputStorage());
|
||||
assert(xOuterStorage.is());
|
||||
// the outer storage needs the same properties as the inner one
|
||||
SetupStorage(xOuterStorage, SOFFICE_FILEFORMAT_CURRENT, false);
|
||||
|
||||
#if 0
|
||||
// does this need to happen here? - GetStorage already did it
|
||||
try {
|
||||
::comphelper::OStorageHelper::SetCommonStorageEncryptionData(xOuterStorage, aEncryptionData);
|
||||
}
|
||||
catch (uno::Exception&)
|
||||
{
|
||||
SAL_WARN("sfx.doc", "Setting of common encryption key failed!");
|
||||
SetError(ERRCODE_IO_GENERAL);
|
||||
bOk = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
uno::Reference<io::XStream> const xEncryptedInnerPackage =
|
||||
xOuterStorage->openStreamElement(
|
||||
"encrypted-package", embed::ElementModes::WRITE);
|
||||
uno::Reference<beans::XPropertySet> const xEncryptedPackageProps(
|
||||
xEncryptedInnerPackage, uno::UNO_QUERY_THROW);
|
||||
xEncryptedPackageProps->setPropertyValue("MediaType", mediaType);
|
||||
|
||||
// encryption: just copy into package stream
|
||||
uno::Reference<io::XSeekable>(xODFDecryptedInnerPackageStream, uno::UNO_QUERY_THROW)->seek(0);
|
||||
comphelper::OStorageHelper::CopyInputToOutput(
|
||||
xODFDecryptedInnerPackageStream->getInputStream(),
|
||||
xEncryptedInnerPackage->getOutputStream());
|
||||
// rely on Commit() below
|
||||
}
|
||||
|
||||
const OUString sName( rMedium.GetName( ) );
|
||||
bOk = rMedium.Commit();
|
||||
const OUString sNewName( rMedium.GetName( ) );
|
||||
@@ -1672,6 +1815,11 @@ bool SfxObjectShell::SaveTo_Impl
|
||||
if ( sName != sNewName )
|
||||
GetMedium( )->SwitchDocumentToFile( sNewName );
|
||||
|
||||
if (xODFDecryptedInnerPackageStream.is())
|
||||
{ // set the inner storage on the medium again, after Switch
|
||||
rMedium.SetInnerStorage_Impl(xODFDecryptedInnerPackage);
|
||||
}
|
||||
|
||||
if ( bOk )
|
||||
{
|
||||
// if the target medium is an alien format and the "old" medium was an own format and the "old" medium
|
||||
|
||||
Reference in New Issue
Block a user