comphelper/Library_comphelper.mk | 1 comphelper/source/misc/storagehelper.cxx | 118 +++++++- cui/source/options/optgenrl.cxx | 22 + 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/UnoApi_offapi.mk | 1 offapi/com/sun/star/embed/XEncryptionProtectedStorage.idl | 31 ++ offapi/com/sun/star/security/XDocumentDigitalSignatures.idl | 2 offapi/com/sun/star/xml/crypto/GPGSEInitializer.idl | 37 ++ 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/inc/gpg/SEInitializer.hxx | 22 + xmlsecurity/qa/unit/signing/data/badDsigGPG.odt |binary xmlsecurity/qa/unit/signing/data/badStreamGPG.odt |binary xmlsecurity/qa/unit/signing/data/goodGPG.odt |binary xmlsecurity/qa/unit/signing/data/pubring.gpg |binary xmlsecurity/qa/unit/signing/data/random_seed | 2 xmlsecurity/qa/unit/signing/data/secring.gpg |binary xmlsecurity/qa/unit/signing/data/trustdb.gpg |binary xmlsecurity/qa/unit/signing/data/untrustedGoodGPG.odt |binary xmlsecurity/qa/unit/signing/signing.cxx | 91 ++++++ 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 xmlsecurity/source/gpg/SEInitializer.cxx | 39 ++ xmlsecurity/source/xmlsec/xsec_xmlsec.cxx | 7 xmlsecurity/util/xsec_xmlsec.component | 3 45 files changed, 735 insertions(+), 68 deletions(-)
New commits: commit fcc949fc94dc05c0562701dab58eb3ad6f1c2962 Author: Thorsten Behrens <thorsten.behr...@cib.de> Date: Thu Dec 7 19:38:10 2017 +0100 comphelper: fix windows build Change-Id: I3241426674050c027e1b000b33fb284525a58cbb (cherry picked from commit a9a4c26ed1365ffa089654fefc8fa2f29862b6c7) diff --git a/comphelper/source/misc/storagehelper.cxx b/comphelper/source/misc/storagehelper.cxx index 7fa46554b595..36641485fe2e 100644 --- a/comphelper/source/misc/storagehelper.cxx +++ b/comphelper/source/misc/storagehelper.cxx @@ -494,7 +494,7 @@ uno::Sequence< beans::NamedValue > OStorageHelper::CreateGpgPackageEncryptionDat // ctx is setup now, let's encrypt the lot! GpgME::Data plain( reinterpret_cast<const char*>(aVector.getConstArray()), - aVector.getLength(), false); + size_t(aVector.getLength()), false); GpgME::Data cipher; GpgME::EncryptionResult crypt_res = ctx->encrypt( commit 6e0d97d09c3cf387fe63aab679905c8845f6d1eb 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 (cherry picked from commit ed50a0a2ce51584fa3a8fba0094220a4bf25c650) 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 ac761ccb088deeb5f363a648feadde327d59a1ea 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 a50c1c1b34a01dc2d8ffa59aa4421bc4906fd236 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 3393046a66bd..6e997d92ebc5 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 500e70db59c62c1f553d9a7bdd15f0433a6d1cbc 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 76424657952de9adc3ca61e99c9b671e55cb36b0 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 c6246c979668..290c4536f192 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 51b789c74208910f6b1d89b37fd73a28523cc2e3 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 75e87e2eb5c7..62a282ab9ea1 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 ); @@ -1072,6 +1073,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 ); @@ -1614,12 +1616,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 0718a369d11b623bd979b0b2d31bfbd0a738f117 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 e3434bc6b2dc641e7dec365782784526cc9c0a43 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 688eefd6b21154b18ea3652e52fcbcd653e455ef 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 9291eb53cbc7..41d65fb97b7c 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 532088359184..f55679d3d826 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 3823ed07ffb8..5e61d4678490 100644 --- a/package/source/zippackage/ZipPackage.cxx +++ b/package/source/zippackage/ZipPackage.cxx @@ -1206,7 +1206,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; @@ -1214,6 +1216,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 ); } @@ -1749,6 +1756,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 ee0f1c7971ff06969ee3e6fd567e202377c5d616 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); commit 9895830b4f00cf54cea64e9b6db46fc627db6222 Author: Thorsten Behrens <thorsten.behr...@cib.de> Date: Wed Dec 6 14:02:25 2017 +0100 gpg4libre: add unit tests for ODF signing feature Since this requires a working gpg setup, limit to linux for the moment. If you need to add signatures or redo them, run LibreOffice from a shell with env var GNUPGHOME=<core>/xmlsecurity/qa/unit/signing/data/ set. For editing keys, gpg2 also accepts a --homedir=<core>/xmlsecurity/qa/unit/signing/data/ option Change-Id: I59e5b563098b19d05c8c2db32537241bc835fc80 Reviewed-on: https://gerrit.libreoffice.org/45950 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Thorsten Behrens <thorsten.behr...@cib.de> (cherry picked from commit 6da58b0e842b81669e5076c2c00dddf67a5616e1) diff --git a/xmlsecurity/qa/unit/signing/data/badDsigGPG.odt b/xmlsecurity/qa/unit/signing/data/badDsigGPG.odt new file mode 100644 index 000000000000..032ddbf7a276 Binary files /dev/null and b/xmlsecurity/qa/unit/signing/data/badDsigGPG.odt differ diff --git a/xmlsecurity/qa/unit/signing/data/badStreamGPG.odt b/xmlsecurity/qa/unit/signing/data/badStreamGPG.odt new file mode 100644 index 000000000000..252ea26b00b1 Binary files /dev/null and b/xmlsecurity/qa/unit/signing/data/badStreamGPG.odt differ diff --git a/xmlsecurity/qa/unit/signing/data/goodGPG.odt b/xmlsecurity/qa/unit/signing/data/goodGPG.odt new file mode 100644 index 000000000000..a02af30169fe Binary files /dev/null and b/xmlsecurity/qa/unit/signing/data/goodGPG.odt differ diff --git a/xmlsecurity/qa/unit/signing/data/pubring.gpg b/xmlsecurity/qa/unit/signing/data/pubring.gpg new file mode 100644 index 000000000000..40a8d53fb401 Binary files /dev/null and b/xmlsecurity/qa/unit/signing/data/pubring.gpg differ diff --git a/xmlsecurity/qa/unit/signing/data/random_seed b/xmlsecurity/qa/unit/signing/data/random_seed new file mode 100644 index 000000000000..8e68109a880e --- /dev/null +++ b/xmlsecurity/qa/unit/signing/data/random_seed @@ -0,0 +1,2 @@ +°Á,A? ´ p£Ôj`\ÚGkV¿feTâ*ì;¼^hÌFÖ¾3µ}²´iõÅsAØr¾9©B´h¡oWFæÀ! !7(â;9µ±xÚ*L¯zY¡8=ë#ç6æñÇï3Y&](^æµ4änZ?ålÿ.÷®ÔÓïØ}Öµ]¡5w6!Ç?ç¼lãÁ'%k©.^,IfÏVîVÏÓ ¥'_R!QºéUݪiDöUZ" ¦ö°Z°$R^MfØçàï )_~»ñûwoÊÃ6c©3/ CÌñ÷Åù*EÅ;BzQ"MÛúÖ¶QCú-é×Òí¾¼' Ýy³$ ë_ ÓÏ!^s2zht¯LÇNÖ;¼©Íè¶\ûÁÅ«çÌ 0måøöG¼÷9õM_®'ÕÆm(K·HÏ|ñôô®ÌézU;0Az|ñ½°§8òX=aÙHºX>cÂ4&Å6¢ãÜkñÓ/TìCäÆý¿sÈÀÊ_O`ä %M{UD çù¸Â{Ô;[cV9Ä]!ýf@û(p^ÝÐ[ÿîhíÌáyòöséTäëotf(«"Î(×qN²©c¤r ÚÓ½aµÔÐܵ Û§õ·³*³?>õYC6Åøa%'Ë]Ìi=g¯lR +/R°?uÿâñâê7[ÄF(È \ No newline at end of file diff --git a/xmlsecurity/qa/unit/signing/data/secring.gpg b/xmlsecurity/qa/unit/signing/data/secring.gpg new file mode 100644 index 000000000000..d98950c22ecd Binary files /dev/null and b/xmlsecurity/qa/unit/signing/data/secring.gpg differ diff --git a/xmlsecurity/qa/unit/signing/data/trustdb.gpg b/xmlsecurity/qa/unit/signing/data/trustdb.gpg new file mode 100644 index 000000000000..c86bb02f3d79 Binary files /dev/null and b/xmlsecurity/qa/unit/signing/data/trustdb.gpg differ diff --git a/xmlsecurity/qa/unit/signing/data/untrustedGoodGPG.odt b/xmlsecurity/qa/unit/signing/data/untrustedGoodGPG.odt new file mode 100644 index 000000000000..e1b36d54417e Binary files /dev/null and b/xmlsecurity/qa/unit/signing/data/untrustedGoodGPG.odt differ diff --git a/xmlsecurity/qa/unit/signing/signing.cxx b/xmlsecurity/qa/unit/signing/signing.cxx index 4d2419cf6e41..635993eb38b6 100644 --- a/xmlsecurity/qa/unit/signing/signing.cxx +++ b/xmlsecurity/qa/unit/signing/signing.cxx @@ -8,6 +8,7 @@ */ #include <config_features.h> +#include <config_gpgme.h> #include <sal/config.h> @@ -102,7 +103,18 @@ public: void testXAdESGood(); /// Test importing of signature line images void testSignatureLineImages(); - +#ifdef LINUX +# if GPGME_HAVE_GPGME + /// Test a typical ODF where all streams are GPG-signed. + void testODFGoodGPG(); + /// Test a typical ODF where all streams are GPG-signed, but we don't trust the signature. + void testODFUntrustedGoodGPG(); + /// Test a typical broken ODF signature where one stream is corrupted. + void testODFBrokenStreamGPG(); + /// Test a typical broken ODF signature where the XML dsig hash is corrupted. + void testODFBrokenDsigGPG(); +# endif +#endif CPPUNIT_TEST_SUITE(SigningTest); CPPUNIT_TEST(testDescription); CPPUNIT_TEST(testODFGood); @@ -125,6 +137,14 @@ public: CPPUNIT_TEST(testXAdES); CPPUNIT_TEST(testXAdESGood); CPPUNIT_TEST(testSignatureLineImages); +#ifdef LINUX +# if GPGME_HAVE_GPGME + CPPUNIT_TEST(testODFGoodGPG); + CPPUNIT_TEST(testODFUntrustedGoodGPG); + CPPUNIT_TEST(testODFBrokenStreamGPG); + CPPUNIT_TEST(testODFBrokenDsigGPG); +# endif +#endif CPPUNIT_TEST_SUITE_END(); private: @@ -157,6 +177,16 @@ void SigningTest::setUp() osl::FileBase::getSystemPathFromFileURL(aTargetDir, aTargetPath); setenv("MOZILLA_CERTIFICATE_FOLDER", aTargetPath.toUtf8().getStr(), 1); #endif +#ifdef LINUX +# if GPGME_HAVE_GPGME + // Make gpg use our own defined setup below data dir + OUString aHomePath; + osl::FileBase::getSystemPathFromFileURL( + m_directories.getURLFromSrc(DATA_DIRECTORY), + aHomePath); + setenv("GNUPGHOME", aHomePath.toUtf8().getStr(), 1); +# endif +#endif } void SigningTest::tearDown() @@ -657,6 +687,65 @@ void SigningTest::testSignatureLineImages() CPPUNIT_ASSERT(xSignatureInfo[0].InvalidSignatureLineImage.is()); } +#ifdef LINUX +# if GPGME_HAVE_GPGME +void SigningTest::testODFGoodGPG() +{ + createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "goodGPG.odt"); + SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get()); + CPPUNIT_ASSERT(pBaseModel); + SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell(); + CPPUNIT_ASSERT(pObjectShell); + // Our local gpg config fully trusts the signing cert, so in + // contrast to the X509 test we can fail on NOTVALIDATED here + SignatureState nActual = pObjectShell->GetDocumentSignatureState(); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + (OString::number( + static_cast<std::underlying_type<SignatureState>::type>(nActual)) + .getStr()), + nActual, SignatureState::OK); +} + +void SigningTest::testODFUntrustedGoodGPG() +{ + createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "untrustedGoodGPG.odt"); + SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get()); + CPPUNIT_ASSERT(pBaseModel); + SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell(); + CPPUNIT_ASSERT(pObjectShell); + // Our local gpg config does _not_ trust the signing cert, so in + // contrast to the X509 test we can fail everything but + // NOTVALIDATED here + SignatureState nActual = pObjectShell->GetDocumentSignatureState(); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + (OString::number( + static_cast<std::underlying_type<SignatureState>::type>(nActual)) + .getStr()), + nActual, SignatureState::NOTVALIDATED); +} + +void SigningTest::testODFBrokenStreamGPG() +{ + createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "badStreamGPG.odt"); + SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get()); + CPPUNIT_ASSERT(pBaseModel); + SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell(); + CPPUNIT_ASSERT(pObjectShell); + CPPUNIT_ASSERT_EQUAL(static_cast<int>(SignatureState::BROKEN), static_cast<int>(pObjectShell->GetDocumentSignatureState())); +} + +void SigningTest::testODFBrokenDsigGPG() +{ + createDoc(m_directories.getURLFromSrc(DATA_DIRECTORY) + "badDsigGPG.odt"); + SfxBaseModel* pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get()); + CPPUNIT_ASSERT(pBaseModel); + SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell(); + CPPUNIT_ASSERT(pObjectShell); + CPPUNIT_ASSERT_EQUAL(static_cast<int>(SignatureState::BROKEN), static_cast<int>(pObjectShell->GetDocumentSignatureState())); +} +# endif +#endif + void SigningTest::registerNamespaces(xmlXPathContextPtr& pXmlXpathCtx) { xmlXPathRegisterNs(pXmlXpathCtx, BAD_CAST("odfds"), BAD_CAST("urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0")); commit c7fa2da1532d9f140cb9018b0a62c62228c67ba1 Author: Katarina Behrens <katarina.behr...@cib.de> Date: Wed Nov 29 23:07:47 2017 +0100 Restore GPG SEInitializer service user config now needs it to collect user's private GPG keys Change-Id: Ia4ad4133b621160cf37281750cafa9f3c5c3c231 Reviewed-on: https://gerrit.libreoffice.org/45562 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Thorsten Behrens <thorsten.behr...@cib.de> (cherry picked from commit 1c58b047d117bb087abc571b74c06cdf7499b1a0) diff --git a/cui/source/options/optgenrl.cxx b/cui/source/options/optgenrl.cxx index a4465ad01487..8639d764c823 100644 --- a/cui/source/options/optgenrl.cxx +++ b/cui/source/options/optgenrl.cxx @@ -18,6 +18,13 @@ */ #include <comphelper/string.hxx> + +#include <config_gpgme.h> +#if GPGME_HAVE_GPGME +#include <com/sun/star/xml/crypto/GPGSEInitializer.hpp> +#include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp> +#endif + #include <i18nlangtag/mslangid.hxx> #include <vcl/svapp.hxx> #include <vcl/msgbox.hxx> @@ -32,6 +39,8 @@ #include <svx/dlgutil.hxx> #include <svx/svxids.hrc> +using namespace css; + namespace { @@ -205,6 +214,19 @@ SvxGeneralTabPage::SvxGeneralTabPage(vcl::Window* pParent, const SfxItemSet& rCo InitControls(); SetExchangeSupport(); // this page needs ExchangeSupport SetLinks(); +#if GPGME_HAVE_GPGME + // unused yet, I just wanted to see if this delivers the desired results + uno::Reference< xml::crypto::XSEInitializer > xSEInitializer; + try + { + xSEInitializer = xml::crypto::GPGSEInitializer::create( comphelper::getProcessComponentContext() ); + uno::Reference<xml::crypto::XXMLSecurityContext> xSC = xSEInitializer->createSecurityContext( OUString() ); + // completely bogus, this is just to appease loplugins + xSEInitializer->freeSecurityContext( xSC ); + } + catch ( uno::Exception const & ) + {} +#endif } SvxGeneralTabPage::~SvxGeneralTabPage() diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk index c32c3265d091..472771a5c15d 100644 --- a/offapi/UnoApi_offapi.mk +++ b/offapi/UnoApi_offapi.mk @@ -461,6 +461,7 @@ $(eval $(call gb_UnoApi_add_idlfiles_nohdl,offapi,com/sun/star/xml/crypto,\ NSSInitializer \ SecurityEnvironment \ SEInitializer \ + GPGSEInitializer \ XMLSecurityContext \ )) $(eval $(call gb_UnoApi_add_idlfiles_nohdl,offapi,com/sun/star/xml/dom,\ diff --git a/offapi/com/sun/star/xml/crypto/GPGSEInitializer.idl b/offapi/com/sun/star/xml/crypto/GPGSEInitializer.idl new file mode 100644 index 000000000000..82e836c7c0ca --- /dev/null +++ b/offapi/com/sun/star/xml/crypto/GPGSEInitializer.idl @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef __com_sun_star_xml_crypto_GPGSEInitializer_idl_ +#define __com_sun_star_xml_crypto_GPGSEInitializer_idl_ + +#include <com/sun/star/xml/crypto/XSEInitializer.idl> + +module com { module sun { module star { module xml { module crypto { + +/** + * Service of GPGSEInitializer + */ +service GPGSEInitializer : XSEInitializer; + +} ; } ; } ; } ; } ; + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmlsecurity/inc/gpg/SEInitializer.hxx b/xmlsecurity/inc/gpg/SEInitializer.hxx index db73d621f7be..3cc89da8d82d 100644 --- a/xmlsecurity/inc/gpg/SEInitializer.hxx +++ b/xmlsecurity/inc/gpg/SEInitializer.hxx @@ -13,14 +13,20 @@ #include <com/sun/star/uno/XComponentContext.hpp> #include <com/sun/star/uno/Reference.hxx> #include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> #include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp> #include <com/sun/star/xml/crypto/XSEInitializer.hpp> #include <xsecgpgdllapi.h> #include <cppuhelper/implbase.hxx> -class XSECGPG_DLLPUBLIC SEInitializerGpg : public cppu::WeakImplHelper< css::xml::crypto::XSEInitializer > +class XSECGPG_DLLPUBLIC SEInitializerGpg : public cppu::WeakImplHelper +< + css::xml::crypto::XSEInitializer, + css::lang::XServiceInfo +> { public: SEInitializerGpg(); @@ -32,6 +38,20 @@ public: virtual void SAL_CALL freeSecurityContext( const css::uno::Reference< css::xml::crypto::XXMLSecurityContext >& securityContext ) override; + + static css::uno::Sequence< OUString > impl_getSupportedServiceNames(); + + static OUString impl_getImplementationName(); + + /* XServiceInfo */ + virtual OUString SAL_CALL getImplementationName( ) override; + + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + static css::uno::Reference< css::uno::XInterface > SAL_CALL impl_createInstance( const css::uno::Reference< css::lang::XMultiServiceFactory >& aServiceManager ) ; + static css::uno::Reference< css::lang::XSingleServiceFactory > impl_createFactory( const css::uno::Reference< css::lang::XMultiServiceFactory >& aServiceManager ) ; }; #endif diff --git a/xmlsecurity/source/gpg/SEInitializer.cxx b/xmlsecurity/source/gpg/SEInitializer.cxx index 667e9ce355c7..93e2ab263d33 100644 --- a/xmlsecurity/source/gpg/SEInitializer.cxx +++ b/xmlsecurity/source/gpg/SEInitializer.cxx @@ -9,6 +9,8 @@ #include <config_gpgme.h> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/supportsservice.hxx> #include <gpg/SEInitializer.hxx> #include "SecurityEnvironment.hxx" #include "XMLSecurityContext.hxx" @@ -56,4 +58,41 @@ void SAL_CALL SEInitializerGpg::freeSecurityContext( const uno::Reference< XXMLS { } + + +uno::Reference< uno::XInterface > SAL_CALL SEInitializerGpg::impl_createInstance( const uno::Reference< lang::XMultiServiceFactory > & /*rxMSF*/) +{ + return static_cast<cppu::OWeakObject*>(new SEInitializerGpg()); +} + +uno::Reference< XSingleServiceFactory > SEInitializerGpg::impl_createFactory( const Reference< XMultiServiceFactory >& aServiceManager ) { + return cppu::createSingleFactory( aServiceManager, impl_getImplementationName(), impl_createInstance, impl_getSupportedServiceNames() ) ; +} + +/* XServiceInfo */ +OUString SAL_CALL SEInitializerGpg::impl_getImplementationName() +{ + return OUString("com.sun.star.xml.security.SEInitializer_Gpg"); +} + +uno::Sequence< OUString > SAL_CALL SEInitializerGpg::impl_getSupportedServiceNames() +{ + return {"com.sun.star.xml.crypto.GPGSEInitializer"}; +} + +sal_Bool SAL_CALL SEInitializerGpg::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL SEInitializerGpg::getSupportedServiceNames() +{ + return impl_getSupportedServiceNames(); +} + +OUString SAL_CALL SEInitializerGpg::getImplementationName() +{ + return impl_getImplementationName(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmlsecurity/source/xmlsec/xsec_xmlsec.cxx b/xmlsecurity/source/xmlsec/xsec_xmlsec.cxx index 265ab2f8f960..d65d92eb1374 100644 --- a/xmlsecurity/source/xmlsec/xsec_xmlsec.cxx +++ b/xmlsecurity/source/xmlsec/xsec_xmlsec.cxx @@ -29,7 +29,8 @@ #include <config_gpgme.h> #if GPGME_HAVE_GPGME -# include <gpg/xmlsignature_gpgimpl.hxx> +#include <gpg/xmlsignature_gpgimpl.hxx> +#include <gpg/SEInitializer.hxx> #endif using namespace ::cppu; @@ -50,6 +51,10 @@ SAL_DLLPUBLIC_EXPORT void* SAL_CALL xsec_xmlsec_component_getFactory( const sal_ { xFactory = XMLSignature_GpgImpl::impl_createFactory( static_cast< XMultiServiceFactory* >( pServiceManager ) ) ; } + else if( SEInitializerGpg::impl_getImplementationName().equalsAscii( pImplName ) ) + { + xFactory = SEInitializerGpg::impl_createFactory( static_cast< XMultiServiceFactory* >( pServiceManager ) ) ; + } else #endif if( XMLElementWrapper_XmlSecImpl_getImplementationName().equalsAscii( pImplName ) ) diff --git a/xmlsecurity/util/xsec_xmlsec.component b/xmlsecurity/util/xsec_xmlsec.component index ff0e09b82f92..d47ceef0b8d5 100644 --- a/xmlsecurity/util/xsec_xmlsec.component +++ b/xmlsecurity/util/xsec_xmlsec.component @@ -26,6 +26,9 @@ <service name="com.sun.star.xml.crypto.NSSInitializer"/> <service name="com.sun.star.xml.crypto.SEInitializer"/> </implementation> + <implementation name="com.sun.star.xml.security.SEInitializer_Gpg"> + <service name="com.sun.star.xml.crypto.GPGSEInitializer"/> + </implementation> <implementation name="com.sun.star.xml.security.bridge.xmlsec.SecurityEnvironment_NssImpl"> <service name="com.sun.star.xml.crypto.SecurityEnvironment"/> </implementation>
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits