[Libreoffice-commits] core.git: Branch 'libreoffice-6-0' - 13 commits - comphelper/Library_comphelper.mk comphelper/source cui/source external/gpgmepp fpicker/source include/sal offapi/com offapi/UnoApi_offapi.mk package/inc package/source sfx2/source vcl/unx xmlsecurity/inc xmlsecurity/qa xmlsecurity/source xmlsecurity/util

Thorsten Behrens Thorsten.Behrens at CIB.de
Thu Dec 7 18:52:49 UTC 2017


 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.Behrens at 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.Behrens at 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.Behrens at 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.Behrens at 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
+ at 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.Behrens at 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.Behrens at 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.Behrens at 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.behrens at 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.behrens at 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.Behrens at 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.Behrens at 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.Behrens at 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 <ci at libreoffice.org>
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at 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¯zY„¡8=ë#ç6æñÇï3ˆY&](^“浊4änZ?ålÿ.÷®ÔÓïØ‹}Öµ]¡5w6!Ç?ç¼l†ãÁ'%k©.^,IfÏVîVÏÓ¥'_R!QºéUÝªiDöUZ" ¦ö°­Z°$R^Mf“Øç—àï )_~»‰ñûw‡oʇÃ6–c©3ž/ CÌñ÷Åù*‰EÅ;BzQ"MÛúÖ¶QCú-é×Òí¾¼'…Ý•y³$…ë_
ӛϟ!^s2zht¯LÇNÖ;¼©Íè¶\ûÁÅ«çÌ0m冑øöG¼÷9õ‘M_­®“'ÕÆm‡(K·HÏ|‚ñôôŠ®ÌézšŸU;0žAz|ñ½°§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.Behrens at 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 <ci at libreoffice.org>
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at 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>


More information about the Libreoffice-commits mailing list