comphelper/Library_comphelper.mk | 1 comphelper/source/misc/storagehelper.cxx | 118 +++++++- external/gpgmepp/ExternalProject_gpgmepp.mk | 5 fpicker/source/office/OfficeControlAccess.cxx | 1 fpicker/source/win32/filepicker/VistaFilePicker.cxx | 2 fpicker/source/win32/filepicker/VistaFilePickerImpl.cxx | 8 fpicker/source/win32/filepicker/VistaFilePickerImpl.hxx | 1 fpicker/source/win32/misc/resourceprovider.cxx | 3 include/sal/log-areas.dox | 1 offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl | 31 ++ offapi/com/sun/star/security/XDocumentDigitalSignatures.idl | 2 package/inc/PackageConstants.hxx | 1 package/inc/ZipPackage.hxx | 1 package/source/manifest/ManifestDefines.hxx | 13 package/source/manifest/ManifestExport.cxx | 175 +++++++++++- package/source/xstor/xstorage.cxx | 60 ++++ package/source/xstor/xstorage.hxx | 1 package/source/zippackage/ZipPackage.cxx | 25 + sfx2/source/dialog/filedlghelper.cxx | 22 + vcl/unx/gtk/fpicker/SalGtkFilePicker.cxx | 4 vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx | 1 vcl/unx/gtk/fpicker/resourceprovider.cxx | 1 vcl/unx/kde4/KDE4FilePicker.cxx | 6 xmlsecurity/inc/certificatechooser.hxx | 2 xmlsecurity/source/component/documentdigitalsignatures.cxx | 32 +- xmlsecurity/source/component/documentdigitalsignatures.hxx | 4 xmlsecurity/source/dialogs/certificatechooser.cxx | 38 +- xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx | 14 xmlsecurity/source/gpg/CertificateImpl.cxx | 6 29 files changed, 514 insertions(+), 65 deletions(-)
New commits: commit ed50a0a2ce51584fa3a8fba0094220a4bf25c650 Author: Thorsten Behrens <thorsten.behr...@cib.de> Date: Thu Dec 7 18:18:47 2017 +0100 gpg4libre: handle unavailable gpg crypto tools more gracefully Change-Id: I58af9d38ea8d202d2bda64cdf45204646ac9fd29 diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx index 9d1244973de7..dd7de2c3bafe 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.cxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx @@ -349,7 +349,7 @@ DocumentDigitalSignatures::ImplVerifySignatures( rSigInfo.CertificateStatus = css::security::CertificateValidity::INVALID; } } - else // GPG + else if (xGpgSecEnv.is()) // GPG { // TODO not ideal to retrieve cert by keyID, might // collide, or PGPKeyID format might change - can't we commit 1e12447f7ea601e158808290f4f67d84efba06e2 Author: Thorsten Behrens <thorsten.behr...@cib.de> Date: Thu Dec 7 14:31:36 2017 +0100 gpg4libre: return key fingerprint / hashes including null character Change-Id: I6b32444bab6848e2b5ddec02fd949c71114a66b2 diff --git a/xmlsecurity/source/gpg/CertificateImpl.cxx b/xmlsecurity/source/gpg/CertificateImpl.cxx index 16eeda80441f..c831011ca50e 100644 --- a/xmlsecurity/source/gpg/CertificateImpl.cxx +++ b/xmlsecurity/source/gpg/CertificateImpl.cxx @@ -158,7 +158,7 @@ Sequence< sal_Int8 > SAL_CALL CertificateImpl::getSHA1Thumbprint() // This is mapped to the fingerprint for gpg const char* keyId = m_pKey.primaryFingerprint(); return comphelper::arrayToSequence<sal_Int8>( - keyId, strlen(keyId)); + keyId, strlen(keyId)+1); } Sequence<sal_Int8> CertificateImpl::getSHA256Thumbprint() @@ -167,7 +167,7 @@ Sequence<sal_Int8> CertificateImpl::getSHA256Thumbprint() // SHA1 actually) const char* keyId = m_pKey.primaryFingerprint(); return comphelper::arrayToSequence<sal_Int8>( - keyId, strlen(keyId)); + keyId, strlen(keyId)+1); } Sequence< sal_Int8 > SAL_CALL CertificateImpl::getMD5Thumbprint() @@ -175,7 +175,7 @@ Sequence< sal_Int8 > SAL_CALL CertificateImpl::getMD5Thumbprint() // This is mapped to the shorter keyID for gpg const char* keyId = m_pKey.keyID(); return comphelper::arrayToSequence<sal_Int8>( - keyId, strlen(keyId)); + keyId, strlen(keyId)+1); } CertificateKind SAL_CALL CertificateImpl::getCertificateKind() commit 626e73eafe953b102107031721a0b145fb713e9d Author: Thorsten Behrens <thorsten.behr...@cib.de> Date: Thu Dec 7 05:11:15 2017 +0100 gpg4libre: permit multi-select encrypt cert And pass down all necessary parameters everywhere Change-Id: I152b9d84c0e35be9e5193a9a6f67de9fb86133b0 diff --git a/comphelper/source/misc/storagehelper.cxx b/comphelper/source/misc/storagehelper.cxx index a05fb1358f3f..7fa46554b595 100644 --- a/comphelper/source/misc/storagehelper.cxx +++ b/comphelper/source/misc/storagehelper.cxx @@ -17,6 +17,8 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include <config_gpgme.h> + #include <com/sun/star/embed/ElementModes.hpp> #include <com/sun/star/embed/XEncryptionProtectedSource2.hpp> #include <com/sun/star/embed/XEncryptionProtectedStorage.hpp> @@ -459,6 +461,9 @@ uno::Sequence< beans::NamedValue > OStorageHelper::CreateGpgPackageEncryptionDat uno::Sequence< uno::Reference< security::XCertificate > > xSignCertificates= xSigner->chooseEncryptionCertificate(); + if (!xSignCertificates.hasElements()) + return uno::Sequence< beans::NamedValue >(); // user cancelled + // generate one encrypted key entry for each recipient // --------------------------------------------------- @@ -478,13 +483,13 @@ uno::Sequence< beans::NamedValue > OStorageHelper::CreateGpgPackageEncryptionDat { uno::Sequence < sal_Int8 > aKeyID; if (pCerts->is()) - aKeyID = (*pCerts)->getSHA256Thumbprint(); + aKeyID = (*pCerts)->getSHA1Thumbprint(); std::vector<GpgME::Key> keys; keys.push_back( ctx->key( reinterpret_cast<const char*>(aKeyID.getConstArray()), - err, true)); + err, false)); // ctx is setup now, let's encrypt the lot! GpgME::Data plain( @@ -504,7 +509,9 @@ uno::Sequence< beans::NamedValue > OStorageHelper::CreateGpgPackageEncryptionDat len += curr; if(crypt_res.error() || !len) - throw uno::RuntimeException("The GpgME library failed to encrypt."); + throw lang::IllegalArgumentException( + "Not a suitable key, or failed to encrypt.", + css::uno::Reference<css::uno::XInterface>(), i); uno::Sequence < sal_Int8 > aCipherValue(len); result = cipher.seek(0,SEEK_SET); diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox index 1df274126d87..3858ea12175b 100644 --- a/include/sal/log-areas.dox +++ b/include/sal/log-areas.dox @@ -94,6 +94,7 @@ certain functionality. @li @c comphelper @li @c comphelper.backupfilehelper @li @c comphelper.container - EmbeddedObjectContainer +@li @c comphelper.crypto @section cppu diff --git a/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl b/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl index 85507940d316..519f77cb62dd 100644 --- a/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl +++ b/offapi/com/sun/star/security/XDocumentDigitalSignatures.idl @@ -148,7 +148,7 @@ interface XDocumentDigitalSignatures : com::sun::star::uno::XInterface @since LibreOffice 6.0 */ - com::sun::star::security::XCertificate chooseEncryptionCertificate( [out] string Description ); + sequence< com::sun::star::security::XCertificate > chooseEncryptionCertificate( ); /** This method shows the CertificateChooser dialog, used by document and PDF signing Shows only private certificates and returns usage string in addition to description. diff --git a/sfx2/source/dialog/filedlghelper.cxx b/sfx2/source/dialog/filedlghelper.cxx index 4482d2887c41..84e248bfa390 100644 --- a/sfx2/source/dialog/filedlghelper.cxx +++ b/sfx2/source/dialog/filedlghelper.cxx @@ -1521,8 +1521,26 @@ ErrCode FileDialogHelper_Impl::execute( std::vector<OUString>& rpURLList, bool bGpg = false; if ( ( aValue >>= bGpg ) && bGpg ) { - // ask for a key - rpSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( ::comphelper::OStorageHelper::CreateGpgPackageEncryptionData() ) ) ); + uno::Sequence< beans::NamedValue > aEncryptionData; + while(true) + { + try + { + // ask for keys + aEncryptionData = ::comphelper::OStorageHelper::CreateGpgPackageEncryptionData(); + break; // user cancelled or we've some keys now + } + catch( const IllegalArgumentException& ) + { + ScopedVclPtrInstance< MessageDialog > aBox( + mpPreferredParentWindow, + SfxResId(RID_SVXSTR_INCORRECT_PASSWORD)); + aBox->Execute(); + } + } + + if ( aEncryptionData.hasElements() ) + rpSet->Put( SfxUnoAnyItem( SID_ENCRYPTIONDATA, uno::makeAny( aEncryptionData) ) ); } } catch( const IllegalArgumentException& ){} diff --git a/xmlsecurity/inc/certificatechooser.hxx b/xmlsecurity/inc/certificatechooser.hxx index 3834dfb111a1..2ae3c1822b1f 100644 --- a/xmlsecurity/inc/certificatechooser.hxx +++ b/xmlsecurity/inc/certificatechooser.hxx @@ -92,7 +92,7 @@ public: short Execute() override; - css::uno::Reference< css::security::XCertificate > GetSelectedCertificate(); + css::uno::Sequence<css::uno::Reference< css::security::XCertificate > > GetSelectedCertificates(); css::uno::Reference< css::xml::crypto::XXMLSecurityContext > GetSelectedSecurityContext(); /// Gets the description string provided when selecting the certificate. OUString GetDescription(); diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx index bc52bdb30ff1..9d1244973de7 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.cxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx @@ -456,7 +456,7 @@ sal_Bool DocumentDigitalSignatures::isAuthorTrusted( return bFound; } -Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseCertificateImpl(std::map<OUString, OUString>& rProperties, const UserAction eAction) +uno::Sequence< Reference< css::security::XCertificate > > DocumentDigitalSignatures::chooseCertificatesImpl(std::map<OUString, OUString>& rProperties, const UserAction eAction) { std::vector< Reference< css::xml::crypto::XXMLSecurityContext > > xSecContexts; @@ -468,17 +468,17 @@ Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseCertif ScopedVclPtrInstance< CertificateChooser > aChooser(nullptr, mxCtx, xSecContexts, eAction); + uno::Sequence< Reference< css::security::XCertificate > > xCerts(1); + xCerts[0] = Reference< css::security::XCertificate >(nullptr); + if (aChooser->Execute() != RET_OK) - return Reference< css::security::XCertificate >(nullptr); + return xCerts; - Reference< css::security::XCertificate > xCert = aChooser->GetSelectedCertificate(); + xCerts = aChooser->GetSelectedCertificates(); rProperties["Description"] = aChooser->GetDescription(); rProperties["Usage"] = aChooser->GetUsageText(); - if ( !xCert.is() ) - return Reference< css::security::XCertificate >(nullptr); - - return xCert; + return xCerts; } Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseCertificate(OUString& rDescription) @@ -489,23 +489,27 @@ Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseCertif Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseSigningCertificate(OUString& rDescription) { std::map<OUString, OUString> aProperties; - Reference< css::security::XCertificate > xCert = chooseCertificateImpl( aProperties, UserAction::Sign ); + Reference< css::security::XCertificate > xCert = chooseCertificatesImpl( aProperties, UserAction::Sign )[0]; rDescription = aProperties["Description"]; return xCert; } -Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseEncryptionCertificate(OUString& rDescription) +css::uno::Sequence< Reference< css::security::XCertificate > > DocumentDigitalSignatures::chooseEncryptionCertificate() { std::map<OUString, OUString> aProperties; - Reference< css::security::XCertificate > xCert = chooseCertificateImpl( aProperties, UserAction::Encrypt ); - rDescription = aProperties["Description"]; - return xCert; + uno::Sequence< Reference< css::security::XCertificate > > aCerts= + chooseCertificatesImpl( aProperties, UserAction::Encrypt ); + if (aCerts.getLength() == 1 && !aCerts[0].is()) + // our error case contract is: empty sequence, so map that! + return uno::Sequence< Reference< css::security::XCertificate > >(); + else + return aCerts; } css::uno::Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseCertificateWithProps(Sequence<::com::sun::star::beans::PropertyValue>& rProperties) { std::map<OUString, OUString> aProperties; - auto xCert = chooseCertificateImpl( aProperties, UserAction::Sign ); + auto xCert = chooseCertificatesImpl( aProperties, UserAction::Sign )[0]; std::vector<css::beans::PropertyValue> vec; for (const auto& pair : aProperties) diff --git a/xmlsecurity/source/component/documentdigitalsignatures.hxx b/xmlsecurity/source/component/documentdigitalsignatures.hxx index 2dbc55685929..9ef24ab36e5e 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.hxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.hxx @@ -63,7 +63,7 @@ private: /// @throws css::uno::RuntimeException css::uno::Sequence< css::security::DocumentSignatureInformation > ImplVerifySignatures( const css::uno::Reference< css::embed::XStorage >& rxStorage, const ::com::sun::star::uno::Reference< css::io::XInputStream >& xSignStream, DocumentSignatureMode eMode ); - css::uno::Reference< css::security::XCertificate > chooseCertificateImpl(std::map<OUString, OUString>& rProperties, const UserAction eAction); + css::uno::Sequence< css::uno::Reference< css::security::XCertificate > > chooseCertificatesImpl(std::map<OUString, OUString>& rProperties, const UserAction eAction); public: explicit DocumentDigitalSignatures( const css::uno::Reference< css::uno::XComponentContext>& rxCtx ); @@ -106,7 +106,7 @@ public: css::uno::Reference< css::security::XCertificate > SAL_CALL chooseCertificate(OUString& rDescription) override; css::uno::Reference< css::security::XCertificate > SAL_CALL chooseSigningCertificate(OUString& rDescription) override; - css::uno::Reference< css::security::XCertificate > SAL_CALL chooseEncryptionCertificate(OUString& rDescription) override; + css::uno::Sequence<css::uno::Reference< css::security::XCertificate > > SAL_CALL chooseEncryptionCertificate() override; css::uno::Reference< css::security::XCertificate > SAL_CALL chooseCertificateWithProps(css::uno::Sequence<::com::sun::star::beans::PropertyValue>& Properties) override; }; diff --git a/xmlsecurity/source/dialogs/certificatechooser.cxx b/xmlsecurity/source/dialogs/certificatechooser.cxx index 08a897f9f0ba..a334e0250225 100644 --- a/xmlsecurity/source/dialogs/certificatechooser.cxx +++ b/xmlsecurity/source/dialogs/certificatechooser.cxx @@ -228,15 +228,33 @@ void CertificateChooser::ImplInitialize() } -uno::Reference< css::security::XCertificate > CertificateChooser::GetSelectedCertificate() +uno::Sequence<uno::Reference< css::security::XCertificate > > CertificateChooser::GetSelectedCertificates() { + std::vector< uno::Reference< css::security::XCertificate > > aRet; SvTreeListEntry* pSel = m_pCertLB->FirstSelected(); - if( !pSel ) - return uno::Reference< css::security::XCertificate >(); - UserData* userData = static_cast<UserData*>(pSel->GetUserData()); - uno::Reference<security::XCertificate> xCert = userData->xCertificate; - return xCert; + if (meAction == UserAction::Encrypt) + { + // for encryption, multiselection is enabled + while(pSel) + { + UserData* userData = static_cast<UserData*>(pSel->GetUserData()); + aRet.push_back( userData->xCertificate ); + pSel = m_pCertLB->NextSelected(pSel); + } + } + else + { + uno::Reference< css::security::XCertificate > xCert; + if( pSel ) + { + UserData* userData = static_cast<UserData*>(pSel->GetUserData()); + xCert = userData->xCertificate; + } + aRet.push_back( xCert ); + } + + return comphelper::containerToSequence(aRet); } uno::Reference<xml::crypto::XXMLSecurityContext> CertificateChooser::GetSelectedSecurityContext() @@ -257,13 +275,15 @@ OUString CertificateChooser::GetDescription() OUString CertificateChooser::GetUsageText() { - uno::Reference<css::security::XCertificate> xCert = GetSelectedCertificate(); - return xCert.is() ? UsageInClearText(xCert->getCertificateUsage()) : OUString(); + uno::Sequence< uno::Reference<css::security::XCertificate> > xCerts = + GetSelectedCertificates(); + return (xCerts.hasElements() && xCerts[0].is()) ? + UsageInClearText(xCerts[0]->getCertificateUsage()) : OUString(); } IMPL_LINK_NOARG(CertificateChooser, CertificateHighlightHdl, SvTreeListBox*, void) { - bool bEnable = GetSelectedCertificate().is(); + bool bEnable = m_pCertLB->GetSelectionCount() > 0; m_pViewBtn->Enable( bEnable ); m_pOKBtn->Enable( bEnable ); m_pDescriptionED->Enable(bEnable); diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx index 42ca15d05faf..195c74ec5c3e 100644 --- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx +++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx @@ -406,7 +406,7 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, Button*, void) if ( aChooser->Execute() == RET_OK ) { sal_Int32 nSecurityId; - if (!maSignatureManager.add(aChooser->GetSelectedCertificate(), aChooser->GetSelectedSecurityContext(), + if (!maSignatureManager.add(aChooser->GetSelectedCertificates()[0], aChooser->GetSelectedSecurityContext(), aChooser->GetDescription(), nSecurityId, m_bAdESCompliant)) return; mbSignaturesChanged = true; commit 5d0f3cc3f9e6fc687ba6a40cebf2096d70e4f811 Author: Thorsten Behrens <thorsten.behr...@cib.de> Date: Thu Dec 7 05:08:37 2017 +0100 gpg4libre: pass proper debug flags down to gpgmepp Change-Id: Ide3f6e9fa218bcd26deaadbbdbed0c8905e66db9 diff --git a/external/gpgmepp/ExternalProject_gpgmepp.mk b/external/gpgmepp/ExternalProject_gpgmepp.mk index 73a0ad68e6cd..a10d41556b0c 100644 --- a/external/gpgmepp/ExternalProject_gpgmepp.mk +++ b/external/gpgmepp/ExternalProject_gpgmepp.mk @@ -59,6 +59,11 @@ $(call gb_ExternalProject_get_state_target,gpgmepp,build): $(gb_COMPILEROPTFLAGS),$(gb_COMPILERNOOPTFLAGS)) \ $(if $(ENABLE_DEBUG),$(gb_DEBUG_CFLAGS)) \ $(if $(filter $(true),$(gb_SYMBOL)),$(gb_DEBUGINFO_FLAGS))' \ + CXXFLAGS='$(CXXFLAGS) \ + $(if $(ENABLE_OPTIMIZED), \ + $(gb_COMPILEROPTFLAGS),$(gb_COMPILERNOOPTFLAGS)) \ + $(if $(ENABLE_DEBUG),$(gb_DEBUG_CXXFLAGS) -D_GLIBCXX_DEBUG) \ + $(if $(filter $(true),$(gb_SYMBOL)),$(gb_DEBUGINFO_FLAGS))' \ $(if $(filter LINUX,$(OS)), \ 'LDFLAGS=-Wl$(COMMA)-z$(COMMA)origin \ -Wl$(COMMA)-rpath$(COMMA)\$$$$ORIGIN') \ commit 757087a9829941bade8259673b57507d48cbdfc6 Author: Thorsten Behrens <thorsten.behr...@cib.de> Date: Wed Dec 6 15:20:54 2017 +0100 gpg4libre: add KDE4 fpicker gpg crypt chechbox Change-Id: Iba8fb0e0ac732f36cd1d880884bde1121e6b1eab diff --git a/vcl/unx/kde4/KDE4FilePicker.cxx b/vcl/unx/kde4/KDE4FilePicker.cxx index 7268bac1dc02..4488d04489b5 100644 --- a/vcl/unx/kde4/KDE4FilePicker.cxx +++ b/vcl/unx/kde4/KDE4FilePicker.cxx @@ -533,6 +533,9 @@ void KDE4FilePicker::addCustomControl(sal_Int16 controlId) case CHECKBOX_PASSWORD: resId = STR_FPICKER_PASSWORD; break; + case CHECKBOX_GPGENCRYPTION: + resId = STR_FPICKER_GPGENCRYPT; + break; case CHECKBOX_FILTEROPTIONS: resId = STR_FPICKER_FILTER_OPTIONS; break; @@ -571,6 +574,7 @@ void KDE4FilePicker::addCustomControl(sal_Int16 controlId) { case CHECKBOX_AUTOEXTENSION: case CHECKBOX_PASSWORD: + case CHECKBOX_GPGENCRYPTION: case CHECKBOX_FILTEROPTIONS: case CHECKBOX_READONLY: case CHECKBOX_LINK: @@ -657,6 +661,7 @@ void SAL_CALL KDE4FilePicker::initialize( const uno::Sequence<uno::Any> &args ) { operationMode = KFileDialog::Saving; addCustomControl( CHECKBOX_PASSWORD ); + addCustomControl( CHECKBOX_GPGENCRYPTION ); break; } case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS: @@ -664,6 +669,7 @@ void SAL_CALL KDE4FilePicker::initialize( const uno::Sequence<uno::Any> &args ) operationMode = KFileDialog::Saving; addCustomControl( CHECKBOX_AUTOEXTENSION ); addCustomControl( CHECKBOX_PASSWORD ); + addCustomControl( CHECKBOX_GPGENCRYPTION ); addCustomControl( CHECKBOX_FILTEROPTIONS ); break; } commit 9992fe1051d7dea3fddeb1d45b0e2a0a3f43ab08 Author: Thorsten Behrens <thorsten.behr...@cib.de> Date: Mon Dec 4 02:22:09 2017 +0100 gpg4libre: add gtk fpicker gpg crypt chechbox Change-Id: I27b494530a2b61eb37c4a9f7c3e1f9845f045e66 diff --git a/vcl/unx/gtk/fpicker/SalGtkFilePicker.cxx b/vcl/unx/gtk/fpicker/SalGtkFilePicker.cxx index 8a71c2de712e..dfc5274bbb63 100644 --- a/vcl/unx/gtk/fpicker/SalGtkFilePicker.cxx +++ b/vcl/unx/gtk/fpicker/SalGtkFilePicker.cxx @@ -161,6 +161,7 @@ SalGtkFilePicker::SalGtkFilePicker( const uno::Reference< uno::XComponentContext switch( i ) { LABEL_TOGGLE( AUTOEXTENSION ); LABEL_TOGGLE( PASSWORD ); + LABEL_TOGGLE( GPGENCRYPTION ); LABEL_TOGGLE( FILTEROPTIONS ); LABEL_TOGGLE( READONLY ); LABEL_TOGGLE( LINK ); @@ -1069,6 +1070,7 @@ GtkWidget *SalGtkFilePicker::getWidget( sal_Int16 nControlId, GType *pType ) { MAP_TOGGLE( AUTOEXTENSION ); MAP_TOGGLE( PASSWORD ); + MAP_TOGGLE( GPGENCRYPTION ); MAP_TOGGLE( FILTEROPTIONS ); MAP_TOGGLE( READONLY ); MAP_TOGGLE( LINK ); @@ -1611,12 +1613,14 @@ void SAL_CALL SalGtkFilePicker::initialize( const uno::Sequence<uno::Any>& aArgu eAction = GTK_FILE_CHOOSER_ACTION_SAVE; first_button_text = GTK_STOCK_SAVE; mbToggleVisibility[PASSWORD] = true; + mbToggleVisibility[GPGENCRYPTION] = true; // TODO break; case FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS: eAction = GTK_FILE_CHOOSER_ACTION_SAVE; first_button_text = GTK_STOCK_SAVE; mbToggleVisibility[PASSWORD] = true; + mbToggleVisibility[GPGENCRYPTION] = true; mbToggleVisibility[FILTEROPTIONS] = true; // TODO break; diff --git a/vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx b/vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx index 4c24307e7fd2..1266ac5cfdd3 100644 --- a/vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx +++ b/vcl/unx/gtk/fpicker/SalGtkFilePicker.hxx @@ -166,6 +166,7 @@ class SalGtkFilePicker : public SalGtkPicker, public SalGtkFilePicker_Base LINK, PREVIEW, SELECTION, + GPGENCRYPTION, TOGGLE_LAST }; diff --git a/vcl/unx/gtk/fpicker/resourceprovider.cxx b/vcl/unx/gtk/fpicker/resourceprovider.cxx index e41c7bf5fd25..3e5469a7c392 100644 --- a/vcl/unx/gtk/fpicker/resourceprovider.cxx +++ b/vcl/unx/gtk/fpicker/resourceprovider.cxx @@ -38,6 +38,7 @@ static const struct } CtrlIdToResIdTable[] = { { CHECKBOX_AUTOEXTENSION, STR_FPICKER_AUTO_EXTENSION }, { CHECKBOX_PASSWORD, STR_FPICKER_PASSWORD }, + { CHECKBOX_GPGENCRYPTION, STR_FPICKER_GPGENCRYPT }, { CHECKBOX_FILTEROPTIONS, STR_FPICKER_FILTER_OPTIONS }, { CHECKBOX_READONLY, STR_FPICKER_READONLY }, { CHECKBOX_LINK, STR_FPICKER_INSERT_AS_LINK }, commit 926dc6c984a4224cf895596504dca1a814a0cb43 Author: Thorsten Behrens <thorsten.behr...@cib.de> Date: Thu Nov 23 23:28:13 2017 +0100 gpg4libre: add gpg encrypt checbox to win32 filepicker Change-Id: Ia6315e8b1f04228984afd2fbca3c059df9589497 diff --git a/fpicker/source/office/OfficeControlAccess.cxx b/fpicker/source/office/OfficeControlAccess.cxx index 1b30f285734b..be9a91f212af 100644 --- a/fpicker/source/office/OfficeControlAccess.cxx +++ b/fpicker/source/office/OfficeControlAccess.cxx @@ -77,6 +77,7 @@ namespace svt { "FilterList", LISTBOX_FILTER, PROPERTY_FLAGS_COMMON }, { "FilterListLabel", LISTBOX_FILTER_LABEL, PROPERTY_FLAGS_COMMON | PropFlags::Text }, { "FilterOptionsBox", CHECKBOX_FILTEROPTIONS, PROPERTY_FLAGS_COMMON | PROPERTY_FLAGS_CHECKBOX }, + { "GpgPassword", CHECKBOX_GPGENCRYPTION, PROPERTY_FLAGS_COMMON | PROPERTY_FLAGS_CHECKBOX }, { "HelpButton", PUSHBUTTON_HELP, PROPERTY_FLAGS_COMMON | PropFlags::Text }, { "ImageTemplateList", LISTBOX_IMAGE_TEMPLATE, PROPERTY_FLAGS_COMMON | PROPERTY_FLAGS_LISTBOX }, { "ImageTemplateListLabel", LISTBOX_IMAGE_TEMPLATE_LABEL, PROPERTY_FLAGS_COMMON | PropFlags::Text }, diff --git a/fpicker/source/win32/filepicker/VistaFilePicker.cxx b/fpicker/source/win32/filepicker/VistaFilePicker.cxx index 449be62fb848..54ff672579ff 100644 --- a/fpicker/source/win32/filepicker/VistaFilePicker.cxx +++ b/fpicker/source/win32/filepicker/VistaFilePicker.cxx @@ -396,6 +396,7 @@ void SAL_CALL VistaFilePicker::initialize(const css::uno::Sequence< css::uno::An bFileOpenDialog = false; nFeatures |= FEATURE_AUTOEXTENSION; nFeatures |= FEATURE_PASSWORD; + nFeatures |= FEATURE_GPGPASSWORD; } break; @@ -405,6 +406,7 @@ void SAL_CALL VistaFilePicker::initialize(const css::uno::Sequence< css::uno::An nFeatures |= FEATURE_AUTOEXTENSION; nFeatures |= FEATURE_PASSWORD; nFeatures |= FEATURE_FILTEROPTIONS; + nFeatures |= FEATURE_GPGPASSWORD; } break; diff --git a/fpicker/source/win32/filepicker/VistaFilePickerImpl.cxx b/fpicker/source/win32/filepicker/VistaFilePickerImpl.cxx index 2b0fffe337d7..35be52b6101a 100644 --- a/fpicker/source/win32/filepicker/VistaFilePickerImpl.cxx +++ b/fpicker/source/win32/filepicker/VistaFilePickerImpl.cxx @@ -590,6 +590,13 @@ void VistaFilePickerImpl::impl_sta_enableFeatures(::sal_Int32 nFeatures, ::sal_I setLabelToControl(iCustom, nControlId); } + if ((nFeatures & FEATURE_GPGPASSWORD) == FEATURE_GPGPASSWORD) + { + nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_GPGENCRYPTION; + iCustom->AddCheckButton (nControlId, L"GpgPassword", false); + setLabelToControl(iCustom, nControlId); + } + if ((nFeatures & FEATURE_READONLY) == FEATURE_READONLY) { nControlId = css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY; @@ -1110,6 +1117,7 @@ void VistaFilePickerImpl::impl_sta_GetControlValue(const RequestRef& rRequest) switch (nId) { case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_PASSWORD : + case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_GPGENCRYPTION : case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_READONLY : case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS : case css::ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_LINK : diff --git a/fpicker/source/win32/filepicker/VistaFilePickerImpl.hxx b/fpicker/source/win32/filepicker/VistaFilePickerImpl.hxx index 70272ad8c1c0..5161d787e767 100644 --- a/fpicker/source/win32/filepicker/VistaFilePickerImpl.hxx +++ b/fpicker/source/win32/filepicker/VistaFilePickerImpl.hxx @@ -67,6 +67,7 @@ static const ::sal_Int32 FEATURE_IMAGETEMPLATE = 128; static const ::sal_Int32 FEATURE_PLAY = 256; static const ::sal_Int32 FEATURE_READONLY = 512; static const ::sal_Int32 FEATURE_VERSION = 1024; +static const ::sal_Int32 FEATURE_GPGPASSWORD = 2048; static const OUString PROP_PICKER_LISTENER("picker_listener" ); // [XFilePickerListenert] static const OUString PROP_DIALOG_SHOW_RESULT("dialog_show_result" ); // [sal_Bool] true=OK, false=CANCEL diff --git a/fpicker/source/win32/misc/resourceprovider.cxx b/fpicker/source/win32/misc/resourceprovider.cxx index bc9c270774b5..b7b70d4d45de 100644 --- a/fpicker/source/win32/misc/resourceprovider.cxx +++ b/fpicker/source/win32/misc/resourceprovider.cxx @@ -61,7 +61,8 @@ Entry const CtrlIdToResIdTable[] = { { LISTBOX_IMAGE_TEMPLATE_LABEL, STR_SVT_FILEPICKER_IMAGE_TEMPLATE }, { CHECKBOX_SELECTION, STR_SVT_FILEPICKER_SELECTION }, { FOLDERPICKER_TITLE, STR_SVT_FOLDERPICKER_DEFAULT_TITLE }, - { FOLDER_PICKER_DEF_DESCRIPTION, STR_SVT_FOLDERPICKER_DEFAULT_DESCRIPTION } + { FOLDER_PICKER_DEF_DESCRIPTION, STR_SVT_FOLDERPICKER_DEFAULT_DESCRIPTION }, + { CHECKBOX_GPGENCRYPTION, STR_SVT_FILEPICKER_GPGENCRYPT } }; const sal_Int32 SIZE_TABLE = SAL_N_ELEMENTS( CtrlIdToResIdTable ); commit c22236d733eff274cbd18e72109ff440177fab67 Author: Thorsten Behrens <thorsten.behr...@cib.de> Date: Thu Nov 23 22:18:09 2017 +0100 gpg4libre: find keymanager executable on Windows Change-Id: If93c06ad90d708b0fbaf476bda6fdb902bd77b1e diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx index ba726e04d0a5..42ca15d05faf 100644 --- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx +++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx @@ -468,9 +468,17 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, RemoveButtonHdl, Button*, void) IMPL_STATIC_LINK_NOARG(DigitalSignaturesDialog, CertMgrButtonHdl, Button*, void) { - const OUString aGUIServers[] = { OUString("kleopatra"), OUString("seahorse"), OUString("gpa"), OUString("kgpg") }; - // FIXME: the same for Windows + registry search for gpg4win +#ifdef _WIN32 + // FIXME: call GpgME::dirInfo("bindir") somewhere in + // SecurityEnvironmentGpg or whatnot + // FIXME: perhaps poke GpgME for uiserver, and hope it returns something useful? + const OUString aGUIServers[] = { OUString("kleopatra.exe"), OUString("launch-gpa.exe"), OUString("gpa.exe"), + OUString("bin\\kleopatra.exe"), OUString("bin\\launch-gpa.exe"), OUString("bin\\gpa.exe") }; + const char* cPath = "C:\\Program Files (x86)\\GNU\\GnuPG"; +#else + const OUString aGUIServers[] = { OUString("kleopatra"), OUString("seahorse"), OUString("gpa"), OUString("kgpg") }; const char* cPath = getenv("PATH"); +#endif if (cPath) { commit 0a58fdfdf48ec95295eca195b07424e98381af3f Author: Thorsten Behrens <thorsten.behr...@cib.de> Date: Sun Aug 20 03:38:05 2017 +0200 gpg4libre: [API CHANGE] add storage helper for GPG encryption data OpenPGP encryption needs to pass down slightly different meta data to package / zip storage. Change-Id: Idba9ad7a821cb33070cf5e5a0f79ae55db99b276 diff --git a/comphelper/Library_comphelper.mk b/comphelper/Library_comphelper.mk index e997bd5e6f32..4a24d65da15c 100644 --- a/comphelper/Library_comphelper.mk +++ b/comphelper/Library_comphelper.mk @@ -37,6 +37,7 @@ $(eval $(call gb_Library_add_defs,comphelper,\ )) $(eval $(call gb_Library_use_externals,comphelper,\ + gpgmepp \ boost_headers \ icuuc \ icu_headers \ diff --git a/comphelper/source/misc/storagehelper.cxx b/comphelper/source/misc/storagehelper.cxx index 166955d3b226..a05fb1358f3f 100644 --- a/comphelper/source/misc/storagehelper.cxx +++ b/comphelper/source/misc/storagehelper.cxx @@ -19,6 +19,7 @@ #include <com/sun/star/embed/ElementModes.hpp> #include <com/sun/star/embed/XEncryptionProtectedSource2.hpp> +#include <com/sun/star/embed/XEncryptionProtectedStorage.hpp> #include <com/sun/star/embed/XStorage.hpp> #include <com/sun/star/embed/XTransactedObject.hpp> #include <com/sun/star/embed/StorageFactory.hpp> @@ -43,6 +44,7 @@ #include <rtl/random.h> #include <osl/time.h> #include <osl/diagnose.h> +#include <sax/tools/converter.hxx> #include <ucbhelper/content.hxx> @@ -50,6 +52,15 @@ #include <comphelper/processfactory.hxx> #include <comphelper/documentconstants.hxx> #include <comphelper/storagehelper.hxx> +#include <comphelper/sequence.hxx> + +#if GPGME_HAVE_GPGME +# include <gpgme.h> +# include <context.h> +# include <encryptionresult.h> +# include <key.h> +# include <data.h> +#endif using namespace ::com::sun::star; @@ -194,11 +205,21 @@ void OStorageHelper::SetCommonStorageEncryptionData( const uno::Reference< embed::XStorage >& xStorage, const uno::Sequence< beans::NamedValue >& aEncryptionData ) { - uno::Reference< embed::XEncryptionProtectedSource2 > xEncrSet( xStorage, uno::UNO_QUERY ); + uno::Reference< embed::XEncryptionProtectedStorage > xEncrSet( xStorage, uno::UNO_QUERY ); if ( !xEncrSet.is() ) throw io::IOException(); // TODO - xEncrSet->setEncryptionData( aEncryptionData ); + if ( aEncryptionData.getLength() == 2 && + aEncryptionData[0].Name == "GpgInfos" && + aEncryptionData[1].Name == "EncryptionKey" ) + { + xEncrSet->setGpgProperties( + aEncryptionData[0].Value.get< uno::Sequence< uno::Sequence< beans::NamedValue > > >() ); + xEncrSet->setEncryptionData( + aEncryptionData[1].Value.get< uno::Sequence< beans::NamedValue > >() ); + } + else + xEncrSet->setEncryptionData( aEncryptionData ); } @@ -409,6 +430,7 @@ uno::Sequence< beans::NamedValue > OStorageHelper::CreatePackageEncryptionData( uno::Sequence< beans::NamedValue > OStorageHelper::CreateGpgPackageEncryptionData() { +#if GPGME_HAVE_GPGME // generate session key // -------------------- @@ -425,34 +447,95 @@ uno::Sequence< beans::NamedValue > OStorageHelper::CreateGpgPackageEncryptionDat rtl_random_destroyPool(aRandomPool); uno::Sequence< beans::NamedValue > aContainer(2); - uno::Sequence< beans::NamedValue > aGpgEncryptionData(3); + std::vector< uno::Sequence< beans::NamedValue > > aGpgEncryptions; + uno::Sequence< beans::NamedValue > aGpgEncryptionEntry(3); uno::Sequence< beans::NamedValue > aEncryptionData(1); - // TODO fire certificate chooser dialog uno::Reference< security::XDocumentDigitalSignatures > xSigner( security::DocumentDigitalSignatures::createWithVersion( comphelper::getProcessComponentContext(), "1.2" ) ); - // The user may provide a description while choosing a certificate. - OUString aDescription; - uno::Reference< security::XCertificate > xSignCertificate= - xSigner->chooseEncryptionCertificate(aDescription); + // fire up certificate chooser dialog - user can multi-select! + uno::Sequence< uno::Reference< security::XCertificate > > xSignCertificates= + xSigner->chooseEncryptionCertificate(); + + // generate one encrypted key entry for each recipient + // --------------------------------------------------- + + std::unique_ptr<GpgME::Context> ctx; + GpgME::Error err = GpgME::checkEngine(GpgME::OpenPGP); + if (err) + throw uno::RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol."); + + ctx.reset( GpgME::Context::createForProtocol(GpgME::OpenPGP) ); + if (ctx == nullptr) + throw uno::RuntimeException("The GpgME library failed to initialize for the OpenPGP protocol."); + ctx->setArmor(false); - uno::Sequence < sal_Int8 > aKeyID; - if (xSignCertificate.is()) + // TODO: add self-encryption key from user config + const uno::Reference< security::XCertificate >* pCerts=xSignCertificates.getConstArray(); + for (sal_uInt32 i = 0, nNum = xSignCertificates.getLength(); i < nNum; i++, pCerts++) { - aKeyID = xSignCertificate->getSHA1Thumbprint(); + uno::Sequence < sal_Int8 > aKeyID; + if (pCerts->is()) + aKeyID = (*pCerts)->getSHA256Thumbprint(); + + std::vector<GpgME::Key> keys; + keys.push_back( + ctx->key( + reinterpret_cast<const char*>(aKeyID.getConstArray()), + err, true)); + + // ctx is setup now, let's encrypt the lot! + GpgME::Data plain( + reinterpret_cast<const char*>(aVector.getConstArray()), + aVector.getLength(), false); + GpgME::Data cipher; + + GpgME::EncryptionResult crypt_res = ctx->encrypt( + keys, plain, + cipher, GpgME::Context::NoCompress); + + off_t result = cipher.seek(0,SEEK_SET); + (void) result; + assert(result == 0); + int len=0, curr=0; char buf; + while( (curr=cipher.read(&buf, 1)) ) + len += curr; + + if(crypt_res.error() || !len) + throw uno::RuntimeException("The GpgME library failed to encrypt."); + + uno::Sequence < sal_Int8 > aCipherValue(len); + result = cipher.seek(0,SEEK_SET); + assert(result == 0); + if( cipher.read(aCipherValue.getArray(), len) != len ) + throw uno::RuntimeException("The GpgME library failed to read the encrypted value."); + + SAL_INFO("comphelper.crypto", "Generated gpg crypto of length: " << len); + + aGpgEncryptionEntry[0].Name = "KeyId"; + aGpgEncryptionEntry[0].Value <<= aKeyID; + aGpgEncryptionEntry[1].Name = "KeyPacket"; + aGpgEncryptionEntry[1].Value <<= aKeyID; + aGpgEncryptionEntry[2].Name = "CipherValue"; + aGpgEncryptionEntry[2].Value <<= aCipherValue; + + aGpgEncryptions.push_back(aGpgEncryptionEntry); } - aGpgEncryptionData[0].Name = "KeyId"; - aGpgEncryptionData[0].Value <<= aKeyID; + aEncryptionData[0].Name = PACKAGE_ENCRYPTIONDATA_SHA256UTF8; + aEncryptionData[0].Value <<= aVector; aContainer[0].Name = "GpgInfos"; - aContainer[0].Value <<= aGpgEncryptionData; + aContainer[0].Value <<= comphelper::containerToSequence(aGpgEncryptions); aContainer[1].Name = "EncryptionKey"; aContainer[1].Value <<= aEncryptionData; return aContainer; +#else + return uno::Sequence< beans::NamedValue >(); +#endif } bool OStorageHelper::IsValidZipEntryFileName( const OUString& aName, bool bSlashAllowed ) diff --git a/offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl b/offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl index 5ddcc6831844..ecba64d51995 100644 --- a/offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl +++ b/offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl @@ -84,6 +84,37 @@ interface XEncryptionProtectedStorage: XEncryptionProtectedSource2 /** allows to get the encryption algorithms of the object. */ sequence< ::com::sun::star::beans::NamedValue > getEncryptionAlgorithms(); + + /** set OpenPGP-specific encryption properties + + <p> + When provided, switch ODF package encryption to OpenPGP. + </p> + <p> + For each recipient, add one sequence of named values, each of + the same structure. The following values could be part of that + provided sequence: + </p> + <dl> + <dt>KeyId</dt> + <dd> + specifies OpenPGP key ID or fingerprint of the public + key used to encrypt this session key against + </dd> + <dt>KeyPacket</dt> + <dd> + (optional) public key packet of the key used to encrypt + </dd> + <dt>CipherValue</dt> + <dd> + OpenPGP-encrypted session key for this recipient + </dd> + </dl> + + @since LibreOffice 6.0 + */ + void setGpgProperties( [in] sequence< sequence< ::com::sun::star::beans::NamedValue > > aProps ) + raises( ::com::sun::star::lang::IllegalArgumentException ); }; diff --git a/package/inc/PackageConstants.hxx b/package/inc/PackageConstants.hxx index df7bebcf6bd4..b81c0dd0a904 100644 --- a/package/inc/PackageConstants.hxx +++ b/package/inc/PackageConstants.hxx @@ -51,6 +51,7 @@ const sal_Int32 n_ConstDigestDecrypt = 1056; // 1024 + 32 #define ENCRYPTION_KEY_PROPERTY "EncryptionKey" #define STORAGE_ENCRYPTION_KEYS_PROPERTY "StorageEncryptionKeys" #define ENCRYPTION_ALGORITHMS_PROPERTY "EncryptionAlgorithms" +#define ENCRYPTION_GPG_PROPERTIES "EncryptionGpGProperties" #define HAS_ENCRYPTED_ENTRIES_PROPERTY "HasEncryptedEntries" #define HAS_NONENCRYPTED_ENTRIES_PROPERTY "HasNonEncryptedEntries" #define IS_INCONSISTENT_PROPERTY "IsInconsistent" diff --git a/package/inc/ZipPackage.hxx b/package/inc/ZipPackage.hxx index 61b0fc883575..f46eb33b0172 100644 --- a/package/inc/ZipPackage.hxx +++ b/package/inc/ZipPackage.hxx @@ -72,6 +72,7 @@ class ZipPackage final : public cppu::WeakImplHelper css::uno::Sequence< css::beans::NamedValue > m_aStorageEncryptionKeys; css::uno::Sequence< sal_Int8 > m_aEncryptionKey; + css::uno::Sequence< css::uno::Sequence< css::beans::NamedValue > > m_aGpgProps; FolderHash m_aRecent; OUString m_aURL; diff --git a/package/source/xstor/xstorage.cxx b/package/source/xstor/xstorage.cxx index cbcceece39ea..66678d7c378d 100644 --- a/package/source/xstor/xstorage.cxx +++ b/package/source/xstor/xstorage.cxx @@ -4205,6 +4205,66 @@ void SAL_CALL OStorage::setEncryptionAlgorithms( const uno::Sequence< beans::Nam } } +void SAL_CALL OStorage::setGpgProperties( const uno::Sequence< uno::Sequence< beans::NamedValue > >& aProps ) +{ + ::osl::MutexGuard aGuard( m_pData->m_xSharedMutex->GetMutex() ); + + if ( !m_pImpl ) + { + SAL_INFO("package.xstor", THROW_WHERE "Disposed!"); + throw lang::DisposedException( THROW_WHERE ); + } + + if ( m_pData->m_nStorageType != embed::StorageFormats::PACKAGE ) + throw uno::RuntimeException( THROW_WHERE ); // the interface must be visible only for package storage + + if ( !aProps.getLength() ) + throw uno::RuntimeException( THROW_WHERE "Unexpected empty encryption algorithms list!" ); + + SAL_WARN_IF( !m_pData->m_bIsRoot, "package.xstor", "setGpgProperties() method is not available for nonroot storages!" ); + if ( m_pData->m_bIsRoot ) + { + try { + m_pImpl->ReadContents(); + } + catch ( const uno::RuntimeException& aRuntimeException ) + { + SAL_INFO("package.xstor", "Rethrow: " << aRuntimeException.Message); + throw; + } + catch ( const uno::Exception& aException ) + { + SAL_INFO("package.xstor", "Rethrow: " << aException.Message); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( THROW_WHERE "Can not open package!", + static_cast< OWeakObject* >( this ), + aCaught ); + } + + uno::Reference< beans::XPropertySet > xPackPropSet( m_pImpl->m_xPackage, uno::UNO_QUERY_THROW ); + try + { + xPackPropSet->setPropertyValue( ENCRYPTION_GPG_PROPERTIES, + uno::makeAny( aProps ) ); + } + catch ( const uno::RuntimeException& aRuntimeException ) + { + SAL_INFO("package.xstor", "Rethrow: " << aRuntimeException.Message); + throw; + } + catch( const uno::Exception& aException ) + { + SAL_INFO("package.xstor", "Rethrow: " << aException.Message); + + uno::Any aCaught( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( THROW_WHERE "Can not open package!", + static_cast< OWeakObject* >( this ), + aCaught ); + } + } +} + uno::Sequence< beans::NamedValue > SAL_CALL OStorage::getEncryptionAlgorithms() { ::osl::MutexGuard aGuard( m_pData->m_xSharedMutex->GetMutex() ); diff --git a/package/source/xstor/xstorage.hxx b/package/source/xstor/xstorage.hxx index 262b317e4def..82cffa69a2fe 100644 --- a/package/source/xstor/xstorage.hxx +++ b/package/source/xstor/xstorage.hxx @@ -459,6 +459,7 @@ public: // XEncryptionProtectedStorage virtual void SAL_CALL setEncryptionAlgorithms( const css::uno::Sequence< css::beans::NamedValue >& aAlgorithms ) override; + virtual void SAL_CALL setGpgProperties( const css::uno::Sequence< css::uno::Sequence< css::beans::NamedValue > >& aCryptProps ) override; virtual css::uno::Sequence< css::beans::NamedValue > SAL_CALL getEncryptionAlgorithms() override; diff --git a/package/source/zippackage/ZipPackage.cxx b/package/source/zippackage/ZipPackage.cxx index 7eef97c5341f..769c7f662bba 100644 --- a/package/source/zippackage/ZipPackage.cxx +++ b/package/source/zippackage/ZipPackage.cxx @@ -1208,7 +1208,9 @@ uno::Reference< io::XInputStream > ZipPackage::writeTempFile() if ( m_nFormat == embed::StorageFormats::PACKAGE ) { - uno::Sequence < PropertyValue > aPropSeq( PKG_SIZE_NOENCR_MNFST ); + bool bIsGpgEncrypt = m_aGpgProps.hasElements(); + uno::Sequence < PropertyValue > aPropSeq( + bIsGpgEncrypt ? PKG_SIZE_NOENCR_MNFST+1 : PKG_SIZE_NOENCR_MNFST ); aPropSeq [PKG_MNFST_MEDIATYPE].Name = sMediaType; aPropSeq [PKG_MNFST_MEDIATYPE].Value <<= m_xRootFolder->GetMediaType(); aPropSeq [PKG_MNFST_VERSION].Name = sVersion; @@ -1216,6 +1218,11 @@ uno::Reference< io::XInputStream > ZipPackage::writeTempFile() aPropSeq [PKG_MNFST_FULLPATH].Name = sFullPath; aPropSeq [PKG_MNFST_FULLPATH].Value <<= OUString("/"); + if( bIsGpgEncrypt ) + { + aPropSeq[PKG_SIZE_NOENCR_MNFST].Name = "KeyInfo"; + aPropSeq[PKG_SIZE_NOENCR_MNFST].Value <<= m_aGpgProps; + } aManList.push_back( aPropSeq ); } @@ -1751,6 +1758,22 @@ void SAL_CALL ZipPackage::setPropertyValue( const OUString& aPropertyName, const } } } + else if ( aPropertyName == ENCRYPTION_GPG_PROPERTIES ) + { + uno::Sequence< uno::Sequence< beans::NamedValue > > aGpgProps; + if ( m_pZipFile || !( aValue >>= aGpgProps ) || aGpgProps.getLength() == 0 ) + { + throw IllegalArgumentException(THROW_WHERE "unexpected Gpg properties are provided.", uno::Reference< uno::XInterface >(), 2 ); + } + + m_aGpgProps = aGpgProps; + + // override algorithm defaults (which are some legacy ODF + // defaults) with reasonable values + m_nStartKeyGenerationID = 0; // this is unused for PGP + m_nCommonEncryptionID = xml::crypto::CipherID::AES_CBC_W3C_PADDING; + m_nChecksumDigestID = xml::crypto::DigestID::SHA512_1K; + } else throw UnknownPropertyException(THROW_WHERE ); } commit 3f775118a6d9e6cbd49edf7d5309e29edeeaff47 Author: Thorsten Behrens <thorsten.behr...@cib.de> Date: Fri Aug 18 21:34:11 2017 +0200 gpg4libre: add manifest entries for gpg encryption Change-Id: I71bd7e2c6c73d997fa1ed5bb36fdc2873daca10c diff --git a/package/source/manifest/ManifestDefines.hxx b/package/source/manifest/ManifestDefines.hxx index 968aed648e6a..c68c241c7514 100644 --- a/package/source/manifest/ManifestDefines.hxx +++ b/package/source/manifest/ManifestDefines.hxx @@ -24,8 +24,10 @@ #define MANIFEST_NSPREFIX "manifest:" #define ELEMENT_MANIFEST "manifest:manifest" #define ATTRIBUTE_XMLNS "xmlns:manifest" +#define ATTRIBUTE_XMLNS_LOEXT "xmlns:loext" #define MANIFEST_NAMESPACE "http://openoffice.org/2001/manifest" #define MANIFEST_OASIS_NAMESPACE "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" +#define MANIFEST_LOEXT_NAMESPACE "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" #define MANIFEST_DOCTYPE "<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">" #define ATTRIBUTE_CDATA "CDATA" @@ -34,6 +36,16 @@ #define ATTRIBUTE_VERSION "manifest:version" #define ATTRIBUTE_MEDIA_TYPE "manifest:media-type" #define ATTRIBUTE_SIZE "manifest:size" +#define ELEMENT_MANIFEST_KEYINFO "loext:keyinfo" +#define ELEMENT_ENCRYPTED_KEYINFO "loext:KeyInfo" +#define ELEMENT_ENCRYPTEDKEY "loext:encrypted-key" +#define ELEMENT_ENCRYPTIONMETHOD "loext:encryption-method" +#define ELEMENT_PGPDATA "loext:PGPData" +#define ELEMENT_PGPKEYID "loext:PGPKeyID" +#define ELEMENT_PGPKEYPACKET "loext:PGPKeyPacket" +#define ATTRIBUTE_ALGORITHM "loext:PGPAlgorithm" +#define ELEMENT_CIPHERDATA "loext:CipherData" +#define ELEMENT_CIPHERVALUE "loext:CipherValue" #define ELEMENT_ENCRYPTION_DATA "manifest:encryption-data" #define ATTRIBUTE_CHECKSUM_TYPE "manifest:checksum-type" @@ -69,6 +81,7 @@ #define AES256_URL "http://www.w3.org/2001/04/xmlenc#aes256-cbc" #define PBKDF2_NAME "PBKDF2" +#define PGP_NAME "PGP" #define PBKDF2_URL "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0#pbkdf2" #endif diff --git a/package/source/manifest/ManifestExport.cxx b/package/source/manifest/ManifestExport.cxx index 60a5128e945d..5cf87334ca62 100644 --- a/package/source/manifest/ManifestExport.cxx +++ b/package/source/manifest/ManifestExport.cxx @@ -23,6 +23,7 @@ #include <com/sun/star/xml/crypto/DigestID.hpp> #include <com/sun/star/xml/crypto/CipherID.hpp> #include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/NamedValue.hpp> #include <com/sun/star/uno/RuntimeException.hpp> #include "ManifestDefines.hxx" @@ -66,11 +67,25 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con const OUString sChecksumTypeAttribute ( ATTRIBUTE_CHECKSUM_TYPE ); const OUString sChecksumAttribute ( ATTRIBUTE_CHECKSUM); + const OUString sKeyInfoElement ( ELEMENT_ENCRYPTED_KEYINFO ); + const OUString sManifestKeyInfoElement ( ELEMENT_MANIFEST_KEYINFO ); + const OUString sEncryptedKeyElement ( ELEMENT_ENCRYPTEDKEY ); + const OUString sEncryptionMethodElement ( ELEMENT_ENCRYPTIONMETHOD ); + const OUString sPgpDataElement ( ELEMENT_PGPDATA ); + const OUString sPgpKeyIDElement ( ELEMENT_PGPKEYID ); + const OUString sPGPKeyPacketElement ( ELEMENT_PGPKEYPACKET ); + const OUString sAlgorithmAttribute ( ATTRIBUTE_ALGORITHM ); + const OUString sCipherDataElement ( ELEMENT_CIPHERDATA ); + const OUString sCipherValueElement ( ELEMENT_CIPHERVALUE ); + const OUString sKeyInfo ( "KeyInfo" ); + const OUString sPgpKeyIDProperty ( "KeyId" ); + const OUString sPgpKeyPacketProperty ( "KeyPacket" ); + const OUString sCipherValueProperty ( "CipherValue" ); const OUString sFullPathProperty ( "FullPath" ); const OUString sVersionProperty ( "Version" ); const OUString sMediaTypeProperty ( "MediaType" ); const OUString sIterationCountProperty ( "IterationCount" ); - const OUString sDerivedKeySizeProperty ( "DerivedKeySize" ); + const OUString sDerivedKeySizeProperty ( "DerivedKeySize" ); const OUString sSaltProperty ( "Salt" ); const OUString sInitialisationVectorProperty( "InitialisationVector" ); const OUString sSizeProperty ( "Size" ); @@ -92,6 +107,7 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con const OUString sAES256_URL ( AES256_URL ); const OUString sPBKDF2_Name ( PBKDF2_NAME ); + const OUString sPGP_Name ( PGP_NAME ); ::comphelper::AttributeList * pRootAttrList = new ::comphelper::AttributeList; const uno::Sequence < beans::PropertyValue > *pSequence = rManList.getConstArray(); @@ -100,6 +116,7 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con // find the mediatype of the document if any OUString aDocMediaType; OUString aDocVersion; + sal_Int32 nRootFolderPropIndex=-1; for (sal_uInt32 nInd = 0; nInd < nManLength ; nInd++ ) { OUString aMediaType; @@ -130,6 +147,7 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con { aDocMediaType = aMediaType; aDocVersion = aVersion; + nRootFolderPropIndex = nInd; break; } } @@ -164,9 +182,14 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con bAcceptNonemptyVersion = true; if ( aDocVersion.compareTo( ODFVER_012_TEXT ) >= 0 ) { - // this is ODF12 generation, let encrypted streams contain start-key-generation entry + // this is ODF12 or later generation, let encrypted + // streams contain start-key-generation entry bStoreStartKeyGeneration = true; pRootAttrList->AddAttribute ( sVersionAttribute, sCdataAttribute, aDocVersion ); + // plus gpg4libre extensions - loext NS for that + pRootAttrList->AddAttribute ( ATTRIBUTE_XMLNS_LOEXT, + sCdataAttribute, + MANIFEST_LOEXT_NAMESPACE ); } } else @@ -192,6 +215,116 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con } xHandler->startElement( sManifestElement, xRootAttrList ); + const uno::Any *pKeyInfoProperty = nullptr; + if ( nRootFolderPropIndex >= 0 ) + { + // do we have package-wide encryption info? + const beans::PropertyValue *pValue = + pSequence[nRootFolderPropIndex].getConstArray(); + for (sal_uInt32 j = 0, nNum = pSequence[nRootFolderPropIndex].getLength(); j < nNum; j++, pValue++) + { + if (pValue->Name == sKeyInfo ) + pKeyInfoProperty = &pValue->Value; + } + + if ( pKeyInfoProperty ) + { + // yeah, so that goes directly below the manifest:manifest + // element + ::comphelper::AttributeList * pNewAttrList = new ::comphelper::AttributeList; + uno::Reference < xml::sax::XAttributeList > xNewAttrList (pNewAttrList); + OUStringBuffer aBuffer; + + xHandler->ignorableWhitespace ( sWhiteSpace ); + + // ==== manifest:keyinfo & children + xHandler->startElement( sManifestKeyInfoElement, nullptr ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + + uno::Sequence< uno::Sequence < beans::NamedValue > > aKeyInfoSequence; + *pKeyInfoProperty >>= aKeyInfoSequence; + const uno::Sequence < beans::NamedValue > *pKeyInfoSequence = aKeyInfoSequence.getConstArray(); + const sal_uInt32 nKeyInfoLength = aKeyInfoSequence.getLength(); + for (sal_uInt32 nInd = 0; nInd < nKeyInfoLength ; nInd++ ) + { + uno::Sequence < sal_Int8 > aPgpKeyID; + uno::Sequence < sal_Int8 > aPgpKeyPacket; + uno::Sequence < sal_Int8 > aCipherValue; + const beans::NamedValue *pNValue = pKeyInfoSequence[nInd].getConstArray(); + for (sal_uInt32 j = 0, nNum = pKeyInfoSequence[nInd].getLength(); j < nNum; j++, pNValue++) + { + if (pNValue->Name == sPgpKeyIDProperty ) + pNValue->Value >>= aPgpKeyID; + else if (pNValue->Name == sPgpKeyPacketProperty ) + pNValue->Value >>= aPgpKeyPacket; + else if (pNValue->Name == sCipherValueProperty ) + pNValue->Value >>= aCipherValue; + } + + if (aPgpKeyID.hasElements() && aCipherValue.hasElements() ) + { + // ==== manifest:encrypted-key & children - one for each recipient + xHandler->startElement( sEncryptedKeyElement, nullptr ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + + // TODO: the algorithm should rather be configurable + pNewAttrList->AddAttribute ( sAlgorithmAttribute, sCdataAttribute, + "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" ); + xHandler->startElement( sEncryptionMethodElement, xNewAttrList ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + xHandler->endElement( sEncryptionMethodElement ); + + xHandler->startElement( sKeyInfoElement, nullptr ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + + xHandler->startElement( sPgpDataElement, nullptr ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + + xHandler->startElement( sPgpKeyIDElement, nullptr ); + ::sax::Converter::encodeBase64(aBuffer, aPgpKeyID); + xHandler->characters( aBuffer.makeStringAndClear() ); + xHandler->endElement( sPgpKeyIDElement ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + + // key packet is optional + if (aPgpKeyPacket.hasElements()) + { + xHandler->startElement( sPGPKeyPacketElement, nullptr ); + ::sax::Converter::encodeBase64(aBuffer, aPgpKeyPacket); + xHandler->characters( aBuffer.makeStringAndClear() ); + xHandler->endElement( sPGPKeyPacketElement ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + } + + xHandler->endElement( sPgpDataElement ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + + xHandler->endElement( sKeyInfoElement ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + + xHandler->startElement( sCipherDataElement, nullptr ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + + xHandler->startElement( sCipherValueElement, nullptr ); + ::sax::Converter::encodeBase64(aBuffer, aCipherValue); + xHandler->characters( aBuffer.makeStringAndClear() ); + xHandler->endElement( sCipherValueElement ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + + xHandler->endElement( sCipherDataElement ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + + xHandler->endElement( sEncryptedKeyElement ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + } + } + + xHandler->endElement( sManifestKeyInfoElement ); + xHandler->ignorableWhitespace ( sWhiteSpace ); + } + } + + // now write individual file entries for (sal_uInt32 i = 0 ; i < nManLength ; i++) { ::comphelper::AttributeList *pAttrList = new ::comphelper::AttributeList; @@ -314,22 +447,36 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con pNewAttrList = new ::comphelper::AttributeList; xNewAttrList = pNewAttrList; - pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute, sCdataAttribute, sPBKDF2_Name ); - - if ( bStoreStartKeyGeneration ) + if ( pKeyInfoProperty ) { - aBuffer.append( nDerivedKeySize ); - pNewAttrList->AddAttribute ( sKeySizeAttribute, sCdataAttribute, aBuffer.makeStringAndClear() ); + pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute, + sCdataAttribute, + sPGP_Name ); + // no start-key-generation needed, our session key has + // max size already + bStoreStartKeyGeneration = false; } + else + { + pNewAttrList->AddAttribute ( sKeyDerivationNameAttribute, + sCdataAttribute, + sPBKDF2_Name ); + + if ( bStoreStartKeyGeneration ) + { + aBuffer.append( nDerivedKeySize ); + pNewAttrList->AddAttribute ( sKeySizeAttribute, sCdataAttribute, aBuffer.makeStringAndClear() ); + } - sal_Int32 nCount = 0; - *pIterationCount >>= nCount; - aBuffer.append (nCount); - pNewAttrList->AddAttribute ( sIterationCountAttribute, sCdataAttribute, aBuffer.makeStringAndClear() ); + sal_Int32 nCount = 0; + *pIterationCount >>= nCount; + aBuffer.append (nCount); + pNewAttrList->AddAttribute ( sIterationCountAttribute, sCdataAttribute, aBuffer.makeStringAndClear() ); - *pSalt >>= aSequence; - ::sax::Converter::encodeBase64(aBuffer, aSequence); - pNewAttrList->AddAttribute ( sSaltAttribute, sCdataAttribute, aBuffer.makeStringAndClear() ); + *pSalt >>= aSequence; + ::sax::Converter::encodeBase64(aBuffer, aSequence); + pNewAttrList->AddAttribute ( sSaltAttribute, sCdataAttribute, aBuffer.makeStringAndClear() ); + } xHandler->ignorableWhitespace ( sWhiteSpace ); xHandler->startElement( sKeyDerivationElement , xNewAttrList); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits