[Libreoffice-commits] core.git: xmlsecurity/inc xmlsecurity/qa xmlsecurity/source xmlsecurity/uiconfig

Tor Lillqvist tml at collabora.com
Tue Nov 8 12:32:17 UTC 2016


 xmlsecurity/inc/digitalsignaturesdialog.hxx                |    7 +-
 xmlsecurity/inc/documentsignaturemanager.hxx               |    6 +
 xmlsecurity/inc/sigstruct.hxx                              |   17 +++++
 xmlsecurity/inc/xmlsignaturehelper.hxx                     |    4 -
 xmlsecurity/qa/unit/signing/signing.cxx                    |    6 -
 xmlsecurity/source/component/documentdigitalsignatures.cxx |    4 +
 xmlsecurity/source/component/documentdigitalsignatures.hxx |    5 +
 xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx     |   37 ++++++++++--
 xmlsecurity/source/helper/documentsignaturemanager.cxx     |   28 ++++++++-
 xmlsecurity/source/helper/ooxmlsecparser.cxx               |    8 +-
 xmlsecurity/source/helper/xmlsignaturehelper.cxx           |    8 +-
 xmlsecurity/source/helper/xsecctl.cxx                      |    8 +-
 xmlsecurity/source/helper/xsecctl.hxx                      |   29 ++++++---
 xmlsecurity/source/helper/xsecparser.cxx                   |   25 ++++++--
 xmlsecurity/source/helper/xsecparser.hxx                   |    4 +
 xmlsecurity/source/helper/xsecsign.cxx                     |   40 +++++++------
 xmlsecurity/source/helper/xsecverify.cxx                   |   12 ++-
 xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui         |   15 ++++
 18 files changed, 201 insertions(+), 62 deletions(-)

New commits:
commit b2318479c8635af8e022ff4f844e85a1f6b9f4de
Author: Tor Lillqvist <tml at collabora.com>
Date:   Sat Oct 29 09:50:28 2016 +0300

    Work in progress on supporting XAdES-compliant signatures for ODF
    
    xmlsecurity is such a mess. Too many different classes that actually
    have more or less identical life-time, with names that smell of
    delusions of grandeur. "Manager", "security framework controller" etc
    for stuff that actually exist only during the execution of a simple
    dialog. And then a "helper" class that actually in on a higher level
    than a "framework controller". But oh well.
    
    Change-Id: I86e461b1bc91a0d8f5b7fb9f13a5be201729df1e

diff --git a/xmlsecurity/inc/digitalsignaturesdialog.hxx b/xmlsecurity/inc/digitalsignaturesdialog.hxx
index f58dccf..c9226e6 100644
--- a/xmlsecurity/inc/digitalsignaturesdialog.hxx
+++ b/xmlsecurity/inc/digitalsignaturesdialog.hxx
@@ -70,6 +70,8 @@ private:
     VclPtr<FixedImage>         m_pSigsOldSignatureImg;
     VclPtr<FixedText>          m_pSigsOldSignatureFI;
 
+    VclPtr<CheckBox>           m_pXAdESCompliantCB;
+
     VclPtr<PushButton>         m_pViewBtn;
     VclPtr<PushButton>         m_pAddBtn;
     VclPtr<PushButton>         m_pRemoveBtn;
@@ -82,6 +84,9 @@ private:
     bool m_bHasDocumentSignature;
     bool m_bWarningShowSignMacro;
 
+    bool m_bXAdESCompliant;
+
+    DECL_LINK(XAdESCompliantCheckBoxHdl, CheckBox&, void);
     DECL_LINK(ViewButtonHdl, Button*, void);
     DECL_LINK(AddButtonHdl, Button*, void);
     DECL_LINK(RemoveButtonHdl, Button*, void);
@@ -90,7 +95,7 @@ private:
     DECL_LINK(StartVerifySignatureHdl, LinkParamNone*, bool );
     DECL_LINK(OKButtonHdl, Button*, void );
 
-    void                ImplGetSignatureInformations(bool bUseTempStream, bool bCacheLastSignature = true);
+    void                ImplGetSignatureInformations(bool bUseTempStream, bool bCacheLastSignature);
     void                ImplFillSignaturesBox();
     void                ImplShowSignaturesDetails();
 
diff --git a/xmlsecurity/inc/documentsignaturemanager.hxx b/xmlsecurity/inc/documentsignaturemanager.hxx
index 097c0e1..fd981d7 100644
--- a/xmlsecurity/inc/documentsignaturemanager.hxx
+++ b/xmlsecurity/inc/documentsignaturemanager.hxx
@@ -57,7 +57,7 @@ public:
     bool isXML(const OUString& rURI);
     SignatureStreamHelper ImplOpenSignatureStream(sal_Int32 eStreamMode, bool bTempStream);
     /// Add a new signature, using xCert as a signing certificate, and rDescription as description.
-    bool add(const css::uno::Reference<css::security::XCertificate>& xCert, const OUString& rDescription, sal_Int32& nSecurityId);
+    bool add(const css::uno::Reference<css::security::XCertificate>& xCert, const OUString& rDescription, sal_Int32& nSecurityId, bool bXAdESCompliantIfODF);
     /// Remove signature at nPosition.
     void remove(sal_uInt16 nPosition);
     /// Read signatures from either a temp stream or the real storage.
@@ -66,6 +66,10 @@ public:
     void write();
     /// Lazy creation of PDF helper.
     PDFSignatureHelper& getPDFSignatureHelper();
+#if 0
+    // Checks if the document is a kind where it is relevant to distinguish between using XAdES or not
+    bool IsXAdESRelevant();
+#endif
 };
 
 #endif // INCLUDED_XMLSECURITY_INC_DOCUMENTSIGNATUREMANAGER_HXX
diff --git a/xmlsecurity/inc/sigstruct.hxx b/xmlsecurity/inc/sigstruct.hxx
index 610845c..e662d36 100644
--- a/xmlsecurity/inc/sigstruct.hxx
+++ b/xmlsecurity/inc/sigstruct.hxx
@@ -23,6 +23,7 @@
 #include <rtl/ustring.hxx>
 #include <com/sun/star/util/DateTime.hpp>
 #include <com/sun/star/xml/crypto/SecurityOperationStatus.hpp>
+#include <com/sun/star/xml/crypto/DigestID.hpp>
 #include <com/sun/star/uno/Sequence.hxx>
 
 #include <vector>
@@ -41,11 +42,23 @@ struct SignatureReferenceInformation
 {
     SignatureReferenceType  nType;
     OUString   ouURI;
+    // For ODF: XAdES digests (SHA256) or the old SHA1, from css::xml::crypto::DigestID
+    sal_Int32  nDigestID;
     OUString   ouDigestValue;
 
-    SignatureReferenceInformation( SignatureReferenceType type, const OUString& uri )
+    SignatureReferenceInformation() :
+        nType(SignatureReferenceType::SAMEDOCUMENT),
+        ouURI(""),
+        nDigestID(css::xml::crypto::DigestID::SHA1),
+        ouDigestValue("")
+    {
+    }
+
+    SignatureReferenceInformation( SignatureReferenceType type, sal_Int32 digestID, const OUString& uri ) :
+        SignatureReferenceInformation()
     {
         nType = type;
+        nDigestID = digestID;
         ouURI = uri;
     }
 };
@@ -57,6 +70,8 @@ struct SignatureInformation
     sal_Int32 nSecurityId;
     sal_Int32 nSecurityEnvironmentIndex;
     css::xml::crypto::SecurityOperationStatus nStatus;
+    // For ODF: XAdES digests (SHA256) or the old SHA1, from css::xml::crypto::DigestID
+    sal_Int32 nDigestID;
     SignatureReferenceInformations  vSignatureReferenceInfors;
     OUString ouX509IssuerName;
     OUString ouX509SerialNumber;
diff --git a/xmlsecurity/inc/xmlsignaturehelper.hxx b/xmlsecurity/inc/xmlsignaturehelper.hxx
index 3ff3a9c..8e0c658 100644
--- a/xmlsecurity/inc/xmlsignaturehelper.hxx
+++ b/xmlsecurity/inc/xmlsignaturehelper.hxx
@@ -172,8 +172,8 @@ public:
     void        SetDateTime( sal_Int32 nSecurityId, const Date& rDate, const tools::Time& rTime );
     void SetDescription(sal_Int32 nSecurityId, const OUString& rDescription);
 
-    void        AddForSigning( sal_Int32 securityId, const OUString& uri, const OUString& objectURL, bool bBinary );
-    bool        CreateAndWriteSignature( const css::uno::Reference< css::xml::sax::XDocumentHandler >& xDocumentHandler );
+    void        AddForSigning( sal_Int32 securityId, const OUString& uri, const OUString& objectURL, bool bBinary, bool bXAdESCompliantIfODF );
+    bool        CreateAndWriteSignature( const css::uno::Reference< css::xml::sax::XDocumentHandler >& xDocumentHandler, bool bXAdESCompliantIfODF );
     bool        ReadAndVerifySignature( const css::uno::Reference< css::io::XInputStream >& xInputStream );
 
     // MT: ??? I think only for adding/removing, not for new signatures...
diff --git a/xmlsecurity/qa/unit/signing/signing.cxx b/xmlsecurity/qa/unit/signing/signing.cxx
index d6833b4..847ef9a 100644
--- a/xmlsecurity/qa/unit/signing/signing.cxx
+++ b/xmlsecurity/qa/unit/signing/signing.cxx
@@ -202,7 +202,7 @@ void SigningTest::testDescription()
     CPPUNIT_ASSERT(xCertificate.is());
     OUString aDescription("SigningTest::testDescription");
     sal_Int32 nSecurityId;
-    aManager.add(xCertificate, aDescription, nSecurityId);
+    aManager.add(xCertificate, aDescription, nSecurityId, false);
 
     // Read back the signature and make sure that the description survives the roundtrip.
     aManager.read(/*bUseTempStream=*/true);
@@ -235,7 +235,7 @@ void SigningTest::testOOXMLDescription()
     CPPUNIT_ASSERT(xCertificate.is());
     OUString aDescription("SigningTest::testDescription");
     sal_Int32 nSecurityId;
-    aManager.add(xCertificate, aDescription, nSecurityId);
+    aManager.add(xCertificate, aDescription, nSecurityId, false);
 
     // Read back the signature and make sure that the description survives the roundtrip.
     aManager.read(/*bUseTempStream=*/true);
@@ -267,7 +267,7 @@ void SigningTest::testOOXMLAppend()
     uno::Reference<security::XCertificate> xCertificate = getCertificate(aManager.maSignatureHelper);
     CPPUNIT_ASSERT(xCertificate.is());
     sal_Int32 nSecurityId;
-    aManager.add(xCertificate, OUString(), nSecurityId);
+    aManager.add(xCertificate, OUString(), nSecurityId, false);
 
     // Read back the signatures and make sure that we have the expected amount.
     aManager.read(/*bUseTempStream=*/true);
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx
index 08da227..4320a88 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
@@ -57,6 +57,10 @@ DocumentDigitalSignatures::DocumentDigitalSignatures( const Reference< XComponen
 {
 }
 
+DocumentDigitalSignatures::~DocumentDigitalSignatures()
+{
+}
+
 void DocumentDigitalSignatures::initialize( const Sequence< Any >& aArguments)
         throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
 {
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.hxx b/xmlsecurity/source/component/documentdigitalsignatures.hxx
index bd07304..8f6515c 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.hxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.hxx
@@ -45,7 +45,9 @@ class DocumentDigitalSignatures : public cppu::WeakImplHelper
 {
 private:
     css::uno::Reference< css::uno::XComponentContext > mxCtx;
-    // will be set by XInitialization. If not we assume true. false means an earlier version.
+    // will be set by XInitialization. If not we assume true. false means an earlier version (whatever that means,
+    // this is a string, not a boolean).
+    // Note that the code talks about "ODF version" even if this class is also used to sign OOXML.
     OUString m_sODFVersion;
     //The number of arguments which were passed in XInitialization::initialize
     int m_nArgumentsCount;
@@ -58,6 +60,7 @@ private:
 
 public:
     explicit DocumentDigitalSignatures( const css::uno::Reference< css::uno::XComponentContext>& rxCtx );
+    virtual ~DocumentDigitalSignatures() override;
 
     // for service registration...
     static OUString GetImplementationName() throw (css::uno::RuntimeException);
diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
index f6bddb6..5d8ab1d 100644
--- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
+++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx
@@ -116,6 +116,7 @@ DigitalSignaturesDialog::DigitalSignaturesDialog(
     get(m_pHintDocFT, "dochint");
     get(m_pHintBasicFT, "macrohint");
     get(m_pHintPackageFT, "packagehint");
+    get(m_pXAdESCompliantCB, "xadescompliant");
     get(m_pViewBtn, "view");
     get(m_pAddBtn, "sign");
     get(m_pRemoveBtn, "remove");
@@ -129,6 +130,8 @@ DigitalSignaturesDialog::DigitalSignaturesDialog(
     get(m_pSigsOldSignatureImg, "oldsignatureimg");
     get(m_pSigsOldSignatureFI, "oldsignatureft");
 
+    m_bXAdESCompliant = !DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion);
+
     Size aControlSize(275, 109);
     const long nControlWidth = aControlSize.Width();
     aControlSize = LogicToPixel(aControlSize, MapUnit::MapAppFont);
@@ -151,6 +154,9 @@ DigitalSignaturesDialog::DigitalSignaturesDialog(
     m_pSignaturesLB->SetSelectHdl( LINK( this, DigitalSignaturesDialog, SignatureHighlightHdl ) );
     m_pSignaturesLB->SetDoubleClickHdl( LINK( this, DigitalSignaturesDialog, SignatureSelectHdl ) );
 
+    m_pXAdESCompliantCB->SetToggleHdl( LINK( this, DigitalSignaturesDialog, XAdESCompliantCheckBoxHdl ) );
+    m_pXAdESCompliantCB->Check(m_bXAdESCompliant);
+
     m_pViewBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, ViewButtonHdl ) );
     m_pViewBtn->Disable();
 
@@ -196,6 +202,7 @@ void DigitalSignaturesDialog::dispose()
     m_pSigsNotvalidatedFI.clear();
     m_pSigsOldSignatureImg.clear();
     m_pSigsOldSignatureFI.clear();
+    m_pXAdESCompliantCB.clear();
     m_pViewBtn.clear();
     m_pAddBtn.clear();
     m_pRemoveBtn.clear();
@@ -315,9 +322,24 @@ short DigitalSignaturesDialog::Execute()
 {
     // Verify Signatures and add certificates to ListBox...
     mbVerifySignatures = true;
-    ImplGetSignatureInformations(false);
+    ImplGetSignatureInformations(/*bUseTempStream=*/false, /*bCacheLastSignature=*/true);
     ImplFillSignaturesBox();
 
+    // FIXME: Disable the "Use XAdES compliant signatures" checkbox if it is irrelevant. If it is
+    // enabled, set its initial state based on existing signatures, if any.
+
+    // If it is OOXML, the checkbox is irrelevant.
+
+    // How to find out here whether it is OOXML? I don't want to create a SignatureStreamHelper and
+    // check its nStorageFormat as that seems overly complicated and seems to have weird indirect
+    // consequences, as I noticed when I tried to use DocumentSignatureManager::IsXAdESRelevant()
+    // (which now is in #if 0).
+
+    if (maSignatureManager.maCurrentSignatureInformations.size() > 0)
+    {
+        // If the document has only SHA-1 signatures we probably want it to stay that way?
+    }
+
     // Only verify once, content will not change.
     // But for refreshing signature information, StartVerifySignatureHdl will be called after each add/remove
     mbVerifySignatures = false;
@@ -346,6 +368,11 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, SignatureSelectHdl, SvTreeListBox*, boo
     return false;
 }
 
+IMPL_LINK_NOARG(DigitalSignaturesDialog, XAdESCompliantCheckBoxHdl, CheckBox&, void)
+{
+    m_bXAdESCompliant = m_pXAdESCompliantCB->IsChecked();
+}
+
 IMPL_LINK_NOARG(DigitalSignaturesDialog, ViewButtonHdl, Button*, void)
 {
     ImplShowSignaturesDetails();
@@ -363,7 +390,7 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, Button*, void)
         if ( aChooser->Execute() == RET_OK )
         {
             sal_Int32 nSecurityId;
-            if (!maSignatureManager.add(aChooser->GetSelectedCertificate(), aChooser->GetDescription(), nSecurityId))
+            if (!maSignatureManager.add(aChooser->GetSelectedCertificate(), aChooser->GetDescription(), nSecurityId, m_bXAdESCompliant))
                 return;
             mbSignaturesChanged = true;
 
@@ -382,7 +409,7 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, Button*, void)
                 // will not contain
                 // SecurityOperationStatus_OPERATION_SUCCEEDED
                 mbVerifySignatures = true;
-                ImplGetSignatureInformations(true, /*bCacheLastSignature=*/false);
+                ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
                 ImplFillSignaturesBox();
             }
         }
@@ -391,7 +418,7 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, Button*, void)
     {
         OSL_FAIL( "Exception while adding a signature!" );
         // Don't keep invalid entries...
-        ImplGetSignatureInformations(true, /*bCacheLastSignature=*/false);
+        ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
         ImplFillSignaturesBox();
     }
 }
@@ -415,7 +442,7 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, RemoveButtonHdl, Button*, void)
         {
             OSL_FAIL( "Exception while removing a signature!" );
             // Don't keep invalid entries...
-            ImplGetSignatureInformations(true);
+            ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/true);
             ImplFillSignaturesBox();
         }
     }
diff --git a/xmlsecurity/source/helper/documentsignaturemanager.cxx b/xmlsecurity/source/helper/documentsignaturemanager.cxx
index 3e33e10..b88714f 100644
--- a/xmlsecurity/source/helper/documentsignaturemanager.cxx
+++ b/xmlsecurity/source/helper/documentsignaturemanager.cxx
@@ -58,6 +58,28 @@ PDFSignatureHelper& DocumentSignatureManager::getPDFSignatureHelper()
     return *mpPDFSignatureHelper;
 }
 
+#if 0 // For some reason does not work
+bool DocumentSignatureManager::IsXAdESRelevant()
+{
+    if (mxStore.is())
+    {
+        // ZIP-based: ODF or OOXML.
+        maSignatureHelper.StartMission();
+
+        SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream(embed::ElementModes::READ, /*bUseTempStream=*/true);
+        if (aStreamHelper.nStorageFormat == embed::StorageFormats::OFOPXML)
+        {
+            maSignatureHelper.EndMission();
+            return false;
+        }
+        // FIXME: How to figure out if it is ODF 1.2?
+        maSignatureHelper.EndMission();
+        return true;
+    }
+    return false;
+}
+#endif
+
 /* Using the zip storage, we cannot get the properties "MediaType" and "IsEncrypted"
     We use the manifest to find out if a file is xml and if it is encrypted.
     The parameter is an encoded uri. However, the manifest contains paths. Therefore
@@ -193,7 +215,7 @@ SignatureStreamHelper DocumentSignatureManager::ImplOpenSignatureStream(sal_Int3
     return aHelper;
 }
 
-bool DocumentSignatureManager::add(const uno::Reference<security::XCertificate>& xCert, const OUString& rDescription, sal_Int32& nSecurityId)
+bool DocumentSignatureManager::add(const uno::Reference<security::XCertificate>& xCert, const OUString& rDescription, sal_Int32& nSecurityId, bool bXAdESCompliantIfODF)
 {
     if (!xCert.is())
     {
@@ -250,7 +272,7 @@ bool DocumentSignatureManager::add(const uno::Reference<security::XCertificate>&
     for (sal_Int32 n = 0; n < nElements; n++)
     {
         bool bBinaryMode = !isXML(aElements[n]);
-        maSignatureHelper.AddForSigning(nSecurityId, aElements[n], aElements[n], bBinaryMode);
+        maSignatureHelper.AddForSigning(nSecurityId, aElements[n], aElements[n], bBinaryMode, bXAdESCompliantIfODF);
     }
 
     maSignatureHelper.SetDateTime(nSecurityId, Date(Date::SYSTEM), tools::Time(tools::Time::SYSTEM));
@@ -275,7 +297,7 @@ bool DocumentSignatureManager::add(const uno::Reference<security::XCertificate>&
             XMLSignatureHelper::ExportSignature(xDocumentHandler, maCurrentSignatureInformations[n]);
 
         // Create a new one...
-        maSignatureHelper.CreateAndWriteSignature(xDocumentHandler);
+        maSignatureHelper.CreateAndWriteSignature(xDocumentHandler, bXAdESCompliantIfODF);
 
         // That's it...
         XMLSignatureHelper::CloseDocumentHandler(xDocumentHandler);
diff --git a/xmlsecurity/source/helper/ooxmlsecparser.cxx b/xmlsecurity/source/helper/ooxmlsecparser.cxx
index cc764b6..8535c82 100644
--- a/xmlsecurity/source/helper/ooxmlsecparser.cxx
+++ b/xmlsecurity/source/helper/ooxmlsecparser.cxx
@@ -59,7 +59,7 @@ throw (xml::sax::SAXException, uno::RuntimeException, std::exception)
     {
         OUString aURI = xAttribs->getValueByName("URI");
         if (aURI.startsWith("#"))
-            m_pXSecController->addReference(aURI.copy(1));
+            m_pXSecController->addReference(aURI.copy(1), xml::crypto::DigestID::SHA1);
         else
         {
             m_aReferenceURI = aURI;
@@ -73,7 +73,7 @@ throw (xml::sax::SAXException, uno::RuntimeException, std::exception)
             OUString aAlgorithm = xAttribs->getValueByName("Algorithm");
             if (aAlgorithm == ALGO_RELATIONSHIP)
             {
-                m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/false);
+                m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/false, /*nDigestID=*/xml::crypto::DigestID::SHA256);
                 m_bReferenceUnresolved = false;
             }
         }
@@ -132,10 +132,10 @@ void SAL_CALL OOXMLSecParser::endElement(const OUString& rName) throw (xml::sax:
         if (m_bReferenceUnresolved)
         {
             // No transform algorithm found, assume binary.
-            m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/true);
+            m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/true, /*nDigestID=*/xml::crypto::DigestID::SHA256);
             m_bReferenceUnresolved = false;
         }
-        m_pXSecController->setDigestValue(m_aDigestValue);
+        m_pXSecController->setDigestValue(xml::crypto::DigestID::SHA256, m_aDigestValue);
     }
     else if (rName == "DigestValue" && !m_bInCertDigest)
         m_bInDigestValue = false;
diff --git a/xmlsecurity/source/helper/xmlsignaturehelper.cxx b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
index 7267e5f..c310633 100644
--- a/xmlsecurity/source/helper/xmlsignaturehelper.cxx
+++ b/xmlsecurity/source/helper/xmlsignaturehelper.cxx
@@ -145,9 +145,9 @@ void XMLSignatureHelper::SetDescription(sal_Int32 nSecurityId, const OUString& r
     mpXSecController->setDescription(nSecurityId, rDescription);
 }
 
-void XMLSignatureHelper::AddForSigning( sal_Int32 nSecurityId, const OUString& uri, const OUString& objectURL, bool bBinary )
+void XMLSignatureHelper::AddForSigning( sal_Int32 nSecurityId, const OUString& uri, const OUString& objectURL, bool bBinary, bool bXAdESCompliantIfODF )
 {
-    mpXSecController->signAStream( nSecurityId, uri, objectURL, bBinary );
+    mpXSecController->signAStream( nSecurityId, uri, objectURL, bBinary, bXAdESCompliantIfODF );
 }
 
 
@@ -221,11 +221,11 @@ void XMLSignatureHelper::ExportOOXMLSignature(const uno::Reference<embed::XStora
     }
 }
 
-bool XMLSignatureHelper::CreateAndWriteSignature( const uno::Reference< xml::sax::XDocumentHandler >& xDocumentHandler )
+bool XMLSignatureHelper::CreateAndWriteSignature( const uno::Reference< xml::sax::XDocumentHandler >& xDocumentHandler, bool bXAdESCompliantIfODF )
 {
     mbError = false;
 
-    if ( !mpXSecController->WriteSignature( xDocumentHandler ) )
+    if ( !mpXSecController->WriteSignature( xDocumentHandler, bXAdESCompliantIfODF ) )
     {
         mbError = true;
     }
diff --git a/xmlsecurity/source/helper/xsecctl.cxx b/xmlsecurity/source/helper/xsecctl.cxx
index d4467a9..380adf7 100644
--- a/xmlsecurity/source/helper/xsecctl.cxx
+++ b/xmlsecurity/source/helper/xsecctl.cxx
@@ -65,6 +65,7 @@ XSecController::XSecController( const cssu::Reference<cssu::XComponentContext>&
     , m_bIsSAXEventKeeperSticky(false)
     , m_nReservedSignatureId(0)
     , m_bVerifyCurrentSignature(false)
+    , m_nDigestID(cssxc::DigestID::SHA1)
 {
 }
 
@@ -614,9 +615,12 @@ void XSecController::exportSignature(
 
             /* Write SignatureMethod element */
             pAttributeList = new SvXMLAttributeList();
+
+            // Assume that all Reference elements use the same DigestMethod:Algorithm, and that the
+            // SignatureMethod:Algorithm should be the corresponding one.
             pAttributeList->AddAttribute(
                 "Algorithm",
-                ALGO_RSASHA1);
+                (vReferenceInfors[0].nDigestID == cssxc::DigestID::SHA1 ? OUString(ALGO_RSASHA1) : OUString(ALGO_RSASHA256)));
             xDocumentHandler->startElement( "SignatureMethod", cssu::Reference< cssxs::XAttributeList > (pAttributeList) );
             xDocumentHandler->endElement( "SignatureMethod" );
 
@@ -676,7 +680,7 @@ void XSecController::exportSignature(
                     pAttributeList = new SvXMLAttributeList();
                     pAttributeList->AddAttribute(
                         "Algorithm",
-                        ALGO_XMLDSIGSHA1);
+                        (refInfor.nDigestID == cssxc::DigestID::SHA1 ? OUString(ALGO_XMLDSIGSHA1) : OUString(ALGO_XMLDSIGSHA256)));
                     xDocumentHandler->startElement(
                         "DigestMethod",
                         cssu::Reference< cssxs::XAttributeList > (pAttributeList) );
diff --git a/xmlsecurity/source/helper/xsecctl.hxx b/xmlsecurity/source/helper/xsecctl.hxx
index a2dc326..eaf4e66 100644
--- a/xmlsecurity/source/helper/xsecctl.hxx
+++ b/xmlsecurity/source/helper/xsecctl.hxx
@@ -78,10 +78,10 @@ public:
         xReferenceResolvedListener = xListener;
     }
 
-    void addReference( SignatureReferenceType type, const OUString& uri, sal_Int32 keeperId )
+    void addReference( SignatureReferenceType type, sal_Int32 digestID, const OUString& uri, sal_Int32 keeperId )
     {
         signatureInfor.vSignatureReferenceInfors.push_back(
-                SignatureReferenceInformation(type, uri));
+                SignatureReferenceInformation(type, digestID, uri));
         vKeeperIds.push_back( keeperId );
     }
 };
@@ -254,6 +254,13 @@ private:
      * representing whether to verify the current signature
      */
     bool m_bVerifyCurrentSignature;
+
+    /*
+     * the type of signature to generate (from the css::xml::crypto::DigestID alternatives) when there is a choice,
+     * in practice currently SHA1 or SHA256 for ODF.
+     */
+    sal_Int32 m_nDigestID;
+
 public:
     /*
      * An xUriBinding is provided to map Uris to XInputStream interfaces.
@@ -281,23 +288,28 @@ private:
      */
     static OUString createId();
     css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > prepareSignatureToWrite(
-        InternalSignatureInformation& signatureInfo, sal_Int32 nStorageFormat = 0 );
+        InternalSignatureInformation& signatureInfo,
+        sal_Int32 nStorageFormat,
+        bool bXAdESCompliantIfODF );
 
     /*
      * For signature verification
      */
     void addSignature();
-    void addReference( const OUString& ouUri);
+    void addReference(
+        const OUString& ouUri,
+        sal_Int32 nDigestID );
     void addStreamReference(
         const OUString& ouUri,
-        bool isBinary );
+        bool isBinary,
+        sal_Int32 nDigestID );
     void setReferenceCount() const;
 
     void setX509IssuerName( OUString& ouX509IssuerName );
     void setX509SerialNumber( OUString& ouX509SerialNumber );
     void setX509Certificate( OUString& ouX509Certificate );
     void setSignatureValue( OUString& ouSignatureValue );
-    void setDigestValue( OUString& ouDigestValue );
+    void setDigestValue( sal_Int32 nDigestID, OUString& ouDigestValue );
 
     void setDate( OUString& ouDate );
     void setDescription(const OUString& rDescription);
@@ -342,7 +354,7 @@ public:
     /*
      * For signature generation
      */
-    void signAStream( sal_Int32 securityId, const OUString& uri, const OUString& objectURL, bool isBinary);
+    void signAStream( sal_Int32 securityId, const OUString& uri, const OUString& objectURL, bool isBinary, bool bXAdESCompliantIfODF);
 
 
     /** sets data that describes the certificate.
@@ -384,7 +396,8 @@ public:
     void setDescription(sal_Int32 nSecurityId, const OUString& rDescription);
 
     bool WriteSignature(
-        const css::uno::Reference< css::xml::sax::XDocumentHandler >& xDocumentHandler );
+        const css::uno::Reference< css::xml::sax::XDocumentHandler >& xDocumentHandler,
+        bool bXAdESCompliantIfODF);
 
     /*
      * For signature verification
diff --git a/xmlsecurity/source/helper/xsecparser.cxx b/xmlsecurity/source/helper/xsecparser.cxx
index 9dd1dc7..c169498 100644
--- a/xmlsecurity/source/helper/xsecparser.cxx
+++ b/xmlsecurity/source/helper/xsecparser.cxx
@@ -25,6 +25,7 @@
 #include <string.h>
 
 namespace cssu = com::sun::star::uno;
+namespace cssxc = com::sun::star::xml::crypto;
 namespace cssxs = com::sun::star::xml::sax;
 
 XSecParser::XSecParser(XSecController* pXSecController,
@@ -39,6 +40,7 @@ XSecParser::XSecParser(XSecController* pXSecController,
     , m_pXSecController(pXSecController)
     , m_xNextHandler(xNextHandler)
     , m_bReferenceUnresolved(false)
+    , m_nReferenceDigestID(cssxc::DigestID::SHA1)
 {
 }
 
@@ -113,7 +115,7 @@ void SAL_CALL XSecParser::startElement(
                 /*
                 * remove the first character '#' from the attribute value
                 */
-                m_pXSecController->addReference( ouUri.copy(1) );
+                m_pXSecController->addReference( ouUri.copy(1), m_nReferenceDigestID );
             }
             else
             {
@@ -124,6 +126,21 @@ void SAL_CALL XSecParser::startElement(
                 m_bReferenceUnresolved = true;
             }
         }
+        else if (aName == "DigestMethod")
+        {
+            OUString ouAlgorithm = xAttribs->getValueByName("Algorithm");
+
+            SAL_WARN_IF( ouAlgorithm.isEmpty(), "xmlsecurity.helper", "no Algorithm in Reference" );
+            if (!ouAlgorithm.isEmpty())
+            {
+                SAL_WARN_IF( ouAlgorithm != ALGO_XMLDSIGSHA1 && ouAlgorithm != ALGO_XMLDSIGSHA256,
+                             "xmlsecurity.helper", "Algorithm neither SHA1 or SHA256");
+                if (ouAlgorithm == ALGO_XMLDSIGSHA1)
+                    m_nReferenceDigestID = cssxc::DigestID::SHA1;
+                else if (ouAlgorithm == ALGO_XMLDSIGSHA256)
+                    m_nReferenceDigestID = cssxc::DigestID::SHA256;
+            }
+        }
         else if (aName == "Transform")
         {
             if ( m_bReferenceUnresolved )
@@ -135,7 +152,7 @@ void SAL_CALL XSecParser::startElement(
                      * a xml stream
                      */
                 {
-                    m_pXSecController->addStreamReference( m_currentReferenceURI, false);
+                    m_pXSecController->addStreamReference( m_currentReferenceURI, false, m_nReferenceDigestID );
                     m_bReferenceUnresolved = false;
                 }
             }
@@ -219,11 +236,11 @@ void SAL_CALL XSecParser::endElement( const OUString& aName )
             * it must be a octet stream
             */
             {
-                m_pXSecController->addStreamReference( m_currentReferenceURI, true);
+                m_pXSecController->addStreamReference( m_currentReferenceURI, true, m_nReferenceDigestID );
                 m_bReferenceUnresolved = false;
             }
 
-            m_pXSecController->setDigestValue( m_ouDigestValue );
+            m_pXSecController->setDigestValue( m_nReferenceDigestID, m_ouDigestValue );
         }
         else if ( aName == "SignedInfo" )
         {
diff --git a/xmlsecurity/source/helper/xsecparser.hxx b/xmlsecurity/source/helper/xsecparser.hxx
index 204ff67..530fa9a 100644
--- a/xmlsecurity/source/helper/xsecparser.hxx
+++ b/xmlsecurity/source/helper/xsecparser.hxx
@@ -95,6 +95,10 @@ private:
     OUString m_currentReferenceURI;
     bool m_bReferenceUnresolved;
 
+    // Relevant for ODF. The digest algorithm selected by the current DigestMethod element's
+    // Algorithm attribute in the current Reference element. From css::xml::crypto::DigestID.
+    sal_Int32 m_nReferenceDigestID;
+
 private:
     static OUString getIdAttr(const css::uno::Reference<
             css::xml::sax::XAttributeList >& xAttribs );
diff --git a/xmlsecurity/source/helper/xsecsign.cxx b/xmlsecurity/source/helper/xsecsign.cxx
index 5b27c13..a6b5a21 100644
--- a/xmlsecurity/source/helper/xsecsign.cxx
+++ b/xmlsecurity/source/helper/xsecsign.cxx
@@ -59,7 +59,9 @@ OUString XSecController::createId()
 }
 
 cssu::Reference< cssxc::sax::XReferenceResolvedListener > XSecController::prepareSignatureToWrite(
-    InternalSignatureInformation& internalSignatureInfor, sal_Int32 nStorageFormat )
+    InternalSignatureInformation& internalSignatureInfor,
+    sal_Int32 nStorageFormat,
+    bool bXAdESCompliantIfODF)
 {
     sal_Int32 nSecurityId = internalSignatureInfor.signatureInfor.nSecurityId;
     SignatureReferenceInformations& vReferenceInfors = internalSignatureInfor.signatureInfor.vSignatureReferenceInfors;
@@ -165,28 +167,30 @@ cssu::Reference< cssxc::sax::XReferenceResolvedListener > XSecController::prepar
     cssu::Reference<cssxc::sax::XKeyCollector> keyCollector (xReferenceResolvedListener, cssu::UNO_QUERY);
     keyCollector->setKeyId(0);
 
+    const sal_Int32 digestID = bXAdESCompliantIfODF ? cssxc::DigestID::SHA256 : cssxc::DigestID::SHA1;
+
     if (nStorageFormat != embed::StorageFormats::OFOPXML)
     {
         internalSignatureInfor.signatureInfor.ouSignatureId = createId();
         internalSignatureInfor.signatureInfor.ouPropertyId = createId();
-        internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, internalSignatureInfor.signatureInfor.ouPropertyId, -1 );
+        internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouPropertyId, -1 );
         size++;
 
         if (!internalSignatureInfor.signatureInfor.ouDescription.isEmpty())
         {
             // Only mention the hash of the description in the signature if it's non-empty.
             internalSignatureInfor.signatureInfor.ouDescriptionPropertyId = createId();
-            internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, internalSignatureInfor.signatureInfor.ouDescriptionPropertyId, -1);
+            internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouDescriptionPropertyId, -1);
             size++;
         }
     }
     else
     {
-        internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, "idPackageObject", -1);
+        internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idPackageObject", -1);
         size++;
-        internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, "idOfficeObject", -1);
+        internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idOfficeObject", -1);
         size++;
-        internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, "idSignedProperties", -1);
+        internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idSignedProperties", -1);
         size++;
     }
 
@@ -204,21 +208,22 @@ cssu::Reference< cssxc::sax::XReferenceResolvedListener > XSecController::prepar
     return xReferenceResolvedListener;
 }
 
-void XSecController::signAStream( sal_Int32 securityId, const OUString& uri, const OUString& /*objectURL*/, bool isBinary)
+void XSecController::signAStream( sal_Int32 securityId, const OUString& uri, const OUString& /*objectURL*/, bool isBinary, bool bXAdESCompliantIfODF)
 {
-    SignatureReferenceType type = isBinary ? SignatureReferenceType::BINARYSTREAM : SignatureReferenceType::XMLSTREAM;
+    const SignatureReferenceType type = isBinary ? SignatureReferenceType::BINARYSTREAM : SignatureReferenceType::XMLSTREAM;
+    const sal_Int32 digestID = bXAdESCompliantIfODF ? cssxc::DigestID::SHA256 : cssxc::DigestID::SHA1;
 
     int index = findSignatureInfor( securityId );
 
     if (index == -1)
     {
         InternalSignatureInformation isi(securityId, nullptr);
-        isi.addReference(type, uri, -1);
+        isi.addReference(type, digestID, uri, -1);
         m_vInternalSignatureInformations.push_back( isi );
     }
     else
     {
-        m_vInternalSignatureInformations[index].addReference(type, uri, -1);
+        m_vInternalSignatureInformations[index].addReference(type, digestID, uri, -1);
     }
 }
 
@@ -302,8 +307,11 @@ void XSecController::setDescription(sal_Int32 nSecurityId, const OUString& rDesc
 }
 
 bool XSecController::WriteSignature(
-    const cssu::Reference<cssxs::XDocumentHandler>& xDocumentHandler )
+    const cssu::Reference<cssxs::XDocumentHandler>& xDocumentHandler,
+    bool bXAdESCompliantIfODF )
 {
+    (void) bXAdESCompliantIfODF;
+
     bool rc = false;
 
     SAL_WARN_IF( !xDocumentHandler.is(), "xmlsecurity.helper", "I really need a document handler!" );
@@ -336,11 +344,9 @@ bool XSecController::WriteSignature(
             {
                 InternalSignatureInformation &isi = m_vInternalSignatureInformations[i];
 
-                /*
-                 * prepare the signature creator
-                 */
-                isi.xReferenceResolvedListener
-                    = prepareSignatureToWrite( isi );
+                // Prepare the signature creator.
+                // 0 is not a documented value of embed::StorageFormats, ugh
+                isi.xReferenceResolvedListener = prepareSignatureToWrite( isi, 0, bXAdESCompliantIfODF );
 
                 exportSignature( xSEKHandler, isi.signatureInfor );
             }
@@ -383,7 +389,7 @@ bool XSecController::WriteOOXMLSignature(const uno::Reference<embed::XStorage>&
             for (InternalSignatureInformation & rInformation : m_vInternalSignatureInformations)
             {
                 // Prepare the signature creator.
-                rInformation.xReferenceResolvedListener = prepareSignatureToWrite(rInformation, embed::StorageFormats::OFOPXML);
+                rInformation.xReferenceResolvedListener = prepareSignatureToWrite(rInformation, embed::StorageFormats::OFOPXML, false);
 
                 exportOOXMLSignature(xRootStorage, xSEKHandler, rInformation.signatureInfor);
             }
diff --git a/xmlsecurity/source/helper/xsecverify.cxx b/xmlsecurity/source/helper/xsecverify.cxx
index 46946fe..2fcead5 100644
--- a/xmlsecurity/source/helper/xsecverify.cxx
+++ b/xmlsecurity/source/helper/xsecverify.cxx
@@ -114,7 +114,7 @@ void XSecController::addSignature()
     m_vInternalSignatureInformations.push_back( isi );
 }
 
-void XSecController::addReference( const OUString& ouUri)
+void XSecController::addReference( const OUString& ouUri, sal_Int32 nDigestID )
 {
     if (m_vInternalSignatureInformations.empty())
     {
@@ -122,12 +122,13 @@ void XSecController::addReference( const OUString& ouUri)
         return;
     }
     InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
-    isi.addReference(SignatureReferenceType::SAMEDOCUMENT,ouUri, -1 );
+    isi.addReference(SignatureReferenceType::SAMEDOCUMENT, nDigestID, ouUri, -1 );
 }
 
 void XSecController::addStreamReference(
     const OUString& ouUri,
-    bool isBinary )
+    bool isBinary,
+    sal_Int32 nDigestID )
 {
         SignatureReferenceType type = (isBinary?SignatureReferenceType::BINARYSTREAM:SignatureReferenceType::XMLSTREAM);
 
@@ -154,7 +155,7 @@ void XSecController::addStreamReference(
         }
     }
 
-    isi.addReference(type, ouUri, -1);
+    isi.addReference(type, nDigestID, ouUri, -1);
 }
 
 void XSecController::setReferenceCount() const
@@ -235,7 +236,7 @@ void XSecController::setSignatureValue( OUString& ouSignatureValue )
     isi.signatureInfor.ouSignatureValue = ouSignatureValue;
 }
 
-void XSecController::setDigestValue( OUString& ouDigestValue )
+void XSecController::setDigestValue( sal_Int32 nDigestID, OUString& ouDigestValue )
 {
     if (m_vInternalSignatureInformations.empty())
     {
@@ -250,6 +251,7 @@ void XSecController::setDigestValue( OUString& ouDigestValue )
     }
     SignatureReferenceInformation &reference =
         isi.signatureInfor.vSignatureReferenceInfors.back();
+    reference.nDigestID = nDigestID;
     reference.ouDigestValue = ouDigestValue;
 }
 
diff --git a/xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui b/xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui
index 4eebb5e..10c0685 100644
--- a/xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui
+++ b/xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui
@@ -139,7 +139,7 @@
               </object>
               <packing>
                 <property name="left_attach">0</property>
-                <property name="top_attach">6</property>
+                <property name="top_attach">7</property>
                 <property name="width">1</property>
                 <property name="height">1</property>
               </packing>
@@ -366,6 +366,19 @@
                 <property name="height">1</property>
               </packing>
             </child>
+            <child>
+              <object class="GtkCheckButton" id="xadescompliant">
+                <property name="label" translatable="yes">Use XAdES-compliant signature when there is a choice</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="left_attach">0</property>
+                <property name="top_attach">6</property>
+              </packing>
+            </child>
           </object>
           <packing>
             <property name="expand">True</property>


More information about the Libreoffice-commits mailing list